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

这篇具有很好参考价值的文章主要介绍了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>

# define MD5_DIGEST_LENGTH 16	// md5哈希值长度
// 初始化函数, 初始化参数 c
int MD5_Init(MD5_CTX *c);
	参数c: 传出参数
// 添加md5运算的数据,此时还没有计算哈希值
// 该函数可以进行多次数据添加 -> 函数多次调用
int MD5_Update(MD5_CTX *c, const void *data, size_t len);
	参数:
		- c: MD5_Init() 初始化得到的
		- data: 传入参数, 字符串
		- len: data数据的长度
// 对添加的数据进行md5计算		
int MD5_Final(unsigned char *md, MD5_CTX *c);
	参数:
		- md: 传出参数, 存储得到的哈希值
		- c: MD5_Init() 初始化得到的

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

二 对称加密

1 特点:

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

2 3DES对称加密算法

重复3次DES,使用3个密钥,实现加密→解密→加密的过程。
c++ openssl rsa加密,C++,c++,ssl,web安全
c++ openssl rsa加密,C++,c++,ssl,web安全
3 AES对称加密算法

(1)特点:

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

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

#include <openssl/aes.h>
# define AES_BLOCK_SIZE 16	// 明文分组的大小
// 加密的时候调用
// aes中的秘钥格式 AES_KEY
// 封装加密时候使用的秘钥
AES_KEY key;
int AES_set_encrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key);
// 封装解密时候使用的秘钥
int AES_set_decrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key);

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

void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
                     size_t length, const AES_KEY *key,
                     unsigned char *ivec, const int 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);
void RSA_free(RSA *);

BIGNUM* BN_new(void);
void BN_free(BIGNUM*);
// 生成密钥对, 密钥对存储在内存中
int RSA_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(const char *filename, const char *mode);
	参数:
		- filename: 文件名
		- mode: 文件打开方式和fopen打开方式的指定相同
		
