Skip to content

Commit

Permalink
HPCC-30214 Use openssl aes encrypt/decrypt functions
Browse files Browse the repository at this point in the history
Signed-off-by: Richard Chapman <[email protected]>
  • Loading branch information
richardkchapman committed Nov 15, 2023
1 parent f60821d commit 4717a5c
Show file tree
Hide file tree
Showing 3 changed files with 239 additions and 2 deletions.
182 changes: 182 additions & 0 deletions system/jlib/jencrypt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
#ifdef _USE_OPENSSL

#include "ske.hpp"
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <string.h>

#endif

Expand Down Expand Up @@ -1829,19 +1833,195 @@ size_t aesDecrypt(const void *key, size_t keylen, const void *input, size_t inle

} // end of namespace jlib

#ifdef _USE_OPENSSL
namespace openssl {

static void encryptError(const char *what)
{
VStringBuffer s("openssl::aesEncrypt: %s", what);
throw makeStringException(0, s.str());
}

MemoryBuffer &aesEncrypt(const void *key, size_t keylen, const void *plaintext, size_t plaintext_len, MemoryBuffer &output)
{
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (!ctx)
encryptError("Failed to create context");
try
{
unsigned char iv[16] = { 0 };
switch (keylen)
{
case 32:
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, (const unsigned char *) key, iv))
encryptError("Failed to initialize context");
break;
case 24:
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_192_cbc(), NULL, (const unsigned char *) key, iv))
encryptError("Failed to initialize context");
break;
case 16:
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, (const unsigned char *) key, iv))
encryptError("Failed to initialize context");
break;
default:
encryptError("Unsupported key length");
break;
}
byte *ciphertext = (byte *) output.reserve(plaintext_len + 100);
int ciphertext_len = 0;
int thislen = 0;
if(1 != EVP_EncryptUpdate(ctx, ciphertext, &thislen, (const unsigned char *) plaintext, plaintext_len))
encryptError("Error in EVP_EncryptUpdate");
ciphertext_len += thislen;
if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + ciphertext_len, &thislen))
encryptError("Error in EVP_EncryptFinal_ex");
ciphertext_len += thislen;
EVP_CIPHER_CTX_free(ctx);
output.setLength(ciphertext_len);
return output;
}
catch (...)
{
EVP_CIPHER_CTX_free(ctx);
throw;
}
}

static void decryptError(const char *what)
{
VStringBuffer s("openssl::aesDecrypt: unexpected failure in %s", what);
throw makeStringException(0, s.str());
}

MemoryBuffer &aesDecrypt(const void *key, size_t keylen, const void *ciphertext, size_t ciphertext_len, MemoryBuffer &output)
{
EVP_CIPHER_CTX *ctx;

int thislen = 0;
int plaintext_len = 0;

if(!(ctx = EVP_CIPHER_CTX_new()))
decryptError("Failed to create context");
try
{
unsigned char iv[16] = { 0 };
switch (keylen)
{
case 32:
if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, (const unsigned char *) key, iv))
decryptError("Failed to initialize context");
break;
case 24:
if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_192_cbc(), NULL, (const unsigned char *) key, iv))
decryptError("Failed to initialize context");
break;
case 16:
if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, (const unsigned char *) key, iv))
decryptError("Failed to initialize context");
break;
default:
decryptError("Unsupported key length");
break;
}
byte *plaintext = (byte *) output.reserve(ciphertext_len + 100);
if(1 != EVP_DecryptUpdate(ctx, plaintext, &thislen, (const unsigned char *) ciphertext, ciphertext_len))
decryptError("Error in EVP_DecryptUpdate");
plaintext_len += thislen;

if(1 != EVP_DecryptFinal_ex(ctx, plaintext + plaintext_len, &thislen))
decryptError("Error in EVP_DecryptFinal_ex");
plaintext_len += thislen;
EVP_CIPHER_CTX_free(ctx);
return output;
}
catch (...)
{
EVP_CIPHER_CTX_free(ctx);
throw;
}
}

size_t aesDecrypt(const void *key, size_t keylen, const void *ciphertext, size_t ciphertext_len, void *output, size_t outlen)
{
EVP_CIPHER_CTX *ctx;

int thislen = 0;
size_t plaintext_len = 0;

if(!(ctx = EVP_CIPHER_CTX_new()))
decryptError("Failed to create context");

try
{
if (outlen < ciphertext_len)
decryptError("output length too small"); // MORE - not sure this is actually true?
unsigned char iv[16] = { 0 };
switch (keylen)
{
case 32:
if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, (const unsigned char *) key, iv))
decryptError("Failed to initialize context");
break;
case 24:
if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_192_cbc(), NULL, (const unsigned char *) key, iv))
decryptError("Failed to initialize context");
break;
case 16:
if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, (const unsigned char *) key, iv))
decryptError("Failed to initialize context");
break;
default:
decryptError("Unsupported key length");
break;
}
byte *plaintext = (byte *) output;
if(1 != EVP_DecryptUpdate(ctx, plaintext, &thislen, (const unsigned char *) ciphertext, ciphertext_len))
decryptError("Error in EVP_DecryptUpdate");
plaintext_len += thislen;

