加密-AES/RSA

一: 非对称加密

1:非对称加密特点

  • 密钥对:公钥、私钥

      公钥加密的数据,只有对应的私钥解密
      私钥加密的数据,只有对应的公钥解密
    
  • 加密速度慢,效率低。加密强度高。

2:主要的应用场景

2.1 分发密钥 – 保护对称加密的密钥
	核心思想:公钥加密
	使用 “对端的公钥” 加密数据。对端,使用自己的 私钥解密数据。
	实现流程

1. A、B两端
2. A端生成密钥对(公钥、私钥)。 将公钥公开。
3. B端获取公钥。
4. B端生成对称加密密钥(随机字符串)。使用A的公钥加密。---> 密文。
5. B端将密文发送给A端。
6. A端使用自己的 私钥 解密。得到对称加密密钥。
7. A、B端,使用相同的对称加密,加密数据。```

####  	2.2		 数字签名 -- 校验数据, 验证对方身份

		核心思想:私钥加密
		使用自己的 私钥加密数据的散列值。对端使用公钥解密。比对散列值。

```c
	实现流程
1. A、B两端。A端签名。B端校验签名。
2. A端,生成密钥对。公钥公开。
3. A端 生成原始数据,使用hash算法得到散列值。
4. A端 使用自己的私钥,对散列值加密。——> 密文。
5. A端 将 “原始数据” + 密文 发送给 B端。
6. B端,使用 A 的公钥解密密文,得到 散列值old。
7. B端,将 A 发送的原始数据,使用相同 hash算法,生成 散列值new。
8. B端,比对散列值old == 散列值new
   - 相同:数据未被篡改,数据所有者为 A。验证成功!
   - 不同:验证失败。```

## 3: 生成密钥对 -- RSA-API

```c
#include <openssl/rsa.h>

// 申请一块内存, 存储公钥和私钥
RSA *RSA_new(void);		// 使用公钥、私钥前,必须先获取RSA类型内存。

// 创建较大数对象
BIGNUM* BN_new(void);
// 初始化较大数
int BN_set_word(BIGNUM *a, unsigned int w);
	参数:
		- a:BN_new函数返回值。
		- w:数值(5位数以内)。—— 越大,生成密钥的时间就越长。
// 释放BIGNUM对象
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。 长度越长,加密速度越慢。
		- e:初始化后的 较大数。BN_set_word(bn, 12345);
		- cb: 回调。传NULL#include <openssl/pem.h>
// 写入文件的公、私钥数据并非原始数据, 是base64编码后的数据。生成pem格式文件。
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: RSA类型对象。包含:公钥、私钥。
		----------------------------------私钥特有
		- enc: 生成私钥使用的加密算法(对称加密)。NULL
		- kstr: 加密的密钥。 NULL.
		- klen: 密钥长度. 0
		- cb: 回调函数。NULL
		- u: 回调使用的参数。NULL.
【使用时的错误】:
	1. 解决控制台,一闪而过。项目右键 --- 属性 --- 连接器 -- 系统 --- 子系统 --- 控制台。
	2. 运行,报错:OPENSSL_Uplink(78CA5340,08): no OPENSSL_Applink
    	- 错误原因,crypto.dll库实现时,使用到 applink.c 文件。制作库时,未导入。
    	- 解决方法:将如下代码,添加到测试程序。
    			extern "C"
				{
					#include <openssl/applink.c> // 将applink.c一起编译生成可执行文件。
				};
    			参照笔记结尾处:【内部错误】小节。
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);
	参数:
		- fp 读取的公、私钥文指针。
		- r:传出。	读公钥文件 —— 传出公钥。
				   读私钥文件 —— 传出私钥。
		- cb:回调函数。NULL
        - u:回调参数。NULL ```

##### 封装了fopen()函数, 可以进行密钥对的写入和提取的相关函数

```c
// 创建bio对象 --- 封装了 FILE *fp = fopen();
BIO *BIO_new_file(const char *filename, const char *mode);
// 释放bio对象
int BIO_free(BIO *a);
		
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);

// 将RSA中的【公钥】提取出来
RSA *RSAPublicKey_dup(RSA *rsa);
// 将RSA中的【私钥】提取出来
RSA *RSAPrivateKey_dup(RSA *rsa);```

## 4: 加密 -- API

```c
	以块方式进行加密的, 加密的数据长度, 不能大于秘钥长度
	假设: 密钥长度: 1024bit = 128byte
