I'd like to encrypt a string in PHP and then decrypt it in C. I'm stuck on the decryption part.
(PHP) I first encrypt the string:
function encrypt($plaintext, $key) {
$iv = 'aaaaaaaaaaaaaaaa';
$ciphertext = openssl_encrypt($plaintext, "AES-256-CBC", $key, OPENSSL_RAW_DATA, $iv);
return $ciphertext;
}
echo encrypt('This is a test', 'test');
// output: 7q�7h_��8� ��L
(C) Then I want to decrypt it, I use tiny-AES-c library for the functions:
int test_decrypt_cbc(void) {
uint8_t key[] = "test";
uint8_t iv[] = "aaaaaaaaaaaaaaaa";
uint8_t str[] = "7q�7h_��8� ��L";
printf("%s", str);
printf("\n Decrypted buffer\n");
struct AES_ctx ctx;
AES_init_ctx_iv(&ctx, key, iv);
AES_CBC_decrypt_buffer(&ctx, str, sizeof(str));
printf("%s", str);
printf("\n");
return 1;
}
This outputs:
7q�7h_��8� ��L
Decrypted buffer
?L??Ɵ??m??Dˍ?'?&??c?W
It should instead output "This is a test".
How can I fix this?
In the PHP code, AES-256 is used. tiny-AES-c only supports AES-128 by default. In order for AES-256 to be supported, the corresponding constant must be defined in aes.h, i.e. the line //#define AES256 1
must be commented in, here.
PHP uses PKCS7 padding by default. The padding should be removed in the C code.
PHP implicitly pads too short keys with zero values to the specified length. Since AES-256-CBC was specified in the PHP code, the key test is extended as follows:
test\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
In the C code this extended key must be used (see also the comment of @r3mainer).
For the transfer of the ciphertext between the two codes a suitable encoding must be used, e.g. Base64 or hexadecimal (see also the comment of @Ôrel). For the latter, bin2hex
can be applied to the ciphertext in the PHP code. An example of a hex decoding in C can be found here.
A possible C-implementation is:
// Pad the key with zero values
uint8_t key[] = "test\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
uint8_t iv[] = "aaaaaaaaaaaaaaaa";
uint8_t ciphertextHex[] = "3771e837685ff5d4173801900de6e14c";
// Hex decode (e.g. https://stackoverflow.com/a/3409211/9014097)
uint8_t ciphertext[sizeof(ciphertextHex) / 2], * pos = ciphertextHex;
for (size_t count = 0; count < sizeof ciphertext / sizeof * ciphertext; count++) {
sscanf((const char*)pos, "%2hhx", &ciphertext[count]);
pos += 2;
}
// Decrypt
struct AES_ctx ctx;
AES_init_ctx_iv(&ctx, key, iv);
AES_CBC_decrypt_buffer(&ctx, ciphertext, sizeof(ciphertext));
// Remove the PKCS7 padding
uint8_t ciphertextLength = sizeof(ciphertext);
uint8_t numberOfPaddingBytes = ciphertext[ciphertextLength - 1];
ciphertext[ciphertextLength - numberOfPaddingBytes] = 0;
printf("%s", ciphertext);