筆記整理——使用openssl編程

error: openssl 的全部解決方案 (2013/6/22 17:39:00)

error: openssl/crypto.h: No such file or directory 解決方案 (2013/6/22 17:39:00)

error: openssl/crypto.h: No such file or directory
 

error: openssl/md5.h: No such file or directory 解決方案

libssl-dev 沒有安裝,只要javascript

sudo apt-get install libssl-dev 就能夠了php

 

libssl-dev 沒有安裝,只要html

sudo apt-get install libssl-dev 就能夠了java


undefined reference to `MD5'_fengzi_lu的空間_百度空間 - Google Chrome (2013/8/8 15:23:26)

undefined reference to `MD5'

這是由於包含md5函數的庫爲/usr/lib/libcrypto.a(.so),因此編譯時使用   -lcrypto  就OK了。

基於X.509證書和SSL協議的身份認證過程實現 - 菜鳥浮出水 - 51CTO技術博客 - Google Chrome (2013/6/7 17:14:52)

客戶端程序代碼:linux

 
 
 
 
  1. //client  
  2. #include <winsock2.h>  
  3. #include <conio.h>  
  4. #include <stdio.h>  
  5. #include "openssl/x509.h"  
  6. #include "openssl/ssl.h"  
  7. #include "openssl/err.h"  
  8. #include "openssl/rand.h" 
  9.  
  10. #define PORT       1111  
  11. #define SERVER     "127.0.0.1"  
  12. #define CACERT     "ca.crt"  
  13. #define MYCERTF    "yuliding.crt"  
  14. #define MYKEYF     "yuliding.key"  
  15. #define MSGLENGTH  1024 
  16.  
  17. int main()  
  18. {  
  19.     WSADATA wsadata;  
  20.     WSAStartup(MAKEWORD(2,2), &wsadata);  
  21.     sockaddr_in sin;  
  22.     int seed_int[100]; /*存放隨機序列*/ 
  23.  
  24.     SSL*ssl;  
  25.     SSL_METHOD *meth;  
  26.     SSL_CTX *ctx; 
  27.  
  28.     //SSL初始化  
  29.     OpenSSL_add_ssl_algorithms();  
  30.     //SSL錯誤信息初始化  
  31.     SSL_load_error_strings(); 
  32.  
  33.     //建立本次會話所使用的協議  
  34.     meth = TLSv1_client_method();  
  35.     //申請SSL會話的環境  
  36.     ctx = SSL_CTX_new(meth);  
  37.     if (NULL == ctx)  
  38.         exit(1); 
  39.  
  40.     //設置會話的握手方式並加載CA證書  
  41.     SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);  
  42.     SSL_CTX_load_verify_locations(ctx, CACERT, NULL);  
  43.     //加載本身的證書  
  44.     if (0 &gt;= SSL_CTX_use_certificate_file(ctx, MYCERTF, SSL_FILETYPE_PEM)) {  
  45.         ERR_print_errors_fp(stderr);  
  46.         exit(1);  
  47.     }  
  48.     //加載本身的私鑰  
  49.     if (0 &gt;= SSL_CTX_use_PrivateKey_file(ctx, MYKEYF, SSL_FILETYPE_PEM)) {  
  50.         ERR_print_errors_fp(stderr);  
  51.         exit(1);  
  52.     }  
  53.     //檢查本身的證書和私鑰是否匹配  
  54.     if (!SSL_CTX_check_private_key(ctx)) {  
  55.         printf("Private key does not match the certificate public key\n");  
  56.         exit(1);  
  57.     }  
  58.     /*構建隨機數生成機制,WIN32平臺必需*/  
  59.     srand((unsigned)time(NULL));  
  60.     for (int i = 0; i < 100; i++)  
  61.         seed_int[i] = rand();  
  62.     RAND_seed(seed_int, sizeof(seed_int)); 
  63.  
  64.     //加密方式  
  65.     SSL_CTX_set_cipher_list(ctx, "RC4-MD5");  
  66.     //處理握手屢次  
  67.     SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); 
  68.  
  69.     /*如下是正常的TCP socket創建過程 .............................. */  
  70.     SOCKET sock;  
  71.     printf("Begin tcp socket...\n");  
  72.     sock = socket(AF_INET, SOCK_STREAM, 0);  
  73.     if (sock == INVALID_SOCKET) {  
  74.         printf("SOCKET有問題. \n");  
  75.     } 
  76.  
  77.     memset(&sin, '\0'sizeof(sin));  
  78.     sin.sin_family = AF_INET;  
  79.     sin.sin_addr.s_addr = inet_addr(SERVER); /* Server IP */  
  80.     sin.sin_port = htons(PORT); /* Server Port number */ 
  81.  
  82.     int icnn = connect(sock, (sockaddr *)&sin, sizeof(sin));  
  83.     if (icnn == SOCKET_ERROR) {  
  84.         printf("連不上服務器\n", GetLastError());  
  85.         exit(1);  
  86.     } 
  87.  
  88.     /* TCP 連接已創建.開始 SSL 握手過程.......................... */  
  89.     //綁定套接字  
  90.     ssl = SSL_new(ctx);  
  91.     if (NULL == ssl)  
  92.         exit(1);  
  93.     if (0 >= SSL_set_fd(ssl, sock)) {  
  94.         printf("Attach to Line fail!\n");  
  95.         exit(1);  
  96.     }  
  97.     //SSL握手  
  98.     //SSL_connect(ssl);  
  99.     int k = SSL_connect(ssl);  
  100.     if (0 &gt;= k) {  
  101.         printf("%d\n", k);  
  102.         printf("SSL connect fail!\n");  
  103.         exit(1);  
  104.     }  
  105.     printf("鏈接服務器成功\n"); 
  106.  
  107.     char sendmsg[MSGLENGTH] = "\0";  
  108.     char revmsg[MSGLENGTH] = "\0"
  109.  
  110.     int err = SSL_read(ssl, revmsg, sizeof(revmsg));  
  111.     revmsg[err] = '\0';  
  112.     printf("%s\n", revmsg); 
  113.  
  114.     while (1) {  
  115.         printf("請輸入所要發送的數據:\n");  
  116.         scanf("%s", sendmsg);  
  117.         SSL_write(ssl, sendmsg, strlen(sendmsg));  
  118.         printf("發送消息「 %s 」成功!\n", sendmsg);  
  119.     } 
  120.  
  121.     //關閉套接字  
  122.     SSL_shutdown(ssl);  
  123.     SSL_free(ssl);  
  124.     SSL_CTX_free(ctx);  
  125.     closesocket(sock);  
  126.     WSACleanup();  
  127.     getch();  
  128.     return 0;  

