zhaocen0 2019-06-22
一、安全问题出现
现在越来越多的人利用互联网支付,转账等功能,方便之余,难免会心生疑问,账号会不会被人盗取?这就对数据安全提出了挑战,为了解决这个问题,数据的加密就显得异常重要了。
二、基本概念
加解密的过程就是发送方将明文通过密钥计算变成密文,接收方再将密文通过密钥计算变成可明文,从而保证在信息传输过程中的具备:可鉴别,完整,防泄漏。
针对以上特性我们要着重介绍一下:对称算法、非对称算法,数字签名
对称算法
加解密使用同一个密钥,所以如何安全的传递密钥成了最头疼的问题。
(1) 甲方将明文使用密钥加密,密文传输给乙方。
(2) 乙方收到密文后,用同一个密钥,解密得到明文。
由于双方采用统一密钥规则,在传递和保持中如何保证密钥的安全,就成了头疼的问题。
### 非对称算法
加解密采用不同密钥,称为公钥和私钥,公私钥成对出现,采用公钥加密,只能用配对的私钥解密。
(1) 乙方生成一对公私钥,并将公钥给甲方
(2) 甲方利用乙方给的公钥将明文加密,生成密文,传输给乙方
(3) 乙方接收到密文,用配对的私钥解密,解出明文
这种方式私钥严格保密,公钥可以对外公布,解决了密钥传递和保存中的安全性问题。
在密码学中还有一个比较重要的概念就是确认发送方身份,也就是签名验证。
数字签名
数字签名,就是只有信息的发送者才能产生的别人无法伪造的一段数字串,这段数字串同时也是对信息的发送者发送信息真实性的一个有效证明。提到数字签名一定绕不开非对称算法和散列函数,数字签名有两个过程:签名和验证,具体的过程如下
(1) 乙方生成一对公私钥,并将公钥给甲方
(2) 乙方用其私钥对文件做加密,并签名
(3) 甲方对文件解密,并验证签名
由于文件内容做加解密算法比较费时,所以一般签名都是采用文件内容通过散列算法得出的字符串(图里的摘要可以认为就是这样的一串字符串)做私钥加密,从而得到一串签名数据,这样验签的效率就大大提升了。
算法举例
密码学发展到现在,涌现出来的算法有很多,比如对称算法中的des,aes,非对称算法中的RSA等,下面就以RSA做个实例解析。RSA的算法原理这里就不介绍了,请开wiki,直接上代码吧。本例子中的算法通过openssl的相关接口实现的。
RSA加密实现
// filename:密钥文件名 // plain_text:明文内容 // is_pubkey: true->公钥加密 false->私钥加密 // encrypt_txt:返回密文 int OpensslRSAUtil::encrypt(std::string filename, std::string plain_text, bool is_pubkey, std::string& encrypt_txt) { if (plain_text.empty()) { return eAuthCryptResult_PARAM_ERROR; } RSA* rsa = RSA_new(); if (!create_rsa(filename, is_pubkey, &rsa)) { if (rsa != NULL) RSA_free(rsa); return eAuthCryptResult_CREATE_RSA_ERROR; } // 分段加密 每段117个字节 int data_len = plain_text.length(); int offset = 0; int block_value = 0; std::string encrypt_data = ""; int code = eAuthCryptResult_SUCCESS; while(data_len > 0) { char encode[MAX_ENCRYPT_BLOCK_VALUE] = {0}; if (data_len >= MAX_ENCRYPT_BLOCK_VALUE) { block_value = MAX_ENCRYPT_BLOCK_VALUE; } else { block_value = data_len; } std::string ming = plain_text.substr(offset, block_value); int ret = 0; if (is_pubkey) { ret = RSA_public_encrypt(block_value, (const unsigned char*)ming.c_str(), (unsigned char*)encode, rsa, RSA_PKCS1_PADDING); } else { ret = RSA_private_encrypt(block_value, (const unsigned char*)ming.c_str(), (unsigned char*)encode, rsa, RSA_PKCS1_PADDING); } if (ret >= 0) { std::string encrypt_tmp(encode, ret); encrypt_data += encrypt_tmp; offset += block_value; data_len = data_len - block_value; } else { code = eAuthCryptResult_ENCRYPT_ERROR; break; } } if (code == eAuthCryptResult_SUCCESS) { // base64 加密 char* base64Text = NULL; int len = 0; cout << "len:" << encrypt_data.length()<<endl; base64_encode((const unsigned char*)encrypt_data.c_str(), encrypt_data.length(), &base64Text, len); if (base64Text == NULL) { code = eAuthCryptResult_BASE64_ENCODE_ERROR; } else { std::string tmp(base64Text, len); encrypt_txt = tmp; replaceString(encrypt_txt, " ", ""); free(base64Text); } } RSA_free(rsa); CRYPTO_cleanup_all_ex_data(); return code; }
RSA解密实现
// filename:密钥文件名
// plain_text:密文内容
// is_pubkey: true->公钥解密 false->私钥解密
// decrypt_txt:返回明文
int OpensslRSAUtil::decrypt(std::string filename, std::string plain_text, bool is_pubkey, std::string& decrypt_txt)
{
if (plain_text.empty())
{
return eAuthCryptResult_PARAM_ERROR;
}
RSA* rsa = RSA_new();
if (!create_rsa(filename, is_pubkey, &rsa)) {
if (rsa != NULL) RSA_free(rsa);
return eAuthCryptResult_CREATE_RSA_ERROR;
}
// base64解密
unsigned char* decode_data = NULL;
size_t data_len = 0;
base64_decode(plain_text.c_str(), &decode_data, &data_len);
if (decode_data == NULL) {
RSA_free(rsa);
return eAuthCryptResult_BASE64_ENCODE_ERROR;
}
// 分段解密 每段128个字节
int offset = 0;
int block_value = 0;
int code = eAuthCryptResult_SUCCESS;
while(data_len > 0) {
char decode[MAX_DECRYPT_BLOCK_VALUE];
if (data_len >= MAX_DECRYPT_BLOCK_VALUE) {
block_value = MAX_DECRYPT_BLOCK_VALUE;
} else {
block_value = data_len;
}
unsigned char* mi = decode_data + offset;
int ret = 0;
if (is_pubkey) {
ret = RSA_public_decrypt(block_value, mi, (unsigned char*)decode, rsa, RSA_PKCS1_PADDING);
} else {
ret = RSA_private_decrypt(block_value, mi, (unsigned char*)decode, rsa, RSA_PKCS1_PADDING);
}
if (ret >= 0) {
string tmp(decode, ret);
decrypt_txt += tmp;
offset += block_value;
data_len = data_len - block_value;
} else {
code = eAuthCryptResult_DECRYPT_ERROR;
char msg[1024];
print_last_error(msg);
break;
}
}
if (decode_data != NULL) {
free(decode_data);
}
RSA_free(rsa);
CRYPTO_cleanup_all_ex_data();
return code;
}
RSA签名实现
// privkey_filename:私钥文件名 // plain_text:明文内容 // signature:返回签名字符串 int OpensslRSAUtil::sign(std::string privkey_filename, std::string plain_text, std::string& signature) { if (plain_text.empty()) { return eAuthCryptResult_PARAM_ERROR; } RSA* rsa = RSA_new(); if (!create_rsa(privkey_filename, false, &rsa)) { if (rsa != NULL) RSA_free(rsa); return eAuthCryptResult_CREATE_RSA_ERROR; } unsigned char* encMessage = NULL; char* base64Text = NULL; int len = 0; size_t encMessageLength; int code = eAuthCryptResult_SUCCESS; if (rsa_sign(rsa, (unsigned char*)plain_text.c_str(), plain_text.length(), &encMessage, &encMessageLength)) { base64_encode(encMessage, encMessageLength, &base64Text, len); std::string tmp(base64Text, len); signature = tmp; replaceString(signature, " ", ""); } else { code = eAuthCryptResult_SIGN_ERROR; } if (encMessage != NULL) { free(encMessage); } if (base64Text != NULL) { free(base64Text); } RSA_free(rsa); CRYPTO_cleanup_all_ex_data(); return code; }
RSA验签实现
// pubkey_filename:私钥文件名 // plain_text:密文内容 // signature:签名字符串 // verify_result:返回验签结果 int OpensslRSAUtil::verify(std::string pubkey_filename, std::string plain_text, std::string signature, bool& verify_result) { if (plain_text.empty()) { return eAuthCryptResult_PARAM_ERROR; } RSA* rsa = RSA_new(); if (!create_rsa(pubkey_filename, true, &rsa)) { if (rsa != NULL) RSA_free(rsa); return eAuthCryptResult_CREATE_RSA_ERROR; } unsigned char* encMessage = NULL; size_t encMessageLength; bool authentic = false; base64_decode(signature.c_str(), &encMessage, &encMessageLength); bool result = rsa_verify_signature(rsa, encMessage, encMessageLength, plain_text.c_str(), plain_text.length(), authentic); int code = eAuthCryptResult_SUCCESS; if (result) { verify_result = authentic; } else { code = eAuthCryptResult_VERIFY_ERROR; } if (encMessage != NULL) { free(encMessage); } RSA_free(rsa); CRYPTO_cleanup_all_ex_data(); return code; }
结束
简单的介绍了一下,密码学的相关知识,偏实用,淡算法理论,有兴趣自己扩展,对实现代码有疑问,可以留言。
获取方式:
1.在你手机的右上角有【关注】选项,或点击我的头像,点击关注!(关注我)
2.关注后,手机客户端点击我的主页面,右上角有私信,请私信发我:编程
电脑已经设置好了关键词自动回复,自动领取就好了!这几天上万个消息,真的回复不过来,所以回复的时候请注意关键词!
其实做为一个开发者,有一个学习的氛围跟一个交流圈子特别重要这里请私信我“编程”不管你是小白还是大牛欢迎入住大家一起交流成长。小编会在里面不定期分享干货源码,包括我精心整理的一份c++零基础教程。欢迎各位感兴趣的的小伙伴。
学习思路:
学习资料: