openssl生成密钥/证书
一、公钥/私钥/签名/验证签名/加密/解密/非对称加密
对称加密:用同一个密码 加密/解密 文件。
非对称加密:加密用的一个密码,解密用另外一组密码。
加密解密:公钥加密数据,然后私钥解密。
公钥加密的数据只有它相对应的私钥可以解开,所以数据只有到了有私钥的你这里,才可以解开成有用的数据。
签名和验证签名:私钥加密数据,公钥解密。
用私钥对数据进行签名,那这个数据就只有配对的公钥可以解开,有这个私钥的只有你,配对的公钥解开了数据,就说明这数据是你发的,这个被称为签名。
二、加密的算法: RSA/DSA/SHA/MD5
RSA可以用于加/解密,也可以用于签名验签。
DSA则只能用于签名。
SHA和MD5:摘要算法
摘要算法:SHA和MD5:.就是通过一种算法,依据数据内容生成一种固定长度的摘要,这串摘要值与原数据存在对应关系。
实际应用过程中,因为需要加密的数据可能会很大,进行加密费时费力,所以一般都会把原数据先进行摘要,然后对这个摘要值进行加密,将原数据的明文和加密后的摘要值一起传给你.这样你解开加密后的摘要值,再和你得到的数据进行的摘要值对应一下就可以知道数据有没有被修改了。
实际应用中,一般都是和对方交换公钥,然后你要发给对方的数据,用他的公钥加密,他得到后用他的私钥解密,他要发给你的数据,用你的公钥加密,你得到后用你的私钥解密,这样最大程度保证了安全性.
三、公钥: CA/PEM/DER/X509/PKCS
四、生成证书
1、创建私钥:openssl genrsa -out ca/ca-key.pem 1024
2、创建证书请求:openssl req -new -out ca-req.csr -key ca-key.pem
3、自签署证书:openssl x509 -req -in ca-req.csr -out ca-cert.pem -signkey ca-key.pem -days 3650
4、将证书导出成浏览器支持的.p12格式 :openssl pkcs12 -export -clcerts -in ca-cert.pem -inkey ca-key.pem -out ca.p12
1 // 服务端代码 2 int Test_openssl_server_v2() 3 { 4 OM_NetworkInit(); 5 6 SSL_CTX *ctx; 7 SSL *ssl; 8 X509 *client_cert; 9 10 char szBuffer[1024]; 11 int nLen; 12 13 struct sockaddr_in addr; 14 int len; 15 int nListenFd, nAcceptFd; 16 17 // 初始化 18 SSLeay_add_ssl_algorithms(); 19 OpenSSL_add_all_algorithms(); 20 SSL_load_error_strings(); 21 ERR_load_BIO_strings(); 22 23 // 我们使用SSL V3,V2 24 EXIT_IF_TRUE((ctx = SSL_CTX_new(SSLv23_method())) == NULL); 25 26 // 要求校验对方证书 27 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); 28 29 // 加载CA的证书 30 EXIT_IF_TRUE(!SSL_CTX_load_verify_locations(ctx, "cacert.cer", NULL)); 31 32 // 加载自己的证书 33 EXIT_IF_TRUE(SSL_CTX_use_certificate_file(ctx, "server.cer", SSL_FILETYPE_PEM) <= 0); 34 35 // 加载自己的私钥 36 EXIT_IF_TRUE(SSL_CTX_use_PrivateKey_file(ctx, "server.key", SSL_FILETYPE_PEM) <= 0); 37 38 // 判定私钥是否正确 39 EXIT_IF_TRUE(!SSL_CTX_check_private_key(ctx)); 40 41 // 创建并等待连接 42 nListenFd = socket(PF_INET, SOCK_STREAM, 0); 43 struct sockaddr_in my_addr; 44 memset(&my_addr, 0, sizeof(my_addr)); 45 my_addr.sin_family = PF_INET; 46 my_addr.sin_port = htons(8812); 47 my_addr.sin_addr.s_addr = inet_addr("127.0.0.1");// INADDR_ANY; 48 if (bind(nListenFd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) { 49 int a = 2; 50 int b = a; 51 } 52 53 // 54 listen(nListenFd, 10); 55 56 memset(&addr, 0, sizeof(addr)); 57 len = sizeof(addr); 58 nAcceptFd = accept(nListenFd, (struct sockaddr *)&addr, (int *)&len); 59 CPosaLog::Printf(CPosaLog::L_DEBUG, "Accept a connect from [%s:%d]\n", 60 inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); 61 62 // 将连接付给SSL 63 EXIT_IF_TRUE((ssl = SSL_new(ctx)) == NULL); 64 SSL_set_fd(ssl, nAcceptFd); 65 int n1 = SSL_accept(ssl); 66 if (n1 == -1) { 67 const char* p1 = SSL_state_string_long(ssl); 68 int a = 2; 69 int b = a; 70 } 71 // 进行操作 72 memset(szBuffer, 0, sizeof(szBuffer)); 73 nLen = SSL_read(ssl, szBuffer, sizeof(szBuffer)); 74 CPosaLog::Printf(CPosaLog::L_DEBUG, "Get Len %d %s ok\n", nLen, szBuffer); 75 76 strcat(szBuffer, " this is from server"); 77 SSL_write(ssl, szBuffer, strlen(szBuffer)); 78 79 // 释放资源 80 SSL_free(ssl); 81 SSL_CTX_free(ctx); 82 closesocket(nAcceptFd); 83 84 return 0; 85 }
五、server证书
1、生成server证书:openssl genrsa -out server-key.pem 1024
2、创建证书请求:openssl req -new -out server-req.csr -key server-key.pem
3、自签署证书:openssl x509 -req -in server-req.csr -out server-cert.pem -signkey server-key.pem -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -days 3650
4、将证书导出成浏览器支持的.p12格式:openssl pkcs12 -export -clcerts -in server-cert.pem -inkey server-key.pem -out server.p12
5、完成
六、Client证书
生成server证书:openssl genrsa -out client-key.pem 1024
创建证书请求:openssl req -new -out client-req.csr -key client-key.pem
自签署证书:openssl x509 -req -in client-req.csr -out client-cert.pem -signkey client-key.pem -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -days 3650
将证书导出成浏览器支持的.p12格式:openssl pkcs12 -export -clcerts -in client-cert.pem -inkey client-key.pem -out client.p12
七、即:使用相同的ca生成两个证书,一个是server.cer,一个是client.cer,注意生成server.cer的时候必须指明证书可以用于服务端的。
八、代码:
// 服务端代码 int Test_openssl_server_v2() { OM_NetworkInit(); SSL_CTX *ctx; SSL *ssl; X509 *client_cert; char szBuffer[1024]; int nLen; struct sockaddr_in addr; int len; int nListenFd, nAcceptFd; // 初始化 SSLeay_add_ssl_algorithms(); OpenSSL_add_all_algorithms(); SSL_load_error_strings(); ERR_load_BIO_strings(); // 我们使用SSL V3,V2 EXIT_IF_TRUE((ctx = SSL_CTX_new(SSLv23_method())) == NULL); // 要求校验对方证书 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); // 加载CA的证书 EXIT_IF_TRUE(!SSL_CTX_load_verify_locations(ctx, "cacert.cer", NULL)); // 加载自己的证书 EXIT_IF_TRUE(SSL_CTX_use_certificate_file(ctx, "server.cer", SSL_FILETYPE_PEM) <= 0); // 加载自己的私钥 EXIT_IF_TRUE(SSL_CTX_use_PrivateKey_file(ctx, "server.key", SSL_FILETYPE_PEM) <= 0); // 判定私钥是否正确 EXIT_IF_TRUE(!SSL_CTX_check_private_key(ctx)); // 创建并等待连接 nListenFd = socket(PF_INET, SOCK_STREAM, 0); struct sockaddr_in my_addr; memset(&my_addr, 0, sizeof(my_addr)); my_addr.sin_family = PF_INET; my_addr.sin_port = htons(8812); my_addr.sin_addr.s_addr = inet_addr("127.0.0.1");// INADDR_ANY; if (bind(nListenFd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) { int a = 2; int b = a; } // listen(nListenFd, 10); memset(&addr, 0, sizeof(addr)); len = sizeof(addr); nAcceptFd = accept(nListenFd, (struct sockaddr *)&addr, (int *)&len); CPosaLog::Printf(CPosaLog::L_DEBUG, "Accept a connect from [%s:%d]\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); // 将连接付给SSL EXIT_IF_TRUE((ssl = SSL_new(ctx)) == NULL); SSL_set_fd(ssl, nAcceptFd); int n1 = SSL_accept(ssl); if (n1 == -1) { const char* p1 = SSL_state_string_long(ssl); int a = 2; int b = a; } // 进行操作 memset(szBuffer, 0, sizeof(szBuffer)); nLen = SSL_read(ssl, szBuffer, sizeof(szBuffer)); CPosaLog::Printf(CPosaLog::L_DEBUG, "Get Len %d %s ok\n", nLen, szBuffer); strcat(szBuffer, " this is from server"); SSL_write(ssl, szBuffer, strlen(szBuffer)); // 释放资源 SSL_free(ssl); SSL_CTX_free(ctx); closesocket(nAcceptFd); return 0; }
1 // 客户端代码 2 int Test_openssl_client_v2() 3 { 4 OM_NetworkInit(); 5 6 SSL_METHOD *meth; 7 SSL_CTX *ctx; 8 SSL *ssl; 9 10 int nFd; 11 int nLen; 12 char szBuffer[1024]; 13 14 // 初始化 15 SSLeay_add_ssl_algorithms(); 16 OpenSSL_add_all_algorithms(); 17 SSL_load_error_strings(); 18 ERR_load_BIO_strings(); 19 20 // 我们使用SSL V3,V2 21 EXIT_IF_TRUE((ctx = SSL_CTX_new(SSLv23_method())) == NULL); 22 23 // 要求校验对方证书 24 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); 25 26 // 加载CA的证书 27 EXIT_IF_TRUE(!SSL_CTX_load_verify_locations(ctx, "cacert.cer", NULL)); 28 29 // 加载自己的证书 30 EXIT_IF_TRUE(SSL_CTX_use_certificate_file(ctx, "client.cer", SSL_FILETYPE_PEM) <= 0); 31 32 // 加载自己的私钥 33 EXIT_IF_TRUE(SSL_CTX_use_PrivateKey_file(ctx, "client.key", SSL_FILETYPE_PEM) <= 0); 34 35 // 判定私钥是否正确 36 EXIT_IF_TRUE(!SSL_CTX_check_private_key(ctx)); 37 38 // new 39 // 创建连接 40 nFd = socket(PF_INET, SOCK_STREAM, 0); 41 struct sockaddr_in dest; 42 memset(&dest, 0, sizeof(dest)); 43 dest.sin_family = AF_INET; 44 dest.sin_port = htons(8812); 45 dest.sin_addr.s_addr = inet_addr("127.0.0.1"); 46 if (connect(nFd, (struct sockaddr *) &dest, sizeof(dest)) != 0) { 47 perror("Connect "); 48 exit(errno); 49 } 50 51 // 将连接付给SSL 52 EXIT_IF_TRUE((ssl = SSL_new(ctx)) == NULL); 53 SSL_set_fd(ssl, nFd); 54 int n1 = SSL_connect(ssl); 55 if (n1 == -1) { 56 int n2 = SSL_get_error(ssl, n1); 57 58 const char* p1 = SSL_state_string(ssl); 59 } 60 61 // 进行操作 62 sprintf(szBuffer, "this is from client %d", getpid()); 63 int nWriten = SSL_write(ssl, szBuffer, strlen(szBuffer)); 64 65 // 释放资源 66 memset(szBuffer, 0, sizeof(szBuffer)); 67 nLen = SSL_read(ssl, szBuffer, sizeof(szBuffer)); 68 CPosaLog::Printf(CPosaLog::L_DEBUG, "Get Len %d %s ok\n", nLen, szBuffer); 69 70 SSL_free(ssl); 71 SSL_CTX_free(ctx); 72 closesocket(nFd); 73 74 return 0; 75 }