openssl实现RSA+AES加密

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;
}

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值