服務端程序代碼:web

 
 
 
 
  1. //server  
  2. #include <winsock2.h>  
  3. #include <conio.h>  
  4. #include <stdio.h>  
  5. #include <winsock.h>  
  6. #include "openssl/x509.h"  
  7. #include "openssl/ssl.h"  
  8. #include "openssl/err.h" 
  9.  
  10. #define MSGLENGTH      1024  
  11. #define PORT           1111  
  12. #define CACERT         "ca.crt"  
  13. #define SVRCERTF       "server.crt"  
  14. #define SVRKEYF        "server.key" 
  15.  
  16. int main()  
  17. {  
  18.     WSADATA wsaData;  
  19.     WSAStartup(MAKEWORD(2,2), &wsaData);  
  20.     SOCKET sock;  
  21.     SSL_METHOD *meth;  
  22.     SSL_CTX* ctx;  
  23.     SSL* ssl;  
  24.     //SSL初始化  
  25.     OpenSSL_add_ssl_algorithms();  
  26.     //SSL錯誤信息初始化  
  27.     SSL_load_error_strings(); 
  28.  
  29.     //建立本次會話所使用的協議  
  30.     meth = TLSv1_server_method();  
  31.     //申請SSL會話的環境  
  32.     ctx = SSL_CTX_new(meth);  
  33.     if (NULL == ctx)  
  34.         exit(1); 
  35.  
  36.     //設置會話的握手方式並加載CA證書  
  37.     SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);  
  38.     SSL_CTX_load_verify_locations(ctx, CACERT, NULL);  
  39.     //加載服務器端的證書  
  40.     if (0 &gt;= SSL_CTX_use_certificate_file(ctx, SVRCERTF, SSL_FILETYPE_PEM)) {  
  41.         ERR_print_errors_fp(stderr);  
  42.         exit(1);  
  43.     }  
  44.     //加載服務器端的私鑰  
  45.     if (0 &gt;= SSL_CTX_use_PrivateKey_file(ctx, SVRKEYF, SSL_FILETYPE_PEM)) {  
  46.         ERR_print_errors_fp(stderr);  
  47.         exit(1);  
  48.     }  
  49.     //檢查服務器端的證書和私鑰是否匹配  
  50.     if (!SSL_CTX_check_private_key(ctx)) {  
  51.         printf("Private key does not match the certificate public key\n");  
  52.         exit(1);  
  53.     } 
  54.  
  55.     //加密方式  
  56.     SSL_CTX_set_cipher_list(ctx, "RC4-MD5");  
  57.     //處理握手屢次  
  58.     SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); 
  59.  
  60.     /*如下是正常的TCP socket創建過程 .............................. */  
  61.     printf("Begin tcp socket...\n");  
  62.     sock = socket(AF_INET, SOCK_STREAM, 0);  
  63.     if (sock == INVALID_SOCKET) {  
  64.         printf("SOCKET有問題. \n");  
  65.         return 0;  
  66.     } 
  67.  
  68.     sockaddr_in addr;  
  69.     memset(&addr, '\0'sizeof(addr));  
  70.     addr.sin_family = AF_INET;  
  71.     addr.sin_port = htons(PORT); /* Server Port number */  
  72.     addr.sin_addr.s_addr = INADDR_ANY; 
  73.  
  74.     //綁定sock  
  75.     int nResult = bind(sock, (sockaddr *)&addr, sizeof(addr));  
  76.     if (nResult == SOCKET_ERROR) {  
  77.         printf("綁定SOCKET有問題. \n");  
  78.         return 0;  
  79.     }  
  80.     printf("服務器啓動成功,端口:%d\n正在等待鏈接\n", PORT); 
  81.  
  82.     /*接受TCP連接*/  
  83.     sockaddr_in sa_cli;  
  84.     int err = listen(sock, 5);  
  85.     if (-1 == err)  
  86.         exit(1);  
  87.     int client_len = sizeof(sa_cli);  
  88.     int ss = accept(sock, (struct sockaddr *) &sa_cli, &client_len);  
  89.     if (ss == -1) {  
  90.         exit(1);  
  91.     }  
  92.     closesocket(sock);  
  93.     printf("Connection from %d, port %d\n", sa_cli.sin_addr.s_addr, sa_cli.sin_port); 
  94.  
  95.     /* TCP 連接已創建.開始 SSL 握手過程.......................... */  
  96.     //綁定套接字  
  97.     ssl = SSL_new(ctx);  
  98.     if (NULL == ssl)  
  99.         exit(1);  
  100.     if (0 &gt;= SSL_set_fd(ssl, ss)) {  
  101.         printf("Attach to Line fail!\n");  
  102.         exit(1);  
  103.     }  
  104.     //SSL握手  
  105.     //SSL_accept(ssl);  
  106.     int k = SSL_accept(ssl);  
  107.     if (0 &gt;= k) {  
  108.         printf("%d\n", k);  
  109.         printf("SSL connect fail!\n");  
  110.         exit(1);  
  111.     }  
  112.     //進行信息驗證  
  113.     X509 *client_cert;  
  114.     client_cert = SSL_get_peer_certificate(ssl); 
  115.  
  116.     printf("發現客戶端嘗試鏈接\n");  
  117.     if (client_cert != NULL) {  
  118.         printf ("Client certificate:\n"); 
  119.  
  120.         //讀取證書subject名並顯示  
  121.         char *str = X509_NAME_oneline(X509_get_subject_name(client_cert), 0, 0);  
  122.         if (NULL == str) {  
  123.             printf("認證出錯!\n");  
  124.             exit(1);  
  125.         }  
  126.         printf("subject: %s\n", str);  
  127.         //讀取證書的issuer名並顯示  
  128.         str = X509_NAME_oneline(X509_get_issuer_name(client_cert), 0, 0);  
  129.         if (NULL == str) {  
  130.             printf("證書名爲空\n");  
  131.             exit(1);  
  132.         }  
  133.         printf("issuer: %s\n", str);  
  134.         printf("鏈接成功\n"); 
  135.  
  136.         X509_free (client_cert);/*如再也不須要,需將證書釋放 */  
  137.         OPENSSL_free(str);  
  138.     }  
  139.     else {  
  140.         printf("找不到客戶端的認證證書\n");  
  141.         exit(1);  
  142.     } 
  143.  
  144.     char buf[MSGLENGTH];  
  145.     SSL_write(ssl, "Server is connect to you!\n", strlen("Server is connect to you!\n"));  
  146.     printf("Listen to the client: \n");  
  147.     while (1) {  
  148.         err = SSL_read(ssl, buf, sizeof(buf));  
  149.         buf[err] = '\0';  
  150.         printf("%s\n", buf);  
  151.     } 
  152.  
  153.     //關閉套接字  
  154.     SSL_shutdown(ssl);  
  155.     SSL_free(ssl);  
  156.     SSL_CTX_free(ctx);  
  157.     WSACleanup();  
  158.     getch();  
  159.     return 0;  

用openssl編寫SSL,TLS程序 - bfcyyb - 51CTO技術博客 - Google Chrome (2013/5/31 11:29:25)

用openssl編寫SSL,TLS程序 - bfcyyb - 51CTO技術博客 - Google Chrome (2013/5/31 11:29:25)

用openssl編寫SSL,TLS程序
2006-05-24 11:15:41
標籤: openssl   SSL   TLS程序   休閒   職場
SSL(Secure Socket Layer)是netscape公司提出的主要用於web的安全通訊標準,分爲2.0版和3.0版.TLS(Transport Layer Security)是IETF的TLS 工做組在SSL3.0基礎之上提出的安全通訊標準,目前版本是1.0,即RFC2246.SSL/TLS提供的安全機制能夠保證應用層數據在互聯網絡傳輸不 被監聽,僞造和竄改.
一:簡介:

SSL(Secure Socket Layer)是netscape公司提出的主要用於web的安全通訊標準,分爲2.0版和3.0版.TLS(Transport Layer Security)是IETF的TLS 工做組在SSL3.0基礎之上提出的安全通訊標準,目前版本是1.0,即RFC2246.SSL/TLS提供的安全機制能夠保證應用層數據在互聯網絡傳輸不 被監聽,僞造和竄改.

openssl( www.openssl.org)是sslv2,sslv3,tlsv1的一份完整實現,內部包含了大量加密算法程序.其命令行提供了豐富的加密,驗證,證書生成等功 能,甚至能夠用其創建一個完整的CA.與其同時,它也提供了一套完整的庫函數,可用開發用SSL/TLS的通訊程序. Apache的https兩種版本 mod_ssl和apachessl均基於它實現的.openssl繼承於ssleay,並作了必定的擴展,當前的版本是0.9.5a.

