openssl使用
一.生成自己的CA根证书
1.生成 CA 根证书私钥
openssl genrsa -des3 -out root.key 1024
genrsa 表示采用RSA算法生成根证书私钥
-des3 表示使用3DES给根证书私钥加密
1024 表示根证书私钥的长度,建议使用2048,越长越安全
这个时候会让你输入两次根证书的加密密码,就是加密证书的3des密码
2.生成 CA 的自签证书
openssl req -new -x509 -key root.key -out root.crt -days 365
这个手输如一堆东西,注意Common Name输入服务器域名或服务器IP.
二.生成服务器证书
1.生成服务器证书私钥
openssl genrsa -out server.key 1024
2.生成服务器端签名请求文件
openssl req -new -key server.key -out server.csr
同样会输入一堆东西,记得跟根证书一样,如果不一样,要去
/etc/pki/tls/openssl.cnf
将对应的项目由 match 设置成 optional
3.要在/etc/pki/CA/ 文件夹下建立一个空文件 index.txt
touch /etc/pki/CA/index.txt
4.要在/etc/pki/CA/ 文件夹下建立一个文件 serial,并写入01
echo "01" > /etc/pki/CA/serial
5.利用 CA 进行签名证书
openssl ca -in server.csr -out server.crt -keyfile root.key -cert root.crt -days 365
附:
得到 pfx 格式的私钥,密钥算法为 pkcs12
openssl pkcs12 -export -out server.pfx -inkey server.key -in server.crt
从pfx文件中分离出 cer 格式的公钥
openssl x509 -inform pem -in server.crt -outform der -out server_public.cer
客户端证书类似操作
服务端程序
#include <stdio.h> #include <stdlib.h> #include <memory.h> #include <errno.h> #include <sys/types.h> #include <unistd.h> #include <sys/socket.h> #include <arpa/inet.h> #include "openssl/rsa.h" #include "openssl/crypto.h" #include "openssl/x509.h" #include "openssl/pem.h" #include "openssl/ssl.h" #include "openssl/err.h" /*所有需要的参数信息都在此处以#define的形式提供*/ #define CERTF "server.crt" /*服务端的证书(需经CA签名)*/ #define KEYF "server.key" /*服务端的私钥(建议加密存储)*/ #define CACERT "root.crt" /*CA 的证书*/ #define PORT 1111 /*准备绑定的端口*/ #define CHK_NULL(x) if ((x)==NULL) exit (1) #define CHK_ERR(err,s) if ((err)==-1) { perror(s); exit(1); } #define CHK_SSL(err) if ((err)==-1) { ERR_print_errors_fp(stderr); exit(2); } int main () { int err; int listen_sd; int sd; struct sockaddr_in sa_serv; struct sockaddr_in sa_cli; socklen_t client_len; SSL_CTX* ctx; SSL* ssl; X509* client_cert; char* str; char buf [4096]; const SSL_METHOD *meth; /* WSADATA wsaData; if(WSAStartup(MAKEWORD(2,2),&wsaData) != 0){ printf("WSAStartup()fail:%d/n",GetLastError()); return -1; } */ SSL_load_error_strings(); /*为打印调试信息作准备*/ OpenSSL_add_ssl_algorithms(); /*初始化*/ meth = TLSv1_server_method(); /*采用什么协议(SSLv2/SSLv3/TLSv1)在此指定*/ ctx = SSL_CTX_new (meth); CHK_NULL(ctx); SSL_CTX_set_verify(ctx,SSL_VERIFY_NONE,NULL); /*验证与否,服务器不验证客户端*/ //SSL_CTX_load_verify_locations(ctx,CACERT,NULL); /*若验证,则放置CA证书*/ if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0) { ERR_print_errors_fp(stderr); exit(3); } if (SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0) { ERR_print_errors_fp(stderr); exit(4); } if (!SSL_CTX_check_private_key(ctx)) { printf("Private key does not match the certificate public key\n"); exit(5); } SSL_CTX_set_cipher_list(ctx,"RC4-MD5"); /*开始正常的TCP socket过程.................................*/ printf("Begin TCP socket...\n"); listen_sd = socket (AF_INET, SOCK_STREAM, 0); CHK_ERR(listen_sd, "socket"); memset (&sa_serv, 0, sizeof(sa_serv)); sa_serv.sin_family = AF_INET; sa_serv.sin_addr.s_addr = INADDR_ANY; sa_serv.sin_port = htons (PORT); err = bind(listen_sd, (struct sockaddr*) &sa_serv, sizeof (sa_serv)); CHK_ERR(err, "bind"); /*接受TCP链接*/ err = listen (listen_sd, 5); CHK_ERR(err, "listen"); client_len = sizeof(sa_cli); sd = accept (listen_sd, (sockaddr*) &sa_cli, &client_len); CHK_ERR(sd, "accept"); close (listen_sd); printf ("Connection from %lx, port %x\n", sa_cli.sin_addr.s_addr, sa_cli.sin_port); /*TCP连接已建立,进行服务端的SSL过程. */ printf("Begin server side SSL\n"); ssl = SSL_new (ctx); CHK_NULL(ssl); SSL_set_fd (ssl, sd); err = SSL_accept (ssl); printf("SSL_accept finished\n"); CHK_SSL(err); /*打印所有加密算法的信息(可选)*/ printf ("SSL connection using %s\n", SSL_get_cipher (ssl)); /*得到服务端的证书并打印些信息(可选) */ client_cert = SSL_get_peer_certificate (ssl); if (client_cert != NULL) { printf ("Client certificate:\n"); str = X509_NAME_oneline (X509_get_subject_name (client_cert), 0, 0); CHK_NULL(str); printf ("/t subject: %s\n", str); free (str); str = X509_NAME_oneline (X509_get_issuer_name (client_cert), 0, 0); CHK_NULL(str); printf ("/t issuer: %s\n", str); free (str); X509_free (client_cert);/*如不再需要,需将证书释放 */ } else printf ("Client does not have certificate.\n"); /* 数据交换开始,用SSL_write,SSL_read代替write,read */ err = SSL_read (ssl, buf, sizeof(buf) - 1); CHK_SSL(err); buf[err] = 0; printf ("Got %d chars:'%s'\n", err, buf); err = SSL_write (ssl, "I hear you.", strlen("I hear you.")); CHK_SSL(err); /* 收尾工作*/ shutdown (sd,2); SSL_free (ssl); SSL_CTX_free (ctx); return 0; }
客户端代码
#include <stdio.h> #include <stdlib.h> #include <memory.h> #include <errno.h> #include <sys/types.h> #include <unistd.h> #include <sys/socket.h> #include <arpa/inet.h> #include "openssl/rsa.h" #include "openssl/crypto.h" #include "openssl/x509.h" #include "openssl/pem.h" #include "openssl/ssl.h" #include "openssl/err.h" #include "openssl/rand.h" /*所有需要的参数信息都在此处以#define的形式提供*/ #define CERTF "client.crt" /*客户端的证书(需经CA签名)*/ #define KEYF "client.key" /*客户端的私钥(建议加密存储)*/ #define CACERT "root.crt" /*CA 的证书*/ #define PORT 1111 /*服务端的端口*/ #define SERVER_ADDR "10.18.12.171" //"127.0.0.1" /*服务段的IP地址*/ #define CHK_NULL(x) if ((x)==NULL) exit (-1) #define CHK_ERR(err,s) if ((err)==-1) { perror(s); exit(-2); } #define CHK_SSL(err) if ((err)==-1) { ERR_print_errors_fp(stderr); exit(-3); } int main () { int err; int sd; struct sockaddr_in sa; SSL_CTX* ctx; SSL* ssl; X509* server_cert; char* str; char buf [4096]; const SSL_METHOD* meth; int seed_int[100]; /*存放随机序列*/ /* WSADATA wsaData; if(WSAStartup(MAKEWORD(2,2),&wsaData) != 0) { printf("WSAStartup()fail:%d\n",GetLastError()); return -1; } */ /*初始化*/ OpenSSL_add_ssl_algorithms(); /*为打印调试信息作准备*/ SSL_load_error_strings(); /*采用什么协议(SSLv2/SSLv3/TLSv1)在此指定*/ meth = TLSv1_client_method(); /*申请SSL会话环境*/ ctx = SSL_CTX_new (meth); CHK_NULL(ctx); /*验证与否,是否要验证对方,客户端要验证服务器*/ SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL); /*若验证对方,则放置CA证书*/ SSL_CTX_load_verify_locations(ctx,CACERT,NULL); /* 服务器不验证自己 //加载自己的证书 if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0) { ERR_print_errors_fp(stderr); exit(-2); } //加载自己的私钥,以用于签名 if (SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0) { ERR_print_errors_fp(stderr); exit(-3); } //调用了以上两个函数后,检验一下自己的证书与私钥是否配对 if (!SSL_CTX_check_private_key(ctx)) { printf("Private key does not match the certificate public key\n"); exit(-4); } */ /*构建随机数生成机制,WIN32平台必需*/ /* srand( (unsigned)time( NULL ) ); for( int i = 0; i < 100;i++ ) seed_int = rand(); RAND_seed(seed_int, sizeof(seed_int)); */ /*以下是正常的TCP socket建立过程 .............................. */ printf("Begin tcp socket...\n"); sd = socket (AF_INET, SOCK_STREAM, 0); CHK_ERR(sd, "socket"); memset (&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_addr.s_addr = inet_addr (SERVER_ADDR); /* Server IP */ sa.sin_port = htons (PORT); /* Server Port number */ err = connect(sd, (struct sockaddr*) &sa, sizeof(sa)); CHK_ERR(err, "connect"); /* TCP 链接已建立.开始 SSL 握手过程.......................... */ printf("Begin SSL negotiation \n"); /*申请一个SSL套接字*/ ssl = SSL_new (ctx); CHK_NULL(ssl); /*绑定读写套接字*/ SSL_set_fd (ssl, sd); err = SSL_connect (ssl); CHK_SSL(err); /*打印所有加密算法的信息(可选)*/ printf ("SSL connection using %s\n", SSL_get_cipher (ssl)); /*得到服务端的证书并打印些信息(可选) */ server_cert = SSL_get_peer_certificate (ssl); CHK_NULL(server_cert); printf ("Server certificate:\n"); str = X509_NAME_oneline (X509_get_subject_name (server_cert),0,0); CHK_NULL(str); printf ("/t subject: %s\n", str); free (str); str = X509_NAME_oneline (X509_get_issuer_name (server_cert),0,0); CHK_NULL(str); printf ("/t issuer: %s\n", str); free (str); X509_free (server_cert); /*如不再需要,需将证书释放 */ /* 数据交换开始,用SSL_write,SSL_read代替write,read */ printf("Begin SSL data exchange\n"); err = SSL_write (ssl, "Hello World!", strlen("Hello World!")); CHK_SSL(err); err = SSL_read (ssl, buf, sizeof(buf) - 1); CHK_SSL(err); buf[err] = 0; printf ("Got %d chars:'%s'\n", err, buf); SSL_shutdown (ssl); /* send SSL/TLS close_notify */ /* 收尾工作 */ shutdown (sd,2); SSL_free (ssl); SSL_CTX_free (ctx); return 0; }
一些测试
#include <openssl/evp.h> #include <openssl/bio.h> #include <openssl/buffer.h> #include <string.h> #include <iostream> using namespace std; char * base64Encode(const char *buffer, int length, bool newLine); char * base64Decode(char *input, int length, bool newLine); int main(int argc, char* argv[]) { bool newLine = false; const char * input = "Hello World!"; char * encode = base64Encode(input, strlen(input), newLine); char * decode = base64Decode(encode, strlen(encode), newLine); cout << "Base64 Encoded : " << encode << endl; cout << "Base64 Decoded : " << decode << endl; cin.get(); } // base64 编码 char * base64Encode(const char *buffer, int length, bool newLine) { BIO *bmem = NULL; BIO *b64 = NULL; BUF_MEM *bptr; b64 = BIO_new(BIO_f_base64()); if (!newLine) { BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); } bmem = BIO_new(BIO_s_mem()); b64 = BIO_push(b64, bmem); BIO_write(b64, buffer, length); BIO_flush(b64); BIO_get_mem_ptr(b64, &bptr); BIO_set_close(b64, BIO_NOCLOSE); char *buff = (char *)malloc(bptr->length + 1); memcpy(buff, bptr->data, bptr->length); buff[bptr->length] = 0; BIO_free_all(b64); return buff; } // base64 解码 char * base64Decode(char *input, int length, bool newLine) { BIO *b64 = NULL; BIO *bmem = NULL; char *buffer = (char *)malloc(length); memset(buffer, 0, length); b64 = BIO_new(BIO_f_base64()); if (!newLine) { BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); } bmem = BIO_new_mem_buf(input, length); bmem = BIO_push(b64, bmem); BIO_read(bmem, buffer, length); BIO_free_all(bmem); return buffer; }
#include <iostream> #include <string> #include <vector> #include <cstdio> #include <iomanip> #include <stdlib.h> #include <openssl/md5.h> #include <string.h> using namespace std; string MD5_Digest(const string cleartext) { string strDigest; unsigned char tmp[16] = {0}; #if 0 MD5((const unsigned char*)cleartext.c_str(), cleartext.length(), tmp); #else MD5_CTX c; MD5_Init(&c); MD5_Update(&c, cleartext.c_str(), cleartext.length()); MD5_Final(tmp, &c); #endif char* tmp1 = new char[32 + 1]; memset(tmp1, 0, 32 + 1); for(int i = 0; i < 16; i++) sprintf(&(tmp1[i*2]), "%02x", tmp[i]); //cout<<hex<<setw(2)<<setfill('0')<<(int)tmp[i]; strDigest = (char*)tmp1; delete [] tmp1; return strDigest; } int main() { string str = MD5_Digest("hello world"); cout<<str<<endl; }
#include <stdio.h> #include <string.h> #include <openssl/rc4.h> void dumprawmsg(char *p, int len) { int i = 0; for (i = 0; i < len; i++) { if (i % 16 == 0) { printf("\n"); } unsigned char c = p[i]; printf("%.2X ", c); } printf("\n\n"); } static unsigned char g_rc4key[16] = { 0x2c, 0xb6, 0xa1, 0xe7, 0xe1, 0x0c, 0x50, 0x02, 0xa5, 0xde, 0xae, 0x7f, 0xe6, 0x05, 0xbd, 0x90, }; int main() { unsigned char buffer[10]; unsigned char buffer1[10]; RC4_KEY m_rc4SendKey, decryKey; unsigned char str[10] = "123456789"; int len = 10; memset(buffer, 0, 10); memset(buffer1, 0, 10); RC4_set_key(&m_rc4SendKey, sizeof(g_rc4key), g_rc4key); RC4_set_key(&decryKey, sizeof(g_rc4key), g_rc4key); printf("org: %s\n", str); RC4(&m_rc4SendKey, len, str, buffer); dumprawmsg((char*)buffer, len); RC4(&decryKey, len, buffer, buffer1); printf("no_cry: %s\n", buffer1); return 0; }
#include <sstream> #include <string> #include <iomanip> #include <iostream> using namespace std; #include <openssl/sha.h> string sha256(const string str) { unsigned char hash[SHA256_DIGEST_LENGTH]; /* // SHA1 SHA_CTX sha; SHA_Init(&sha); SHA_Update(&sha, str.c_str(), str.size()); SHA_Final(hash, &sha); stringstream ss; for(int i = 0; i < 20; i++) */ SHA256_CTX sha256; SHA256_Init(&sha256); SHA256_Update(&sha256, str.c_str(), str.size()); SHA256_Final(hash, &sha256); stringstream ss; for(int i = 0; i < SHA256_DIGEST_LENGTH; i++) { ss << hex << setw(2) << setfill('0') << (int)hash[i]; } return ss.str(); } int main() { cout << sha256("test") << endl; cout << sha256("test2") << endl; return 0; }