1.哈希

1.1 md5的使用

  • 头文件
#include <openssl/md5.h>
#include <openssl/sha.h>
  • MD5 散列值的长度
# define MD5_DIGEST_LENGTH 16    // 根据这个分配一块空内存保存散列值
  • 初始化MD5 -> 给MD5传入运算的数据(可以多次传入) -> 计算MD5
# 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 哈希值
// 通过传递的参数, 直接生成一个md5哈希值,只能添加一次数据
unsigned char *MD5(const unsigned char *d, size_t n, unsigned char *md);
/* 参数:
- d: 传入, 要进行md5运算的字符串
- n: 字符串的的长度
- md: 传出, 存储md5的哈希值
返回值: 这个地址的函数第三个参数md地址 */
  • 编译时记得加 lcrypto -lssl

2. 非对称加密

2.1 非对称加密简介

  • 密钥对:公钥、私钥(非对称加密,一方加密只有另一方可以解密)

    • 公钥加密、必须私钥解密
    • 私钥加密、必须公钥解密
  • 应用场景:
    • 密钥分发(对称加密的密钥分发)

      • 公钥加密,私钥解密
      • 将公钥分发给其他人,其他人都可以使用公钥加密数据,但只有自己的私钥可以解密数据
    • 数字签名(验证数据是否被篡改、数据的所有者)
      • 私钥加密,公钥解密
      • 签名
        • 对原始数据进行哈希运算,对哈希值加密得到密文
        • 将原始数据和加密的哈希值发送给其他人
      • 校验签名
        • 收到 原始数据 和 加密的哈希值
        • 对原始数据求 哈希值
        • 对加密的哈希值解密得到 哈希值
        • 比较两个哈希值判断数据是否被篡改(还需要验证公钥的发送人身份,CA机构就是干这个的)

2.2 生成RSA密钥对

  • 头文件
#include <openssl/rsa.h>
  • 得到RSA类型的变量
RSA* RSA_new(void);        // 申请一块内存, 存储了公钥和私钥
void RSA_free(RSA *);
  • 生成密钥对,取公钥和私钥
int RSA_generate_key_ex(RSA* rsa, int bits, BIGNUM* e, BN_GENCB* cb);
/* 参数:
rsa: 通过RSA_new()获得
bits: 秘钥长度, 单位: bit, 常用的长度 1024*n (n正整数)
e: 比较大的数(5位以内)
通过 BIGNUM* e = 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私钥 */
  • 将密钥存储到磁盘
#include <openssl/pem.h>    // 头文件
extern "C"
{ // 由于dll库里没有这个部分,需要包含进去一起编译
#include <openssl/applink.c>
} 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 */
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);
  • 示例代码
#include <openssl/pem.h>
using namespace std;
int main()
{
RSA* rsa = RSA_new(); // 创建RSA变量
BIGNUM* e = BN_new(); // 创建bignum变量并实例化
BN_set_word(e, 12345);
RSA_generate_key_ex(rsa, 4096, e, NULL); // 生成密钥对
FILE* fp = fopen("public.pem", "w");
PEM_write_RSAPublicKey(fp, rsa); // 写入公钥
fp = fopen("private.pem", "w");
PEM_write_RSAPrivateKey(fp, rsa, NULL, NULL, 0, NULL, NULL); // 写入私钥
fclose(fp);
}

2.3 加密

  • 使用公钥或私钥,加密或解密(加密后的长度和密钥长度相同,还需要指定填充方案,所以传入的数据应该小于等于密钥长度 - 填充长度
// ---- 加密使用 ----
// 公钥加密
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字节 */
  • 代码示例
#include <openssl/pem.h>
#include <string.h>
#include <iostream>
using namespace std;
int main()
{
// 创建密钥过程
RSA *rsa = RSA_new(); // 创建RSA变量
BIGNUM *e = BN_new(); // 创建bignum变量并实例化
BN_set_word(e, 12345);
RSA_generate_key_ex(rsa, 1024, e, NULL); // 生成密钥对
RSA *pubKey = RSAPublicKey_dup(rsa);
RSA *priKey = RSAPrivateKey_dup(rsa);
// 加密过程
int keyLen = RSA_size(pubKey); // 数据被加密后和密钥的长度相同
string msg = "Hello world!";
char *buf = new char[keyLen];
int ret = RSA_public_encrypt(msg.size(), (const unsigned char *)msg.data(), (unsigned char *)buf, pubKey, RSA_PKCS1_PADDING);
cout << "加密后的长度为 " << ret << endl;
// 解密过程
char *newText = new char[keyLen];
ret = RSA_private_decrypt(128, (const unsigned char *)buf, (unsigned char *)newText, priKey, RSA_PKCS1_PADDING);
cout << "解密后的长度为 " << ret << endl;
cout << newText << endl;
}

2.4 签名

  • 加密哈希值和验证哈希值,其实就是帮我们把加密和验证放到一个函数里了(这里有一个坑,要签名的数据长度必须小于密钥长度-11)
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: 成功 */

3. 对称加密

  • 生成加密解密的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);
