I'm trying the implement the following openssl command line in C:
openssl enc -aes-256-cbc -d -in /tmp/out_enc -K \
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA \
-iv 0 -nopad -p
Output of the command line:
key=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
iv =00000000000000000000000000000000
<CONNECTION_REQUEST ATS_ID="2" ATP_SEQ_ID="1" REGISTRATION_ID="Y2G5R52S8PP6YX47" SERIAL_NUMBER="724574802" SPC_PRODUCT_TITLE="SPC5300" SPC_FW_VERSION="3.8.5 - R.31629" ATS_NAME="Système (ATS) 2" ATP1_ID="2" ATP1_UID="34" ATP1_NAME="Principal ATP 1" ATP1_COMMS_INTERFACE="1" ATP1_DEST="1, 192.168.1.62:52000" ATP1_CATEGORY="50"/>�z
This is my equivalent in C:
long
_ast_crypt_decrypt_generic(unsigned char* ciphertext, long cipherlen, unsigned char* plaintext, const EVP_CIPHER *cipher) {
long result = 0;
/* A 256 bit key */
unsigned char *key = (unsigned char *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
/* A 128 bit IV */
unsigned char *iv = (unsigned char *)"0000000000000000";
EVP_CIPHER_CTX *ctx = NULL;
int len;
long plaintext_len;
if (cipher) {
/* Create and initialise the context */
if (!(ctx = EVP_CIPHER_CTX_new())) {
g_warning("AstCrypt : EVP_CIPHER_CTX_new failed");
goto end;
}
if (1 != EVP_DecryptInit_ex(ctx, cipher, NULL, key, iv)) {
g_warning("AstCrypt : EVP_DecryptInit_ex");
}
EVP_CIPHER_CTX_set_padding(ctx, 0);
if (1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, cipherlen)) {
g_warning("AstCrypt : EVP_DecryptUpdate");
goto end;
}
plaintext_len = len;
if (1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) {
g_warning("AstCrypt : EVP_DecryptFinal_ex failed");
goto end;
}
plaintext_len += len;
result= plaintext_len;
}
else {
g_warning("AstCrypt : Failed to get the openssl elements.");
}
end:
if (ctx)
EVP_CIPHER_CTX_free(ctx);
return result;
}
long plainSize = _ast_crypt_decrypt_generic(headerData, headerLength, bPlain, EVP_aes_256_cbc());
//fwrite(bPlain, plainSize, 1, stdout);
The previous code sample doesn't decrypt the data correctly (in C).
Do you have any ideas what I am missing?
It's probably a missing understanding of the key/iv format in the openssl lib.
The answer is that the key/iv must be represented in hex :
The following works as expected :
unsigned char key[] =
{ 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA,0 };
//unsigned char key[] = {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} ;
/* A 128 bit IV */
unsigned char iv[] =
{ 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,0 };
The problem is that you are assuming the key is direct copy of the "password". What you are doing with that command line is specifying the key as a hex string. So what you need to do is convert your "password" from a hex string into a the key buffer. In your example you should end up with every byte set to the hex value "0xAA".
Because you are passing in the key directly, there is no need for the MD5 parameter (to your function or into openssl).
If you wanted to using a password instead of a "hex string", then you need to hash it somehow into the key buffer. This is where the MD5 parameter comes in. You can use something like PBKDF2 (although I would use the openssl default SHA256 and not MD5 as the hashing function).
e.g. openssl enc -aes-256-cbc -pbkdf2 -k password
Related
I've been playing with openssl and am trying to write a simple program in C for encrypting a string. I'm trying to replicate the following command to encrypt the string "test" and then see the encrypted version using a given key and IV and AES-CBC-128:
echo test | openssl enc -e -aes-128-cbc -nosalt -K 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a -iv 00000000000000000000000000000000 | xxd
and this returns the encrypted string in hex of
a63b e13d 47a5 b94c c1cb 466e 28af 19d8
I'm trying to replicate this in C with the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/aes.h>
int main() {
AES_KEY aes;
unsigned char* input_string = "test";
unsigned char* encrypt_string;
unsigned int len;
unsigned char key[] = {0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A,
0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A};
unsigned char iv[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint32_t result;
result = AES_set_encrypt_key(key, 128, &aes);
if (result < 0) {
fprintf(stderr, "Unable to set encryption key in AES\n");
printf("%i", result);
exit(-1);
}
// set the encryption length
len = 0;
if ((strlen("test") + 1) % AES_BLOCK_SIZE == 0) {
len = strlen("test") + 1;
} else {
len = ((strlen("test") + 1) / AES_BLOCK_SIZE + 1) * AES_BLOCK_SIZE;
}
encrypt_string = (unsigned char*)calloc(len, sizeof(unsigned char));
AES_cbc_encrypt(input_string, encrypt_string, 128, &aes, iv , AES_ENCRYPT);
printf("encrypted string = ");
for (int i=0; i<len; ++i) {
printf("%02X ", encrypt_string[i]);
}
printf("\n");
return 0;
}
and this returns the encrypted string as
encrypted string = C2 5D 07 2D D5 EC DB 94 3B FE 31 9F 51 DE EE 93
which doesn't match what I get from the CLI. What am I missing here that causing these not to match?
I've been trying to use the AES CTR 128 from tiny-aes-c (https://github.com/kokke/tiny-AES-c) to encrypt a randomly generated token, and it works, but not all the time. In some cases the retrieved string after encrypting and decrypting is cut off at some point. Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "token_auth.h"
#include "aes.h"
uint8_t * create_token() {
static char charset[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
uint8_t *token = malloc(sizeof(uint8_t) * (TOKEN_LENGTH + 1));
int i = 0;
srand ( time(NULL) );
for (i = 0; i < TOKEN_LENGTH; i++) {
int pos = rand() % (int)(strlen(charset) - 1);
token[i] = (int) charset[pos] - 0;
}
token[TOKEN_LENGTH] = 0;
return token;
}
int main() {
uint8_t key[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
uint8_t iv[16] = { 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
uint8_t *in = create_token();
printf("\nInput: %s\nSize: %d", (char *) in, strlen((char *) in));
struct AES_ctx ctx;
AES_init_ctx_iv(&ctx, key, iv);
AES_CTR_xcrypt_buffer(&ctx, in, strlen((char *) in));
AES_init_ctx_iv(&ctx, key, iv);
AES_CTR_xcrypt_buffer(&ctx, in, strlen((char *) in));
printf("\nDEC: %s\n", (char *) in);
return 0;
}
TOKEN_LENGTH is 128. As an example of the behavior, the string NM5DlWyYInbeNtEWhBxGCdEjHSv2I6FzTMffJNgudrL2UsYe6zVJMA3wvAyhHeQD18UMXckcF8gBAfPGQNqGqwdW9MgS39w7huVfIgtoqJ212SKSIdBaJP9VErOJAmQT comes out NM5DlWyYInbeNtEWhBxGCdEjHSv2 after being encrypted and decrypted. I'm not really good at C, so it might just well be a problem with something else I've done, but at this point I'm lost. Any ideas? Thanks in advance.
The first call to AES_CTR_xcrypt_buffer encrypts the buffer in place in CTR mode.
The buffer still has the same size (128 in your case), but can contain NUL bytes.
The strlen call in the second call of AES_CTR_xcrypt_buffer for decryption can therefore result in a length < 128 if the buffer contains a NUL byte.
By the way: It works in cases where the encryption does not result in a NUL byte in the buffer.
So if you call it with TOKEN_LENGTH as the length parameter decryption will give the original string again:
AES_CTR_xcrypt_buffer(&ctx, in, TOKEN_LENGTH);
I am using C-API of OpenSSL, but I am confused on how IV (Initialization Vector) is used in OpenSSL.
Say, I have
plaintext.txt file = "This is a top secret."
Key = "example#########"
IV = 010203040506070809000a0b0c0d0e0f
when I encrypt this using OpenSSL AES-128-CBC, I should get:
e5accdb667e8e569b1b34f423508c15422631198454e104ceb658f5918800c22
Which is true when I try this (key converted to hex):
openssl enc -aes-128-cbc -e -in plaintext.txt -out ciphertext.bin
-K 6578616d706c65232323232323232323 -iv 010203040506070809000a0b0c0d0e0f
I get:
xxd -p ciphertext.bin
e5accdb667e8e569b1b34f423508c15422631198454e104ceb658f5918800c22
But I got different ciphertext thing using C
char plaintext[] = "This is a top secret.";
unsigned char iv[16] = {
0x01, 0x02, 0x03, 0x04,
0x05, 0x06, 0x07, 0x08,
0x09, 0x00, 0x0A, 0x0B,
0x0C, 0x0D, 0x0E, 0x0F
};
unsigned char ciphertext[] = {
0xe5, 0xac, 0xcd, 0xb6,
0x67, 0xe8, 0xe5, 0x69,
0xb1, 0xb3, 0x4f, 0x42,
0x35, 0x08, 0xc1, 0x54,
0x22, 0x63, 0x11, 0x98,
0x45, 0x4e, 0x10, 0x4c,
0xeb, 0x65, 0x8f, 0x59,
0x18, 0x80, 0x0c, 0x22
};
key (example) is in a words.txt file.
My encryption process:
while(fgets(words, 16, wordsfile)) { //for getting key and padding
index = strlen(words) - 1; //key "example" is the last word in words.txt
while(index < 16) {
words[index] = 0x20;
index++;
}
words[index] = '\0';
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
EVP_CipherInit_ex(&ctx, EVP_aes_128_cbc(), NULL, words, iv, 1);
EVP_CipherUpdate(&ctx, outbuf, &outlen, plaintext, strlen(plaintext));
EVP_CipherFinal_ex(&ctx, outbuf + outlen, &templ);
outlen += templ;
EVP_CIPHER_CTX_cleanup(&ctx);
}
When I check the ciphertext matches to key "example", I got a completely different ciphertext. Which part I was wrong? I am assuming the format of IV or the way I implemented IV is wrong.
It looks like you are pretty close. By narrowing down the problem to just the encryption, the correct ciphertext can be produced. So in stead of reading the key from the file, define it as an array of unsigned chars, similar to what you did for the other variables:
unsigned char key[]={0x65,0x78,0x61,0x6d,0x70,0x6c,0x65,0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23,0x23};
Then the following code (reusing your variables) shows the successful encryption:
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
EVP_CipherInit_ex(&ctx, EVP_aes_128_cbc(),NULL, key, iv, 1);
EVP_CipherUpdate(&ctx, outbuf, &outlen, (unsigned char *)plaintext, strlen(plaintext));
EVP_CipherFinal_ex(&ctx, outbuf+outlen, &templ);
outlen+=templ;
EVP_CIPHER_CTX_cleanup(&ctx);
int cmpres = memcmp(outbuf, ciphertext, sizeof(ciphertext));
printf("cmpres is %d, sizeof(ciphertext) is %lu, outlen is %d\n",
cmpres, sizeof(ciphertext), outlen);
because it prints
$ ./main
cmpres is 0, sizeof(ciphertext) is 32, outlen is 32
This means that the problem is in how you read the key from the file. That is much easier to analyze than cryptographic issues :-) and I will leave it up to you to figure out that part...
By the way, make sure to check all return codes for your OpenSSL calls, it will help you to detect error situations.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
CHAR fileBuffer[1000];
uint8_t tmpArray[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t tmpArray2] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
for (i = 0; i < sizeof(fileBuffer); i++)
{
printf("%02X ", (uint8_t)tmpArray[i]);
}
take string from the file and convert to a byte array as in tmpArray. The string in the file would be like,
5FE1908F5FA463A9F94B8B1EA460B70A7D946B144E6A5093965A882E7855931A
I did try to read this into two byte arrays like this
memmove(tmpArray, fileBuffer, 32 * sizeof(uint8_t));
memmove(tmpArray2,fileBuffer[32], 32 *sizeof(uint8_t));
it copied in ok to tmpArray first 16bytes but the next 16bytes got messed up in tmpArray2.
If you could help with either way it would be great
string from file, string as above and convert to uint8_t arrays. the two separate arrays should result after reading/converting
uint8_t tmpArray[] = { 0x5F, 0xE1, 0x90, 0x8F, 0x5F, 0xA4, 0x63, 0xA9, 0xF9, 0x4B, 0x8B, 0x1E, 0xA4, 0x60, 0xB7, 0x0A };
uint8_t tmpArray2[] = { 0x7D, 0x94, 0x6B, 0x14, 0x4E, 0x6A, 0x50, 0x93, 0x96, 0x5A, 0x88, 0x2E, 0x78, 0x55, 0x93, 0x1A };
Is that what you wanted? (to test give binary 01 combination as an first argument)
#include <stdio.h>
#include <stdint.h>
uint8_t charToBin(char c)
{
switch(c)
{
case '0': return 0;
case '1': return 1;
}
return 0;
}
uint8_t CstringToU8(const char * ptr)
{
uint8_t value = 0;
for(int i = 0; (ptr[i] != '\0') && (i<8); ++i)
{
value = (value<<1) | charToBin(ptr[i]);
}
return value;
}
int main(int argc,const char *argv[])
{
printf("%d\n",CstringToU8(argv[1]));
return 0;
}
You can use CstringToU8() to convert 8 characters to one u8 number. Read whole data to char array (e.g. char * text) and then convert 8 characters to u8 number, store it and move you pointer 8 bytes further until array won't end.
Because after edit question was changed so here is my new solution. Code reading hex numbers from file and storing it into array.
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
int main()
{
FILE * fp;
uint8_t number = 0;
size_t fileSize = 0;
uint8_t * array = NULL;
size_t readedBytes = 0;
size_t iterator = 0;
fp = fopen ("hexNumbers.txt", "r");
// check file size
fseek(fp, 0L, SEEK_END);
fileSize = ftell(fp);
fseek(fp, 0L, SEEK_SET);
/// allocate max possible array size = fileSize/2
array = malloc(fileSize/2 * sizeof(uint8_t));
/// read data into array
while(!feof(fp))
{
if (fscanf(fp,"%2hhx",&number) == 1)
{
array[readedBytes++] = number;
}
}
fclose(fp);
/// print array output
for (iterator=0; iterator<readedBytes; ++iterator)
{
printf("%02x ", array[iterator]);
}
free(array);
return 0;
}
I wrote the following simple encryption-decryption program using mbedtls library. Encryption works fine (checked against http://aes.online-domain-tools.com/). However, when decrypting back I get incorrect result (output2 and input are different). Am I misusing the lib?
int main()
{
mbedtls_aes_context aes;
mbedtls_aes_context aes2;
unsigned char key[16] = "itzkbgulrcsjmnv";
key[15] = 'x';
unsigned char iv[16] = {0xb2, 0x4b, 0xf2, 0xf7, 0x7a, 0xc5, 0xec, 0x0c, 0x5e, 0x1f, 0x4d, 0xc1, 0xae, 0x46, 0x5e, 0x75};
const unsigned char *input = (const unsigned char*) "Some string to b";
unsigned char output[128] = {0};
unsigned char output2[128] = {0};
mbedtls_aes_setkey_enc( &aes, key, 16*8 );
mbedtls_aes_crypt_cbc( &aes, MBEDTLS_AES_ENCRYPT, strlen((const char*)input), iv, input, output );
mbedtls_aes_setkey_dec( &aes2, key, 16*8 );
mbedtls_aes_crypt_cbc( &aes2, MBEDTLS_AES_DECRYPT, strlen((const char*)output), iv, output, output2 );
}
I believe that the mbedtls_aes_crypt_cbc() function will alter the initialisation vector as it works. If you expect the same value that was input, you will need to start with the same initialisation vector.
The function mbedtls_aes_crypt_cbc() modifies iv's value so that the second call of mbedtls_aes_crypt_cbc() does not use the same value. This explains the failure of the decryption.
int main()
{
mbedtls_aes_context aes;
mbedtls_aes_context aes2;
unsigned char key[16] = "itzkbgulrcsjmnv";
key[15] = 'x';
unsigned char eiv[16] = {0xb2, 0x4b, 0xf2, 0xf7, 0x7a, 0xc5, 0xec, 0x0c, 0x5e, 0x1f, 0x4d, 0xc1, 0xae, 0x46, 0x5e, 0x75};
unsigned char div[16] = {0xb2, 0x4b, 0xf2, 0xf7, 0x7a, 0xc5, 0xec, 0x0c, 0x5e, 0x1f, 0x4d, 0xc1, 0xae, 0x46, 0x5e, 0x75};
const unsigned char *input = (const unsigned char*) "Some string to b";
unsigned char output[128] = {0};
unsigned char output2[128] = {0};
mbedtls_aes_setkey_enc( &aes, key, 16*8 );
mbedtls_aes_crypt_cbc( &aes, MBEDTLS_AES_ENCRYPT, strlen((const char*)input), eiv, input, output );
mbedtls_aes_setkey_dec( &aes2, key, 16*8 );
mbedtls_aes_crypt_cbc( &aes2, MBEDTLS_AES_DECRYPT, strlen((const char*)output), div, output, output2 );
}