openssl的缺點是文檔太少,連一份完整的函數說明都沒有,man page也至今沒作完整:-(,若是想用它編程序,除了熟悉已有的文檔(包括 ssleay,mod_ssl,apachessl的文檔)外,能夠到它的maillist上找相關的帖子,許多問題能夠在之前的文章中找到答案.

編程:
程序分爲兩部分,客戶端和服務器端,咱們的目的是利用SSL/TLS的特性保證通訊雙方可以互相驗證對方身份(真實性),並保證數據的完整性, 私密性.

1.客戶端程序的框架爲:

/*生成一個SSL結構*/
meth = SSLv23_client_method();
ctx = SSL_CTX_new (meth);  
ssl = SSL_new(ctx);

/*下面是正常的socket過程*/
fd = socket();
connect();

/*把創建好的socket和SSL結構聯繫起來*/
SSL_set_fd(ssl,fd);

/*SSL的握手過程*/
SSL_connect(ssl);

/*接下來用SSL_write(), SSL_read()代替原有的write(),read()便可*/
SSL_write(ssl,"Hello world",strlen("Hello World!"));

2.服務端程序的框架爲:

/*生成一個SSL結構*/
meth = SSLv23_server_method();
ctx = SSL_CTX_new (meth);  
ssl = SSL_new(ctx);

/*下面是正常的socket過程*/
fd = socket();
bind();
listen();
accept();

/*把創建好的socket和SSL結構聯繫起來*/
SSL_set_fd(ssl,fd);

/*SSL的握手過程*/
SSL_connect(ssl);

/*接下來用SSL_write(), SSL_read()代替原有的write(),read()便可*/
SSL_read (ssl, buf, sizeof(buf));

根據RFC2246(TLS1.0)整個TLS(SSL)的流程以下:

Client Server

ClientHello -------->
ServerHello
Certificate*
ServerKeyExchange*
CertificateRequest*
<-------- ServerHelloDone
Certificate*
ClientKeyExchange
CertificateVerify*
[ChangeCipherSpec]
Finished -------->
[ChangeCipherSpec]
<-------- Finished
Application Data <-------> Application Data

對程序來講,openssl將整個握手過程用一對函數體現,即客戶端的SSL_connect和服務端的SSL_accept.然後的應用層數據交換則用SSL_read和 SSL_write來完成.

二:證書文件生成

除將程序編譯成功外,還需生成必要的證書和私鑰文件使雙方可以成功驗證對方,步驟以下:

1.首先要生成服務器端的私鑰(key文件):
openssl genrsa -des3 -out server.key 1024
運行時會提示輸入密碼,此密碼用於加密key文件(參數des3即是指加密算法,固然也能夠選用其餘你認爲安全的算法.),之後每當需讀取此文 件(經過openssl提供的命令或API)都需輸入口令.若是以爲不方便,也能夠去除這個口令,但必定要採起其餘的保護措施!
去除key文件口令的命令:
openssl rsa -in server.key -out server.key

2.openssl req -new -key server.key -out server.csr
生成Certificate Signing Request(CSR),生成的csr文件交給CA簽名後造成服務端本身的證書.屏幕上將有提示,依照其指示一步一步輸入要 求的我的信息便可.

3.對客戶端也做一樣的命令生成key及csr文件:
openssl genrsa -des3 -out client.key 1024
openssl req -new -key client.key -out client.csr

4.CSR文件必須有CA的簽名纔可造成證書.可將此文件發送到verisign等地方由它驗證,要交一大筆錢,何不本身作CA呢.
首先生成CA的key文件:
openssl -des3 -out ca.key 1024
在生成CA自簽名的證書:
openssl req -new -x509 -key ca.key -out ca.crt
若是想讓此證書有個期限,如一年,則加上"-days 365".
("若是非要爲這個證書加上一個期限,我情願是..一萬年")

5.用生成的CA的證書爲剛纔生成的server.csr,client.csr文件簽名:
能夠用openssl中CA系列命令,但不是很好用(也不是多難,唉,一言難盡),一篇文章中推薦用mod_ssl中的sign.sh腳本,試了一下,確實方便了不 少,若是ca.csr存在的話,只需:
./sigh.sh server.csr
./sign.sh client.csr
相應的證書便生成了(後綴.crt).

如今咱們所需的所有文件便生成了.

其實openssl中還附帶了一個叫CA.pl的文件(在安裝目錄中的misc子目錄下),可用其生成以上的文件,使用也比較方便,但此處就不做介紹了.

三:須要瞭解的一些函數:

1.int SSL_CTX_set_cipher_list(SSL_CTX *,const char *str);
根據SSL/TLS規範,在ClientHello中,客戶端會提交一份本身可以支持的加密方法的列表,由服務端選擇一種方法後在ServerHello中通知服務端, 從而完成加密算法的協商.

可用的算法爲:
EDH-RSA-DES-CBC3-SHA
EDH-DSS-DES-CBC3-SHA
DES-CBC3-SHA
DHE-DSS-RC4-SHA
IDEA-CBC-SHA
RC4-SHA
RC4-MD5
EXP1024-DHE-DSS-RC4-SHA
EXP1024-RC4-SHA
EXP1024-DHE-DSS-DES-CBC-SHA
EXP1024-DES-CBC-SHA
EXP1024-RC2-CBC-MD5
EXP1024-RC4-MD5
EDH-RSA-DES-CBC-SHA
EDH-DSS-DES-CBC-SHA
DES-CBC-SHA
EXP-EDH-RSA-DES-CBC-SHA
EXP-EDH-DSS-DES-CBC-SHA
EXP-DES-CBC-SHA
EXP-RC2-CBC-MD5
EXP-RC4-MD5
這些算法按必定優先級排列,若是不做任何指定,將選用DES-CBC3-SHA.用SSL_CTX_set_cipher_list能夠指定本身但願用的算法(實際上只是 提升其優先級,是否能使用還要看對方是否支持).

咱們在程序中選用了RC4作加密,MD5作消息摘要(先進行MD5運算,後進行RC4加密).即
SSL_CTX_set_cipher_list(ctx,"RC4-MD5");

在消息傳輸過程當中採用對稱加密(比公鑰加密在速度上有極大的提升),其所用祕鑰(shared secret)在握手過程當中中協商(每次對話過程均不一樣, 在一次對話中都有可能有幾回改變),並經過公鑰加密的手段由客戶端提交服務端.

2.void SSL_CTX_set_verify(SSL_CTX *ctx,int mode,int (*callback)(int, X509_STORE_CTX *));
缺省mode是SSL_VERIFY_NONE,若是想要驗證對方的話,便要將此項變成SSL_VERIFY_PEER.SSL/TLS中缺省只驗證server,若是沒有設置 SSL_VERIFY_PEER的話,客戶端連證書都不會發過來.

3.int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,const char *CApath);
要驗證對方的話,固然裝要有CA的證書了,此函數用來即是加載CA的證書文件的.

4.int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type);
加載本身的證書文件.

5.int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type);
加載本身的私鑰,以用於簽名.

6.int SSL_CTX_check_private_key(SSL_CTX *ctx);
調用了以上兩個函數後,本身檢驗一下證書與私鑰是否配對.

7.void RAND_seed(const void *buf,int num);
在win32的環境中client程序運行時出錯(SSL_connect返回-1)的一個主要機制即是與UNIX平臺下的隨機數生成機制不一樣(握手的時候用的到). 具體描述可見mod_ssl的FAQ.解決辦法就是調用此函數,其中buf應該爲一隨機的字符串,做爲"seed".
還能夠採用一下兩個函數:
void RAND_screen(void);
int RAND_event(UINT, WPARAM, LPARAM);
其中RAND_screen()以屏幕內容做爲"seed"產生隨機數,RAND_event能夠捕獲windows中的事件(event),以此爲基礎產生隨機數.若是一直有 用戶干預的話,用這種辦法產生的隨機數可以"更加隨機",但若是機器一直沒人理(如總停在登陸畫面),則每次都將產生一樣的數字.

這幾個函數都只在WIN32環境下編譯時有用,各類UNIX下就沒必要調了.
大量其餘的相關函數原型,見cryptorandrand.h.

8.OpenSSL_add_ssl_algorithms()或SSLeay_add_ssl_algorithms()
其實都是調用int SSL_library_init(void)
進行一些必要的初始化工做,用openssl編寫SSL/TLS程序的話第一句便應是它.

9.void SSL_load_error_strings(void );
若是想打印出一些方便閱讀的調試信息的話,便要在一開始調用此函數.

10.void ERR_print_errors_fp(FILE *fp);
若是調用了SSL_load_error_strings()後,即可以隨時用ERR_print_errors_fp()來打印錯誤信息了.

11.X509 *SSL_get_peer_certificate(SSL *s);
握手完成後,即可以用此函數從SSL結構中提取出對方的證書(此時證書獲得且已經驗證過了)整理成X509結構.

12.X509_NAME *X509_get_subject_name(X509 *a);
獲得證書全部者的名字,參數可用經過SSL_get_peer_certificate()獲得的X509對象.

13.X509_NAME *X509_get_issuer_name(X509 *a)
獲得證書籤署者(每每是CA)的名字,參數可用經過SSL_get_peer_certificate()獲得的X509對象.

14.char *X509_NAME_oneline(X509_NAME *a,char *buf,int size);
將以上兩個函數獲得的對象變成字符型,以便打印出來.

15.SSL_METHOD的構造函數,包括
SSL_METHOD *TLSv1_server_method(void); /* TLSv1.0 */
SSL_METHOD *TLSv1_client_method(void); /* TLSv1.0 */

SSL_METHOD *SSLv2_server_method(void); /* SSLv2 */
SSL_METHOD *SSLv2_client_method(void); /* SSLv2 */

SSL_METHOD *SSLv3_server_method(void); /* SSLv3 */
SSL_METHOD *SSLv3_client_method(void); /* SSLv3 */

SSL_METHOD *SSLv23_server_method(void); /* SSLv3 but can rollback to v2 */
SSL_METHOD *SSLv23_client_method(void); /* SSLv3 but can rollback to v2 */
在程序中究竟採用哪種協議(TLSv1/SSLv2/SSLv3),就看調哪一組構造函數了.

四:程序源代碼(WIN32版本):

基本上是改造的openssl自帶的demos目錄下的cli.cpp,serv.cpp文件,作了一些修改,並增長了一些功能.

/******************************************************************************************
*SSL/TLS客戶端程序WIN32版(以demos/cli.cpp爲基礎)
*須要用到動態鏈接庫libeay32.dll,ssleay.dll,
*同時在setting中加入ws2_32.lib libeay32.lib ssleay32.lib,
*以上庫文件在編譯openssl後可在out32dll目錄下找到,
*所需證書文件請參照文章自行生成*/
******************************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <errno.h>
#include <sys/types.h>

#include <winsock2.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 "ca.crt" /*CA 的證書*/
#define PORT 1111 /*服務端的端口*/
#define SERVER_ADDR "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];
SSL_METHOD *meth;
int seed_int[100]; /*存放隨機序列*/

WSADATA wsaData;

if(WSAStartup(MAKEWORD(2,2),&wsaData) != 0){
printf("WSAStartup()fail:%dn",GetLastError());
return -1;
}  

OpenSSL_add_ssl_algorithms(); /*初始化*/
SSL_load_error_strings(); /*爲打印調試信息做準備*/

meth = TLSv1_client_method(); /*採用什麼協議(SSLv2/SSLv3/TLSv1)在此指定*/
ctx = SSL_CTX_new (meth);  
CHK_NULL(ctx);

SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,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(-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 keyn");
exit(-4);
}  

/*構建隨機數生成機制,WIN32平臺必需*/
srand( (unsigned)time( NULL ) );
for( int i = 0; i < 100;i++ )
seed_int[i] = 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, '', 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_new (ctx);  
CHK_NULL(ssl);

