0


c++中的OpenSSL加密(对称与非对称)

使用OpenSSL实现安全加密通信的服务器与客户端项目
https://gitee.com/lzhiqiang1999/sec-tans
欢迎star

一 哈希算法

1 特点:

  • 不可逆
  • 抗碰撞性强 - 不同的数据拥有不同的哈希值, 相同的数据哈希值是相同的
  • 原始数据有细微的变化, 哈希值的变化是非常大的
  • 通过哈希函数将原始数据进行运算, 得到的哈希值长度是固定的
  • 原始的哈希值是一个定长的二进制字符串

2 常用哈希算法:

  • md5。散列值: 16byte
  • sha1。散列值: 20byte
  • sha224。散列值: 28byte
  • sha256。散列值: 32byte
  • sha384。散列值: 48byte
  • sha512。散列值: 64byte

以上说的散列值长度是二进制数据长度, 一般散列值使用 16 进制格式的数字串表示的, 看到的字符串长度是原来的2倍长。

3 OpenSSL下的函数使用

// 使用的头文件#include<openssl/md5.h>#include<openssl/sha.h>#defineMD5_DIGEST_LENGTH16// md5哈希值长度// 初始化函数, 初始化参数 cintMD5_Init(MD5_CTX *c);
    参数c: 传出参数
// 添加md5运算的数据,此时还没有计算哈希值// 该函数可以进行多次数据添加 -> 函数多次调用intMD5_Update(MD5_CTX *c,constvoid*data, size_t len);
    参数:- c:MD5_Init() 初始化得到的
        - data: 传入参数, 字符串
        - len: data数据的长度
// 对添加的数据进行md5计算        intMD5_Final(unsignedchar*md, MD5_CTX *c);
    参数:- md: 传出参数, 存储得到的哈希值
        - c:MD5_Init() 初始化得到的

// 通过传递的参数, 直接生成一个md5哈希值// 只能添加一次数据unsignedchar*MD5(constunsignedchar*d, size_t n,unsignedchar*md);
    参数:- d: 传入, 要进行md5运算的字符串
        - n: 字符串的的长度
        - md: 传出, 存储md5的哈希值
    返回值: 这个地址的函数第三个参数md地址

二 对称加密

1 特点:

  • 秘钥短、效率高、强度低、分发困难(需要配合非对称加密)
  • 秘钥只有一个
  • 加解密使用的秘钥相同
  • 结合Base64使用

2 3DES对称加密算法

重复3次DES,使用3个密钥,实现加密→解密→加密的过程。
在这里插入图片描述
在这里插入图片描述
3 AES对称加密算法

(1)特点:

  • 最安全,效率最高
  • 秘钥长度:16字节、24字节、32字节
  • 分组加密,每组长度16字节
  • 每组秘文和明文长度相同 == 16字节

(2)生成加密/解密的Key

#include<openssl/aes.h>#defineAES_BLOCK_SIZE16// 明文分组的大小// 加密的时候调用// aes中的秘钥格式 AES_KEY// 封装加密时候使用的秘钥
AES_KEY key;intAES_set_encrypt_key(constunsignedchar*userKey,constint bits, AES_KEY *key);// 封装解密时候使用的秘钥intAES_set_decrypt_key(constunsignedchar*userKey,constint bits, AES_KEY *key);

(3)CBC方式加密 - 密码分组链接模式

voidAES_cbc_encrypt(constunsignedchar*in,unsignedchar*out,
                     size_t length,const AES_KEY *key,unsignedchar*ivec,constint enc);
    参数:- in: 要加密/解密的数据
        - out: 传出参数
            - 加密: 存储密文
            - 解密: 存储明文
        - length: 必须是16的整数倍,out的长度
            -(len =(字符串长度 + \0)%16)==0- 如果不是在函数内部会自动填充
                - 实际长度:((len /16)+1)*16- key: 初始化之后的秘钥
        - ivec: 初始化向量, 字符串 ==> 长度和分组长度相同
        - enc: 指定数据要解密还是解密
            - # define AES_ENCRYPT     1-> 加密
            - # define AES_DECRYPT     0-> 解密

三 非对称加密

1 特点:

  • 秘钥是一个密钥对: 公钥, 私钥- 公钥加密, 必须私钥解密- 私钥加密, 必须公钥解密
  • 加密强度比较高, 效率低 - 不会使用非对称加密, 加密特别大的数据

2 应用场景:

  • 秘钥分发对称加密的密钥- 核心思想: 加密的时候, 公钥加密, 私钥解密- 分发步骤: - 假设A, B两端- A端生成了一个密钥对, 分发公钥, B端有了公钥- B端生成一个对称加密的秘钥, 使用公钥加密 -> 密文- B将密文发送给A- A接收数据 -> 密文, 使用私钥对密文解密 -> 对称加密的秘钥
  • 数字签名:验证数据是否被篡改, 验证数据的所有者- 核心思想: 私钥加密, 公钥解密- A, B两端, 假设A要发送数据 - A端生成一个密钥对, 将公钥进行分发, 自己留私钥- 签名 - A对原始数据进行哈希运算 -> 哈希值- A使用私钥对哈希值加密 -> 密文- 将原始数据+密文发送给B- 校验签名 - B接收数据: 密文 + 收到的原始数据- 使用公钥对密文解密 -> 哈希值old- 使用has算法对收到的数据进行哈希运算 -> 哈希值new- 比较这两个哈希值 - 相同: 校验成功- 不同: 失败

3 生成、保存、读取密钥

#include<openssl/rsa.h>// 申请一块内存, 存储了公钥和私钥// 如果想得到RSA类型变量必须使用 RSA_new();
RSA *RSA_new(void);voidRSA_free(RSA *);

