|
本帖最后由 dukelec 于 2019-7-15 03:48 编辑
对我而言,Linux 内核代码是嵌入式的圣经,里面有很多值得我学习的东西,同时也为我带来很多宝藏。
做嵌入式和搞软件,非常重要的一点是选择,主系统选择 windows 还是 linux、选择 vbs 还是 python、选择 mfc 还是 html5、AD 还是 KiCad ...
众多的选择又决定了派系。如果选择的不好,你会发现,学了很多东西都白学,接下来遇到想学的新事务也会越发的力不从心。
选择的好,学的东西则会终身受用,精力比较集中,不用重复学习,不用很被动的跟在别人后面追。
所以,选择很重要,要抛开当下的舒适圈,不要随波逐流,要独立思考,选择长远对自己更有益的东西。
好了,不废话了,回到主题,很多人会觉得 linux 内核很神圣、很难懂,其实不然,譬如今天介绍的 speck 对称加解密算法,新的内核代码已经被删掉,因为它是美国国家安全局 NSA 设计的算法,开源社区的人担心有后门。
不过,我们用来做 bootloader 等加密是不需担心它是否真的有后门。很多场合可以代替 aes 加密。
原始的内核代码参见:
https://elixir.bootlin.com/linux/v4.18/source/crypto/speck.c
https://elixir.bootlin.com/linux ... lude/crypto/speck.h
包含注释等 N 多代码无关信息,c 文件一共才 307 行,包含了两个位宽版本,而且没啥依赖。
下面这个是我把代码搬到用户空间,写了一个小 main 文件测试的工程:
- #include <stdio.h>
- #include "speck.h"
- static speck64_t speck_ctx;
- static uint8_t key96[12] = {0,1,2,3,4,5,6,7,8,9,1,2}; // 密钥
- static uint8_t ori[8] = {1,2,3,4,5,6,7,8}; // 原始明文,一个 block 8 字节,正好 64 位
- static uint8_t enc[8] = {0}; // 存放加密得到的密文
- static uint8_t back[8]= {0}; // 存放再次解密得到的明文
- int main(void)
- {
- crypto_speck64_setkey(&speck_ctx, key96, SPECK64_96_KEY_SIZE); // 第 3 个参数 8 位机版本已删掉,进一步减少开销
- crypto_speck64_encrypt(&speck_ctx, enc, ori);
- crypto_speck64_decrypt(&speck_ctx, back, enc);
- printf("enc: %d %d %d %d %d %d %d %d\n", enc[0], enc[1], enc[2], enc[3], enc[4], enc[5], enc[6], enc[7]);
- printf("back: %d %d %d %d %d %d %d %d\n", back[0], back[1], back[2], back[3], back[4], back[5], back[6], back[7]);
- return 0;
- }
复制代码
这是最终搬到 8 位机的代码,只保留 64 位版本,不算注释,c 文件只有 70 多行,只是 put_unaligned_le32 和 get_unaligned_le32 这种通用函数里面,为移位加上显式类型转换,防止高位数据丢失而已。
为方便阅读,贴出相关代码:
头文件:
- #ifndef _CRYPTO_SPECK_H
- #define _CRYPTO_SPECK_H
- #define SPECK64_BLOCK_SIZE 8
- #define SPECK64_96_KEY_SIZE 12
- #define SPECK64_96_NROUNDS 26
- typedef struct {
- uint32_t round_keys[SPECK64_96_NROUNDS];
- } speck64_t;
- void crypto_speck64_cal(const speck64_t *ctx, bool is_encrypt,
- uint8_t *out, const uint8_t *in);
- void crypto_speck64_setkey(speck64_t *ctx, const uint8_t *key);
- #endif /* _CRYPTO_SPECK_H */
复制代码
c 文件算法部分:
- static inline void speck64_round(uint32_t *x, uint32_t *y, uint32_t k)
- {
- *x = ror32(*x, 8);
- *x += *y;
- *x ^= k;
- *y = rol32(*y, 3);
- *y ^= *x;
- }
- static inline void speck64_unround(uint32_t *x, uint32_t *y, uint32_t k)
- {
- *y ^= *x;
- *y = ror32(*y, 3);
- *x ^= k;
- *x -= *y;
- *x = rol32(*x, 8);
- }
- void crypto_speck64_cal(const speck64_t *ctx, bool is_encrypt,
- uint8_t *out, const uint8_t *in)
- {
- uint32_t y = get_unaligned_le32(in);
- uint32_t x = get_unaligned_le32(in + 4);
- int8_t i;
- if (is_encrypt) {
- for (i = 0; i < SPECK64_96_NROUNDS; i++)
- speck64_round(&x, &y, ctx->round_keys[i]);
- } else {
- for (i = SPECK64_96_NROUNDS - 1; i >= 0; i--)
- speck64_unround(&x, &y, ctx->round_keys[i]);
- }
- put_unaligned_le32(y, out);
- put_unaligned_le32(x, out + 4);
- }
- void crypto_speck64_setkey(speck64_t *ctx, const uint8_t *key)
- {
- uint32_t l[2];
- uint32_t k;
- int8_t i;
- k = get_unaligned_le32(key);
- l[0] = get_unaligned_le32(key + 4);
- l[1] = get_unaligned_le32(key + 8);
- for (i = 0; i < SPECK64_96_NROUNDS; i++) {
- ctx->round_keys[i] = k;
- speck64_round(&l[i % 2], &k, i);
- }
- }
复制代码
辅助代码:(如果是小端 mcu,不需要 get_unaligned_le32 和 put_unaligned_le32, 直接用类型强制转化即可。)
- /**
- * rol32 - rotate a 32-bit value left
- * @word: value to rotate
- * @shift: bits to roll
- */
- static inline uint32_t rol32(uint32_t word, uint8_t shift)
- {
- return (word << shift) | (word >> ((-shift) & 31));
- }
- /**
- * ror32 - rotate a 32-bit value right
- * @word: value to rotate
- * @shift: bits to roll
- */
- static inline uint32_t ror32(uint32_t word, uint8_t shift)
- {
- return (word >> shift) | (word << (32 - shift));
- }
- static inline uint32_t get_unaligned_le32(const uint8_t *p)
- {
- return p[0] | (uint16_t)p[1] << 8 | (uint32_t)p[2] << 16 | (uint32_t)p[3] << 24;
- }
- /*
- static inline void put_unaligned_le16(uint16_t val, uint8_t *p)
- {
- *p++ = val;
- *p++ = val >> 8;
- } */
- static inline void put_unaligned_le32(uint32_t val, uint8_t *p)
- {
- //put_unaligned_le16(val >> 16, p + 2);
- //put_unaligned_le16(val, p);
- p[0] = val & 0xff;
- p[1] = (val >> 8) & 0xff;
- p[2] = (val >> 16) & 0xff;
- p[3] = val >> 24;
- }
复制代码
总的来说,几乎没啥改动,内核代码就可以直接搬到 8 位 mcu 运行。
内核里面还有很多类似的好东西,除了内核以外,linux 系统上的软件就更多更丰富了。平时用 linux 多,要什么软件很快能找到,而且有源码。不存在 windows 上很普通的小工具还要破解、被中毒、弹广告。。。 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?注册
x
阿莫论坛20周年了!感谢大家的支持与爱护!!
阿莫论坛才是最爱国的,关心国家的经济、社会的发展、担心国家被别国牵连卷入战争、知道珍惜来之不易的和平发展,知道师夷之长,关注世界的先进文化与技术,也探讨中国文化的博大精深,也懂得警惕民粹主义的祸国殃民等等等等,无不是爱国忧民的表现。(坛友:tianxian)
|