├── LICENSE ├── README.md ├── headers ├── aes.h ├── cryptstructs.h ├── encrypt.h ├── filequeue.h ├── scrypt.h ├── sha256.h └── utils.h ├── makefile └── src ├── aes.c ├── encrypt.c ├── filequeue.c ├── main.c ├── scrypt.c ├── sha256.c └── utils.c /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AEScrypt 2 | Cross platform command line tool to encrypt/decrypt files with AES (ECB or CBC). 3 | 4 | Compile with "gcc aes.c sha256.c encrypt.c -Werror -Wall" 5 | 6 | The tool can encrypt files and directories and take a user specified key or use the default. The initialization vector in CBC mode is stored with the key in a file. This file cannot be re-created as the IV is completely random, so don't lose this file if in CBC mode (default). 7 | 8 | Credit to [kokke's Tiny AES](https://github.com/kokke/tiny-AES128-C) and [B-con's crypto-algorithms](https://github.com/B-Con/crypto-algorithms). 9 | 10 | NOTICE: This tool was created as a learning experience. While the algorithms used are standardized, it is still possible vulnerabilities remain in the program. 11 | 12 | ## TODO List 13 | 14 | + Build and test on \*nix environment 15 | + Add extension to encrypted files 16 | + Add key checksum to encrypted files 17 | + Implement different key sizes 18 | + Rewrite AES to have GPU support, side-channel resistance 19 | + Add other crypto options (twofish, RSA, one-time-pad, viginere?, 3DES?) 20 | -------------------------------------------------------------------------------- /headers/aes.h: -------------------------------------------------------------------------------- 1 | #ifndef _AES_H_ 2 | #define _AES_H_ 3 | 4 | #include 5 | 6 | void setAESMode(const uint32_t mode); 7 | 8 | void AES_ECB_encrypt(const uint8_t* input, const uint8_t* key, uint8_t *output, const uint32_t length); 9 | void AES_ECB_decrypt(const uint8_t* input, const uint8_t* key, uint8_t *output, const uint32_t length); 10 | 11 | void AES_CBC_encrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv); 12 | void AES_CBC_decrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv); 13 | 14 | /*****************************************************************************/ 15 | /* Defines: */ 16 | /*****************************************************************************/ 17 | // The number of columns comprising a state in AES. This is a constant in AES. Value=4 18 | #define Nb 4 19 | #define AES_BLOCKLEN 16 //Block length in bytes AES is 128b block only 20 | 21 | extern int KEYLEN; 22 | // Initial Vector used only for CBC mode 23 | extern uint8_t* Iv; 24 | 25 | #endif //_AES_H_ 26 | -------------------------------------------------------------------------------- /headers/cryptstructs.h: -------------------------------------------------------------------------------- 1 | #ifndef _CRYPTSTRUCTS_H_ 2 | #define _CRYPTSTRUCTS_H_ 3 | 4 | #include "aes.h" // AES_BLOCKLEN 5 | 6 | #include 7 | 8 | #ifndef CHUNK_SIZE // Max size of chunk to read at a time 9 | #define CHUNK_SIZE 8192 10 | #endif 11 | 12 | /** Cross platform path separator **/ 13 | static const char kPathSeparator = 14 | #ifdef _WIN32 15 | '\\'; 16 | #else 17 | '/'; 18 | #endif 19 | 20 | #define MAX_KEY_SIZE 32 21 | #define SALT_LEN 32 22 | #define CHECKSUM_SIZE 32 23 | #define CRYPT_CONFIG_PV1 1 24 | #define CRYPT_CONFIG_KV1 2 25 | #define CRYPT_HEADER_VERSION 1 26 | 27 | struct CryptOptions { 28 | int e_flag; // 0 for decrypt, non-0 for encrypt 29 | int v_flag; // How verbose to be 30 | int r_flag; // non-zero for recursive (directories) 31 | int g_flag; // Generate key file 32 | int mode; // Which aes mode to use (128, 192, 256) 33 | int key_flag; // Type of key to use (password or file) 34 | char keyFilePath[256]; // Path to key file 35 | } options; 36 | 37 | struct CryptConfig { 38 | uint32_t version; 39 | uint8_t iv[AES_BLOCKLEN]; 40 | uint8_t salt[SALT_LEN]; // only used for password mode 41 | }; 42 | 43 | struct CryptSecrets { 44 | char* password; 45 | uint8_t key[MAX_KEY_SIZE]; 46 | }; 47 | 48 | #endif // _CRYPTSTRUCTS_H_ 49 | 50 | -------------------------------------------------------------------------------- /headers/encrypt.h: -------------------------------------------------------------------------------- 1 | #ifndef ENCRYPT_H_ 2 | #define ENCRYPT_H_ 3 | 4 | 5 | #include // printf, perror 6 | #include // malloc 7 | #include // realpath 8 | #include // time 9 | #include // memset 10 | 11 | #include // uint32_t, uint8_t 12 | #include // getopt 13 | 14 | #include // lstat, S_ISDIR, S_ISREG 15 | #include // access 16 | #include // opendir, readdir 17 | 18 | #ifdef _WIN32 19 | #include // GetFullPathName 20 | #include // CryptGenRandom 21 | #else 22 | #include 23 | #endif 24 | 25 | 26 | #include "aes.h" // AES-256 encryption 27 | #include "sha256.h" // SHA-256 hashing 28 | #include "cryptstructs.h" 29 | 30 | 31 | void decryptFile(const char *path, struct CryptSecrets secrets); 32 | void encryptFile(const char *path, struct CryptSecrets secrets); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /headers/filequeue.h: -------------------------------------------------------------------------------- 1 | #ifndef _FILEQUEUE_H_ 2 | #define _FILEQUEUE_H_ 3 | 4 | #define PATH_MAX_LENGTH 2048 5 | 6 | struct PathNode { 7 | char *path; 8 | struct PathNode* next; 9 | }; 10 | 11 | struct PathNode* getNextPath(struct PathNode* node, char* path); 12 | struct PathNode* pushNextPath(struct PathNode* node, const char* path); 13 | 14 | #endif // _FILEQUEUE_H_ 15 | -------------------------------------------------------------------------------- /headers/scrypt.h: -------------------------------------------------------------------------------- 1 | #ifndef _SCRYPT_H_ 2 | #define _SCRYPT_H_ 3 | 4 | /** 5 | * Scrypt functions for password based key derivation 6 | * Functions here are based off of RFC 2104, 2898, 7914 7 | * and tested using the test vectors outlined in RFC7914 8 | * 9 | * @author Jacob Heard 10 | */ 11 | #include 12 | 13 | struct ScryptInfo { 14 | uint8_t *salt; // salt to use 15 | uint32_t slen; // salt length (in bytes 16 | 17 | // Note: n must be a power of 2 < 2^(128*r/8) 18 | int32_t n, p; // CPU/memory cost, parallelization parameter 19 | 20 | uint32_t dklen; // Derived key length (in bytes) 21 | int32_t r; // blocksize 22 | }; 23 | 24 | /** 25 | * Initializes values of a ScryptInfo struct to their defaults. 26 | * The user can then make any desire changes to the values. 27 | * 28 | * @param info A pointer to the ScryptInfo struct to fill 29 | */ 30 | void initScryptInfo(struct ScryptInfo *info); 31 | 32 | /** 33 | * Based on RFC 7914 and the "Stronger Key Derivation 34 | * via Sequential 35 | * Memory-Hard Functions" (http://www.tarsnap.com/scrypt/scrypt.pdf) 36 | * 37 | * @param passwd The \0 terminated password 38 | * @param info A struct with parameters for scrypt to use. 39 | * Leave NULL for defaults. 40 | * 41 | * @return A derived key of length dklen bytes 42 | */ 43 | uint8_t *scrypt(char *passwd, int plen, struct ScryptInfo *info); 44 | 45 | /** 46 | * Based on RTF2104 HMAC specification + wikipedia pseudocode 47 | * 48 | * @param key The key to use for the hash function 49 | * @param klen Length of key in bytes 50 | * @param message The message to be HMACd 51 | * @param mlen Length of the message in bytes 52 | * 53 | * @return The HMAC of the message using key (allocated using malloc, must be freed by user) 54 | */ 55 | void HMAC_SHA256(const uint8_t *key, int klen, const uint8_t*message, int mlen, uint8_t *out); 56 | 57 | /** 58 | * Extracts, and extends entropy from a given password into 59 | * a key of desired size. Based on RTF2898 PBKDF2 (section 5.2) 60 | * 61 | * @param passwd The \0 terminated password to use 62 | * @param salt The random salt to use 63 | * @param slen The length of the salt (in bytes) 64 | * @param c The number of rounds 65 | * @param dklen The desired key length of the result 66 | * 67 | * @return A pointer to a key of length dklen, the key 68 | * is created using malloc and should be freed by the user 69 | */ 70 | uint8_t *PBKDF2(const uint8_t *passwd, int plen, const uint8_t *salt, int slen, int c, int dklen); 71 | 72 | #endif // _SCRYPT_H_ 73 | -------------------------------------------------------------------------------- /headers/sha256.h: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * Filename: sha256.h 3 | * Author: Brad Conte (brad AT bradconte.com) 4 | * Copyright: 5 | * Disclaimer: This code is presented "as is" without any guarantees. 6 | * Details: Defines the API for the corresponding SHA1 implementation. 7 | *********************************************************************/ 8 | 9 | #ifndef SHA256_H 10 | #define SHA256_H 11 | 12 | /*************************** HEADER FILES ***************************/ 13 | #include 14 | #include 15 | 16 | /****************************** MACROS ******************************/ 17 | #define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest 18 | 19 | /**************************** DATA TYPES ****************************/ 20 | 21 | typedef struct { 22 | uint8_t data[64]; 23 | uint32_t datalen; 24 | unsigned long long bitlen; 25 | uint32_t state[8]; 26 | } SHA256_CTX; 27 | 28 | /*********************** FUNCTION DECLARATIONS **********************/ 29 | void sha256_init(SHA256_CTX *ctx); 30 | void sha256_update(SHA256_CTX *ctx, const uint8_t data[], size_t len); 31 | void sha256_final(SHA256_CTX *ctx, uint8_t hash[]); 32 | void sha256(const char *in, char *out, int len); 33 | 34 | #endif // SHA256_H 35 | -------------------------------------------------------------------------------- /headers/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_H_ 2 | #define UTILS_H_ 3 | 4 | #include 5 | #ifdef _WIN32 6 | #include 7 | #include // CryptGenRandom 8 | #else 9 | #include 10 | #endif 11 | 12 | #include "cryptstructs.h" 13 | #include "filequeue.h" 14 | 15 | #define PASSWORD_MODE 1 16 | #define FILE_MODE 2 17 | #define MAX_PASSWORD_LENGTH 128 18 | 19 | void writeKeyFile(struct CryptSecrets* secrets); 20 | void readKeyFile(struct CryptSecrets* secrets); 21 | void getPassword(char *passwd); 22 | void getConfigFromPassword(struct CryptConfig* config, struct CryptSecrets* secrets); 23 | FILE *getTempFile(char* nameBuffer); 24 | int replace(const char* src, const char* dst); 25 | void doAllFiles(struct PathNode* start, struct CryptSecrets secrets); 26 | 27 | /** 28 | * Generates a array of cryptographically secure pseudorandom numbers. This uses getrandom() 29 | * on *nix systems and CryptGenRandom on Windows. 30 | * 31 | * @param buf The buffer to store the random numbers in 32 | * @param bytes The number of bytes of randoms to generate 33 | * @return 0 on success, nonzero on error 34 | */ 35 | int gen_randoms(char *buf, int bytes); 36 | 37 | /** 38 | * Checks if a given path is a file 39 | * 40 | * @param path The path to test for file-ness 41 | * @return nonzero if path is a file, 0 otherwise 42 | */ 43 | int is_file(const char* path); 44 | 45 | /** 46 | * Checks if a given path is a directory 47 | * 48 | * @param path The path totest for directory-ness 49 | * @return nonzero if path is a directory, 0 otherwise 50 | */ 51 | int is_dir(const char* path); 52 | 53 | /** 54 | * Print a verbose message where v is the verbosity rank 55 | * e.g. if the call is v_print(2, "some message") then the program 56 | * needs to be run with at least 2 v flags (-vv) to print the message 57 | * 58 | * @param v The level of verbosity to display this message at 59 | * @param format The format string 60 | * @param ... A list of arguments corresponding to the format string 61 | */ 62 | void v_print(int v, const char* format, ...); 63 | 64 | /** 65 | * Reads a line and trims trailing whitespace, excluding spaces 66 | * 67 | * @param line The buffer to read the line into 68 | * @param max_bytes The maximum number of bytes to read 69 | * @param stream The file stream to read from 70 | * @return The number of bytes read into line 71 | */ 72 | size_t readline(char* line, int max_bytes, FILE* stream); 73 | 74 | #endif // UTILS_H_ 75 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | GXX=gcc 2 | FLAGS=-I./headers 3 | FILES=src/sha256.c src/aes.c src/scrypt.c src/encrypt.c src/utils.c src/filequeue.c 4 | 5 | default: 6 | $(GXX) -g $(FILES) src/main.c -o aes $(FLAGS) 7 | -------------------------------------------------------------------------------- /src/aes.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | This is an implementation of the AES algorithm, specifically ECB and CBC mode. 4 | Block size can be chosen in aes.h - available choices are AES128, AES192, AES256. 5 | 6 | The implementation is verified against the test vectors in: 7 | National Institute of Standards and Technology Special Publication 800-38A 2001 ED 8 | 9 | ECB-AES128 10 | ---------- 11 | 12 | plain-text: 13 | 6bc1bee22e409f96e93d7e117393172a 14 | ae2d8a571e03ac9c9eb76fac45af8e51 15 | 30c81c46a35ce411e5fbc1191a0a52ef 16 | f69f2445df4f9b17ad2b417be66c3710 17 | 18 | key: 19 | 2b7e151628aed2a6abf7158809cf4f3c 20 | 21 | resulting cipher 22 | 3ad77bb40d7a3660a89ecaf32466ef97 23 | f5d3d58503b9699de785895a96fdbaaf 24 | 43b1cd7f598ece23881b00e3ed030688 25 | 7b0c785e27e8ad3f8223207104725dd4 26 | 27 | 28 | NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0) 29 | You should pad the end of the string with zeros if this is not the case. 30 | For AES192/256 the block size is proportionally larger. 31 | 32 | */ 33 | 34 | 35 | /*****************************************************************************/ 36 | /* Includes: */ 37 | /*****************************************************************************/ 38 | #include 39 | #include // CBC mode, for memset 40 | #include "aes.h" 41 | 42 | 43 | // jcallan@github points out that declaring Multiply as a function 44 | // reduces code size considerably with the Keil ARM compiler. 45 | // See this link for more information: https://github.com/kokke/tiny-AES128-C/pull/3 46 | #ifndef MULTIPLY_AS_A_FUNCTION 47 | #define MULTIPLY_AS_A_FUNCTION 0 48 | #endif 49 | 50 | 51 | /*****************************************************************************/ 52 | /* Private variables: */ 53 | /*****************************************************************************/ 54 | // state - array holding the intermediate results during decryption. 55 | typedef uint8_t state_t[4][4]; 56 | static state_t* state; 57 | 58 | // Default to 128bit mode 59 | int KEYLEN = 16; 60 | static int Nk = 4; 61 | static int Nr = 10; 62 | 63 | // The array that stores the round keys. (set size to max roundkey size) 64 | static uint8_t RoundKey[240]; 65 | 66 | // The Key input to the AES Program 67 | static const uint8_t* Key; 68 | 69 | // Initial Vector used only for CBC mode 70 | uint8_t* Iv; 71 | 72 | // The lookup-tables are marked const so they can be placed in read-only storage instead of RAM 73 | // The numbers below can be computed dynamically trading ROM for RAM - 74 | // This can be useful in (embedded) bootloader applications, where ROM is often limited. 75 | static const uint8_t sbox[256] = { 76 | //0 1 2 3 4 5 6 7 8 9 A B C D E F 77 | 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 78 | 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 79 | 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 80 | 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 81 | 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 82 | 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 83 | 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 84 | 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 85 | 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 86 | 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 87 | 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 88 | 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 89 | 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 90 | 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 91 | 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 92 | 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; 93 | 94 | static const uint8_t rsbox[256] = { 95 | 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 96 | 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 97 | 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 98 | 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 99 | 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 100 | 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 101 | 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 102 | 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 103 | 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 104 | 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 105 | 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 106 | 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 107 | 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 108 | 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 109 | 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 110 | 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d }; 111 | 112 | // The round constant word array, Rcon[i], contains the values given by 113 | // x to th e power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8) 114 | static const uint8_t Rcon[256] = { 115 | 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 116 | 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 117 | 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 118 | 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 119 | 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 120 | 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 121 | 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 122 | 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 123 | 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 124 | 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 125 | 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 126 | 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 127 | 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 128 | 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 129 | 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 130 | 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d }; 131 | 132 | 133 | /*****************************************************************************/ 134 | /* Private functions: */ 135 | /*****************************************************************************/ 136 | static uint8_t getSBoxValue(uint8_t num) 137 | { 138 | return sbox[num]; 139 | } 140 | 141 | static uint8_t getSBoxInvert(uint8_t num) 142 | { 143 | return rsbox[num]; 144 | } 145 | 146 | // This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states. 147 | static void KeyExpansion(void) 148 | { 149 | uint32_t i, k; 150 | uint8_t tempa[4]; // Used for the column/row operations 151 | 152 | // The first round key is the key itself. 153 | for (i = 0; i < Nk; ++i) 154 | { 155 | RoundKey[(i * 4) + 0] = Key[(i * 4) + 0]; 156 | RoundKey[(i * 4) + 1] = Key[(i * 4) + 1]; 157 | RoundKey[(i * 4) + 2] = Key[(i * 4) + 2]; 158 | RoundKey[(i * 4) + 3] = Key[(i * 4) + 3]; 159 | } 160 | 161 | // All other round keys are found from the previous round keys. 162 | //i == Nk 163 | for (; i < Nb * (Nr + 1); ++i) 164 | { 165 | { 166 | tempa[0]=RoundKey[(i-1) * 4 + 0]; 167 | tempa[1]=RoundKey[(i-1) * 4 + 1]; 168 | tempa[2]=RoundKey[(i-1) * 4 + 2]; 169 | tempa[3]=RoundKey[(i-1) * 4 + 3]; 170 | } 171 | 172 | if (i % Nk == 0) 173 | { 174 | // This function shifts the 4 bytes in a word to the left once. 175 | // [a0,a1,a2,a3] becomes [a1,a2,a3,a0] 176 | 177 | // Function RotWord() 178 | { 179 | k = tempa[0]; 180 | tempa[0] = tempa[1]; 181 | tempa[1] = tempa[2]; 182 | tempa[2] = tempa[3]; 183 | tempa[3] = k; 184 | } 185 | 186 | // SubWord() is a function that takes a four-byte input word and 187 | // applies the S-box to each of the four bytes to produce an output word. 188 | 189 | // Function Subword() 190 | { 191 | tempa[0] = getSBoxValue(tempa[0]); 192 | tempa[1] = getSBoxValue(tempa[1]); 193 | tempa[2] = getSBoxValue(tempa[2]); 194 | tempa[3] = getSBoxValue(tempa[3]); 195 | } 196 | 197 | tempa[0] = tempa[0] ^ Rcon[i/Nk]; 198 | } 199 | #if defined(AES256) && (AES256 == 1) 200 | if (i % Nk == 4) 201 | { 202 | // Function Subword() 203 | { 204 | tempa[0] = getSBoxValue(tempa[0]); 205 | tempa[1] = getSBoxValue(tempa[1]); 206 | tempa[2] = getSBoxValue(tempa[2]); 207 | tempa[3] = getSBoxValue(tempa[3]); 208 | } 209 | } 210 | #endif 211 | RoundKey[i * 4 + 0] = RoundKey[(i - Nk) * 4 + 0] ^ tempa[0]; 212 | RoundKey[i * 4 + 1] = RoundKey[(i - Nk) * 4 + 1] ^ tempa[1]; 213 | RoundKey[i * 4 + 2] = RoundKey[(i - Nk) * 4 + 2] ^ tempa[2]; 214 | RoundKey[i * 4 + 3] = RoundKey[(i - Nk) * 4 + 3] ^ tempa[3]; 215 | } 216 | } 217 | 218 | // This function adds the round key to state. 219 | // The round key is added to the state by an XOR function. 220 | static void AddRoundKey(uint8_t round) 221 | { 222 | uint8_t i,j; 223 | for (i=0;i<4;++i) 224 | { 225 | for (j = 0; j < 4; ++j) 226 | { 227 | (*state)[i][j] ^= RoundKey[round * Nb * 4 + i * Nb + j]; 228 | } 229 | } 230 | } 231 | 232 | // The SubBytes Function Substitutes the values in the 233 | // state matrix with values in an S-box. 234 | static void SubBytes(void) 235 | { 236 | uint8_t i, j; 237 | for (i = 0; i < 4; ++i) 238 | { 239 | for (j = 0; j < 4; ++j) 240 | { 241 | (*state)[j][i] = getSBoxValue((*state)[j][i]); 242 | } 243 | } 244 | } 245 | 246 | // The ShiftRows() function shifts the rows in the state to the left. 247 | // Each row is shifted with different offset. 248 | // Offset = Row number. So the first row is not shifted. 249 | static void ShiftRows(void) 250 | { 251 | uint8_t temp; 252 | 253 | // Rotate first row 1 columns to left 254 | temp = (*state)[0][1]; 255 | (*state)[0][1] = (*state)[1][1]; 256 | (*state)[1][1] = (*state)[2][1]; 257 | (*state)[2][1] = (*state)[3][1]; 258 | (*state)[3][1] = temp; 259 | 260 | // Rotate second row 2 columns to left 261 | temp = (*state)[0][2]; 262 | (*state)[0][2] = (*state)[2][2]; 263 | (*state)[2][2] = temp; 264 | 265 | temp = (*state)[1][2]; 266 | (*state)[1][2] = (*state)[3][2]; 267 | (*state)[3][2] = temp; 268 | 269 | // Rotate third row 3 columns to left 270 | temp = (*state)[0][3]; 271 | (*state)[0][3] = (*state)[3][3]; 272 | (*state)[3][3] = (*state)[2][3]; 273 | (*state)[2][3] = (*state)[1][3]; 274 | (*state)[1][3] = temp; 275 | } 276 | 277 | static uint8_t xtime(uint8_t x) 278 | { 279 | return ((x<<1) ^ (((x>>7) & 1) * 0x1b)); 280 | } 281 | 282 | // MixColumns function mixes the columns of the state matrix 283 | static void MixColumns(void) 284 | { 285 | uint8_t i; 286 | uint8_t Tmp,Tm,t; 287 | for (i = 0; i < 4; ++i) 288 | { 289 | t = (*state)[i][0]; 290 | Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3] ; 291 | Tm = (*state)[i][0] ^ (*state)[i][1] ; Tm = xtime(Tm); (*state)[i][0] ^= Tm ^ Tmp ; 292 | Tm = (*state)[i][1] ^ (*state)[i][2] ; Tm = xtime(Tm); (*state)[i][1] ^= Tm ^ Tmp ; 293 | Tm = (*state)[i][2] ^ (*state)[i][3] ; Tm = xtime(Tm); (*state)[i][2] ^= Tm ^ Tmp ; 294 | Tm = (*state)[i][3] ^ t ; Tm = xtime(Tm); (*state)[i][3] ^= Tm ^ Tmp ; 295 | } 296 | } 297 | 298 | // Multiply is used to multiply numbers in the field GF(2^8) 299 | #if MULTIPLY_AS_A_FUNCTION 300 | static uint8_t Multiply(uint8_t x, uint8_t y) 301 | { 302 | return (((y & 1) * x) ^ 303 | ((y>>1 & 1) * xtime(x)) ^ 304 | ((y>>2 & 1) * xtime(xtime(x))) ^ 305 | ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ 306 | ((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))); 307 | } 308 | #else 309 | #define Multiply(x, y) \ 310 | ( ((y & 1) * x) ^ \ 311 | ((y>>1 & 1) * xtime(x)) ^ \ 312 | ((y>>2 & 1) * xtime(xtime(x))) ^ \ 313 | ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ \ 314 | ((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))) \ 315 | 316 | #endif 317 | 318 | // MixColumns function mixes the columns of the state matrix. 319 | // The method used to multiply may be difficult to understand for the inexperienced. 320 | // Please use the references to gain more information. 321 | static void InvMixColumns(void) 322 | { 323 | int i; 324 | uint8_t a, b, c, d; 325 | for (i = 0; i < 4; ++i) 326 | { 327 | a = (*state)[i][0]; 328 | b = (*state)[i][1]; 329 | c = (*state)[i][2]; 330 | d = (*state)[i][3]; 331 | 332 | (*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09); 333 | (*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d); 334 | (*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b); 335 | (*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e); 336 | } 337 | } 338 | 339 | 340 | // The SubBytes Function Substitutes the values in the 341 | // state matrix with values in an S-box. 342 | static void InvSubBytes(void) 343 | { 344 | uint8_t i,j; 345 | for (i = 0; i < 4; ++i) 346 | { 347 | for (j = 0; j < 4; ++j) 348 | { 349 | (*state)[j][i] = getSBoxInvert((*state)[j][i]); 350 | } 351 | } 352 | } 353 | 354 | static void InvShiftRows(void) 355 | { 356 | uint8_t temp; 357 | 358 | // Rotate first row 1 columns to right 359 | temp = (*state)[3][1]; 360 | (*state)[3][1] = (*state)[2][1]; 361 | (*state)[2][1] = (*state)[1][1]; 362 | (*state)[1][1] = (*state)[0][1]; 363 | (*state)[0][1] = temp; 364 | 365 | // Rotate second row 2 columns to right 366 | temp = (*state)[0][2]; 367 | (*state)[0][2] = (*state)[2][2]; 368 | (*state)[2][2] = temp; 369 | 370 | temp = (*state)[1][2]; 371 | (*state)[1][2] = (*state)[3][2]; 372 | (*state)[3][2] = temp; 373 | 374 | // Rotate third row 3 columns to right 375 | temp = (*state)[0][3]; 376 | (*state)[0][3] = (*state)[1][3]; 377 | (*state)[1][3] = (*state)[2][3]; 378 | (*state)[2][3] = (*state)[3][3]; 379 | (*state)[3][3] = temp; 380 | } 381 | 382 | 383 | // Cipher is the main function that encrypts the PlainText. 384 | static void Cipher(void) 385 | { 386 | uint8_t round = 0; 387 | 388 | // Add the First round key to the state before starting the rounds. 389 | AddRoundKey(0); 390 | 391 | // There will be Nr rounds. 392 | // The first Nr-1 rounds are identical. 393 | // These Nr-1 rounds are executed in the loop below. 394 | for (round = 1; round < Nr; ++round) 395 | { 396 | SubBytes(); 397 | ShiftRows(); 398 | MixColumns(); 399 | AddRoundKey(round); 400 | } 401 | 402 | // The last round is given below. 403 | // The MixColumns function is not here in the last round. 404 | SubBytes(); 405 | ShiftRows(); 406 | AddRoundKey(Nr); 407 | } 408 | 409 | static void InvCipher(void) 410 | { 411 | uint8_t round=0; 412 | 413 | // Add the First round key to the state before starting the rounds. 414 | AddRoundKey(Nr); 415 | 416 | // There will be Nr rounds. 417 | // The first Nr-1 rounds are identical. 418 | // These Nr-1 rounds are executed in the loop below. 419 | for (round = (Nr - 1); round > 0; --round) 420 | { 421 | InvShiftRows(); 422 | InvSubBytes(); 423 | AddRoundKey(round); 424 | InvMixColumns(); 425 | } 426 | 427 | // The last round is given below. 428 | // The MixColumns function is not here in the last round. 429 | InvShiftRows(); 430 | InvSubBytes(); 431 | AddRoundKey(0); 432 | } 433 | 434 | /*****************************************************************************/ 435 | /* Public functions: */ 436 | /*****************************************************************************/ 437 | 438 | void setAESMode(const uint32_t mode) { 439 | switch(mode){ 440 | case 256: // 256 bit mode 441 | KEYLEN = 32; 442 | Nk = 8; 443 | Nr = 14; 444 | break; 445 | case 192: // 192 bit mode 446 | KEYLEN = 24; 447 | Nk = 6; 448 | Nr = 12; 449 | break; 450 | case 128: //128 bit mode 451 | default: // Default to 128 bit encryption 452 | KEYLEN = 16; 453 | Nk = 4; 454 | Nr = 10; 455 | break; 456 | } 457 | } 458 | 459 | void AES_ECB_encrypt(const uint8_t* input, const uint8_t* key, uint8_t* output, const uint32_t length) 460 | { 461 | // Copy input to output, and work in-memory on output 462 | memcpy(output, input, length); 463 | state = (state_t*)output; 464 | 465 | Key = key; 466 | KeyExpansion(); 467 | 468 | // The next function call encrypts the PlainText with the Key using AES algorithm. 469 | Cipher(); 470 | } 471 | 472 | void AES_ECB_decrypt(const uint8_t* input, const uint8_t* key, uint8_t *output, const uint32_t length) 473 | { 474 | // Copy input to output, and work in-memory on output 475 | memcpy(output, input, length); 476 | state = (state_t*)output; 477 | 478 | // The KeyExpansion routine must be called before encryption. 479 | Key = key; 480 | KeyExpansion(); 481 | 482 | InvCipher(); 483 | } 484 | 485 | 486 | static void XorWithIv(uint8_t* buf) 487 | { 488 | uint8_t i; 489 | for (i = 0; i < AES_BLOCKLEN; ++i) //WAS for(i = 0; i < KEYLEN; ++i) but the block in AES is always 128bit so 16 bytes! 490 | { 491 | buf[i] ^= Iv[i]; 492 | } 493 | } 494 | 495 | void AES_CBC_encrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv) 496 | { 497 | uintptr_t i; 498 | uint8_t extra = length % AES_BLOCKLEN; /* Remaining bytes in the last non-full block */ 499 | 500 | // Skip the key expansion if key is passed as 0 501 | if (0 != key) 502 | { 503 | Key = key; 504 | KeyExpansion(); 505 | } 506 | 507 | if (iv != 0) 508 | { 509 | Iv = (uint8_t*)iv; 510 | } 511 | 512 | for (i = 0; i < length; i += AES_BLOCKLEN) 513 | { 514 | XorWithIv(input); 515 | memcpy(output, input, AES_BLOCKLEN); 516 | state = (state_t*)output; 517 | Cipher(); 518 | Iv = output; 519 | input += AES_BLOCKLEN; 520 | output += AES_BLOCKLEN; 521 | } 522 | 523 | if (extra) 524 | { 525 | memcpy(output, input, extra); 526 | state = (state_t*)output; 527 | Cipher(); 528 | } 529 | } 530 | 531 | void AES_CBC_decrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv) 532 | { 533 | uintptr_t i; 534 | uint8_t extra = length % AES_BLOCKLEN; /* Remaining bytes in the last non-full block */ 535 | 536 | // Skip the key expansion if key is passed as 0 537 | if (0 != key) 538 | { 539 | Key = key; 540 | KeyExpansion(); 541 | } 542 | 543 | // If iv is passed as 0, we continue to encrypt without re-setting the Iv 544 | if (iv != 0) 545 | { 546 | Iv = (uint8_t*)iv; 547 | } 548 | 549 | for (i = 0; i < length; i += AES_BLOCKLEN) 550 | { 551 | memcpy(output, input, AES_BLOCKLEN); 552 | state = (state_t*)output; 553 | InvCipher(); 554 | XorWithIv(output); 555 | Iv = input; 556 | input += AES_BLOCKLEN; 557 | output += AES_BLOCKLEN; 558 | } 559 | 560 | if (extra) 561 | { 562 | memcpy(output, input, extra); 563 | state = (state_t*)output; 564 | InvCipher(); 565 | } 566 | } 567 | -------------------------------------------------------------------------------- /src/encrypt.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "encrypt.h" 4 | #include "cryptstructs.h" 5 | #include "utils.h" 6 | 7 | static int writeCryptHeader( 8 | struct CryptConfig *config, 9 | const char *checksum, 10 | FILE *fp 11 | ) { 12 | if(fwrite(&(config->version), 4, 1, fp) != 1) 13 | return 0; 14 | if(fwrite(config->iv, 1, AES_BLOCKLEN, fp) != AES_BLOCKLEN) 15 | return 0; 16 | if(fwrite(config->salt, 1, SALT_LEN, fp) != SALT_LEN) 17 | return 0; 18 | if(fwrite(checksum, 1, CHECKSUM_SIZE, fp) != CHECKSUM_SIZE) 19 | return 0; 20 | 21 | return 1; 22 | } 23 | 24 | static int readCryptHeader( 25 | struct CryptConfig *config, 26 | char *checksum, 27 | FILE *fp 28 | ) { 29 | if(fread(&(config->version), 4, 1, fp) != 1) 30 | return 0; 31 | if(fread(config->iv, 1, AES_BLOCKLEN, fp) != AES_BLOCKLEN) 32 | return 0; 33 | if(fread(config->salt, 1, SALT_LEN, fp) != SALT_LEN) 34 | return 0; 35 | if(fread(checksum, 1, CHECKSUM_SIZE, fp) != CHECKSUM_SIZE) 36 | return 0; 37 | 38 | return 1; 39 | } 40 | 41 | /** 42 | * Resulting output file will be in the format: 43 | * 44 | * 45 | * 46 | * 47 | * 48 | * Where the size of the chunk is a uint32_t (4 byte unsigned int) 49 | * and the chunk is an array of type uint8_t* 50 | * 51 | * @param fname the name of the file to encrypt 52 | * @param config The (en/de)crypt configuration to use 53 | * @param fp The open file pointer to the file to encrypt 54 | * @return 0 on success, nonzero on failure 55 | */ 56 | static int encrypt( 57 | const char *fname, 58 | struct CryptConfig config, 59 | struct CryptSecrets secrets, 60 | FILE *inputFile, 61 | FILE *tempFile 62 | ) { 63 | v_print(1, "Encrypting file \"%s\"\n", fname); 64 | 65 | v_print(3, "Allocating %d bytes for AES...\n", CHUNK_SIZE*2); 66 | uint8_t *output = malloc(CHUNK_SIZE); // Allocate chunk of memory for output 67 | uint8_t *input = malloc(CHUNK_SIZE); // Allocate chunk of memory for input 68 | if(output == NULL || input == NULL) { 69 | output = (output) ? output : input; // Get the successful alloc (if there is one) 70 | if(output != NULL) free(output); // If one alloc worked and the other failed, free the successful one 71 | printf("Error allocating memory. Aborting...\n"); 72 | return EXIT_FAILURE; 73 | } 74 | 75 | v_print(2, "Reading input file %s...\n", fname); 76 | uint32_t len, err, pad, rtotal = 0, wtotal = 0; 77 | Iv = config.iv; 78 | while( (len = fread(input, 1, CHUNK_SIZE, inputFile)) ) { 79 | pad = (AES_BLOCKLEN - (len % AES_BLOCKLEN)) % AES_BLOCKLEN; 80 | if(pad > 0) { 81 | // Put some zeroes into buffer for padding 82 | memset(input + len, 0, pad); 83 | } 84 | // Encrypt the buffer 85 | AES_CBC_encrypt_buffer(output, input, len+pad, secrets.key, 0); 86 | 87 | // Write size of data 88 | fwrite(&len, sizeof len, 1, tempFile); 89 | // Write actual data with padding 90 | fwrite(output, 1, len+pad, tempFile); 91 | rtotal += len; 92 | wtotal += len + pad + sizeof len; 93 | } 94 | v_print(2, "Read %d bytes as %d chunks. Wrote %d bytes.\n", rtotal, (rtotal / CHUNK_SIZE)+1, wtotal); 95 | 96 | v_print(3, "Freeing AES memory...\n"); 97 | free(input); 98 | free(output); 99 | 100 | v_print(1, "Done encrypting \"%s\"\n\n", fname); 101 | 102 | return EXIT_SUCCESS; 103 | } 104 | 105 | /** 106 | * Accepts a file that was encrypted using encrypt() 107 | * Decrypts the file and keeps the original file name 108 | * 109 | * @param fname The name of the file to decrypt 110 | * @param config The (en/de)crypt configuration to use 111 | * @param fp The open file pointer to the encrypted file 112 | * @return 0 on success, nonzero on failure 113 | */ 114 | static int decrypt( 115 | const char *fname, 116 | struct CryptConfig config, 117 | struct CryptSecrets secrets, 118 | FILE *inputFile, 119 | FILE *tempFile 120 | ) { 121 | v_print(1, "Decrypting file \"%s\"\n", fname); 122 | v_print(3, "Allocating %d bytes for AES...\n", CHUNK_SIZE*2); 123 | 124 | uint8_t *output = malloc(CHUNK_SIZE); // Allocate chunk of memory for output 125 | uint8_t *input = malloc(CHUNK_SIZE); // Allocate chunk of memory for input 126 | if(output == NULL || input == NULL) { 127 | output = (output) ? output : input; // Get the successful alloc (if there is one) 128 | if(output != NULL) free(output); // If one alloc worked and the other failed, free the successful one 129 | printf("Error allocating memory. Aborting...\n"); 130 | return EXIT_FAILURE; 131 | } 132 | 133 | v_print(2, "Reading %s...\n", fname); 134 | 135 | uint32_t len, err, pad, rtotal = 0, wtotal = 0; 136 | Iv = config.iv; // Set iv initially, AES_CBC_decrypt_buffer will update as necessary 137 | // Read size of data in loop 138 | while( fread(&len, sizeof len, 1, inputFile) ) { 139 | pad = (AES_BLOCKLEN - (len % AES_BLOCKLEN)) % AES_BLOCKLEN; // Get size of padding 140 | // Read correct number of bytes into buffer 141 | err = fread(input, 1, len+pad, inputFile); 142 | if(err != len+pad) { 143 | printf("Error: File read issue.\n"); 144 | return EXIT_FAILURE; 145 | } 146 | // Decrypt the data 147 | AES_CBC_decrypt_buffer(output, input, len+pad, secrets.key, 0); 148 | // Write only the data to output (not zero padding) 149 | fwrite(output, 1, len, tempFile); 150 | rtotal += len + pad + sizeof len; 151 | wtotal += len; 152 | } 153 | v_print(2, "Read %d bytes as %d chunks. Wrote %d bytes.\n", rtotal, (rtotal / CHUNK_SIZE)+1, wtotal); 154 | 155 | v_print(3, "Freeing AES memory...\n"); 156 | free(output); 157 | free(input); 158 | 159 | v_print(1, "Done working on \"%s\"\n\n", fname); 160 | 161 | return EXIT_SUCCESS; 162 | } 163 | 164 | void decryptFile(const char *path, struct CryptSecrets secrets) { 165 | struct CryptConfig config; 166 | char checksumActual[CHECKSUM_SIZE]; 167 | char checksum[CHECKSUM_SIZE]; 168 | 169 | FILE* inputFile = fopen(path, "rb"); 170 | if(inputFile == NULL) { 171 | v_print(1, "Error opening file.\n"); 172 | exit(EXIT_FAILURE); 173 | } 174 | 175 | if(!readCryptHeader(&config, checksum, inputFile)) { 176 | printf("Malformed header. Aborting...\n"); 177 | fclose(inputFile); 178 | exit(EXIT_FAILURE); 179 | } 180 | 181 | if(secrets.password) { 182 | getConfigFromPassword(&config, &secrets); 183 | } 184 | 185 | sha256((char*)secrets.key, checksumActual, KEYLEN); 186 | if(memcmp(checksumActual, checksum, CHECKSUM_SIZE) != 0) { 187 | printf("Invalid checksum, quitting.\n"); 188 | fclose(inputFile); 189 | exit(EXIT_FAILURE); 190 | } 191 | 192 | v_print(2, "Creating temp file...\n"); 193 | char tempFileName[32] = {0}; 194 | FILE *tempFile = getTempFile(tempFileName); 195 | if(tempFile == NULL) { 196 | printf("Error creating temp file, aborting..."); 197 | fclose(inputFile); 198 | exit(EXIT_FAILURE); 199 | } 200 | 201 | int status = decrypt(path, config, secrets, inputFile, tempFile); 202 | 203 | v_print(3, "Closing \"%s\"...\n", path); 204 | fclose(inputFile); 205 | v_print(3, "Closing \"%s\"...\n", tempFileName); 206 | fclose(tempFile); 207 | 208 | if(status != EXIT_SUCCESS) 209 | exit(status); 210 | 211 | v_print(2, "Replacing \"%s\" with temp file...\n", path); 212 | replace(tempFileName, path); 213 | } 214 | 215 | void encryptFile(const char *path, struct CryptSecrets secrets) { 216 | struct CryptConfig config; 217 | char checksum[CHECKSUM_SIZE]; 218 | 219 | FILE* inputFile = fopen(path, "rb+"); 220 | if(inputFile == NULL) { 221 | v_print(1, "Error opening file.\n"); 222 | exit(EXIT_FAILURE); 223 | } 224 | 225 | gen_randoms((char*)config.salt, SALT_LEN); 226 | if(secrets.password) { 227 | getConfigFromPassword(&config, &secrets); 228 | } else { 229 | if(gen_randoms((char*)config.iv, AES_BLOCKLEN) != 0) { 230 | printf("Error generating IV\n"); 231 | exit(EXIT_FAILURE); 232 | } 233 | } 234 | 235 | v_print(2, "Creating temp file...\n"); 236 | char tempFileName[32] = {0}; 237 | FILE *tempFile = getTempFile(tempFileName); 238 | if(tempFile == NULL) { 239 | printf("Error creating temp file, aborting..."); 240 | fclose(inputFile); 241 | exit(EXIT_FAILURE); 242 | } 243 | 244 | v_print(2, "Writing file header...\n"); 245 | sha256((char*)secrets.key, checksum, KEYLEN); 246 | if(!writeCryptHeader(&config, checksum, tempFile)) { 247 | printf("Error writing header information. Aborting...\n"); 248 | fclose(tempFile); 249 | remove(tempFileName); 250 | exit(EXIT_FAILURE); 251 | } 252 | 253 | int status = encrypt(path, config, secrets, inputFile, tempFile); 254 | 255 | v_print(3, "Closing \"%s\"...\n", path); 256 | fclose(inputFile); 257 | v_print(3, "Closing temp file...\n", tempFileName); 258 | fclose(tempFile); 259 | 260 | if(status != EXIT_SUCCESS) 261 | exit(status); 262 | 263 | v_print(2, "Replacing \"%s\" with temp file...\n", path); 264 | replace(tempFileName, path); 265 | } 266 | 267 | -------------------------------------------------------------------------------- /src/filequeue.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include // realpath 6 | 7 | #ifdef _WIN32 8 | #include // GetFullPathName 9 | #endif 10 | 11 | #include "utils.h" 12 | #include "filequeue.h" 13 | 14 | static struct PathNode* newPathNode(const char*); 15 | static void freeNode(struct PathNode*); 16 | static struct PathNode* expandDirectory(struct PathNode*, const char*); 17 | 18 | static struct PathNode* newPathNode(const char* path) { 19 | struct PathNode* node = malloc(sizeof(struct PathNode)); 20 | node->path = malloc(strlen(path)+1); 21 | strcpy(node->path, path); 22 | node->next = NULL; 23 | return node; 24 | } 25 | 26 | static void freeNode(struct PathNode* node) { 27 | free(node->path); 28 | free(node); 29 | } 30 | 31 | static struct PathNode* expandDirectory(struct PathNode* node, const char* directory) { 32 | char buf[PATH_MAX_LENGTH+1] = {0}; 33 | DIR *dir; 34 | struct dirent *ent; 35 | if((dir = opendir(node->path)) != NULL) { 36 | /* print all the files and directories within directory */ 37 | while((ent = readdir (dir)) != NULL) { 38 | #ifdef _WIN32 39 | GetFullPathName(node->path, PATH_MAX_LENGTH, buf, NULL); 40 | sprintf(buf, "%s%c%s", buf, kPathSeparator, ent->d_name); 41 | #else 42 | realpath(node->path, buf); 43 | sprintf(buf, "%s%c%s", buf, kPathSeparator, ent->d_name); 44 | #endif 45 | node = pushNextPath(node, buf); 46 | } 47 | closedir(dir); 48 | } else { 49 | // Could not open directory 50 | perror("Error"); 51 | } 52 | 53 | return node; 54 | } 55 | 56 | struct PathNode* pushNextPath(struct PathNode* node, const char* path) { 57 | struct PathNode* newNode = newPathNode(path); 58 | newNode->next = node; 59 | return newNode; 60 | } 61 | 62 | // Returns the next file path, automatically expands directories 63 | struct PathNode* getNextPath(struct PathNode* node, char* path) { 64 | if(!node) { 65 | path[0] = '\0'; 66 | return NULL; 67 | } 68 | 69 | strncpy(path, node->path, PATH_MAX_LENGTH-1); 70 | struct PathNode* nextNode = node->next; 71 | 72 | freeNode(node); 73 | 74 | if(is_dir(path)) { 75 | nextNode = expandDirectory(nextNode, path); 76 | if(nextNode && is_dir(nextNode->path)) { 77 | return getNextPath(nextNode, path); 78 | } 79 | } 80 | 81 | return nextNode; 82 | } 83 | 84 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | /** AES encryption software 2 | * @author Jacob Heard 3 | * 4 | * Command line program to encrypt a file or directory using AES. 5 | * 6 | **/ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "cryptstructs.h" 16 | #include "filequeue.h" 17 | #include "utils.h" 18 | 19 | void show_usage(char *name, int more) { 20 | printf("Usage: %s path [-r -e -d -p -g -k -m ]\n", name); 21 | if(more) { 22 | printf(" Encrypts a file or directory using AES. Applies a given key or generates one randomly into a file.\n\n"); 23 | printf(" path Path to the file/directory to work on\n"); 24 | printf(" -r, --recursive Recursively work on files in directory\n"); 25 | printf(" -e, --encrypt Sets mode to encrypt given file/directory\n"); 26 | printf(" -d, --decrypt Sets mode to decrypt given file/directory\n"); 27 | printf(" -p, --password Prompt for password to use for key\n"); 28 | printf(" -g, --gen-key Generate a keyfile (use with -p to seed keyfile from pass)\n"); 29 | printf(" -k, --keyfile Load a key from file\n"); 30 | printf(" -m, --mode Sets cipher mode (128/192/256) default:128\n"); 31 | printf(" -v(vv), --verbose Run in verbose mode\n"); 32 | printf("\n"); 33 | } else { 34 | printf("Use %s --help to show help page.\n", name); 35 | } 36 | } 37 | 38 | int main(int argc, char **argv) { 39 | if(argc < 2) { 40 | show_usage(argv[0], 0); 41 | return EXIT_SUCCESS; 42 | } 43 | /* Display help page on -h, --help */ 44 | if(strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0) { 45 | show_usage(argv[0], 1); 46 | return EXIT_SUCCESS; 47 | } 48 | 49 | if(!is_file(argv[1]) && !is_dir(argv[1])) { 50 | printf("Error: Could not find \"%s\", please check that it is a file or directory and there are no typos.\n", argv[1]); 51 | return EXIT_FAILURE; 52 | } 53 | 54 | const char *path = argv[1]; 55 | char *err; // Error handling for strtol 56 | int opt; 57 | struct CryptSecrets secrets; 58 | secrets.password = NULL; // Must be NULL by default 59 | 60 | options.e_flag = 1; // encrypt by default 61 | 62 | static struct option long_options[] = { 63 | {"recursive", no_argument, 0, 'r'}, 64 | {"encrypt", no_argument, 0, 'e'}, 65 | {"decrypt", no_argument, 0, 'd'}, 66 | {"gen-key", no_argument, 0, 'g'}, 67 | {"password", no_argument, 0, 'p'}, 68 | {"verbose", no_argument, 0, 'v'}, 69 | {"keyfile", required_argument, 0, 'k'}, 70 | {"mode", required_argument, 0, 'm'}, 71 | {0, 0, 0, 0} 72 | }; 73 | int option_index = 0; 74 | 75 | while(1) { 76 | // getopt_long stores the option index here. 77 | opt = getopt_long(argc, argv, "redgpvk:m:", long_options, &option_index); 78 | 79 | // Detect the end of the options. 80 | if(opt == -1) 81 | break; 82 | 83 | switch(opt) { 84 | case 0: 85 | // If this option set a flag, do nothing else 86 | break; 87 | case 'r': 88 | options.r_flag = 1; 89 | break; 90 | case 'e': 91 | options.e_flag = 1; 92 | break; 93 | case 'd': 94 | options.e_flag = 0; 95 | break; 96 | case 'g': 97 | options.g_flag = 1; 98 | break; 99 | case 'p': 100 | options.key_flag = PASSWORD_MODE; 101 | break; 102 | case 'v': 103 | options.v_flag += 1; 104 | break; 105 | case 'k': 106 | strncpy(options.keyFilePath, optarg, 256); // Copy name to place 107 | options.key_flag = FILE_MODE; 108 | break; 109 | case 'm': 110 | options.mode = (int) strtol(optarg, &err, 10); 111 | if(*err != '\0' || (options.mode != 128 && options.mode != 192 && options.mode != 256)) { 112 | printf("invalid argument '%s' should be one of (128/192/256)\n", optarg); 113 | return EXIT_FAILURE; 114 | } else { 115 | setAESMode(options.mode); 116 | } 117 | break; 118 | case '?': 119 | // getopt_long already printed an error 120 | return EXIT_FAILURE; 121 | break; 122 | default: // This shouldn't happen 123 | exit(1); 124 | break; 125 | } 126 | } 127 | 128 | if(!options.key_flag && !options.e_flag) { 129 | printf("Please specify a key file or use password for decrypting.\n"); 130 | return EXIT_FAILURE; 131 | } 132 | if(!options.r_flag && is_dir(path)) { 133 | printf("\"%s\" is a directory, to recursively encrypt all files, use -r\n"); 134 | return EXIT_FAILURE; 135 | } 136 | 137 | if(options.e_flag) { 138 | int exists = (options.keyFilePath[0] != '\0' && access(options.keyFilePath, F_OK) == 0); 139 | if(options.g_flag && exists) { 140 | char choice[8] = {0}; 141 | printf("The file \"%s\" will be overwritten, would you like to continue? (Y/N) ", options.keyFilePath); 142 | fgets(choice, 8, stdin); 143 | if(choice[0] != 'y' && choice[0] != 'Y') { 144 | printf("Aborting...\n"); 145 | exit(EXIT_FAILURE); 146 | } 147 | } else if( !exists ) { 148 | // If the file does not exist, set the flag to create it 149 | options.g_flag = 1; 150 | } 151 | } 152 | 153 | if(options.key_flag == PASSWORD_MODE) { 154 | secrets.password = malloc(MAX_PASSWORD_LENGTH+1); 155 | getPassword(secrets.password); 156 | } else { 157 | if(gen_randoms((char*)secrets.key, MAX_KEY_SIZE) != 0) { 158 | printf("Error generating entropy for key\n"); 159 | return EXIT_FAILURE; 160 | } 161 | v_print(2, "Generated key\n"); 162 | } 163 | 164 | if(options.g_flag) { 165 | writeKeyFile(&secrets); 166 | } else if(options.key_flag == FILE_MODE) { 167 | readKeyFile(&secrets); 168 | } 169 | 170 | struct PathNode* start = pushNextPath(NULL, path); 171 | doAllFiles(start, secrets); 172 | 173 | free(secrets.password); 174 | 175 | return EXIT_SUCCESS; 176 | } 177 | 178 | -------------------------------------------------------------------------------- /src/scrypt.c: -------------------------------------------------------------------------------- 1 | #include // malloc, free 2 | #include // malloc, free 3 | #include // int32_t 4 | #include // memcpy 5 | 6 | #include "sha256.h" // sha256 7 | #include "scrypt.h" 8 | 9 | /**************** Static Utility Functions *****************/ 10 | 11 | // Function prototypes for static utilities (for use in this file only) 12 | static void XOR(uint8_t *, const uint8_t *, int); 13 | static void INT(uint8_t *, int32_t); 14 | static void malloc2D(uint8_t ***, int, int); 15 | static void free2D(uint8_t **, int); 16 | static uint64_t integerify(void *, size_t); 17 | static void scryptBlockMix(int, uint8_t *); 18 | static void scryptROMix(int, int, uint8_t *); 19 | static void salsa20_core(uint32_t[16],uint32_t[16]); 20 | 21 | static void XOR(uint8_t *dest, const uint8_t *src, int len) { 22 | for(int i = 0; i < len; i++) 23 | dest[i] ^= src[i]; 24 | } 25 | 26 | static void INT(uint8_t *res, int32_t i) { 27 | res[0] = (i >> 24) & 0xFF; 28 | res[1] = (i >> 16) & 0xFF; 29 | res[2] = (i >> 8) & 0xFF; 30 | res[3] = i & 0xFF; 31 | } 32 | 33 | static void malloc2D(uint8_t ***dest, int d1, int d2) { 34 | uint8_t **T; 35 | 36 | *dest = malloc(d1 * sizeof (uint8_t*)); 37 | T = *dest; 38 | 39 | if(T == NULL) { 40 | perror("malloc"); 41 | abort(); 42 | } 43 | for(int i = 0; i < d1; i++) { 44 | T[i] = malloc(d2); 45 | if(T[i] == NULL) { 46 | perror("malloc"); 47 | abort(); 48 | } 49 | } 50 | } 51 | 52 | static void free2D(uint8_t **dest, int d1) { 53 | for(int i = 0; i < d1; i ++) 54 | free(dest[i]); 55 | free(dest); 56 | } 57 | 58 | static uint64_t integerify(void * B, size_t r) { 59 | uint32_t * X = (void *)((uintptr_t)(B) + (2 * r - 1) * 64); 60 | 61 | return (((uint64_t)(X[13]) << 32) + X[0]); 62 | } 63 | 64 | static void scryptBlockMix(int r, uint8_t *B) { 65 | uint8_t *Y = malloc(128*r); 66 | uint8_t X[64]; 67 | uint8_t T[64]; 68 | 69 | memcpy(X, &B[64*(2*r-1)], 64); 70 | 71 | // Step 2 72 | for(int i = 0; i < 2*r; i++) { 73 | memcpy(T, B + 64*i, 64); 74 | XOR(T, X, 64); 75 | salsa20_core((uint32_t*)X, (uint32_t*)T); 76 | if(i % 2 == 0) // even indices (0...r-1) 77 | memcpy(Y + (64*i/2), X, 64); 78 | else // odd indices (r...2r-1) 79 | memcpy(Y + (64*(i/2) + 64*r), X, 64); 80 | } 81 | memcpy(B, Y, 128*r); 82 | free(Y); 83 | } 84 | 85 | static void scryptROMix(int r, int n, uint8_t *B) { 86 | int j; 87 | uint8_t **V; 88 | 89 | // Step 1 90 | uint8_t *X = malloc(r*128); 91 | memcpy(X, B, r*128); 92 | malloc2D(&V, n, r*128); 93 | 94 | // Step 2 95 | for(int i = 0; i < n; i++) { 96 | memcpy(V[i], X, 128*r); 97 | scryptBlockMix(r, X); 98 | } 99 | 100 | // Step 3 101 | for(int i = 0; i < n; i++) { 102 | j = integerify(X, r) % n; 103 | XOR(X, V[j], 128*r); 104 | scryptBlockMix(r, X); 105 | } 106 | 107 | // Step 4 108 | memcpy(B, X, r*128); 109 | free2D(V, n); 110 | free(X); 111 | } 112 | 113 | /** 114 | * salsa20/8 Core algorithm from rfc7914 (section 3) 115 | * TODO: endianness conversion and alignment (see http://cr.yp.to/snuffle/spec.pdf for Salsa20 spec) 116 | */ 117 | #define R(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) 118 | static void salsa20_core(uint32_t out[16],uint32_t in[16]) { 119 | int i; 120 | uint32_t x[16]; 121 | for (i = 0;i < 16;++i) x[i] = in[i]; 122 | 123 | for (i = 8;i > 0;i -= 2) { 124 | x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9); 125 | x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18); 126 | x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9); 127 | x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18); 128 | x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9); 129 | x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18); 130 | x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9); 131 | x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18); 132 | x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9); 133 | x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18); 134 | x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9); 135 | x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18); 136 | x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9); 137 | x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18); 138 | x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9); 139 | x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18); 140 | } 141 | 142 | for (i = 0;i < 16;++i) out[i] = x[i] + in[i]; 143 | } 144 | 145 | /***************** End of Utility Functions *****************/ 146 | 147 | void initScryptInfo(struct ScryptInfo *info) { 148 | info->salt = NULL; 149 | info->slen = 0; 150 | info->n = 16384; 151 | info->p = 1; 152 | info->r = 8; 153 | info->dklen = 32; 154 | } 155 | 156 | void HMAC_SHA256(const uint8_t *key, int klen, const uint8_t *message, int mlen, uint8_t *out) { 157 | const int bsize = 64; // sha256 block size (bytes) 158 | const int hsize = 32; // sha256 output size (bytes) 159 | 160 | uint8_t temp[mlen+bsize]; // for intermediate steps 161 | uint8_t usekey[bsize]; // The buffer we will use for the key 162 | uint8_t okp[bsize], ikp[bsize]; // Outer and Inner Key Pads 163 | memcpy(usekey, key, klen); // Copy original key into key area 164 | 165 | if(klen > bsize) { 166 | // Hash key down to hash output size 167 | sha256((char*)key, (char*)usekey, klen); 168 | klen = hsize; 169 | } 170 | if(klen < bsize) { 171 | memset(usekey+klen, 0, bsize-klen); 172 | } 173 | 174 | memset(okp, 0x5c, bsize); // Fill okp with 5C (opad) 175 | memset(ikp, 0x36, bsize); // Fill ikp with 36 (ipad) 176 | XOR(okp, usekey, bsize); // = okp xor key 177 | XOR(ikp, usekey, bsize); // = ikp xor key 178 | 179 | // Append message to inner key 180 | memcpy(temp, ikp, bsize); 181 | memcpy(temp+bsize, message, mlen); 182 | // hash inner key + message 183 | sha256((char*)temp, (char*)out, mlen+bsize); 184 | 185 | // Append result hash to outer key 186 | memcpy(temp, okp, bsize); 187 | memcpy(temp+bsize, out, hsize); 188 | // Hash again for final result 189 | sha256((char*)temp, (char*)out, bsize+hsize); 190 | } 191 | 192 | uint8_t *PBKDF2(const uint8_t *passwd, int plen, const uint8_t *salt, int slen, int c, int dklen) { 193 | const int hlen = 32; // SHA-256 output length in bytes 194 | int r, ctr = 0; // Progress tracking 195 | uint8_t T[hlen]; // Tracks progress of final result 196 | uint8_t *final = malloc(dklen); // Final result, returned to user 197 | uint8_t Uprev[hlen], Ucurr[hlen]; // For our previous and current blocks 198 | uint8_t rnd1[slen+4]; // round 1 buffer (salt+INT(i)) 199 | memcpy(rnd1, salt, slen); 200 | 201 | // F(P, S, c, i) (RFC 2898 p10 step 3) 202 | for(int i = 1; dklen > 0; i++) { 203 | // Get 4 byte, big-endian integer repr 204 | INT(rnd1+slen, i); 205 | // Calculate initial hash (U_1) for this round 206 | HMAC_SHA256(passwd, plen, rnd1, slen+4, Uprev); 207 | memcpy(T, Uprev, hlen); 208 | 209 | for(int j = 1; j < c; j++) { 210 | // Get PRF output for current U 211 | HMAC_SHA256(passwd, plen, Uprev, hlen, Ucurr); 212 | // Running XOR of T with current U 213 | XOR(T, Ucurr, hlen); 214 | // Update previous 215 | memcpy(Uprev, Ucurr, hlen); 216 | } 217 | 218 | // Step 4 key extraction 219 | r = (dklen < hlen) ? dklen : hlen; 220 | memcpy(final+ctr, T, r); 221 | ctr += r; 222 | dklen -= r; 223 | } 224 | 225 | return final; 226 | } 227 | 228 | uint8_t *scrypt(char *passwd, int plen, struct ScryptInfo *info) { 229 | uint8_t *B; 230 | B = PBKDF2((uint8_t*)passwd, plen, info->salt, info->slen, 1, info->p * 128 * info->r); 231 | 232 | for(int i = 0; i < info->p; i++) { 233 | scryptROMix(info->r, info->n, B + 128 * info->r * i); 234 | } 235 | 236 | uint8_t* result = PBKDF2((uint8_t*)passwd, plen, B, info->r*info->p*128, 1, info->dklen); 237 | free(B); 238 | 239 | return result; 240 | } 241 | 242 | -------------------------------------------------------------------------------- /src/sha256.c: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * Filename: sha256.c 3 | * Author: Brad Conte (brad AT bradconte.com) 4 | * Copyright: 5 | * Disclaimer: This code is presented "as is" without any guarantees. 6 | * Details: Implementation of the SHA-256 hashing algorithm. 7 | SHA-256 is one of the three algorithms in the SHA2 8 | specification. The others, SHA-384 and SHA-512, are not 9 | offered in this implementation. 10 | Algorithm specification can be found here: 11 | * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf 12 | This implementation uses little endian byte order. 13 | *********************************************************************/ 14 | 15 | /*************************** HEADER FILES ***************************/ 16 | #include 17 | #include 18 | #include "sha256.h" 19 | 20 | /****************************** MACROS ******************************/ 21 | #define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b)))) 22 | #define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b)))) 23 | 24 | #define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) 25 | #define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) 26 | #define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22)) 27 | #define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25)) 28 | #define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3)) 29 | #define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10)) 30 | 31 | /**************************** VARIABLES *****************************/ 32 | static const uint32_t k[64] = { 33 | 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, 34 | 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, 35 | 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, 36 | 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, 37 | 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, 38 | 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, 39 | 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, 40 | 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 41 | }; 42 | 43 | /*********************** FUNCTION DEFINITIONS ***********************/ 44 | void sha256_transform(SHA256_CTX *ctx, const uint8_t data[]) 45 | { 46 | uint32_t a, b, c, d, e, f, g, h, i, j, t1, t2, m[64]; 47 | 48 | for (i = 0, j = 0; i < 16; ++i, j += 4) 49 | m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]); 50 | for ( ; i < 64; ++i) 51 | m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; 52 | 53 | a = ctx->state[0]; 54 | b = ctx->state[1]; 55 | c = ctx->state[2]; 56 | d = ctx->state[3]; 57 | e = ctx->state[4]; 58 | f = ctx->state[5]; 59 | g = ctx->state[6]; 60 | h = ctx->state[7]; 61 | 62 | for (i = 0; i < 64; ++i) { 63 | t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i]; 64 | t2 = EP0(a) + MAJ(a,b,c); 65 | h = g; 66 | g = f; 67 | f = e; 68 | e = d + t1; 69 | d = c; 70 | c = b; 71 | b = a; 72 | a = t1 + t2; 73 | } 74 | 75 | ctx->state[0] += a; 76 | ctx->state[1] += b; 77 | ctx->state[2] += c; 78 | ctx->state[3] += d; 79 | ctx->state[4] += e; 80 | ctx->state[5] += f; 81 | ctx->state[6] += g; 82 | ctx->state[7] += h; 83 | } 84 | 85 | void sha256_init(SHA256_CTX *ctx) 86 | { 87 | ctx->datalen = 0; 88 | ctx->bitlen = 0; 89 | ctx->state[0] = 0x6a09e667; 90 | ctx->state[1] = 0xbb67ae85; 91 | ctx->state[2] = 0x3c6ef372; 92 | ctx->state[3] = 0xa54ff53a; 93 | ctx->state[4] = 0x510e527f; 94 | ctx->state[5] = 0x9b05688c; 95 | ctx->state[6] = 0x1f83d9ab; 96 | ctx->state[7] = 0x5be0cd19; 97 | } 98 | 99 | void sha256_update(SHA256_CTX *ctx, const uint8_t data[], size_t len) 100 | { 101 | uint32_t i; 102 | 103 | for (i = 0; i < len; ++i) { 104 | ctx->data[ctx->datalen] = data[i]; 105 | ctx->datalen++; 106 | if (ctx->datalen == 64) { 107 | sha256_transform(ctx, ctx->data); 108 | ctx->bitlen += 512; 109 | ctx->datalen = 0; 110 | } 111 | } 112 | } 113 | 114 | void sha256_final(SHA256_CTX *ctx, uint8_t hash[]) 115 | { 116 | uint32_t i; 117 | 118 | i = ctx->datalen; 119 | 120 | // Pad whatever data is left in the buffer. 121 | if (ctx->datalen < 56) { 122 | ctx->data[i++] = 0x80; 123 | while (i < 56) 124 | ctx->data[i++] = 0x00; 125 | } 126 | else { 127 | ctx->data[i++] = 0x80; 128 | while (i < 64) 129 | ctx->data[i++] = 0x00; 130 | sha256_transform(ctx, ctx->data); 131 | memset(ctx->data, 0, 56); 132 | } 133 | 134 | // Append to the padding the total message's length in bits and transform. 135 | ctx->bitlen += ctx->datalen * 8; 136 | ctx->data[63] = ctx->bitlen; 137 | ctx->data[62] = ctx->bitlen >> 8; 138 | ctx->data[61] = ctx->bitlen >> 16; 139 | ctx->data[60] = ctx->bitlen >> 24; 140 | ctx->data[59] = ctx->bitlen >> 32; 141 | ctx->data[58] = ctx->bitlen >> 40; 142 | ctx->data[57] = ctx->bitlen >> 48; 143 | ctx->data[56] = ctx->bitlen >> 56; 144 | sha256_transform(ctx, ctx->data); 145 | 146 | // Since this implementation uses little endian byte ordering and SHA uses big endian, 147 | // reverse all the bytes when copying the final state to the output hash. 148 | for (i = 0; i < 4; ++i) { 149 | hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; 150 | hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; 151 | hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; 152 | hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; 153 | hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff; 154 | hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff; 155 | hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff; 156 | hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff; 157 | } 158 | } 159 | 160 | /** 161 | * Converts a string of bytes into a 256bit hash using SHA2-256 162 | * 163 | * @param in The array of bytes to hash 164 | * @param out Pointer to output, needs at least 32 bytes free 165 | * @param len The number of bytes from in to hash 166 | */ 167 | void sha256(const char *in, char *out, int len) { 168 | SHA256_CTX ctx; // Create CTX object on stack 169 | sha256_init(&ctx); // Init CTX object 170 | sha256_update(&ctx, (uint8_t*)in, len); // Add key data to CTX 171 | sha256_final(&ctx, (uint8_t*)out); // Get SHA256 hash for key 172 | } 173 | -------------------------------------------------------------------------------- /src/utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include // lstat, S_ISDIR, S_ISREG 6 | #include // access 7 | 8 | #include "encrypt.h" 9 | #include "cryptstructs.h" 10 | #include "scrypt.h" 11 | #include "utils.h" 12 | 13 | 14 | int is_file(const char *path) { 15 | struct stat path_stat; 16 | #ifdef _WIN32 17 | /** TODO Check for symlinks on windows? **/ 18 | stat(path, &path_stat); 19 | #else 20 | // Handles symlinks on *nix machines 21 | lstat(path, &path_stat); 22 | #endif 23 | return S_ISREG(path_stat.st_mode); 24 | } 25 | 26 | int is_dir(const char *path) { 27 | struct stat path_stat; 28 | #ifdef _WIN32 29 | /** TODO Check for symlinks on windows? **/ 30 | stat(path, &path_stat); 31 | #else 32 | // Handles symlinks on *nix machines 33 | lstat(path, &path_stat); 34 | #endif 35 | return S_ISDIR(path_stat.st_mode); 36 | } 37 | 38 | void v_print(int v, const char* format, ...) { 39 | va_list argptr; 40 | va_start(argptr, format); 41 | if(options.v_flag >= v) 42 | vprintf(format, argptr); 43 | va_end(argptr); 44 | } 45 | 46 | size_t readline(char *line, int max_bytes, FILE *stream) { 47 | fgets(line, max_bytes, stream); 48 | size_t len = strlen(line); 49 | int whitespace = 1; // loop condition, there is still whitespace 50 | while(whitespace) { 51 | switch(line[len-1]) { 52 | case '\n': case '\r': 53 | case '\f': case '\t': 54 | line[len-1] = '\0'; 55 | len--; 56 | break; 57 | default: 58 | whitespace = 0; 59 | break; 60 | } 61 | } 62 | return len; 63 | } 64 | 65 | int gen_randoms(char *buf, int bytes) { 66 | #ifdef _WIN32 67 | HCRYPTPROV hCryptProv = 0; // Crypto context 68 | if(CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0) == 0) { 69 | return 1; 70 | } 71 | if(CryptGenRandom(hCryptProv, bytes, (PBYTE)buf) == 0) { // Generate random number 72 | return 1; 73 | } 74 | #else 75 | //TODO verify this works on older *nix distros, or find workaround 76 | if(getrandom(buf, bytes, GRND_NONBLOCK) == -1) { 77 | return 1; 78 | } 79 | #endif 80 | return 0; 81 | } 82 | 83 | #ifdef _WIN32 84 | #include 85 | 86 | int getpass(const char *prompt, char *buf, int len) { 87 | DWORD oflags; 88 | HANDLE h = GetStdHandle(STD_INPUT_HANDLE); 89 | 90 | // Get initial console mode 91 | if(!GetConsoleMode(h, &oflags)) { 92 | perror("retrieving console mode"); 93 | return -1; 94 | } 95 | // Disable echo on input 96 | if(!SetConsoleMode(h, oflags & (~ENABLE_ECHO_INPUT))){ 97 | perror("disabling output"); 98 | return -1; 99 | } 100 | 101 | // Read the actual password 102 | printf("%s", prompt); // Print prompt 103 | len = readline(buf, len, stdin); // Get password & length 104 | 105 | // Restore console state 106 | if(!SetConsoleMode(h, oflags)) { 107 | perror("restoring console"); 108 | return -1; 109 | } 110 | printf("\n"); 111 | return len; 112 | } 113 | 114 | #else 115 | #include 116 | 117 | int getpass(const char *prompt, char *buf, int len) { 118 | struct termios oflags, nflags; 119 | 120 | /* disabling echo */ 121 | tcgetattr(fileno(stdin), &oflags); 122 | nflags = oflags; 123 | nflags.c_lflag &= ~ECHO; 124 | nflags.c_lflag |= ECHONL; 125 | 126 | if (tcsetattr(fileno(stdin), TCSANOW, &nflags) != 0) { 127 | perror("tcsetattr failed to disable echo"); 128 | return -1; 129 | } 130 | 131 | printf("%s", prompt); // Print prompt 132 | len = readline(buf, len, stdin); // Get line 133 | 134 | /* restore terminal */ 135 | if (tcsetattr(fileno(stdin), TCSANOW, &oflags) != 0) { 136 | perror("tcsetattr failed to restore terminal"); 137 | return -1; 138 | } 139 | printf("\n"); 140 | return len; 141 | } 142 | 143 | #endif 144 | 145 | void getPassword(char *passwd) { 146 | static char firstTry[MAX_PASSWORD_LENGTH] = {0}; 147 | // Password mode; get password, set IV and key based on user input 148 | int len = getpass("password: ", firstTry, MAX_PASSWORD_LENGTH); 149 | if(options.e_flag) { 150 | char secondTry[MAX_PASSWORD_LENGTH] = {0}; 151 | getpass("repeat : ", secondTry, MAX_PASSWORD_LENGTH); 152 | if(strcmp(firstTry, secondTry) != 0) { 153 | printf("Passwords do not match, aborting...\n"); 154 | exit(EXIT_FAILURE); 155 | } 156 | } 157 | strncpy(passwd, firstTry, MAX_PASSWORD_LENGTH); 158 | } 159 | 160 | void readKeyFile(struct CryptSecrets* secrets) { 161 | // A key file was specified for encryption 162 | // Open the file and read the key 163 | FILE *fv = fopen(options.keyFilePath, "rb"); 164 | if(fv == NULL) { 165 | printf("Error opening key file \"%s\".\n", options.keyFilePath); 166 | exit(EXIT_FAILURE); 167 | } 168 | uint16_t kl; 169 | v_print(1, "Reading key from file.\n"); 170 | fread(&kl, sizeof kl, 1, fv); // Get key size 171 | int read = fread(secrets->key, 1, kl, fv); // Read key 172 | fclose(fv); // Close file 173 | 174 | if(read != kl) { 175 | exit(EXIT_FAILURE); 176 | } 177 | 178 | // In case we are in the wrong mode 179 | if(kl != KEYLEN) { 180 | printf("Inconsistent mode, changing to %d bit mode\n", kl*8); 181 | setAESMode(kl*8); 182 | } 183 | } 184 | 185 | void writeKeyFile(struct CryptSecrets* secrets) { 186 | v_print(1, "Creating key file...\n"); 187 | 188 | // If the key file name was not specified 189 | if(options.keyFilePath[0] == '\0') { 190 | int i = 1; 191 | // Get unused name for file 192 | sprintf(options.keyFilePath, "key-%d.aes", i); 193 | while(access(options.keyFilePath, F_OK) != -1) { 194 | sprintf(options.keyFilePath, "key-%d.aes", ++i); 195 | } 196 | } 197 | 198 | // Create file and write key 199 | FILE *fv = fopen(options.keyFilePath, "wb"); 200 | if(fv == NULL) { 201 | printf("Error: Could not create key file. Aborting...\n"); 202 | exit(EXIT_FAILURE); 203 | } 204 | uint16_t kl = (uint16_t)KEYLEN; 205 | fwrite(&kl, sizeof kl, 1, fv); // Write key size 206 | int wrote = fwrite(secrets->key, 1, KEYLEN, fv); // Write key 207 | fclose(fv); // Close file 208 | 209 | if(wrote != kl) { 210 | exit(EXIT_FAILURE); 211 | } 212 | 213 | printf("Created key file \"%s\"\n", options.keyFilePath); // Let user know name of key file 214 | } 215 | 216 | FILE *getTempFile(char* nameBuffer) { 217 | int i = 1; 218 | 219 | // Get unused name for file 220 | sprintf(nameBuffer, "temp-%d.temp", i); 221 | while(access(nameBuffer, F_OK) != -1) { 222 | sprintf(nameBuffer, "temp-%d.temp", ++i); 223 | } 224 | 225 | FILE *fv = fopen(nameBuffer, "wb"); 226 | if(fv == NULL) { 227 | v_print(3, "Error creating temp file \"%s\".\n", nameBuffer); 228 | return NULL; 229 | } 230 | return fv; 231 | } 232 | 233 | void getConfigFromPassword(struct CryptConfig* config, struct CryptSecrets* secrets) { 234 | // Scrypt variables 235 | struct ScryptInfo info; 236 | uint8_t *ptr; 237 | 238 | initScryptInfo(&info); 239 | info.salt = config->salt; 240 | info.slen = SALT_LEN; 241 | info.dklen = (AES_BLOCKLEN + MAX_KEY_SIZE)*2; 242 | 243 | // Run scrypt 244 | ptr = scrypt(secrets->password, strlen(secrets->password), &info); 245 | 246 | // Use scrypt result for key and IV 247 | memcpy(secrets->key, ptr, MAX_KEY_SIZE); 248 | memcpy(config->iv, ptr + MAX_KEY_SIZE, AES_BLOCKLEN); 249 | free(ptr); // Clean up 250 | } 251 | 252 | int replace(const char* src, const char* dst) { 253 | int err; 254 | remove(dst); // Remove old file 255 | if( (err = rename(src, dst)) != 0) { 256 | printf("Error moving file \"%s\" to \"%s\".\n", src, dst); 257 | v_print(2, "Removing temp file...\n"); 258 | remove(src); 259 | return EXIT_FAILURE; 260 | } 261 | 262 | return EXIT_SUCCESS; 263 | } 264 | 265 | void doAllFiles( 266 | struct PathNode* start, 267 | struct CryptSecrets secrets 268 | ) { 269 | char path[PATH_MAX_LENGTH+1] = {0}; 270 | int encrypt = options.e_flag; 271 | 272 | while(start) { 273 | start = getNextPath(start, path); 274 | if(encrypt) { 275 | encryptFile(path, secrets); 276 | } else { 277 | decryptFile(path, secrets); 278 | } 279 | } 280 | } 281 | 282 | --------------------------------------------------------------------------------