// RSA_PKCS1_PADDING
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 <= 117(128-11)
        - from: 传入。加密:明文(原始数据内容)
        		解密:密文
        - to:传出。  加密:加密后的密文内存存储的位置。 加密的密文长度 == 密钥长度。
        			解密:明文内存存储的位置。
        - rsa:
				加密、解密使用的 公、私钥。		
		- padding: 函数内部自动填充。但,需要我们指定填充方案。
        		RSA_PKCS1_PADDING  —— 对应的填充方案 11 字节。
【返回值】:
		加密:返回加密后的密文长度。
		解密:返回原始数据的长度。


		加密生成的   ==密文长度 == 密钥长度==
- 原始数据 17字节 ——>加密得密文 ——> 128字节(密钥长度)——> 解密 ——>明文 17```

## 5: 数字签名 -- API

```c
// 数字签名 
int RSA_sign(int type, const unsigned char *m, unsigned int m_length,
             unsigned char *sigret, unsigned int *siglen, RSA *rsa);
	参数:
		- type: hash算法。(NID_md5/NID_sha1/NID_sha224...)
        - m : 传入。 原始数据。(自动生成) 
        - m_length: m 的长度。0 < flen <= 117(128-11)
        - sigret: 传出。密文(原始数据 求散列值 加密后的)
        - siglen: 传出。sigret的长度。
        - rsa:私钥!
    返回值:
    	成功:1,失败:0
      
// 校验签名
int RSA_verify(int type, const unsigned char *m, unsigned int m_length,
               const unsigned char *sigbuf, unsigned int siglen, RSA *rsa);
	参数:
		- type: hash算法。(NID_md5/NID_sha1/NID_sha224...)
        - m : 传入。 原始数据。(接收对端发送的)
        - m_length: m 的长度。0 < flen <= 117(128-11)
        - sigbuf: 传入。密文(接收对端发送的)
        - siglen: sigbuf长度。
        - rsa:公钥钥!		
	返回值:
		用来校验:
	    	校验成功:1。 
	    	校验失败:0。 ```


# 二:对称加密

## 1:AES 知识
```c
AES是一套对称密钥的密码术,目前已广泛使用,用于替代已经不够安全的DES算法。所谓对称密钥,就是说加密和解密用的是同一个密钥,消息的发送方和接收方在消息传递前需要享有这个密钥。和非对称密钥体系不同,这里的密钥是双方保密的,不会让任何第三方知道。

对称密钥加密法主要==**基于块加密****选取固定长度的密钥**==,去==**加密明文中固定长度的块,生成的密文块与明文块长度一样**==。显然密钥长度十分重要,块的长度也很重要。如果太短,则很容易枚举出所有的明文-密文映射;如果太长,性能则会急剧下降。==**AES中规定块长度为128 bit**==,而==**密钥长度可以选择128, 192256 bit**== 。暴力破解密钥需要万亿年,这保证了AES的安全性。```

## 2: 对称加密的特性

+ 加密、解密使用相同的密钥。加密较大数据。
+ 密钥长度:16 byte、24 byte、32 byte
+ 分组长度:16 byte!
+ 分组密文长度 == 分组明文长度 == 16 byte

## 3: 分组密码模式 -- 5种(自行了解)

+ CBC 模式: 密文分组连接模式
		分组长度:16 byte!
		需要 “初始化向量” 参与
		“初始化向量” 本质:字符串。 长度:与分组长度一致。16 byte!
		初始化向量 加密、解密时使用的 一致

## 4:AES 加解密 API

#### 	4.1 		生成封装后的密钥

```c
#include <openssl/aes.h>
# define AES_BLOCK_SIZE 16	// 明文分组的大小

// 封装加密时使用的密钥
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);
	-参数:
		userKey:加解密使用的对称密钥
		bits:密钥长度,单位bit
		key:传出。封装后的密钥。AES_KEY key --> &key;```

####  	4.2		 CBC 分组模式加密 - (分组链接模式)

```c
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:
		in、out的数据长度。  密文长度 == 明文长度。
		分组、填充函数内自动实现。长度,留出足够大空间。
		len = 数据长度+\0
		length = ((len/16)+1)*16	
	-key:
		AES_set_encrypt_key、AES_set_decrypt_key 传出值。
	-ivec:
		初始化向量!本质:字符串。与分组长度一致。16字节。
	-enc:
		加密:# define AES_ENCRYPT     1
		解密:# define AES_DECRYPT     0 ```







  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值