• 正文
    • 一、一種常見的網(wǎng)絡(luò)通信的加密流程
    • 二、函數(shù)實(shí)現(xiàn)
    • 三、測(cè)試代碼實(shí)例
    • 四、數(shù)據(jù)加密的實(shí)際使用
    • 五、 原理
  • 相關(guān)推薦
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

手把手教你如何實(shí)現(xiàn)一個(gè)簡(jiǎn)單的數(shù)據(jù)加解密算法

01/03 15:30
526
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

之前寫過一篇關(guān)于MD5摘要算法的文章,很多老鐵說能否出一篇關(guān)于加密的文章嗎?一口君的字典里沒有"不行"這兩個(gè)字!必須安排!

關(guān)于加密的一些基本概念,大家可以參考下面這一篇文章:?《公鑰密碼學(xué)簡(jiǎn)介》

本文,一口君帶著大家自己實(shí)現(xiàn)一個(gè)簡(jiǎn)單但也很實(shí)用的加密方法,讓大家了解實(shí)際項(xiàng)目開發(fā)中數(shù)據(jù)加密的流程。

一、一種常見的網(wǎng)絡(luò)通信的加密流程

關(guān)于加密的算法很多,實(shí)際實(shí)現(xiàn)過程千差萬別,

下圖是一個(gè)常見的網(wǎng)絡(luò)通信加密的應(yīng)用場(chǎng)景。

密碼機(jī)的一些說明:

    • 客戶端服務(wù)器端都可以設(shè)置密碼機(jī)(可以是軟件、也可以是一個(gè)硬件,可以在本地也可以在某個(gè)服務(wù)器上,只要能夠產(chǎn)生密鑰即可)keygen和同步碼都會(huì)影響到密碼機(jī)生成的密鑰序列密碼機(jī)在keygen和同步碼相同的情況下,會(huì)產(chǎn)生相同的密鑰序列,加解密雙方需要記住產(chǎn)生密鑰的順序,解密多少數(shù)據(jù)就申請(qǐng)多少密鑰

如上圖所示,基于C/S架構(gòu)的服務(wù)器和客戶端通信模型,

下面以客戶端如果要發(fā)送一段加密的密文給服務(wù)器,C/S需要交互的流程。

1 服務(wù)器端發(fā)送密鑰密文

    首先服務(wù)器端、客戶端都保存了一個(gè)默認(rèn)的密鑰服務(wù)器端隨機(jī)生成密鑰keygen,并使用該默認(rèn)密鑰對(duì)keygen加密,生成密鑰密文客戶端可以通過命令定期請(qǐng)求該密鑰密文或者服務(wù)器定時(shí)下發(fā)客戶端收到密鑰密文后,也可以通過默認(rèn)密鑰進(jìn)行解密得到明文的keygen

2. 客戶端對(duì)數(shù)據(jù)加密

    客戶端在發(fā)送數(shù)據(jù)之前,首先生成一個(gè)同步碼將同步碼和keygen設(shè)置給密碼機(jī),然后向密碼機(jī)申請(qǐng)一定長(zhǎng)度的密鑰將明文和密鑰通過一定的算法進(jìn)行加密(通常是異或),生成數(shù)據(jù)密文

3. 客戶端發(fā)送同步碼和數(shù)據(jù)密文

    客戶端將數(shù)據(jù)密文和同步碼明文一起發(fā)送給服務(wù)器服務(wù)器提取出同步碼

4. 服務(wù)器端接收數(shù)據(jù)并解密

    服務(wù)器將keygen和同步碼設(shè)置給密碼機(jī),同時(shí)申請(qǐng)一定數(shù)量的密鑰服務(wù)器根據(jù)密鑰對(duì)密文進(jìn)行解密,即得到對(duì)應(yīng)的明文

因?yàn)榉?wù)器和客戶端此時(shí)都使用了相同的keygen,和同步碼,所以雙方申請(qǐng)的密鑰序列一定是一樣的。

二、函數(shù)實(shí)現(xiàn)

下面是一口君實(shí)現(xiàn)的加密算法的一些函數(shù)原型以及功能說明,這些函數(shù)基本實(shí)現(xiàn)了第一節(jié)的功能。