SSL_set_fd (ssl, sd);
err = SSL_connect (ssl);
CHK_SSL(err);

/*打印全部加密算法的信息(可選)*/
printf ("SSL connection using %sn", 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: %sn", str);
Free (str);

str = X509_NAME_oneline (X509_get_issuer_name (server_cert),0,0);
CHK_NULL(str);
printf ("t issuer: %sn", str);
Free (str);

X509_free (server_cert); /*如再也不須要,需將證書釋放 */

/* 數據交換開始,用SSL_write,SSL_read代替write,read */
printf("Begin SSL data exchangen");

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] = '';
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;
}
/***************************************************************************************
* EOF - cli.cpp
***************************************************************************************/


/***************************************************************************************
*SSL/TLS服務端程序WIN32版(以demos/server.cpp爲基礎)
*須要用到動態鏈接庫libeay32.dll,ssleay.dll,
*同時在setting中加入ws2_32.lib libeay32.lib ssleay32.lib,
*以上庫文件在編譯openssl後可在out32dll目錄下找到,
*所需證書文件請參照文章自行生成.
***************************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <errno.h>
#include <sys/types.h>

#include <winsock2.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 "ca.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;
int client_len;
SSL_CTX* ctx;
SSL* ssl;
X509* client_cert;
char* str;
char buf [4096];
SSL_METHOD *meth;
WSADATA wsaData;

if(WSAStartup(MAKEWORD(2,2),&wsaData) != 0){
printf("WSAStartup()fail:%dn",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_PEER,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 keyn");
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, '', 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, (struct sockaddr*) &sa_cli, &client_len);
CHK_ERR(sd, "accept");
closesocket (listen_sd);

printf ("Connection from %lx, port %xn",
sa_cli.sin_addr.s_addr, sa_cli.sin_port);


/*TCP鏈接已創建,進行服務端的SSL過程. */
printf("Begin server side SSLn");

ssl = SSL_new (ctx);  
CHK_NULL(ssl);
SSL_set_fd (ssl, sd);
err = SSL_accept (ssl);
printf("SSL_accept finishedn");
CHK_SSL(err);


/*打印全部加密算法的信息(可選)*/
printf ("SSL connection using %sn", 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: %sn", str);
Free (str);

str = X509_NAME_oneline (X509_get_issuer_name (client_cert), 0, 0);
CHK_NULL(str);
printf ("t issuer: %sn", 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] = '';
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;
}
/*****************************************************************
* EOF - serv.cpp
*****************************************************************/

五.參考文獻

1.SSL規範(draft302)
2.TLS標準(rfc2246)
3.openssl源程序及文檔
4.SSLeay Programmer Reference
5.Introducing SSL and Certificates using SSLeay

openssl編譯問題 - C/C++ - ChinaUnix.net - - Google Chrome (2013/5/31 14:44:39)

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

#define MAXBUF 1024

void ShowCerts(SSL * ssl)
{
    X509 *cert;
    char *line;

    cert = SSL_get_peer_certificate(ssl);
    if (cert != NULL) {
        printf("數字證書信息:n");
        line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
        printf("證書: %sn", line);
        free(line);
        line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
        printf("頒發者: %sn", line);
        free(line);
        X509_free(cert);
    } else
        printf("無證書信息!n");
}
/************關於本文檔********************************************
*filename: ssl-client.c
*purpose: 演示利用 OpenSSL 庫進行基於 IP層的 SSL 加密通信的方法,這是客戶端例子
*wrote by: zhoulifa( zhoulifa@163.com ) 周立發( http://zhoulifa.bokee.com )
Linux愛好者 Linux知識傳播者 SOHO族 開發者 最擅長C語言
*date time:2007-02-02 20:10
*Note: 任何人能夠任意複製代碼並運用這些文檔,固然包括你的商業用途
* 但請遵循GPL
*Thanks to:Google
*Hope:但願愈來愈多的人貢獻本身的力量,爲科學技術發展出力
* 科技站在巨人的肩膀上進步更快!感謝有開源前輩的貢獻!
*********************************************************************/
int main(int argc, char **argv)
{
    int sockfd, len;
    struct sockaddr_in dest;
    char buffer[MAXBUF + 1];
    SSL_CTX *ctx;
    SSL *ssl;

    if (argc != 3) {
        printf
            ("參數格式錯誤!正確用法以下:ntt%s IP地址 端口nt好比:t%s 127.0.0.1 80n此程序用來從某個 IP 地址的服務器某個端口接收最多 MAXBUF 個字節的消息",
             argv[0], argv[0]);
        exit(0);
    }

    /* SSL 庫初始化,參看 ssl-server.c 代碼 */
    SSL_library_init();
    OpenSSL_add_all_algorithms();
    SSL_load_error_strings();
    ctx = SSL_CTX_new(SSLv23_client_method());
    if (ctx == NULL) {
        ERR_print_errors_fp(stdout);
        exit(1);
    }

    /* 建立一個 socket 用於 tcp 通訊 */
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("Socket");
        exit(errno);
    }
    printf("socket createdn");

    /* 初始化服務器端(對方)的地址和端口信息 */
    bzero(&dest, sizeof(dest));
    dest.sin_family = AF_INET;
    dest.sin_port = htons(atoi(argv[2]));
    if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0) {
        perror(argv[1]);
        exit(errno);
    }
    printf("address createdn");

    /* 鏈接服務器 */
    if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0) {
        perror("Connect ");
        exit(errno);
    }
    printf("server connectedn");

    /* 基於 ctx 產生一個新的 SSL */
    ssl = SSL_new(ctx);
    SSL_set_fd(ssl, sockfd);
    /* 創建 SSL 鏈接 */
    if (SSL_connect(ssl) == -1)
        ERR_print_errors_fp(stderr);
    else {
        printf("Connected with %s encryptionn", SSL_get_cipher(ssl));
        ShowCerts(ssl);
    }

   /* 發消息給服務器 */

    sprintf(buffer, "GET %s HTTP/1.1rnrn", "/accounts/ClientAuth?Email=jinhui1231&Passwd=hao1234567&PersistentCookie=false&source=googletalk");
    len = SSL_write(ssl, buffer, strlen(buffer));
    if (len < 0)
        printf
            ("消息'%s'發送失敗!錯誤代碼是%d,錯誤信息是'%s'n",
             buffer, errno, strerror(errno));
    else
        printf("消息'%s'發送成功,共發送了%d個字節!n",
               buffer, len);

#if 1
    /* 接收對方發過來的消息,最多接收 MAXBUF 個字節 */
    bzero(buffer, MAXBUF + 1);
    /* 接收服務器來的消息 */
    len = SSL_read(ssl, buffer, MAXBUF);
    if (len > 0)
        printf("接收消息成功:'%s',共%d個字節的數據n",
               buffer, len);
    else {
        printf("消息接收失敗!錯誤代碼是%d,錯誤信息是'%s'n",
             errno, strerror(errno));
        goto finish;
    }
  //  bzero(buffer, MAXBUF + 1);
   // strcpy(buffer, "from client->server");
#endif

  finish:
    /* 關閉鏈接 */
    SSL_shutdown(ssl);
    SSL_free(ssl);
    close(sockfd);
    SSL_CTX_free(ctx);
    return 0;
}

使用 OpenSSL API 進行安全編程 - JORDANSG的我的空間 - 開源中國社區 - Google Chrome (2013/5/30 17:45:09)

使用 OpenSSL API 進行安全編程

1人收藏此文章, 我要收藏發表於9個月前(2012-08-27 22:21) , 已有 52次閱讀 ,共 0個評論

OpenSSL API 的文檔有些含糊不清。由於尚未多少關於 OpenSSL 使用的教程,因此對初學者來講,在 應用程序中使用它可能會有一些困難。那麼怎樣才能使用 OpenSSL 實現一個基本的安全鏈接呢? 本教程將幫助您解決這個問題。算法

學習如何實現 OpenSSL 的困難部分在於其文檔的不徹底。不徹底的 API 文檔一般會妨礙開發人員 使用該 API,而這一般意味着它註定要失敗。但 OpenSSL 仍然很活躍,並且正逐漸變得強大。這是爲何?apache

OpenSSL 是用於安全通訊的最著名的開放庫。在 google 中搜索「SSL library」獲得的返回結果中, 列表最上方就是 OpenSSL。它誕生於 1998 年,源自 Eric Young 和 Tim Hudson 開發的 SSLeay 庫。其餘 SSL 工具包包括遵循 GNU General Public License 發行的 GNU TLS,以及 Mozilla Network Security Services(NSS)(請參閱本文後面的 參考資料 ,以得到 其餘信息)。編程

那麼,是什麼使得 OpenSSL 比 GNU TLS、Mozilla NSS 或其餘全部的庫都優越呢?許但是一方面因素 (請參閱 參考資料)。此外,GNS TLS(迄今爲止)只支持 TLS v1.0 和 SSL v3.0 協議,僅此而已。windows

