1. 程式人生 > >2-1. 基於OpenSSL的傳輸子系統實現

2-1. 基於OpenSSL的傳輸子系統實現

一. 基本傳輸子系統程式設計

  客戶端可上傳檔案至伺服器,或下載伺服器上的檔案

  系統程式構架:

客戶端 伺服器

TCP建立連線

menu()-> 上傳命令、下載命令

close(socket)

TCP建立連線

handle()-> 根據命令響應

close(socket);

 

 

 

 

 

 

主函式框架:

客戶端 伺服器
int main(int argc, char *args[])
{
    if (argc != 2)
    {
        printf("usage: ./client 192.168.10.18 (serverip)\n");
        exit(0);    //退出    
    }
    strcpy(ipaddr,args[1]);  //將伺服器地址放入字串中
    //1.建立連線
    clink();  
    //2.輸入命令, 實現上傳和下載,實現選單
    menu();
    //3.關閉連線
    close(sockfd); 
    return 0;
}
 
int clink()
{
    //1.建立socket
    sockfd = socket(AF_INET, SOCK_STREAM, 0);  //IPv4,用於TCP通訊
    
    /*2.1 初始化地址*/
    memset(&sockaddr1,0,sizeof(sockaddr1));//清零
    sockaddr1.sin_family = AF_INET;//協議族
    sockaddr1.sin_addr.s_addr = inet_addr(ipaddr);//
    sockaddr1.sin_port = htons(port);//埠,跟隨網路傳輸,
    //2.連線伺服器    
    connect(sockfd,(struct sockaddr *)&sockaddr1,sizeof(sockaddr1));  
    return 1;
}

 

