I'm writing simple aes decoder/encoder using libtomcrypt. I need to story symmetric keys used in encoding, to decode data later. The problem is that the value of key which I access from "storage" struct changes comparing to the key that was used in encoder.
I've tried to assign key value to element of global symmetric_key array elem, but the value is still different from original
#include <tomcrypt.h>
typedef struct {
unsigned char * data;
unsigned char * crc_value;
symmetric_key skey;
}
aes_info_set;
aes_info_set aes_encrypter(unsigned char * data, unsigned char * key, int buf_size, int keysize, int rounds);
void main() {
unsigned char * data = "hallo world";
aes_info_set test;
test = aes_encrypter(data, key, 80, 32, 14);
printf("struct skey: %x \n", test.skey);
}
aes_info_set aes_encrypter(unsigned char * data, unsigned char * key, int buf_size, int keysize, int rounds) {
aes_info_set info_pack;
unsigned char * text = data;
unsigned char enc_out[buf_size];
unsigned char * crc_value = (unsigned char * ) malloc(4 * sizeof(unsigned char));
symmetric_key skey;
crc_value = crc_check(text, strlen(text));
aes_keysize( & keysize);
aes_setup(key, keysize, rounds, & skey);
aes_ecb_encrypt(text, enc_out, & skey);
printf("FROM FUNC\n");
info_pack.data = enc_out;
info_pack.crc_value = crc_value;
info_pack.skey = skey;
printf("func skey: %x \n", skey);
return info_pack;
}
//Output
>func skey: a15b56e0
>
>struct skey: a15b7890
I expected them to be the same
If I understand correctly you're confusing the key you need to encrypt/decrypt your file and the "key" that is used internally by the library to do what you want.
The key that you want to store is the one that is passed as first argument to aes_setup(), whereas the instance of a symmetric_key is not important.
See the examples in e.g. the AES tests aes.c:647 on how rijndael_setup() is used (rijndael_setup() is the same as aes_setup()).
Related
I try to add a nonce to my blockchain program. But when I test a program performance by trying to repeat the result (I need to be able to do to verify my chain), I do not get an identical result.
First I have a function which transform a structure to unsigned array pointer :
struct Test{
unsigned char data[4];
unsigned char nonce[4];
unsigned char hash[32];
}*prev,*next;
unsigned char *toStringTest(struct Test data)
{
unsigned char *str=malloc(sizeof(unsigned char)*sizeof(data));
memcpy(str,&data,sizeof(data));
return str;
}
Then, I have a program which give me a hash and nonce:
In this function:
I concatenated unsigned char pointer from toStringTest() with unsigned char arrat nonce.
I calculated hash of this concatenation.
If the hash starts by 0x00 I save hash and nonce into next block. If not, I repeat the function.
void hash_with_nonce(struct Test* message,struct Test* new_message){
unsigned char nonce[4]; //number only used once
unsigned char buffer[32];
while(1){
RAND_bytes(nonce, 4); //this function puts 4 cryptographically strong pseudo-random bytes into nonce.
unsigned char* str=toStringTest(*message);
int len = sizeof(unsigned char)*sizeof(*str)+sizeof(unsigned char)*sizeof(nonce);
unsigned char* message_with_nonce = malloc(len);
memcpy(message_with_nonce,str,sizeof(*str));
memcpy(message_with_nonce+sizeof(unsigned char)*sizeof(*str),nonce,sizeof(nonce));
//I concatenated toStringTest(*message) with nonce
SHA256(message_with_nonce, sizeof(message_with_nonce), buffer); //calculation of hash
free(message_with_nonce);
unsigned char var[1] = {0x00}; //rule for nonce decision, I want what hash start by 0x00
if((int *)var[0] == (int *)buffer[0]){
memcpy(new_message->hash,buffer, 32);
memcpy(new_message->nonce, nonce,sizeof(nonce));
return;
}
}
}
This is my main:
int main(int argc, char **argv)
{
unsigned char hash[32];
prev=malloc(sizeof(struct Test));
RAND_bytes(prev->data, 4);
RAND_bytes(prev->nonce, 4);
SHA256("",sizeof(""),prev->hash);
next=malloc(sizeof(struct Test));
RAND_bytes(next->data, 4);
//I just have filled this block with random data
hash_with_nonce(prev,next);
unsigned char* str=toStringTest(*prev);
int len = sizeof(unsigned char)*sizeof(*str)+sizeof(unsigned char)*sizeof(next->nonce);
unsigned char* message_with_nonce = malloc(len);
memcpy(message_with_nonce,str,sizeof(*str));
memcpy(message_with_nonce+sizeof(unsigned char)*sizeof(*str),next->nonce,sizeof(next->nonce));
SHA256(message_with_nonce, sizeof(message_with_nonce), hash);
}
prev and next are just 2 blocks which I use to check if function hash_with_nonce is working.
A problem is that the unsigned char hash[32] of the main is not the identical to next->hash. SHA256() and RAND_bytes() are openssl functions.
To check if 2 hashs are same, I have this function:
void PrintHex(unsigned char data[], int size)
{
unsigned char tmp[size];
for (int i=0; i<size; i++)
{
sprintf(tmp, "%02x",data[i]);
printf("%s", tmp);
}
printf("\n");
}
I'm trying to implement the AWS V4 signature in C, but am failing to calculate the hash in the string to sign. The test example here has:
key = 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY'
dateStamp = '20120215'
regionName = 'us-east-1'
serviceName = 'iam'
producing
kSecret = '41575334774a616c725855746e46454d492f4b374d44454e472b62507852666943594558414d504c454b4559'
kDate = '969fbb94feb542b71ede6f87fe4d5fa29c789342b0f407474670f0c2489e0a0d'
kRegion = '69daa0209cd9c5ff5c8ced464a696fd4252e981430b10e3d3fd8e2f197d7a70c'
kService = 'f72cfd46f26bc4643f06a11eabb6c0ba18780c19a8da0c31ace671265e3c87fa'
kSigning = 'f4780e2d9f65fa895f9c67b32ce1baf0b0d8a43505a000a1a9e090d414db404d'
But, for some reason my implementation drops the last few characters of the final element, and I get:
kSecret : 41575334774a616c725855746e46454d492f4b374d44454e472b62507852666943594558414d504c454b4559
kDate : 969fbb94feb542b71ede6f87fe4d5fa29c789342b0f407474670f0c2489e0a0d
kRegion : 69daa0209cd9c5ff5c8ced464a696fd4252e981430b10e3d3fd8e2f197d7a70c
kService : f72cfd46f26bc4643f06a11eabb6c0ba18780c19a8da0c31ace671265e3c87fa
kSigning : f4780e2d9f65fa895f9c67b32ce1baf0b0d8a43505a0
I'm just using an example for the HMAC_SHA256 calculation from https://stackoverflow.com/a/29862424/993874, I can't see what I'm missing. For other calculations (i.e. ones performing requests for my own AWS data etc) I also see that some of the hmac outputs are not 32 characters in length.
Can anyone help address this (and also confirm whether I need to convert all the char arrays to hex strings for AWS requests)?
Example code:
#include <stdio.h>
#include <string.h>
#include <openssl/hmac.h>
void printHex(const char* preface, const char* toPrint) {
printf("%s\t: ", preface);
for(size_t i = 0; i < strlen(toPrint); i++) {
printf("%02x", toPrint[i] & 0xff);
}
printf("\n");
}
void hmac_sha256(const unsigned char* key,
const unsigned char* text,
unsigned char* result) {
unsigned int resultLen;
HMAC(EVP_sha256(), key, strlen(key), text, strlen(text), result, &resultLen);
}
void amazonV4Sign(const unsigned char* accessSecret,
const unsigned char* amzDate,
const unsigned char* region,
const unsigned char* service) {
unsigned char kDate[BUFSIZ];
unsigned char kRegion[BUFSIZ];
unsigned char kService[BUFSIZ];
unsigned char kSigning[BUFSIZ];
unsigned char kSecret[BUFSIZ];
sprintf(kSecret, "AWS4%s", accessSecret);
unsigned char request[BUFSIZ];
sprintf(request, "aws4_request");
hmac_sha256(kSecret, amzDate, kDate);
hmac_sha256(kDate, region, kRegion);
hmac_sha256(kRegion, service, kService);
hmac_sha256(kService, request, kSigning);
printHex("kSecret", kSecret);
printHex("kDate", kDate);
printHex("kRegion", kRegion);
printHex("kService", kService);
printHex("kSigning", kSigning);
}
int main(int argc, char* argv[]) {
unsigned char* key = "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY";
unsigned char* dateStamp = "20120215";
unsigned char* regionName = "us-east-1";
unsigned char* serviceName = "iam";
amazonV4Sign(key, dateStamp, regionName, serviceName);
return 0;
}
You cannot use strlen to print the HMAC output because byte array may contain 0 byte.
Hence you can use the md_len returned by HMAC as below to print the byte array.
HMAC returns the length of md and syntax is.
unsigned char *HMAC(const EVP_MD *evp_md, const void *key,
int key_len, const unsigned char *d, int n,
unsigned char *md, unsigned int *md_len);
Hence use md_len to print the array.
void printHex(const char* preface, const char* toPrint, int len) {
printf("%s\t: ", preface);
for(size_t i = 0; i < len; i++) {
printf("%02x", toPrint[i] & 0xff);
}
printf("\n");
}
int hmac_sha256(const unsigned char* key,
const unsigned char* text,
unsigned char* result) {
unsigned int resultLen;
HMAC(EVP_sha256(), key, strlen(key), text, strlen(text), result, &resultLen);
printf("%d\n", resultLen);
return resultLen;
}
void amazonV4Sign(const unsigned char* accessSecret,
const unsigned char* amzDate,
const unsigned char* region,
const unsigned char* service) {
unsigned char kDate[EVP_MAX_MD_SIZE] = {0};
unsigned char kRegion[EVP_MAX_MD_SIZE] = {0};
unsigned char kService[EVP_MAX_MD_SIZE] = {0};
unsigned char kSigning[EVP_MAX_MD_SIZE] = {0};
unsigned char kSecret[BUFSIZ];
sprintf(kSecret, "AWS4%s", accessSecret);
printf("%s\n", kSecret);
unsigned char request[BUFSIZ];
sprintf(request, "aws4_request");
int len = hmac_sha256(kSecret, amzDate, kDate);
printHex("kSecret", kSecret,strlen(kSecret));
printHex("kDate", kDate,len);
len = hmac_sha256(kDate, region, kRegion);
printHex("kRegion", kRegion,len);
len = hmac_sha256(kRegion, service, kService);
printHex("kService", kService,len);
len = hmac_sha256(kService, request, kSigning);
printHex("kSigning", kSigning,len);
}
Output:
kSecret : 41575334774a616c725855746e46454d492f4b374d44454e472b62507852666943594558414d504c454b4559
kDate : 969fbb94feb542b71ede6f87fe4d5fa29c789342b0f407474670f0c2489e0a0d
kRegion : 69daa0209cd9c5ff5c8ced464a696fd4252e981430b10e3d3fd8e2f197d7a70c
kService : f72cfd46f26bc4643f06a11eabb6c0ba18780c19a8da0c31ace671265e3c87fa
kSigning : f4780e2d9f65fa895f9c67b32ce1baf0b0d8a43505a000a1a9e090d414db404d
Your loop in PrintHex is up to strlen(toPrint). It's a byte array, not a string, so you cannot use strlen( ). The loop needs to go up to 32.
I'll say up front, that my aim is not for security, but rather verifying data integrity.
I want to compute a standard hash for several terabytes of data using OpenSSL routines. The data is logically serialized (i.e. one array of bytes), but is distributed over many computers.
Rather than move the huge dataset to a single process (and memory space) for hashing, I want to pass around the hashing "context" so that the hash computation can take place locally everywhere the data is held.
Another way to frame the problem would be, I want to add bytes to the dataset later and continue the hash computation but result in the same hash answer as though all the bytes were available initially.
I've run into a sticking point, because I can't figure out how the "context" is stored by the library. I don't know what I would need to pass around or save to accomplish my intent.
(It is safe to assume that all hashing participants will be using the same version of the OpenSSL library.)
I adapted the documentation example to process two chunks of bytes to facilitate discussion. Now I want to know is there a way to pull the plug on the computer between chunk1 and chunk2 and still get the same answer? Or what if chunk1 and chunk2 are stored on different computers?
#include <openssl/evp.h>
#include <stdio.h>
#include <string.h>
void print_bytes(const unsigned char * bytes, size_t count, const char * prefix)
{
printf("%s",prefix);
for(size_t i = 0; i < count; ++i) {
printf("%02x", bytes[i]);
}
printf(" (%zd Bytes)\n", count);
}
unsigned int md5_digest_process(const EVP_MD* type, const unsigned char *input, size_t numBytes, unsigned char* hash_out) {
EVP_MD_CTX mdctx;
unsigned int hash_len = 0;
size_t chunk1_size = numBytes/2;
size_t chunk2_size = numBytes - chunk1_size;
EVP_MD_CTX_init(&mdctx);
print_bytes( (const unsigned char *)&mdctx, sizeof(EVP_MD_CTX), "EVP_MD_CTX: " );
EVP_DigestInit_ex(&mdctx, type, NULL);
print_bytes( (const unsigned char *)&mdctx, sizeof(EVP_MD_CTX), "EVP_MD_CTX: " );
// Hash chunk 1:
EVP_DigestUpdate(&mdctx, input, chunk1_size);
print_bytes( (const unsigned char *)&mdctx, sizeof(EVP_MD_CTX), "EVP_MD_CTX: " );
// Hash chunk 2:
EVP_DigestUpdate(&mdctx, input+chunk1_size, chunk2_size);
print_bytes( (const unsigned char *)&mdctx, sizeof(EVP_MD_CTX), "EVP_MD_CTX: " );
EVP_DigestFinal_ex(&mdctx, hash_out, &hash_len);
EVP_MD_CTX_cleanup(&mdctx);
return hash_len;
}
int main(int argc, char *argv[]) {
if (argc!=2) {
fprintf(stderr, "One argument string expected.\n");
return 1;
}
//OpenSSL_add_all_digests();
//const EVP_MD *md = EVP_get_digestbyname("MD5");
const EVP_MD *md = EVP_md5(); //EVP_sha256();
if(!md) {
fprintf(stderr, "Unable to init MD5 digest\n");
return 1;
}
unsigned char hash[EVP_MAX_MD_SIZE];
const unsigned char * allBytes = (const unsigned char *)argv[1];
size_t numBytes = strlen(argv[1]); // skip null terminator, consistent with command line md5 -s [string]
printf("Hashing %zd bytes. EVP_MAX_MD_SIZE is %zd, EVP_MD_CTX size is %zd bytes.\n", numBytes, EVP_MAX_MD_SIZE, sizeof(EVP_MD_CTX));
int hash_len = md5_digest_process(md, allBytes, numBytes, hash);
print_bytes(hash, hash_len, "Hash: " );
return 0;
}
With output:
$ ./a.out foobar
Hashing 6 bytes. EVP_MAX_MD_SIZE is 64, EVP_MD_CTX size is 48 bytes.
EVP_MD_CTX: 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 (48 Bytes)
EVP_MD_CTX: 609d9d01010000000000000000000000000000000000000080274062cd7f0000000000000000000040de8e0101000000 (48 Bytes)
EVP_MD_CTX: 609d9d01010000000000000000000000000000000000000080274062cd7f0000000000000000000040de8e0101000000 (48 Bytes)
EVP_MD_CTX: 609d9d01010000000000000000000000000000000000000080274062cd7f0000000000000000000040de8e0101000000 (48 Bytes)
Hash: 3858f62230ac3c915f300c664312c63f (16 Bytes)
$ md5 -s foobar
MD5 ("foobar") = 3858f62230ac3c915f300c664312c63f
Since EVP_MD_CTX is not changing after each update, I infer that the algorithm state is actually stored elsewhere and I cannot simply copy the 48 EVP_MD_CTX bytes.
I've seen EVP_MD_CTX_copy_ex() in the manual, but I don't see how to use it for my purpose.
Folks,
Trying to troubleshoot an issue with the base64 function below. About 2-3% of the requests that pass through this process return an incorrect (too short) base64output.
static const char *header_request_gce(request_rec *r, char *a)
{
char *tim = apr_palloc(r->pool, APR_RFC822_DATE_LEN);
apr_rfc822_date(tim, r->request_time);
char *uri = apr_psprintf(r->pool, "%s", r->uri);
char encode[32768];
//encode = malloc(strlen(tim)+strlen(uri)); /* make space for the new string (should check the return value ...) */
strcpy(encode, "GET\n\n\n");
strcat(encode, tim);
strcat(encode, "\n");
strcat(encode, uri);
unsigned int encode_length = strlen(encode);
unsigned char* result;
unsigned char* key = (unsigned char*) "2kcXHh+K+XLtI61/KIV3d1tVzOooTdeOqFii9osz";
static char res_hexstring[8192];
result = HMAC(EVP_sha1(), key, 40, encode, encode_length, NULL, NULL);
char *base64(const unsigned char *input, int length);
char *base64output = base64(result, strlen(result));
return base64output;
}
char *base64(const unsigned char *input, int length)
{
BIO *bmem, *b64;
BUF_MEM *bptr;
b64 = BIO_new(BIO_f_base64());
bmem = BIO_new(BIO_s_mem());
b64 = BIO_push(b64, bmem);
BIO_write(b64, input, length);
BIO_flush(b64);
BIO_get_mem_ptr(b64, &bptr);
char *buff = (char *)malloc(bptr->length);
memcpy(buff, bptr->data, bptr->length-1);
buff[bptr->length-1] = 0;
BIO_free_all(b64);
return buff;
}
The key above has been modified ofcourse, but kept in the correct character format
This line is incorrect:
char *base64output = base64(result, strlen(result));
The data (output from sha1) that you are encoding can contain the NUL byte which means strlen returns a number that is too small (with a probability of 1 - (255/256)^20 which is approximately 7.5%). Rather than call strlen you should just pass in the size as a constant. I believe that if you are just encoding a sha1 hash, the length will always be 20:
char *base64output = base64(result, 20);
There is probably a better way to get that length from an HMAC function or something (so that it updates automatically if you change the hashing algorithm), but I am, admittedly, not very familiar with the hashing functions you're using.
Following the OpenSSL docs, I /think/ that what I'm doing is correct.. but apparently it's not. Compiling the file (with gcc -g -Wall -Wextra -lssl sign.c) yields no errors or warnings. EVP_VerifyFinal() always returns 0 (Meaning the check failed). What is causing that?
static const EVP_MD * type;
unsigned char * sha(char * input)
{
EVP_MD_CTX c;
unsigned char *md;
unsigned int md_len;
md = malloc(EVP_MAX_MD_SIZE);
EVP_MD_CTX_init(&c);
EVP_DigestInit_ex(&c, type, NULL);
EVP_DigestUpdate(&c, input, strlen(input));
EVP_DigestFinal_ex(&c, md, &md_len);
EVP_MD_CTX_cleanup(&c);
return md;
}
unsigned char * sign(EVP_PKEY * key, unsigned char * data)
{
EVP_MD_CTX c;
unsigned char *sig;
unsigned int len;
EVP_MD_CTX_init(&c);
sig = malloc(EVP_PKEY_size(key));
EVP_SignInit(&c, type);
EVP_SignUpdate(&c, data, strlen((char *)data));
EVP_SignFinal(&c, sig, &len, key);
EVP_MD_CTX_cleanup(&c);
return sig;
}
int verify(EVP_PKEY * key, unsigned char * data, unsigned char * original)
{
EVP_MD_CTX c;
int ret;
EVP_MD_CTX_init(&c);
EVP_VerifyInit(&c, type);
EVP_VerifyUpdate(&c, data, (unsigned int)sizeof(data));
ret = EVP_VerifyFinal(&c, original, (unsigned int)strlen((char *)original), key);
return ret;
}
int main(void)
{
EVP_PKEY *sk, *pk;
FILE *sfd, *pfd;
unsigned char *hash, *sig;
unsigned int i;
sfd = fopen("secret.pem", "r");
pfd = fopen("public.pem", "r");
sk = PEM_read_PrivateKey(sfd, NULL, NULL, NULL);
pk = PEM_read_PUBKEY(pfd, NULL, NULL, NULL);
fclose(sfd);
fclose(pfd);
OpenSSL_add_all_digests();
type = EVP_get_digestbyname("SHA1");
hash = sha("moo");
for(i = 0; i < sizeof(hash); i++)
printf("%02x", hash[i]);
printf("\n");
sig = sign(sk, hash);
switch( verify(pk, sig, hash) )
{
case 0:
printf("Check failed.\n");
break;
case 1:
printf("Check succeeded!\n");
break;
default:
printf("Oh look, an error: %d", ERR_get_error());
break;
}
return 0;
}
You are not passing the correct size:
EVP_VerifyUpdate(&c, data, (unsigned int)sizeof(data));
Since data is defined as unsigned char *, sizeof(data) is probably 4 or 8 (number of bytes required to hold a pointer).
Try passing the actual number of bytes that you've allocated, i.e. EVP_PKEY_size(key). You will have to pass that to your verify() function.
It's possible that something else is also wrong, but this one caught my eye.
I know this is an old question, but one bug could confuse users.
In the verify function original and data should be swapped, original past to EVP_VerifyUpdate and data to EVP_VerifyFinal. String length should not be used as a byte array can contain 0x00 as a valid value which will be recognized as "\0".