Mozilla NSS 的發行既遵循 Mozilla Public License 又遵循 GNU GPL,它容許開發人員進行選擇。 不過,Mozilla NSS 比 OpenSSL 大,而且須要其餘外部庫來對庫進行編譯,而 OpenSSL 是徹底 自包含的。與 OpenSSL 相同,大部分 NSS API 也沒有文檔資料。Mozilla NSS 得到了 PKCS #11 支持,該支持能夠用於諸如智能卡這樣的加密標誌。OpenSSL 就不具有這一支持。

先決條件

要充分理解並利用本文,您應該:

  • 精通 C 編程。
  • 熟悉 Internet 通訊和支持 Internet 的應用程序的編寫。

並不絕對要求您熟悉 SSL ,由於稍後將給出對 SLL 的簡短說明;不過,若是您但願獲得詳細論述 SSL 的文章的連接,請參閱 參考資料部分。擁有密碼學方面的知識當然好,但這 並非必需的。

回頁首

什麼是 SSL?

SSL 是一個縮寫,表明的是 Secure Sockets Layer。它是支持在 Internet 上進行安全通訊的 標準,而且將數據密碼術集成到了協議之中。數據在離開您的計算機以前就已經被加密,而後只有 到達它預約的目標後才被解密。證書和密碼學算法支持了這一切的運轉,使用 OpenSSL,您將 有機會切身體會它們。

理論上,若是加密的數據在到達目標以前被截取或竊聽,那些數據是不可能被破解的。不過, 因爲計算機的變化一年比一年快,並且密碼翻譯方法有了新的發展,所以,SSL 中使用的加密協議 被破解的可能性也在增大。

能夠將 SSL 和安全鏈接用於 Internet 上任何類型的協議,無論是 HTTP、POP3,仍是 FTP。還能夠用 SSL 來保護 Telnet 會話。雖然能夠用 SSL 保護任何鏈接,可是沒必要對每一類鏈接都使用 SSL。 若是鏈接傳輸敏感信息,則應使用 SSL。

回頁首

什麼是 OpenSSL?

OpenSSL 不只僅是 SSL。它能夠實現消息摘要、文件的加密和解密、數字證書、數字簽名 和隨機數字。關於 OpenSSL 庫的內容很是多,遠不是一篇文章能夠容納的。

OpenSSL 不僅是 API,它仍是一個命令行工具。命令行工具能夠完成與 API 一樣的工做, 並且更進一步,能夠測試 SSL 服務器和客戶機。它還讓開發人員對 OpenSSL 的能力有一個 認識。要得到關於如何使用 OpenSSL 命令行工具的資料,請參閱 參考資料部分。

回頁首

您須要什麼

首先須要的是最新版本的 OpenSSL。查閱參考資料部分,以肯定從哪裏能夠得到最新的能夠本身編譯的源代碼, 或者最新版本的二進制文件(若是您不但願花費時間來編譯的話)。不過,爲了安全起見, 我建議您下載最新的源代碼並本身編譯它。二進制版本一般是由第三方而不是由 OpenSSL 的開發人員來編譯和發行的。

一些 Linux 的發行版本附帶了 OpenSSL 的二進制版本,對於學習如何使用 OpenSSL 庫來講,這足夠了;不過, 若是您打算去作一些實際的事情,那麼必定要獲得最新的版本,並保持該版本一直是最新的。

對於以 RPM 形式安裝的 Linux 發行版本(Red Hat、Mandrake 等),建議您經過從發行版本製造商那裏得到 RPM 程序包來更新您的 OpenSSL 發行版本。出於安全方面的緣由,建議您使用 最新版本的發行版本。若是您的發行版本不能使用最新版本的 OpenSSL,那麼建議您只覆蓋庫文件,不要覆蓋 可執行文件。OpenSSL 附帶的 FAQ 文檔中包含了有關這方面的細節。

還要注意的是,OpenSSL 並無在全部的平臺上都得到官方支持。雖然製造商已經盡力使其可以跨平臺兼容, 但仍然存在 OpenSSL 不能用於您的計算機 和/或 操做系統的可能。請參閱 OpenSSL 的 Web 站點( 參考資料 中 的連接),以得到關於哪些平臺能夠獲得支持的信息。

若是想使用 OpenSSL 來生成證書請求和數字證書,那麼必須建立一個配置文件。在 OpenSSL 程序包 的 apps 文件夾中,有一個名爲 openssl.cnf 的 可用模板文件。我不會對該文件進行討論,由於這不在本文要求範圍以內。不過,該模板文件有一些很是好的註釋,並且若是 在 Internet 上搜索,您能夠找到不少討論修改該文件的教程。

回頁首

頭文件和初始化

本教程所使用的頭文件只有三個:ssl.h、bio.h 和 err.h。它們都位於 openssl 子目錄中,並且都是開發您的項目 所必需的。要初始化 OpenSSL 庫,只須要三個代碼行便可。清單 1 中列出了全部內容。其餘的頭文件 和/或 初始化函數可能 是其餘一些功能所必需的。


清單 1. 必需的頭文件  
/* OpenSSL headers */
#include "openssl/bio.h"
#include "openssl/ssl.h"
#include "openssl/err.h"
/* Initializing OpenSSL */
SSL_load_error_strings();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();

回頁首

創建非安全鏈接

無論鏈接是 安全的仍是不安全的,OpenSSL 都使用了一個名爲 BIO 的抽象庫來處理包括文件和套接字在內的各類類型的通訊。您還能夠將 OpenSSL 設置成爲一個過濾器,好比用於 UU 或 Base64 編碼的過濾器。

在這裏對 BIO 庫進行全面說明有點麻煩,因此我將根據須要一點一點地介紹它。首先, 我將向您展現如何創建一個標準的套接字鏈接。相對於使用 BSD 套接字庫,該操做須要 的代碼行更少一些。

在創建鏈接(不管安全與否)以前,要建立一個指向 BIO 對象的指針。這相似於在標準 C 中 爲文件流建立 FILE 指針。


清單 2. 指針  
BIO * bio;

打開鏈接

建立新的鏈接須要調用 BIO_new_connect 。您能夠在同一個調用中同時 指定主機名和端口號。也能夠將其拆分爲兩個單獨的調用:一個是建立鏈接並設置主機名的 BIO_new_connect 調用,另外一個是設置端口號的 BIO_set_conn_port (或者BIO_set_conn_int_port )調用。

無論怎樣,一旦 BIO 的主機名和端口號都已指定,該指針會嘗試打開鏈接。沒有什麼能夠影響它。若是建立 BIO 對象時遇到問題,指針將會是 NULL。爲了確保鏈接成功,必須執行 BIO_do_connect 調用。


清單 3. 建立並打開鏈接  
bio = BIO_new_connect("hostname:port");
if(bio == NULL)
{
    /* Handle the failure */
}
if(BIO_do_connect(bio) <= 0)
{
    /* Handle failed connection */
}

在這裏,第一行代碼使用指定的主機名和端口建立了一個新的 BIO 對象,並以所示風格對該對象進行 格式化。例如, 若是您要鏈接到 www.ibm.com 的 80 端口,那麼該字符串將是 www.ibm.com:80 。調用 BIO_do_connect 檢查鏈接是否成功。若是出錯,則返回 0 或 -1。

與服務器進行通訊

無論 BIO 對象是套接字仍是文件,對其進行的讀和寫操做都是經過如下兩個函數來完成的: BIO_read 和 BIO_write 。 很簡單,對吧?精彩之處就在於它始終如此。

BIO_read 將嘗試從服務器讀取必定數目的字節。它返回讀取的字節數、 0 或者 -1。在受阻塞的鏈接中,該函數返回 0,表示鏈接已經關閉,而 -1 則表示鏈接出現錯誤。在非阻塞鏈接的狀況下,返回 0 表示沒有能夠得到的數據,返回 -1 表示鏈接出錯。能夠調用BIO_should_retry 來肯定是否可能重複出現該錯誤。


清單 4. 從鏈接讀取  
int x = BIO_read(bio, buf, len);
if(x == 0)
{
    /* Handle closed connection */
}
else if(x < 0)
{
   if(! BIO_should_retry(bio))
    {
        /* Handle failed read here */
    }
    /* Do something to handle the retry */
}

BIO_write 會試着將字節寫入套接字。它將返回實際寫入的 字節數、0 或者 -1。同 BIO_read ,0 或 -1 不必定表示錯誤。BIO_should_retry 是找出問題的途徑。若是須要重試寫操做,它必須 使用和前一次徹底相同的參數。


清單 5. 寫入到鏈接  
if(BIO_write(bio, buf, len) <= 0)
{
    if(! BIO_should_retry(bio))
    {
        /* Handle failed write here */
    }
    /* Do something to handle the retry */
}

關閉鏈接

關閉鏈接也很簡單。您可使用如下兩種方式之一來關閉鏈接: BIO_reset 或 BIO_free_all 。若是您還須要從新使用對象,那麼請使用第一種方式。 若是您再也不從新使用它,則可使用第二種方式。