int PEM_write_bio_RSAPublicKey(BIO* bp, const RSA* r);
int PEM_write_bio_RSAPrivateKey(BIO* bp, const RSA* r, const EVP_CIPHER* enc, 
	unsigned char* 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进行编码
int PEM_write_RSAPublicKey(FILE* fp, const RSA* r);
int PEM_write_RSAPrivateKey(FILE* fp, const RSA* r, const EVP_CIPHER* enc, 
	unsigned char* kstr, int klen, pem_password_cb *cb, void* u);	
	参数:
		- fp: 需要打开一个磁盘文件, 并且指定写权限
		- r: 存储了密钥对
		 - 私钥独有的参数
		- enc: 指定的加密算法 -> 对称加密 -> NULL
		- kstr: 对称加密的秘钥 -> NULL
		- klen: 秘钥长度 -> 0
		- cb: 回调函数, 用不到, NULL
		- u: 给回调传参, 用不到, NULL

4 加密

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

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

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

// 公钥加密
int RSA_public_encrypt(int flen, const unsigned char *from,
                       unsigned char *to, RSA *rsa, int padding);
// 私钥解密
int RSA_private_decrypt(int flen, const unsigned char *from,
                        unsigned char *to, RSA *rsa, int padding);

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

5 签名文章来源地址https://www.toymoban.com/news/detail-643877.html

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

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

到了这里,关于c++中的OpenSSL加密(对称与非对称)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 20.2 OpenSSL 非对称RSA加解密算法

    RSA算法是一种非对称加密算法,由三位数学家 Rivest 、 Shamir 和 Adleman 共同发明,以他们三人的名字首字母命名。RSA算法的安全性基于大数分解问题,即对于一个非常大的合数,将其分解为两个质数的乘积是非常困难的。 RSA算法是一种常用的非对称加密算法,与对称加密算法

    2024年02月08日
    浏览(49)
  • 20.5 OpenSSL 套接字RSA加密传输

    RSA算法同样可以用于加密传输,但此类加密算法虽然非常安全,但通常不会用于大量的数据传输,这是因为 RSA 算法加解密过程涉及大量的数学运算,尤其是模幂运算(即计算大数的幂模运算),这些运算对于计算机而言是十分耗时。 其次在 RSA 算法中,加密数据的长度不能

    2024年02月06日
    浏览(41)
  • 20.7 OpenSSL 套接字SSL加密传输

    OpenSSL 中的 SSL 加密是通过 SSL/TLS 协议来实现的。 SSL/TLS 是一种安全通信协议,可以保障通信双方之间的通信安全性和数据完整性。在 SSL/TLS 协议中,加密算法是其中最核心的组成部分之一,SSL可以使用各类加密算法进行密钥协商,一般来说会使用 RSA 等加密算法,使用 TLS 加

    2024年02月05日
    浏览(134)
  • 基于OpenSSL的SSL/TLS加密套件全解析

    SSL/TLS握手时,客户端与服务端协商加密套件是很重要的一个步骤,协商出加密套件后才能继续完成后续的握手和加密通信。而现在SSL/TLS协议通信的实现,基本都是通过OpenSSL开源库,本文章就主要介绍下加密套件的含义以及如何在OpenSSL中指定加密套件。 SSL/TLS协议的加密套件

    2024年01月22日
    浏览(41)
  • 常见的对称式加密与非对称式加密算法

            对称式加密 :对称加密算法就是传统的用一个密码进行加密和解密,通信发送方使用这种算法加密数据,接收方也用同样的算法解密数据. 因此对称式加密本身不是安全的。从程序的角度看,所谓加密,就是这样一个函数:         它接收密码和明文,然后输出密

    2023年04月08日
    浏览(38)
  • 区块链学习系列:对称与非对称加密区别?

    图表:在这篇博文中,我们讨论了对称加密(一种单密钥加密技术)与非对称加密(也称为公钥密码术)之间的区别,后者使用私钥和公钥对加密密钥。 传输密钥或不传输密钥。就是那个问题。 目前使用的数据加密主要有两种形式:对称加密和非对称加密。每天,当您使用

    2023年04月08日
    浏览(43)
  • 基于openssl v3搭建ssl安全加固的c++ tcpserver

    tcp server和tcp client同时使用openssl库,可对通信双方流通的字节序列进行加解密,保障通信的安全。本文以c++编写的tcp server和tcp client为例子,openssl的版本为v3。 openssl项目中的config脚本需要用到perl-IPC-Cmd工具。 安装的结果放在目录/opt/openssl中。 安装完毕后,结果如下图所示:

    2024年01月25日
    浏览(45)
  • AES(对称加密)和RSA(非对称加密)使用详情

          待加密的明文以16字节分组进行加密,如果数据字节长度不是16的倍数,最后的一组则需要在有效数据后面进行填充,使得数据长度变为16字节,AES填充方式分为NoPadding、PKCS5(PKCS7)、ISO10126、Zeros。 NoPadding :不填充,那就只能加密长度为16倍数的数据,一般不使用; Zero

    2024年02月08日
    浏览(97)
  • c++使用OpenSSL基于socket实现tcp双向认证ssl(使用TSL协议)代码实现

    相信各位对OpenSSL库已经不陌生了,目前笔者使用这个库实现了RSA、AES加解密和tcp的双向认证功能,下面来看tcp的双向认证。 简单说双向认证就是:客户端认证服务端是否合法,服务端认证客户端是否合法 。 可以借助于HTTPS来说明,http网络传输协议是超文本的明文协议,也就

    2024年02月06日
    浏览(59)
  • 【Https协议】http的孪生兄弟,你了解多少呢,认识Https,Https工作原理之对称加密与非对称加密

    前言: 大家好,我是 良辰丫 ,这篇文章我们就来学习一下Https协议,了解Https的工作原理,对称加密以及非对称加密.💞💞💞 🧑个人主页:良辰针不戳 📖所属专栏:javaEE初阶 🍎励志语句:生活也许会让我们遍体鳞伤,但最终这些伤口会成为我们一辈子的财富。 💦期待大家三

    2024年02月10日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包