BIGNUM*BN_new(void);voidBN_free(BIGNUM*);// 生成密钥对, 密钥对存储在内存中intRSA_generate_key_ex(RSA *rsa,int bits, BIGNUM *e, BN_GENCB *cb);
    参数:- rsa: 通过RSA_new()获得
        - bits: 秘钥长度, 单位: bit, 常用的长度 1024*n(n正整数)- e: 比较大的数(5位以内)- 通过 BN_new 得到对应的变量
            - 初始化:BN_set_word(e,12345);- cb: 回调函数, 用不到, 直接写NULL// rsa公钥私钥类型是一样的: RSA类型// 将参数rsa中的公钥提取出来
RSA *RSAPublicKey_dup(RSA *rsa);- rsa参数: 秘钥信息
    - 返回值: rsa公钥
// 将参数rsa中的私钥提取出来
RSA *RSAPrivateKey_dup(RSA *rsa);- rsa参数: 秘钥信息
    - 返回值: rsa私钥

// 创建bio对象// 密钥对写磁盘文件的时候, 需要编码 -> base64// 封装了fopen
BIO *BIO_new_file(constchar*filename,constchar*mode);
    参数:- filename: 文件名
        - mode: 文件打开方式和fopen打开方式的指定相同
        
intPEM_write_bio_RSAPublicKey(BIO* bp,const RSA* r);intPEM_write_bio_RSAPrivateKey(BIO* bp,const RSA* r,const EVP_CIPHER* enc,unsignedchar* kstr,int klen, pem_password_cb *cb,void* u);
RSA*PEM_read_bio_RSAPublicKey(BIO* bp, RSA** r, pem_password_cb *cb,void* u);
RSA*PEM_read_bio_RSAPrivateKey(BIO* bp, RSA** r, pem_password_cb *cb,void* u);
    参数:- bp: 通过BIO_new_file();函数得到该对象
        - r: 传递一个RSA* rsa指针的地址, 传出参数-> 公钥/私钥
        - cb: 回调函数, 用不到, 指定为NULL- u: 给回调传参, 用不到, 指定为NULL//从FILE中读公私钥
RSA*PEM_read_RSAPublicKey(FILE* fp, RSA** r, pem_password_cb *cb,void* u);
RSA*PEM_read_RSAPrivateKey(FILE* fp, RSA** r, pem_password_cb *cb,void* u);// 写入文件中的公钥私钥数据不是原始数据, 写入的编码之后的数据// 是一种pem的文件格式, 数据使用base64进行编码intPEM_write_RSAPublicKey(FILE* fp,const RSA* r);intPEM_write_RSAPrivateKey(FILE* fp,const RSA* r,const EVP_CIPHER* enc,unsignedchar* kstr,int klen, pem_password_cb *cb,void* u);    
    参数:- fp: 需要打开一个磁盘文件, 并且指定写权限
        - r: 存储了密钥对
         - 私钥独有的参数- enc: 指定的加密算法 -> 对称加密 ->NULL- kstr: 对称加密的秘钥 ->NULL- klen: 秘钥长度 ->0- cb: 回调函数, 用不到,NULL- u: 给回调传参, 用不到,NULL

4 加密

以块的方式进行加密的, 加密的数据长度, 不能大于秘钥长度

  • 假设: 秘钥长度: 1024bit = 128byte

数据被加密之后, 长度<秘钥长度

// 公钥加密intRSA_public_encrypt(int flen,constunsignedchar*from,unsignedchar*to, RSA *rsa,int padding);// 私钥解密intRSA_private_decrypt(int flen,constunsignedchar*from,unsignedchar*to, RSA *rsa,int padding);  签名使用 /// // 私钥加密intRSA_private_encrypt(int flen,constunsignedchar*from,unsignedchar*to, RSA *rsa,int padding);// 公钥解密intRSA_public_decrypt(int flen,constunsignedchar*from,unsignedchar*to, RSA *rsa,int padding);
参数:- flen: 要加密/解密的数据长度
        长度 0< flen <= 秘钥长度-11- from: 传入, 要加密/解密的数据
    - to: 传出, 存储数据, 加密->存储密文, 解密->存储明文
    - rsa: 秘钥: 公钥/私钥
    - padding: 指定填充方案, 数据填充, 不需要使用者做
        -     RSA_PKCS1_PADDING -> 使用该方案会填充11字节

5 签名

intRSA_sign(int type,constunsignedchar*m,unsignedint m_length,unsignedchar*sigret,unsignedint*siglen, RSA *rsa);
    参数:- type: 使用的哈希算法
            - NID_MD5
            - NID_SHA1
            - NID_SHA224
            -.....- m: 要进行签名的数据
        - m_length: 要签名的数据长度
            -0< m_length <= 秘钥长度-11- sigret: 传出, 存储了签名之后的数据 -> 密文
        - siglen: sigret密文长度
        - rsa: 私钥
     返回值: 判断函数状态

intRSA_verify(int type,constunsignedchar*m,unsignedint m_length,constunsignedchar*sigbuf,unsignedint siglen, RSA *rsa);
    参数:- type: 使用的哈希算法, 和签名使用的哈希算法一致
            - NID_MD5
            - NID_SHA1
            - NID_SHA224
            -.....- m: 进行签名的原始数据 -> 接收到的
        - m_length: m参数字符串的长度
        - sigbuf: 接收到的签名数据
        - siglen: sigbuf接收到的签名数据的长度
        - rsa: 公钥
    返回值:
        如果!=1: 失败
        如果==1: 成功
标签: c++ ssl web安全

本文转载自: https://blog.csdn.net/qq_44778436/article/details/128493429
版权归原作者 johnsonli99 所有, 如有侵权,请联系我们删除。

“c++中的OpenSSL加密(对称与非对称)”的评论:

还没有评论