#include #include #include #include using std::unique_ptr; #include #include #include #include #include EVP_CIPHER_CTX *ctx; RSA* rsa; BIGNUM* bn; // assumes that the digest is at least of length 256/8 bytes. uint32_t generate_sha256_hash(const unsigned char *message, size_t message_len, unsigned char *digest) { EVP_MD_CTX *mdctx; unsigned int digest_len; if((mdctx = EVP_MD_CTX_create()) == NULL) { printf("EVP_MD_CTX_create returned NULL - could not create context\n"); fflush(stdout); return 0x1; } if(EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL) != 1) { printf("EVP_DigestInit_ex returned 0 - could not initialize hash with SHA256\n"); fflush(stdout); return 0x2; } if(EVP_DigestUpdate(mdctx, message, message_len) != 1) { printf("EVP_DigestUpdate returned 0 - could not compute SHA256 hash\n"); fflush(stdout); return 0x3; } if(1 != EVP_DigestFinal_ex(mdctx, digest, &digest_len)) { printf("EVP_DigestFinal_ex returned 0 - could not finalize SHA256 hash\n"); fflush(stdout); return 0x4; } if(digest_len != 32) { printf("EVP_DigestFinal_ex returned a digest length of 0x%x instead of 0x20\n", digest_len); fflush(stdout); return 0x5; } EVP_MD_CTX_destroy(mdctx); return 0; } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////// void crypto_cleanup() { RSA_free(rsa); BN_free(bn); EVP_CIPHER_CTX_free(ctx); } // Code adapted from here: https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption int aes_gcm_128(int enc, unsigned char *key, unsigned char *iv, unsigned char* plaintext, uint32_t plaintext_len, unsigned char *ciphertext, uint32_t* op_ciphertext_len, unsigned char* tag) { int len; int ciphertext_len; if(ctx == NULL) { /* Create and initialise the context */ if(!(ctx = EVP_CIPHER_CTX_new())) { ERR_print_errors_fp(stderr); fflush(stderr);return 0x1; } } /* Initialise the encryption operation. */ if(1 != EVP_CipherInit_ex(ctx, EVP_aes_128_gcm(), NULL, key, iv, enc)) { EVP_CIPHER_CTX_init(ctx); ERR_print_errors_fp(stderr); return 0x2; } /* Provide the message to be encrypted, and obtain the encrypted output. * EVP_EncryptUpdate can be called multiple times if necessary */ if(1 != EVP_CipherUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) { EVP_CIPHER_CTX_init(ctx); ERR_print_errors_fp(stderr); return 0x3; } ciphertext_len = len; if(enc == 0) { if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag)) { EVP_CIPHER_CTX_init(ctx); ERR_print_errors_fp(stderr); fflush(stderr); return 0x5; } } /* Finalise the encryption. Normally ciphertext bytes may be written at * this stage, but this does not occur in GCM mode */ // TODO: ^^^ Why the heck does it not occur in GCM mode ? if(1 != EVP_CipherFinal_ex(ctx, ciphertext + len, &len)) { EVP_CIPHER_CTX_init(ctx); ERR_print_errors_fp(stderr); fflush(stderr); return 0x4; } ciphertext_len += len; /* Get the tag */ if(enc == 1) { if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag)) { EVP_CIPHER_CTX_init(ctx); ERR_print_errors_fp(stderr); fflush(stderr); return 0x5; } } /* Clean up */ EVP_CIPHER_CTX_init(ctx); *op_ciphertext_len=ciphertext_len; return 0; } uint32_t base64_encoding_wrapper(unsigned char* src, uint32_t length, unsigned char* dest) { return EVP_EncodeBlock(dest, src, length); } uint32_t base64_decoding_wrapper(const char* src, uint32_t length, unsigned char* dest) { int length_with_padding = EVP_DecodeBlock(dest, (const unsigned char*) src, length); if(length_with_padding == -1) return length_with_padding; char* first_equals_character = strstr((char*)src, "="); if(first_equals_character != NULL) { if(first_equals_character == (char*)src + length - 1) // the first equals character is also the last character in the string ==> Only one equals length_with_padding -= 1; else // assuming that the base64 string is valid (EVP_DecodeBlock would have thrown an error in that case). length_with_padding -= 2; } return length_with_padding; }