6-openssl加解密

1. 哈希算法

  1. 散列值的形式?原因?
    答:散列值表现为是一串16进制数,但实质是一堆二进制数值但无法显示,为了直观显示,将二进制数值转为16进制数。
  2. 哈希算法的散列值长度?
    答:MD4/MD5:散列值长度16byte,碰撞性已经被攻破;SHA1:散列值长度20byte;SHA2:包含有SHA224/SHA256/SHA384/SHA512;
  3. 如何得到MD5的散列值?
    答:通过MD5_Init()/MD5_Update()/MD5_Final()三个函数或MD5()函数来实现。其中前三个函数可以将数据分多次输入后再得到散列值,而MD5()函数的数据只能一次性输入。
//获取散列值需要的变量
int MD5_Init(MD5_CTX *c);
c:传出参数,获取的变量;
返回值:成功 - 1;失败 - 其他;	

int MD5_Update(MD5_CTX *c, const void *data, unsigned long len);
c:MD5_Init所获得的变量
data:要进行MD5运算的数据
len:data的长度
返回值:成功 - 1;失败 - 其他;	

int MD5_Final(unsigned char *md, MD5_CTX *c);
md:传出参数,得到的散列值;
c:MD5_Init得到的变量
返回值:成功 - 1;失败 - 其他;	
//只能将一次性数据进行传输
 unsigned char *MD5(const unsigned char *d, unsigned long n, unsigned char *md);
 d:进行MD5运算的字符串
 n:d的长度
 md:传出参数,得到的散列值
 返回值:得到的散列值
  1. 示例得到哈希值?
#include <iostream>
#include <openssl/md5.h>

using namespace std;

void md5Test(const char *p)
{
	//初始化
	MD5_CTX ctx;
	MD5_Init(&ctx);
	//添加数据
	MD5_Update(&ctx, p, strlen(p));
	//计算结果
	unsigned char md[MD5_DIGEST_LENGTH] = {0};
	MD5_Final(md, &ctx);
	cout << "md5: " << md << endl;
	//将哈希值转换为16进制字符串
	unsigned char res[MD5_DIGEST_LENGTH * 2 + 1];
	for(int i = 0; i < MD5_DIGEST_LENGTH; i++)
	{
		sprintf(&res[i * 2], "%02x", md[i]);
	}
	cout << "md5: " << res << endl;
}
int main()
{
	char *p = "hello world";
	md5Test(p);
}
  1. 如何配置vs的openssl环境?
    答:包含目录位于安装openssl的include文件路径中, 库目录位于安装openssl的lib目录中,附加依赖项为libcrypto.lib
  2. 为什么转换的数据中含有中文,得到的结果不同?
    答:中文需要先转成utf-8或其他码再进行哈希运算,编码方式不同,得到的结果则不同。
  3. 如何对哈希运算过程进行C++封装?

2. 非对称加密

  1. RSA密钥的长度?
    答:RSA 算法密钥长度越长,安全性越好,加密解密所需时间越长。可以通过bits参数进行随便设置,单位为bit,一般设为1028;长度越长,生成密钥和加密的时间就越长。
  2. 如何生成RSA密钥对?
    答:(1)申请一块内存;(2)生成密钥对,并分发;(3)释放内存
//申请密钥对内存
RSA *RSA_NEW(void);
返回值:申请的存储密钥的内存;

//生成密钥对
int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb);
rsa: RSA_NEW生成的结构体,用来存储密钥对;
bits:密钥的长度,单位为bit,一般最小为512,否则容易破解
e: BIG_NEW生成的结构体, BIGNUM *BN_NEW(void);
cb: 函数指针,通常为NULL

//提取公钥
RSA *RSAPublickey_dup(RSA *rsa);
//提取私钥
RSA *RSAPrivateKey_dep(RSA *rsa);
void generateKey()
{
	//1.创建密钥对象
	RSA *r = RSA_NEW();
	BIGNUM *e = BN_NEW();
	BN_set_word(e, 10);
	//2.生成密钥对
	RSA_generate_key_ex(r, 1024, e, NULL);
	//3.释放内存
	RSA_free(r);
	BN_free(e);
}
  1. 如何将密钥写入/读出磁盘?
    答:(1)打开文件;(2)将密钥写入/读出;(3)关闭文件