1. 申請(qǐng)加密密鑰函數(shù)request_key

int?request_key(int?sync,int?key_num,char?key[])
功能:
?向密碼機(jī)申請(qǐng)一定數(shù)量的用于加密數(shù)據(jù)的密鑰,如果不設(shè)置新的keygen,那么生成的密碼會(huì)順序產(chǎn)生下去,每次申請(qǐng)密鑰都會(huì)記錄上次生成的密鑰的偏移,下次在申請(qǐng)的時(shí)候,都會(huì)從上一位置繼續(xù)分配密鑰
參數(shù):
?sync:同步碼,密碼機(jī)依據(jù)此同步產(chǎn)生隨機(jī)序列的密鑰
?key_num:申請(qǐng)的密鑰個(gè)數(shù)
?key:申請(qǐng)的密鑰存儲(chǔ)的緩存
返回值:
?實(shí)際返回密鑰個(gè)數(shù)

2. 設(shè)置密鑰序列函數(shù)set_keygen

void?set_keygen(int?key)
功能:
?向密碼機(jī)設(shè)置keygen,設(shè)置后會(huì)影響產(chǎn)生的隨機(jī)密鑰序列
參數(shù):
?key:密鑰
返回值:
?無

3. 產(chǎn)生隨機(jī)數(shù)born_seed

int?born_seed(int?sync,int?key)
功能:
?根據(jù)同步碼和keygen生成隨機(jī)密鑰種子
參數(shù):
??? sync:同步碼?
?key:密鑰
返回值:
?種子

4. 重置keygen reset_keygen()

void?reset_keygen()
功能:
?重置keygen,會(huì)影響生成的隨機(jī)數(shù)序列

三、測(cè)試代碼實(shí)例

最終文件如下:

key.c??key.h??main.c

示例1 檢測(cè)產(chǎn)生的隨機(jī)序列

int?main(int?argc,?char?*argv[])
{
?int?i;
?unsigned?int?len;
?int?j,?r,?key_num;
?unsigned?int?sync?=?0;
?unsigned?char?key[MAX_KEY_REQUEST];


?key_num?=?10;

?printf("n--------------采用默認(rèn)keygen?同步碼=0?產(chǎn)生密文----------------n");
?reset_keygen();

?memset(key,0,sizeof(key));
?len?=?request_key(sync,key_num,key);

?print_array("密鑰0-9:",key,len);

?memset(key,0,sizeof(key));
?len?=?request_key(sync,key_num,key);

?print_array("密鑰10-19:",key,len);

?printf("n--------------采用keygen=1234?同步碼=0?產(chǎn)生密文----------------n");
?set_keygen(1234);

?memset(key,0,sizeof(key));
?len?=?request_key(sync,key_num,key);

?print_array("密鑰0-9:",key,len);

?memset(key,0,sizeof(key));
?len?=?request_key(sync,key_num,key);

?print_array("密鑰10-19:",key,len);
}

執(zhí)行結(jié)果:

--------------采用默認(rèn)keygen?同步碼=0?產(chǎn)生密文----------------
密鑰0-9:?----[10]
a5?52?c8?14?5d?f7?46?5b?89?42?
密鑰10-19:?----[10]
38?69?6f?a6?08?d2?69?39?cd?29?

--------------采用keygen=1234?同步碼=0?產(chǎn)生密文----------------
密鑰0-9:?----[10]
0e?83?0b?73?ec?f5?4b?4a?74?35?
密鑰10-19:?----[10]
e7?f1?06?41?c8?6b?aa?df?0c?3d?

可以看到采用不同的keygen產(chǎn)生的隨機(jī)序列是不一樣的。

如果設(shè)置不同的同步碼,仍然序列還會(huì)不一樣。

示例2 用默認(rèn)keygen,加解密

