OpenSSL编程实例.doc
- 格式:doc
- 大小:17.91 KB
- 文档页数:11
客户端程序// OpenSSLClient、cpp#include <winsock2、h>#include <iostream>using namespace std;#pragma ment (lib, "Ws2_32、lib")#include "openssl/ssl、h"#pragma ment(lib, "ssleay32、lib")#pragma ment(lib, "libeay32、lib")#define SERVICE_PORT 10000const int nBufSize = 512;// 初始化2、2版本Winsockint InitWinsock(){WSADATA wsaData = {0};WORD wVer = MAKEWORD(2,2);int nRet = WSAStartup(wVer, &wsaData);if(nRet != 0){cout<<"Winsock初始化失败,错误代码就是"<<nRet<<endl; }return nRet;}// 创建一个套接字SOCKET CreateSocket(){SOCKET hSocket = INVALID_SOCKET;hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if(hSocket == INVALID_SOCKET){int last_err = WSAGetLastError();cout<<"创建套接字失败,错误代码就是"<<last_err<<endl;}return hSocket;}// 连接到服务器int ConnectServer(SOCKET hSocket){// 填充远程套接字地址SOCKADDR_IN saServer = {0};saServer、sin_family = AF_INET;saServer、sin_port = htons(SERVICE_PORT);saServer、sin_addr、s_addr = inet_addr("127、0、0、1");// 使用远程套接字地址连接到服务器int nRet = connect(hSocket, (SOCKADDR *)&saServer, sizeof(saServer));if(nRet == SOCKET_ERROR){int last_err = WSAGetLastError();cout<<"连接失败,错误代码就是"<<last_err<<endl;}return nRet;}bool InitOpenSSL(){if(!SSL_library_init())return false;SSL_load_error_strings();return true;}int PasswordCB(char *buf, int size, int flag, void *userdata){// 作者所创建得客户端程序私匙密码就是12345678const char* pass = "12345678";if(size < strlen(pass) + 1)return(0);strcpy(buf, pass);return(strlen(pass));}int VerifyCB(int ok, X509_STORE_CTX *store){if(!ok){int err = X509_STORE_CTX_get_error(store);cout<<err<<":"<<X509_verify_cert_error_string(err)<<endl;}return ok;}SSL_CTX* InitSSLContext(){const SSL_METHOD *meth = NULL;SSL_CTX* ctx = NULL;meth = SSLv23_method();ctx = SSL_CTX_new(meth);// 加载客户端程序证书链if(!SSL_CTX_use_certificate_chain_, "ClientAppChain、pem")){cout<<"加载客户端程序证书链失败"<<endl;return NULL;}SSL_CTX_set_default_passwd_cb(ctx, PasswordCB);// 加载客户端程序私匙文件if(!SSL_CTX_use_PrivateKey_, "ClientApp_PrivateKey、pem",SSL_)){cout<<"加载客户端程序私匙文件失败"<<endl;return NULL;}// 加载客户端程序所信任得CAif(!SSL_CTX_load_verify_locations(ctx, "MyTestCA_Certificate、pem",NULL)){cout<<"加载客户端程序所信任得CA失败"<<endl;return NULL;}// 加载OpenSSL缺省信任得CAif(!SSL_CTX_set_default_verify_paths(ctx)){cout<<" 加载OpenSSL缺省信任得CA失败"<<endl;return NULL;}// 我们知道,服务器得证书链就是serverApp-->ServerCA-->MyTestCA,// 所以可以明确验证深度就是2,即最多检查ServerCA与MyTestCA两个CASSL_CTX_set_verify_depth(ctx, 2);// SSL_VERIFY_PEER要求服务器提供证书,VerifyCB用于输出OpenSSL// 握手过程中验证服务器证书链失败时得错误信息SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, VerifyCB);SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);return ctx;}// 简单得校验,仅检查mon namebool CheckCertificate(SSL* ssl){X509* cert = SSL_get_peer_certificate(ssl);if(cert == NULL)return false;X509_NAME* subjectName = X509_get_subject_name(cert);if(subjectName == NULL)return false;char buf[256];if(X509_NAME_get_text_by_NID(subjectName, NID_monName, buf, 256) >0 ){if(strcmp(buf, "serverApp") == 0)return true;}}void DoWork(SSL* ssl){char buf[256];while(true){if(!fgets(buf, sizeof(buf)/sizeof(buf[0]), stdin)){SSL_shutdown(ssl);break;}int len = strlen(buf);int nSent = 0;while(nSent < len){int nRet = SSL_write(ssl, buf+nSent, len-nSent); if(nRet <= 0){cout<<"SSL_write发生错误"<<endl;SSL_clear(ssl);break;}nSent += nRet;}}}int main(int argc, char* argv[]){if(InitWinsock() != 0)SOCKET hSocket = INVALID_SOCKET;SSL_CTX* ctx = NULL;SSL* ssl = NULL;BIO* sbio = NULL;int nRet = 0;try{if(!InitOpenSSL())throw -1;ctx = InitSSLContext();if(ctx == NULL)throw -1;ssl = SSL_new(ctx);hSocket = CreateSocket();if(hSocket == INVALID_SOCKET)throw -1;if(ConnectServer(hSocket) == SOCKET_ERROR) throw -1;sbio = BIO_new_socket(hSocket, BIO_NOCLOSE); SSL_set_bio(ssl, sbio, sbio);if(SSL_connect(ssl) <= 0){cout<<"SSL握手发生错误"<<endl;throw -1;}if(!CheckCertificate(ssl))throw -1;DoWork(ssl);}catch(int excpt_err){nRet = excpt_err;}//if(sbio) BIO_free(sbio);if(ssl) SSL_free(ssl);if(ctx) SSL_CTX_free(ctx);if(hSocket != INVALID_SOCKET)closesocket(hSocket);WSACleanup();return 0;}----------------------------------------------------服务器程序// OpenSSLServer、cpp#include <winsock2、h>#include <iostream>using namespace std;#pragma ment (lib, "Ws2_32、lib")#include "openssl/ssl、h"#pragma ment(lib, "ssleay32、lib")#pragma ment(lib, "libeay32、lib")#define SERVICE_PORT 10000const int nBufSize = 512;// 初始化2、2版本Winsockint InitWinsock(){WSADATA wsaData = {0};WORD wVer = MAKEWORD(2,2);int nRet = WSAStartup(wVer, &wsaData);if(nRet != 0){cout<<"Winsock初始化失败,错误代码就是"<<nRet<<endl; }return nRet;}// 创建一个套接字SOCKET CreateSocket(){SOCKET hSocket = INVALID_SOCKET;hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if(hSocket == INVALID_SOCKET){int last_err = WSAGetLastError();cout<<"创建套接字失败,错误代码就是"<<last_err<<endl; }return hSocket;}// 绑定与监听int BindListen(SOCKET hSocket){// 填充本地套接字地址sockaddr_in saListen = {0};saListen、sin_family = AF_INET;saListen、sin_port = htons(SERVICE_PORT);saListen、sin_addr、s_addr = htonl(INADDR_ANY);// 把本地套接字地址绑定到监听套接字int nRet = bind(hSocket, (sockaddr*)&saListen, sizeof(sockaddr));if(nRet == SOCKET_ERROR){int last_err = WSAGetLastError();cout<<"绑定套接字失败,错误代码就是"<<last_err<<endl;}else{// 开始监听nRet = listen(hSocket, 5);if(nRet == SOCKET_ERROR){int last_err = WSAGetLastError();cout<<"监听失败,错误代码就是"<<last_err<<endl;}}return nRet;}// 接收连接请求SOCKET AcceptRequest(SOCKET hSocket){sockaddr_in saClient = {0};int nSALen = sizeof(sockaddr);SOCKET hClientSocket = accept(hSocket, (sockaddr*)&saClient, &nSALen);if(hClientSocket == INVALID_SOCKET){int last_err = WSAGetLastError();cout<<"接受连接请求失败,错误代码就是"<<last_err<<endl;}return hClientSocket;}bool InitOpenSSL(){if(!SSL_library_init())return false;SSL_load_error_strings();return true;}int PasswordCB(char *buf, int size, int flag, void *userdata){// 作者所创建得服务器程序私匙密码就是abcdefghconst char* pass = "abcdefgh";if(size < strlen(pass) + 1)return(0);strcpy(buf, pass);return(strlen(pass));}int VerifyCB(int ok, X509_STORE_CTX *store){if(!ok){int err = X509_STORE_CTX_get_error(store);cout<<err<<":"<<X509_verify_cert_error_string(err)<<endl;}return ok;}SSL_CTX* InitSSLContext(){const SSL_METHOD *meth = NULL;SSL_CTX* ctx = NULL;meth = SSLv23_method();ctx = SSL_CTX_new(meth);// 加载服务器程序证书链if(!SSL_CTX_use_certificate_chain_, "serverAppChain、pem")){cout<<"加载服务器程序证书链失败"<<endl;return NULL;}SSL_CTX_set_default_passwd_cb(ctx, PasswordCB);// 加载服务器程序私匙文件if(!SSL_CTX_use_PrivateKey_, "ServerApp_PrivateKey、pem",SSL_)){cout<<"加载服务器程序私匙文件失败"<<endl;return NULL;}// 加载服务器程序所信任得CAif(!SSL_CTX_load_verify_locations(ctx, "MyTestCA_Certificate、pem",NULL)){cout<<"加载服务器程序所信任得CA失败"<<endl;return NULL;}// 加载OpenSSL缺省信任得CAif(!SSL_CTX_set_default_verify_paths(ctx)){cout<<" 加载OpenSSL缺省信任得CA失败"<<endl;return NULL;}// 我们知道,客户端得证书链就是ClientApp-->MyTestCA,// 所以可以明确验证深度就是1,即只检查MyTestCASSL_CTX_set_verify_depth(ctx, 1);// SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT要求客户端提供证书,// 如果不提供得话,则校验失败。
OpenSSL 是一个开源的加密库,提供了各种加密算法、数字证书、SSL/TLS 协议等功能,被广泛用于网络安全和加密通信领域。
以下是OpenSSL 的一些常见用法和操作:1. 生成证书:使用OpenSSL 可以生成各种类型的数字证书,包括自签名证书、CA 证书、服务器证书、客户端证书等。
您可以使用OpenSSL 提供的命令行工具或API 接口来生成证书。
2. 加密和解密:OpenSSL 提供了各种加密算法,包括对称加密和非对称加密。
您可以使用OpenSSL 提供的命令行工具或API 接口来进行加密和解密操作。
3. 签名和验证:OpenSSL 提供了数字签名和验证的功能,可以用于保证数据的完整性和真实性。
您可以使用OpenSSL 提供的命令行工具或API 接口来进行签名和验证操作。
4. SSL/TLS 安全通信:OpenSSL 提供了SSL/TLS 协议的实现,可以用于安全通信。
您可以使用OpenSSL 提供的命令行工具或API 接口来实现SSL/TLS 安全通信。
5. 网络安全工具:OpenSSL 提供了各种网络安全工具,包括OpenSSL s_server、OpenSSL s_client、OpenSSL speed、OpenSSL rand 等。
这些工具可以用于测试和评估网络安全性能。
要使用OpenSSL,您需要安装OpenSSL 库,并包含相应的头文件。
在编写代码时,您可以调用OpenSSL 提供的函数和数据结构来实现您需要的加密、签名、SSL/TLS 安全通信等功能。
OpenSSL 提供了详细的文档和使用手册,您可以在OpenSSL 官方网站上找到完整的文档和参考手册。
在文档中,您可以找到各种函数的使用说明、示例代码和详细的接口说明,以帮助您更好地使用OpenSSL 库。
openssl3.0加密算法库编程精要05-详解EVPAPI公开密钥密码算法--⽣成密钥对5.1 公开密钥系统简介 公开密钥系统最早于上世纪 70 年代被发明。
在这种密码系统中,已知加密密钥,在现有计算机技术条件下很难快速求出解密密钥,这个推导过程耗费的计算机算⼒巨⼤到不切实际,所以加密密钥是可以公开的,所以这种系统被称为公开密钥系统。
公开密钥系统被⼴泛地⽤于各种密码协议、数字签名以及电⼦商务等各种领域中。
5.2 RSA 算法 公开密钥系统使⽤的算法最流⾏的当属 RSA 算法,它由 Ronald Rivest、Adi Shamir 和 Lenoard Adleman 于上世纪70 年代发明,该算法的安全性基于⼤数分解的难度,它的原理如下: 设:明⽂为P,密⽂为C,加密函数E(x),解密函数D(x); (1)⾸先选取⼀个公钥指数 e,同时⽣成两个⼤素数 p 和 q; (2)计算n=pq,同时计算欧拉函数ϕ(n)=ϕ(pq)=ϕ(p)ϕ(q)=(p−1)(q−1),确保当前公钥指数 e 和ϕ(n) 互素,那么 e 和 n 组成的数对 (e, n) 即为公钥; (3)加密过程为E(P)=C≡P e(mod n), 0⩽; (4)由于 e 和 n 互素,所以存在⼀个 e 的逆 d,使得ed \equiv 1 (mod \phi(n)) 成⽴,故解密时需要先解线 性同余⽅程求出 d; (5)求出 d 之后,解密过程则为D(C) = C^{d} = ( P^{e} )^{d} = P^{ed}; (6)由于ed \equiv 1 (mod \phi(n)) 成⽴,所以存在⼀个整数 k,使得等式ed = k\phi(n) + 1成⽴; (7)如果P和 n 互素,由欧拉定理得出,P^{\phi(ed)} \equiv P^{k\phi(n) + 1} \equiv PP^{k\phi(n)} \equiv P(mod n) (8)⼀般情况下,P和 n 不互素的概率极⼩,但是如果P和 n 不互素,那么由于P必然⼩于 n (如果 P > n,则⽆法通过解密算法计算出明⽂),p 和 q ⼜都是素数,那么 P必然符合以下的条件 P = ap或P = bq,同时P \neq kpq,a 和 b 为正整数,由于 p 和 q 为素数,所以有以下结论 如果P = ap,那么P和 q 互素; 如果P = bq,那么P和 p 互素; 所以我们假设P = ap,那么P和 q 互素,根据欧拉定理得 P^{\phi(q)} \equiv 1(mod q),然后有 (P^{\phi(q)})^{k\phi(p)} \equiv (1)^{k\phi(p)}(mod q) P^{k\phi(n)} \equiv 1(mod q),然后根据同余的定义可知,存在⼀个数 r,使得以下式⼦成⽴ P^{k\phi(n)} = 1 + rq,两边同时乘以P,得 P^{k\phi(n) + 1} = P + rqP,⼜因为P = ap,所以 P^{k\phi(n) + 1} = P + rqap,然后由于n = pq,所以 P^{k\phi(n) + 1} = P + ran,由于 r、a 是常量,所以最终得 P^{k\phi(n) + 1} \equiv P(mod n),进⼀步得到 P^{ed} \equiv P(mod n) 所以我们证明了使⽤ d 可以解密出加密数据,那么数对 (d,n) 即为私钥,但是原⽂P必须⼩于模数 n, 否则⽆法正确解密。
openssl编程示例以OpenSSL编程示例为标题的文章是关于如何使用OpenSSL库进行编程的。
OpenSSL是一个开源的加密工具包,提供了许多密码学功能,如加密、解密、签名和验证等。
在本文中,我将介绍OpenSSL 库的基本使用方法,并提供一些编程示例来帮助读者更好地理解。
OpenSSL是一个功能强大且广泛使用的加密库,可以用于开发各种应用程序,包括网络安全、数据传输和身份验证等。
它支持许多密码学算法,如对称加密算法(如AES和DES)、非对称加密算法(如RSA和ECC)以及哈希函数(如MD5和SHA-256)等。
在开始使用OpenSSL之前,我们需要安装OpenSSL库并配置开发环境。
安装OpenSSL库的具体方法因操作系统而异,可以在OpenSSL 官方网站上找到相关的安装指南。
配置开发环境主要包括设置编译器参数和链接库文件等。
一旦环境配置完成,我们就可以开始使用OpenSSL库进行编程了。
下面是一些常用的OpenSSL编程示例:1. 生成密钥对使用OpenSSL库生成非对称加密算法所需的密钥对是一个常见的操作。
以下是一个生成RSA密钥对的示例代码:```c#include <openssl/rsa.h>int main() {RSA* rsa = RSA_generate_key(2048, RSA_F4, NULL, NULL);if (rsa == NULL) {printf("Failed to generate RSA key pair\n");return -1;}// 打印公钥和私钥printf("Public Key:\n%s\n", BN_bn2hex(rsa->n));printf("Private Key:\n%s\n", BN_bn2hex(rsa->d));RSA_free(rsa);return 0;}```2. 加密和解密数据使用OpenSSL库进行数据加密和解密是保护数据安全的常见操作。
openssl简易文档一:编译前置工作:1.下载openssl.网址:/source/2.解压缩.3.下载activeperl,并安装.编译:用vs2005编译,编译之前要先根据配置生成makefile,具体为下面a,b,c三步:a.C:\OpenSSL\openssl-0.9.8>Perl Configure VC-WIN32b.C:\OpenSSL\openssl1-0.9.8>ms\do_ms.batc.C:\OpenSSL\openssl-0.9.8>nmake -f ms\ntdll.mak编译选项:我们必须在生成makefile前使得openssl得到正确配置,方法就是在Perl Configure VC-WIN32命令行加入编译选项,具体为:Perl Configure VC-WIN32 XXX,其中XXX为下列三大类全局选项第一类是全局性选项:zlibzlib-dynamicno-zlib使用静态的zlib压缩库、使用动态的zlib压缩库、不使用zlib压缩功能。
threadsno-threads是否编译支持多线程的库。
默认支持。
sharedno-shared是否生成动态连接库。
(重点)enable-sse2no-sse2启用/禁用SSE2指令集加速。
如果你的CPU支持SSE2指令集,就可以打开,否则就要关闭。
gmpno-gmp启用/禁用GMP库rfc3779no-rfc3779启用/禁用实现X509v3证书的IP地址扩展krb5no-krb5启用/禁用Kerberos 5 支持sslno-sslssl2ssl3no-ssl2no-ssl3tlsno-tls 启用/禁用SSL(包含了SSL2/SSL3) TLS 协议支持。
算法选项可选的目录如下:no-md2,no-md4,no-mdc2,no-ripemd这些都是摘要算法,含义一目了然。
openssl使用方式
摘要:
1.OpenSSL 简介
2.OpenSSL 的使用方式
3.示例:使用OpenSSL 进行加密和解密
4.小结
正文:
OpenSSL 是一个安全套接字层(SSL)和传输层安全(TLS)协议的开源加密库,广泛应用于互联网的安全通信。
它支持多种加密算法、数字签名、证书管理等功能,为网络应用程序提供了安全的通信功能。
OpenSSL 的使用方式主要分为以下几个步骤:
1.安装OpenSSL 库:首先,你需要在你的计算机或服务器上安装OpenSSL 库。
在Linux 系统中,可以使用“sudo apt-get install openssl”命令进行安装。
在Windows 系统中,可以通过访问OpenSSL 官网下载相应版本的安装包进行安装。
2.配置OpenSSL:安装完成后,你需要对OpenSSL 进行配置,以便它能够正确地为你的应用程序提供服务。
配置过程包括设置加密算法、生成密钥和证书等。
具体的配置方法可以参考OpenSSL 的官方文档。
3.初始化OpenSSL:在应用程序中,你需要使用OpenSSL 的API 对SSL/TLS 连接进行初始化。
这一步通常包括创建一个SSL/TLS 上下文、初始化一个SSL/TLS 连接等。
4.加密和解密数据:在数据传输过程中,你需要使用OpenSSL 的API 对数据进行加密和解密。
加密过程中,你需要使用SSL/TLS 上下文和密钥对数据进行加密;解密过程中,你需要使用SSL/TLS 上下文和相应的私钥对数据进行解密。
openssl的man中文文档发信站: BBS 水木清华站 (Fri Nov 10 20:19:30 2000) [/b:631992e780]不久前接到有关ssl的活,结果找遍中文网站资料实在奇缺。
感觉是好象现在国内做这个技术的人不多所有有兴趣写点东西来介绍一下。
我使用的ssl的toolkit是openssl就用openssl做例子来讲解openssl实在太大了,指令也多,API也多,更严重的是它的API没有说明。
我打算漫漫说清楚其主要指令的用法,主要API的中文说明,以及使用/编程的方法。
工作量很大,因为我接触它也没几个月,现在大概完成了1/10吧,先把目前自己的一些心得,找到的资料和一些翻译出来的东西贴出来,希望对研究ssl的人有帮助openssl简介-证书/forum/viewtopic.php?p=3161562#3161585openssl简介-加密算法/forum/viewtopic.php?p=3161562#3161685openssl简介-协议/forum/viewtopic.php?p=3161562#3161727openssl简介-入门/forum/viewtopic.php?p=3161562#3162073openssl简介-指令 verify/forum/viewtopic.php?p=3161562#3173096openssl简介-指令asn1parse/forum/viewtopic.php?p=3161562#3173120 openssl简介-指令ca/forum/viewtopic.php?p=3173126#3173126openssl简介-指令cipher/forum/viewtopic.php?p=3173132#3173132 openssl简介-指令dgst/forum/viewtopic.php?p=3173136#3173136openssl简介-指令dhparam/forum/viewtopic.php?p=3173142#3173142openssl简介-指令enc/forum/viewtopic.php?p=3173146#3173146openssl简介-指令gendsa/forum/viewtopic.php?p=3173149#3173149openssl简介-指令genrsa/forum/viewtopic.php?p=3173152#3173152openssl简介-指令passwd/forum/viewtopic.php?p=3173154#3173154openssl简介-指令pkcs7/forum/viewtopic.php?p=3173156#3173156openssl简介-指令rand/forum/viewtopic.php?p=3173158#3173158openssl简介-指令req/forum/viewtopic.php?p=3173162#3173162openssl简介-指令rsa/forum/viewtopic.php?p=3173164#3173164openssl简介-指令rsautl/forum/viewtopic.php?p=3173168#3173168 openssl简介-指令s_client/forum/viewtopic.php?p=3173171#3173171openssl简介-指令s_server/forum/viewtopic.php?p=3173175#3173175openssl简介-指令sess_id/forum/viewtopic.php?p=3173176#3173176openssl简介-指令speed/forum/viewtopic.php?p=3173178#3173178openssl简介-指令version/forum/viewtopic.php?p=3173181#3173181openssl简介-指令x509/forum/viewtopic.php?p=3173188#3173188wingger 回复于:2005-01-07 09:29:51[b:2f84c104e9]标题:openssl简介--证书[/b:2f84c104e9][b:2f84c104e9]发信站:BBS水木清华站(FriNov1020:29:282000)引用请指明原作译者fordesign@二证书[/b:2f84c104e9]证书就是数字化的文件,里面有一个实体(网站,个人等)的公共密钥和其他的属性,如名称等。
Openssl之EVP系列作者: LaoKa200804261.算法封装EVP系列的函数定义包含在"evp.h"里面,这是一系列封装了openssl加密库里面所有算法的函数。
通过这样的统一的封装,使得只需要在初始化参数的时候做很少的改变,就可以使用相同的代码但采用不同的加密算法进行数据的加密和解密。
EVP系列函数主要封装了三大类型的算法,要支持全部这些算法,请调用OpenSSL_add_all_algorithms 函数,下面分别就其结构作一个简单的介绍。
1.1公开密钥算法函数名称:EVP_Seal*...*,EVP_Open*...*功能描述:该系列函数封装提供了公开密钥算法的加密和解密功能,实现了电子信封的功能。
相关文件:p_seal.c,p_open.c1.2数字签名算法函数名称:EVP_Sign*...*,EVP_Verify*...*功能描述:该系列函数封装提供了数字签名算法和功能。
相关文件:p_sign.c,p_verify.c1.3对称加密算法函数名称:EVP_Encrypt*...*功能描述:该系列函数封装提供了对称加密算法的功能。
相关文件:evp_enc.c,p_enc.c,p_dec.c,e_*.c1.4信息摘要算法函数名称:EVP_Digest*...*功能描述:该系列函数封装实现了多种信息摘要算法。
相关文件:digest.c,m_*.c1.5信息编码算法函数名称:EVP_Encode*...*功能描述:该系列函数封装实现了ASCII码与二进制码之间的转换函数和功能。
相关文件:encode.c注意:自从出现engin版本以后,所有对称加密算法和摘要算法可以用ENGINE模块实现的算法代替。
如果ENGINE模块实现的对称加密和信息摘要函数被注册为缺省的实现算法,那么当使用各种EVP函数时,软件编译的时候会自动将该实现模块连接进去。
2.对称加密算法概述对称加密算法封装的函数系列名字是以EVP_Encrypt*...*开头的,其实,这些函数只是简单调用了EVP_Cipher*...*系列的同名函数,换一个名字可能是为了更好的区别和理解。
OpenSSL程序编写步骤OpenSSL是一个开放源代码的SSL协议的产品实现,它采用C语言作为开发语言,具备了跨系统的性能。
调用OpenSSL 的函数就可以实现一个SSL加密的安全数据传输通道,从而保护客户端和服务器之间数据的安全。
头文件:#include <openssl/ssl.h>#include <openssl/err.h>基于OpenSSL的程序都要遵循以下几个步骤:(1 ) OpenSSL初始化在使用OpenSSL之前,必须进行相应的协议初始化工作,这可以通过下面的函数实现:int SSL_library_int(void);(2 ) 选择会话协议在利用OpenSSL开始SSL会话之前,需要为客户端和服务器制定本次会话采用的协议,目前能够使用的协议包括TLSv1.0、SSLv2、SSLv3、SSLv2/v3。
需要注意的是,客户端和服务器必须使用相互兼容的协议,否则SSL会话将无法正常进行。
(3 ) 创建会话环境在OpenSSL中创建的SSL会话环境称为CTX,使用不同的协议会话,其环境也不一样的。
申请SSL会话环境的OpenSSL函数是:SSL_CTX *SSL_CTX_new(SSL_METHOD * method);当SSL会话环境申请成功后,还要根据实际的需要设置CTX的属性,通常的设置是指定SSL 握手阶段证书的验证方式和加载自己的证书。
制定证书验证方式的函数是:int SSL_CTX_set_verify(SSL_CTX *ctx,int mode,int(*verify_callback),int(X509_STORE_CTX *));为SSL会话环境加载CA证书的函数是:SSL_CTX_load_verify_location(SSL_CTX *ctx,const char *Cafile,const char *Capath);为SSL会话加载用户证书的函数是:SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file,int type);为SSL会话加载用户私钥的函数是:SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx,const char* file,int type);在将证书和私钥加载到SSL会话环境之后,就可以调用下面的函数来验证私钥和证书是否相符:int SSL_CTX_check_private_key(SSL_CTX *ctx);(4) 建立SSL套接字SSL套接字是建立在普通的TCP套接字基础之上,在建立SSL套接字时可以使用下面的一些函数:SSL *SSl_new(SSL_CTX *ctx);//申请一个SSL套接字int SSL_set_fd(SSL *ssl,int fd);)//绑定读写套接字int SSL_set_rfd(SSL *ssl,int fd);//绑定只读套接字int SSL_set_wfd(SSL *ssl,int fd);//绑定只写套接字(5) 完成SSL握手在成功创建SSL套接字后,客户端应使用函数SSL_connect( )替代传统的函数connect( )来完成握手过程:int SSL_connect(SSL *ssl);而对服务器来讲,则应使用函数SSL_ accept ( )替代传统的函数accept ( )来完成握手过程:int SSL_accept(SSL *ssl);握手过程完成之后,通常需要询问通信双方的证书信息,以便进行相应的验证,这可以借助于下面的函数来实现:X509 *SSL_get_peer_certificate(SSL *ssl);该函数可以从SSL套接字中提取对方的证书信息,这些信息已经被SSL验证过了。
openssl之aes加密(AES_cbc_encrypt与AES_encrypt的编程案例)openssl之aes加密(AES_cbc_encrypt 与 AES_encrypt 的编程案例)2014-01-09 16:28:26| 分类:软件安全以及传输|举报|字号订阅下载LOFTER我的照片书 |上图是运行程序的测试结果。
可见加密解密已经完成。
这里也能够看出,AES_cbc_encrypt的参数主要用途,其中,len 是加密数据长度,由于加密调用了AES_encrypt,而这个函数每次只能加密16个字节,所以,out长度必须是16的整数倍,或者至少大于in长度的最小16倍数,这样才能真正完成加密解密。
而如果in长度不足不是16的倍数,那么最后的几个字节,其实相当于填充0。
AES_cbc_encrypt((unsigned char*)in, (unsigned char*)out, len, &aes, iv, AES_ENCRYPT)PS:我在编写代码的过程中,又一次,加密成功,但是解密一直失败,一直不明白为什么,后来才懂。
注意代码中的红色部分,AES_set_encrypt_key和AES_set_decrypt_key是不一样的,同时,加密和解密的参数AES_ENCRYPT和AES_DECRYPT也是不一样的,要特别注意,很可能因为细节忘了,导致出现问题而浪费时间。
现在,上面这个加密解密后的结果。
如果仔细观察的话,可以看出,两种加密方式得到的密文,前面的16个字节是一样的。
而后面的就不一样了。
这是因为,cbc模式使用了初始化向量,而我初始化向量设置为0,等于不起作用,而cbc模式的加密也是调用了AES_encrypt接口,所以前面的16个字节是一样的,接着的内容,会跟前一次得到的密文进行异或,所以就不一样了。
关于cbc加密和ecb加密,强烈推荐看openssl之aes加密(源码分析AES_encrypt 与AES_cbc_encrypt ,加密模式),是一个很好的理解和入门。
openssl编程轻松入门(含完整示例). 编写目的第一次跑起openssl示例并不太简单,本文的目的是为了让这个过程变得非常简单。
在开始之前,要非常感谢周立发同学,正是通过他共享的示例,较轻松的入了门。
本文档对他共享的示例中的一个小错误进行了修正,并提供了傻瓜式的“编译-生成-KEY运行”一条龙脚本(方法请参见压缩包中的readme文件),让跑第一个openssl程序变得轻轻松松。
2. 示例包8. 相关头文件8.1. socket头文件#include <sys/types.h>#include <arpa/inet.h>#include <netinet/in.h>#include <sys/socket.h>8.2. SSL头文件#include <openssl/ssl.h>#include <openssl/err.h>9. 结尾上面步骤应当画得比较清楚了,结合图再对照ssl_test.tar.gz和《加密通讯协议SSL编程.pdf》就可以非常快地上手了。
ssl_test.tar.gz为示例源代码包,openssl-0.9.8h-SuSE10.tar.gz 为openssl二进制包(因超过2M,不能作为附件下载,请上官网下载),测试时是安装在/usr/local/ssl。
ssl_test.tar.gz中的示例在SuSE10中测试通过,使用的是openssl-0.9.8h,它包括如下文件:-rw-r--r-- 1 root root 1346 Dec 5 18:11 cacert.pem-rwxr-xr-x 1 root root 114 Dec 5 18:11 make_key.sh-rwxr-xr-x 1 root root 172 Dec 5 18:37 mk_client.sh-rwxr-xr-x 1 root root 172 Dec 5 18:37 mk_server.sh-rw-r--r-- 1 root root 1679 Dec 5 18:11 privkey.pem-rw-r--r-- 1 root root 167 Dec 5 18:39 readme-rwxr-xr-x 1 root root 38 Dec 5 18:38 run_client.sh-rwxr-xr-x 1 root root 64 Dec 5 18:38 run_server.sh-rwxr-xr-x 1 root root 1140142 Dec 5 18:38 ssl_client-rw-r--r-- 1 root root 3928 Dec 5 17:31 ssl_client.cpp-rwxr-xr-x 1 root root 1139667 Dec 5 18:38 ssl_server-rw-r--r-- 1 root root 4882 Dec 5 17:31 ssl_server.cppreadme为包内容说明,run_server.sh用来运行服务端,run_client.sh用来运行客户端,mk_server.sh用来编译服务端,mk_client.sh用来编译客户端,make_key.sh用来生成钥匙KEY。
OpenSSL有两种运行模式:交互模式和批处理模式。
直接输入openssl回车进入交互模式,输入带命令选项的openssl进入批处理模式。
(1) 配置文件OpenSSL的默认配置文件位置不是很固定,可以用openssl ca命令得知。
你也可以指定自己的配置文件。
当前只有三个OpenSSL命令会使用这个配置文件:ca, req, x509。
有望未来版本会有更多命令使用配置文件。
(2)消息摘要算法支持的算法包括:MD2, MD4, MD5, MDC2, SHA1(有时候叫做DSS1), RIPEMD-160。
SHA1和RIPEMD-160产生160位哈西值,其他的产生128位。
除非出于兼容性考虑,否则推荐使用SHA1或者RIPEMD-160。
除了RIPEMD-160需要用rmd160命令外,其他的算法都可用dgst命令来执行。
OpenSSL对于SHA1的处理有点奇怪,有时候必须把它称作DSS1来引用。
消息摘要算法除了可计算哈西值,还可用于签名和验证签名。
签名的时候,对于DSA生成的私匙必须要和DSS1(即SHA1)搭配。
而对于RSA生成的私匙,任何消息摘要算法都可使用。
############################################################## 消息摘要算法应用例子# 用SHA1算法计算文件file.txt的哈西值,输出到stdout$ openssl dgst -sha1 file.txt# 用SHA1算法计算文件file.txt的哈西值,输出到文件digest.txt$ openssl sha1 -out digest.txt file.txt# 用DSS1(SHA1)算法为文件file.txt签名,输出到文件dsasign.bin# 签名的private key必须为DSA算法产生的,保存在文件dsakey.pem中$ openssl dgst -dss1 -sign dsakey.pem -out dsasign.bin file.txt# 用dss1算法验证file.txt的数字签名dsasign.bin,# 验证的private key为DSA算法产生的文件dsakey.pem$ openssl dgst -dss1 -prverify dsakey.pem -signature dsasign.bin file.txt# 用sha1算法为文件file.txt签名,输出到文件rsasign.bin# 签名的private key为RSA算法产生的文件rsaprivate.pem$ openssl sha1 -sign rsaprivate.pem -out rsasign.bin file.txt# 用sha1算法验证file.txt的数字签名rsasign.bin,# 验证的public key为RSA算法生成的rsapublic.pem$ openssl sha1 -verify rsapublic.pem -signature rsasign.bin file.txt(3) 对称密码OpenSSL支持的对称密码包括Blowfish, CAST5, DES, 3DES(Triple DES), IDEA, RC2, RC4以及RC5。
OpenSSL源代码学习 - P7/P10/P12说明一、基础知识1.Openssl 简史OpenSSL项目是加拿大人Eric A.Yang 和Tim J.Hudson开发,现在有OpenSS项目小组负责改进和维护;他们是全球一些技术精湛的志愿技术人员,他们的劳动是无偿的,在此我们应该向他们表示崇高的敬意。
OpenSSL 最早的版本在1995年发布,1998年开始由OpenSSL项目组维护。
当前最新版本为OpenSSL 1.0.1;开放源代码的SSL产品实现,采用C语言开发;源代码可以在自由下载,The OpenSSL Project is a collaborative effort to develop a robust, commercial-grade, full-featured, and Open Source toolkit implementing the Secure Sockets Layer (SSL v2/v3) and Transport La yer Security (TLS v1) protocols as well as a full-strength general purpose cryptography library. The project is managed by a worldwide community of volu nteers that use the Internet to communicate, plan, and develop the OpenSSL toolkit and its related docum entation.OpenSSL is based on the excellent SSLeay library developed by Eric A. Young and Tim J. Hudson. The OpenSSL toolkit is licensed under an Apache-style licence, which basically means that you are free to get and use it for commercial and non-commercial purposes subject to some simple license conditions.2.SSL协议和TLS协议SSL是Netscape开发的专门用户保护Web通讯的,目前版本为3.0。
实用密码库openssl简单编程实践一、概述在网络信息安全的应用中,密码学技术是一项非常重要的技术之一。
而openssl是一个强大的密码库,提供了多种密码学算法的实现,是开发安全网络应用的理想选择。
本文将介绍openssl密码库的简单编程实践,帮助读者快速上手使用openssl库进行密码学应用的开发。
二、概述openssl密码库1. openssl密码库简介openssl密码库是一个开源的密码库,提供了丰富的密码学算法的实现,包括对称加密算法、非对称加密算法、数字签名算法等。
它广泛应用于网络安全、加密通信、数字证书等领域,是当前最流行的密码库之一。
2. openssl密码库的特点- 开源免费:openssl密码库是一个开源项目,可以免费获取源代码进行使用和修改。
- 跨评台:openssl密码库支持多种操作系统,包括Linux、Windows、Mac等,可以在不同评台上进行应用开发。
- 支持多种密码算法:openssl密码库支持对称加密算法如AES、DES,非对称加密算法如RSA、ECC,以及数字签名算法如DSA、ECDSA 等,满足各种安全需求。
- 丰富的应用库:openssl密码库还提供了丰富的应用库,包括SSL/TLS协议实现、数字证书管理等,可以满足各种安全应用的开发需求。
三、openssl密码库的安装和配置1. openssl密码库的安装在Linux系统中,openssl密码库通常已经预装。
如果没有预装,可以通过包管理工具安装openssl库:```sudo apt-get install openssl```在Windows系统中,可以从openssl全球信息站下载对应版本的openssl库进行安装。
2. openssl密码库的配置安装完成后,需要配置openssl密码库的环境变量,以方便编程时调用openssl库中的函数和头文件。
在Linux系统中,可以将openssl库的路径添加到LD_LIBRARY_PATH环境变量中:```export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/ssl/lib```在Windows系统中,可以将openssl库的路径添加到环境变量中,在编译时指定openssl库的路径。
要编译使用OpenSSL ECC (Elliptic Curve Cryptography) 的程序,您需要确保已经安装了OpenSSL 库,并且使用适当的编译命令。
以下是一个示例程序和编译命令:```c#include <stdio.h>#include <openssl/ec.h>#include <openssl/err.h>int main() {// 创建ECC 密钥对EC_KEY *key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);if (key == NULL) {printf("Failed to create ECC key pair\n");return 1;}// 生成随机私钥if (!EC_KEY_generate_key(key)) {printf("Failed to generate ECC private key\n");EC_KEY_free(key);return 1;}// 获取公钥ECPublicKey pubKey;EC_KEY_set_public_key(key, &pubKey);// 打印公钥和私钥printf("Public key: ");BN_print_fp(stdout, EC_KEY_get0_public_key(key)); printf("\n");printf("Private key: ");BN_print_fp(stdout, EC_KEY_get0_private_key(key)); printf("\n");// 释放密钥对和错误队列EC_KEY_free(key);ERR_free_strings();return 0;}```要编译这个示例程序,您可以使用以下命令:```bashgcc -o ecc_example ecc_example.c -lcrypto -lgmp -ldl```这将使用GCC 编译器编译名为`ecc_example.c` 的源文件,并将输出文件命名为`ecc_example`。
opensslAES加密算法API的使⽤⽰例openssl为⽤户提供了丰富的指令,同时也提供了供编程调⽤的API,本⽂以使⽤128位aes算法的ecb模式进⾏加密和解密验证,如下所⽰第⼀种⽅法,直接使⽤aes算法提供的api进⾏调⽤,代码如下#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <openssl/aes.h>int main(void){char userkey[AES_BLOCK_SIZE];unsigned char *date = malloc(AES_BLOCK_SIZE*3);unsigned char *encrypt = malloc(AES_BLOCK_SIZE*3 + 4);unsigned char *plain = malloc(AES_BLOCK_SIZE*3);AES_KEY key;memset((void*)userkey, 'k', AES_BLOCK_SIZE);memset((void*)date, 'p', AES_BLOCK_SIZE*3);memset((void*)encrypt, 0, AES_BLOCK_SIZE*6);memset((void*)plain, 0, AES_BLOCK_SIZE*3);/*设置加密key及密钥长度*/AES_set_encrypt_key(userkey, AES_BLOCK_SIZE*8, &key);int len = 0;/*循环加密,每次只能加密AES_BLOCK_SIZE长度的数据*/while(len < AES_BLOCK_SIZE*3) {AES_encrypt(date+len, encrypt+len, &key);len += AES_BLOCK_SIZE;}/*设置解密key及密钥长度*/AES_set_decrypt_key(userkey, AES_BLOCK_SIZE*8, &key);len = 0;/*循环解密*/while(len < AES_BLOCK_SIZE*3) {AES_decrypt(encrypt+len, plain+len, &key);len += AES_BLOCK_SIZE;}/*解密后与原数据是否⼀致*/if(!memcmp(plain, date, AES_BLOCK_SIZE*3)){printf("test success\n");}else{printf("test failed\n");}printf("encrypt: ");int i = 0;for(i = 0; i < AES_BLOCK_SIZE*3 + 4; i++){printf("%.2x ", encrypt[i]);if((i+1) % 32 == 0){printf("\n");}}printf("\n");return0;}编译执⾏结果如下xlzh@cmos:~/cmos/openssl-code/aes$ gcc aes.c -o aes.out -lssl -lcryptoxlzh@cmos:~/cmos/openssl-code/aes$ ./aes.outtest successencrypt: 08 a9 74 4d b0 6657 1b 57 fe 60 3d 91 e4 ed 5308 a9 74 4d b0 6657 1b 57 fe 60 3d 91 e4 ed 5308 a9 74 4d b0 6657 1b 57 fe 60 3d 91 e4 ed 5300000000xlzh@cmos:~/cmos/openssl-code/aes$第⼆种⽅法,使⽤EVP框架,⽰例如下#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <openssl/evp.h>#include <openssl/aes.h>int main(void){char userkey[EVP_MAX_KEY_LENGTH];char iv[EVP_MAX_IV_LENGTH];unsigned char *date = malloc(AES_BLOCK_SIZE*3);unsigned char *encrypt = malloc(AES_BLOCK_SIZE*6);unsigned char *plain = malloc(AES_BLOCK_SIZE*6);EVP_CIPHER_CTX ctx;int ret;int tlen = 0;int mlen = 0;int flen = 0;memset((void*)userkey, 'k', EVP_MAX_KEY_LENGTH);memset((void*)iv, 'i', EVP_MAX_IV_LENGTH);memset((void*)date, 'p', AES_BLOCK_SIZE*3);memset((void*)encrypt, 0, AES_BLOCK_SIZE*6);memset((void*)plain, 0, AES_BLOCK_SIZE*6);/*初始化ctx*/EVP_CIPHER_CTX_init(&ctx);/*指定加密算法及key和iv(此处IV没有⽤)*/ret = EVP_EncryptInit_ex(&ctx, EVP_aes_128_ecb(), NULL, userkey, iv);if(ret != 1) {printf("EVP_EncryptInit_ex failed\n");exit(-1);}/*禁⽤padding功能*/EVP_CIPHER_CTX_set_padding(&ctx, 0);/*进⾏加密操作*/ret = EVP_EncryptUpdate(&ctx, encrypt, &mlen, date, AES_BLOCK_SIZE*3); if(ret != 1) {printf("EVP_EncryptUpdate failed\n");exit(-1);}/*结束加密操作*/ret = EVP_EncryptFinal_ex(&ctx, encrypt+mlen, &flen);if(ret != 1) {printf("EVP_EncryptFinal_ex failed\n");exit(-1);}tlen = mlen + flen;tlen = 0;mlen = 0;flen = 0;EVP_CIPHER_CTX_cleanup(&ctx);EVP_CIPHER_CTX_init(&ctx);ret = EVP_DecryptInit_ex(&ctx, EVP_aes_128_ecb(), NULL, userkey, iv);if(ret != 1) {printf("EVP_DecryptInit_ex failed\n");exit(-1);}EVP_CIPHER_CTX_set_padding(&ctx, 0);ret = EVP_DecryptUpdate(&ctx, plain, &mlen, encrypt, AES_BLOCK_SIZE*3); if(ret != 1) {printf("EVP_DecryptUpdate failed\n");exit(-1);}ret = EVP_DecryptFinal_ex(&ctx, plain+mlen, &flen);if(ret != 1) {printf("EVP_DecryptFinal_ex failed\n");exit(-1);}/*对⽐解密后与原数据是否⼀致*/if(!memcmp(plain, date, AES_BLOCK_SIZE*3)) {printf("test success\n");} else {printf("test failed\n");}printf("encrypt: ");int i;for(i = 0; i < AES_BLOCK_SIZE*3+4; i ++){printf("%.2x ", encrypt[i]);if((i+1)%32 == 0){printf("\n");}}printf("\n");return0;}编译执⾏结果如下:xlzh@cmos:~/cmos/openssl-code/aes$ gcc evp.c -o evp.out -lssl -lcryptoxlzh@cmos:~/cmos/openssl-code/aes$ ./evp.outtest successencrypt: 08 a9 74 4d b0 6657 1b 57 fe 60 3d 91 e4 ed 5308 a9 74 4d b0 6657 1b 57 fe 60 3d 91 e4 ed 5308 a9 74 4d b0 6657 1b 57 fe 60 3d 91 e4 ed 5300000000xlzh@cmos:~/cmos/openssl-code/aes$EVP框架是对openssl提供的所有算法进⾏了封装,在使⽤⼯程中只需要修改少量的代码就可以选择不同的加密算法,在⼯作中通常采⽤这种⽅式。
openssl实验会用opensll.exe应用程序指令参阅两个文档《openssl编程第32章》和《openssl应用程序指令》rand 生成随机数生成随机数。
用法:openssl rand [-out file] [-rand file(s)] [-base64] num选项:-out file结果输出到file中。
-engine e采用engine来生成随机数。
-rand file指定随机数种子文件。
-base64输出结果为BASE64编码数据。
num随机数长度。
示例:(1) openssl rand –base64 100(2)openssl rand –base64 –out myr.dat 100用WinHex或UltraEdit打开myr.datspeedspeed命令用于测试库的性能。
用法:openssl speed [-engine id] [md2] [mdc2] [md5] [hmac] [sha1] [rmd160] [idea-cbc] [rc2-cbc] [rc5-cbc] [bf-cbc] [des-cbc] [des-ede3] [rc4][rsa512] [rsa1024] [rsa2048] [rsa4096] [dsa512] [dsa1024][dsa2048][idea] [rc2] [des] [rsa] [blowfish]选项:-engine id设置硬件引擎id。
-elapsed测量采用实时时间,不是所用CPU时间,两者时间差异较大。
-mr生成机器可读显示。
-multi n并行允许n个测试。
示例:openssl speed md5Prime检查一个数是否为素数。
示例如下:openssl prime 79openssl prime -hex 4Fencenc为对称加解密工具,还可以进行base64编码转换。
用法:openssl enc -ciphername [-in filename] [-out filename] [-pass arg] [-e ] [-d ] [-a ] [-A] [-k password ] [-kfile filename] [-K key] [-iv IV] [-p] [-P] [-bufsize number] [-nopad] [-debug] 选项:-ciphername对称算法名字,此命令有两种适用方式:-ciphername方式或者省略enc直接用ciphername。
openssl rsa c++用法OpenSSL 是一个强大的加密库,它可以用于在C++ 程序中执行各种加密和解密操作,包括RSA 密钥的生成、加密和解密。
以下是一个简单的示例,演示如何在C++ 中使用OpenSSL 来生成RSA 密钥、加密和解密数据。
请注意,使用OpenSSL 需要安装OpenSSL 库并包含正确的头文件。
此示例假设您已经配置了OpenSSL 环境。
```cpp#include <iostream>#include <openssl/rsa.h>#include <openssl/pem.h>#include <openssl/err.h>int main() {// 初始化OpenSSL 库OpenSSL_add_all_algorithms();ERR_load_crypto_strings();// 生成RSA 密钥对RSA *rsa = RSA_generate_key(2048, RSA_F4, nullptr, nullptr);if (rsa == nullptr) {std::cerr << "Failed to generate RSA key pair." << std::endl;return 1;}// 加密和解密数据const char *plaintext = "Hello, RSA!";size_t plaintext_len = strlen(plaintext);unsigned char encrypted[256]; // 大小足够存放加密后的数据unsigned char decrypted[256]; // 大小足够存放解密后的数据int encrypted_len = RSA_public_encrypt(plaintext_len, (const unsigned char*)plaintext, encrypted, rsa, RSA_PKCS1_PADDING);if (encrypted_len == -1) {std::cerr << "Encryption failed." << std::endl;return 1;}int decrypted_len = RSA_private_decrypt(encrypted_len, encrypted, decrypted, rsa, RSA_PKCS1_PADDING);if (decrypted_len == -1) {std::cerr << "Decryption failed." << std::endl;return 1;}std::cout << "Original Text: " << plaintext << std::endl;std::cout << "Encrypted Text: ";for (int i = 0; i < encrypted_len; ++i) {printf("%02X", encrypted[i]);}std::cout << std::endl;std::cout << "Decrypted Text: " << decrypted << std::endl;// 释放RSA 密钥RSA_free(rsa);// 清理OpenSSL 资源ERR_free_strings();EVP_cleanup();return 0;}```上述示例中,我们首先初始化OpenSSL 库,然后生成了一个2048 位的RSA 密钥对。
openssl加解密代码⽰例#include <iostream>#include <string.h>// sha系列哈希算法都包含该头⽂件#include <openssl/sha.h>#include <openssl/rsa.h>#include <openssl/pem.h> // 将秘钥写⽂件的时候#include <string>#include <openssl/aes.h>extern "C"{#include <openssl/applink.c> // 编译的时候将applinc.c包含进去参与编译};using namespace std;void sha1Test(){// 1. 初始化SHA_CTX ctx;SHA1_Init(&ctx);// 2. 添加数据SHA1_Update(&ctx, "hello", strlen("hello"));SHA1_Update(&ctx, ", world", strlen(", world"));// 3. 哈希计算unsigned char* md = new unsigned char[SHA_DIGEST_LENGTH];char* res = new char[SHA_DIGEST_LENGTH*2 + 1];SHA1_Final(md, &ctx);// 4. 格式转换for (int i = 0; i < SHA_DIGEST_LENGTH; ++i){sprintf(&res[i * 2], "%02x", md[i]);}cout << "sha1: " << res << endl;}// ⽣成rsa密钥对void generateRsaKey(){// 1. 创建rsa变量RSA* rsa = RSA_new();// 1.5 创建bignum对象, 并初始化BIGNUM* e = BN_new();BN_set_word(e, 12345);// 2. ⽣成密钥对 -> 密钥对在内存中RSA_generate_key_ex(rsa, 1024, e, NULL);// 3. 将密钥对写⼊到磁盘#if 1// 公钥RSA* pubKey = RSAPublicKey_dup(rsa);// 私钥RSA* priKey = RSAPrivateKey_dup(rsa);#endif#if 0FILE* fp = fopen("public.pem", "w");PEM_write_RSAPublicKey(fp, rsa);fclose(fp);// 写私钥fp = fopen("private.pem", "w");PEM_write_RSAPrivateKey(fp, rsa, NULL, NULL, 0, NULL, NULL);fclose(fp);#elseBIO* bio = BIO_new_file("public-1.pem", "w");PEM_write_bio_RSAPublicKey(bio, rsa);// 释放资源BIO_free(bio);bio = BIO_new_file("private-1.pem", "w");PEM_write_bio_RSAPrivateKey(bio, rsa, NULL, NULL, 0, NULL, NULL);BIO_free(bio);#endif}// 公钥加密string encryptPublicKey(){// 1. 准备要加密数据string text = "让编程改变世界...";// 2. 准备秘钥 -> 公钥// 从磁盘⽂件读秘钥// 使⽤bio的⽅式BIO* bio = BIO_new_file("public-1.pem", "r");RSA* pubKey = RSA_new();if (PEM_read_bio_RSAPublicKey(bio, &pubKey, NULL, NULL) == NULL){cout << "读公钥失败了..." << endl;return string();}BIO_free(bio);// 3. 加密 -> 密⽂// 数据被加密之后, 长度和秘钥长度相同// 通过函数计算秘钥长度int keyLen = RSA_size(pubKey);char *buf = new char[keyLen];// 返回值就是密⽂长度int len = RSA_public_encrypt(text.size(), (const unsigned char*)text.data(),(unsigned char*)buf, pubKey, RSA_PKCS1_PADDING);// 4. 将密⽂返回cout << "加密之后的数据: " << buf << endl;cout << "加密之后的数据长度: " << len << endl;return string(buf, len);}// 私钥解密string decryptPrivateKey(string str){// 1. 准备秘钥 ->私钥// 从磁盘⽂件读秘钥// 使⽤bio的⽅式BIO* bio = BIO_new_file("private-1.pem", "r");RSA* priKey = RSA_new();if (PEM_read_bio_RSAPrivateKey(bio, &priKey, NULL, NULL) == NULL){cout << "读私钥失败..." << endl;return string();}BIO_free(bio);// 解密 -> 明⽂// 数据被加密之后, 长度和秘钥长度相同// 通过函数计算秘钥长度int keyLen = RSA_size(priKey);char *buf = new char[keyLen];// 返回值是解密之后的数据长度 == 原始数据长度int len = RSA_private_decrypt(str.size(), (const unsigned char*)str.data(),(unsigned char*)buf, priKey, RSA_PKCS1_PADDING);// 4. 将明⽂返回cout << "buf: " << buf << endl;return string(buf, len);}// 签名和验证签名void rsaSigAndVerfiy(){// 1. 签名数据string text = "让编程改变世界...";// 2. 秘钥RSA* pubKey = RSA_new();RSA* priKey = RSA_new();BIO* pubBio = BIO_new_file("public.pem", "r");PEM_read_bio_RSAPublicKey(pubBio, &pubKey, NULL, NULL);BIO_free(pubBio);BIO* prilBio = BIO_new_file("private.pem", "r");PEM_read_bio_RSAPrivateKey(prilBio, &priKey, NULL, NULL);BIO_free(prilBio);// 3. 签名int len = RSA_size(priKey);unsigned int outLen = 0;unsigned char* out = new unsigned char[len];RSA_sign(NID_sha1, (const unsigned char*)text.data(), text.size(),out, &outLen, priKey);// 要给到⽤户的数据string sigbuf((char*)out, outLen);// 4. 验证签名int ret = RSA_verify(NID_sha1, (const unsigned char*)text.data(), text.size(),(const unsigned char*)sigbuf.data(), sigbuf.size(), pubKey);cout << "ret : " << ret << endl;}// 测试对称加密void aesCBCCrypto(){// 1. 准备数据const char* pt = "AES是⼀套对称密钥的密码术,⽬前已⼴泛使⽤,⽤于替代已经不够安全的DES算法。
客户端程序// OpenSSLClient.cpp#include <winsock2.h>#include <iostream>using namespace std;#pragma comment (lib, "Ws2_32.lib")#include "openssl/ssl.h"#pragma comment(lib, "ssleay32.lib")#pragma comment(lib, "libeay32.lib")#define SERVICE_PORT 10000const int nBufSize = 512;// 初始化2.2版本Winsockint InitWinsock(){WSADATA wsaData = {0};WORD wVer = MAKEWORD(2,2);int nRet = WSAStartup(wVer, &wsaData);if(nRet != 0){cout<<"Winsock初始化失败,错误代码是"<<nRet<<endl;}return nRet;}// 创建一个套接字SOCKET CreateSocket(){SOCKET hSocket = INVALID_SOCKET;hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if(hSocket == INVALID_SOCKET){int last_err = WSAGetLastError();cout<<"创建套接字失败,错误代码是"<<last_err<<endl;}return hSocket;}// 连接到服务器int ConnectServer(SOCKET hSocket){// 填充远程套接字地址SOCKADDR_IN saServer = {0};saServer.sin_family = AF_INET;saServer.sin_port = htons(SERVICE_PORT);saServer.sin_addr.s_addr = inet_addr("127.0.0.1");// 使用远程套接字地址连接到服务器int nRet = connect(hSocket, (SOCKADDR *)&saServer, sizeof(saServer));if(nRet == SOCKET_ERROR){int last_err = WSAGetLastError();cout<<"连接失败,错误代码是"<<last_err<<endl;}return nRet;}bool InitOpenSSL(){if(!SSL_library_init())return false;SSL_load_error_strings();return true;}int PasswordCB(char *buf, int size, int flag, void *userdata){// 作者所创建的客户端程序私匙密码是12345678const char* pass = "12345678";if(size < strlen(pass) + 1)return(0);strcpy(buf, pass);return(strlen(pass));}int VerifyCB(int ok, X509_STORE_CTX *store){if(!ok){int err = X509_STORE_CTX_get_error(store);cout<<err<<":"<<X509_verify_cert_error_string(err)<<endl;}return ok;}SSL_CTX* InitSSLContext(){const SSL_METHOD *meth = NULL;SSL_CTX* ctx = NULL;meth = SSLv23_method();ctx = SSL_CTX_new(meth);// 加载客户端程序证书链if(!SSL_CTX_use_certificate_chain_file(ctx, "ClientAppChain.pem")){ cout<<"加载客户端程序证书链失败"<<endl;return NULL;}SSL_CTX_set_default_passwd_cb(ctx, PasswordCB);// 加载客户端程序私匙文件if(!SSL_CTX_use_PrivateKey_file(ctx, "ClientApp_PrivateKey.pem",SSL_FILETYPE_PEM)){cout<<"加载客户端程序私匙文件失败"<<endl;return NULL;}// 加载客户端程序所信任的CAif(!SSL_CTX_load_verify_locations(ctx, "MyTestCA_Certificate.pem",NULL)){cout<<"加载客户端程序所信任的CA失败"<<endl;return NULL;}// 加载OpenSSL缺省信任的CAif(!SSL_CTX_set_default_verify_paths(ctx)){cout<<" 加载OpenSSL缺省信任的CA失败"<<endl;return NULL;}// 我们知道,服务器的证书链是serverApp-->ServerCA-->MyTestCA,// 所以可以明确验证深度是2,即最多检查ServerCA和MyTestCA两个CA SSL_CTX_set_verify_depth(ctx, 2);// SSL_VERIFY_PEER要求服务器提供证书,VerifyCB用于输出OpenSSL// 握手过程中验证服务器证书链失败时的错误信息SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, VerifyCB);SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);return ctx;}// 简单的校验,仅检查common namebool CheckCertificate(SSL* ssl){X509* cert = SSL_get_peer_certificate(ssl);if(cert == NULL)return false;X509_NAME* subjectName = X509_get_subject_name(cert);if(subjectName == NULL)return false;char buf[256];if(X509_NAME_get_text_by_NID(subjectName, NID_commonName, buf, 256) >0 ){if(strcmp(buf, "serverApp") == 0)return true;}return false;}void DoWork(SSL* ssl){char buf[256];while(true){if(!fgets(buf, sizeof(buf)/sizeof(buf[0]), stdin)){SSL_shutdown(ssl);break;}int len = strlen(buf);int nSent = 0;while(nSent < len){int nRet = SSL_write(ssl, buf+nSent, len-nSent);if(nRet <= 0){cout<<"SSL_write发生错误"<<endl;SSL_clear(ssl);break;}nSent += nRet;}}}int main(int argc, char* argv[]){if(InitWinsock() != 0)return -1;SOCKET hSocket = INVALID_SOCKET;SSL_CTX* ctx = NULL;SSL* ssl = NULL;BIO* sbio = NULL;int nRet = 0;try{if(!InitOpenSSL())throw -1;ctx = InitSSLContext();if(ctx == NULL)throw -1;ssl = SSL_new(ctx);hSocket = CreateSocket();if(hSocket == INVALID_SOCKET)throw -1;if(ConnectServer(hSocket) == SOCKET_ERROR)throw -1;sbio = BIO_new_socket(hSocket, BIO_NOCLOSE);SSL_set_bio(ssl, sbio, sbio);if(SSL_connect(ssl) <= 0){cout<<"SSL握手发生错误"<<endl;throw -1;}if(!CheckCertificate(ssl))throw -1;DoWork(ssl);}catch(int excpt_err){nRet = excpt_err;}//if(sbio) BIO_free(sbio);if(ssl) SSL_free(ssl);if(ctx) SSL_CTX_free(ctx);if(hSocket != INVALID_SOCKET)closesocket(hSocket);WSACleanup();return 0;}----------------------------------------------------服务器程序// OpenSSLServer.cpp#include <winsock2.h>#include <iostream>using namespace std;#pragma comment (lib, "Ws2_32.lib")#include "openssl/ssl.h"#pragma comment(lib, "ssleay32.lib")#pragma comment(lib, "libeay32.lib")#define SERVICE_PORT 10000const int nBufSize = 512;// 初始化2.2版本Winsockint InitWinsock(){WSADATA wsaData = {0};WORD wVer = MAKEWORD(2,2);int nRet = WSAStartup(wVer, &wsaData);if(nRet != 0){cout<<"Winsock初始化失败,错误代码是"<<nRet<<endl;}return nRet;}// 创建一个套接字SOCKET CreateSocket(){SOCKET hSocket = INVALID_SOCKET;hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if(hSocket == INVALID_SOCKET){int last_err = WSAGetLastError();cout<<"创建套接字失败,错误代码是"<<last_err<<endl;}return hSocket;}// 绑定和监听int BindListen(SOCKET hSocket){// 填充本地套接字地址sockaddr_in saListen = {0};saListen.sin_family = AF_INET;saListen.sin_port = htons(SERVICE_PORT);saListen.sin_addr.s_addr = htonl(INADDR_ANY);// 把本地套接字地址绑定到监听套接字int nRet = bind(hSocket, (sockaddr*)&saListen, sizeof(sockaddr));if(nRet == SOCKET_ERROR){int last_err = WSAGetLastError();cout<<"绑定套接字失败,错误代码是"<<last_err<<endl;}else{// 开始监听nRet = listen(hSocket, 5);if(nRet == SOCKET_ERROR){int last_err = WSAGetLastError();cout<<"监听失败,错误代码是"<<last_err<<endl;}}return nRet;}// 接收连接请求SOCKET AcceptRequest(SOCKET hSocket){sockaddr_in saClient = {0};int nSALen = sizeof(sockaddr);SOCKET hClientSocket = accept(hSocket, (sockaddr*)&saClient, &nSALen);if(hClientSocket == INVALID_SOCKET){int last_err = WSAGetLastError();cout<<"接受连接请求失败,错误代码是"<<last_err<<endl;}return hClientSocket;}bool InitOpenSSL(){if(!SSL_library_init())return false;SSL_load_error_strings();return true;}int PasswordCB(char *buf, int size, int flag, void *userdata){// 作者所创建的服务器程序私匙密码是abcdefghconst char* pass = "abcdefgh";if(size < strlen(pass) + 1)return(0);strcpy(buf, pass);return(strlen(pass));}int VerifyCB(int ok, X509_STORE_CTX *store){if(!ok){int err = X509_STORE_CTX_get_error(store);cout<<err<<":"<<X509_verify_cert_error_string(err)<<endl;}return ok;}SSL_CTX* InitSSLContext(){const SSL_METHOD *meth = NULL;SSL_CTX* ctx = NULL;meth = SSLv23_method();ctx = SSL_CTX_new(meth);// 加载服务器程序证书链if(!SSL_CTX_use_certificate_chain_file(ctx, "serverAppChain.pem")){cout<<"加载服务器程序证书链失败"<<endl;return NULL;}SSL_CTX_set_default_passwd_cb(ctx, PasswordCB);// 加载服务器程序私匙文件if(!SSL_CTX_use_PrivateKey_file(ctx, "ServerApp_PrivateKey.pem",SSL_FILETYPE_PEM)){cout<<"加载服务器程序私匙文件失败"<<endl;return NULL;}// 加载服务器程序所信任的CAif(!SSL_CTX_load_verify_locations(ctx, "MyTestCA_Certificate.pem",NULL)){cout<<"加载服务器程序所信任的CA失败"<<endl;return NULL;}// 加载OpenSSL缺省信任的CAif(!SSL_CTX_set_default_verify_paths(ctx)){cout<<" 加载OpenSSL缺省信任的CA失败"<<endl;return NULL;}// 我们知道,客户端的证书链是ClientApp-->MyTestCA,// 所以可以明确验证深度是1,即只检查MyTestCASSL_CTX_set_verify_depth(ctx, 1);// SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT要求客户端提供证书,// 如果不提供的话,则校验失败。