1. 介绍
SCE 部件作为飞腾平台的平安组件,提供了对称算法加速器 (SCA)、哈希算法加速器(HASH)、非对称算法加速器(ACA) 和真随机数生成器(TRNG)。
用户通过 Linux Kernel Crypto API 框架实现内核对各种算法驱动的反对,目前内核态已实现 SCA、HASH、TRNG 反对的算法驱动。通过装置 SCE 内核层驱动可查看已反对的算法驱动,利用开发者可通过相应的内核态接口实现对算法模块的调用。
2. 装置与测试
2.1 硬件及零碎要求
硬件要求如下表所示。
我的项目 | 阐明 |
---|---|
CPU | 飞腾平台 CPU |
已支持系统 | 1、Ubuntu 22.04(kernel 4.19.0) |
存储 | 无要求 |
内存 | 无要求 |
2.2 软件目录架构
软件目录架构如图所示:
1.src 文件夹:驱动模块源码。
2.include 文件夹:驱动模块头文件。
3.test 文件夹:内核层驱动测试代码。
2.3 内核驱动算法概述
目前反对的内核态驱动算法如下表所示。
加速器 | 算法 | 算法名 | 驱动名 |
---|---|---|---|
对称引擎 | SM4 | ecb(sm4) cbc(sm4) ctr(sm4) ofb(sm4) |
ecb(sm4)-phytium cbc(sm4)phytium ctr(sm4)-phytium ofb(sm4)-phytium |
对称引擎 | AES | ecb(aes) cbc(aes) ctr(aes) ofb(aes) |
ecb(aes)-phytium cbc(aes)phytium ctr(aes)-phytium ofb(aes)-phytium |
对称引擎 | DES | ecb(des) cbc(des) ctr(des) ofb(des) ecb(des3_ede) cbc(des3_ede) ctr(des3_ede) ofb(des3_ede) |
ecb(aes)-phytium cbc(aes)phytium ctr(aes)-phytium ofb(aes)-phytium ecb(des3_ede)-phytium cbc(des3_ede)-phytium ctr(des3_ede)-phytium ofb(des3_ede)-phytium |
哈希引擎 | DES | ecb(des) cbc(des) ctr(des) ofb(des) ecb(des3_ede) cbc(des3_ede) ctr(des3_ede) ofb(des3_ede) |
ecb(des)-phytium cbc(des)-phytium ctr(des)-phytium ofb(des)-phytium ecb(des3_ede)-phytium cbc(des3_ede)-phytium ctr(des3_ede)-phytium ofb(des3_ede)-phytium |
哈希引擎 | SHA | sha1 sha224 sha256 sha384 sha512 md5 hmac(sha1) hmac(sha224) hmac(sha256) hmac(sha384) hmac(sha512) hmac(md5) |
sha1-phytium sha224-phytium sha256-phytium sha384-phytium sha512-phytium md5-phytium hmac(sha1)-phytium hmac(sha224)-phytium hmac(sha256)-phytium hmac(sha384)-phytium hmac(sha512)-phytium hmac(md5)-phytium |
哈希引擎 | SM3 | sm3 hmac(sm3) |
sm3-phytium hmac(sm3)-phytium |
真随机数生成器 | TRNG | TRNG | trng-phytium |
2.4 内核层编译、装置与测试
1.SCE 内核层内核驱动编译装置步骤
进入驱动代码目录
cd driver
# 编译驱动模块
make
# 加载驱动模块
sudo insmod phytium_sce.ko
# 抉择应用内核层驱动模块
# 驱动模块反对用户态和内核态切换
# 通过操作 /proc/sce_dir/sce_work_state 管制
# 输出 1 启用内核态模块,输出 2 启用用户态模块,输出 0 敞开所有模块
sudo echo 1 > /proc/sce_dir/sce_work_state
# 查看驱动模块以后模式
cat /proc/sce_dir/sce_work_state
# 查看内核反对的 SCE 算法驱动
cat /proc/crypto | grep phytium
2.SCE 内核态接口编译装置
# 进入内核态测试代码目录
cd driver/test
# 编译测试模块
make
# 在执行 mtest.ko 前必须先加载好内核驱动模块
# 执行 mtest.ko 时通过传入参数可反对对不同算法进行功能性测试
# 倡议关上两个终端窗口 A 和 B,其中可在 A 终端输出测试命令,B 终端执行命令“sudo dmesg -w”sudo insmod mtest.ko #当在终端 A 执行该命令之后,可在终端 B 查到到内核打印信息,其中表明须要传入的参数信息
#示例命令,对 hash 进行功能测试
sudo insmod mtest.ko alg=sm3 mode=hash
3 SCE 内核态 API 阐明
该章节介绍 SCE 内核态 API 接口,接口的应用示例可浏览参考 kernel/test 目录下的测试用例。
3.1 哈希算法
3.1.1 调配哈希算法对象
函数原型 | struct crypto_ahash *crypto_alloc_ahash(const char *alg_name, u32 type, u32 mask) |
函数性能 | 调配一个新创建的异步哈希算法实例 |
输出阐明 | alg_name – 算法名 type – 算法类型 mask – 算法类型屏蔽字 |
输入阐明 | 无 |
返回值阐明 | 新创建的异步哈希算法对象 |
应用阐明 | |
注意事项 | hash 算法能够是同步形式实现或异步形式实现,但算法利用不关注 hash 算法的实现形式,而是关注 hash 算法提供的算法接口。为实现对立治理,加密框架默认 hash 算法的实现形式为异步形式,将哈希算法的内部接口对立定义为异步哈希算法接口 |
3.1.2 调配哈希算法数据申请对象
函数原型 | struct ahash_request *ahash_request_alloc(struct crypto_ahash *tfm, gfp_t gfp) |
函数性能 | 调配申请数据结构 |
输出阐明 | tfm – 算法实例 gfp – API 调用传递给 kmalloc 的内存调配标记 |
输入阐明 | 无 |
返回值阐明 | 胜利时返回调配的申请句柄,如果内存不足则返回 NULL |
应用阐明 | |
注意事项 | 若为同步调用的形式,则不须要调配创立 req 对象 |
3.1.3 设置异步回调
函数原型 | void ahash_request_set_callback(struct ahash_request *req, u32 flags,crypto_completion_t compl, void *data) |
函数性能 | 用于设置加解密实现后须要调用的回调函数 |
输出阐明 | req – 申请句柄 flags - 标记位,指定为 0 或 ORing compl - 注册到申请句柄的回调函数指针 data – 指向内核加密 API 不应用的内存 |
输入阐明 | 无 |
返回值阐明 | 无 |
应用阐明 | |
注意事项 |
3.1.4 设置密钥
函数原型 | int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key, unsigned int keylen) |
函数性能 | 设置密钥 |
输出阐明 | tfm – 算法实例 key – 密钥数据 keylen – 密钥数据长度 |
输入阐明 | 无 |
返回值阐明 | 胜利时返回调配的申请句柄,如果内存不足则返回 NULL |
应用阐明 | |
注意事项 |
3.1.5 设置数据
函数原型 | void ahash_request_set_crypt(struct ahash_request *req, struct scatterlist *src, u8 *result, unsigned int nbytes) |
函数性能 | 设置数据内存 |
输出阐明 | req – 申请句柄 src – 源扩散 / 收集列表 result – 由音讯摘要填充的缓冲区 nbytes – 从 @src 解决的字节数 |
输入阐明 | 无 |
返回值阐明 | 无 |
应用阐明 | |
注意事项 |
3.1.6 性能接口
函数原型 | int crypto_ahash_init(struct ahash_request *req) int crypto_ahash_digest(struct ahash_request *req) int crypto_ahash_update(struct ahash_request *req) int crypto_ahash_finup(struct ahash_request *req) int crypto_ahash_final(struct ahash_request *req) |
函数性能 | init:初始化音讯摘要 digest:计算缓冲区的音讯摘要 update:向音讯摘要中增加数据以进行解决 finup:更新和实现音讯摘要 final:计算音讯摘要 |
输出阐明 | req – ahash_request 句柄 |
输入阐明 | 无 |
返回值阐明 | 胜利计算音讯摘要返回 0,非 0 为 失败 |
应用阐明 | hash 算法最终摘要值生成接口能够有多种调用形式,如 crypto_ahash_digest 示意在该接口中会实现生成摘要相干的所有流程。当然该操作也可拆分为 init、update、final 或 init、update、finup 类型的步骤,步骤拆分当前就能够反对在 init 之后执行屡次 update,以间断为 hash 操作提供数据,并在数据更新实现后调用 final 操作获取所有数据的最终 hash 值 |
注意事项 |
3.1.7 开释 req 资源
函数原型 | void ahash_request_free(struct ahash_request *req) |
函数性能 | 开释 req 资源 |
输出阐明 | req – ahash_request 句柄 |
输入阐明 | 无 |
返回值阐明 | 无 |
应用阐明 | |
注意事项 |
3.1.8 开释 tfm 资源
函数原型 | void crypto_free_ahash(struct crypto_ahash *tfm) |
函数性能 | 开释 tfm 资源 |
输出阐明 | tfm - 算法实例 |
输入阐明 | 无 |
返回值阐明 | 无 |
应用阐明 | |
注意事项 |
3.2 对称算法
3.2.1 调配对称算法对象
函数原型 | struct crypto_skcipher *crypto_alloc_skcipher(const char *alg_name, u32 type, u32 mask) |
函数性能 | 调配一个新创建的对称算法实例 |
输出阐明 | alg_name – 算法名 type – 算法类型 mask – 算法类型屏蔽字 |
输入阐明 | 无 |
返回值阐明 | 新创建的算法实例 |
应用阐明 | |
注意事项 |
3.2.2 调配对称算法数据申请对象
函数原型 | struct skcipher_request *skcipher_request_alloc(struct crypto_skcipher *tfm, gfp_t gfp) |
函数性能 | 调配 req |
输出阐明 | tfm – 算法实例 gfp – API 调用传递给 kmalloc 的内存调配标记 |
输入阐明 | 无 |
返回值阐明 | 胜利时返回调配的申请句柄,如果内存不足则返回 NULL |
应用阐明 | |
注意事项 |
3.2.3 设置异步回调
函数原型 | void skcipher_request_set_callback(struct skcipher_request *req, u32 flags, crypto_completion_t compl, void *data) |
函数性能 | 用于设置加解密实现后须要调用的回调函数 |
输出阐明 | req – 申请句柄 flags - 标记位,指定为 0 或 ORing compl - 注册到申请句柄的回调函数指针 data – 指向内核加密 API 不应用的内存 |
输入阐明 | 无 |
返回值阐明 | 无 |
应用阐明 | |
注意事项 |
3.2.4 设置密钥
函数原型 | int crypto_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, unsigned int keylen) |
函数性能 | 设置密钥 |
输出阐明 | tfm – 算法实例 key – 密钥数据 keylen – 密钥数据长度 |
输入阐明 | 无 |
返回值阐明 | 胜利时返回调配的申请句柄,如果内存不足则返回 NULL |
应用阐明 | |
注意事项 |
3.2.5 设置数据
函数原型 | void skcipher_request_set_crypt(struct skcipher_request *req, struct scatterlist *src, struct scatterlist *dst, unsigned int cryptlen, void *iv) |
函数性能 | 设置数据内存 |
输出阐明 | req – 申请句柄 src – 源扩散 / 收集列表 dst – 指标扩散 / 收集列表 cryptlen – 从 @src 解决的字节数 iv – IV 数据,必须合乎 crypto_skcipher_ivsize 定义的 IV 大小 |
输入阐明 | 无 |
返回值阐明 | 无 |
应用阐明 | |
注意事项 |
3.2.6 加密
函数原型 | int crypto_skcipher_encrypt(struct skcipher_request *req) |
函数性能 | 加密流程 |
输出阐明 | req – 申请句柄 |
输入阐明 | 无 |
返回值阐明 | 胜利加密返回 0,非 0 为失败 |
应用阐明 | |
注意事项 |
3.2.7 解密
函数原型 | int crypto_skcipher_decrypt(struct skcipher_request *req) |
函数性能 | 解密流程 |
输出阐明 | req – 申请句柄 |
输入阐明 | 无 |
返回值阐明 | 胜利解密返回 0,非 0 为失败 |
应用阐明 | |
注意事项 |
3.2.8 开释 req 资源
函数原型 | void skcipher_request_free(struct skcipher_request *req) |
函数性能 | 开释 req 资源 |
输出阐明 | req – 申请句柄 |
输入阐明 | 无 |
返回值阐明 | 无 |
应用阐明 | |
注意事项 |
3.2.9 开释 tfm 资源
函数原型 | void crypto_free_skcipher(struct crypto_skcipher *tfm) |
函数性能 | 开释 tfm 资源 |
输出阐明 | tfm - 算法实例 |
输入阐明 | 无 |
返回值阐明 | 无 |
应用阐明 | |
注意事项 |
3.3 真随机数生成器
3.3.1 调配真随机数生成器对象
函数原型 | struct crypto_rng *crypto_alloc_rng(const char *alg_name, u32 type, u32 mask) |
函数性能 | 调配一个新创建的 TRNG 实例 |
输出阐明 | alg_name – 算法名 type – 算法类型 mask – 算法类型屏蔽字 |
输入阐明 | 无 |
返回值阐明 | 新创建的算法实例 |
应用阐明 | |
注意事项 |
3.3.2 获取随机数
函数原型 | int crypto_rng_get_bytes(struct crypto_rng *tfm, u8 *rdata, unsigned int dlen) |
函数性能 | 获取随机数 |
输出阐明 | tfm – 算法实例 rdata – 保留随机数的输入缓冲区 dlen – 输入缓冲区的长度 |
输入阐明 | 无 |
返回值阐明 | 0 为胜利,非 0 为失败 |
应用阐明 | |
注意事项 |
3.3.3 开释 tfm 资源
函数原型 | void crypto_free_rng(struct crypto_rng *tfm) |
函数性能 | 开释 tfm 资源 |
输出阐明 | tfm - 算法实例 |
输入阐明 | 无 |
返回值阐明 | 无 |
应用阐明 | |
注意事项 |
4 算法应用示例
4.1 哈希算法应用示例
4.1.1 定义构造
定义多个构造体变量,其中:
struct crypto_wait:异步操作期待对象
struct ahash_request:异步操作申请对象
struct crypto_ahash:哈希算法对象(上下文)
struct scatterlist:用来保留加 / 解密缓冲区的构造
struct crypto_wait wait;
struct ahash_request *req;
struct crypto_ahash *tfm;
struct scatterlist *sg = NULL;
4.1.2 申请内存
申请明文(src)和哈希值(dst)的数据内存空间。
src = kmalloc(1024 + 512, GFP_KERNEL);
if (src == NULL) {printk(KERN_ERR"%s:kmalloc failed!\n", __func__);
return;
}
dst = src+1024;
4.1.3 调配算法对象
通过传入的算法名 alg 和内核接口 crypto_alloc_ahash 调配算法名对应的算法对象,反对的算法对象能够通过在 /proc/crypto 文件中查看。
tfm = crypto_alloc_ahash(alg, 0, 0);
if (IS_ERR(tfm)) {printk(KERN_ERR"failed to load transform for %s: %ld\n", alg, PTR_ERR(tfm));
return;
}
4.1.4 调配算法数据申请对象
调配 request 异步操作期待对象。
req = ahash_request_alloc(tfm, GFP_KERNEL);
if (!req) {printk(KERN_INFO"ahash: Failed to allocate request for %s\n", alg);
goto fail;
}
4.1.5 设置上下文
设置上下文,通过 ahash_request_set_callback 接口给异步申请对象设置回调函数,负责唤醒实现量相干的的回调传给加解密函数,以使其能在实现后唤醒对应线程。通过 crypto_ahash_setkey 接口为 hash 算法设置密钥。通过 ahash_request_set_crypt 接口设置生成哈希值操作相干参数,如源数据 sg 指针、填充音讯哈希值的缓冲区以及数据长度信息。
crypto_init_wait(&wait);
ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, crypto_req_done, &wait);
if (key && klen)
crypto_ahash_setkey(tfm, key, klen);
if (len) {sg = kmalloc(sizeof(struct scatterlist) * len, GFP_KERNEL);
if (sg == NULL) {printk(KERN_ERR"%s:kmalloc sg failed!\n", __func__);
goto fail1;
}
sg_init_table(sg, len);
for (i = 0; i < len; i ++) {sg_set_buf(sg + i, data + i, 1);
}
}
ahash_request_set_crypt(req, sg, out, len);
4.1.6 进行 digest 摘要操作
ret = crypto_wait_req(crypto_ahash_digest(req), &wait);
if (ret) {printk(KERN_ERR"hashing failed ret=%d\n", ret);
}
4.1.7 开释对象
ahash_request_free(req);
crypto_free_ahash(tfm);
4.2 对称算法应用示例
定义多个构造体变量,其中:
struct crypto_wait:异步操作期待对象
struct skcipher_request:对称密钥异步操作申请对象
struct crypto_skcipher:加密算法对象(上下文)
struct scatterlist:用来保留加 / 解密缓冲区的构造
struct crypto_wait wait;
struct skcipher_request *req;
struct crypto_skcipher *tfm;
struct scatterlist *ssg = NULL, *dsg = NULL;
4.2.2 申请内存
申请明文(src)、密文(dst)、密钥(key)和 IV(iv)等数据内存空间。
src = kmalloc(1024 * 3, GFP_KERNEL);
if (src == NULL) {printk(KERN_ERR"%s:kmalloc failed!\n", __func__);
return;
}
memset(src, 0, 1024*3);
dst = src + 1024;
key = dst + 1024;
iv = key + 512;
4.2.3 调配算法对象
通过传入的算法名 alg 和内核接口 crypto_alloc_skcipher 调配算法名对应的算法对象,反对的算法对象能够通过在 /proc/crypto 文件中查看。
tfm = crypto_alloc_skcipher(alg, 0, 0);
if (IS_ERR(tfm)) {printk(KERN_ERR"failed to load transform for %s: %ld\n", alg, PTR_ERR(tfm));
return;
}
4.2.4 调配算法数据申请对象
调配 request 异步操作期待对象。
req = skcipher_request_alloc(tfm, GFP_KERNEL);
if (!req) {printk(KERN_INFO"skcipher: Failed to allocate request for %s\n", alg);
goto fail;
}
4.2.5 设置上下文
设置上下文,通过 skcipher_request_set_callback 接口给异步申请对象设置回调函数,负责唤醒实现量相干的的回调传给加解密函数,以使其能在实现后唤醒对应线程。通过 crypto_skcipher_setkey 接口为 skcipher 算法设置密钥。通过 skcipher_request_set_crypt 接口设置加解密操作相干参数,如源数据、目标数据 sg 指针、iv 指针以及数据长度信息。
crypto_init_wait(&wait);
skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, crypto_req_done, &wait);
crypto_skcipher_clear_flags(tfm, ~0);
crypto_skcipher_setkey(tfm, key, klen);
ssg = kmalloc(sizeof(struct scatterlist) * len, GFP_KERNEL);
if (ssg == NULL) {printk(KERN_ERR"%s:kmalloc ssg failed!\n", __func__);
goto fail1;
}
sg_init_table(ssg, len);
for (i = 0; i < len; i ++) {sg_set_buf(ssg + i, data + i, 1);
}
dsg = kmalloc(sizeof(struct scatterlist) * len, GFP_KERNEL);
if (dsg == NULL) {printk(KERN_ERR"%s:kmalloc dsg failed!\n", __func__);
goto fail2;
}
sg_init_table(dsg, len);
for (i = 0; i < len; i ++) {sg_set_buf(dsg + i, out + i, 1);
}
skcipher_request_set_crypt(req, ssg, dsg, len, iv);
4.2.6 实现加 / 解密
通过 crypto_skcipher_encrypt 接口执行理论的加密流程。
通过 crypto_skcipher_decrypt 接口执行理论的解密流程。
if (enc)
ret = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
else
ret = crypto_wait_req(crypto_skcipher_decrypt(req), &wait);
if (ret) {printk(KERN_ERR"failed ret=%d\n", ret);
}
4.2.7 开释对象
skcipher_request_free(req);
crypto_free_skcipher(tfm);
4.3 真随机数生成器应用示例
4.3.1 定义构造
定义多个构造体变量,其中:
struct crypto_rng:随机数算法对象(上下文)
struct crypto_rng *tfm;
4.3.2 调配算法对象
通过传入的算法名 alg 和内核接口 crypto_alloc_rng 调配算法名对应的算法对象,反对的算法对象能够通过在 /proc/crypto 文件中查看。
tfm = crypto_alloc_rng("trng", 0, 0);
if (IS_ERR(tfm)) {printk(KERN_ERR "alg: cprng: Failed to load transform for %s:""%ld\n","trng", PTR_ERR(tfm));
return;
}
4.3.3 获取随机数
err = crypto_rng_get_bytes(tfm, buf, len);
if(err) {printk(KERN_ERR"generate len %d error", len);
break;
}
4.3.4 开释对象
crypto_free_rng(tfm);
5 术语和缩略语
术语 | 全称 | 解释 |
---|---|---|
ACA | Asymmetric Cryptography Accelerator | 非对称明码加速器 |
SCA | Symmetric Cryptography Accelerator | 对称明码加速器 |
TRNG | True Random Number Generator | 真随机数发生器 |
6 常见问题
无
版权所有。飞腾信息技术有限公司 2023。保留所有权力。
未经本公司批准,任何单位、公司或集体不得擅自复制,翻译,摘抄本文档内容的局部或全副,不得以任何形式或路径进行流传和宣传。
商标申明
Phytium 和其余飞腾商标均为飞腾信息技术有限公司的商标。
本文档提及的其余所有商标或注册商标,由各自的所有人领有。
留神
本文档的内容视为飞腾的窃密信息,您该当严格遵守窃密工作;未经飞腾当时书面批准,您不得向任何第三方披露本文档内容或提供给任何第三方应用。
因为产品版本升级或其余起因,本文档内容会不定期进行更新。除非另有约定,本文档仅作为应用领导,飞腾在现有技术的根底上尽最大致力提供相应的介绍及操作指引,但飞腾在此明确申明对本文档内容的准确性、完整性、适用性、可靠性的等不作任何明示或暗示的保障。
本文档中所有内容,包含但不限于图片、架构设计、页面布局、文字描述,均由飞腾和 / 或其关联公司依法领有其知识产权,包含但不限于商标权、专利权、著作权等。非经飞腾和 / 或其关联公司书面批准,任何人不得擅自应用、批改,复制上述内容。
如有技术问题,可分割 support@phytium.com.cn 获取反对。