|
@@ -2,25 +2,66 @@
|
|
|
#include <string>
|
|
|
#include <memory>
|
|
|
using std::unique_ptr;
|
|
|
-
|
|
|
+#include <openssl/err.h>
|
|
|
#include <openssl/bn.h>
|
|
|
#include <openssl/rsa.h>
|
|
|
-#include <openssl/sha.h>
|
|
|
-using BN_ptr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>;
|
|
|
-using RSA_ptr = std::unique_ptr<RSA, decltype(&::RSA_free)>;
|
|
|
+#include <openssl/evp.h>
|
|
|
+#include <openssl/pem.h>
|
|
|
+//using BN_ptr = std::unique_ptr<BIGNUM, decltype(&::BN_free)>;
|
|
|
+//using RSA_ptr = std::unique_ptr<RSA, decltype(&::RSA_free)>;
|
|
|
+EVP_CIPHER_CTX *ctx;
|
|
|
+RSA* rsa;
|
|
|
+BIGNUM* bn;
|
|
|
+//RSA_ptr rsa_signing_keypair; //(RSA_new(), ::RSA_free);
|
|
|
+//BN_ptr rsa_bignum;
|
|
|
|
|
|
-uint32_t generate_rsa_key(std::string& priv_key_str, std::string& pub_key_str)
|
|
|
+// 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)
|
|
|
{
|
|
|
- int rc;
|
|
|
+ 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;
|
|
|
+ }
|
|
|
|
|
|
- RSA_ptr rsa(RSA_new(), ::RSA_free);
|
|
|
- BN_ptr bn(BN_new(), ::BN_free);
|
|
|
+ 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;
|
|
|
+ }
|
|
|
|
|
|
- rc = BN_set_word(bn.get(), 3);
|
|
|
+ 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;
|
|
|
+}
|
|
|
+
|
|
|
+//private:
|
|
|
+// RSA_ptr rsa(RSA_new(), ::RSA_free);
|
|
|
+// BN_ptr bn(BN_new(), ::BN_free);
|
|
|
+uint32_t generate_rsa_keypair(FILE* fp, std::string& priv_key_str, std::string& pub_key_str) //, uint8_t* hash)
|
|
|
+{
|
|
|
+ int rc;
|
|
|
+
|
|
|
+ rsa=RSA_new();
|
|
|
+ bn=BN_new();
|
|
|
+ rc = BN_set_word(bn, 3);
|
|
|
if(rc != 1)
|
|
|
return 0x1;
|
|
|
|
|
|
- rc = RSA_generate_key_ex(rsa.get(), 3072, bn.get(), NULL);
|
|
|
+ rc = RSA_generate_key_ex(rsa, 3072, bn, NULL);
|
|
|
if(rc != 1)
|
|
|
return 0x2;
|
|
|
printf("Generated key\n"); fflush(stdout);
|
|
@@ -40,9 +81,25 @@ uint32_t generate_rsa_key(std::string& priv_key_str, std::string& pub_key_str)
|
|
|
// priv_key_str=std::string(priv_key_der, priv_key_der_encoded_len); //, priv_key_der);
|
|
|
// pub_key_str=std::string(pub_key_der, pub_key_der_encoded_len);
|
|
|
*/
|
|
|
+// BIO* bio_rsa;
|
|
|
+ rc = PEM_write_RSA_PUBKEY(fp, rsa); // doesn't work
|
|
|
+ if(rc != 1)
|
|
|
+ return 0x3;
|
|
|
+ fflush(fp);
|
|
|
+// bio_rsa = BIO_new_file("apache_signature_keypair.pem", "w+");
|
|
|
+// rc = PEM_write_bio_RSAPublicKey(bio_rsa, rsa.get());
|
|
|
+// if(rc != 1)
|
|
|
+// return 0x3;
|
|
|
+ // BIO_flush(bio_rsa); free(bio_rsa);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
+uint32_t generate_rsa_keypair_hash(uint8_t* hash)
|
|
|
+{
|
|
|
+ uint32_t return_internal;
|
|
|
const BIGNUM* n_internal_bigendian_struct;
|
|
|
- RSA_get0_key(rsa.get(), &n_internal_bigendian_struct, NULL, NULL);
|
|
|
+ RSA_get0_key(rsa, &n_internal_bigendian_struct, NULL, NULL);
|
|
|
BIGNUM* n_bigendian_struct = BN_dup(n_internal_bigendian_struct);
|
|
|
|
|
|
uint32_t count;
|
|
@@ -52,15 +109,110 @@ uint32_t generate_rsa_key(std::string& priv_key_str, std::string& pub_key_str)
|
|
|
unsigned char* n_littleendian = (unsigned char*) malloc(length_bignum_le);
|
|
|
for(count=0; count<length_bignum_le; count++)
|
|
|
n_littleendian[count] = n_bigendian[length_bignum_le-count-1];
|
|
|
- unsigned char hash[SHA256_DIGEST_LENGTH];
|
|
|
- SHA256_CTX sha256;
|
|
|
- SHA256_Init(&sha256);
|
|
|
- SHA256_Update(&sha256, n_littleendian, length_bignum_le);
|
|
|
- SHA256_Final(hash, &sha256);
|
|
|
-// TODO: Return hash of the public key for now
|
|
|
-// TODO: Print public key
|
|
|
-// TODO: Use EVP funs - https://www.openssl.org/docs/man1.1.0/crypto/EVP_DigestInit.html
|
|
|
- free(n_bigendian); free(n_littleendian);
|
|
|
- return 0; //length_bignum_le;
|
|
|
+ free(n_bigendian);
|
|
|
+// unsigned char hash[32];
|
|
|
+ return_internal=generate_sha256_hash(n_littleendian, length_bignum_le, hash);
|
|
|
+ free(n_littleendian);
|
|
|
+ if(return_internal != 0)
|
|
|
+ { return return_internal ; }// TODO: Memory leak here.
|
|
|
+
|
|
|
+ for(count=0;count<32; count++)
|
|
|
+ printf("%x", hash[count]);
|
|
|
+ printf("\n");
|
|
|
+ fflush(stdout);
|
|
|
+ return return_internal;
|
|
|
+// return 0; //length_bignum_le;
|
|
|
+}
|
|
|
+
|
|
|
+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_cipher(int enc, unsigned char *key, unsigned char *iv, unsigned char* plaintext, int plaintext_len, unsigned char *ciphertext, int* op_ciphertext_len, unsigned char* tag)
|
|
|
+{
|
|
|
+ int len;
|
|
|
+ int ciphertext_len;
|
|
|
+ int reset_return;
|
|
|
+ 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))
|
|
|
+ {
|
|
|
+ reset_return = EVP_CIPHER_CTX_reset(ctx);
|
|
|
+ ERR_print_errors_fp(stderr);
|
|
|
+ if(reset_return != 1)
|
|
|
+ return 0xf2;
|
|
|
+ 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))
|
|
|
+ {
|
|
|
+ reset_return = EVP_CIPHER_CTX_reset(ctx);
|
|
|
+ ERR_print_errors_fp(stderr);
|
|
|
+ if(1 != reset_return)
|
|
|
+ return 0xF3;
|
|
|
+ return 0x3;
|
|
|
+ }
|
|
|
+ ciphertext_len = len;
|
|
|
+
|
|
|
+ if(enc == 0)
|
|
|
+ {
|
|
|
+ if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag))
|
|
|
+ {
|
|
|
+ reset_return = EVP_CIPHER_CTX_reset(ctx);
|
|
|
+ ERR_print_errors_fp(stderr); fflush(stderr);
|
|
|
+ if(1 != reset_return)
|
|
|
+ return 0xF5;
|
|
|
+ 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))
|
|
|
+ {
|
|
|
+ reset_return = EVP_CIPHER_CTX_reset(ctx);
|
|
|
+ ERR_print_errors_fp(stderr); fflush(stderr);
|
|
|
+ if(1 != reset_return)
|
|
|
+ return 0xF4;
|
|
|
+ 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))
|
|
|
+ {
|
|
|
+ reset_return = EVP_CIPHER_CTX_reset(ctx);
|
|
|
+ ERR_print_errors_fp(stderr); fflush(stderr);
|
|
|
+ if(1 != reset_return)
|
|
|
+ return 0xF5;
|
|
|
+ return 0x5;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Clean up */
|
|
|
+ if(1 != EVP_CIPHER_CTX_reset(ctx))
|
|
|
+ {
|
|
|
+ ERR_print_errors_fp(stderr); fflush(stderr);
|
|
|
+ return 0xF0;
|
|
|
+ }
|
|
|
+
|
|
|
+ *op_ciphertext_len=ciphertext_len;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|