RSA+AES加密是传输数据过程中常用的一种加密方式,通讯双方都要实现加密解密过程,作为java,有接口,直接调用就好了,然而作为C语言这一端,加解密起来就比较蛋疼了,最近折腾了一下,这里留个脚印
AES加密算法
AES是一种对称加密算法,有几种加密方式(ecb,cbc,cfb等等),这里不细说,可以看这里 https://blog.csdn.net/qq_28205153/article/details/55798628
AES 秘钥可以为128,192,156位,AES-128最为常用。
ECB模式(电子密码本模式:Electronic codebook),是最简单的AES加密方式,只需要一个秘钥,将明文分组(每一组为16字节)后,一组一组与秘钥key经过一通变换,最后变成一组组的密文,然后把所有分组的密文拼起来,就变成了最后的密文
CBC模式(密码分组链接:Cipher-block chaining),是目前最常用的AES加密方式,除了需要一个秘钥,还需要一个初始向量iv(initialization vector),通常也和秘钥长度一致(128位,16字节),将明文分组(每一组位16字节)后,将初始向量iv与第一个分组 异或,得到结果后再与秘钥key经过一通变换,变成第一组密文,之后的分组也是这样变换,只是第二组开始iv变成前一个分组的密文
RSA加密算法
RSA是一种非对称加密算法(加密和解密的秘钥不同),通常为一对秘钥,称为公钥和私钥,公钥用来加密,私钥用来解密
公钥是公开的,别人要给你发信息,就用你的公钥把消息加密后发给你
私钥是私有的,只有你自己有,你收到了加密的消息,就用你的私钥解密,之后就能看到明文消息了
具体可以看这里 https://blog.csdn.net/huanhuanq1209/article/details/80614271
RSA加密算法安全性比较高,但比较耗时,所以通常用来加密AES秘钥,而真正的消息内容,则采用AES加密,所以通常RSA+AES加密,传输的内容格式为
RSA加密AES秘钥后的密文 ;AES加密data数据后的密文
解密的时候,先利用RSA解密出AES的秘钥,然后用AES秘钥才解密后面的data
越写越觉得要写的东西太多,感觉需要总结很久才能总结清楚,不折腾了,直接上代码吧
static RSA * m_pRsaPublic;
static RSA * m_pRsaPrivate;
int aes_encrypt_pkcs5_padding(char *in, int len, char *out, char *key)
{
if (!in || !key || !out) return 0;
AES_KEY aes;
if (AES_set_encrypt_key((unsigned char *)key, 128, &aes) < 0)
return 0;
int en_len = 0;
int do_len = len <= strlen(in) ? len : strlen(in);
// add padding
int padding_size = AES_BLOCK_SIZE - (len % AES_BLOCK_SIZE);
char *str = (char *)malloc(do_len + padding_size + 1);
char *p = str;
memcpy(str, in, do_len);
for (int i = 0; i < padding_size; i++)
{
str[len + i] = padding_size;
}
str[len + padding_size] = '\0';
while (en_len < len + padding_size)
{
AES_encrypt((unsigned char *)str, (unsigned char *)out, &aes);
str += AES_BLOCK_SIZE;
out += AES_BLOCK_SIZE;
en_len += AES_BLOCK_SIZE;
}
free(p);
return en_len;
}
int aes_decrypt_pkcs5_padding(char *in, int len, char *out, char *key)
{
if (!in || !key || !out) return 0;
AES_KEY aes;
if (AES_set_decrypt_key((unsigned char *)key, 128, &aes) < 0)
return 0;
int de_len = 0;
char *s = out;
while (de_len < len)
{
AES_decrypt((unsigned char *)in, (unsigned char *)s, &aes);
in += AES_BLOCK_SIZE;
s += AES_BLOCK_SIZE;
de_len += AES_BLOCK_SIZE;
}
// remove padding
int padding = out[de_len - 1];
if (padding > 0 && padding <= AES_BLOCK_SIZE)
{
for (int i = 0; i < padding; i++)
{
out[de_len - 1 - i] = '\0';
}
}
else
{
padding = 0;
}
return de_len - padding;
}
EVP_PKEY* OpenPublicKeyFile(const char *strKeyFile)
{
EVP_PKEY* key = NULL;
BIO *bp = NULL;
m_pRsaPublic = NULL;
bp = BIO_new(BIO_s_file());;
BIO_read_filename(bp, strKeyFile);
if (NULL == bp)
{
// printf("open_public_key bio file new error!\n");
return NULL;
}
m_pRsaPublic = PEM_read_bio_RSAPublicKey(bp, NULL, NULL, NULL);
if (m_pRsaPublic == NULL)
{
// printf("open_public_key failed to PEM_read_bio_RSAPublicKey!\n");
BIO_free(bp);
RSA_free(m_pRsaPublic);
return NULL;
}
// printf("open_public_key success to PEM_read_bio_RSAPublicKey!\n");
key = EVP_PKEY_new();
if (NULL == key)
{
// printf("open_public_key EVP_PKEY_new failed\n");
RSA_free(m_pRsaPublic);
return NULL;
}
EVP_PKEY_assign_RSA(key, m_pRsaPublic);
return key;
}
EVP_PKEY* OpenPrivateKeyFile(const char *strKeyFile, const char *strKeyPassWord)
{
EVP_PKEY* key = NULL;
BIO *bp = NULL;
m_pRsaPrivate = RSA_new();
bp = BIO_new_file(strKeyFile, "rb+");
if (NULL == bp)
{
printf("open_private_key bio file new error!\n");
return NULL;
}
m_pRsaPrivate = PEM_read_bio_RSAPrivateKey(bp, &m_pRsaPrivate, NULL, (void *)strKeyPassWord);
if (m_pRsaPrivate == NULL)
{
printf("open_private_key failed to PEM_read_bio_RSAPrivateKey!\n");
BIO_free(bp);
RSA_free(m_pRsaPrivate);
return NULL;
}
printf("open_private_key success to PEM_read_bio_RSAPrivateKey!\n");
key = EVP_PKEY_new();
if (NULL == key)
{
printf("open_private_key EVP_PKEY_new failed\n");
RSA_free(m_pRsaPrivate);
return NULL;
}
EVP_PKEY_assign_RSA(key, m_pRsaPrivate);
return key;
}
char * EncodeRSAKeyFile(char * strData)
{
int nLen = 0;
int ret = 0;
char* pEncode = NULL;
if (strlen(strData) == 0)
{
return NULL;
}
nLen = RSA_size(m_pRsaPublic);
pEncode = (char *)malloc(nLen + 1);
ret = RSA_public_encrypt((int)strlen(strData), (const unsigned char*)strData, (unsigned char*)pEncode, m_pRsaPublic, RSA_PKCS1_PADDING);
// pEncode[nLen] = '\0';
RSA_free(m_pRsaPublic);
CRYPTO_cleanup_all_ex_data();
return pEncode;
}
char * DecodeRSAKeyFile(char * strData)
{
int nLen = 0;
int ret = 0;
char *pDecode = NULL;
if (strlen(strData) == 0)
{
return NULL;
}
nLen = RSA_size(m_pRsaPrivate);
pDecode = (char *)malloc(nLen + 1);
memset(pDecode, 0, nLen + 1);
ret = RSA_private_decrypt(nLen, (const unsigned char*)strData, (unsigned char*)pDecode, m_pRsaPrivate, RSA_PKCS1_PADDING);
RSA_free(m_pRsaPrivate);
CRYPTO_cleanup_all_ex_data();
return pDecode;
}
char *padding_buf(char *str, int len)
{
int do_len = len <= strlen(str) ? len : strlen(str);
// add padding
int padding_size = AES_BLOCK_SIZE - (len % AES_BLOCK_SIZE);
char *out = (char *)malloc(do_len + padding_size + 1);
memcpy(out, str, do_len);
for (int i = 0; i < padding_size; i++)
{
out[do_len + i] = padding_size;
}
out[do_len + padding_size] = '\0';
return out;
}
char *remove_padding(char *str, int len)
{
// remove padding
int padding = str[len - 1];
if (padding > 0 && padding <= AES_BLOCK_SIZE)
{
for (int i = 0; i < padding; i++)
{
str[len - 1 - i] = '\0';
}
}
else
{
padding = 0;
}
return str;
}
#define BASE64_LEN(len) ((len % 3) ? (len / 3 * 4 + 4) : (len / 3 * 4))
#define RSA_PRIKEY_FILE "rsa_pri.key"
#define RSA_PUBKEY_FILE "rsa_pub.key"
char *decrypt_aes_data(char *data, int len, char *key)
{
int decoded_len = 0;
char *base64_data = (char *)malloc(len + 1);
char *decoded_data = (char *)malloc(len);
memset(base64_data, 0, len + 1);
memcpy(base64_data, data + 1, len);
// printf("decrypt 1111 len=[%d]", len);
decoded_len = base64_decode(base64_data, len, (unsigned char *)decoded_data);
decoded_data[decoded_len] = '\0';
// printf("decrypt 2222 decoded_len=[%d]", decoded_len);
char *decoded_msg = (char *)malloc(len);
int dlen = aes_decrypt_pkcs5_padding(decoded_data, decoded_len, decoded_msg, key);
decoded_msg[dlen] = '\0';
// printf("decrypt 2222 dlen=[%d]", dlen);
free(base64_data);
free(decoded_data);
return decoded_msg;
}
char *get_aes_key(const char *data, int len)
{
int key_len = 0;
char * key = NULL;
char *base64_key = (char *)malloc(len + 1);
char *decoded_key = (char *)malloc(len);
memset(base64_key, 0, len + 1);
memcpy(base64_key, data, len);
key_len = base64_decode(base64_key, len, (unsigned char *)decoded_key);
// printf("get_aes_key, base64 decoded len=[%d]", key_len);
decoded_key[key_len] = '\0';
OpenPrivateKeyFile(RSA_PRIKEY_FILE, NULL);
key = DecodeRSAKeyFile(decoded_key);
free(base64_key);
free(decoded_key);
return key;
}
char *encrypt_and_encode(char *data, int len)
{
char *rsa_key = NULL;
char *out_str = NULL;
char *base64_data = NULL;
char *base64_key = NULL;
int base64_data_len = 0;
int base64_key_len = 0;
char *aes_key = "iiiioooojjjjpppp";
// rsa encrypt key
OpenPublicKeyFile(RSA_PUBKEY_FILE);
rsa_key = EncodeRSAKeyFile(aes_key);
base64_key_len = BASE64_LEN(128);
base64_key = (char *)malloc(base64_key_len + 1);
memset(base64_key, 0, base64_key_len + 1);
base64_encode((unsigned char*)rsa_key, base64_key, 128);
char *aes_data = (char *)malloc((len / AES_BLOCK_SIZE) * AES_BLOCK_SIZE + AES_BLOCK_SIZE + 1);
int aes_data_len = aes_encrypt_pkcs5_padding(data, len, aes_data, aes_key);
base64_data_len = BASE64_LEN(aes_data_len);
base64_data = (char *)malloc(base64_data_len + 1);
memset(base64_data, 0, base64_data_len + 1);
base64_encode((unsigned char*)aes_data, base64_data, aes_data_len);
out_str = (char *)malloc(base64_data_len + base64_key_len + 1 + 1);
sprintf_s(out_str, base64_data_len + base64_key_len + 2, "%s;%s", base64_key, base64_data);
out_str[base64_data_len + base64_key_len + 1] = '\0';
free(aes_data);
free(rsa_key);
free(base64_data);
free(base64_key);
return out_str;
}
int main()
{
#if 0
// RSA+AES ECB
char *aes_key = NULL;
char *str = "AAAABBBBCCCCDDDDEEEEFFFF";
char *data = encrypt_and_encode(str, (int)strlen(str));
int len = (int)strlen(data);
char *split = strchr((char *)data, ';');
if (split)
{
aes_key = get_aes_key(data, int(split - data));
}
char *msg = decrypt_aes_data(split, (len - (int)(split - data + 1)), aes_key);
free(data);
free(aes_key);
free(msg);
#endif
// AES CBC
char *key = "iiiioooojjjjpppp";
char iv[AES_BLOCK_SIZE];
for (int i = 0; i<AES_BLOCK_SIZE; ++i)
iv[i] = 'a' + i;
char *str = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIII";
char *data = (char *)malloc(1024 + 1);
char *buf = (char *)malloc(1024 + 1);
memset(data, 0, 1024 + 1);
memset(buf, 0, 1024 + 1);
char *pbuf = padding_buf(str, strlen(str));
AES_KEY aes;
if (AES_set_encrypt_key((unsigned char *)key, 128, &aes) < 0)
return 0;
AES_cbc_encrypt((unsigned char*)pbuf, (unsigned char*)data, strlen(pbuf), &aes, (unsigned char*)iv, AES_ENCRYPT);
printf("len=[%d]--[%d]\n", strlen(pbuf), strlen(data));
for (int i = 0; i < strlen(data); i++)
{
printf("%02x ", data[i]);
}
printf("\n");
for (int i = 0; i<AES_BLOCK_SIZE; ++i)
iv[i] = 'a' + i;
if (AES_set_decrypt_key((unsigned char *)key, 128, &aes) < 0)
return 0;
AES_cbc_encrypt((unsigned char*)data, (unsigned char*)buf, strlen(data), &aes, (unsigned char*)iv, AES_DECRYPT);
remove_padding(buf, strlen(buf));
return 0;
}