概述
- 互联网时代,安全成为了一个沉重的话题。文件传输、电子邮件等的安全性尤为重要。我们为了保证安全性,必须对其内容加密,
- 加密的作用就是防止有用或私有化信息在传输链路上被拦截和窃取。提高数据传输的可靠性。
- 在嵌入式开发中,我们会涉及到数据的传输,文件的传输。很多人都没有考虑其数据的安全性问题,往往都是明文的方式传输,最多增加CRC进行数据的完整性校验。这明显没有考虑数据的安全性问题。
- 最近项目遇到安全性问题,所以也开始折磨一下加密相关知识,发现RT-THREAD有个比较好软件包--tinycrypt(一个简小并且可配置的加解密软件包,包含算法:aes,base64,md5,sha1,sha2)。其中:AES刚好符合我的项目需求。
AES加密算法
AES加密标准又称为高级加密标准Rijndael加密法,是美国国家标准技术研究所NIST旨在取代DES的21世纪的加密标准。AES的基本要求是,采用对称分组密码体制,密钥长度可以为128、192或256位,分组长度128位。AES算法是最为常见的额对称加密算法之一。
AES加密流程说明:
AES的加解密流程图如下:
加解密流程图部件说明:
- 明文P:没有经过加密的数据或文件。
- 密钥K:用来加密明文P的密钥,在对称加密算法中,加密与解密的密钥是相同的。密钥为接收方与发送方协商产生,但不可以直接在网络上传输,否则会导致密钥泄漏,通常是通过非对称加密算法加密密钥,然后再通过网络传输给对方,或者直接面对面商量密钥。密钥是绝对不可以泄漏的,否则会被攻击者还原密文,窃取机密数据。
- AES加密函数:设AES加密函数为E,则 C = E(K + P),其中P为明文,K为密钥,C为密文。也就是说,把明文P和密钥K作为加密函数的参数输入,则加密函数E会输出密文C。
- 密文C:通过密钥对明文进行加密处理后的数据或文件。
- AES解密函数:设AES解密函数为D,则 P = D(K + C),其中C为密文,K为密钥,P为明文。也就是说,把密文C和密钥K作为解密函数的参数输入,则解密函数会输出明文P。
AES加密方法:
- AES为分组加密,分组加密也就是把明文分成一组一组的,每组的长度相等,每次加密一组数据,直到加密完整个明文。
AES | 密钥长度(32bit) | 分组长度(32bit) | 加密轮数 |
---|---|---|---|
AES-128 | 4 | 4 | 10 |
AES-192 | 6 | 4 | 12 |
AES-256 | 8 | 4 | 14 |
- 在AES标准规范中,分组长度只能是128位,也就是说,每个分组为16个字节,每个字节8位,密钥的长度可以使用128位、192位或者258位。密钥的长度不同,推荐加密轮数也不同,比如AES-128也就是密钥的长度为128位,加密轮数为10轮,AES-192为12轮,AES-256为14轮。以AES-128为例,加密中一轮的4个操作:
- 字节代换:AES的字符代换其实就是一个简单的查表操作,AES定义了一个S盒和一个逆S盒。
- 行位移:就是一个简单的左循环移位操作。
- 列混合:是通过矩阵相乘来实现的,经过移位后的状态矩阵与固定的矩阵相乘,得到混淆后的状态矩阵。
- 轮密钥加:是将128位轮密钥Ki同状态矩阵中的数据进行逐位异或操作。
- 加密:加密第1轮到第9轮的轮函数一样,最后一轮迭代不执行列混合,另外,在第一轮迭代之前,先将明文和原始密钥进行一次异或加密操作。
- 解密:解密过程仍为10轮,每一轮的操作是加密操作的逆操作。由于AES的4个轮操作都是可逆的,因此,解密操作的一轮就是顺序执行逆行移位、逆字节代换、轮密钥加和逆列混合。同加密操作类似,最后一轮不执行逆列混合,在第1轮解密之前,要执行1次密钥加操作。
tinycrypt的AES使用
- tinycrypt这个软件包精简使用起来很方便,其包含了源码和测试用例(AES和MD5),tinycrypt软件包的目录结构如下:
.
├──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测试用例头文件
│└──md5_sample.c//md5测试用例头文件
└──src
├──tiny_aes.c//aes源文件
├──tiny_base64.c//base64源文件
├──tiny_md5.c//md5头文件
├──tiny_sha1.c//sha1头文件
└──tiny_sha2.c//sha2头文件
- 在Ubuntu环境下,搭建tinycrypt的环境,测试加解密文件,目录结构如下:
.
├──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用于构建工程,main.c用于编写我们的测试代码,其中:
-
makefile文件内容:
VERSION=1.0.0#版本号
SOURCE=main.c#源文件
SOURCE+=$(wildcard./tinycrypt/src/*.c)#通过wildcard函数获取tinycrypt源文件
OBJECT=$(patsubst%.c,%.o,$(SOURCE))#通过patsubst函数替换源文件为目标文件
INCLUDE=-I./tinycrypt/include#包含头文件路径
TARGET=tinycrypt#目标文件名字
CC=gcc#工具链
CFLAGS=-Wall-g#编译选项
OUTPUT=output#输出目录
$(TARGET):$(OBJECT)#构建执行命令
@mkdir-p$(OUTPUT)#创建输出目录
$(CC)$^$(CFLAGS)-o$(OUTPUT)/$(TARGET)_$(VERSION)#编译
%.o:%.c#将源文件编译成目标文件
$(CC)$(INCLUDE)$(CFLAGS)-c$< -o $@
.PHONY:clean # 执行make clean之后,清除过程文件
clean:
@rm -rf $(OBJECT) $(OUTPUT)
- main.c文件内容,测试历程说明:将一个文件(index.js)通过AES加密,然后生成加密文件(encrypt_index.js),再将加密文件(encrypt_index.js)通过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//加密单包长度
#defineENCRYPT_AES_IV_LEN16//AES向量长度
#defineENCRYPT_AES_KEY_LEN256//AES密钥长度
#defineENCRYPT_AES_IV"0123456789ABCDEF"//AES向量
#defineENCRYPT_AES_KEY"0123456789ABCDEF0123456789ABCDEF"//AES密钥
//AES参数结构体定义
typedefstruct
{
uint8_taesIv[ENCRYPT_AES_IV_LEN];
uint8_taesKey[ENCRYPT_AES_KEY_LEN];
tiny_aes_contextaes_ctx;
}EncryptInfo;
staticEncryptInfog_info={0};
//aes参数初始化
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加密函数的封装
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解密函数的封装
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)通过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);//设置密钥
src_fd=open(ENCRYPT_TEST_FILE,O_RDONLY,0777);//打开明文文件
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);//打开加密文件
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_offset< raw_size) {
memset(src_buff,0,ENCRYPT_SINGLE_SIZE);
memset(encrypt_buff,0,ENCRYPT_SINGLE_SIZE);
read(src_fd,src_buff,ENCRYPT_SINGLE_SIZE);//读取明文文件内容
aes_encrypt(encrypt_buff,src_buff,ENCRYPT_SINGLE_SIZE);//明文文件内容加密
write(encrypt_fd,encrypt_buff,ENCRYPT_SINGLE_SIZE);//将加密内容写入加密文件中
srv_file_offset+=ENCRYPT_SINGLE_SIZE;
}
close(src_fd);
src_fd=-1;
close(encrypt_fd);
encrypt_fd=-1;
}
//解密文件,将加密文件(encrypt_index.js)通过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);//设置密钥
src_fd=open(ENCRYPT_TEST_ENCRYPT_FILE,O_RDONLY,0777);//打开密文文件
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);//打开解密文件
if(decrypt_fd==-1){
printf("%d-ERR:openfile(%s)failedrn",__LINE__,ENCRYPT_TEST_DECRYPT_FILE);
return-1;
}
src_file_size=raw_size;//设置明文文件的大小
srv_file_offset=0;
lseek(src_fd,0,SEEK_SET);
printf("%d-INFO:encryptfilesize:%drn",__LINE__,src_file_size);
while(srv_file_offset< src_file_size) {
memset(src_buff,0,ENCRYPT_SINGLE_SIZE);
memset(decrypt_buff,0,ENCRYPT_SINGLE_SIZE);
if((srv_file_offset+ENCRYPT_SINGLE_SIZE)< src_file_size)
{
read(src_fd, src_buff, ENCRYPT_SINGLE_SIZE); //读取密文文件内容
aes_decrypt(decrypt_buff,src_buff,ENCRYPT_SINGLE_SIZE);//密文文件解密
write(decrypt_fd,decrypt_buff,ENCRYPT_SINGLE_SIZE);//将解密内容写入解密文件中
srv_file_offset+=ENCRYPT_SINGLE_SIZE;
}
else
{
read(src_fd,src_buff,ENCRYPT_SINGLE_SIZE);//读取最后一包密文文件内容
aes_decrypt(decrypt_buff,src_buff,(ENCRYPT_SINGLE_SIZE));//密文文件解密
write(decrypt_fd,decrypt_buff,(src_file_size-srv_file_offset));//将最后一包解密内容写入解密文件中
break;
}
}
close(src_fd);
src_fd=-1;
close(decrypt_fd);
decrypt_fd=-1;
}
return0;
}
-
验证时发现一个问题,加密内容的长度需要16字节的整数倍,所以加密完的文件大小也为16字节的整数倍。值得注意的是,解密的最后一包要根据明文文件的大小算出来的,然后写进解密文件中,因为加密文件是16字节对齐的,所以要去除16字节对齐。
-
编译及运行:
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$
- 演示结果:
结论:
- 通过加密方式,提高数据的安全性,避免了数据的泄露
- AES加密方式,加密内容的长度需要16字节的整数倍,加密之后长度比实际明文可能要长。所以明文的长度需要告知解密方。
- AES是对称加密,所以加密方和解密方的密钥需要一直。
审核编辑黄宇
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。
举报投诉
-
数据传输
+关注
关注
9文章
1823浏览量
64463 -
加密
+关注
关注
0文章
302浏览量
23895
发布评论请先 登录
相关推荐
无线数据传输模块的实际应用
,使设备厂商可以远程随时随地对设备进行监控、升级和维护等操作,无线数据传输模块又将这些监测的数据传输给处理系统,是用户可以了解产品的使用状况,完成产品全生命周期的信息收集,指导产品设计和售后服务
发表于 06-18 04:21
如何利用MEMS和FPGA设计移动硬盘数据加解密系统?
来源:维库电子随着信息量的急剧增长,信息安全日益受到人们重视。一个完整的数据加解密系统应该 具备安全可靠的密码认证机制和
发表于 07-31 07:40
硬件加解密主要优点及引擎种类
IoT联网装置日渐普及,大家在享受联网装置所带来便利性的同时,也必须同时承担联网装置的风险,即数据在传输过程可能遭窃取、伪造,因此数据传输过程的安全性,对于IoT联网装置是基本的要求,
发表于 08-28 07:29
STM32加解密技术
没有加解密技术是万万不能的• 通讯安全• 平台安全• *例外:STM32 RDP保护知识产权• 加解密技术不是万能的• 只是工具• 无法代替其它STM32
发表于 09-08 08:18
基于MEMS和FPGA的移动硬盘数据加解密系统
基于MEMS和FPGA的移动硬盘数据加解密系统
随着信息量的急剧增长,信息安全日益受到人们重视。一个完整的数据加解密系统应该 具备
发表于 11-05 08:57
•763次阅读
评论