char?data0[10]={
?0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0x10,
};
int?main(int?argc,?char?*argv[])
{
?int?i;
?unsigned?int?len;
?int?j,?r,?key_num;
?unsigned?int?sync?=?0;
?unsigned?char?key[MAX_KEY_REQUEST];
?char?buf[120]={0};

?key_num?=?10;
?printf("n--------------采用默認(rèn)keygen開始加密----------------n");
?reset_keygen();
?print_array("n明文:",data0,key_num);

?memset(key,0,sizeof(key));
?len?=?request_key(sync,key_num,key);

?print_array("密鑰:",key,len);
?for(i=0;i<len;i++)
?{
??buf[i]?=?data0[i]^key[i];
?}
?print_array("n密文:",buf,len);
?
?printf("n--------------------開始解密--------------------n");
?reset_keygen();

?memset(key,0,sizeof(key));
?len?=?request_key(sync,key_num,key);

?
?for(i=0;i<len;i++)
?{
??buf[i]?=?buf[i]^key[i];
?}

?print_array("n明文:",buf,len);
}

測(cè)試結(jié)果

--------------采用默認(rèn)keygen開始加密----------------

明文:?----[10]
01?02?03?04?05?06?07?08?09?10?
密鑰:?----[10]
a5?52?c8?14?5d?f7?46?5b?89?42?

密文:?----[10]
a4?50?cb?10?58?f1?41?53?80?52?

--------------------開始解密--------------------

明文:?----[10]
01?02?03?04?05?06?07?08?09?10?

示例3 用不同的keygen和同步碼加解密

int?main(int?argc,?char?*argv[])
{
?int?i;
?unsigned?int?len;
?int?j,?r,?key_num;
?unsigned?int?sync?=?0;
?unsigned?char?key[MAX_KEY_REQUEST];
?char?buf[120]={0};
?unsigned?int?mykeygen;


?if?(argc?!=?4)?{
??fprintf(stderr,?"Usage:?%s?<seed>?<key?num>?<keygen>n",?argv[0]);
??exit(EXIT_FAILURE);
?}

?sync?=?atoi(argv[1]);
?key_num?=?atoi(argv[2]);
?mykeygen?=?atoi(argv[3]);

?printf("n--------------采用自定義的keygen、同步碼開始加密----------------n");
?set_keygen(mykeygen);
?print_array("n明文:",data0,key_num);

?memset(key,0,sizeof(key));
?len?=?request_key(sync,key_num,key);
?print_array("密鑰:",key,len);

?for(i=0;i<len;i++)
?{
??buf[i]?=?data0[i]^key[i];
?}
?print_array("n密文:",buf,len);
?

?printf("n--------------------開始解密--------------------n");
?set_keygen(mykeygen);

?memset(key,0,sizeof(key));
?len?=?request_key(sync,key_num,key);
?for(i=0;i<len;i++)
?{
??buf[i]?=?buf[i]^key[i];
?}
?print_array("n明文:",buf,len);
?exit(EXIT_SUCCESS);
}

執(zhí)行結(jié)果如下:

--------------采用自定義的keygen、同步碼開始加密----------------

明文:?----[10]
01?02?03?04?05?06?07?08?09?10?
密鑰:?----[10]
53?00?29?cd?27?eb?cc?80?1a?d7?

密文:?----[10]
52?02?2a?c9?22?ed?cb?88?13?c7?

--------------------開始解密--------------------

明文:?----[10]
01?02?03?04?05?06?07?08?09?10?

可見我們的確實(shí)現(xiàn)了數(shù)據(jù)的加密和解密。

四、數(shù)據(jù)加密的實(shí)際使用

假定我們使用上述實(shí)例代碼,把對(duì)應(yīng)的功能移植到C/S兩端,

那么一次完整的數(shù)據(jù)加密以及數(shù)據(jù)的傳輸參考流程如下:

記住一點(diǎn),只要雙方設(shè)置相同的keygen和同步碼,那么密碼機(jī)吐出來的密鑰就是相同序列,

客戶端發(fā)送每發(fā)送一個(gè)報(bào)文,就把自己的明文同步碼一起發(fā)送給服務(wù)器,

服務(wù)器根據(jù)提前發(fā)送給客戶端的keygen和同步碼就可以實(shí)現(xiàn)解密操作,

雖然你可以看到明文的同步碼,

但是還需要破解密碼機(jī)算法、服務(wù)器下發(fā)的keygen密文。

五、 原理

實(shí)現(xiàn)加密算法的主要問題是如何產(chǎn)生隨機(jī)序列作為密鑰。

本例是借用庫(kù)函數(shù)rand()
原型如下:

#include?<stdlib.h>

int?rand(void);