/* userkey: 对称加密的密钥->字符串长度: 16, 24, 32byte
bites: 指定密钥的长度: 单位 bit
key: 传出参数 */
  • CBC方式加密 - 密码分组链接模式

    • ivec: 一个初始化向量,长度与分组长度相同(16, 24, 32byte -> 128, 192, 256bit)。注意这个初始化向量传入之后会一直参与计算,实际上他是个传入传出参数,虽然没什么用
    • length: 密文长度必须是16(24, 32)的整数倍,如果不够需要自己计算补充

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的长度
(len = (字符串长度 + \0) % 16) == 0
如果不是在函数内部会自动填充
实际长度: ((len / 16) + 1 ) * 16
key: 初始化之后的秘钥
ivec: 初始化向量, 字符串 ==> 长度和分组长度相同
enc: 指定数据要解密还是解密
# define AES_ENCRYPT 1 -> 加密
# define AES_DECRYPT 0 -> 解密 */
  • 示例代码
#include <openssl/aes.h>
#include <string.h>
#include <iostream>
using namespace std;
int main()
{
// 1.准备数据
const char *pt = "data1, data2, data3, data4, data5, data6, data7, data8, data9, data10";
// 2.准备密钥
const char *key = "123456787654321"; // 16位(或24,32)
// 3.初始化密钥
AES_KEY encKey;
AES_set_encrypt_key((const unsigned char*)key, 128, &encKey);
// 4.加密
int length = 0;
int len = strlen((char *)pt) + 1;
if (len % 16 != 0)
{
length = ((len / 16) + 1) * 16;
}
else
{
length = len;
}
unsigned char *out = new unsigned char[length]; // 存储密文
unsigned char ivec[16];
memset(ivec, 9, sizeof(ivec));
AES_cbc_encrypt((const unsigned char*)pt, out, length, &encKey, ivec, AES_ENCRYPT);
// 5.解密
unsigned char* data = new unsigned char[length];
AES_KEY deckey;
AES_set_decrypt_key((const unsigned char*)key, 128, &deckey);
memset(ivec, 9, sizeof(ivec));
AES_cbc_encrypt((const unsigned char*)out, data, length, &deckey, ivec, AES_DECRYPT);
// 6.打印
cout<<data<<endl;
delete[] out;
delete[] data;
}

