前言
Linux内核里有一个密码学框架Linux kernel crypto。框架内部提供了常用的标准算法,比如:AES, DES, MD5, SHA1, RSA,DSA等。框架也是支持开发者自定义算法的,通过框架可以注册我们自己的算法,比如国标的SM2, SM3, SM4等, 或者某个公司内部的私有算法。当然了, 也支持对已有的算法重新注册,可以通过优先级设置让用户调用到我们注册的算法。框架代码在内核源码下的crypto目录。
框架提供了一个算法的自检的实现,也就是tcrypt。在我们注册算法的时候,框架会自动使用我们提供的数据执行用例。
tcrypt
tcrypt其实分为两个部分,一个是编译进内核的testmgr.c, 另外一个就是编译成模块的tcrypt.c。
testmgr
在我们往框架注册算法的时候,框架默认就会调用testmgr.c里的alg_test函数,查找对应的测试用例函数,找到之后就会执行用例,检测算法实现是否符合预期。如果没有对应的用例或者用例执行成功的话,则算法直接注册成功,否则注册失败。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
|
int crypto_register_alg(struct crypto_alg *alg) { struct crypto_larval *larval; bool test_started; int err;
alg->cra_flags &= ~CRYPTO_ALG_DEAD; err = crypto_check_alg(alg); if (err) return err;
down_write(&crypto_alg_sem); larval = __crypto_register_alg(alg); test_started = static_key_enabled(&crypto_boot_test_finished); if (!IS_ERR_OR_NULL(larval)) larval->test_started = test_started; up_write(&crypto_alg_sem);
if (IS_ERR_OR_NULL(larval)) return PTR_ERR(larval);
if (test_started) crypto_wait_for_test(larval); return 0; }
void crypto_wait_for_test(struct crypto_larval *larval) { int err;
err = crypto_probing_notify(CRYPTO_MSG_ALG_REGISTER, larval->adult); if (WARN_ON_ONCE(err != NOTIFY_STOP)) goto out;
err = wait_for_completion_killable(&larval->completion); WARN_ON(err); if (!err) crypto_notify(CRYPTO_MSG_ALG_LOADED, larval);
out: crypto_larval_kill(&larval->alg); }
static int cryptomgr_test(void *data) { struct crypto_test_param *param = data; u32 type = param->type; int err = 0;
#ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS goto skiptest; #endif
if (type & CRYPTO_ALG_TESTED) goto skiptest;
err = alg_test(param->driver, param->alg, type, CRYPTO_ALG_TESTED);
skiptest: crypto_alg_tested(param->driver, err);
kfree(param); module_put_and_exit(0); }
|
我们需要在testmgr.h里面定义测试的几组数据。如下 MD5算法的测试数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
|
static const struct hash_testvec md5_tv_template[] = { { .digest = "\xd4\x1d\x8c\xd9\x8f\x00\xb2\x04" "\xe9\x80\x09\x98\xec\xf8\x42\x7e", }, { .plaintext = "a", .psize = 1, .digest = "\x0c\xc1\x75\xb9\xc0\xf1\xb6\xa8" "\x31\xc3\x99\xe2\x69\x77\x26\x61", }, { .plaintext = "abc", .psize = 3, .digest = "\x90\x01\x50\x98\x3c\xd2\x4f\xb0" "\xd6\x96\x3f\x7d\x28\xe1\x7f\x72", }, { .plaintext = "message digest", .psize = 14, .digest = "\xf9\x6b\x69\x7d\x7c\xb7\x93\x8d" "\x52\x5a\x2f\x31\xaa\xf1\x61\xd0", }, { .plaintext = "abcdefghijklmnopqrstuvwxyz", .psize = 26, .digest = "\xc3\xfc\xd3\xd7\x61\x92\xe4\x00" "\x7d\xfb\x49\x6c\xca\x67\xe1\x3b", }, { .plaintext = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", .psize = 62, .digest = "\xd1\x74\xab\x98\xd2\x77\xd9\xf5" "\xa5\x61\x1c\x2c\x9f\x41\x9d\x9f", }, { .plaintext = "12345678901234567890123456789012345678901234567890123456789012" "345678901234567890", .psize = 80, .digest = "\x57\xed\xf4\xa2\x2b\xe3\xc9\x55" "\xac\x49\xda\x2e\x21\x07\xb6\x7a", }
}
|
然后再在alg_test_descs里面添加映射关系, 注意这里有个巧妙的实现, 映射关系需要按照算法名升序加入。 因为在查找算法用例的时候,它其实是一个二分查找的过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| { .alg = "md4", .test = alg_test_hash, .suite = { .hash = __VECS(md4_tv_template) } }, { .alg = "md5", .test = alg_test_hash, .suite = { .hash = __VECS(md5_tv_template) } }, { .alg = "michael_mic", .test = alg_test_hash, .suite = { .hash = __VECS(michael_mic_tv_template) } }
static int alg_find_test(const char *alg) { int start = 0; int end = ARRAY_SIZE(alg_test_descs);
while (start < end) { int i = (start + end) / 2; int diff = strcmp(alg_test_descs[i].alg, alg);
if (diff > 0) { end = i; continue; }
if (diff < 0) { start = i + 1; continue; }
return i; }
return -1; }
|
alg_test_hash是内核提供的一个测试hash算法的用例模板,里面的流程就是调用Linux kernel crypto框架提供的接口来运行算法,然后拿结果跟提供的数据作对比。关于这个接口的使用,在后面出文章讲一下。
不同的算法类型都有对应的测试函数,没有的话, 得研究一下怎么自己加一下。
tcrypt模块
tcrypt.c则编译成一个内核模块,允许我们通过insmod/modprobe 动态加载来测试不同的算法。它提供了好几个模块参数,加载模块的时候传递不同参数来控制调用不同的算法用例。
在我们编译完内核之后, 可以在/lib/modules/5.17.1/kernel/crypto (5.17.1 是内核版本号)找到tcrypt.ko
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
| root@keep-VirtualBox:/lib/modules/5.17.1/kernel/crypto# ls 842.ko authencesn.ko chacha20poly1305.ko ecdsa_generic.ko ofb.ko twofish_common.ko adiantum.ko authenc.ko chacha_generic.ko echainiv.ko pcbc.ko twofish_generic.ko aegis128.ko blake2b_generic.ko cmac.ko ecrdsa_generic.ko pcrypt.ko vmac.ko aes_ti.ko blake2s_generic.ko crc32_generic.ko essiv.ko poly1305_generic.ko wp512.ko af_alg.ko blowfish_common.ko cryptd.ko fcrypt.ko rmd160.ko xcbc.ko algif_aead.ko blowfish_generic.ko crypto_engine.ko keywrap.ko serpent_generic.ko xor.ko algif_hash.ko camellia_generic.ko crypto_simd.ko lrw.ko sha3_generic.ko xxhash_generic.ko algif_rng.ko cast5_generic.ko crypto_user.ko lz4hc.ko sm2_generic.ko zstd.ko algif_skcipher.ko cast6_generic.ko curve25519-generic.ko lz4.ko sm3_generic.ko ansi_cprng.ko cast_common.ko des_generic.ko md4.ko sm4_generic.ko asymmetric_keys ccm.ko ecc.ko michael_mic.ko streebog_generic.ko async_tx cfb.ko ecdh_generic.ko nhpoly1305.ko tcrypt.ko
root@keep-VirtualBox:/lib/modules/5.17.1/kernel/crypto# insmod tcrypt.ko mode=1000 insmod: ERROR: could not insert module tcrypt.ko: Resource temporarily unavailable root@keep-VirtualBox:/lib/modules/5.17.1/kernel/crypto# 7月 02 20:16:02 keep-VirtualBox kernel: alg des 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg md5 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg des3_ede 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg rot13 7月 02 20:16:02 keep-VirtualBox kernel: not found 7月 02 20:16:02 keep-VirtualBox kernel: alg sha1 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg sha224 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg sha256 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg sm3 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg blowfish 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg twofish 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg serpent 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg sha384 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg sha512 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg md4 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg aes 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg cast6 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg arc4 7月 02 20:16:02 keep-VirtualBox kernel: not found 7月 02 20:16:02 keep-VirtualBox kernel: alg michael_mic 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg deflate 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg crc32c 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg tea 7月 02 20:16:02 keep-VirtualBox kernel: not found 7月 02 20:16:02 keep-VirtualBox kernel: alg xtea 7月 02 20:16:02 keep-VirtualBox kernel: not found 7月 02 20:16:02 keep-VirtualBox kernel: alg khazad 7月 02 20:16:02 keep-VirtualBox kernel: not found 7月 02 20:16:02 keep-VirtualBox kernel: alg wp512 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg wp384 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg wp256 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg xeta 7月 02 20:16:02 keep-VirtualBox kernel: not found 7月 02 20:16:02 keep-VirtualBox kernel: alg fcrypt 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg camellia 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg seed 7月 02 20:16:02 keep-VirtualBox kernel: not found 7月 02 20:16:02 keep-VirtualBox kernel: alg rmd160 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg lzo 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg lzo-rle 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg cts 7月 02 20:16:02 keep-VirtualBox kernel: not found 7月 02 20:16:02 keep-VirtualBox kernel: alg sha3-224 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg sha3-256 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg sha3-384 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg sha3-512 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg streebog256 7月 02 20:16:02 keep-VirtualBox kernel: found 7月 02 20:16:02 keep-VirtualBox kernel: alg streebog512 7月 02 20:16:02 keep-VirtualBox kernel: found
|
传入mode=1000表示输出内核中注册的算法, 这里不包含组合的算法。具体的参数可以去看tcrypt.c的do_test函数。如果我们要自己添加一个测试算法的入口,那么只需要增加一个case, 然后调用我们自己指定的算法就可以了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) { int i; int ret = 0;
switch (m) { ... case 159: ret += tcrypt_test("cmac(sm4)"); break; case 160: ret += tcrypt_test("zuc"); break;
|
编译
要能tcrypt测试, 还需要在内核编译make menuconfig的时候选择
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| --- Cryptographic API │ │ │ │ *** Crypto core or helper *** │ │ │ │ -*- Cryptographic algorithm manager │ │ │ │ <M> Userspace cryptographic algorithm configuration │ │ │ │ [ ] Disable run-time self tests │ │ # 不选择 │ │ -*- Null algorithms │ │ │ │ <M> Parallel crypto engine │ │ │ │ {M} Software async crypto daemon │ │ │ │ {M} Authenc support │ │ │ │ <M> Testing module │ │ # 选择 │ │ *** Public-key cryptography *** │ │ │ │ -*- RSA algorithm │ │ │ │ -*- Diffie-Hellman algorithm │ │ │ │ {M} ECDH algorithm │ │ │ │ <M> ECDSA (NIST P192, P256 etc.) algorithm │ │ │ │ <M> EC-RDSA (GOST 34.10) algorithm │ │ │ │ <M> SM2 algorithm │ │ │ │ <M> Curve25519 algorithm │ │ │ │ {M} x86_64 accelerated Curve25519 scalar multiplication library │ │ │ │ *** Authenticated Encryption with Associated Data *** │ │ │ │ {M} CCM support │ │ │ │ {*} GCM/GMAC support │ │ │ │ {M} ChaCha20-Poly1305 AEAD support │ │ │ │ <M> AEGIS-128 AEAD algorithm │ │ │ │ <M> AEGIS-128 AEAD algorithm (x86_64 AESNI+SSE2 implementation)
|
更多
最近股市行情不错,账户也已经回血了许多。但是搞了大半年,发现也就是几千块钱的收益(哈哈,主要是本金少),还不如好好工作,拿个好绩效,做出成绩来得更实在一些。
另外,六月份的时候工作也转正了,工作上的事情还是蛮多的,有很多事情可以做,单单把目前看到的事情做好就得有个一两年吧。好好学习,天天向上吧。
现在开始做驱动开发,每天都会花个半小时到1小时的时间看驱动的书《Linux驱动开发详解:基于最新Linux4.0内核》,也是个大块头啊,发现内核里面做的事情还是很多的,有的学了。工作的时候,看到很多新的概念名词,还有知识点,由于实在太多,很多没有深入,但是基本上都记录下来了,需要多花写时间梳理小结一下,下半年出文章的数量估计会多一些, 当然保底依旧是每周一篇的。
周末和晚上的时间可以好好利用,做好规划,不断地在知识的海洋中遨游!
行动,才不会被动!
欢迎关注个人公众号 微信 -> 搜索 -> fishmwei,沟通交流。
博客地址: https://fishmwei.github.io
掘金主页: https://juejin.cn/user/2084329776486919