BIO_reset 關閉鏈接並從新設置 BIO 對象的內部狀態,以即可以從新使用鏈接。若是要在整個應用程序中使用同一對象,好比使用一臺安全的聊天 客戶機,那麼這樣作是有益的。該函數沒有返回值。

BIO_free_all 所作正如其所言:它釋放內部結構體,並釋放 全部相關聯的內存,其中包括關閉相關聯的套接字。若是將 BIO 嵌入於一個類中,那麼應該在類的 析構函數中使用這個調用。


清單 6. 關閉鏈接  
/* To reuse the connection, use this line */
BIO_reset(bio);
/* To free it from memory, use this line */
BIO_free_all(bio);

回頁首

創建安全鏈接

如今須要給出創建安全鏈接須要作哪些事情。唯一要改變的地方就是創建並進行鏈接。其餘全部內容都是相同的。

安全鏈接要求在鏈接創建後進行握手。在握手過程當中,服務器向客戶機發送一個證書, 而後,客戶機根據一組可信任證書來覈實該證書。它還將檢查證書,以確保它沒有過時。要 檢驗證書是可信任的,須要在鏈接創建以前提早加載一個可信任證書庫。

只有在服務器發出請求時,客戶機纔會向服務器發送一個證書。該過程叫作客戶機認證。使用證書, 在客戶機和服務器之間傳遞密碼參數,以創建安全鏈接。儘管握手是在創建鏈接以後才進行的,可是客戶機或服務器能夠在任什麼時候刻請求進行一次新的握手。

參考資料 部分中列出的 Netscasp 文章 和 RFC 2246 ,對握手以及創建安全鏈接的其餘方面的知識進行了更詳盡的論述。

爲安全鏈接進行設置

爲安全鏈接進行設置要多幾行代碼。同時須要有另外一個類型爲 SSL_CTX 的指針。該結構保存了一些 SSL 信息。您也能夠利用它經過 BIO 庫創建 SSL 鏈接。能夠經過使用 SSL 方法函數調用 SSL_CTX_new 來建立這個結構,該方法函數一般是SSLv23_client_method 。

還須要另外一個 SSL 類型的指針來保持 SSL 鏈接結構(這是短期就能完成的一些鏈接所必需的)。之後還能夠用該 SSL 指針來檢查鏈接信息或設置其餘 SSL 參數。


清單 7. 設置 SSL 指針  
SSL_CTX * ctx = SSL_CTX_new(SSLv23_client_method());
SSL * ssl;

加載可信任證書庫

在建立上下文結構以後,必須加載一個可信任證書庫。這是成功驗證每一個證書所必需的。若是 不能確認證書是可信任的,那麼 OpenSSL 會將證書標記爲無效(但鏈接仍能夠繼續)。

OpenSSL 附帶了一組可信任證書。它們位於源文件樹的 certs 目錄中。 不過,每一個證書都是一個獨立的文件 —— 也就是說,須要單獨加載每個證書。在 certs 目錄下,還有一個存放過時證書的子目錄。試圖加載這些證書將會出錯。

若是您願意,能夠分別加載每個文件,但爲了簡便起見,最新的 OpenSSL 發行版本的可信任證書 一般存放在源代碼檔案文件中,這些檔案文件位於名爲「TrustStore.pem」的單個文件中。若是已經有了一個可信任證書庫, 並打算將它用於特定的項目中,那麼只需使用您的文件替換清單 8 中的「TrustStore.pem」(或者使用 單獨的函數調用將它們所有加載)便可。

能夠調用 SSL_CTX_load_verify_locations 來加載可信任證書庫文件。這裏要用到 三個參數:上下文指針、可信任庫文件的路徑 和文件名,以及證書所在目錄的路徑。必須指定可信任庫文件或證書的目錄。 若是指定成功,則返回 1,若是遇到問題,則返回 0。


清單 8. 加載信任庫  
if(! SSL_CTX_load_verify_locations(ctx, "/path/to/TrustStore.pem", NULL))
{
    /* Handle failed load here */
}

若是打算使用目錄存儲可信任庫,那麼必需要以特定的方式命名文件。OpenSSL 文檔清楚 地說明了應該如何去作,不過,OpenSSL 附帶了一個名爲 c_rehash 的工具, 它能夠將文件夾配置爲可用於 SSL_CTX_load_verify_locations 的 路徑參數。


清單 9. 配置證書文件夾並使用它  
/* Use this at the command line */
c_rehash /path/to/certfolder
/* then call this from within the application */
if(! SSL_CTX_load_verify_locations(ctx, NULL, "/path/to/certfolder"))
{
    /* Handle error here */
}

爲了指定全部須要的驗證證書,您能夠根據須要命名任意數量的單獨文件或文件夾。您還能夠同時指定 文件和文件夾。

建立鏈接

將指向 SSL 上下文的指針做爲唯一參數,使用 BIO_new_ssl_connect 建立 BIO 對象。還須要得到指向 SSL 結構的指針。在本文中,只將該指針用於 SSL_set_mode 函數。而這個函數是用來設置 SSL_MODE_AUTO_RETRY 標記的。使用這個選項進行設置,若是服務器忽然但願進行 一次新的握手,那麼 OpenSSL 能夠在後臺處理它。若是沒有這個選項,當服務器但願進行一次新的握手時, 進行讀或寫操做都將返回一個錯誤,同時還會在該過程當中設置 retry 標記。


清單 10. 設置 BIO 對象  
bio = BIO_new_ssl_connect(ctx);
BIO_get_ssl(bio, & ssl);
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);

設置 SSL 上下文結構以後,就能夠建立鏈接了。主機名是使用 BIO_set_conn_hostname 函數 設置的。主機名和端口的指定格式與前面的相同。該函數還能夠打開到主機的鏈接。爲了確認已經成功打開鏈接,必須 執行對 BIO_do_connect 的調用。該調用還將執行握手來創建安全鏈接。


清單 11. 打開安全鏈接  
/* Attempt to connect */
BIO_set_conn_hostname(bio, "hostname:port");
/* Verify the connection opened and perform the handshake */
if(BIO_do_connect(bio) <= 0)
{
    /* Handle failed connection */
}

鏈接創建後,必須檢查證書,以肯定它是否有效。實際上,OpenSSL 爲咱們完成了這項任務。若是證書有致命的 問題(例如,哈希值無效),那麼將沒法創建鏈接。可是,若是證書的問題並非致命的(當它已通過期 或者尚不合法時),那麼仍能夠繼續使用鏈接。

能夠將 SSL 結構做爲唯一參數,調用 SSL_get_verify_result 來查 明證書是否經過了 OpenSSL 的檢驗。若是證書經過了包括信任檢查在內的 OpenSSL 的內部檢查,則返回 X509_V_OK。若是有地方出了問題,則返回一個錯誤代碼,該代碼被記錄在命令行工具的 verify 選項下。

應該注意的是,驗證失敗並不意味着鏈接不能使用。是否應該使用鏈接取決於驗證結果和安全方面的考慮。例如, 失敗的信任驗證可能只是意味着沒有可信任的證書。鏈接仍然可用,只是須要從思想上提升安全意識。


清單 12. 檢查證書是否有效  
if(SSL_get_verify_result(ssl) != X509_V_OK)
{
    /* Handle the failed verification */
}

這就是所須要的所有操做。一般,與服務器進行通訊都要使用 BIO_read 和 BIO_write 。而且只需調用 BIO_free_all 或BIO_reset ,就能夠關閉 鏈接,具體調用哪個方法取決因而否重用 BIO。

必須在結束應用程序以前的某個時刻釋放 SSL 上下文結構。能夠調用 SSL_CTX_free 來釋放該結構。


清單 13. 清除 SSL 上下文  
SSL_CTX_free(ctx);

回頁首

錯誤檢測

顯然 OpenSSL 拋出了某種類型的錯誤。這意味着什麼?首先,您須要獲得錯誤代碼自己; ERR_get_error 能夠完成這項任務;而後,須要將錯誤代碼轉換爲錯誤 字符串,它是一個指向由 SSL_load_error_strings 或 ERR_load_BIO_strings 加載到內存中的永久字符串的指針。 能夠在一個嵌套調用中完成這項操做。

表 1 略述了從錯誤棧檢索錯誤的方法。清單 24 展現瞭如何打印文本字符串中的最後一個 錯誤信息。

表 1. 從棧中檢索錯誤

ERR_reason_error_string 返回一個靜態字符串的指針,而後能夠將字符串顯示在屏幕上、寫入文件,或者以任何您但願的方式進行處理
ERR_lib_error_string 指出錯誤發生在哪一個庫中
ERR_func_error_string 返回致使錯誤的 OpenSSL 函數


清單 14. 打印出最後一個錯誤  
printf("Error: %s\n", ERR_reason_error_string(ERR_get_error()));