//将密钥写入到磁盘
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:要写入密钥的磁盘文件,.pem格式
r: 生成的密钥
enc/kstr/klen/cb/u: 一般写NULL/NULL/0/NULL/NULL//将密钥从磁盘读出
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/u:一般写NULL
  1. 如何配置vs环境?
    答:包含目录、库目录安装路径lib文件夹、附加依赖项libcrypto.lib
//公钥写入文件
FILE *fp = fopen("public.pem", "w");
PEM_write_RSAPublicKey(fp, r);
fclose(fp);
//私钥写入文件
fp = fopen("private.pem", "w");
PEM_write_RSARrivateKey(fp, r, NULL, NULL, 0, NULL, NULL);
fclose(fp);

//从磁盘提取公钥
RSA *x = RSA_new();
FILE *fp = fopen("public.pem", "r");
PEM_read_RSAPublicKey(fp, &x, NULL, NULL);
//从磁盘提取私钥
RSA *x = RSA_new();
FILE *fp = fopen("private.pem", "r");
PEM_read_RSAPrivateKey(fp, &x, NULL, NULL);
  1. 如何用RSA算法加/解密?、
    答:(1)生成密钥;(2)将密钥刷入磁盘;(3)从磁盘中提取公/私钥;(4)对数据进行加/解密;(5)将加/解密后的密/明文返回。
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:要加密数据的长度,最大长度为密钥长度-11;若长度不够,则需要分组
from:要加密的数据
to:加密后的密文
rsa:公钥/私钥
padding:填充数据,大小为11,设置为RSA_PKCS1_PADDING自动填充。
  1. 为什么要填充数据?
    答:加密后的数据是一堆二进制文件存放在buf中,填充数据用来分隔加密后的数据与buf中其他乱码
/*1.生成密钥对*/
void generateKey()
{
	//1.申请密钥空间
	RSA *r = RSA_new();
	//2.生成密钥
	BIGNUM *e = BN_new();
	BN_set_word(e, 111);
	RSA_generate_key_ex(r, 1024, e, NULL);

	//3.将密钥刷新到磁盘
	FILE *fp = fopen("public.pem", "w");
	PEM_write_RSAPublicKey(fp, r);
	fclose(fp);

	fp = fopen("private.pem", "w");
	PEM_write_RSAPrivateKey(fp, r, NULL, NULL, 0, NULL, NULL);
	fclose(fp);
	RSA_free(r);
	BN_free(e);
}

/*2.从磁盘提取公钥进行加密*/
string getKeyToenCode()
{
	//1.获取公钥
	RSA *x = RSA_new();
	FILE *fp = fopen("public.pem", "r");
	PEM_read_RSAPublicKey(fp, &x, NULL, NULL);
	//2.准备明文
	const char *s = "让编程改变世界, hello world,i'm coming";
	//3.进行加密
	char *buf = new char[1024];
	memset(buf, 0, sizeof(buf));
	int ret = RSA_public_encrypt(strlen(s), (const unsigned char *)s, (unsigned char *)buf, x, RSA_PKCS1_PADDING);
	//4.得到密文
	string str = string(buf, ret);
	delete[] buf;
	return str;
}


//3.从磁盘提取私钥进行解密
string getKeyToDeCode(string s)
{
	//1.获取私钥
	RSA *x = RSA_new();
	FILE *fp = fopen("private.pem", "r");
	PEM_read_RSAPrivateKey(fp, &x, NULL, NULL);
	//2.解密密文
	char *buf = new char[1024];
	memset(buf, 0, sizeof(buf));
	int ret = RSA_private_decrypt(s.size(), (const unsigned char *)s.c_str(), (unsigned char *)buf, x,  RSA_PKCS1_PADDING);
	//3.返回明文
	string str = string(buf, ret);
	delete[]buf;
	return str;
}	


int main()
{
	generateKey();	//生成密钥
	string str = getKeyToenCode();	//加密
	str = getKeyToDeCode(str);
	cout << "解密数据为:" << str << endl;
	return 0;
}
  1. 如何对数据进行签名和验证?
    答:A:(数据 * 哈希运算 * 私钥)= 密文, 密文+数据==>B ;
    B:数据 * 哈希运算 == 密文 * 公钥 ?
