openssl

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.csdn.net/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

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值