您還可讓庫給出預先格式化了的錯誤字符串。能夠調用 ERR_error_string 來 獲得該字符串。該函數將錯誤代碼和一個預分配的緩衝區做爲參數。而這個緩衝區必須是 256 字節長。若是參數 爲 NULL,則 OpenSSL 會將字符串寫入到一個長度爲 256 字節的靜態緩衝區中,並返回指向該緩衝區的 指針。不然,它將返回您給出的指針。若是您選擇的是靜態緩衝區選項,那麼在下一次調用ERR_error_string 時,該緩衝區會被覆蓋。


清單 15. 得到預先格式化的錯誤字符串  
printf("%s\n", ERR_error_string(ERR_get_error(), NULL));

您還能夠將整個錯誤隊列轉儲到文件或 BIO 中。能夠經過 ERR_print_errors 或 ERR_print_errors_fp 來實現這項操做。隊列是以可讀格式被轉儲的。第一個函數將隊列發送到 BIO ,第二個函數將隊列發送到 FILE 。 字符串格式以下(引自 OpenSSL 文檔):

[pid]:error:[error code]:[library name]:[function name]:[reason string]:[file name]:[line]:[optional text message]

其中, [pid] 是進程 ID, [error code] 是一個 8 位十六進制代碼, [file name] 是 OpenSSL 庫中的源代碼文件, [line] 是源文件中的行號。


清單 16. 轉儲錯誤隊列  
ERR_print_errors_fp(FILE *);
ERR_print_errors(BIO *);

回頁首

開始作吧

使用 OpenSSL 建立基本的鏈接並不困難,可是,當試着肯定該如何去作時,文檔多是一個小障礙。本文向您介紹了一些基本概念,但 OpenSSL 還有不少靈活之處有待發掘,並且 您還可能須要一些高級設置,以便項目可以充分利用 SSL 的功能。

本文中有兩個樣例。一個樣例展現了到 http://www.verisign.com/ 的非安全鏈接,另外一個則展現了到 http://www.verisign.com/ 的安全 SSL 鏈接。二者都是鏈接到服務器並下載其主頁。它們沒有進行 任何安全檢查,並且庫中的全部設置都是默認值 —— 做爲本文的一部分,應該只將這些用於教學目的。

在任何支持的平臺上,源代碼的編譯都應該是很是容易的,不過我建議您使用最新版本的 OpenSSL。在撰寫本文時,OpenSSL 的最新版本是 0.9.7d。


參考資料

關於做者

Kenneth 是 Peru State College(位於 Peru, Nebraska)計算機科學專業的大四學生。他仍是 學生報 The Peru State Times 的職業做者。他擁有 Southwestern Community College (位於 Creston, Iowa)計算機編程專業的理學副學士(Associate of Science)學位, 在這所大學裏,他是一名半工半讀的 PC 技術員。他的研究領域包括 Java、C++、COBOL、 Visual Basic 和網絡。


openssl使用方法 - Linux - UNIX技術社區 - Google Chrome (2013/5/30 16:58:46)

OpenSSL 是使用很是普遍的 SSL 的開源實現。因爲其中實現了爲 SSL 所用的各類加密算法,所以 OpenSSL 也是被普遍使用的加密函數庫。

1.1 SSL

SSL(Secure Socket Layer) 安全協議是由 Netscape 公司首先提出,最初用在保護 Navigator 瀏覽器和 Web 服務器之間的 HTTP 通訊 ( 即 HTTPS) 。後來 SSL 協議成爲傳輸層安全通訊事實上的標準,並被 IETF 吸取改進爲 TLS(Transport Layer Security) 協議。

SSL/TLS 協議位於 TCP 協議和應用層協議之間,爲傳輸雙方提供認證、加密和完整性保護等安全服務。 SSL 做爲一個協議框架,通訊雙方能夠選用合適的對稱算法、公鑰算法、 MAC 算法等密碼算法實現安全服務。

1.2 OpenSSL

OpenSSL 是著名的 SSL 的開源實現,是用 C 語言實現的。

OpenSSL 的前身是 SSLeay ,一個由 Eric Young 開發的 SSL 的開源實現,支持 SSLv2/v3 和 TLSv1 。

伴隨着 SSL 協議的普及應用, OpenSSL 被普遍應用在基於 TCP/Socket 的網絡程序中,尤爲是 OpenSSL 和 Apache 相結合,是不少電子商務網站服務器的典型配置。



•  編譯和安裝 OpenSSL

OpenSSL 開放源代碼,這對學習、分析 SSL 和各類密碼算法提供了機會,也便於在上面進一步開發。

2.1 得到 OpenSSL

到 OpenSSL 的網站便可下載當前版本的 OpenSSL 源代碼壓縮包。

當前版本 openssl- 0.9.8 .tar.gz ,只有 3M 多,比較精簡。解壓縮後獲得一個目錄 openssl-0.9.8 ,共有約 1800 個文件, 15M 。其中 crypto 子目錄中是衆多密碼算法實現, ssl 子目錄中是 SSL 協議的實現。

在 Linux 中解壓縮:

$tar zxf openssl- 0.9.8 .tar.gz

在 Windows 中可使用 winzip 或 winrar 。

2.2 編譯工具

編譯 OpenSSL 須要 Perl 和 C 編譯器。在 Windows 下若是要用加密算法的彙編代碼實現,還須要 masm 或 nasm 彙編器。 ( 彙編代碼能夠比 C 代碼顯著提升密碼運算速度 )

Perl 在 Windows 下推薦使用 Active Perl 。

C 編譯器可使用 gcc 。在 W indows 下可使用 Visual C 編譯器。

彙編器推薦使用 nasm 。

這些工具所在目錄必須加入到 PATH 環境變量中去。

2.3 編譯和安裝步驟

查看 readme 是個好習慣。從 readme 瞭解到須要進一步查看 INSTALL 和 INSTALL.W32 文件。

在 Windows 中:

>perl Configure VC-WIN32

>ms\do_nasm ( 若是不使用匯編代碼實現,則可 >ms\do_ms)

>nmake -f ms\ntdll.mak

>cd out32dll

>..\ms\test

編譯結果獲得頭文件、連接庫、運行庫和 openssl.exe 工具。頭文件位於 ./inc32 或者 ./inculde 目錄,有一個 openssl 子目錄,內有幾十個 .h 文件。連接庫即 ./out32dll 目錄中的 libeay32.lib 和 ssleay32.lib ,分別是密碼算法相關的和 ssl 協議相關的。運行庫是 ./out32dll 目錄中的 libeay32.dll 和 ssleay32.dll ,和連接庫相對應。在 ./out32dll 中還有一個工具 openssl.exe ,能夠直接用來測試性能、產生 RSA 密鑰、加解密文件,甚至能夠用來維護一個測試用的 CA 。

在 Linux 中的編譯和安裝步驟較簡單 :

$./config

$make

$make test

$make install

在 Linux 下,頭文件、庫文件、工具都已被安裝放到了合適的位置。庫文件是 .a 或 .so 格式。



•  使用 OpenSSL.exe

使用 OpenSSL.exe(Linux 中可執行文件名是 openssl) 能夠作不少工做,是一個很好的測試或調試工具。

3.1 版本和編譯參數

顯示版本和編譯參數: >openssl version -a

3.2 支持的子命令、密碼算法

查看支持的子命令: >openssl ?

SSL 密碼組合列表: >openssl ciphers

3.3 測試密碼算法速度

測試全部算法速度: >openssl speed

測試 RSA 速度: >openssl speed rsa

測試 DES 速度: >openssl speed des

3.4 RSA 密鑰操做

產生 RSA 密鑰對: >openssl genrsa -out 1.key 1024

取出 RSA 公鑰: >openssl rsa -in 1.key -pubout -out 1.pubkey

3.5 加密文件

加密文件: >openssl enc -e -rc4 -in 1.key -out 1.key.enc

解密文件: >openssl enc -d -rc4 -in 1.key.enc -out 1.key.dec

3.6 計算 Hash 值

計算文件的 MD5 值: >openssl md5 < 1.key

計算文件的 SHA1 值: >openssl sha1 < 1.key



•  算法編程 API

OpenSSL 中支持衆多的密碼算法,並提供了很好的封裝和接口。密碼算法主要分爲以下幾類:對稱算法、公鑰算法、散列算法、隨機數產生算法等。

OpenSSL 的目標是實現安全協議。其中相關協議和標準包括: SSL/TLS 、 PKCS#1 、 PCKS#10 、 X.509 、 PEM 、 OCSP 等。

4.1 對稱算法接口

OpenSSL 中實現的對稱算法太多,舉三個例子: DES 、 AES 、 RC4 。

4.1.1 DES

DES 加密算法是分組算法。 DES 的基本操做是把 64 比特明文在 56 比特密鑰指引下加密成 64 比特密文。在實際使用中把密鑰看做 64 比特能夠更方便。

DES ( IN , KEY ) = OUT

(1) DES ECB 模式

在 OpenSSL 中 ECB 操做模式對應的函數是 DES_ecb_encrypt() ,該函數把一個 8 字節明文分組 input 加密成爲一個 8 字節密文分組 output 。參數中密鑰結構 ks 是用函數 DES_set_key() 準備好的,而密鑰 key 是用隨機數算法產生的 64 個隨機比特。參數 enc 指示是加密仍是解密。該函數每次只加密一個分組,所以用來加密不少數據時不方便使用。

