├── .gitignore ├── Crypto.cpp ├── Crypto.h ├── LICENSE ├── Makefile ├── README.md ├── base64.cpp ├── base64.h ├── crypto_example.cpp ├── crypto_example.h ├── crypto_file_example.cpp ├── crypto_file_example.h ├── lorem_ipsum.txt └── sample.txt /.gitignore: -------------------------------------------------------------------------------- 1 | crypto_example 2 | crypto_file_example 3 | 4 | lorem_ipsum.txt.dec 5 | lorem_ipsum.txt.enc 6 | 7 | # Compiled Object files 8 | *.slo 9 | *.lo 10 | *.o 11 | 12 | # Compiled Dynamic libraries 13 | *.so 14 | *.dylib 15 | 16 | # Compiled Static libraries 17 | *.lai 18 | *.la 19 | *.a 20 | -------------------------------------------------------------------------------- /Crypto.cpp: -------------------------------------------------------------------------------- 1 | #include "Crypto.h" 2 | #include 3 | 4 | using namespace std; 5 | 6 | EVP_PKEY* Crypto::localKeypair; 7 | 8 | Crypto::Crypto() { 9 | localKeypair = NULL; 10 | remotePublicKey = NULL; 11 | 12 | #ifdef PSEUDO_CLIENT 13 | generateRsaKeypair(&remotePublicKey); 14 | #endif 15 | 16 | init(); 17 | } 18 | 19 | Crypto::Crypto(unsigned char *remotePublicKey, size_t remotePublicKeyLength) { 20 | localKeypair = NULL; 21 | this->remotePublicKey = NULL; 22 | 23 | setRemotePublicKey(remotePublicKey, remotePublicKeyLength); 24 | init(); 25 | } 26 | 27 | Crypto::~Crypto() { 28 | EVP_PKEY_free(localKeypair); 29 | EVP_PKEY_free(remotePublicKey); 30 | 31 | EVP_CIPHER_CTX_free(rsaEncryptContext); 32 | EVP_CIPHER_CTX_free(aesEncryptContext); 33 | 34 | EVP_CIPHER_CTX_free(rsaDecryptContext); 35 | EVP_CIPHER_CTX_free(aesDecryptContext); 36 | 37 | free(aesKey); 38 | free(aesIv); 39 | } 40 | 41 | int Crypto::init() { 42 | // Initalize contexts 43 | rsaEncryptContext = EVP_CIPHER_CTX_new(); 44 | aesEncryptContext = EVP_CIPHER_CTX_new(); 45 | 46 | rsaDecryptContext = EVP_CIPHER_CTX_new(); 47 | aesDecryptContext = EVP_CIPHER_CTX_new(); 48 | 49 | // Check if any of the contexts initializations failed 50 | if(rsaEncryptContext == NULL || aesEncryptContext == NULL || rsaDecryptContext == NULL || aesDecryptContext == NULL) { 51 | return FAILURE; 52 | } 53 | 54 | /* Don't set key or IV right away; we want to set lengths */ 55 | EVP_CIPHER_CTX_init(aesEncryptContext); 56 | EVP_CIPHER_CTX_init(aesDecryptContext); 57 | 58 | EVP_CipherInit_ex(aesEncryptContext, EVP_aes_256_cbc(), NULL, NULL, NULL, 1); 59 | 60 | /* Now we can set key and IV lengths */ 61 | aesKeyLength = EVP_CIPHER_CTX_key_length(aesEncryptContext); 62 | aesIvLength = EVP_CIPHER_CTX_iv_length(aesEncryptContext); 63 | 64 | // Generate RSA and AES keys 65 | generateRsaKeypair(&localKeypair); 66 | generateAesKey(&aesKey, &aesIv); 67 | 68 | return SUCCESS; 69 | } 70 | 71 | int Crypto::generateRsaKeypair(EVP_PKEY **keypair) { 72 | EVP_PKEY_CTX *context = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); 73 | 74 | if(EVP_PKEY_keygen_init(context) <= 0) { 75 | return FAILURE; 76 | } 77 | 78 | if(EVP_PKEY_CTX_set_rsa_keygen_bits(context, RSA_KEYLEN) <= 0) { 79 | return FAILURE; 80 | } 81 | 82 | if(EVP_PKEY_keygen(context, keypair) <= 0) { 83 | return FAILURE; 84 | } 85 | 86 | EVP_PKEY_CTX_free(context); 87 | 88 | return SUCCESS; 89 | } 90 | 91 | int Crypto::generateAesKey(unsigned char **aesKey, unsigned char **aesIv) { 92 | *aesKey = (unsigned char*)malloc(aesKeyLength); 93 | *aesIv = (unsigned char*)malloc(aesIvLength); 94 | 95 | if(*aesKey == NULL || *aesIv == NULL) { 96 | return FAILURE; 97 | } 98 | 99 | // For the AES key we have the option of using a PBKDF or just using straight random 100 | // data for the key and IV. Depending on your use case, you will want to pick one or another. 101 | #ifdef USE_PBKDF 102 | unsigned char *aesPass = (unsigned char*)malloc(aesKeyLength); 103 | unsigned char *aesSalt = (unsigned char*)malloc(8); 104 | 105 | if(aesPass == NULL || aesSalt == NULL) { 106 | return FAILURE; 107 | } 108 | 109 | // Get some random data to use as the AES pass and salt 110 | if(RAND_bytes(aesPass, aesKeyLength) == 0) { 111 | return FAILURE; 112 | } 113 | 114 | if(RAND_bytes(aesSalt, 8) == 0) { 115 | return FAILURE; 116 | } 117 | 118 | if(EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha256(), aesSalt, aesPass, aesKeyLength, AES_ROUNDS, *aesKey, *aesIv) == 0) { 119 | return FAILURE; 120 | } 121 | 122 | free(aesPass); 123 | free(aesSalt); 124 | #else 125 | if(RAND_bytes(*aesKey, aesKeyLength) == 0) { 126 | return FAILURE; 127 | } 128 | 129 | if(RAND_bytes(*aesIv, aesIvLength) == 0) { 130 | return FAILURE; 131 | } 132 | #endif 133 | 134 | return SUCCESS; 135 | } 136 | 137 | int Crypto::rsaEncrypt(const unsigned char *message, size_t messageLength, unsigned char **encryptedMessage, unsigned char **encryptedKey, 138 | size_t *encryptedKeyLength, unsigned char **iv, size_t *ivLength) { 139 | 140 | // Allocate memory for everything 141 | size_t encryptedMessageLength = 0; 142 | size_t blockLength = 0; 143 | 144 | *encryptedKey = (unsigned char*)malloc(EVP_PKEY_size(remotePublicKey)); 145 | *iv = (unsigned char*)malloc(EVP_MAX_IV_LENGTH); 146 | *ivLength = EVP_MAX_IV_LENGTH; 147 | 148 | if(*encryptedKey == NULL || *iv == NULL) { 149 | return FAILURE; 150 | } 151 | 152 | *encryptedMessage = (unsigned char*)malloc(messageLength + EVP_MAX_IV_LENGTH); 153 | if(encryptedMessage == NULL) { 154 | return FAILURE; 155 | } 156 | 157 | // Encrypt it! 158 | if(!EVP_SealInit(rsaEncryptContext, EVP_aes_256_cbc(), encryptedKey, (int*)encryptedKeyLength, *iv, &remotePublicKey, 1)) { 159 | return FAILURE; 160 | } 161 | 162 | if(!EVP_SealUpdate(rsaEncryptContext, *encryptedMessage + encryptedMessageLength, (int*)&blockLength, (const unsigned char*)message, (int)messageLength)) { 163 | return FAILURE; 164 | } 165 | encryptedMessageLength += blockLength; 166 | 167 | if(!EVP_SealFinal(rsaEncryptContext, *encryptedMessage + encryptedMessageLength, (int*)&blockLength)) { 168 | return FAILURE; 169 | } 170 | encryptedMessageLength += blockLength; 171 | 172 | return (int)encryptedMessageLength; 173 | } 174 | 175 | int Crypto::rsaDecrypt(unsigned char *encryptedMessage, size_t encryptedMessageLength, unsigned char *encryptedKey, 176 | size_t encryptedKeyLength, unsigned char *iv, size_t ivLength, unsigned char **decryptedMessage) { 177 | 178 | // Allocate memory for everything 179 | size_t decryptedMessageLength = 0; 180 | size_t blockLength = 0; 181 | 182 | *decryptedMessage = (unsigned char*)malloc(encryptedMessageLength + ivLength); 183 | if(*decryptedMessage == NULL) { 184 | return FAILURE; 185 | } 186 | 187 | #ifdef PSEUDO_CLIENT 188 | EVP_PKEY *key = remotePublicKey; 189 | #else 190 | EVP_PKEY *key = localKeypair; 191 | #endif 192 | 193 | // Decrypt it! 194 | if(!EVP_OpenInit(rsaDecryptContext, EVP_aes_256_cbc(), encryptedKey, encryptedKeyLength, iv, key)) { 195 | return FAILURE; 196 | } 197 | 198 | if(!EVP_OpenUpdate(rsaDecryptContext, (unsigned char*)*decryptedMessage + decryptedMessageLength, (int*)&blockLength, encryptedMessage, (int)encryptedMessageLength)) { 199 | return FAILURE; 200 | } 201 | decryptedMessageLength += blockLength; 202 | 203 | if(!EVP_OpenFinal(rsaDecryptContext, (unsigned char*)*decryptedMessage + decryptedMessageLength, (int*)&blockLength)) { 204 | return FAILURE; 205 | } 206 | decryptedMessageLength += blockLength; 207 | 208 | return (int)decryptedMessageLength; 209 | } 210 | 211 | int Crypto::aesEncrypt(const unsigned char *message, size_t messageLength, unsigned char **encryptedMessage) { 212 | // Allocate memory for everything 213 | size_t blockLength = 0; 214 | size_t encryptedMessageLength = 0; 215 | 216 | *encryptedMessage = (unsigned char*)malloc(messageLength + AES_BLOCK_SIZE); 217 | if(encryptedMessage == NULL) { 218 | return FAILURE; 219 | } 220 | 221 | // Encrypt it! 222 | if(!EVP_EncryptInit_ex(aesEncryptContext, EVP_aes_256_cbc(), NULL, aesKey, aesIv)) { 223 | return FAILURE; 224 | } 225 | 226 | if(!EVP_EncryptUpdate(aesEncryptContext, *encryptedMessage, (int*)&blockLength, (unsigned char*)message, messageLength)) { 227 | return FAILURE; 228 | } 229 | encryptedMessageLength += blockLength; 230 | 231 | if(!EVP_EncryptFinal_ex(aesEncryptContext, *encryptedMessage + encryptedMessageLength, (int*)&blockLength)) { 232 | return FAILURE; 233 | } 234 | 235 | return encryptedMessageLength + blockLength; 236 | } 237 | 238 | int Crypto::aesDecrypt(unsigned char *encryptedMessage, size_t encryptedMessageLength, unsigned char **decryptedMessage) { 239 | // Allocate memory for everything 240 | size_t decryptedMessageLength = 0; 241 | size_t blockLength = 0; 242 | 243 | *decryptedMessage = (unsigned char*)malloc(encryptedMessageLength); 244 | if(*decryptedMessage == NULL) { 245 | return FAILURE; 246 | } 247 | 248 | // Decrypt it! 249 | if(!EVP_DecryptInit_ex(aesDecryptContext, EVP_aes_256_cbc(), NULL, aesKey, aesIv)) { 250 | return FAILURE; 251 | } 252 | 253 | if(!EVP_DecryptUpdate(aesDecryptContext, (unsigned char*)*decryptedMessage, (int*)&blockLength, encryptedMessage, (int)encryptedMessageLength)) { 254 | return FAILURE; 255 | } 256 | decryptedMessageLength += blockLength; 257 | 258 | if(!EVP_DecryptFinal_ex(aesDecryptContext, (unsigned char*)*decryptedMessage + decryptedMessageLength, (int*)&blockLength)) { 259 | return FAILURE; 260 | } 261 | decryptedMessageLength += blockLength; 262 | 263 | return (int)decryptedMessageLength; 264 | } 265 | 266 | int Crypto::getRemotePublicKey(unsigned char **publicKey) { 267 | BIO *bio = BIO_new(BIO_s_mem()); 268 | PEM_write_bio_PUBKEY(bio, remotePublicKey); 269 | return bioToString(bio, publicKey); 270 | } 271 | 272 | int Crypto::setRemotePublicKey(unsigned char *publicKey, size_t publicKeyLength) { 273 | BIO *bio = BIO_new(BIO_s_mem()); 274 | 275 | if(BIO_write(bio, publicKey, publicKeyLength) != (int)publicKeyLength) { 276 | return FAILURE; 277 | } 278 | 279 | PEM_read_bio_PUBKEY(bio, &remotePublicKey, NULL, NULL); 280 | BIO_free_all(bio); 281 | 282 | return SUCCESS; 283 | } 284 | 285 | int Crypto::getLocalPublicKey(unsigned char **publicKey) { 286 | BIO *bio = BIO_new(BIO_s_mem()); 287 | PEM_write_bio_PUBKEY(bio, localKeypair); 288 | return bioToString(bio, publicKey); 289 | } 290 | 291 | int Crypto::getLocalPrivateKey(unsigned char **privateKey) { 292 | BIO *bio = BIO_new(BIO_s_mem()); 293 | PEM_write_bio_PrivateKey(bio, localKeypair, NULL, NULL, 0, 0, NULL); 294 | return bioToString(bio, privateKey); 295 | } 296 | 297 | int Crypto::getAesKey(unsigned char **aesKey) { 298 | *aesKey = this->aesKey; 299 | return aesKeyLength; 300 | } 301 | 302 | int Crypto::setAesKey(unsigned char *aesKey, size_t aesKeyLengthgth) { 303 | // Ensure the new key is the proper size 304 | if(aesKeyLengthgth != aesKeyLength) { 305 | return FAILURE; 306 | } 307 | 308 | memcpy(this->aesKey, aesKey, aesKeyLength); 309 | 310 | return SUCCESS; 311 | } 312 | 313 | int Crypto::getAesIv(unsigned char **aesIv) { 314 | *aesIv = this->aesIv; 315 | return aesIvLength; 316 | } 317 | 318 | int Crypto::setAesIv(unsigned char *aesIv, size_t aesIvLengthgth) { 319 | // Ensure the new IV is the proper size 320 | if(aesIvLengthgth != aesIvLength) { 321 | return FAILURE; 322 | } 323 | 324 | memcpy(this->aesIv, aesIv, aesIvLength); 325 | 326 | return SUCCESS; 327 | } 328 | 329 | int Crypto::writeKeyToFile(FILE *file, int key) { 330 | switch(key) { 331 | case KEY_SERVER_PRI: 332 | if(!PEM_write_PrivateKey(file, localKeypair, NULL, NULL, 0, 0, NULL)) { 333 | return FAILURE; 334 | } 335 | break; 336 | 337 | case KEY_SERVER_PUB: 338 | if(!PEM_write_PUBKEY(file, localKeypair)) { 339 | return FAILURE; 340 | } 341 | break; 342 | 343 | case KEY_CLIENT_PUB: 344 | if(!PEM_write_PUBKEY(file, remotePublicKey)) { 345 | return FAILURE; 346 | } 347 | break; 348 | 349 | case KEY_AES: 350 | fwrite(aesKey, 1, aesKeyLength * 8, file); 351 | break; 352 | 353 | case KEY_AES_IV: 354 | fwrite(aesIv, 1, aesIvLength * 8, file); 355 | break; 356 | 357 | default: 358 | return FAILURE; 359 | } 360 | 361 | return SUCCESS; 362 | } 363 | 364 | int Crypto::bioToString(BIO *bio, unsigned char **string) { 365 | size_t bioLength = BIO_pending(bio); 366 | *string = (unsigned char*)malloc(bioLength + 1); 367 | 368 | if(string == NULL) { 369 | return FAILURE; 370 | } 371 | 372 | BIO_read(bio, *string, bioLength); 373 | 374 | // Insert the NUL terminator 375 | (*string)[bioLength] = '\0'; 376 | 377 | BIO_free_all(bio); 378 | 379 | return (int)bioLength; 380 | } 381 | -------------------------------------------------------------------------------- /Crypto.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #ifndef CRYPTO_H 11 | #define CRYPTO_H 12 | 13 | #define RSA_KEYLEN 2048 14 | #define AES_ROUNDS 6 15 | 16 | #define PSEUDO_CLIENT 17 | 18 | //#define USE_PBKDF 19 | 20 | #define SUCCESS 0 21 | #define FAILURE -1 22 | 23 | #define KEY_SERVER_PRI 0 24 | #define KEY_SERVER_PUB 1 25 | #define KEY_CLIENT_PUB 2 26 | #define KEY_AES 3 27 | #define KEY_AES_IV 4 28 | 29 | class Crypto { 30 | public: 31 | Crypto(); 32 | Crypto(unsigned char *remotePubKey, size_t remotePubKeyLen); 33 | ~Crypto(); 34 | 35 | int rsaEncrypt(const unsigned char *message, size_t messageLength, unsigned char **encryptedMessage, unsigned char **encryptedKey, 36 | size_t *encryptedKeyLength, unsigned char **iv, size_t *ivLength); 37 | int rsaDecrypt(unsigned char *encryptedMessage, size_t encryptedMessageLength, unsigned char *encryptedKey, size_t encryptedKeyLength, 38 | unsigned char *iv, size_t ivLength, unsigned char **decryptedMessage); 39 | 40 | int aesEncrypt(const unsigned char *message, size_t messageLength, unsigned char **encryptedMessage); 41 | int aesDecrypt(unsigned char *encryptedMessage, size_t encryptedMessageLength, unsigned char **decryptedMessage); 42 | 43 | int getRemotePublicKey(unsigned char **publicKey); 44 | int setRemotePublicKey(unsigned char *publicKey, size_t publicKeyLength); 45 | 46 | int getLocalPublicKey(unsigned char **publicKey); 47 | int getLocalPrivateKey(unsigned char **privateKey); 48 | 49 | int getAesKey(unsigned char **aesKey); 50 | int setAesKey(unsigned char *aesKey, size_t aesKeyLen); 51 | 52 | int getAesIv(unsigned char **aesIv); 53 | int setAesIv(unsigned char *aesIv, size_t aesIvLen); 54 | 55 | int writeKeyToFile(FILE *file, int key); 56 | 57 | private: 58 | static EVP_PKEY *localKeypair; 59 | EVP_PKEY *remotePublicKey; 60 | 61 | EVP_CIPHER_CTX *rsaEncryptContext; 62 | EVP_CIPHER_CTX *aesEncryptContext; 63 | 64 | EVP_CIPHER_CTX *rsaDecryptContext; 65 | EVP_CIPHER_CTX *aesDecryptContext; 66 | 67 | unsigned char *aesKey; 68 | unsigned char *aesIv; 69 | 70 | size_t aesKeyLength; 71 | size_t aesIvLength; 72 | 73 | int init(); 74 | int generateRsaKeypair(EVP_PKEY **keypair); 75 | int generateAesKey(unsigned char **aesKey, unsigned char **aesIv); 76 | int bioToString(BIO *bio, unsigned char **string); 77 | }; 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Shane Tully 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC = g++ 2 | CFLAGS = -Wall -Wextra -ggdb 3 | LIBS = -lcrypto 4 | SRC = base64.cpp Crypto.cpp 5 | 6 | EXAMPLE_TARGET = crypto_example 7 | FILE_EXAMPLE_TARGET = crypto_file_example 8 | 9 | .PHONY: all text file test clean 10 | 11 | all: text file 12 | 13 | text: 14 | $(CC) $(CFLAGS) -o $(EXAMPLE_TARGET) $(SRC) crypto_example.cpp $(LIBS) 15 | 16 | file: 17 | $(CC) $(CFLAGS) -o $(FILE_EXAMPLE_TARGET) $(SRC) crypto_file_example.cpp $(LIBS) 18 | 19 | exec: 20 | ./$(EXAMPLE_TARGET) 21 | 22 | file_exec: 23 | ./$(FILE_EXAMPLE_TARGET) lorem_ipsum.txt 24 | 25 | clean: 26 | rm $(EXAMPLE_TARGET) $(FILE_EXAMPLE_TARGET) 27 | 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Crypto-Example 2 | ============== 3 | 4 | #### shane tully (shanetully.com) 5 | 6 | A short, proof-of-concept RSA and AES encryption program with OpenSSL. 7 | 8 | Accompanying documentation and walk-through is available at: https://shanetully.com/2012/06/openssl-rsa-aes-and-c/ 9 | 10 | This example builds two binaries: 11 | 12 | 1. `crypto_example` reads from stdin and encrypts/decrypts strings in RSA & AES. 13 | 2. `crypto_file_example` takes a file as an argument, encrypts it with AES, writes it to a file base64 encoded, reads it back, decrypts it, and writes the decrypted file out. 14 | 15 | ## Usage 16 | 17 | ### Prerequisites 18 | 19 | You must have a recent version of OpenSSL installed before building. 20 | 21 | ### Compiling & Running 22 | 23 | ``` 24 | $ make 25 | $ make exec # Runs the `crypto_example` binary 26 | $ make file_exec # Runs the `crypto_file_example` binary on a lorem ipsum text file 27 | ``` 28 | 29 | ## Problems? 30 | 31 | Despite going long periods of time without being updated, this repo is actively maintained. Being an example that I don't check often, I rely on users for reports if something breaks. Issues and pull requests are greatly appreciated. 32 | 33 | ## License 34 | 35 | The MIT License (MIT) 36 | 37 | Copyright (c) 2013 Shane Tully 38 | 39 | Permission is hereby granted, free of charge, to any person obtaining a copy 40 | of this software and associated documentation files (the "Software"), to deal 41 | in the Software without restriction, including without limitation the rights 42 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 43 | copies of the Software, and to permit persons to whom the Software is 44 | furnished to do so, subject to the following conditions: 45 | 46 | The above copyright notice and this permission notice shall be included in 47 | all copies or substantial portions of the Software. 48 | 49 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 50 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 51 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 52 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 53 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 54 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 55 | THE SOFTWARE. 56 | -------------------------------------------------------------------------------- /base64.cpp: -------------------------------------------------------------------------------- 1 | #include "base64.h" 2 | 3 | char* base64Encode(const unsigned char *message, const size_t length) { 4 | int encodedSize = 4 * ceil((double)length / 3); 5 | char *encodedMessage = (char*)malloc(encodedSize + 1); 6 | 7 | if(encodedMessage == NULL) { 8 | fprintf(stderr, "Failed to allocate memory\n"); 9 | exit(1); 10 | } 11 | 12 | BIO *b64 = BIO_new(BIO_f_base64()); 13 | BIO *bio = BIO_new(BIO_s_mem()); 14 | bio = BIO_push(b64, bio); 15 | BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); 16 | 17 | BIO_write(bio, message, length); 18 | BIO_flush(bio); 19 | 20 | BUF_MEM *bufferPtr; 21 | BIO_get_mem_ptr(bio, &bufferPtr); 22 | BIO_set_close(bio, BIO_CLOSE); 23 | 24 | // Add a NUL terminator 25 | memcpy(encodedMessage, (*bufferPtr).data, (*bufferPtr).length + 1); 26 | encodedMessage[(*bufferPtr).length] = '\0'; 27 | 28 | BIO_free_all(bio); 29 | return encodedMessage; 30 | } 31 | 32 | int base64Decode(const char *encodedMessage, const size_t encodedMessageLength, unsigned char **decodedMessage) { 33 | int decodedLength = calculateDecodedLength(encodedMessage, encodedMessageLength); 34 | *decodedMessage = (unsigned char*)malloc(decodedLength + 1); 35 | 36 | if(*decodedMessage == NULL) { 37 | fprintf(stderr, "Failed to allocate memory\n"); 38 | exit(1); 39 | } 40 | 41 | BIO *bio = BIO_new_mem_buf(encodedMessage, encodedMessageLength); 42 | BIO *b64 = BIO_new(BIO_f_base64()); 43 | bio = BIO_push(b64, bio); 44 | BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); 45 | 46 | // Add a NUL terminator 47 | decodedLength = BIO_read(bio, *decodedMessage, encodedMessageLength); 48 | (*decodedMessage)[decodedLength] = '\0'; 49 | 50 | BIO_free_all(bio); 51 | 52 | return decodedLength; 53 | } 54 | 55 | int calculateDecodedLength(const char *encodedMessage, const size_t encodedMessageLength) { 56 | unsigned int padding = 0; 57 | 58 | // Check for trailing '=''s as padding 59 | if(encodedMessage[encodedMessageLength - 1] == '=' && encodedMessage[encodedMessageLength - 2] == '=') { 60 | padding = 2; 61 | } else if (encodedMessage[encodedMessageLength - 1] == '=') { 62 | padding = 1; 63 | } 64 | 65 | return (int)encodedMessageLength * 0.75 - padding; 66 | } 67 | -------------------------------------------------------------------------------- /base64.h: -------------------------------------------------------------------------------- 1 | #ifndef BASE64_H 2 | #define BASE64_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | char* base64Encode(const unsigned char *message, const size_t length); 13 | int base64Decode(const char *encodedMessage, const size_t encodedMessageLength, unsigned char **decodedMessage); 14 | int calculateDecodedLength(const char *b64input, const size_t length); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /crypto_example.cpp: -------------------------------------------------------------------------------- 1 | #include "crypto_example.h" 2 | 3 | using std::string; 4 | using std::cin; 5 | 6 | int main() { 7 | Crypto crypto; 8 | 9 | #ifdef PRINT_KEYS 10 | printKeys(&crypto); 11 | #endif 12 | 13 | while(!std::cin.eof()) { 14 | encryptRsa(&crypto); 15 | encryptAes(&crypto); 16 | } 17 | 18 | return 0; 19 | } 20 | 21 | void encryptRsa(Crypto *crypto) { 22 | // Get the message to encrypt 23 | string message = getMessage("Message to RSA encrypt: "); 24 | 25 | // Encrypt the message with RSA 26 | unsigned char *encryptedMessage = NULL; 27 | unsigned char *encryptedKey; 28 | unsigned char *iv; 29 | size_t encryptedKeyLength; 30 | size_t ivLength; 31 | 32 | // +1 on the string length argument because we want to encrypt the NUL terminator too 33 | int encryptedMessageLength = crypto->rsaEncrypt((const unsigned char*)message.c_str(), message.size()+1, 34 | &encryptedMessage, &encryptedKey, &encryptedKeyLength, &iv, &ivLength); 35 | 36 | if(encryptedMessageLength == -1) { 37 | fprintf(stderr, "Encryption failed\n"); 38 | return; 39 | } 40 | 41 | // Print the encrypted message as a base64 string 42 | char* b64Message = base64Encode(encryptedMessage, encryptedMessageLength); 43 | printf("Encrypted message: %s\n", b64Message); 44 | 45 | // Decrypt the message 46 | char *decryptedMessage = NULL; 47 | 48 | int decryptedMessageLength = crypto->rsaDecrypt(encryptedMessage, (size_t)encryptedMessageLength, 49 | encryptedKey, encryptedKeyLength, iv, ivLength, (unsigned char**)&decryptedMessage); 50 | 51 | if(decryptedMessageLength == -1) { 52 | fprintf(stderr, "Decryption failed\n"); 53 | return; 54 | } 55 | 56 | printf("Decrypted message: %s\n", decryptedMessage); 57 | 58 | // Clean up 59 | free(encryptedMessage); 60 | free(decryptedMessage); 61 | free(encryptedKey); 62 | free(iv); 63 | free(b64Message); 64 | } 65 | 66 | void encryptAes(Crypto *crypto) { 67 | // Get the message to encrypt 68 | string message = getMessage("Message to AES encrypt: "); 69 | 70 | // Encrypt the message with AES 71 | unsigned char *encryptedMessage = NULL; 72 | int encryptedMessageLength = crypto->aesEncrypt((const unsigned char*)message.c_str(), message.size()+1, &encryptedMessage); 73 | 74 | if(encryptedMessageLength == -1) { 75 | fprintf(stderr, "Encryption failed\n"); 76 | return; 77 | } 78 | 79 | // Print the encrypted message as a base64 string 80 | char *b64Message = base64Encode(encryptedMessage, encryptedMessageLength); 81 | printf("Encrypted message: %s\n", b64Message); 82 | 83 | // Decrypt the message 84 | char *decryptedMessage = NULL; 85 | int decryptedMessageLength = crypto->aesDecrypt(encryptedMessage, (size_t)encryptedMessageLength, (unsigned char**)&decryptedMessage); 86 | 87 | if(decryptedMessageLength == -1) { 88 | fprintf(stderr, "Decryption failed\n"); 89 | return; 90 | } 91 | 92 | printf("Decrypted message: %s\n", decryptedMessage); 93 | 94 | // Clean up 95 | free(encryptedMessage); 96 | free(decryptedMessage); 97 | free(b64Message); 98 | } 99 | 100 | string getMessage(const char *prompt) { 101 | string message; 102 | 103 | printf(prompt); 104 | fflush(stdout); 105 | 106 | getline(std::cin, message); 107 | return message; 108 | } 109 | 110 | void printKeys(Crypto *crypto) { 111 | // Write the RSA keys to stdout 112 | crypto->writeKeyToFile(stdout, KEY_SERVER_PRI); 113 | crypto->writeKeyToFile(stdout, KEY_SERVER_PUB); 114 | crypto->writeKeyToFile(stdout, KEY_CLIENT_PUB); 115 | 116 | // Write the AES key to stdout in hex 117 | unsigned char *aesKey; 118 | size_t aesKeyLength = crypto->getAesKey(&aesKey); 119 | printBytesAsHex(aesKey, aesKeyLength, "AES Key"); 120 | 121 | // Write the AES IV to stdout in hex 122 | unsigned char *aesIv; 123 | size_t aesIvLength = crypto->getAesIv(&aesIv); 124 | printBytesAsHex(aesIv, aesIvLength, "AES IV"); 125 | } 126 | 127 | void printBytesAsHex(unsigned char *bytes, size_t length, const char *message) { 128 | printf("%s: ", message); 129 | 130 | for(unsigned int i=0; i 5 | #include 6 | #include 7 | 8 | #include "base64.h" 9 | #include "Crypto.h" 10 | 11 | // #define PRINT_KEYS 12 | 13 | void encryptRsa(Crypto *crypto); 14 | void encryptAes(Crypto *crypto); 15 | void printKeys(Crypto *crypto); 16 | void printBytesAsHex(unsigned char *bytes, size_t length, const char *message); 17 | std::string getMessage(const char *prompt); 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /crypto_file_example.cpp: -------------------------------------------------------------------------------- 1 | #include "crypto_file_example.h" 2 | 3 | // Note: This isn't a good way to encrypt large file (anything that can't be read into 4 | // memory in a single buffer). A better approach for this is to read in one block at a type, 5 | // encrypt it, write it to a file, and so on. 6 | 7 | int main(int argc, char **argv) { 8 | if(argc != 2) { 9 | fprintf(stderr, "Invalid number of arguments given.\nUsage: %s [input file]\n", argv[0]); 10 | return 1; 11 | } 12 | 13 | Crypto crypto; 14 | 15 | char *encryptedOutput = appendToString(argv[1], (char*)".enc"); 16 | char *decryptedOutput = appendToString(argv[1], (char*)".dec"); 17 | 18 | encryptFile(&crypto, argv[1], encryptedOutput); 19 | decryptFile(&crypto, encryptedOutput, decryptedOutput); 20 | 21 | free(encryptedOutput); 22 | free(decryptedOutput); 23 | 24 | return 0; 25 | } 26 | 27 | void encryptFile(Crypto *crypto, char *input, char *output) { 28 | // Read the file to encrypt 29 | unsigned char *plaintext; 30 | size_t plainTextLength = readFile(input, &plaintext); 31 | printf("%d bytes to be encrypted\n", (int)plainTextLength); 32 | 33 | // Encrypt the file 34 | unsigned char *ciphertext; 35 | int ciphertextLength = crypto->aesEncrypt((const unsigned char*)plaintext, plainTextLength, &ciphertext); 36 | 37 | if(ciphertextLength == -1) { 38 | fprintf(stderr, "Encryption failed\n"); 39 | exit(1); 40 | } 41 | printf("%d bytes encrypted\n", ciphertextLength); 42 | 43 | // Encode the encrypted file to base64 44 | char *base64Ciphertext = base64Encode(ciphertext, ciphertextLength); 45 | 46 | // Write the encrypted file to its own file 47 | writeFile(output, (unsigned char*)base64Ciphertext, strlen((char*)base64Ciphertext)); 48 | printf("Encrypted file written to \"%s\"\n", output); 49 | 50 | free(plaintext); 51 | free(ciphertext); 52 | free(base64Ciphertext); 53 | } 54 | 55 | void decryptFile(Crypto *crypto, char *input, char *output) { 56 | // Read the encrypted file back 57 | unsigned char *base64Ciphertext; 58 | size_t base64CiphertextLength = readFile(input, &base64Ciphertext); 59 | 60 | // Decode the encrypted file from base64 61 | unsigned char *ciphertext; 62 | size_t ciphertextLength = base64Decode((char*)base64Ciphertext, base64CiphertextLength, &ciphertext); 63 | 64 | // Decrypt the encrypted file 65 | unsigned char *plaintext; 66 | int plaintextLength = crypto->aesDecrypt(ciphertext, ciphertextLength, &plaintext); 67 | 68 | if(plaintextLength == -1) { 69 | fprintf(stderr, "Decryption failed\n"); 70 | exit(1); 71 | } 72 | printf("%d bytes decrypted\n", (int)plaintextLength); 73 | 74 | // Write the decrypted file to its own file 75 | writeFile(output, plaintext, plaintextLength); 76 | printf("Decrypted file written to \"%s\"\n", output); 77 | 78 | free(base64Ciphertext); 79 | free(ciphertext); 80 | free(plaintext); 81 | } 82 | 83 | void writeFile(char *filename, unsigned char *file, size_t fileLength) { 84 | FILE *fd = fopen(filename, "w"); 85 | if(fd == NULL) { 86 | fprintf(stderr, "Failed to open file: %s\n", strerror(errno)); 87 | exit(1); 88 | } 89 | 90 | size_t bytesWritten = fwrite(file, 1, fileLength, fd); 91 | 92 | if(bytesWritten != fileLength) { 93 | fprintf(stderr, "Failed to write file\n"); 94 | exit(1); 95 | } 96 | 97 | fclose(fd); 98 | } 99 | 100 | int readFile(char *filename, unsigned char **file) { 101 | FILE *fd = fopen(filename, "r"); 102 | if(fd == NULL) { 103 | fprintf(stderr, "Failed to open file: %s\n", strerror(errno)); 104 | exit(1); 105 | } 106 | 107 | // Determine size of the file 108 | fseek(fd, 0, SEEK_END); 109 | size_t fileLength = ftell(fd); 110 | fseek(fd, 0, SEEK_SET); 111 | 112 | // Allocate space for the file 113 | *file = (unsigned char*)malloc(fileLength); 114 | if(*file == NULL) { 115 | fprintf(stderr, "Failed to allocate memory\n"); 116 | exit(1); 117 | } 118 | 119 | // Read the file into the buffer 120 | size_t bytesRead = fread(*file, 1, fileLength, fd); 121 | 122 | if(bytesRead != fileLength) { 123 | fprintf(stderr, "Error reading file\n"); 124 | exit(1); 125 | } 126 | 127 | fclose(fd); 128 | 129 | return fileLength; 130 | } 131 | 132 | char* appendToString(char *string, char *suffix) { 133 | char *appenedString = (char*)malloc(strlen(string) + strlen(suffix) + 1); 134 | 135 | if(appenedString == NULL) { 136 | fprintf(stderr, "Failed to allocate memory\n"); 137 | exit(1); 138 | } 139 | 140 | sprintf(appenedString, "%s%s", string, suffix); 141 | return appenedString; 142 | } 143 | -------------------------------------------------------------------------------- /crypto_file_example.h: -------------------------------------------------------------------------------- 1 | #ifndef CRYPTO_FILE_EXAMPLE_H 2 | #define CRYPTO_FILE_EXAMPLE_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "base64.h" 9 | #include "Crypto.h" 10 | 11 | void encryptFile(Crypto *crypto, char *input, char *output); 12 | void decryptFile(Crypto *crypto, char *input, char *output); 13 | 14 | void writeFile(char *filename, unsigned char *file, size_t fileLength); 15 | int readFile(char *filename, unsigned char **file); 16 | 17 | char* appendToString(char *string, char *suffix); 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /lorem_ipsum.txt: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut maximus felis eu aliquam luctus. Donec tempus pharetra laoreet. Cras laoreet nisi sem, ut ullamcorper sapien sollicitudin sit amet. Proin a est vitae enim blandit aliquam. Maecenas vitae turpis pretium dui vestibulum finibus in eget sem. Fusce dignissim est a ante sagittis volutpat. Donec ac molestie felis, eu ultricies velit. Proin feugiat facilisis ante ac dapibus. Morbi nec bibendum neque. 2 | -------------------------------------------------------------------------------- /sample.txt: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus scelerisque felis odio, eu hendrerit eros laoreet at. Fusce ac rutrum nisl, quis feugiat tortor. Vestibulum non urna est. Maecenas quis mi at est blandit tempor. Nullam ut quam porttitor, convallis nisl vitae, pulvinar quam. In hac habitasse platea dictumst. Aenean vehicula mauris odio, eu mattis augue tristique in. Morbi nec magna sit amet elit tempor sagittis. Suspendisse id tempor velit. Suspendisse nec velit orci. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vivamus commodo ullamcorper convallis. Nunc congue lobortis dictum. 2 | 3 | Praesent commodo mattis tempus. Fusce molestie at nisl at euismod. Fusce pulvinar porttitor turpis a iaculis. Quisque faucibus, erat et hendrerit lobortis, tellus diam sollicitudin mauris, a maximus odio nisi non diam. Maecenas velit justo, volutpat a lectus vel, malesuada placerat ante. Ut accumsan ipsum et ipsum ornare ultricies. Integer at tincidunt massa. Quisque at arcu fermentum, blandit urna vitae, lobortis ante. Mauris facilisis lectus aliquet erat pulvinar aliquet vel at sapien. Integer bibendum odio nibh, nec lobortis ligula iaculis eget. Duis vitae massa risus. In auctor neque nec dolor laoreet, eget fringilla felis egestas. Sed mattis sit amet sapien et euismod. Vivamus ac massa sapien. Praesent hendrerit lacus a lacus lobortis elementum. Aenean mollis sollicitudin turpis, sit amet rutrum enim pretium ac. 4 | 5 | Curabitur convallis varius ante, vel ultricies sem volutpat eu. Vivamus dapibus lectus vel sem blandit finibus. Curabitur sit amet felis nibh. Nulla tempor velit tortor, nec euismod lacus mattis eget. Nulla rutrum interdum est, quis scelerisque velit pellentesque sit amet. Donec iaculis nisl nec convallis suscipit. Nulla ac iaculis velit, non tristique augue. Nulla vestibulum eleifend lacus, sit amet viverra risus. Donec convallis blandit libero at feugiat. Vestibulum finibus dictum nulla, ac tempus enim auctor vitae. In hac habitasse platea dictumst. Suspendisse eu placerat felis. Nunc eget metus nec nisi egestas iaculis vel ac justo. Fusce sed rutrum neque, sed elementum magna. Sed ultrices ex molestie ligula dictum, ut mattis lorem facilisis. Vivamus a urna iaculis, blandit est vel, tempor justo. 6 | 7 | Donec efficitur, lacus non eleifend cursus, dolor nunc maximus ex, ac ultricies ante mauris eu quam. Aliquam dapibus pulvinar tincidunt. In sed nisl sit amet eros dictum laoreet sit amet sit amet mauris. Donec scelerisque porttitor arcu, blandit fermentum arcu sollicitudin at. Sed nunc velit, bibendum egestas consequat sit amet, suscipit nec arcu. Suspendisse sed ante tincidunt, venenatis velit et, varius orci. Etiam a interdum nibh, sed congue erat. Ut viverra velit eget tortor commodo, aliquam ullamcorper mi lobortis. Phasellus quis tellus sit amet libero condimentum dapibus. Pellentesque vel ex nunc. Fusce non ultricies dui. Integer dolor ipsum, hendrerit sed enim et, tincidunt lobortis nisl. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Maecenas vitae metus et neque viverra vulputate et ut sem. 8 | 9 | Mauris eget eleifend felis, in tempor augue. In feugiat tincidunt elementum. Quisque varius nibh vel quam tempor, imperdiet elementum quam sollicitudin. Pellentesque laoreet, turpis ac commodo suscipit, ligula nulla tincidunt magna, id mollis lorem nunc eget metus. Aliquam mollis lectus eleifend massa iaculis, et eleifend quam porta. Duis fermentum lectus placerat ante aliquam, rhoncus egestas velit aliquet. Proin dui augue, condimentum ut sem id, rhoncus cursus magna. Sed venenatis auctor condimentum. 10 | --------------------------------------------------------------------------------