int main()
{
    //1.1建立socket
    sockfd = socket(AF_INET, SOCK_STREAM, 0);  //IPv4,用於TCP通訊
    //1.2繫結地址
     /*初始化地址*/
    bzero(&server_addr,sizeof(struct sockaddr_in));//清零
    server_addr.sin_family = AF_INET;//協議族
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//跟隨網路傳輸 
    server_addr.sin_port = htons(port);//埠,跟隨網路傳輸
     /*繫結地址*/  
   //1.3監聽埠 bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr)); listen(sockfd,5); //客戶機數目 //1.4等待連線 while(1) { //client_addr儲存客戶機地址 &sin_size長度的地址 new_fd = accept(sockfd,(struct sockaddr *)(&client_addr),&sin_size);
//2.響應客戶端請求 while(1) { read(new_fd,&cmd,1); //讀取操作型別碼 if(cmd == 'Q') { close(new_fd); break; } else { handle(cmd); } } close(sockfd); } return 0; }

 

-------------------------------------------------------------------------------------------------------------------------

  客戶端操作選單及伺服器端命令響應:

客戶端操作選單 伺服器端命令響應
 1 void menu()
 2 {
 3     while(1)
 4     {
 5         printf("\n-------- 1. Upload Files -----------\n");    
 6         printf("-------- 2. Download Files ----------\n");    
 7         printf("--------------- 3. Exit ------------\n");
 8         printf("Please input the Client command:");      
 9         command = getchar();    //等待使用者輸入字元
10         switch(command)
11         {
12 case '1':
13   {          //上傳檔案
14     while ((c=getchar()) != '\n' && c != EOF);//獲取鍵盤輸入的檔名
15           fgets(file_u,30,stdin);  //stdin 標準輸入
16     upload_file(file_u);      //上傳
17   }
18 case '2':
19   {          //下載檔案
20     while ((c=getchar()) != '\n' && c != EOF);
21           fgets(file_d,30,stdin);    //stdin 標準輸入    
22     download_file(file_d);    //下載
23   }
24 }

 

  
按照客戶端的合適進行設定
    //1.接收操作符--->>>第一部曲    --->>>1步
read(new_fd,&cmd,1);  //讀取操作型別碼
    //2.按照操作符進行命令函式
if(cmd == 'Q')
   { close(new_fd);     break;}
else
    handle(cmd);
    //3.進行正式檔案處理--->>>剩下4部曲

void handle(char cmd) { switch(cmd) { case 'U'://伺服器接收 { read(new_fd~ //接收檔名 --->>>2步 read(new_fd~ //接收檔案長度 --->>>3步 fd = open(filename~//建立檔案準備接受--->>>4步 write(fd,&buf~ //接收檔案內容 --->>>5步 } case 'D'://伺服器傳出 { read(new_fd~ //接收檔名 --->>>2步 fd = open(filename~//開啟當前目錄檔案--->>>3步 write(new_fd~ //傳送檔案長度 --->>>4步 write(new_fd //傳送檔案內容 --->>>5步 } case 'Q'://退出 { close(new_fd); break; } }

 

//case "1"  上傳檔案   5部曲
void upload_file(char *filename)
{
    //1.開啟要上傳的檔案
fd = open(filename,O_RDONLY);  //以只讀方式開啟檔案
    //2.傳送操作符 cmd="U"
write(sockfd,&cmd,1);
    //3.傳送要上傳的檔名
write(sockfd,filename,size);
    //4.傳送檔案長度
stat(filename,&fstat);  //獲取檔案屬性
write(sockfd,(void *)&(fstat.st_size),4);
    //5.傳送檔案
while((count=read(fd,(void *)buf,1024))>0)//讀取來的資料存到buf的空間
        write(sockfd,&buf,count);
}

//case "2"  下載檔案   5部曲相同
void download_file(char *filename)
{
    //1.傳送操作符 cmd="D"
write(sockfd,&cmd,1);
    //2.傳送要下載的檔名
write(sockfd,filename,size);
    //3.建立接收檔案
fd = open(filename,O_RDONLY|O_CREAT,0777);  //以只讀方式開啟檔案
    //4.接收檔案長度
read(sockfd,&filesize,4);
    //5.接收檔案
while((count=read(fd,(void *)buf,1024))>0)//讀取來的資料存到buf的空間
        write(fd,&buf,count);
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

-------------------------------------------------------------------------------------------------------------------

二. OpenSSL加密系統

  由於網路傳輸資料中,易被抓包軟體截獲。因此運用非對稱加密方法(公鑰、私鑰、數字證書),檔案內容+公鑰 ->加密系統 ->私鑰,方可解密檔案。

a)公鑰與私鑰是配對時候用的;

b)私鑰加密的檔案同樣用對應的公鑰解密,而為了區分公鑰(防止公鑰被偷換,導致私密檔案洩露),引入數字證書再加密。

c)數字證書有權威機構發放,包含公鑰及持有人資訊,無法丟失假冒;

  SSL協議處於應用層協議(HTTP/SMTP)與TCP/IP協議之間,可實現檔案加密傳輸。開源套接字層密碼庫OpenSSL,包含SSL、密碼演算法、祕鑰證書管理功能等。 

  

 

 

 

 

 

 

 

-----------------------------------------------------------------------------------------------

  移植OpenSSL庫:

解壓安裝檔案 -> 配置.config檔案,修改交叉工具鏈arm-linux- -> 編譯make,make install,即生成OpenSSL的庫函式檔案 .a、.so -> 置於/rootfs/lib/目錄下,OK!

  OpenSSL通訊模型:基於下列通訊模型優化原始傳輸子系統程式設計

客戶端SSL模型 伺服器端SSL模型

初始化SSL ->

(建立套接字、連線伺服器) ->

建立SSL ->

基於SSL收發資料 ->

關閉SSL ->

(關閉套接字)

初始化SSL ->

公鑰私鑰數字證書設定 ->

(建立套接字、繫結、等待連線) ->

建立SSL ->

基於SSL收發資料 ->

關閉SSL ->

(關閉套接字)

 

 

 

 

 

 

 

 

 

 

 

 

基於SSL收發資料:將write (sockfd,~) ->SSL_write (ssl,~)、read (sockfd,~) ->SSL_read (ssl,~)即可!

再對應產生公鑰、私鑰:(全部置於伺服器目錄下)

  # openssl genrsa -out privkey.pem 2048  ->私鑰

  # openssl req -new -x509 -key privkey.pem -out cacert.pem -days 1095 ->對應產生的公鑰

  OpenSSL加密傳輸子系統程式設計完成,對應產生伺服器加密所需的公鑰與私鑰,分別進行編譯即可實現:對上傳、下載伺服器檔案的加密傳輸。

&n