if(1 != EVP_DecryptFinal_ex(ctx, plaintext + plaintext_len, &thislen))
decryptError("Error in EVP_DecryptFinal_ex");
plaintext_len += thislen;
assertex(plaintext_len <= outlen);
EVP_CIPHER_CTX_free(ctx);
return plaintext_len;
}
catch (...)
{
EVP_CIPHER_CTX_free(ctx);
throw;
}
}

} // namespace
#endif

MemoryBuffer &aesEncrypt(const void *key, size_t keylen, const void *input, size_t inlen, MemoryBuffer &output)
{
#ifdef _USE_OPENSSL
return openssl::aesEncrypt(key, keylen, input, inlen, output);
#else
return jlib::aesEncrypt(key, keylen, input, inlen, output);
#endif
}

MemoryBuffer &aesDecrypt(const void *key, size_t keylen, const void *input, size_t inlen, MemoryBuffer &output)
{
#ifdef _USE_OPENSSL
return openssl::aesDecrypt(key, keylen, input, inlen, output);
#else
return jlib::aesDecrypt(key, keylen, input, inlen, output);
#endif
}

size_t aesDecrypt(const void *key, size_t keylen, const void *input, size_t inlen, void *output, size_t outlen)
{
#ifdef _USE_OPENSSL
return openssl::aesDecrypt(key, keylen, input, inlen, output, outlen);
#else
return jlib::aesDecrypt(key, keylen, input, inlen, output, outlen);
#endif
}

#define CRYPTSIZE 32
Expand Down Expand Up @@ -1874,3 +2054,5 @@ void decrypt(StringBuffer &ret, const char *in)
}
}



12 changes: 10 additions & 2 deletions system/jlib/jencrypt.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,17 @@ namespace jlib
extern jlib_decl size_t aesDecrypt(const void *key, size_t keylen, const void *input, size_t inlen, void *output, size_t outlen);
} // end of namespace jlib;

#ifdef _USE_OPENSSL
namespace openssl
{
extern jlib_decl MemoryBuffer &aesEncrypt(const void *key, size_t keylen, const void *input, size_t inlen, MemoryBuffer &output);
extern jlib_decl MemoryBuffer &aesDecrypt(const void *key, size_t keylen, const void *input, size_t inlen, MemoryBuffer &output);
extern jlib_decl size_t aesDecrypt(const void *key, size_t keylen, const void *input, size_t inlen, void *output, size_t outlen);
} // end of namespace openssl;
#endif

// NB: these are wrappers to either the openssl versions (if USE_OPENSSL) or the jlib version.
// MORE - are they?? I see no evidence of that!

extern jlib_decl MemoryBuffer &aesEncrypt(const void *key, size_t keylen, const void *input, size_t inlen, MemoryBuffer &output);
extern jlib_decl MemoryBuffer &aesDecrypt(const void *key, size_t keylen, const void *input, size_t inlen, MemoryBuffer &output);
extern jlib_decl size_t aesDecrypt(const void *key, size_t keylen, const void *input, size_t inlen, void *output, size_t outlen);
Expand All @@ -46,7 +55,6 @@ extern jlib_decl size_t aesDecrypt(const void *key, size_t keylen, const void *i
extern jlib_decl void encrypt(StringBuffer &ret, const char *in);
extern jlib_decl void decrypt(StringBuffer &ret, const char *in);


// simple inline block scrambler (shouldn't need jlib_decl)
class Csimplecrypt
{
Expand Down
47 changes: 47 additions & 0 deletions testing/unittests/jlibtests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3610,5 +3610,52 @@ class JLibUnicodeTest : public CppUnit::TestFixture
CPPUNIT_TEST_SUITE_REGISTRATION( JLibUnicodeTest );
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( JLibUnicodeTest, "JLibUnicodeTest" );

#ifdef _USE_OPENSSL
#include <jencrypt.hpp>

class JLibOpensslAESTest : public CppUnit::TestFixture
{
public:
CPPUNIT_TEST_SUITE(JLibOpensslAESTest);
CPPUNIT_TEST(test);
CPPUNIT_TEST_SUITE_END();

protected:

void test()
{
/* A 256 bit key */
unsigned char key[] = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33,
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31
};

/* Message to be encrypted */
unsigned char *plaintext = (unsigned char *)"The quick brown fox jumps over the lazy dog";

MemoryBuffer ciphertext1, ciphertext2, decrypted;

openssl::aesEncrypt(key, 32, plaintext, strlen ((char *)plaintext), ciphertext1);
jlib::aesEncrypt(key, 32, plaintext, strlen ((char *)plaintext), ciphertext2);

CPPUNIT_ASSERT(ciphertext1.length()==ciphertext2.length());
CPPUNIT_ASSERT(memcmp(ciphertext1.bytes(), ciphertext2.bytes(), ciphertext1.length()) == 0);

/* Decrypt the ciphertext */
openssl::aesDecrypt(key, 32, ciphertext1.bytes(), ciphertext1.length(), decrypted);

/* Add a NULL terminator. We are expecting printable text */
decrypted.append('\0');

/* Show the decrypted text */
DBGLOG("Decrypted text is: %s", (const char *) decrypted.bytes());
}

};

CPPUNIT_TEST_SUITE_REGISTRATION( JLibOpensslAESTest );
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( JLibOpensslAESTest, "JLibOpensslAESTest" );
#endif

#endif // _USE_CPPUNIT

0 comments on commit 4717a5c

Please sign in to comment.