【OpenSSL】哈希、非对称加密和对称加密函数使用的更多相关文章

  1. java-信息安全(七)-基于非对称加密,对称加密等理解HTTPS

    概述 java-信息安全(一)-BASE64,MD5,SHA,HMAC java-信息安全(二)-对称加密算法DES,3DES,AES,Blowfish,RC2,RC4 java-信息安全(四)-数据 ...

  2. java-信息安全(九)-基于DH,非对称加密,对称加密等理解HTTPS

    概述 java-信息安全(七)-基于非对称加密,对称加密等理解HTTPS 如果想要理解好https,请尽量了解好以上信息等. 参看文章: http://www.ruanyifeng.com/blog/ ...

  3. php中des加密解密 匹配C#des加密解密 对称加密

    原文:php中des加密解密 匹配C#des加密解密 对称加密 网上找来的 php des加密解密 完全匹配上一篇C# 字符串加密解密函数  可以用于C#和php通信 对数据进行加密,其中$key 是 ...

  4. 常见三种加密(MD5、非对称加密,对称加密)

    转载. https://blog.csdn.net/SSY_1992/article/details/79094556 任何应用的开发中安全都是重中之重,在信息交互异常活跃的现在,信息加密技术显得尤为 ...

  5. c#简单加密和对称加密

    转自:https://www.cnblogs.com/zhihai/archive/2012/05/03/2480856.html using System;using System.Collecti ...

  6. 指定字符串加密(对称加密DES)

    /* * @(#) EncrypAES.java */ import java.security.InvalidKeyException; import java.security.NoSuchAlg ...

  7. [svc]对称加密/非对称加密细枝末节-如何做到数据传输的authentication/data integrity/confidentiality(私密)

    对称/非对称/混合加密的冷知识 数据在互联网上传输,要考虑安全性. 讲到安全,要从三方面考虑: 1.authentication 每一个IP包的认证,确保合法源的数据 2.data integrity ...

  8. Android 中 非对称(RSA)加密和对称(AES)加密

    在非对称加密中使用的主要算法有:RSA.Elgamal.背包算法.Rabin.D-H.ECC(椭圆曲线加密算法)等. 优点: 非对称加密与对称加密相比,其安全性更好:对称加密的通信双方使用相同的秘钥, ...

  9. Java安全之对称加密、非对称加密、数字签名

    原文地址: http://blog.csdn.net/furongkang/article/details/6882039 Java中加密分为两种方式一个是对称加密,另一个是非对称加密.对称加密是因为 ...

  10. https处理的一个过程,对称加密和非对称加密

    一,对称加密 所谓对称加密,就是它们在编码时使用的密钥e和解码时一样d(e=d),我们就将其统称为密钥k. 对称加解密的过程如下: 发送端和接收端首先要共享相同的密钥k(即通信前双方都需要知道对应的密 ...

随机推荐

  1. 定制Django的Tag和Filter(二)

    配置 (1)最常见的放置自定义Tag和Filter的地方是在Django的app下.当一个app被添加到settings.py的INSTALLED_APPS 后,任何在它下面的合法位置将自动的可在te ...

  2. 面试官说又逮到一个不会用Git的

    这里这写简要,要看具体的步骤及解释清移步:https://www.bilibili.com/read/cv10510952 如果是自己创建仓库写代码上传(demo是自己仓库的自定义名字): git i ...

  3. 使用SimpleDateFormat获取指定时区时间

    摘要:使用SimpleDateFormat把时间戳转换成指定格式的.指定时区的字符串.   SimpleDateFormat是Java中的一个日期格式化类,继承了DateFormat,可以实现日期时间 ...

  4. Java 自定义线程池的线程工厂

      本文分享创建线程工厂 ThreadFactory 的三种方式,以方便大家快速创建线程池,并通过线程工厂给每个创建出来的线程设置极富业务含义的名字. 线程池大小考虑因素   由于需要自定义线程池,故 ...

  5. 如何用Leangoo破解需求隔离与频繁变更的协作困局?

    作为一位经历过"需求文档满天飞.系统各自为战"的研发负责人,我深知团队在需求频繁变更时面临的痛点--信息割裂导致响应滞后.优先级混乱引发返工.协作低效拖慢交付节奏. 近期,我深度测 ...

  6. markitdown的安装与简单使用

    欢迎阅读我的blog! 个人网站阅读<markitdown 的安装和简单使用> 安装 microsoft/markitdown: Python tool for converting fi ...

  7. Spring、Spring Framework、Spring Boot、Spring Cloud的区别

    Spring Spring是一个生态体系(也可以说是技术体系),是集大成者,它包含了Spring Framework.Spring Boot.Spring Cloud等(还包括Spring Cloud ...

  8. cpp零碎知识点小记

    字符串读取方法记录 记录 个人小结: 按整行读到string ,推荐用 方法2 getline(cin, string) 按整行读到char[] ,推荐用 方法4 cin.getline(cin, c ...

  9. 对比分析LinkedBlockingQueue和SynchronousQueue

    缘起 最近在 review 同事代码时,看到其使用了org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor 来构建线程池,而没 ...

  10. K&R 语法 vs. ANSI C 语法

    由于项目中使用了Bison,看到有个奇怪的C语言的语法,查了一下居然是要兼容早期的C标准 Bison 是什么? Bison 是一个 语法分析器生成器(parser generator),它用于根据 上 ...