概述
- 互聯(lián)網(wǎng)時(shí)代,安全成為了一個(gè)沉重的話題。文件傳輸、電子郵件等的安全性尤為重要。我們?yōu)榱吮WC安全性,必須對(duì)其內(nèi)容加密,
- 加密的作用就是防止有用或私有化信息在傳輸鏈路上被攔截和竊取。提高數(shù)據(jù)傳輸?shù)目煽啃浴?/li>
- 在嵌入式開(kāi)發(fā)中,我們會(huì)涉及到數(shù)據(jù)的傳輸,文件的傳輸。很多人都沒(méi)有考慮其數(shù)據(jù)的安全性問(wèn)題,往往都是明文的方式傳輸,最多增加CRC進(jìn)行數(shù)據(jù)的完整性校驗(yàn)。這明顯沒(méi)有考慮數(shù)據(jù)的安全性問(wèn)題。
- 最近項(xiàng)目遇到安全性問(wèn)題,所以也開(kāi)始折磨一下加密相關(guān)知識(shí),發(fā)現(xiàn)RT-THREAD有個(gè)比較好軟件包--tinycrypt(一個(gè)簡(jiǎn)小并且可配置的加解密軟件包,包含算法:aes,base64,md5,sha1,sha2)。其中:AES剛好符合我的項(xiàng)目需求。
AES加密算法
AES加密標(biāo)準(zhǔn)又稱為高級(jí)加密標(biāo)準(zhǔn)Rijndael加密法,是美國(guó)國(guó)家標(biāo)準(zhǔn)技術(shù)研究所NIST旨在取代DES的21世紀(jì)的加密標(biāo)準(zhǔn)。AES的基本要求是,采用對(duì)稱分組密碼體制,密鑰長(zhǎng)度可以為128、192或256位,分組長(zhǎng)度128位。AES算法是最為常見(jiàn)的額對(duì)稱加密算法之一。
AES加密流程說(shuō)明:
AES的加解密流程圖如下:
加解密流程圖部件說(shuō)明:
- 明文P:沒(méi)有經(jīng)過(guò)加密的數(shù)據(jù)或文件。
- 密鑰K:用來(lái)加密明文P的密鑰,在對(duì)稱加密算法中,加密與解密的密鑰是相同的。密鑰為接收方與發(fā)送方協(xié)商產(chǎn)生,但不可以直接在網(wǎng)絡(luò)上傳輸,否則會(huì)導(dǎo)致密鑰泄漏,通常是通過(guò)非對(duì)稱加密算法加密密鑰,然后再通過(guò)網(wǎng)絡(luò)傳輸給對(duì)方,或者直接面對(duì)面商量密鑰。密鑰是絕對(duì)不可以泄漏的,否則會(huì)被攻擊者還原密文,竊取機(jī)密數(shù)據(jù)。
- AES加密函數(shù):設(shè)AES加密函數(shù)為E,則 C = E(K + P),其中P為明文,K為密鑰,C為密文。也就是說(shuō),把明文P和密鑰K作為加密函數(shù)的參數(shù)輸入,則加密函數(shù)E會(huì)輸出密文C。
- 密文C:通過(guò)密鑰對(duì)明文進(jìn)行加密處理后的數(shù)據(jù)或文件。
- AES解密函數(shù):設(shè)AES解密函數(shù)為D,則 P = D(K + C),其中C為密文,K為密鑰,P為明文。也就是說(shuō),把密文C和密鑰K作為解密函數(shù)的參數(shù)輸入,則解密函數(shù)會(huì)輸出明文P。
AES加密方法:
- AES為分組加密,分組加密也就是把明文分成一組一組的,每組的長(zhǎng)度相等,每次加密一組數(shù)據(jù),直到加密完整個(gè)明文。
AES | 密鑰長(zhǎng)度(32bit) | 分組長(zhǎng)度(32bit) | 加密輪數(shù) |
---|---|---|---|
AES-128 | 4 | 4 | 10 |
AES-192 | 6 | 4 | 12 |
AES-256 | 8 | 4 | 14 |
- 在AES標(biāo)準(zhǔn)規(guī)范中,分組長(zhǎng)度只能是128位,也就是說(shuō),每個(gè)分組為16個(gè)字節(jié),每個(gè)字節(jié)8位,密鑰的長(zhǎng)度可以使用128位、192位或者258位。密鑰的長(zhǎng)度不同,推薦加密輪數(shù)也不同,比如AES-128也就是密鑰的長(zhǎng)度為128位,加密輪數(shù)為10輪,AES-192為12輪,AES-256為14輪。以AES-128為例,加密中一輪的4個(gè)操作:
- 字節(jié)代換:AES的字符代換其實(shí)就是一個(gè)簡(jiǎn)單的查表操作,AES定義了一個(gè)S盒和一個(gè)逆S盒。
- 行位移:就是一個(gè)簡(jiǎn)單的左循環(huán)移位操作。
- 列混合:是通過(guò)矩陣相乘來(lái)實(shí)現(xiàn)的,經(jīng)過(guò)移位后的狀態(tài)矩陣與固定的矩陣相乘,得到混淆后的狀態(tài)矩陣。
- 輪密鑰加:是將128位輪密鑰Ki同狀態(tài)矩陣中的數(shù)據(jù)進(jìn)行逐位異或操作。
![ca623e64-b13a-11ed-a826-dac502259ad0.png](https://file1.elecfans.com//web2/M00/99/31/wKgaomTnZlmABv2KAABNueJoWN4731.png)
- 加密:加密第1輪到第9輪的輪函數(shù)一樣,最后一輪迭代不執(zhí)行列混合,另外,在第一輪迭代之前,先將明文和原始密鑰進(jìn)行一次異或加密操作。
- 解密:解密過(guò)程仍為10輪,每一輪的操作是加密操作的逆操作。由于AES的4個(gè)輪操作都是可逆的,因此,解密操作的一輪就是順序執(zhí)行逆行移位、逆字節(jié)代換、輪密鑰加和逆列混合。同加密操作類似,最后一輪不執(zhí)行逆列混合,在第1輪解密之前,要執(zhí)行1次密鑰加操作。
tinycrypt的AES使用
- tinycrypt這個(gè)軟件包精簡(jiǎn)使用起來(lái)很方便,其包含了源碼和測(cè)試用例(AES和MD5),tinycrypt軟件包的目錄結(jié)構(gòu)如下:
.
├──include
│├──tiny_aes.h//aes頭文件
│├──tiny_base64.h//base64頭文件
│├──tinycrypt_config.h//tinycrypt配置頭文件
│├──tinycrypt.h//tinycrypt頭文件
│├──tiny_md5.h//md5頭文件
│├──tiny_sha1.h//sha1頭文件
│└──tiny_sha2.h//sha2頭文件
├──LICENSE
├──README.md
├──samples
│├──aes_sample.c//aes測(cè)試用例頭文件
│└──md5_sample.c//md5測(cè)試用例頭文件
└──src
├──tiny_aes.c//aes源文件
├──tiny_base64.c//base64源文件
├──tiny_md5.c//md5頭文件
├──tiny_sha1.c//sha1頭文件
└──tiny_sha2.c//sha2頭文件
- 在Ubuntu環(huán)境下,搭建tinycrypt的環(huán)境,測(cè)試加解密文件,目錄結(jié)構(gòu)如下:
.
├──main.c
├──makefile
└──tinycrypt
├──include
│├──tiny_aes.h
│├──tiny_base64.h
│├──tinycrypt_config.h
│├──tinycrypt.h
│├──tiny_md5.h
│├──tiny_sha1.h
│└──tiny_sha2.h
├──LICENSE
├──README.md
├──samples
│├──aes_sample.c
│└──md5_sample.c
└──src
├──tiny_aes.c
├──tiny_base64.c
├──tiny_md5.c
├──tiny_sha1.c
└──tiny_sha2.c
-
在目錄中增加makefile文件和main.c,其中makefile用于構(gòu)建工程,main.c用于編寫(xiě)我們的測(cè)試代碼,其中:
-
makefile文件內(nèi)容:
VERSION=1.0.0#版本號(hào)
SOURCE=main.c#源文件
SOURCE+=$(wildcard./tinycrypt/src/*.c)#通過(guò)wildcard函數(shù)獲取tinycrypt源文件
OBJECT=$(patsubst%.c,%.o,$(SOURCE))#通過(guò)patsubst函數(shù)替換源文件為目標(biāo)文件
INCLUDE=-I./tinycrypt/include#包含頭文件路徑
TARGET=tinycrypt#目標(biāo)文件名字
CC=gcc#工具鏈
CFLAGS=-Wall-g#編譯選項(xiàng)
OUTPUT=output#輸出目錄
$(TARGET):$(OBJECT)#構(gòu)建執(zhí)行命令
@mkdir-p$(OUTPUT)#創(chuàng)建輸出目錄
$(CC)$^$(CFLAGS)-o$(OUTPUT)/$(TARGET)_$(VERSION)#編譯
%.o:%.c#將源文件編譯成目標(biāo)文件
$(CC)$(INCLUDE)$(CFLAGS)-c$-o?$@??????????????????
.PHONY:clean????????????????????????????????????????????????#?執(zhí)行make?clean之后,清除過(guò)程文件
clean:
?@rm?-rf?$(OBJECT)?$(OUTPUT)
- main.c文件內(nèi)容,測(cè)試歷程說(shuō)明:將一個(gè)文件(index.js)通過(guò)AES加密,然后生成加密文件(encrypt_index.js),再將加密文件(encrypt_index.js)通過(guò)AES解密,生成解密文件(decrypt_index.js)。
#include
#include
#include
#include
#include
#include
#include
#include
#include"tiny_aes.h"
#defineENCRYPT_TEST_FILE"./index.js"
#defineENCRYPT_TEST_ENCRYPT_FILE"./encrypt_index.js"
#defineENCRYPT_TEST_DECRYPT_FILE"./decrypt_index.js"
#defineENCRYPT_SINGLE_SIZE1024//加密單包長(zhǎng)度
#defineENCRYPT_AES_IV_LEN16//AES向量長(zhǎng)度
#defineENCRYPT_AES_KEY_LEN256//AES密鑰長(zhǎng)度
#defineENCRYPT_AES_IV"0123456789ABCDEF"//AES向量
#defineENCRYPT_AES_KEY"0123456789ABCDEF0123456789ABCDEF"//AES密鑰
//AES參數(shù)結(jié)構(gòu)體定義
typedefstruct
{
uint8_taesIv[ENCRYPT_AES_IV_LEN];
uint8_taesKey[ENCRYPT_AES_KEY_LEN];
tiny_aes_contextaes_ctx;
}EncryptInfo;
staticEncryptInfog_info={0};
//aes參數(shù)初始化
voidaes_init(constchar*iv,constchar*key)
{
memset(g_info.aesIv,0,ENCRYPT_AES_IV_LEN);
memset(g_info.aesKey,0,ENCRYPT_AES_KEY_LEN);
if(iv==NULL){
memcpy(g_info.aesIv,ENCRYPT_AES_IV,strlen(ENCRYPT_AES_IV));
}
else{
memcpy(g_info.aesIv,iv,strlen(iv));
}
if(key==NULL){
memcpy(g_info.aesKey,ENCRYPT_AES_KEY,strlen(ENCRYPT_AES_KEY));
}
else{
memcpy(g_info.aesKey,key,strlen(key));
}
}
//aes加密函數(shù)的封裝
voidaes_encrypt(uint8_t*dest_buff,constuint8_t*src_buff,uint32_tlen)
{
tiny_aes_crypt_cbc(&g_info.aes_ctx,AES_ENCRYPT,len,g_info.aesIv,(uint8_t*)src_buff,dest_buff);
}
//aes解密函數(shù)的封裝
voidaes_decrypt(uint8_t*dest_buff,constuint8_t*src_buff,uint32_tlen)
{
tiny_aes_crypt_cbc(&g_info.aes_ctx,AES_DECRYPT,len,g_info.aesIv,(uint8_t*)src_buff,dest_buff);
}
intmain(intargc,char*argv[])
{
intraw_size=0;
intsrc_fd=-1;
intencrypt_fd=-1;
intdecrypt_fd=-1;
intsrc_file_size=0;
intsrv_file_offset=0;
uint8_tsrc_buff[ENCRYPT_SINGLE_SIZE];
uint8_tencrypt_buff[ENCRYPT_SINGLE_SIZE];
uint8_tdecrypt_buff[ENCRYPT_SINGLE_SIZE];
//加密文件,將明文文件(index.js)通過(guò)AES加密為加密文件(encrypt_index.js)
{
aes_init(NULL,NULL);//aes初始化
tiny_aes_setkey_enc(&g_info.aes_ctx,(uint8_t*)g_info.aesKey,ENCRYPT_AES_KEY_LEN);//設(shè)置密鑰
src_fd=open(ENCRYPT_TEST_FILE,O_RDONLY,0777);//打開(kāi)明文文件
if(src_fd==-1){
printf("%d-ERR:openfile(%s)failedrn",__LINE__,ENCRYPT_TEST_FILE);
return-1;
}
encrypt_fd=open(ENCRYPT_TEST_ENCRYPT_FILE,O_RDWR|O_CREAT|O_TRUNC,0777);//打開(kāi)加密文件
if(encrypt_fd==-1){
printf("%d-ERR:openfile(%s)failedrn",__LINE__,ENCRYPT_TEST_ENCRYPT_FILE);
return-1;
}
raw_size=lseek(src_fd,0,SEEK_END);//獲取明文文件的大小
srv_file_offset=0;
lseek(src_fd,0,SEEK_SET);
printf("%d-INFO:sourcefilesize:%drn",__LINE__,raw_size);
while(srv_file_offsetmemset(src_buff,0,ENCRYPT_SINGLE_SIZE);
memset(encrypt_buff,0,ENCRYPT_SINGLE_SIZE);
read(src_fd,src_buff,ENCRYPT_SINGLE_SIZE);//讀取明文文件內(nèi)容
aes_encrypt(encrypt_buff,src_buff,ENCRYPT_SINGLE_SIZE);//明文文件內(nèi)容加密
write(encrypt_fd,encrypt_buff,ENCRYPT_SINGLE_SIZE);//將加密內(nèi)容寫(xiě)入加密文件中
srv_file_offset+=ENCRYPT_SINGLE_SIZE;
}
close(src_fd);
src_fd=-1;
close(encrypt_fd);
encrypt_fd=-1;
}
//解密文件,將加密文件(encrypt_index.js)通過(guò)AES解密為解密文件(decrypt_index.js)
{
aes_init(NULL,NULL);//aes初始化
tiny_aes_setkey_dec(&g_info.aes_ctx,(uint8_t*)g_info.aesKey,ENCRYPT_AES_KEY_LEN);//設(shè)置密鑰
src_fd=open(ENCRYPT_TEST_ENCRYPT_FILE,O_RDONLY,0777);//打開(kāi)密文文件
if(src_fd==-1){
printf("%d-ERR:openfile(%s)failedrn",__LINE__,ENCRYPT_TEST_ENCRYPT_FILE);
return-1;
}
decrypt_fd=open(ENCRYPT_TEST_DECRYPT_FILE,O_RDWR|O_CREAT|O_TRUNC,0777);//打開(kāi)解密文件
if(decrypt_fd==-1){
printf("%d-ERR:openfile(%s)failedrn",__LINE__,ENCRYPT_TEST_DECRYPT_FILE);
return-1;
}
src_file_size=raw_size;//設(shè)置明文文件的大小
srv_file_offset=0;
lseek(src_fd,0,SEEK_SET);
printf("%d-INFO:encryptfilesize:%drn",__LINE__,src_file_size);
while(srv_file_offsetmemset(src_buff,0,ENCRYPT_SINGLE_SIZE);
memset(decrypt_buff,0,ENCRYPT_SINGLE_SIZE);
if((srv_file_offset+ENCRYPT_SINGLE_SIZE)//讀取密文文件內(nèi)容
aes_decrypt(decrypt_buff,src_buff,ENCRYPT_SINGLE_SIZE);//密文文件解密
write(decrypt_fd,decrypt_buff,ENCRYPT_SINGLE_SIZE);//將解密內(nèi)容寫(xiě)入解密文件中
srv_file_offset+=ENCRYPT_SINGLE_SIZE;
}
else
{
read(src_fd,src_buff,ENCRYPT_SINGLE_SIZE);//讀取最后一包密文文件內(nèi)容
aes_decrypt(decrypt_buff,src_buff,(ENCRYPT_SINGLE_SIZE));//密文文件解密
write(decrypt_fd,decrypt_buff,(src_file_size-srv_file_offset));//將最后一包解密內(nèi)容寫(xiě)入解密文件中
break;
}
}
close(src_fd);
src_fd=-1;
close(decrypt_fd);
decrypt_fd=-1;
}
return0;
}
-
驗(yàn)證時(shí)發(fā)現(xiàn)一個(gè)問(wèn)題,加密內(nèi)容的長(zhǎng)度需要16字節(jié)的整數(shù)倍,所以加密完的文件大小也為16字節(jié)的整數(shù)倍。值得注意的是,解密的最后一包要根據(jù)明文文件的大小算出來(lái)的,然后寫(xiě)進(jìn)解密文件中,因?yàn)榧用芪募?6字節(jié)對(duì)齊的,所以要去除16字節(jié)對(duì)齊。
-
編譯及運(yùn)行:
rice@rice:~/project/encrypt$make
gcc-I./tinycrypt/include-Wall-g-cmain.c-omain.o
gcc-I./tinycrypt/include-Wall-g-ctinycrypt/src/tiny_sha1.c-otinycrypt/src/tiny_sha1.o
gcc-I./tinycrypt/include-Wall-g-ctinycrypt/src/tiny_aes.c-otinycrypt/src/tiny_aes.o
gcc-I./tinycrypt/include-Wall-g-ctinycrypt/src/tiny_md5.c-otinycrypt/src/tiny_md5.o
gcc-I./tinycrypt/include-Wall-g-ctinycrypt/src/tiny_sha2.c-otinycrypt/src/tiny_sha2.o
gcc-I./tinycrypt/include-Wall-g-ctinycrypt/src/tiny_base64.c-otinycrypt/src/tiny_base64.o
gccmain.otinycrypt/src/tiny_sha1.otinycrypt/src/tiny_aes.otinycrypt/src/tiny_md5.otinycrypt/src/tiny_sha2.otinycrypt/src/tiny_base64.o-Wall-g-ooutput/tinycrypt_1.0.0
rice@rice:~/ohos/project/encrypt$./output/tinycrypt_1.0.0
136-INFO:sourcefilesize:445
171-INFO:encryptfilesize:445
rice@rice:~/ohos/project/encrypt$
- 演示結(jié)果:
![ca7fbeb2-b13a-11ed-a826-dac502259ad0.png](https://file1.elecfans.com//web2/M00/99/31/wKgaomTnZlmAPm6_AAGxWBSAlO4754.png)
結(jié)論:
- 通過(guò)加密方式,提高數(shù)據(jù)的安全性,避免了數(shù)據(jù)的泄露
- AES加密方式,加密內(nèi)容的長(zhǎng)度需要16字節(jié)的整數(shù)倍,加密之后長(zhǎng)度比實(shí)際明文可能要長(zhǎng)。所以明文的長(zhǎng)度需要告知解密方。
- AES是對(duì)稱加密,所以加密方和解密方的密鑰需要一直。
審核編輯黃宇
-
數(shù)據(jù)傳輸
+關(guān)注
關(guān)注
9文章
1962瀏覽量
64867 -
加密
+關(guān)注
關(guān)注
0文章
305瀏覽量
24020
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
請(qǐng)問(wèn)NFC數(shù)據(jù)傳輸如何保證數(shù)據(jù)安全?
無(wú)線數(shù)據(jù)傳輸模塊的實(shí)際應(yīng)用
如何利用MEMS和FPGA設(shè)計(jì)移動(dòng)硬盤(pán)數(shù)據(jù)加解密系統(tǒng)?
mbedtls開(kāi)源庫(kù)在單片機(jī)的數(shù)據(jù)加解密中有何作用
硬件加解密主要優(yōu)點(diǎn)及引擎種類
STM32加解密技術(shù)
數(shù)據(jù)傳輸介質(zhì)
基于MEMS和FPGA的移動(dòng)硬盤(pán)數(shù)據(jù)加解密系統(tǒng)
![基于MEMS和FPGA的移動(dòng)硬盤(pán)<b class='flag-5'>數(shù)據(jù)</b><b class='flag-5'>加解密</b>系統(tǒng)](https://file1.elecfans.com//web2/M00/A5/59/wKgZomUMOAKAWPFnAABipNKsmgU138.jpg)
IDE數(shù)據(jù)傳輸模式
Modem數(shù)據(jù)傳輸標(biāo)準(zhǔn)
數(shù)據(jù)傳輸,數(shù)據(jù)傳輸的工作方式有哪些?
數(shù)據(jù)傳輸速率是什么意思
網(wǎng)絡(luò)高效安全數(shù)據(jù)傳輸方法設(shè)計(jì)
![網(wǎng)絡(luò)高效<b class='flag-5'>安全數(shù)據(jù)傳輸</b>方法設(shè)計(jì)](https://file1.elecfans.com//web2/M00/A5/D0/wKgZomUMOj6AaFZ7AABxrV9wHwo059.jpg)
評(píng)論