lighttpd开启ssl是出现:(mod_openssl.c.872) SSL: not enough entropy in the pool错误(RAND_status函数失败),是因为我用的openssl-1.1.1g,改为openssl-1.1.1k就可以乐
eas加密:加密模式有很多,ecb,cbc等。key16-24-32字节,16字节为单位块进行加密
rsa:主要用于,公钥加密私钥解密
1.问题:PEM_read_RSAPublicKey函数返回NULL
rsa加密的public key格式有多种,常见的有两种,一种密钥头为‘-----BEGIN RSA PUBLIC KEY-----’,一种开头为‘-----BEGIN PUBLIC KEY-----’,二者分别对应rsa的PKCS#1和PKCS#8格式。使用openssl库加载rsa的公钥时,使用的函数也不同。以字符串公钥为例,对PKCS#1格式的密钥加载使用PEM_read_bio_RSAPublicKey()函数,对PKCS#8格式公钥的加载使用PEM_read_bio_RSA_PUBKEY()函数。
2.RSA_size(privateRsa)的长度是根据密钥长度决定的,RSA_generate_key(2048, RSA_F4, NULL, NULL);其中2048是私钥长度,RSA_size(privateRsa)=私钥长度/8。2048计算出来的长度为256,1024计算出来是128。
rsa加密长度不能大于RSA_size(privateRsa)-11(如128-11=117)个数据,否则报错。
3.int RSA_public_encrypt(int flen, const unsigned char *from, unsigned char *to,RSA *rsa, int padding)
其中flen <= RSA_size(privateRsa)-11;
from输入,可以是二进制数据。
to输出buffer,大小为RSA_size(privateRsa)。需要提前分配
padding没研究RSA_PKCS1_PADDING
4.签名和验签:
tmpbuf数组长度nOutLen=RSA_size(rsaCryptKey);请熟知。
RSA_sign(RSA_SHA_WORK_TYPE, md, RSA_SIGN_SHA_WORK_LEN, tmpbuf, &nOutLen, rsaCryptKey);
// 标签是用私钥签名,把摘要和签名一起发出去;公钥验签成功,说明内容没被篡改,并能确定是对应的私钥签名的。
int encryptRsaSignStr(string encstr, string &outsign)
{
outsign.clear();
if (!(rsaCryptKey && rsaKefFlag == 0))
{
printferr("%d", rsaKefFlag);
return -1;
}
u8 md[RSA_SIGN_SHA_WORK_LEN];
u8 *tmpbuf = NULL;
u32 nOutLen = 0;
int result = 0;
allocComMemrry(tmpbuf, RSA_size(rsaCryptKey));//[128] = {0};
if(tmpbuf == NULL)
{
printferr("");
return -2;
}
SHA_RSA_WORK((const u8 *)encstr.c_str(), encstr.length(), md);
result = RSA_sign(RSA_SHA_WORK_TYPE, md, RSA_SIGN_SHA_WORK_LEN, tmpbuf, &nOutLen, rsaCryptKey);
if(result != 1)
{
printferr("RSA_sign err !!! \n");
goto signOutFree;
result = -3;
}
outsign.append((char *)tmpbuf, nOutLen);
result = 0;
signOutFree:
freeComMemrry(tmpbuf);
return result;
}
// 标签是用私钥签名,把摘要和签名一起发出去;公钥验签成功,说明内容没被篡改,并能确定是对应的私钥签名的。
int encryptRsaVerifyStr(string encstr, string signstr)
{
if (!(rsaCryptKey && rsaKefFlag != 0))
{
printferr("%d", rsaKefFlag);
return -1;
}
u8 md[RSA_SIGN_SHA_WORK_LEN];
int result = 0;
SHA_RSA_WORK((const u8 *)encstr.c_str(), encstr.length(), md);
result = RSA_verify(RSA_SHA_WORK_TYPE, md, RSA_SIGN_SHA_WORK_LEN, (u8 *)signstr.c_str(),
signstr.length(), rsaCryptKey);
if(result != 1)
{
//printferr("RSA_verify err !!! \n");
return -2;
}
return 0;
}
这里阐述个人观点:
1.加密就是为了数据安全,知己知彼方能百战百胜,需要知道攻击者的手段,和各种加密的优缺点。
2.AES比RSA快;钥匙均私有,双方数据均安全;包以16字节为单位,可以更小。缺点:破解AES钥匙快,需要频繁换钥匙;钥匙只有一把,需要通讯双方保密。
3.RSA的公钥是谁都能拿到的,说明私钥加密的内容不安全,私钥加密没有意义!所以主要场景用于:公钥加密->私钥解密。
4.服务器和设备自身原始数据安全,也是很重要的。
5.网络安全(中间人攻击),在数据发出去之后,任何事情都有可能:a.数据被截取,篡改,发送到目的机;b.数据被截取,直接应答发送机。
6.先说网页,网站这东西其实很不安全,即便用HTTPS。因为大家的习惯直接点击链接,容易进入钓鱼网站,其实觉得IE浏览器(CA验证特别严,不认识的就不进;而火狐和360只是屏蔽一致不安全网页)不好用的,在这一方面还是可以的。
7.HTTPS流程:a.客服端请求连接;b.服务器发送CA认证数据,CA认证数据由CA机构的私钥生成,公钥固定的,认证数据不好伪造;c.客服端验证通过,拿到服务器公钥,发送密码登录。
8.所以如果自定义网络,可以参考https流程。CA认证数据,那就在搞一个自己的认证摘要即可,这个认证数据使用另一个固定的公私钥来做,和通讯的公钥分开。因为通讯的公钥是服务器临时发出来的,攻击者也可以伪造一个公钥给客服端。
9.自定义流程:
a.tcp连接成功,客户端发起认证请求,附带(客服端通讯版本号VC1,随机数(RANDSTR)生成的MD5字符串STR1)。
b.服务器通过版本号得到VC1私钥,并用VC1私钥对摘要(STR1 + 服务器通讯版本VC2 + VC2对应的公钥 + 有效日期)做一个签名(SIGN),然后摘要和签名一起发给客户端。
c.客户端使用版本号VC1公钥对摘要和签名进行验签;如果验签成功,说明服务器可信,记住VC2 + VC2对应的公钥;并用VC2公钥加密(随机数RANDSTR + 一个随机AES钥匙)发送给服务器。
d.服务器使用VC2私钥解密获得RANDSTR和AES钥匙,如果RANDSTR生成的MD5字符串STR2与(第二歩获得STR1)相等; 说明客户端正确,握手成功,AES钥匙可以和对应客户端正常使用。
e.之后使用AES通讯。
10.关于DES3+iv+PKCS5Padding程序
参考:
https://blog.youkuaiyun.com/goodstudy168/article/details/72779077
#ifndef __DES3_ENCODE_DECODE_H__
#define __DES3_ENCODE_DECODE_H__
#include <types.h>
#include <openssl/des.h>
//备注:我这里只测试了CBC
//备注:PKCS5Padding,zeropadding需要手动添加
enum DEC_CODE_MODE_LIST
{
CBC = 0,
CFB,
ECB
};
class Des3EncDecClass
{
public:
/*
使用DES算法对数据加密
desKey 密钥,支持单倍、双倍、三倍
data 源数据 长度必须为8的倍数
mode 加密模式 ECB CBC CFB
iv 仅 CBC CFB两种模式才有此值,长度为8字节
返回值:
>=0 加密数据的长度
<0 错误码
*/
static int DesEncryptData(const string &desKey, string &data, int mode, const string &iv, string &encData)
{
int keyLen = 0, x = 0;
long dataLen = 0;
DES_key_schedule ks1, ks2, ks3;
unsigned char tmpData[8], ke1[8], ke2[8], ke3[8], ivec[8];
// unsigned char input[8192], output[8192];
keyLen = desKey.length();
dataLen = data.length();
if (keyLen == 0 || dataLen == 0)
return -1;
long tmplen = 8 - dataLen % 8;
for(int i = 0; i < tmplen; i++)
{
data += tmplen;//DESede/CBC/PKCS5Padding
// data += 0;//zeropadding
}
dataLen += tmplen;
unsigned char *output = NULL;
const unsigned char *input = (const u8*)data.data();
output = newwork u8[dataLen];
encData.clear();
if(output == NULL)
{
return -2;
}
// memset(input, 0, 8192);
// memset(output, 0, 8192);
// memcpy(input, data.c_str(), dataLen);
switch (keyLen)
{
case 8:
memset(ke1, 0, 8);
memcpy(ke1, desKey.c_str(), 8);
DES_set_key_unchecked((const_DES_cblock*)ke1, &ks1);
switch (mode)
{
case CBC:
memcpy(ivec, iv.c_str(), 8);
DES_cbc_encrypt(input, output, dataLen, &ks1, (DES_cblock *)ivec, DES_ENCRYPT);
break;
case CFB:
memcpy(ivec, iv.c_str(), 8);
DES_cfb_encrypt(input, output, 8, dataLen, &ks1, (DES_cblock *)ivec, DES_ENCRYPT);
break;
case ECB:
default:
for (x=0;x<dataLen;x+=8)
{
memcpy(tmpData, input+x, 8);
DES_ecb_encrypt((const_DES_cblock*)tmpData, (DES_cblock *)(output+x), &ks1, DES_ENCRYPT);
}
break;
}
break;
case 16:
case 24:
memset(ke1, 0, 8);
memset(ke2, 0, 8);
memset(ke3, 0, 8);
if (keyLen == 16)
{
memcpy(ke1, desKey.c_str(), 8);
memcpy(ke2, desKey.c_str()+8, 8);
memcpy(ke3, desKey.c_str(), 8);
}else
{
memcpy(ke1, desKey.c_str(), 8);
memcpy(ke2, desKey.c_str()+8, 8);
memcpy(ke3, desKey.c_str()+16, 8);
}
DES_set_key_unchecked((const_DES_cblock*)ke1, &ks1);
DES_set_key_unchecked((const_DES_cblock*)ke2, &ks2);
DES_set_key_unchecked((const_DES_cblock*)ke3, &ks3);
switch (mode)
{
case CBC:
memcpy(ivec, iv.c_str(), 8);
DES_ede3_cbc_encrypt(input, output, dataLen, &ks1, &ks2, &ks3, (DES_cblock *)ivec, DES_ENCRYPT);
break;
case CFB:
memcpy(ivec, iv.c_str(), 8);
DES_ede3_cfb_encrypt(input, output, 8, dataLen, &ks1, &ks2, &ks3, (DES_cblock *)ivec, DES_ENCRYPT);
case ECB:
default:
for (x=0;x<dataLen;x+=8)
{
memcpy(tmpData, input+x, 8);
DES_ecb3_encrypt((const_DES_cblock*)tmpData, (DES_cblock *)(output+x), &ks1, &ks2, &ks3, DES_ENCRYPT);
}
break;
}
break;
default:
dataLen = -1;
break;
}
if (dataLen > 0)
{
// string result((char *)output, dataLen);
// encData = result;
encData.append((char *)output, dataLen);
}
deleteComClassArray(output);
return dataLen;
}
/*
使用DES算法对数据解密
desKey 密钥,支持单倍、双倍、三倍
data 源数据 长度必须为8的倍数
mode 加密模式 ECB CBC CFB
iv 仅CBC CFB两种模式才有此值
*/
static int DesDecryptData(const string &desKey, const string &data, int mode, const string &iv, string &plainData)
{
int keyLen = 0, x = 0;
long dataLen = 0;
DES_key_schedule ks1, ks2, ks3;
unsigned char tmpData[8], ke1[8], ke2[8], ke3[8], ivec[8];
// unsigned char input[8192], output[8192];
keyLen = desKey.length();
dataLen = data.length();
plainData.clear();
if (keyLen == 0 || dataLen == 0)
return -1;
unsigned char *output = NULL;
const unsigned char *input = (const u8*)data.data();
output = newwork u8[dataLen];
if(output == NULL)
{
return -2;
}
// memset(input, 0, 8192);
// memset(output, 0, 8192);
// memcpy(input, data.c_str(), dataLen);
switch (keyLen)
{
case 8:
memset(ke1, 0, 8);
memcpy(ke1, desKey.c_str(), 8);
DES_set_key_unchecked((const_DES_cblock*)ke1, &ks1);
switch (mode)
{
case CBC:
memcpy(ivec, iv.c_str(), 8);
DES_cbc_encrypt(input, output, dataLen, &ks1, (DES_cblock *)ivec, DES_DECRYPT);
break;
case CFB:
memcpy(ivec, iv.c_str(), 8);
DES_cfb_encrypt(input, output, 8, dataLen, &ks1, (DES_cblock *)ivec, DES_DECRYPT);
break;
case ECB:
default:
for (x=0;x<dataLen;x+=8)
{
memcpy(tmpData, input+x, 8);
DES_ecb_encrypt((const_DES_cblock*)tmpData, (DES_cblock *)(output+x), &ks1, DES_DECRYPT);
}
break;
}
break;
case 16:
case 24:
memset(ke1, 0, 8);
memset(ke2, 0, 8);
memset(ke3, 0, 8);
if (keyLen == 16)
{
memcpy(ke1, desKey.c_str(), 8);
memcpy(ke2, desKey.c_str()+8, 8);
memcpy(ke3, desKey.c_str(), 8);
}else
{
memcpy(ke1, desKey.c_str(), 8);
memcpy(ke2, desKey.c_str()+8, 8);
memcpy(ke3, desKey.c_str()+16, 8);
}
DES_set_key_unchecked((const_DES_cblock*)ke1, &ks1);
DES_set_key_unchecked((const_DES_cblock*)ke2, &ks2);
DES_set_key_unchecked((const_DES_cblock*)ke3, &ks3);
switch (mode)
{
case CBC:
memcpy(ivec, iv.c_str(), 8);
DES_ede3_cbc_encrypt(input, output, dataLen, &ks1, &ks2, &ks3, (DES_cblock *)ivec, DES_DECRYPT);
break;
case CFB:
memcpy(ivec, iv.c_str(), 8);
DES_ede3_cfb_encrypt(input, output, 8, dataLen, &ks1, &ks2, &ks3, (DES_cblock *)ivec, DES_DECRYPT);
case ECB:
default:
for (x=0;x<dataLen;x+=8)
{
memcpy(tmpData, input+x, 8);
DES_ecb3_encrypt((const_DES_cblock*)tmpData, (DES_cblock *)(output+x), &ks1, &ks2, &ks3, DES_DECRYPT);
}
break;
}
break;
default:
dataLen = -1;
break;
}
if (dataLen > 0)
{
// string result((char *)output, dataLen);
// plainData = result;
plainData.append((char *)output, dataLen);
}
return dataLen;
}
};
#endif