//签字加密函数
int RSA_sign(int type, const unsigned char *m, unsigned int m_length, unsigned char *sigret, unsigned int *siglen, RSA *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_SH1...
m:要进行加密的数据
m_length: m的长度
sigret:加密后的密文,传出参数
sigbuf:要解密的密文,传入参数
siglen:sigret/sigbuf的长度,传出参数
rsa:加/解密的密钥
/*对数据进行签名*/
void signAndVerify()
{
	//1.签名
	const char *s = "让编程改变世界, hello world,i'm coming";
	char buf[1024] = { 0 };
	unsigned int len;
	//准备私钥
	BIO *priBio = BIO_new_file("private.pem", "r");
	RSA *priKey = RSA_new();
	PEM_read_bio_RSAPrivateKey(priBio, &priKey, NULL, NULL);
	RSA_sign(NID_sha1, (const unsigned char *)s, strlen(s), (unsigned char *)buf, &len, priKey);
	
	//2.验证
	//准备公钥
	BIO *pubBio = BIO_new_file("public.pem", "r");
	RSA *pubKey = RSA_new();
	PEM_read_bio_RSAPublicKey(pubBio, &pubKey, NULL, NULL);
	int ret = RSA_verify(NID_sha1, (const unsigned char *)s, strlen(s), (const unsigned char *)buf, len, pubKey);
	if (ret == 1)
	{
		cout << "校验成功" << endl;
	}
	else
	{
		cout << "校验失败" << endl;
	}
}

3. 对称加密

  1. AES算法加密方式?特点?
    答:密钥长度16、24、32byte,字节越大加密程度越高;将数据分成128bit每块进行逐块加密,加密后的密文与明文长度相同。
  2. 如何用AES算法对数据进行加密?
    答:
//获取密钥函数
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: 获取密钥的字符串,随便填写,长度可选: 16byte, 24byte, 32byte
bits:密钥的长度,单位bit
key:传出参数,保存密钥的信息

//cdc加密算法
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的长度,必须为16的整数倍,通过strlen(in) % 16判断,若余数不为0,则将length修改为(strlen(in)/16+1)*16
key: 密钥
ivec:初始化字符串,随便设置,和第一个明文分组进行位运算,16个字符加解密的时候保证该数组中的数据完全相同
enc: 加解密的标志
    # define AES_ENCRYPT     1
	# define AES_DECRYPT     0
void aestest()
{
	// 数据准备
	// 16byte 的秘钥
	char ivec[AES_BLOCK_SIZE];
	const char* key = "1234567887654321";
	const char* text = "AES是一套对称密钥的密码术,目前已广泛使用,用于替代已经不够安全的DES算法。所谓对称密钥,就是说加密和解密用的是同一个密钥,消息的发送方和接收方在消息传递前需要享有这个密钥。和非对称密钥体系不同,这里的密钥是双方保密的,不会让任何第三方知道。对称密钥加密法主要基于块加密,选取固定长度的密钥,去加密明文中固定长度的块,生成的密文块与明文块长度一样。显然密钥长度十分重要,块的长度也很重要。如果太短,则很容易枚举出所有的明文-密文映射;如果太长,性能则会急剧下降。AES中规定块长度为128 bit,而密钥长度可以选择128, 192或256 bit 。暴力破解密钥需要万亿年,这保证了AES的安全性。";
	memset(ivec, 9, sizeof(ivec));
	// 加密
	int length = strlen(text) + 1;
	if (length % 16 != 0)
	{
		length = (length / 16 + 1) * 16;
	}
	// 得到秘钥
	AES_KEY encKey;
	AES_set_encrypt_key((const unsigned char*)key, 128, &encKey);
	char *encText = new char[length];
	AES_cbc_encrypt((const unsigned char*)text, 
		(unsigned char*)encText, length, &encKey, (unsigned char*)ivec, AES_ENCRYPT);

	// 解密
	AES_KEY decKey;
	memset(ivec, 9, sizeof(ivec));
	AES_set_decrypt_key((const unsigned char*)key, 128, &decKey);
	char *decText = new char[length];
	AES_cbc_encrypt((const unsigned char*)encText, (unsigned char*)decText,
		length, &decKey, (unsigned char*)ivec, AES_DECRYPT);
	cout << "解密之后的数据: " << decText << endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值