|
/************************************************************************* |
|
> File Name: aes.c |
|
> Author: jige003 |
|
> Created Time: Thu 25 Apr 2019 04:39:32 PM CST |
|
************************************************************************/ |
|
|
|
#include <stdio.h> |
|
#include <string.h> |
|
#include <stdlib.h> |
|
#include <unistd.h> |
|
#include <assert.h> |
|
#include <errno.h> |
|
#include <stdint.h> |
|
#include <sys/time.h> |
|
#include <sys/resource.h> |
|
#include <openssl/evp.h> |
|
#include <openssl/err.h> |
|
#include <openssl/aes.h> |
|
#include <openssl/rand.h> |
|
#include <openssl/bio.h> |
|
#include <openssl/buffer.h> |
|
|
|
#include "hex.h" |
|
|
|
typedef unsigned char byte; |
|
|
|
void hex_debug(const byte *inbuf, size_t inlen, const byte *msg){ |
|
byte *enc_buf; |
|
bin2hex(inbuf, inlen, &enc_buf); |
|
printf("%s:%s\n", msg, enc_buf); |
|
free(enc_buf); |
|
} |
|
|
|
int aes_encrypt (const char *key, const byte *inbuf, size_t inlen, byte **outbuf, size_t *outlen){ |
|
int ret = 0, olen = 0, flen = 0; |
|
|
|
const EVP_CIPHER *cipher = EVP_aes_128_cbc(); |
|
assert(cipher != NULL); |
|
|
|
int cipher_block_size = EVP_CIPHER_block_size(cipher); |
|
int cipher_iv_len = EVP_CIPHER_iv_length(cipher); |
|
char iv[EVP_MAX_IV_LENGTH]; |
|
|
|
byte * enc_buf = (byte *) malloc( (inlen + cipher_block_size + cipher_iv_len) * sizeof(byte)); |
|
/* init evp */ |
|
if (!RAND_bytes(iv, sizeof(iv))) { |
|
/* OpenSSL reports a failure, act accordingly */ |
|
fprintf(stderr, "ERROR: RAND_bytes error: %s\n", strerror(errno)); |
|
ret = errno; |
|
goto cleanup; |
|
} |
|
|
|
EVP_CIPHER_CTX ctx; |
|
EVP_CIPHER_CTX_init(&ctx); |
|
ret = EVP_EncryptInit_ex(&ctx, cipher, NULL, key, iv); |
|
if (ret == 0 ){ |
|
fprintf(stderr, "ERROR: EVP_CipherInit_ex failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL)); |
|
goto cleanup; |
|
} |
|
|
|
/* encrypt */ |
|
ret = EVP_CipherUpdate(&ctx, enc_buf, &olen, inbuf, inlen); |
|
if( ret == 0) { |
|
fprintf(stderr, "ERROR: EVP_CipherUpdate failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL)); |
|
goto cleanup; |
|
} |
|
ret = EVP_EncryptFinal_ex(&ctx, enc_buf + olen, &flen); |
|
if ( ret == 0 ){ |
|
fprintf(stderr, "ERROR: EVP_CipherFinal_ex failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL)); |
|
goto cleanup; |
|
} |
|
*outlen = olen + flen; |
|
*outbuf = (byte *) malloc( ((*outlen) + EVP_MAX_IV_LENGTH + 1) * sizeof(byte)); |
|
memset((*outbuf), 0 , ((*outlen) + EVP_MAX_IV_LENGTH + 1)); |
|
memcpy((*outbuf), iv, EVP_MAX_IV_LENGTH); |
|
memcpy((*outbuf) + EVP_MAX_IV_LENGTH, enc_buf, (*outlen)); |
|
(*outlen) += EVP_MAX_IV_LENGTH; |
|
free(enc_buf); |
|
|
|
cleanup: |
|
EVP_CIPHER_CTX_cleanup(&ctx); |
|
return ret; |
|
} |
|
|
|
|
|
|
|
int aes_decrypt(const char *key, const byte *inbuf, size_t inlen, byte **outbuf, size_t *outlen){ |
|
int ret = 0, olen = 0, flen = 0; |
|
|
|
const EVP_CIPHER *cipher = EVP_aes_128_cbc(); |
|
assert( cipher != NULL ); |
|
|
|
int cipher_iv_len = EVP_CIPHER_iv_length(cipher); |
|
char iv[EVP_MAX_IV_LENGTH]; |
|
|
|
memcpy(iv, inbuf, EVP_MAX_IV_LENGTH); |
|
|
|
byte *enc_buf; |
|
enc_buf = (byte *)inbuf + EVP_MAX_IV_LENGTH; |
|
|
|
EVP_CIPHER_CTX dctx; |
|
EVP_CIPHER_CTX_init(&dctx); |
|
ret = EVP_DecryptInit_ex(&dctx, cipher, NULL, key, iv); |
|
|
|
if (ret == 0 ){ |
|
fprintf(stderr, "ERROR: EVP_CipherInit_ex failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL)); |
|
goto cleanup; |
|
} |
|
|
|
*outbuf = (byte *)malloc(inlen * sizeof(byte)); |
|
memset((*outbuf), 0 , inlen); |
|
|
|
/* decrypt */ |
|
ret = EVP_CipherUpdate(&dctx, (*outbuf), &olen, enc_buf, inlen - EVP_MAX_IV_LENGTH); |
|
if( ret == 0) { |
|
fprintf(stderr, "ERROR: EVP_CipherUpdate failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL)); |
|
goto cleanup; |
|
} |
|
ret = EVP_DecryptFinal_ex(&dctx, ((*outbuf) + olen), &flen); |
|
if ( ret == 0 ){ |
|
fprintf(stderr, "ERROR: EVP_CipherFinal_ex failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL)); |
|
goto cleanup; |
|
} |
|
*outlen = olen + flen; |
|
(*outbuf)[(*outlen)] = '\0'; |
|
cleanup: |
|
EVP_CIPHER_CTX_cleanup(&dctx); |
|
return ret; |
|
} |
|
|
|
|
|
void xfree(void *ptr){ |
|
if (ptr != ((void*)0)) free(ptr); |
|
} |
|
|
|
int main(void){ |
|
|
|
char key[] = "this is a key"; |
|
byte inbuf[] = "this is a test string by jige003 skeleton encrypt"; |
|
size_t inlen = strlen(inbuf); |
|
byte *outbuf ; |
|
size_t outlen; |
|
|
|
#ifdef LOOP |
|
while(1){ |
|
#endif |
|
|
|
aes_encrypt(key, inbuf, inlen, &outbuf, &outlen); |
|
#define P printf |
|
hex_debug(outbuf, outlen, "outbuf"); |
|
byte *plainbuf; |
|
size_t plen; |
|
|
|
aes_decrypt(key, outbuf, outlen, &plainbuf, &plen); |
|
printf("plainbuf:%s\n", plainbuf); |
|
|
|
if ( strcmp(inbuf, plainbuf) == 0 ){ |
|
P("aes encrypt/decrypt test success\n"); |
|
}else{ |
|
P("aes encrypt/decrypt test fail\n"); |
|
} |
|
|
|
xfree(plainbuf); |
|
xfree(outbuf); |
|
#ifdef LOOP |
|
} |
|
#endif |
|
return 0; |
|
} |