void DES_ecb_encrypt(const_DES_cblock *input,DES_cblock *output, DES_key_schedule *ks,int enc);

int DES_set_key(const_DES_cblock *key,DES_key_schedule *schedule);

(2) DES CBC 模式

DES 算法 CBC 操做模式加解密函數是 DES_ncbc_encrypt() 。參數 length 指示輸入字節長度。若是長度不是 8 字節的倍數,則會被用 0 填充到 8 字節倍數。所以,輸出可能比 length 長,並且必然是 8 字節的倍數。

void DES_ncbc_encrypt(const unsigned char *input,unsigned char *output, long length, DES_key_schedule *schedule, DES_cblock *ivec, int enc);

(3) DES CFB 模式

DES 算法 CFB 操做模式加解密函數是 DES_cfb_encrypt() 。參數 length 指示輸入字節長度。參數 numbits 則指示了 CFB 每次循環加密多少明文比特,也即密文反饋的比特數目。 ivec 是初始向量,被看作第 0 個密文分組,是不用保密但應隨機取值的 8 個字節。若是在一次會話中數次調用 DES_cfb_encrypt() ,則應該記憶 ivec 。因爲 CFB 模式中每次 DES 基本操做只加密 numbits 比特明文,所以若是 numbits 過小則效率過低。

void DES_cfb_encrypt(const unsigned char *in, unsigned char *out, int numbits, long length, DES_key_schedule *schedule, DES_cblock *ivec, int enc);

另有一個 numbit 是 64 比特的版本,既高效又沒有填充的麻煩,推薦使用。 num 中的返回值指示了 ivec 中的狀態,是和下次調用銜接的。

void DES_cfb64_encrypt(const unsigned char *in, unsigned char *out, long length, DES_key_schedule *schedule, DES_cblock *ivec, int *num, int enc) ;

(4) DES OFB 模式

OFB 和 CFB 相似,也有兩個函數,用法同樣。

void DES_ofb_encrypt(const unsigned char *in,unsigned char *out,int numbits,long length,DES_key_schedule *schedule,DES_cblock *ivec);

void DES_ofb64_encrypt(const unsigned char *in,unsigned char *out,long length,DES_key_schedule *schedule,DES_cblock *ivec,int *num);

(5) DES 函數示例程序

見附件 A.1 。

4.1.2 A ES

AES 加密算法是分組算法。典型參數的 AES 的基本操做是把 128 比特明文在 128 比特密鑰指引下加密成 128 比特密文。

AES ( IN , KEY ) = OUT

OpenSSL 中關於 AES 的函數名和參數接口和 DES 的雷同。相關函數名以下 ( 參數略 ) 。

int AES_set_encrypt_key();

int AES_set_decrypt_key();

void AES_ecb_encrypt();

void AES_cbc_encrypt();

void AES_cfb128_encrypt();

void AES_ofb128_encrypt();

AES 示例程序見附件 A.2 。

4.1.3 RC4

RC4 密碼算法是流算法,也叫序列算法。流算法是從密鑰做爲種子產生密鑰流,明文比特流和密鑰流異或即加密。 RC4 算法因爲算法簡潔,速度極快,密鑰長度可變,並且也沒有填充的麻煩,所以在不少場合值得大力推薦。

OpenSSL 中 RC4 算法有兩個函數 : RC4_set_key() 設置密鑰, RC4() 加解密。能夠把 RC4 看做異或,所以加密兩次即解密。

void RC4_set_key(RC4_KEY *key, int len, const unsigned char *data);

void RC4(RC4_KEY *key, unsigned long len, const unsigned char *indata, unsigned char *outdata);

RC4 示例程序見附件 A.3 。

例子 A.3.(1) 是利用 OpenSSL 動態庫函數。例子 A.3.(2) 是把 RC4 的實現代碼從 OpenSSL 中分離出來的。例子 A.3.(3) 是另外一個演示實現。

4.2 公鑰算法

OpenSSL 中實現了 RSA 、 DSA 、 ECDSA 等公鑰算法。

4.2.1 RSA

RSA 是分組算法,典型的密鑰模長度 1024 比特時,分組便是 1024 比特,即 128 字節。

(1) RSA 密鑰

RSA 密鑰產生函數 RSA_generate_key() ,須要指定模長比特數 bits 和公鑰指數 e 。另外兩個參數爲 NULL 便可。

RSA * RSA_generate_key(int bits, unsigned long e, void (*callback) (int,int,void *),void *cb_arg);

若是從文件中讀取密鑰,可以使用函數 PEM_read_bio_PrivateKey()/ PEM_read_bio_PUBKEY(); EVP_PKEY 中包含一個 RSA 結構,能夠引用。

EVP_PKEY *PEM_read_bio_PrivateKey(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, void *u);

(2) RSA 加密解密

RSA 加密函數 RSA_public_encrypt() 使用公鑰部分,解密函數 RSA_private_decrypt() 使用私鑰。填充方式經常使用的有兩種 RSA_PKCS1_PADDING 和 RSA_PKCS1_OAEP_PADDING 。出錯時返回 -1 。輸入必須比 RSA 鑰模長短至少 11 個字節(在 RSA_PKCS1_PADDING 時?)。輸出長度等於 RSA 鑰的模長。

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);

(3) 簽名和驗證

簽名使用私鑰,驗證使用公鑰。 RSA 簽名是把被簽署消息的散列值編碼後用私鑰加密,所以函數中參數 type 用來指示散列函數的類型,通常是 NID_md5 或 NID_sha1 。正確狀況下返回 0 。

int RSA_sign(int type, const unsigned char *m, unsigned int m_length, unsigned char *sigret, unsigned int *siglen, RSA *rsa);

int RSA_verify(int type, const unsigned char *m, unsigned int m_length, unsigned char *sigbuf, unsigned int siglen, RSA *rsa);

(4) RSA 函數示例程序

RSA 示例程序見附件 A.4 。

例子 A.4.(1) 是加密解密例子。例子 A.4.(2) 是簽名驗證例子。

4.2.2 DSA

( TOBE )

4.2.2 ECDSA

( or NOT TOBE )

4.3 Hash 算法

Hash 算法舉 MD5 和 SHA1 兩個例子。 Hash 算法重複接收用戶輸入,直到最後一次結束時輸出散列結果。

4.3.1 MD5

MD5 算法輸出的散列值是 16 字節。

int MD5_Init(MD5_CTX *c);

int MD5_Update(MD5_CTX *c, const void *data, size_t len);

int MD5_Final(unsigned char *md, MD5_CTX *c);

4.3.2 SHA1

SHA1 算法輸出的散列值是 20 字節。

int SHA1_Init(SHA_CTX *c);

int SHA1_Update(SHA_CTX *c, const void *data, size_t len);

int SHA1_Final(unsigned char *md, SHA_CTX *c);

4.3.3 MD5 例子

MD5 示例程序見附件 A.5 。

md5sum 這是一個實用小工具,能夠計算一個文件的 MD5 值。

4.4 隨機數算法

隨機性是密碼安全的基石。爲了產生安全的僞隨機數,必須有好的隨機因素做爲種子。 OpenSSL 在內部作了努力,可是仍建議在實用隨機數產生函數以前添加隨機因素。

函數 RAND_add() 能夠添加隨機因素到內部狀態中去。而後,便可以使用 RAND_bytes() 得到隨機數。

void RAND_add(const void *buf,int num,double entropy);

int RAND_bytes(unsigned char *buf,int num);



•  SSL 協議編程 API

5.1 客戶端

5.2 服務器端

5.3 SSL 示例程序

參見 A.6 。



•  CA 和證書

6.1 OpenSSL 中 CA 的配置

6.2 配置示例

參見 A.7.(1) 。

6.3 證書解析

6.4 解析示例程序

參見 A.7.(2) 。



•   



•  參考網址

SSL 3.0 Specification

http://www.netscape.com/eng/ssl3/

Transp ort Layer Security (tls) Charter

http://www.ietf.org/html.charters/tls-charter.html

OpenSSL: The Open Source toolkit for SSL/TLS

http://www.openssl.org/

SSLeay

http://www2.psy.uq.edu.au/~ftp/Crypto/

OpenSSL 中文論壇

http://openssl.cn/

Perl

http://www.cpan.org/src/README.html

http://www.activestate.com/Products/ActivePerl/

NASM

http://www.perl.com/

studio



•   



•  示例程序

注 : 此嵌入的文件對象能夠被拖放到磁盤目錄中去。

•  DES 示例程序

•  AES 示例程序

•  RC4 示例程序

( 1 ). ( 2 ). ( 3 )

•  RSA 示例程序

( 1 ). ( 2 ).

•  Hash 算法示例程序

•  SSL 示例程序

•  CA 配置示例和證書解析示例程序




posted @ 2017-01-16 12:16  suntl 閱讀( ...) 評論( ...) 編輯 收藏
相關文章
相關標籤/搜索