函數(shù)rand() 雖然可以產(chǎn)生隨機(jī)序列,但是每次產(chǎn)生的序列其實(shí)順序是一樣的。

#include?<stdio.h>

main()
{
?int?i?=?0;

?for(i=0;i<10;i++)
?{
??printf("%d?",rand());
?}
?putchar('n');
}

運(yùn)行結(jié)果如下:

peng@peng-virtual-machine:/mnt/hgfs/peng/rand/code$?./a.out?
1804289383?846930886?1681692777?1714636915?1957747793?424238335?719885386?1649760492?596516649?1189641421?
peng@peng-virtual-machine:/mnt/hgfs/peng/rand/code$?./a.out?
1804289383?846930886?1681692777?1714636915?1957747793?424238335?719885386?1649760492?596516649?1189641421?

要想每次都產(chǎn)生不一樣的隨機(jī)序列應(yīng)該怎么辦呢?需要借助srand()函數(shù)

void?srand(unsigned?int?seed);

只需要通過該函數(shù)設(shè)置一個(gè)種子,那么產(chǎn)生的序列,就會(huì)完全不一樣,

通常我們用time()返回值作為種子,

在此我們隨便寫入幾個(gè)數(shù)據(jù),來測(cè)試下該函數(shù)

#include?<stdio.h>

main()
{
?int?i?=?0;

?srand(111);
?for(i=0;i<10;i++)
?{
??printf("%d?",rand());
?}
?putchar('n');
?srand(1111);
?for(i=0;i<10;i++)
?{
??printf("%d?",rand());
?}
?putchar('n');
}

執(zhí)行結(jié)果如下:

peng@peng-virtual-machine:/mnt/hgfs/peng/rand/code$?./a.out?
1629905861?708017477?1225010071?14444113?324837614?2112273117?1166384513?1539134273?1883039818?779189906?
1383711924?882432674?1555165704?1334863495?1474679554?676796645?154721979?534868285?1892754119?100411878?

可見輸入不同的種子就會(huì)產(chǎn)生不同的序列。

函數(shù)原型如下:

本例原理比較簡(jiǎn)單,沒有考慮太復(fù)雜的應(yīng)用(比如多路密鑰的管理)和數(shù)據(jù)安全性,

只闡述加解密的流程,僅作為學(xué)習(xí)理解加解密流程用,此種加密算法屬于對(duì)稱加密,相對(duì)比較簡(jiǎn)單,還是比較容易破解。

目前市場(chǎng)上都是由專業(yè)的公司和團(tuán)隊(duì)實(shí)現(xiàn)加解密功能。

一口君之前曾寫過聊天室的一個(gè)小項(xiàng)目,《從0實(shí)現(xiàn)基于Linux socket聊天室》

后面一口君會(huì)基于該加密機(jī)制,將聊天室所有客戶端與服務(wù)器所有交互數(shù)據(jù)進(jìn)行加密處理,請(qǐng)大家持續(xù)關(guān)注:一口Linux。

本文完整代碼下載地址:鏈接:https://pan.baidu.com/s/1VvGNlNGEUWWZHQZ1_gYU7A 提取碼:o9se

相關(guān)推薦

登錄即可解鎖
  • 海量技術(shù)文章
  • 設(shè)計(jì)資源下載
  • 產(chǎn)業(yè)鏈客戶資源
  • 寫文章/發(fā)需求
立即登錄

公眾號(hào)『一口Linux』號(hào)主彭老師,擁有15年嵌入式開發(fā)經(jīng)驗(yàn)和培訓(xùn)經(jīng)驗(yàn)。曾任職ZTE,某研究所,華清遠(yuǎn)見教學(xué)總監(jiān)。擁有多篇網(wǎng)絡(luò)協(xié)議相關(guān)專利和軟件著作。精通計(jì)算機(jī)網(wǎng)絡(luò)、Linux系統(tǒng)編程、ARM、Linux驅(qū)動(dòng)、龍芯、物聯(lián)網(wǎng)。原創(chuàng)內(nèi)容基本從實(shí)際項(xiàng)目出發(fā),保持原理+實(shí)踐風(fēng)格,適合Linux驅(qū)動(dòng)新手入門和技術(shù)進(jìn)階。