一、openssl aead算法接口使用示例:
//gcc -g -lssl aead_test.c -lcrypto -L /usr/local/lib/
#include <string.h>
#include <openssl/evp.h>
#define IV_SIZE 8
#define KEY_SIZE 24
#define INPUT_SIZE 100
void print_hexdata(unsigned char *b, int len, char *title)
{
int i = 0, c = 0;
printf("===================================== %s =====================================\n", title);
for (; i<len; i++) {
printf("0x%02x ", b[i]);
c++;
if (!(c%16))
printf("\n");
}
printf("\n");
}
int gcm_encrypt(unsigned char *plaintext, int plaintext_len,
unsigned char *aad, int aad_len,
unsigned char *key,
unsigned char *iv, int iv_len,
unsigned char *ciphertext,
unsigned char *tag)
{
EVP_CIPHER_CTX *ctx;
int len;
int ciphertext_len;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new()))
return -1;
/* Initialise the encryption operation. */
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
return -1;
/*
* Set IV length if default 12 bytes (96 bits) is not appropriate
*/
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
return -1;
/* Initialise key and IV */
if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv))
return -1;
/*
* Provide any AAD data. This can be called zero or more times as
* required
*/
if(1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len))
return -1;
printf("len:%d\n", len);
/*
* Provide the message to be encrypted, and obtain the encrypted output.
* EVP_EncryptUpdate can be called multiple times if necessary
*/
if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
return -1;
ciphertext_len = len;
printf("len:%d\n", len);
/*
* Finalise the encryption. Normally ciphertext bytes may be written at
* this stage, but this does not occur in GCM mode
*/
if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
return -1;
ciphertext_len += len;
printf("len:%d\n", len);
/* Get the tag */
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
return -1;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return ciphertext_len;
}
int gcm_decrypt(unsigned char *ciphertext, int ciphertext_len,
unsigned char *aad, int aad_len,
unsigned char *tag,
unsigned char *key,
unsigned char *iv, int iv_len,
unsigned char *plaintext)
{
EVP_CIPHER_CTX *ctx;
int len;
int plaintext_len;
int ret;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new()))
return -1;
/* Initialise the decryption operation. */
if(!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
return -1;
/* Set IV length. Not necessary if this is 12 bytes (96 bits) */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
return -1;
/* Initialise key and IV */
if(!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv))
return -1;
/*
* Provide any AAD data. This can be called zero or more times as
* required
*/
if(!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len))
return -1;
/*
* Provide the message to be decrypted, and obtain the plaintext output.
* EVP_DecryptUpdate can be called multiple times if necessary
*/
if(!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
return -1;
plaintext_len = len;
printf("len:%d\n", len);
/* Set expected tag value. Works in OpenSSL 1.0.1d and later */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag))
return -1;
/*
* Finalise the decryption. A positive return value indicates success,
* anything else is a failure - the plaintext is not trustworthy.
*/
ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
printf("len:%d\n", len);
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
if(ret > 0) {
/* Success */
plaintext_len += len;
return plaintext_len;
} else {
/* Verify failed */
return -1;
}
}
int main()
{
unsigned char plaintext[16] = "aaaabbbbccccdddd";
unsigned char add[16] = "aaaabbbbccccdddd";
unsigned char key[16] = "aaaabbbbccccdddd";
unsigned char iv[16] = "aaaabbbbccccdddd";
unsigned char ciphertext[16] = "
一、openssl aead算法接口使用示例:
//gcc -g -lssl aead_test.c -lcrypto -L /usr/local/lib/
#include <string.h>
#include <openssl/evp.h>
#define IV_SIZE 8
#define KEY_SIZE 24
#define INPUT_SIZE 100
void print_hexdata(unsigned char *b, int len, char *title)
{
int i = 0, c = 0;
printf("===================================== %s =====================================\n", title);
for (; i<len; i++) {
printf("0x%02x ", b[i]);
c++;
if (!(c%16))
printf("\n");
}
printf("\n");
}
int gcm_encrypt(unsigned char *plaintext, int plaintext_len,
unsigned char *aad, int aad_len,
unsigned char *key,
unsigned char *iv, int iv_len,
unsigned char *ciphertext,
unsigned char *tag)
{
EVP_CIPHER_CTX *ctx;
int len;
int ciphertext_len;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new()))
return -1;
/* Initialise the encryption operation. */
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
return -1;
/*
* Set IV length if default 12 bytes (96 bits) is not appropriate
*/
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
return -1;
/* Initialise key and IV */
if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv))
return -1;
/*
* Provide any AAD data. This can be called zero or more times as
* required
*/
if(1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len))
return -1;
printf("len:%d\n", len);
/*
* Provide the message to be encrypted, and obtain the encrypted output.
* EVP_EncryptUpdate can be called multiple times if necessary
*/
if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
return -1;
ciphertext_len = len;
printf("len:%d\n", len);
/*
* Finalise the encryption. Normally ciphertext bytes may be written at
* this stage, but this does not occur in GCM mode
*/
if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
return -1;
ciphertext_len += len;
printf("len:%d\n", len);
/* Get the tag */
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
return -1;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return ciphertext_len;
}
int gcm_decrypt(unsigned char *ciphertext, int ciphertext_len,
unsigned char *aad, int aad_len,
unsigned char *tag,
unsigned char *key,
unsigned char *iv, int iv_len,
unsigned char *plaintext)
{
EVP_CIPHER_CTX *ctx;
int len;
int plaintext_len;
int ret;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new()))
return -1;
/* Initialise the decryption operation. */
if(!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
return -1;
/* Set IV length. Not necessary if this is 12 bytes (96 bits) */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
return -1;
/* Initialise key and IV */
if(!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv))
return -1;
/*
* Provide any AAD data. This can be called zero or more times as
* required
*/
if(!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len))
return -1;
/*
* Provide the message to be decrypted, and obtain the plaintext output.
* EVP_DecryptUpdate can be called multiple times if necessary
*/
if(!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
return -1;
plaintext_len = len;
printf("len:%d\n", len);
/* Set expected tag value. Works in OpenSSL 1.0.1d and later */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag))
return -1;
/*
* Finalise the decryption. A positive return value indicates success,
* anything else is a failure - the plaintext is not trustworthy.
*/
ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
printf("len:%d\n", len);
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
if(ret > 0) {
/* Success */
plaintext_len += len;
return plaintext_len;
} else {
/* Verify failed */
return -1;
}
}
int main()
{
unsigned char plaintext[16] = "aaaabbbbccccdddd";
unsigned char add[16] = "aaaabbbbccccdddd";
unsigned char key[16] = "aaaabbbbccccdddd";
unsigned char iv[16] = "aaaabbbbccccdddd";
unsigned char ciphertext[16] = "\0";
unsigned char tag[16] = "\0";
unsigned char de_plaintext[16] = "\0";
gcm_encrypt(plaintext, 16, add, 16, key, iv, 16, ciphertext, tag);
print_hexdata(plaintext, 16, "plaintext");
print_hexdata(add, 16, "add");
print_hexdata(key, 16, "key");
print_hexdata(iv, 16, "iv");
print_hexdata(ciphertext, 16, "ciphertext");
print_hexdata(tag, 16, "tag");
gcm_decrypt(ciphertext, 16, add, 16, tag, key, iv, 16, de_plaintext);
print_hexdata(de_plaintext, 16, "de_plaintext");
printf("test ok\n");
return 0;
}
二、使用一组协议数据进行算法验证:
//gcc -g -lssl aead_test.c -lcrypto -L /usr/local/lib/
#include <string.h>
#include <openssl/evp.h>
struct aead_testvec {
const char *key;
const char *iv;
const char *ptext;
const char *assoc;
const char *ctext;
unsigned char novrfy;
unsigned char wk;
unsigned char klen;
unsigned int plen;
unsigned int clen;
unsigned int alen;
int setkey_error;
int setauthsize_error;
int crypt_error;
};
/* 256bit */
struct aead_testvec aes_gcm_tv_template_256[] = {
{
.key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
"\x6d\x6a\x8f\x94\x67\x30\x83\x08"
"\xfe\xff\xe9\x92\x86\x65\x73\x1c"
"\x6d\x6a\x8f\x94\x67\x30\x83\x08",
.klen = 32,
.iv = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
"\xde\xca\xf8\x88",
.ptext = "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
"\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
"\x86\xa7\xa9\x53\x15\x34\xf7\xda"
"\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
"\x1c\x3c\x0c\x95\x95\x68\x09\x53"
"\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
"\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
"\xba\x63\x7b\x39",
.plen = 60,
.assoc = "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
"\xfe\xed\xfa\xce\xde\xad\xbe\xef"
"\xab\xad\xda\xd2",
.alen = 20,
.ctext = "\x52\x2d\xc1\xf0\x99\x56\x7d\x07"
"\xf4\x7f\x37\xa3\x2a\x84\x42\x7d"
"\x64\x3a\x8c\xdc\xbf\xe5\xc0\xc9"
"\x75\x98\xa2\xbd\x25\x55\xd1\xaa"
"\x8c\xb0\x8e\x48\x59\x0d\xbb\x3d"
"\xa7\xb0\x8b\x10\x56\x82\x88\x38"
"\xc5\xf6\x1e\x63\x93\xba\x7a\x0a"
"\xbc\xc9\xf6\x62"
"\x76\xfc\x6e\xce\x0f\x4e\x17\x68"
"\xcd\xdf\x88\x53\xbb\x2d\x55\x1b",
.clen = 76,
}
};
void print_hexdata(unsigned char *b, int len, char *title)
{
int i = 0, c = 0;
printf("===================================== %s =====================================\n", title);
for (; i<len; i++) {
printf("0x%02x ", b[i]);
c++;
if (!(c%16))
printf("\n");
}
printf("\n");
}
int gcm_encrypt(unsigned char *plaintext, int plaintext_len,
unsigned char *aad, int aad_len,
unsigned char *key,
unsigned char *iv, int iv_len,
unsigned char *ciphertext,
unsigned char *tag)
{
EVP_CIPHER_CTX *ctx;
int len;
int ciphertext_len;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new()))
return -1;
/* Initialise the encryption operation. */
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
return -1;
/*
* Set IV length if default 12 bytes (96 bits) is not appropriate
*/
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
return -1;
/* Initialise key and IV */
if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv))
return -1;
/*
* Provide any AAD data. This can be called zero or more times as
* required
*/
if(1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len))
return -1;
printf("len:%d\n", len);
/*
* Provide the message to be encrypted, and obtain the encrypted output.
* EVP_EncryptUpdate can be called multiple times if necessary
*/
if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
return -1;
ciphertext_len = len;
printf("len:%d\n", len);
/*
* Finalise the encryption. Normally ciphertext bytes may be written at
* this stage, but this does not occur in GCM mode
*/
if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
return -1;
ciphertext_len += len;
printf("len:%d\n", len);
/* Get the tag */
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
return -1;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return ciphertext_len;
}
int gcm_decrypt(unsigned char *ciphertext, int ciphertext_len,
unsigned char *aad, int aad_len,
unsigned char *tag,
unsigned char *key,
unsigned char *iv, int iv_len,
unsigned char *plaintext)
{
EVP_CIPHER_CTX *ctx;
int len;
int plaintext_len;
int ret;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new()))
return -1;
/* Initialise the decryption operation. */
if(!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
return -1;
/* Set IV length. Not necessary if this is 12 bytes (96 bits) */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
return -1;
/* Initialise key and IV */
if(!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv))
return -1;
/*
* Provide any AAD data. This can be called zero or more times as
* required
*/
if(!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len))
return -1;
/*
* Provide the message to be decrypted, and obtain the plaintext output.
* EVP_DecryptUpdate can be called multiple times if necessary
*/
if(!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
return -1;
plaintext_len = len;
printf("len:%d\n", len);
/* Set expected tag value. Works in OpenSSL 1.0.1d and later */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag))
return -1;
/*
* Finalise the decryption. A positive return value indicates success,
* anything else is a failure - the plaintext is not trustworthy.
*/
ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
printf("len:%d\n", len);
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
if(ret > 0) {
/* Success */
plaintext_len += len;
return plaintext_len;
} else {
/* Verify failed */
return -1;
}
}
int main()
{
unsigned char plaintext[60] =
"\xd9\x31\x32\x25\xf8\x84\x06\xe5"
"\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
"\x86\xa7\xa9\x53\x15\x34\xf7\xda"
"\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
"\x1c\x3c\x0c\x95\x95\x68\x09\x53"
"\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
"\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
"\xba\x63\x7b\x39";
unsigned char add[20] = "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
"\xfe\xed\xfa\xce\xde\xad\xbe\xef"
"\xab\xad\xda\xd2";
unsigned char key[32] =
"\xfe\xff\xe9\x92\x86\x65\x73\x1c"
"\x6d\x6a\x8f\x94\x67\x30\x83\x08"
"\xfe\xff\xe9\x92\x86\x65\x73\x1c"
"\x6d\x6a\x8f\x94\x67\x30\x83\x08";
unsigned char iv[12] = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
"\xde\xca\xf8\x88";
unsigned char ciphertext[60] = "\0";
unsigned char tag[16] = "\0";
unsigned char de_plaintext[60] = "\0";
gcm_encrypt(plaintext, 60, add, 20, key, iv, 12, ciphertext, tag);
print_hexdata(plaintext, 60, "plaintext");
print_hexdata(add, 20, "add");
print_hexdata(key, 32, "key");
print_hexdata(iv, 12, "iv");
print_hexdata(ciphertext, 60, "ciphertext");
print_hexdata(tag, 16, "tag");
gcm_decrypt(ciphertext, 60, add, 20, tag1, key, iv, 12, de_plaintext);
print_hexdata(de_plaintext, 60, "de_plaintext");
printf("test ok\n");
return 0;
}
";
unsigned char tag[16] = "
一、openssl aead算法接口使用示例:
//gcc -g -lssl aead_test.c -lcrypto -L /usr/local/lib/
#include <string.h>
#include <openssl/evp.h>
#define IV_SIZE 8
#define KEY_SIZE 24
#define INPUT_SIZE 100
void print_hexdata(unsigned char *b, int len, char *title)
{
int i = 0, c = 0;
printf("===================================== %s =====================================\n", title);
for (; i<len; i++) {
printf("0x%02x ", b[i]);
c++;
if (!(c%16))
printf("\n");
}
printf("\n");
}
int gcm_encrypt(unsigned char *plaintext, int plaintext_len,
unsigned char *aad, int aad_len,
unsigned char *key,
unsigned char *iv, int iv_len,
unsigned char *ciphertext,
unsigned char *tag)
{
EVP_CIPHER_CTX *ctx;
int len;
int ciphertext_len;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new()))
return -1;
/* Initialise the encryption operation. */
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
return -1;
/*
* Set IV length if default 12 bytes (96 bits) is not appropriate
*/
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
return -1;
/* Initialise key and IV */
if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv))
return -1;
/*
* Provide any AAD data. This can be called zero or more times as
* required
*/
if(1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len))
return -1;
printf("len:%d\n", len);
/*
* Provide the message to be encrypted, and obtain the encrypted output.
* EVP_EncryptUpdate can be called multiple times if necessary
*/
if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
return -1;
ciphertext_len = len;
printf("len:%d\n", len);
/*
* Finalise the encryption. Normally ciphertext bytes may be written at
* this stage, but this does not occur in GCM mode
*/
if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
return -1;
ciphertext_len += len;
printf("len:%d\n", len);
/* Get the tag */
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
return -1;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return ciphertext_len;
}
int gcm_decrypt(unsigned char *ciphertext, int ciphertext_len,
unsigned char *aad, int aad_len,
unsigned char *tag,
unsigned char *key,
unsigned char *iv, int iv_len,
unsigned char *plaintext)
{
EVP_CIPHER_CTX *ctx;
int len;
int plaintext_len;
int ret;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new()))
return -1;
/* Initialise the decryption operation. */
if(!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
return -1;
/* Set IV length. Not necessary if this is 12 bytes (96 bits) */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
return -1;
/* Initialise key and IV */
if(!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv))
return -1;
/*
* Provide any AAD data. This can be called zero or more times as
* required
*/
if(!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len))
return -1;
/*
* Provide the message to be decrypted, and obtain the plaintext output.
* EVP_DecryptUpdate can be called multiple times if necessary
*/
if(!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
return -1;
plaintext_len = len;
printf("len:%d\n", len);
/* Set expected tag value. Works in OpenSSL 1.0.1d and later */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag))
return -1;
/*
* Finalise the decryption. A positive return value indicates success,
* anything else is a failure - the plaintext is not trustworthy.
*/
ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
printf("len:%d\n", len);
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
if(ret > 0) {
/* Success */
plaintext_len += len;
return plaintext_len;
} else {
/* Verify failed */
return -1;
}
}
int main()
{
unsigned char plaintext[16] = "aaaabbbbccccdddd";
unsigned char add[16] = "aaaabbbbccccdddd";
unsigned char key[16] = "aaaabbbbccccdddd";
unsigned char iv[16] = "aaaabbbbccccdddd";
unsigned char ciphertext[16] = "\0";
unsigned char tag[16] = "\0";
unsigned char de_plaintext[16] = "\0";
gcm_encrypt(plaintext, 16, add, 16, key, iv, 16, ciphertext, tag);
print_hexdata(plaintext, 16, "plaintext");
print_hexdata(add, 16, "add");
print_hexdata(key, 16, "key");
print_hexdata(iv, 16, "iv");
print_hexdata(ciphertext, 16, "ciphertext");
print_hexdata(tag, 16, "tag");
gcm_decrypt(ciphertext, 16, add, 16, tag, key, iv, 16, de_plaintext);
print_hexdata(de_plaintext, 16, "de_plaintext");
printf("test ok\n");
return 0;
}
二、使用一组协议数据进行算法验证:
//gcc -g -lssl aead_test.c -lcrypto -L /usr/local/lib/
#include <string.h>
#include <openssl/evp.h>
struct aead_testvec {
const char *key;
const char *iv;
const char *ptext;
const char *assoc;
const char *ctext;
unsigned char novrfy;
unsigned char wk;
unsigned char klen;
unsigned int plen;
unsigned int clen;
unsigned int alen;
int setkey_error;
int setauthsize_error;
int crypt_error;
};
/* 256bit */
struct aead_testvec aes_gcm_tv_template_256[] = {
{
.key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
"\x6d\x6a\x8f\x94\x67\x30\x83\x08"
"\xfe\xff\xe9\x92\x86\x65\x73\x1c"
"\x6d\x6a\x8f\x94\x67\x30\x83\x08",
.klen = 32,
.iv = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
"\xde\xca\xf8\x88",
.ptext = "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
"\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
"\x86\xa7\xa9\x53\x15\x34\xf7\xda"
"\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
"\x1c\x3c\x0c\x95\x95\x68\x09\x53"
"\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
"\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
"\xba\x63\x7b\x39",
.plen = 60,
.assoc = "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
"\xfe\xed\xfa\xce\xde\xad\xbe\xef"
"\xab\xad\xda\xd2",
.alen = 20,
.ctext = "\x52\x2d\xc1\xf0\x99\x56\x7d\x07"
"\xf4\x7f\x37\xa3\x2a\x84\x42\x7d"
"\x64\x3a\x8c\xdc\xbf\xe5\xc0\xc9"
"\x75\x98\xa2\xbd\x25\x55\xd1\xaa"
"\x8c\xb0\x8e\x48\x59\x0d\xbb\x3d"
"\xa7\xb0\x8b\x10\x56\x82\x88\x38"
"\xc5\xf6\x1e\x63\x93\xba\x7a\x0a"
"\xbc\xc9\xf6\x62"
"\x76\xfc\x6e\xce\x0f\x4e\x17\x68"
"\xcd\xdf\x88\x53\xbb\x2d\x55\x1b",
.clen = 76,
}
};
void print_hexdata(unsigned char *b, int len, char *title)
{
int i = 0, c = 0;
printf("===================================== %s =====================================\n", title);
for (; i<len; i++) {
printf("0x%02x ", b[i]);
c++;
if (!(c%16))
printf("\n");
}
printf("\n");
}
int gcm_encrypt(unsigned char *plaintext, int plaintext_len,
unsigned char *aad, int aad_len,
unsigned char *key,
unsigned char *iv, int iv_len,
unsigned char *ciphertext,
unsigned char *tag)
{
EVP_CIPHER_CTX *ctx;
int len;
int ciphertext_len;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new()))
return -1;
/* Initialise the encryption operation. */
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
return -1;
/*
* Set IV length if default 12 bytes (96 bits) is not appropriate
*/
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
return -1;
/* Initialise key and IV */
if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv))
return -1;
/*
* Provide any AAD data. This can be called zero or more times as
* required
*/
if(1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len))
return -1;
printf("len:%d\n", len);
/*
* Provide the message to be encrypted, and obtain the encrypted output.
* EVP_EncryptUpdate can be called multiple times if necessary
*/
if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
return -1;
ciphertext_len = len;
printf("len:%d\n", len);
/*
* Finalise the encryption. Normally ciphertext bytes may be written at
* this stage, but this does not occur in GCM mode
*/
if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
return -1;
ciphertext_len += len;
printf("len:%d\n", len);
/* Get the tag */
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
return -1;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return ciphertext_len;
}
int gcm_decrypt(unsigned char *ciphertext, int ciphertext_len,
unsigned char *aad, int aad_len,
unsigned char *tag,
unsigned char *key,
unsigned char *iv, int iv_len,
unsigned char *plaintext)
{
EVP_CIPHER_CTX *ctx;
int len;
int plaintext_len;
int ret;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new()))
return -1;
/* Initialise the decryption operation. */
if(!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
return -1;
/* Set IV length. Not necessary if this is 12 bytes (96 bits) */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
return -1;
/* Initialise key and IV */
if(!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv))
return -1;
/*
* Provide any AAD data. This can be called zero or more times as
* required
*/
if(!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len))
return -1;
/*
* Provide the message to be decrypted, and obtain the plaintext output.
* EVP_DecryptUpdate can be called multiple times if necessary
*/
if(!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
return -1;
plaintext_len = len;
printf("len:%d\n", len);
/* Set expected tag value. Works in OpenSSL 1.0.1d and later */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag))
return -1;
/*
* Finalise the decryption. A positive return value indicates success,
* anything else is a failure - the plaintext is not trustworthy.
*/
ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
printf("len:%d\n", len);
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
if(ret > 0) {
/* Success */
plaintext_len += len;
return plaintext_len;
} else {
/* Verify failed */
return -1;
}
}
int main()
{
unsigned char plaintext[60] =
"\xd9\x31\x32\x25\xf8\x84\x06\xe5"
"\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
"\x86\xa7\xa9\x53\x15\x34\xf7\xda"
"\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
"\x1c\x3c\x0c\x95\x95\x68\x09\x53"
"\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
"\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
"\xba\x63\x7b\x39";
unsigned char add[20] = "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
"\xfe\xed\xfa\xce\xde\xad\xbe\xef"
"\xab\xad\xda\xd2";
unsigned char key[32] =
"\xfe\xff\xe9\x92\x86\x65\x73\x1c"
"\x6d\x6a\x8f\x94\x67\x30\x83\x08"
"\xfe\xff\xe9\x92\x86\x65\x73\x1c"
"\x6d\x6a\x8f\x94\x67\x30\x83\x08";
unsigned char iv[12] = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
"\xde\xca\xf8\x88";
unsigned char ciphertext[60] = "\0";
unsigned char tag[16] = "\0";
unsigned char de_plaintext[60] = "\0";
gcm_encrypt(plaintext, 60, add, 20, key, iv, 12, ciphertext, tag);
print_hexdata(plaintext, 60, "plaintext");
print_hexdata(add, 20, "add");
print_hexdata(key, 32, "key");
print_hexdata(iv, 12, "iv");
print_hexdata(ciphertext, 60, "ciphertext");
print_hexdata(tag, 16, "tag");
gcm_decrypt(ciphertext, 60, add, 20, tag1, key, iv, 12, de_plaintext);
print_hexdata(de_plaintext, 60, "de_plaintext");
printf("test ok\n");
return 0;
}
";
unsigned char de_plaintext[16] = "
一、openssl aead算法接口使用示例:
//gcc -g -lssl aead_test.c -lcrypto -L /usr/local/lib/
#include <string.h>
#include <openssl/evp.h>
#define IV_SIZE 8
#define KEY_SIZE 24
#define INPUT_SIZE 100
void print_hexdata(unsigned char *b, int len, char *title)
{
int i = 0, c = 0;
printf("===================================== %s =====================================\n", title);
for (; i<len; i++) {
printf("0x%02x ", b[i]);
c++;
if (!(c%16))
printf("\n");
}
printf("\n");
}
int gcm_encrypt(unsigned char *plaintext, int plaintext_len,
unsigned char *aad, int aad_len,
unsigned char *key,
unsigned char *iv, int iv_len,
unsigned char *ciphertext,
unsigned char *tag)
{
EVP_CIPHER_CTX *ctx;
int len;
int ciphertext_len;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new()))
return -1;
/* Initialise the encryption operation. */
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
return -1;
/*
* Set IV length if default 12 bytes (96 bits) is not appropriate
*/
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
return -1;
/* Initialise key and IV */
if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv))
return -1;
/*
* Provide any AAD data. This can be called zero or more times as
* required
*/
if(1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len))
return -1;
printf("len:%d\n", len);
/*
* Provide the message to be encrypted, and obtain the encrypted output.
* EVP_EncryptUpdate can be called multiple times if necessary
*/
if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
return -1;
ciphertext_len = len;
printf("len:%d\n", len);
/*
* Finalise the encryption. Normally ciphertext bytes may be written at
* this stage, but this does not occur in GCM mode
*/
if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
return -1;
ciphertext_len += len;
printf("len:%d\n", len);
/* Get the tag */
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
return -1;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return ciphertext_len;
}
int gcm_decrypt(unsigned char *ciphertext, int ciphertext_len,
unsigned char *aad, int aad_len,
unsigned char *tag,
unsigned char *key,
unsigned char *iv, int iv_len,
unsigned char *plaintext)
{
EVP_CIPHER_CTX *ctx;
int len;
int plaintext_len;
int ret;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new()))
return -1;
/* Initialise the decryption operation. */
if(!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
return -1;
/* Set IV length. Not necessary if this is 12 bytes (96 bits) */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
return -1;
/* Initialise key and IV */
if(!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv))
return -1;
/*
* Provide any AAD data. This can be called zero or more times as
* required
*/
if(!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len))
return -1;
/*
* Provide the message to be decrypted, and obtain the plaintext output.
* EVP_DecryptUpdate can be called multiple times if necessary
*/
if(!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
return -1;
plaintext_len = len;
printf("len:%d\n", len);
/* Set expected tag value. Works in OpenSSL 1.0.1d and later */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag))
return -1;
/*
* Finalise the decryption. A positive return value indicates success,
* anything else is a failure - the plaintext is not trustworthy.
*/
ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
printf("len:%d\n", len);
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
if(ret > 0) {
/* Success */
plaintext_len += len;
return plaintext_len;
} else {
/* Verify failed */
return -1;
}
}
int main()
{
unsigned char plaintext[16] = "aaaabbbbccccdddd";
unsigned char add[16] = "aaaabbbbccccdddd";
unsigned char key[16] = "aaaabbbbccccdddd";
unsigned char iv[16] = "aaaabbbbccccdddd";
unsigned char ciphertext[16] = "\0";
unsigned char tag[16] = "\0";
unsigned char de_plaintext[16] = "\0";
gcm_encrypt(plaintext, 16, add, 16, key, iv, 16, ciphertext, tag);
print_hexdata(plaintext, 16, "plaintext");
print_hexdata(add, 16, "add");
print_hexdata(key, 16, "key");
print_hexdata(iv, 16, "iv");
print_hexdata(ciphertext, 16, "ciphertext");
print_hexdata(tag, 16, "tag");
gcm_decrypt(ciphertext, 16, add, 16, tag, key, iv, 16, de_plaintext);
print_hexdata(de_plaintext, 16, "de_plaintext");
printf("test ok\n");
return 0;
}
二、使用一组协议数据进行算法验证:
//gcc -g -lssl aead_test.c -lcrypto -L /usr/local/lib/
#include <string.h>
#include <openssl/evp.h>
struct aead_testvec {
const char *key;
const char *iv;
const char *ptext;
const char *assoc;
const char *ctext;
unsigned char novrfy;
unsigned char wk;
unsigned char klen;
unsigned int plen;
unsigned int clen;
unsigned int alen;
int setkey_error;
int setauthsize_error;
int crypt_error;
};
/* 256bit */
struct aead_testvec aes_gcm_tv_template_256[] = {
{
.key = "\xfe\xff\xe9\x92\x86\x65\x73\x1c"
"\x6d\x6a\x8f\x94\x67\x30\x83\x08"
"\xfe\xff\xe9\x92\x86\x65\x73\x1c"
"\x6d\x6a\x8f\x94\x67\x30\x83\x08",
.klen = 32,
.iv = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
"\xde\xca\xf8\x88",
.ptext = "\xd9\x31\x32\x25\xf8\x84\x06\xe5"
"\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
"\x86\xa7\xa9\x53\x15\x34\xf7\xda"
"\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
"\x1c\x3c\x0c\x95\x95\x68\x09\x53"
"\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
"\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
"\xba\x63\x7b\x39",
.plen = 60,
.assoc = "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
"\xfe\xed\xfa\xce\xde\xad\xbe\xef"
"\xab\xad\xda\xd2",
.alen = 20,
.ctext = "\x52\x2d\xc1\xf0\x99\x56\x7d\x07"
"\xf4\x7f\x37\xa3\x2a\x84\x42\x7d"
"\x64\x3a\x8c\xdc\xbf\xe5\xc0\xc9"
"\x75\x98\xa2\xbd\x25\x55\xd1\xaa"
"\x8c\xb0\x8e\x48\x59\x0d\xbb\x3d"
"\xa7\xb0\x8b\x10\x56\x82\x88\x38"
"\xc5\xf6\x1e\x63\x93\xba\x7a\x0a"
"\xbc\xc9\xf6\x62"
"\x76\xfc\x6e\xce\x0f\x4e\x17\x68"
"\xcd\xdf\x88\x53\xbb\x2d\x55\x1b",
.clen = 76,
}
};
void print_hexdata(unsigned char *b, int len, char *title)
{
int i = 0, c = 0;
printf("===================================== %s =====================================\n", title);
for (; i<len; i++) {
printf("0x%02x ", b[i]);
c++;
if (!(c%16))
printf("\n");
}
printf("\n");
}
int gcm_encrypt(unsigned char *plaintext, int plaintext_len,
unsigned char *aad, int aad_len,
unsigned char *key,
unsigned char *iv, int iv_len,
unsigned char *ciphertext,
unsigned char *tag)
{
EVP_CIPHER_CTX *ctx;
int len;
int ciphertext_len;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new()))
return -1;
/* Initialise the encryption operation. */
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
return -1;
/*
* Set IV length if default 12 bytes (96 bits) is not appropriate
*/
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
return -1;
/* Initialise key and IV */
if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv))
return -1;
/*
* Provide any AAD data. This can be called zero or more times as
* required
*/
if(1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len))
return -1;
printf("len:%d\n", len);
/*
* Provide the message to be encrypted, and obtain the encrypted output.
* EVP_EncryptUpdate can be called multiple times if necessary
*/
if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
return -1;
ciphertext_len = len;
printf("len:%d\n", len);
/*
* Finalise the encryption. Normally ciphertext bytes may be written at
* this stage, but this does not occur in GCM mode
*/
if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
return -1;
ciphertext_len += len;
printf("len:%d\n", len);
/* Get the tag */
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
return -1;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return ciphertext_len;
}
int gcm_decrypt(unsigned char *ciphertext, int ciphertext_len,
unsigned char *aad, int aad_len,
unsigned char *tag,
unsigned char *key,
unsigned char *iv, int iv_len,
unsigned char *plaintext)
{
EVP_CIPHER_CTX *ctx;
int len;
int plaintext_len;
int ret;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new()))
return -1;
/* Initialise the decryption operation. */
if(!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
return -1;
/* Set IV length. Not necessary if this is 12 bytes (96 bits) */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL))
return -1;
/* Initialise key and IV */
if(!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv))
return -1;
/*
* Provide any AAD data. This can be called zero or more times as
* required
*/
if(!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len))
return -1;
/*
* Provide the message to be decrypted, and obtain the plaintext output.
* EVP_DecryptUpdate can be called multiple times if necessary
*/
if(!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
return -1;
plaintext_len = len;
printf("len:%d\n", len);
/* Set expected tag value. Works in OpenSSL 1.0.1d and later */
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag))
return -1;
/*
* Finalise the decryption. A positive return value indicates success,
* anything else is a failure - the plaintext is not trustworthy.
*/
ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
printf("len:%d\n", len);
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
if(ret > 0) {
/* Success */
plaintext_len += len;
return plaintext_len;
} else {
/* Verify failed */
return -1;
}
}
int main()
{
unsigned char plaintext[60] =
"\xd9\x31\x32\x25\xf8\x84\x06\xe5"
"\xa5\x59\x09\xc5\xaf\xf5\x26\x9a"
"\x86\xa7\xa9\x53\x15\x34\xf7\xda"
"\x2e\x4c\x30\x3d\x8a\x31\x8a\x72"
"\x1c\x3c\x0c\x95\x95\x68\x09\x53"
"\x2f\xcf\x0e\x24\x49\xa6\xb5\x25"
"\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57"
"\xba\x63\x7b\x39";
unsigned char add[20] = "\xfe\xed\xfa\xce\xde\xad\xbe\xef"
"\xfe\xed\xfa\xce\xde\xad\xbe\xef"
"\xab\xad\xda\xd2";
unsigned char key[32] =
"\xfe\xff\xe9\x92\x86\x65\x73\x1c"
"\x6d\x6a\x8f\x94\x67\x30\x83\x08"
"\xfe\xff\xe9\x92\x86\x65\x73\x1c"
"\x6d\x6a\x8f\x94\x67\x30\x83\x08";
unsigned char iv[12] = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad"
"\xde\xca\xf8\x88";
unsigned char ciphertext[60] = "\0";
unsigned char tag[16] = "\0";
unsigned char de_plaintext[60] = "\0";
gcm_encrypt(plaintext, 60, add, 20, key, iv, 12, ciphertext, tag);
print_hexdata(plaintext, 60, "plaintext");
print_hexdata(add, 20, "add");
print_hexdata(key, 32, "key");
print_hexdata(iv, 12, "iv");
print_hexdata(ciphertext, 60, "ciphertext");
print_hexdata(tag, 16, "tag");
gcm_decrypt(ciphertext, 60, add, 20, tag1, key, iv, 12, de_plaintext);
print_hexdata(de_plaintext, 60, "de_plaintext");
printf("test ok\n");
return 0;
}
";
gcm_encrypt(plaintext, 16, add, 16, key, iv, 16, ciphertext, tag);
print_hexdata(plaintext, 16, "plaintext");
print_hexdata(add, 16, "add");
print_hexdata(key, 16, "key");
print_hexdata(iv, 16, "iv");
print_hexdata(ciphertext, 16, "ciphertext");
print_hexdata(tag, 16, "tag");
gcm_decrypt(ciphertext, 16, add, 16, tag, key, iv, 16, de_plaintext);
print_hexdata(de_plaintext, 16, "de_plaintext");
printf("test ok\n");
return 0;
}//gcc -g -lssl aead_t