openssl
一、入门
平台:linux
(一)下载和使用
1、直接安装
执行以下命令,会安装OpenSSL的开发头文件和库文件
sudo apt-get update
sudo apt-get install libssl-dev
创建源代码文件main.cpp,内容如下
#include <iostream>
#include <openssl/evp.h>
#include <openssl/rand.h>
int main() {
std::cout << "OpenSSL C++ Development Environment is set up!" << std::endl;
return 0;
}
编译:
g++ -o main main.cpp -lssl -lcrypto
执行
./main
2、源码编译
下载当前最新版本:openssl-3.2.0.tar.gz
解压
tar -xvf openssl-3.2.0.tar.gz
进入目录,参考INSTALL.md进行编译,linux平台
./Configure # 如果是openssl-1.1.1w.tar.gz版本,使用./config
# 如果是更低版本,如1.0.1u,默认是不生成动态库的,使用./config shared
make
#make test
#make install
找到生成头文件和库文件位置
头文件:/home/work/openssl-3.2.0/include
库文件:/home/work/openssl-3.2.0/
测试,新建main.cpp:使用OpenSSL库在Linux上生成自签名证书
#include <iostream>
#include <fstream>
#include <iomanip>
#include <openssl/bio.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
int main() {
// 生成自签名证书
EVP_PKEY *pkey = nullptr;
X509 *x = nullptr;
RSA *rsa = RSA_generate_key(2048, RSA_F4, nullptr, nullptr);
pkey = EVP_PKEY_new();
EVP_PKEY_assign_RSA(pkey, rsa);
x = X509_new();
ASN1_INTEGER_set(X509_get_serialNumber(x), 1);
X509_gmtime_adj(X509_get_notBefore(x), 0);
X509_gmtime_adj(X509_get_notAfter(x), 31536000L); // 设置有效期为1年
X509_set_pubkey(x, pkey);
int ret = X509_sign(x, pkey, EVP_sha256());
if (ret != 1) {
std::cerr << "Failed to generate self-signed certificate." << std::endl;
return -1;
}
// 将证书保存到文件
BIO *bio = BIO_new_file("certificate.pem", "w+");
PEM_write_bio_X509(bio, x);
BIO_free(bio);
std::cout << "Certificate saved to certificate.pem." << std::endl;
// 释放资源
EVP_PKEY_free(pkey);
X509_free(x);
RSA_free(rsa);
return 0;
}
编译
g++ -o main main.cpp -I/home/work/openssl-3.2.0/include -L/home/work/openssl-3.2.0/ -lssl -lcrypto
执行
./main
如缺少动态库,使用以下命令添加,注-只对当前对话有效
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:实际路径
测试2:
#include <iostream>
#include <cassert>
#include <string>
#include <vector>
#include "openssl/md5.h"
#include "openssl/sha.h"
#include "openssl/des.h"
#include "openssl/rsa.h"
#include "openssl/pem.h"
#pragma comment(lib,"libcrypto.lib")
// ---- md5摘要哈希 ---- //
void md5(const std::string &srcStr, std::string &encodedStr, std::string &encodedHexStr)
{
unsigned char mdStr[33] = { 0 };
MD5((const unsigned char *)srcStr.c_str(), srcStr.length(), mdStr);// 调用md5哈希
encodedStr = std::string((const char *)mdStr);// 哈希后的字符串
char buf[65] = { 0 };
char tmp[3] = { 0 };
for (int i = 0; i < 32; i++)// 哈希后的十六进制串 32字节
{
sprintf(tmp, "%02x", mdStr[i]);
strcat(buf, tmp);
}
buf[32] = '\0'; // 后面都是0,从32字节截断
encodedHexStr = std::string(buf);
}
// ---- sha256摘要哈希 ---- //
void sha256(const std::string &srcStr, std::string &encodedStr, std::string &encodedHexStr)
{
unsigned char mdStr[33] = { 0 };
SHA256((const unsigned char *)srcStr.c_str(), srcStr.length(), mdStr);// 调用sha256哈希
encodedStr = std::string((const char *)mdStr);// 哈希后的字符串
char buf[65] = { 0 };
char tmp[3] = { 0 };
for (int i = 0; i < 32; i++)// 哈希后的十六进制串 32字节
{
sprintf(tmp, "%02x", mdStr[i]);
strcat(buf, tmp);
}
buf[32] = '\0'; // 后面都是0,从32字节截断
encodedHexStr = std::string(buf);
}
// ---- des对称加解密 ---- //
// 加密 ecb模式
std::string des_encrypt(const std::string &clearText, const std::string &key)
{
std::string cipherText; // 密文
DES_cblock keyEncrypt;
memset(keyEncrypt, 0, 8);
// 构造补齐后的密钥
if (key.length() <= 8)
memcpy(keyEncrypt, key.c_str(), key.length());
else
memcpy(keyEncrypt, key.c_str(), 8);
// 密钥置换
DES_key_schedule keySchedule;
DES_set_key_unchecked(&keyEncrypt, &keySchedule);
// 循环加密,每8字节一次
const_DES_cblock inputText;
DES_cblock outputText;
std::vector<unsigned char> vecCiphertext;
unsigned char tmp[8];
for (int i = 0; i < clearText.length() / 8; i++)
{
memcpy(inputText, clearText.c_str() + i * 8, 8);
DES_ecb_encrypt(&inputText, &outputText, &keySchedule, DES_ENCRYPT);
memcpy(tmp, outputText, 8);
for (int j = 0; j < 8; j++)
vecCiphertext.push_back(tmp[j]);
}
if (clearText.length() % 8 != 0)
{
int tmp1 = clearText.length() / 8 * 8;
int tmp2 = clearText.length() - tmp1;
memset(inputText, 0, 8);
memcpy(inputText, clearText.c_str() + tmp1, tmp2);
DES_ecb_encrypt(&inputText, &outputText, &keySchedule, DES_ENCRYPT);// 加密函数
memcpy(tmp, outputText, 8);
for (int j = 0; j < 8; j++)
vecCiphertext.push_back(tmp[j]);
}
cipherText.clear();
cipherText.assign(vecCiphertext.begin(), vecCiphertext.end());
return cipherText;
}
// 解密 ecb模式
std::string des_decrypt(const std::string &cipherText, const std::string &key)
{
std::string clearText; // 明文
DES_cblock keyEncrypt;
memset(keyEncrypt, 0, 8);
if (key.length() <= 8)
memcpy(keyEncrypt, key.c_str(), key.length());
else
memcpy(keyEncrypt, key.c_str(), 8);
DES_key_schedule keySchedule;
DES_set_key_unchecked(&keyEncrypt, &keySchedule);
const_DES_cblock inputText;
DES_cblock outputText;
std::vector<unsigned char> vecCleartext;
unsigned char tmp[8];
for (int i = 0; i < cipherText.length() / 8; i++)
{
memcpy(inputText, cipherText.c_str() + i * 8, 8);
DES_ecb_encrypt(&inputText, &outputText, &keySchedule, DES_DECRYPT);
memcpy(tmp, outputText, 8);
for (int j = 0; j < 8; j++)
vecCleartext.push_back(tmp[j]);
}
if (cipherText.length() % 8 != 0)
{
int tmp1 = cipherText.length() / 8 * 8;
int tmp2 = cipherText.length() - tmp1;
memset(inputText, 0, 8);
memcpy(inputText, cipherText.c_str() + tmp1, tmp2);
DES_ecb_encrypt(&inputText, &outputText, &keySchedule, DES_DECRYPT);// 解密函数
memcpy(tmp, outputText, 8);
for (int j = 0; j < 8; j++)
vecCleartext.push_back(tmp[j]);
}
clearText.clear();
clearText.assign(vecCleartext.begin(), vecCleartext.end());
return clearText;
}
// ---- rsa非对称加解密 ---- //
#define KEY_LENGTH 2048 // 密钥长度
#define PUB_KEY_FILE "pubkey.pem" // 公钥路径
#define PRI_KEY_FILE "prikey.pem" // 私钥路径
// 函数方法生成密钥对
void generateRSAKey(std::string strKey[2])
{
// 公私密钥对
size_t pri_len;
size_t pub_len;
char *pri_key = NULL;
char *pub_key = NULL;
// 生成密钥对
RSA *keypair = RSA_generate_key(KEY_LENGTH, RSA_3, NULL, NULL);
BIO *pri = BIO_new(BIO_s_mem());
BIO *pub = BIO_new(BIO_s_mem());
PEM_write_bio_RSAPrivateKey(pri, keypair, NULL, NULL, 0, NULL, NULL);
PEM_write_bio_RSAPublicKey(pub, keypair);
// 获取长度
pri_len = BIO_pending(pri);
pub_len = BIO_pending(pub);
// 密钥对读取到字符串
pri_key = (char *)malloc(pri_len + 1);
pub_key = (char *)malloc(pub_len + 1);
BIO_read(pri, pri_key, pri_len);
BIO_read(pub, pub_key, pub_len);
pri_key[pri_len] = '\0';
pub_key[pub_len] = '\0';
// 存储密钥对
strKey[0] = pub_key;
strKey[1] = pri_key;
// 存储到磁盘(这种方式存储的是begin rsa public key/ begin rsa private key开头的)
FILE *pubFile = fopen(PUB_KEY_FILE, "w");
if (pubFile == NULL)
{
assert(false);
return;
}
fputs(pub_key, pubFile);
fclose(pubFile);
FILE *priFile = fopen(PRI_KEY_FILE, "w");
if (priFile == NULL)
{
assert(false);
return;
}
fputs(pri_key, priFile);
fclose(priFile);
// 内存释放
RSA_free(keypair);
BIO_free_all(pub);
BIO_free_all(pri);
free(pri_key);
free(pub_key);
}
// 命令行方法生成公私钥对(begin public key/ begin private key)
// 找到openssl命令行工具,运行以下
// openssl genrsa -out prikey.pem 1024
// openssl rsa - in privkey.pem - pubout - out pubkey.pem
// 公钥加密
std::string rsa_pub_encrypt(const std::string &clearText, const std::string &pubKey)
{
std::string strRet;
RSA *rsa = NULL;
BIO *keybio = BIO_new_mem_buf((unsigned char *)pubKey.c_str(), -1);
// 此处有三种方法
// 1, 读取内存里生成的密钥对,再从内存生成rsa
// 2, 读取磁盘里生成的密钥对文本文件,在从内存生成rsa
// 3,直接从读取文件指针生成rsa
RSA* pRSAPublicKey = RSA_new();
rsa = PEM_read_bio_RSAPublicKey(keybio, &rsa, NULL, NULL);
int len = RSA_size(rsa);
char *encryptedText = (char *)malloc(len + 1);
memset(encryptedText, 0, len + 1);
// 加密函数
int ret = RSA_public_encrypt(clearText.length(), (const unsigned char*)clearText.c_str(), (unsigned char*)encryptedText, rsa, RSA_PKCS1_PADDING);
if (ret >= 0)
strRet = std::string(encryptedText, ret);
// 释放内存
free(encryptedText);
BIO_free_all(keybio);
RSA_free(rsa);
return strRet;
}
// 私钥解密
std::string rsa_pri_decrypt(const std::string &cipherText, const std::string &priKey)
{
std::string strRet;
RSA *rsa = RSA_new();
BIO *keybio;
keybio = BIO_new_mem_buf((unsigned char *)priKey.c_str(), -1);
// 此处有三种方法
// 1, 读取内存里生成的密钥对,再从内存生成rsa
// 2, 读取磁盘里生成的密钥对文本文件,在从内存生成rsa
// 3,直接从读取文件指针生成rsa
rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa, NULL, NULL);
int len = RSA_size(rsa);
char *decryptedText = (char *)malloc(len + 1);
memset(decryptedText, 0, len + 1);
// 解密函数
int ret = RSA_private_decrypt(cipherText.length(), (const unsigned char*)cipherText.c_str(), (unsigned char*)decryptedText, rsa, RSA_PKCS1_PADDING);
if (ret >= 0)
strRet = std::string(decryptedText, ret);
// 释放内存
free(decryptedText);
BIO_free_all(keybio);
RSA_free(rsa);
return strRet;
}
int main(int argc, char **argv)
{
// 原始明文
std::string srcText = "this is an example";
std::string encryptText;
std::string encryptHexText;
std::string decryptText;
std::cout << "=== 原始明文 ===" << std::endl;
std::cout << srcText << std::endl;
// md5
std::cout << "=== md5哈希 ===" << std::endl;
md5(srcText, encryptText, encryptHexText);
std::cout << "摘要字符: " << encryptText << std::endl;
std::cout << "摘要串: " << encryptHexText << std::endl;
// sha256
std::cout << "=== sha256哈希 ===" << std::endl;
sha256(srcText, encryptText, encryptHexText);
std::cout << "摘要字符: " << encryptText << std::endl;
std::cout << "摘要串: " << encryptHexText << std::endl;
// des
std::cout << "=== des加解密 ===" << std::endl;
std::string desKey = "12345";
encryptText = des_encrypt(srcText, desKey);
std::cout << "加密字符: " << std::endl;
std::cout << encryptText << std::endl;
decryptText = des_decrypt(encryptText, desKey);
std::cout << "解密字符: " << std::endl;
std::cout << decryptText << std::endl;
// rsa
std::cout << "=== rsa加解密 ===" << std::endl;
std::string key[2];
generateRSAKey(key);
std::cout << "公钥: " << std::endl;
std::cout << key[0] << std::endl;
std::cout << "私钥: " << std::endl;
std::cout << key[1] << std::endl;
encryptText = rsa_pub_encrypt(srcText, key[0]);
std::cout << "加密字符: " << std::endl;
std::cout << encryptText << std::endl;
decryptText = rsa_pri_decrypt(encryptText, key[1]);
std::cout << "解密字符: " << std::endl;
std::cout << decryptText << std::endl;
system("pause");
return 0;
}
编译同上
解析
①md5:不可逆,MD5的输出长度是128位,通常以32位的16进制数字表示,例如:0caa3b23b8da53f9e4e041d95dc8fa2c,
3、md5
参考:https://blog.51cto.com/dlican/3744253
简介
md5信息摘要算法:广泛使用的哈希算法,产生一个128位的哈希值,用于验证信息传输的一致性。无法防止碰撞。
用途
密码加密:用户的密码不以明文存储在数据库中,而是保存md5,再再次输入密码校验时,计算md5,与数据库中的md5比较。
电子签名:相当于每个文件的指纹,用于软件下载,对比是否一致
垃圾邮件筛选:建立邮件md5值资料库,统计邮件的md5,允许出现次数,出现的次数。对每一封收到的邮件进行计算、比较、判断。
源码
md5.h
/*
* Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#ifndef OPENSSL_MD5_H
# define OPENSSL_MD5_H
# pragma once
# include <openssl/macros.h>
# ifndef OPENSSL_NO_DEPRECATED_3_0
# define HEADER_MD5_H
# endif
# include <openssl/opensslconf.h>
# ifndef OPENSSL_NO_MD5
# include <openssl/e_os2.h>
# include <stddef.h>
# ifdef __cplusplus
extern "C" {
# endif
# define MD5_DIGEST_LENGTH 16
# if !defined(OPENSSL_NO_DEPRECATED_3_0)
/*
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* ! MD5_LONG has to be at least 32 bits wide. !
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*/
# define MD5_LONG unsigned int
# define MD5_CBLOCK 64
# define MD5_LBLOCK (MD5_CBLOCK/4)
typedef struct MD5state_st {
MD5_LONG A, B, C, D;
MD5_LONG Nl, Nh;
MD5_LONG data[MD5_LBLOCK];
unsigned int num;
} MD5_CTX;
# endif
# ifndef OPENSSL_NO_DEPRECATED_3_0
OSSL_DEPRECATEDIN_3_0 int MD5_Init(MD5_CTX *c);
OSSL_DEPRECATEDIN_3_0 int MD5_Update(MD5_CTX *c, const void *data, size_t len);
OSSL_DEPRECATEDIN_3_0 int MD5_Final(unsigned char *md, MD5_CTX *c);
OSSL_DEPRECATEDIN_3_0 unsigned char *MD5(const unsigned char *d, size_t n,
unsigned char *md);
OSSL_DEPRECATEDIN_3_0 void MD5_Transform(MD5_CTX *c, const unsigned char *b);
# endif
# ifdef __cplusplus
}
# endif
# endif
#endif
相关函数分析
// 初始化,成功返回1,失败返回0
int MD5_Init(MD5_CTX *c);
// 循环调用此函数,可以将不同的数据加到一起计算md5,成功返回1,失败返回0
int MD5_Update(MD5_CTX *c, const void *data, size_t len);
// 计算md5结果,成功返回1,失败返回0
int MD5_Final(unsigned char *md, MD5_CTX *c);
// 前三个函数的总和,直接计算md5
unsigned char *MD5(const unsigned char *d, size_t n, unsigned char *md);
// 内部函数,不需要调用
void MD5_Transform(MD5_CTX *c, const unsigned char *b);
示例
#include <string.h>
#include <iostream>
#include "openssl/md5.h"
int md5(int length)
{
int ret = -1; // 函数调用返回值
MD5_CTX c;
const char* data = "hello world"; // 原始内容
unsigned char md5[length + 1];
// 1.初始化
ret = MD5_Init(&c);
if (ret != 1)
{
std::cout << "MD5_Init failed ...\n";
return 1;
}
// 2.添加数据
ret = MD5_Update(&c, data, strlen(data));
if (ret != 1)
{
std::cout << "MD5_Update failed ...\n";
return 1;
}
// 3.计算md5结果
memset(md5, 0 ,sizeof(md5));
ret = MD5_Final(md5, &c);
if (ret != 1)
{
std::cout << "MD5_Final failed ...\n";
return 1;
}
// 4.输出结果
std::cout << "原始内容=" << data << std::endl;
std::cout << "length=" << length << std::endl; // 16B,128位
std::cout << "md5=" << md5 << std::endl; // 16B,按字符串输出
// 按16进制输出,4位为一组
unsigned char buf[length * 2 + 1];
memset(buf, 0, sizeof(buf));
for(int i=0; i<length; i++)
{
sprintf((char*)&buf[i*2], "%02x", md5[i]);
}
std::cout << "md5=" << buf << std::endl;
std::cout << "=========================\n";
// 1、直接使用MD5
memset(md5, 0, sizeof(md5));
MD5((unsigned char*)data, strlen(data), md5);
// 2、输出
std::cout << "原始内容=" << data << std::endl;
std::cout << "length=" << length << std::endl; // 16B,128位
std::cout << "md5=" << md5 << std::endl; // 16B,按字符串输出
// 按16进制输出,4位为一组
memset(buf, 0, sizeof(buf));
for(int i=0; i<length; i++)
{
sprintf((char*)&buf[i*2], "%02x", md5[i]);
}
std::cout << "md5=" << buf << std::endl;
std::cout << std::endl;
return 0;
}
int main()
{
md5(MD5_DIGEST_LENGTH); // 5eb63bbbe01eeed093cb22bb8f5acdc3
}
4、sha
密码散列函数,生成160位(20B)的散列值,通常呈现为40个十六进制数
源码:
sha.h
/*
* Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#ifndef OPENSSL_SHA_H
# define OPENSSL_SHA_H
# pragma once
# include <openssl/macros.h>
# ifndef OPENSSL_NO_DEPRECATED_3_0
# define HEADER_SHA_H
# endif
# include <openssl/e_os2.h>
# include <stddef.h>
# ifdef __cplusplus
extern "C" {
# endif
# define SHA_DIGEST_LENGTH 20
# ifndef OPENSSL_NO_DEPRECATED_3_0
/*-
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* ! SHA_LONG has to be at least 32 bits wide. !
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*/
# define SHA_LONG unsigned int
# define SHA_LBLOCK 16
# define SHA_CBLOCK (SHA_LBLOCK*4)/* SHA treats input data as a
* contiguous array of 32 bit wide
* big-endian values. */
# define SHA_LAST_BLOCK (SHA_CBLOCK-8)
typedef struct SHAstate_st {
SHA_LONG h0, h1, h2, h3, h4;
SHA_LONG Nl, Nh;
SHA_LONG data[SHA_LBLOCK];
unsigned int num;
} SHA_CTX;
OSSL_DEPRECATEDIN_3_0 int SHA1_Init(SHA_CTX *c);
OSSL_DEPRECATEDIN_3_0 int SHA1_Update(SHA_CTX *c, const void *data, size_t len);
OSSL_DEPRECATEDIN_3_0 int SHA1_Final(unsigned char *md, SHA_CTX *c);
OSSL_DEPRECATEDIN_3_0 void SHA1_Transform(SHA_CTX *c, const unsigned char *data);
# endif
unsigned char *SHA1(const unsigned char *d, size_t n, unsigned char *md);
# ifndef OPENSSL_NO_DEPRECATED_3_0
# define SHA256_CBLOCK (SHA_LBLOCK*4)/* SHA-256 treats input data as a
* contiguous array of 32 bit wide
* big-endian values. */
typedef struct SHA256state_st {
SHA_LONG h[8];
SHA_LONG Nl, Nh;
SHA_LONG data[SHA_LBLOCK];
unsigned int num, md_len;
} SHA256_CTX;
OSSL_DEPRECATEDIN_3_0 int SHA224_Init(SHA256_CTX *c);
OSSL_DEPRECATEDIN_3_0 int SHA224_Update(SHA256_CTX *c,
const void *data, size_t len);
OSSL_DEPRECATEDIN_3_0 int SHA224_Final(unsigned char *md, SHA256_CTX *c);
OSSL_DEPRECATEDIN_3_0 int SHA256_Init(SHA256_CTX *c);
OSSL_DEPRECATEDIN_3_0 int SHA256_Update(SHA256_CTX *c,
const void *data, size_t len);
OSSL_DEPRECATEDIN_3_0 int SHA256_Final(unsigned char *md, SHA256_CTX *c);
OSSL_DEPRECATEDIN_3_0 void SHA256_Transform(SHA256_CTX *c,
const unsigned char *data);
# endif
unsigned char *SHA224(const unsigned char *d, size_t n, unsigned char *md);
unsigned char *SHA256(const unsigned char *d, size_t n, unsigned char *md);
# define SHA256_192_DIGEST_LENGTH 24
# define SHA224_DIGEST_LENGTH 28
# define SHA256_DIGEST_LENGTH 32
# define SHA384_DIGEST_LENGTH 48
# define SHA512_DIGEST_LENGTH 64
# ifndef OPENSSL_NO_DEPRECATED_3_0
/*
* Unlike 32-bit digest algorithms, SHA-512 *relies* on SHA_LONG64
* being exactly 64-bit wide. See Implementation Notes in sha512.c
* for further details.
*/
/*
* SHA-512 treats input data as a
* contiguous array of 64 bit
* wide big-endian values.
*/
# define SHA512_CBLOCK (SHA_LBLOCK*8)
# if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32__)
# define SHA_LONG64 unsigned __int64
# elif defined(__arch64__)
# define SHA_LONG64 unsigned long
# else
# define SHA_LONG64 unsigned long long
# endif
typedef struct SHA512state_st {
SHA_LONG64 h[8];
SHA_LONG64 Nl, Nh;
union {
SHA_LONG64 d[SHA_LBLOCK];
unsigned char p[SHA512_CBLOCK];
} u;
unsigned int num, md_len;
} SHA512_CTX;
OSSL_DEPRECATEDIN_3_0 int SHA384_Init(SHA512_CTX *c);
OSSL_DEPRECATEDIN_3_0 int SHA384_Update(SHA512_CTX *c,
const void *data, size_t len);
OSSL_DEPRECATEDIN_3_0 int SHA384_Final(unsigned char *md, SHA512_CTX *c);
OSSL_DEPRECATEDIN_3_0 int SHA512_Init(SHA512_CTX *c);
OSSL_DEPRECATEDIN_3_0 int SHA512_Update(SHA512_CTX *c,
const void *data, size_t len);
OSSL_DEPRECATEDIN_3_0 int SHA512_Final(unsigned char *md, SHA512_CTX *c);
OSSL_DEPRECATEDIN_3_0 void SHA512_Transform(SHA512_CTX *c,
const unsigned char *data);
# endif
unsigned char *SHA384(const unsigned char *d, size_t n, unsigned char *md);
unsigned char *SHA512(const unsigned char *d, size_t n, unsigned char *md);
# ifdef __cplusplus
}
# endif
#endif
函数说明
// SHA1算法,是对md5的升级,结果为20B,SHA256,SHA384,SHA512是对SHA1的升级
// 初始化SHA_CTX,成功返回1,失败返回0
int SHA1_Init(SHA_CTX *c);
// 用户循环调用此函数,可以将不同数据叠加在一起计算SHA1,成功返回1,失败返回0
int SHA1_Update(SHA_CTX *c, const void *data, size_t len);
// 计算SHA1
int SHA1_Final(unsigned char *md, SHA_CTX *c);
// 内部函数,用户不需要调用
void SHA1_Transform(SHA_CTX *c, const unsigned char *data);
// SHA1_Init、SHA1_Update、SHA1_Final的合并版本,直接计算SHA1的值
unsigned char *SHA1(const unsigned char *d, size_t n, unsigned char *md);
例子
#include <string.h>
#include <iostream>
#include "openssl/sha.h"
int sha1(int length)
{
int ret = -1; // 函数调用返回值
SHA_CTX c;
const char* data = "hello world"; // 原始内容
unsigned char md[length + 1];
// 1.初始化
ret = SHA1_Init(&c);
if (ret != 1)
{
std::cout << "SHA1_Init failed ...\n";
return 1;
}
// 2.添加数据
ret = SHA1_Update(&c, data, strlen(data));
if (ret != 1)
{
std::cout << "SHA1_Update failed ...\n";
return 1;
}
// 3.计算sha结果
memset(md, 0 ,sizeof(md));
ret = SHA1_Final(md, &c);
if (ret != 1)
{
std::cout << "SHA1_Final failed ...\n";
return 1;
}
// 4.输出结果
std::cout << "原始内容=" << data << std::endl;
std::cout << "length=" << length << std::endl; // 16B,128位
std::cout << "sha1=" << md << std::endl; // 16B,按字符串输出
// 按16进制输出,4位为一组
unsigned char buf[length * 2 + 1];
memset(buf, 0, sizeof(buf));
for(int i=0; i<length; i++)
{
sprintf((char*)&buf[i*2], "%02x", md[i]);
}
std::cout << "sha1=" << buf << std::endl;
std::cout << "=========================\n";
// 1、直接使用SHA1
memset(md, 0, sizeof(md));
SHA1((unsigned char*)data, strlen(data), md);
// 2、输出
std::cout << "原始内容=" << data << std::endl;
std::cout << "length=" << length << std::endl; // 16B,128位
std::cout << "sha1=" << md << std::endl; // 16B,按字符串输出
// 按16进制输出,4位为一组
memset(buf, 0, sizeof(buf));
for(int i=0; i<length; i++)
{
sprintf((char*)&buf[i*2], "%02x", md[i]);
}
std::cout << "sha1=" << buf << std::endl;
std::cout << std::endl;
return 0;
}
int main()
{
sha1(SHA_DIGEST_LENGTH); // 2aae6c35c94fcfb415dbe95f408b9ce91ee846ed
}
5、对内容进行加解密
如何选择合适的加密算法和密钥?
①密钥加密/对称加密:使用相同的密钥进行加解密
②公钥加密/非对称加密:使用不同的密钥进行加解密,公钥-加密,私钥-解密
加密算法
- 对称加密算法:
- DES(Data Encryption Standard):是一种较旧的加密算法,安全性相对较低,已被更强大的算法所取代。
- 3DES:是DES的一种更安全的变种,使用三个密钥进行三次加密。
- AES(Advanced Encryption Standard):是一种广泛使用的加密算法,具有较高的安全性和性能。适用于大量数据的加密。
- RC4:是一种流式加密算法,速度快,适用于较小的数据块和网络传输加密。
- 非对称加密算法:
- RSA(Rivest-Shamir-Adleman):是最常见的非对称加密算法之一,用于公钥加密和数字签名。适用于数字证书和网络安全等领域。
- DSA(Digital Signature Algorithm):是一种数字签名算法,用于验证数据的完整性和身份认证。
- 混合加密方案:
- 在实际应用中,通常会结合使用对称加密算法和非对称加密算法。例如,使用非对称加密算法交换密钥,然后使用对称加密算法加密实际数据。这样可以提高加密和解密的速度,同时保证安全性。
选择合适的加密和解密算法时,需要考虑以下几个因素:
- 安全性:选择足够安全的算法,能够抵御各种攻击和破解手段。
- 性能:选择高效、快速的算法,能够满足实际应用的需求。
- 兼容性:选择广泛接受和使用的算法,以确保与其他系统和工具的兼容性。
- 密钥管理:需要考虑密钥的生成、存储、备份和更新等管理问题。
- 成本:需要考虑实现和使用这些算法所需的成本,包括硬件、软件和人员培训等方面的成本
aes
参考:https://blog.csdn.net/m0_46577050/article/details/121302115
介绍
高级加密标准:Advanced encryption Standard
分组密码:数据分组长度为128比特、密钥长度为128/192/256比特
工作模式:分为ecb模式和cbc模式
ecb:将数据按照8个字节一段进行DES加密或解密得到一段段的8个字节的密文或者明文。ECB模式简单高效,易于并行化计算,但在某些情况下可能存在安全漏洞,因为相同的明文块会被加密为相同的密文块,容易受到某些类型的攻击
cbc:每个明文块先与前一个密文块进行异或后,再进行加密。CBC模式提供了更好的安全性,因为相同的明文块加密后不会得到相同的密文块,但需要更多的计算资源和存储空间。
函数说明
aes.h
// 设置加密密钥
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);
void AES_encrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key);
void AES_decrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key);
// ecb模式加解密,enc:AES_ENCRYPT代表加密,AES_DECRYPT代表解密;
void AES_ecb_encrypt(const unsigned char *in, unsigned char *out,
const AES_KEY *key, const int enc);
void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
size_t length, const AES_KEY *key,
unsigned char *ivec, const int enc);
注意:调用加解密函数之前,必须要设置密钥
例子一
使用AES_encrypt、AES_decrypt
#include <string.h>
#include <iostream>
#include "openssl/aes.h"
// 十六进制输出
void printHex(const char* text, int length)
{
unsigned char buf[length * 2 + 1];
memset(buf, 0, sizeof(buf));
for(int i=0; i<length; i++)
{
sprintf((char*)&buf[i*2], "%02x", text[i]);
}
std::cout << "加密=" << buf << std::endl;
}
std::string encryptAES(const std::string &plaintext, const std::string &key)
{
AES_KEY aesKey;
if (AES_set_encrypt_key(reinterpret_cast<const unsigned char *>(key.c_str()), 128, &aesKey) < 0)
{
std::cerr << "Error setting AES encryption key" << std::endl;
return "";
}
std::string ciphertext;
ciphertext.resize(plaintext.size());
AES_encrypt(reinterpret_cast<const unsigned char *>(plaintext.c_str()),
reinterpret_cast<unsigned char *>(&ciphertext[0]), &aesKey);
return ciphertext;
}
std::string decryptAES(const std::string &ciphertext, const std::string &key)
{
AES_KEY aesKey;
if (AES_set_decrypt_key(reinterpret_cast<const unsigned char *>(key.c_str()), 128, &aesKey) < 0)
{
std::cerr << "Error setting AES decryption key" << std::endl;
return "";
}
std::string plaintext;
plaintext.resize(ciphertext.size());
AES_decrypt(reinterpret_cast<const unsigned char *>(ciphertext.c_str()),
reinterpret_cast<unsigned char *>(&plaintext[0]), &aesKey);
return plaintext;
}
int main()
{
std::string plaintext = "hello world"; // 原始文本内容
std::string key = "0123456789abcdef"; // 用户密钥
std::cout << "Plaintext: " << plaintext << std::endl;
std::string ciphertext = encryptAES(plaintext, key);
// std::cout << "Ciphertext: " << ciphertext << std::endl;
printHex(ciphertext.c_str(), ciphertext.length()); // 76ff3262ff511cffff59ffffffbb
std::string decryptedText = decryptAES(ciphertext, key);
std::cout << "Decrypted text: " << decryptedText << std::endl;
return 0;
}
例子二
使用AES_ecb_encrypt
#include <iostream>
#include <cstring>
#include "openssl/aes.h"
// 十六进制输出
void printHex(const unsigned char* text, int length)
{
// c
// unsigned char buf[length * 2 + 1];
// memset(buf, 0, sizeof(buf));
// for(int i=0; i<length; i++)
// {
// sprintf((char*)&buf[i*2], "%02x", text[i]);
// }
// std::cout << "加密=" << buf << std::endl;
// c++
std::cout << "加密=";
for (int i = 0; i < length; i++)
{
std::cout << std::hex << (int)text[i];
}
std::cout << std::endl;
}
// 加密函数
void encrypt(const unsigned char *plaintext, const unsigned char *key, unsigned char *ciphertext)
{
AES_KEY aesKey;
AES_set_encrypt_key(key, 128, &aesKey);
AES_ecb_encrypt(plaintext, ciphertext, &aesKey, AES_ENCRYPT);
}
// 解密函数
void decrypt(const unsigned char *ciphertext, const unsigned char *key, unsigned char *plaintext)
{
AES_KEY aesKey;
AES_set_decrypt_key(key, 128, &aesKey);
AES_ecb_encrypt(ciphertext, plaintext, &aesKey, AES_DECRYPT);
}
int main()
{
unsigned char plaintext[] = "hello world";
unsigned char key[] = "0123456789abcdef";
unsigned char ciphertext[AES_BLOCK_SIZE];
unsigned char decryptedtext[AES_BLOCK_SIZE];
encrypt(plaintext, key, ciphertext);
decrypt(ciphertext, key, decryptedtext);
std::cout << "Plaintext: " << plaintext << std::endl;
printHex(ciphertext, AES_BLOCK_SIZE); // a41348d7816565d39541068aaa72f75
std::cout << "Decryptedtext: " << decryptedtext << std::endl;
return 0;
}
例子三
使用AES_cbc_encrypt
#include <iostream>
#include <string>
#include <string.h>
#include "openssl/aes.h"
// 十六进制输出
void printHex(const unsigned char* text, int length)
{
// c
// unsigned char buf[length * 2 + 1];
// memset(buf, 0, sizeof(buf));
// for(int i=0; i<length; i++)
// {
// sprintf((char*)&buf[i*2], "%02x", text[i]);
// }
// std::cout << "加密=" << buf << std::endl;
// c++
std::cout << "加密=";
for (int i = 0; i < length; i++)
{
std::cout << std::hex << (int)text[i];
}
std::cout << std::endl;
}
// 加密函数
void encrypt(const unsigned char *plaintext, int plaintext_len, const unsigned char *key, unsigned char *iv, unsigned char *ciphertext)
{
AES_KEY aes_key;
AES_set_encrypt_key(key, 128, &aes_key);
AES_cbc_encrypt(plaintext, ciphertext, plaintext_len, &aes_key, iv, AES_ENCRYPT);
}
// 解密函数
void decrypt(const unsigned char *ciphertext, int ciphertext_len, const unsigned char *key, unsigned char *iv, unsigned char *plaintext)
{
AES_KEY aes_key;
AES_set_decrypt_key(key, 128, &aes_key);
AES_cbc_encrypt(ciphertext, plaintext, ciphertext_len, &aes_key, iv, AES_DECRYPT);
}
int main()
{
const unsigned char key[] = "0123456789abcdef"; // 16字节的密钥
unsigned char iv1[] = "1234567890abcdef"; // 16字节的初始向量
unsigned char iv2[] = "1234567890abcdef"; // 16字节的初始向量
const unsigned char plaintext[] = "hello world"; // 明文
int plaintext_len = strlen((const char *)plaintext);
unsigned char ciphertext[16] = {0}; // 存储加密后的密文
encrypt(plaintext, plaintext_len, key, iv1, ciphertext); // iv会被篡改
unsigned char decrypted[16] = {0}; // 存储解密后的明文
decrypt(ciphertext, plaintext_len, key, iv2, decrypted); // iv会被篡改
std::cout << "Plaintext: " << plaintext << std::endl;
printHex(ciphertext, 16); // e62dfbf3621ac86a5a1c17c6a9578a6
std::cout << "Decrypted: " << decrypted << std::endl;
return 0;
}
命令使用*
二、基础
(一)版本
openssl与gcc编译器,或者说ubuntu系统,centos系统,国产系统的版本对应情况
1、libcrypto.so跟系统GLIBC版本相关
openssl-3.2.0中,libcrypto.so.3需要GLIBC_2.25
如何查询GLIBC版本,可以使用以下命令
①通用
getconf GNU_LIBC_VERSION
②ubuntu
ldd --version:输出结果中包含版本信息,如ldd (Ubuntu GLIBC 2.27-3ubuntu1.4) 2.27
strings /lib/x86_64-linux-gnu/libc.so.6 | grep GLIBC
③centos
rpm -qa | grep glibc
三、问题
(一)环境和依赖
1、找不到-lm/-lc
错误:
g++ md5test.cpp -I/home/work/openssl-1.0.1u/include -L/home/work/openssl-1.0.1u/ -lcrypto -static
/usr/bin/ld:找不到-lm
/usr/bin/ld:找不到-lc
collect2:错误:ld返回1
环境:
centos7.5下使用openssl-1.0.1u.tar.gz默认配置生成的静态库进行编译,会产生此错误
解决:
标签:std,const,int,openssl,unsigned,char,include From: https://www.cnblogs.com/circlelll/p/17988788①yum install glibc-static
②使用动态库:重新编译,注意清除之前静态库的编译内容,否则报错:./config shared