| /* |
| copyright: Boaz segev, 2016 |
| license: MIT |
| |
| Feel free to copy, use and enjoy according to the license provided. |
| */ |
| #ifndef MINI_CRYPT |
| |
| /** |
| The MiniCrypt library supplies the following, basic, cryptographic functions: |
| |
| - SHA-1 hashing (considered less secure, use SHA-2/SHA-3 instead). |
| - SHA-2 hashing |
| - SHA-3 hashing (on the wish list) |
| |
| Non-cryptographic, but related, algorithms also supported are: |
| |
| - Base64 encoding/decoding (non cryptographic, but often used in relation). |
| |
| The following is a list of Hashing and Encryption methods that should be avoided |
| and (unless required for some of my projects, such as for websockets), will NOT |
| be supported: |
| |
| - SHA-1 (Used for Websockets, but is better avoided). |
| - RC4 |
| - MD5 |
| |
| All functions will be available under the MiniCrypt global object, i.e.: |
| |
| char buffer[13] = {0}; |
| MiniCrypt.base64_encode(buffer, "My String", 9); |
| |
| |
| */ |
| #define MINI_CRYPT "0.1.1" |
| |
| #ifndef _GNU_SOURCE |
| #define _GNU_SOURCE |
| #endif |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <stdint.h> |
| #include <time.h> |
| |
| /* ***************************************************************************** |
| Helper types / structs |
| */ |
| |
| /** |
| SHA-1 hashing container - you should ignore the contents of this struct. |
| |
| The `sha1_s` type will contain all the sha1 data required to perform the |
| hashing, managing it's encoding. If it's stack allocated, no freeing will be |
| required. |
| |
| Use, for example: |
| |
| #include "mini-crypt.h" |
| sha1_s sha1; |
| MiniCrypt.sha1_init(&sha1); |
| MiniCrypt.sha1_write(&sha1, |
| "The quick brown fox jumps over the lazy dog", 43); |
| char *hashed_result = MiniCrypt.sha1_result(&sha1); |
| */ |
| typedef struct { |
| union { |
| uint32_t i[80]; |
| unsigned char str[64]; |
| } buffer; |
| union { |
| uint64_t i; |
| unsigned char str[8]; |
| } msg_length; |
| union { |
| uint32_t i[5]; |
| char str[21]; |
| } digest; |
| unsigned buffer_pos : 6; |
| unsigned initialized : 1; |
| unsigned finalized : 1; |
| } sha1_s; |
| |
| /** |
| SHA-2 function variants. |
| |
| This enum states the different SHA-2 function variants. placing SHA_512 at the |
| beginning is meant to set this variant as the default (in case a 0 is passed). |
| */ |
| typedef enum { |
| SHA_512 = 0, |
| SHA_512_256, |
| SHA_512_224, |
| SHA_384, |
| SHA_256, |
| SHA_224, |
| } sha2_variant; |
| |
| /** |
| SHA-2 hashing container - you should ignore the contents of this struct. |
| |
| The `sha2_s` type will contain all the SHA-2 data required to perform the |
| hashing, managing it's encoding. If it's stack allocated, no freeing will be |
| required. |
| |
| Use, for example: |
| |
| #include "mini-crypt.h" |
| sha2_s sha2; |
| MiniCrypt.sha2_init(&sha2, SHA_512); |
| MiniCrypt.sha2_write(&sha2, |
| "The quick brown fox jumps over the lazy dog", 43); |
| char *hashed_result = MiniCrypt.sha2_result(&sha2); |
| |
| */ |
| typedef struct { |
| union { |
| uint32_t i32[8]; |
| uint64_t i64[8]; |
| char str[65]; /* added 64+1 for the NULL byte.*/ |
| } digest; |
| union { |
| uint32_t i32[16]; |
| uint64_t i64[16]; |
| char str[128]; |
| } buffer; |
| /* notice: we're counting bits, not bytes. max length: 2^128 bits */ |
| union { |
| __uint128_t i; |
| char str[16]; |
| } msg_length; |
| unsigned buffer_pos : 7; |
| unsigned initialized : 1; |
| unsigned finalized : 1; |
| sha2_variant type : 3; |
| unsigned type_512 : 1; |
| } sha2_s; |
| |
| /** |
| The `xor_key_s` type is a struct containing XOR key data. This will be used for |
| all the encryption/decription functions that use XOR key data, such as the |
| `MiniCrypt.xor_crypt` function. |
| */ |
| typedef struct xor_key_s { |
| /** A pointer to a string containing the key. */ |
| uint8_t* key; |
| /** The length of the key string */ |
| size_t length; |
| /** |
| The vector / position from which to start the next encryption/decryption. |
| |
| This value is automatically advanced when encrypting / decrypting data. |
| */ |
| size_t position; |
| /** |
| An optional callback to be called whenever the XOR key finished a cycle and |
| the `position` is being reset to 0. |
| |
| The function should return 0 on sucess and -1 on failure. Failue will cause |
| endryption/decryption to fail. |
| */ |
| int (*on_cycle)(struct xor_key_s* key); |
| /** Opaque user data. */ |
| void* udata; |
| } xor_key_s; |
| |
| /** |
| File dump data. |
| |
| This struct (or, a pointer to this struct) is returned by the `MiniCrypt.fdump` |
| function on success. |
| |
| To free the pointer returned, simply call `free`. |
| */ |
| typedef struct { |
| size_t length; |
| char data[]; |
| } fdump_s; |
| |
| /* ***************************************************************************** |
| API Gateway (the MiniCrypt global object) |
| */ |
| |
| /** |
| The MiniCrypt global object (member of the struct MiniCrypt__API___) is the |
| API |
| namespace gateway fot the MiniCrypt library. |
| |
| For example: |
| |
| #include "mini-crypt.h" |
| sha2_s sha2; |
| MiniCrypt.sha2_init(&sha2, SHA_512); |
| MiniCrypt.sha2_write(&sha2, |
| "The quick brown fox jumps over the lazy dog", 43); |
| char *hashed_result = MiniCrypt.sha2_result(&sha2); |
| |
| */ |
| extern struct MiniCrypt__API___ { |
| /* *************************************************************************** |
| SHA-1 hashing |
| */ |
| |
| /** |
| Initialize or reset the `sha1` object. This must be performed before hashing |
| data using sha1. |
| */ |
| void (*sha1_init)(sha1_s*); |
| /** |
| Writes data to the sha1 buffer. |
| */ |
| int (*sha1_write)(sha1_s* s, const char* data, size_t len); |
| /** |
| Finalizes the SHA1 hash, returning the Hashed data. |
| |
| `sha1_result` can be called for the same object multiple times, but the |
| finalization will only be performed the first time this function is called. |
| */ |
| char* (*sha1_result)(sha1_s* s); |
| |
| /* *************************************************************************** |
| SHA-2 hashing |
| */ |
| |
| /** |
| Initialize/reset the SHA-2 object. |
| |
| SHA-2 is actually a family of functions with different variants. When |
| initializing the SHA-2 container, you must select the variant you intend to |
| apply. The following are valid options (see the sha2_variant enum): |
| |
| - SHA_512 (== 0) |
| - SHA_384 |
| - SHA_512_224 |
| - SHA_512_256 |
| - SHA_256 |
| - SHA_224 |
| |
| */ |
| void (*sha2_init)(sha2_s* s, sha2_variant variant); |
| /** |
| Writes data to the SHA-2 buffer. |
| */ |
| int (*sha2_write)(sha2_s* s, const char* data, size_t len); |
| /** |
| Finalizes the SHA-2 hash, returning the Hashed data. |
| |
| `sha2_result` can be called for the same object multiple times, but the |
| finalization will only be performed the first time this function is called. |
| */ |
| char* (*sha2_result)(sha2_s* s); |
| |
| /* *************************************************************************** |
| Base64 encoding |
| */ |
| |
| /** |
| This will encode a byte array (data) of a specified length (len) and |
| place the encoded data into the target byte buffer (target). The target buffer |
| MUST have enough room for the expected data. |
| |
| Base64 encoding always requires 4 bytes for each 3 bytes. Padding is added if |
| the raw data's length isn't devisable by 3. |
| |
| Always assume the target buffer should have room enough for (len*4/3 + 4) |
| bytes. |
| |
| Returns the number of bytes actually written to the target buffer |
| (including the Base64 required padding and excluding a NULL terminator). |
| |
| A NULL terminator char is NOT written to the target buffer. |
| */ |
| int (*base64_encode)(char* target, const char* data, int len); |
| |
| /** |
| This will decode a Base64 encoded string of a specified length (len) and |
| place the decoded data into the target byte buffer (target). |
| |
| The target buffer MUST have enough room for the expected data. |
| |
| A NULL byte will be appended to the target buffer. The function will return |
| the number of bytes written to the target buffer. |
| |
| If the target buffer is NULL, the encoded string will be destructively edited |
| and the decoded data will be placed in the original string's buffer. |
| |
| Base64 encoding always requires 4 bytes for each 3 bytes. Padding is added if |
| the raw data's length isn't devisable by 3. Hence, the target buffer should |
| be, at least, `base64_len/4*3 + 3` long. |
| |
| Returns the number of bytes actually written to the target buffer (excluding |
| the NULL terminator byte). |
| */ |
| int (*base64_decode)(char* target, char* encoded, int base64_len); |
| |
| /* *************************************************************************** |
| Hex Conversion |
| */ |
| |
| /** |
| Returns 1 if the string is HEX encoded (no non-valid hex values). Returns 0 if |
| it isn't. |
| */ |
| int (*is_hex)(const char* string, size_t length); |
| /** |
| This will convert the string (byte stream) to a Hex string. This is not |
| cryptography, just conversion for pretty print. |
| |
| The target buffer MUST have enough room for the expected data. The expected |
| data is double the length of the string + 1 byte for the NULL terminator |
| byte. |
| |
| A NULL byte will be appended to the target buffer. The function will return |
| the number of bytes written to the target buffer. |
| |
| Returns the number of bytes actually written to the target buffer (excluding |
| the NULL terminator byte). |
| */ |
| int (*str2hex)(char* target, const char* string, size_t length); |
| |
| /** |
| This will convert a Hex string to a byte string. This is not cryptography, |
| just conversion for pretty print. |
| |
| The target buffer MUST have enough room for the expected data. The expected |
| data is half the length of the Hex string + 1 byte for the NULL terminator |
| byte. |
| |
| A NULL byte will be appended to the target buffer. The function will return |
| the number of bytes written to the target buffer. |
| |
| If the target buffer is NULL, the encoded string will be destructively |
| edited |
| and the decoded data will be placed in the original string's buffer. |
| |
| Returns the number of bytes actually written to the target buffer (excluding |
| the NULL terminator byte). |
| */ |
| int (*hex2str)(char* target, char* hex, size_t length); |
| |
| /* *************************************************************************** |
| XOR encryption |
| */ |
| |
| /** |
| Uses an XOR key `xor_key_s` to encrypt / decrypt the data provided. |
| |
| Encryption/decryption can be destructive (the target and the source can point |
| to the same object). |
| |
| The key's `on_cycle` callback option should be utilized to er-calculate the |
| key every cycle. Otherwise, XOR encryption should be avoided. |
| |
| A more secure encryption would be easier to implement using seperate |
| `xor_key_s` objects for encryption and decription. |
| |
| If `target` is NULL, the source will be used as the target (destructive mode). |
| |
| Returns -1 on error and 0 on success. |
| */ |
| int (*xor_crypt)(xor_key_s* key, |
| void* target, |
| const void* source, |
| size_t length); |
| |
| /* *************************************************************************** |
| Other helper functions |
| */ |
| |
| /** |
| Allocates memory and dumps the whole file into the memory allocated. |
| Remember |
| to call `free` when done. |
| |
| Returns the number of bytes allocated. On error, returns 0 and sets the |
| container pointer to NULL. |
| |
| This function has some Unix specific properties that resolve links and user |
| folder referencing. |
| */ |
| fdump_s* (*fdump)(const char* file_path, size_t size_limit); |
| /** |
| A faster (yet less localized) alternative to `gmtime_r`. |
| |
| See the libc `gmtime_r` documentation for details. |
| |
| Falls back to `gmtime_r` for dates before epoch. |
| */ |
| struct tm* (*gmtime)(const time_t* timer, struct tm* tmbuf); |
| } MiniCrypt; |
| |
| /* end include gate */ |
| #endif |