推荐 Linux 源码中的 speck 加密,极简,可用于 stm8 和 51
本帖最后由 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/v4.18/source/include/crypto/speck.h
包含注释等 N 多代码无关信息,c 文件一共才 307 行,包含了两个位宽版本,而且没啥依赖。
下面这个是我把代码搬到用户空间,写了一个小 main 文件测试的工程:
#include <stdio.h>
#include "speck.h"
static speck64_t speck_ctx;
static uint8_t key96 = {0,1,2,3,4,5,6,7,8,9,1,2}; // 密钥
static uint8_t ori = {1,2,3,4,5,6,7,8}; // 原始明文,一个 block 8 字节,正好 64 位
static uint8_t enc = {0}; // 存放加密得到的密文
static uint8_t back= {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, enc, enc, enc, enc, enc, enc, enc);
printf("back: %d %d %d %d %d %d %d %d\n", back, back, back, back, back, back, back, back);
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_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);
} else {
for (i = SPECK64_96_NROUNDS - 1; i >= 0; i--)
speck64_unround(&x, &y, ctx->round_keys);
}
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;
uint32_t k;
int8_t i;
k = get_unaligned_le32(key);
l = get_unaligned_le32(key + 4);
l = get_unaligned_le32(key + 8);
for (i = 0; i < SPECK64_96_NROUNDS; i++) {
ctx->round_keys = k;
speck64_round(&l, &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 | (uint16_t)p << 8 | (uint32_t)p << 16 | (uint32_t)p << 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 = val & 0xff;
p = (val >> 8) & 0xff;
p = (val >> 16) & 0xff;
p = val >> 24;
}
总的来说,几乎没啥改动,内核代码就可以直接搬到 8 位 mcu 运行。
内核里面还有很多类似的好东西,除了内核以外,linux 系统上的软件就更多更丰富了。平时用 linux 多,要什么软件很快能找到,而且有源码。不存在 windows 上很普通的小工具还要破解、被中毒、弹广告。。。 666,记得以前有个PTHREAD线程好像也是来自linux,也能移植方便到普通MCU Linux speck 加密 极简, 收藏,替换我的bootloader试试 duxingkei 发表于 2019-7-14 20:20
666,记得以前有个PTHREAD线程好像也是来自linux,也能移植方便到普通MCU
pthread能移植到普通MCU?具体说说? 本帖最后由 pazulin 于 2019-7-14 21:51 编辑
非常好的参考!谢谢!! 不单单用在bootloader ,很多场合可用 保存下。Linux speck 加密 极简 感谢分享, 谢谢 分享,先支持后看货。 mark,备用 speck 加密,学习了 XXTEA更简单。 speck 加密 多谢分享 收藏了,好东西 本帖最后由 dukelec 于 2019-7-15 12:37 编辑
gzhuli 发表于 2019-7-14 23:49
XXTEA更简单。
我曾经有对比过,xxtea wikipedia 上面那个代码虽然看起来不长,但那个 MX macro 展开还是挺占代码空间的 。
1 楼代码中的函数去掉 inline, 会更加节省代码空间,8 位机编程,经常代码空间不足,省一两个字节都是好的。
虽然 speck 的 key 展开之后比较占内存,但做为 bootloader, 内存不用白不用。
speck 比 tea 更小更快,支持更多不同的 key 大小,见楼下 #18 楼比较。
我当时主要是看了 #18 楼的比较才选了 speck, 不过你这么一提醒,我又对比了下:
xxtea 支持指定数据长度,核心操作步骤更多,更占代码空间;
xtea 是固定 8 字节数据长度,xtea 比较简单,可以把核心位操作打包成非 inline 函数,以减少代码空间。
Linux 内核只支持 xtea, 没有 xxtea, 所以,我觉得可以试试 xtea, 之前不想试是因为:总觉得有高版本的就不愿意用低版本,另外误以为 tea 的 key size 更长 footprint 会更大。
我抽空对比下,都用最节省 flash 的写法,对比 xtea 和 speck 的 flash 占用情况,感觉自己有点被 #18 楼的文章误导。
顺便贴出内核的 xtea 代码:
#define XTEA_KEY_SIZE 16
#define XTEA_BLOCK_SIZE 8
#define XTEA_ROUNDS 32
#define XTEA_DELTA 0x9e3779b9
struct xtea_ctx {
u32 KEY;
};
static void xtea_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
{
u32 y, z, sum = 0;
u32 limit = XTEA_DELTA * XTEA_ROUNDS;
struct xtea_ctx *ctx = crypto_tfm_ctx(tfm);
const __le32 *in = (const __le32 *)src;
__le32 *out = (__le32 *)dst;
y = le32_to_cpu(in);
z = le32_to_cpu(in);
while (sum != limit) {
y += ((z << 4 ^ z >> 5) + z) ^ (sum + ctx->KEY);
sum += XTEA_DELTA;
z += ((y << 4 ^ y >> 5) + y) ^ (sum + ctx->KEY);
}
out = cpu_to_le32(y);
out = cpu_to_le32(z);
}
static void xtea_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
{
u32 y, z, sum;
struct tea_ctx *ctx = crypto_tfm_ctx(tfm);
const __le32 *in = (const __le32 *)src;
__le32 *out = (__le32 *)dst;
y = le32_to_cpu(in);
z = le32_to_cpu(in);
sum = XTEA_DELTA * XTEA_ROUNDS;
while (sum) {
z -= ((y << 4 ^ y >> 5) + y) ^ (sum + ctx->KEY);
sum -= XTEA_DELTA;
y -= ((z << 4 ^ z >> 5) + z) ^ (sum + ctx->KEY);
}
out = cpu_to_le32(y);
out = cpu_to_le32(z);
} 有没有人对比下,和aes加密,哪个占用存储资源小 本帖最后由 dukelec 于 2019-7-15 05:17 编辑
wx-ta 发表于 2019-7-15 00:15
有没有人对比下,和aes加密,哪个占用存储资源小
你这是拿 单车 与 跑车 做比较。。。
这有个比较的报告,文末有总结文字,还有个表:
https://pdfs.semanticscholar.org/bc77/d9dd70bacd6da036445cb6a78fea67b3b5dd.pdf
如果 mcu 自带硬件 aes,那么可以考虑用硬件 aes. SPECK加密,留个爪,新许哪天会用到。之前在数据传输上倒是用过TEA,不过是在PC上
Linux speck 加密 极简, 一直在用XTEA,不懂密码学,但是感觉算法和XTEA很相似,都是和秘钥做N轮迭代运算得到密文。 收藏一下。多谢! 收藏一下,好东西。
Linux speck 加密 极简 感谢分享 感谢分享,留脚印 我用TEA加密,单片机端和电脑端的C#算出来加密后的值不一样。有什么算法加 密效果不差,加密后的值一样的吗?这样可以在对方还原。 本帖最后由 fnems 于 2019-7-15 10:00 编辑
liansh2002 发表于 2019-7-15 08:31
一直在用XTEA,不懂密码学,但是感觉算法和XTEA很相似,都是和秘钥做N轮迭代运算得到密文。 ...
很多对称加密都是基于多轮feistel网络迭代来实现位扩散,tea和这个都是。
你觉得眼熟的就是这个feistel网络,可以找维基百科看看。有点对称加密基石的意思。
AES有点不一样,是基于s-box和p-box变换。 speck 加密 极简谢谢 学习一下 对称加密 MARK 加密算法 mark,收藏下,有机会用上去试试 这比AES有多大的优势呢? speck 加密 ,不错
用来做通信加密应该不错,以后应该用得上 看了一下,这个speck用在BL上很合适,源码也较精简 确实,Linux内核里面有很多好东西,我03年的时候看了list的实现,真是佩服。
Linux speck 加密 实际怎么使用? 好东西,收藏了 本帖最后由 dukelec 于 2019-7-15 12:34 编辑
cycisok 发表于 2019-7-15 08:59
我用TEA加密,单片机端和电脑端的C#算出来加密后的值不一样。有什么算法加 密效果不差,加密后的值一样的吗 ...
相同配置,不同软件算出来值必须相同,你结果不同肯定是你代码有 bug.
请检查 左 移位是否丢数据,iar stm8 char 左移后存入 int,高出 8 位数据会丢失。
更重要的是,要检查大小端不同带来的差异,pc、stm32 是小端,stm8 iar、51 keil 是大端。
参考 linux 代码的好处之一是:大小端都兼容,不会因为大小端不同而出错。 小溪 发表于 2019-7-15 10:25
这比AES有多大的优势呢?
aes stm8s103 级别的 8 位机装不下。 好动动,下载留用。 好东西,mark speck 加密 好东西,先mark一下,speck 加密 mark 咱是不是也跟风mark一把。 这分享是好东西呀,研究中{:lol:} dukelec 发表于 2019-7-15 12:33
aes stm8s103 级别的 8 位机装不下。
终于等到了这个回复,以前一直用AES的。回头试下Speck~ 谢谢楼主推荐呢{:handshake:}
有个问题呢,在Flash中存储的是明文吗?
对于加密,是对编译软件生成文件进行加密,需要一个上位机进行加密,然后在MCU端解密,再把明文写道flash中吗? crazydtone 发表于 2019-7-15 23:11
谢谢楼主推荐呢
有个问题呢,在Flash中存储的是明文吗?
对于加密,是对编译软件生成文件进行 ...
对的,是这样。 楼主高手。收藏下备用! speck 加密 speck通讯加密收藏下 Mark,收藏下! speck 加密 极简 spek 加密 mark
linux 加密算法
XXTEA更简单 mark, 回头用得上再来研究 收藏加密算法 Linux speck 加密 极简, 收藏了.好 学习了 谢谢 后续可以用 已收藏,多谢楼主! 谢谢分享!
下载试试。 Linux speck 加密 看起来很高科技。
惭愧啊,工作十余年,从来没碰过 Linux,更不用说看源码了。
Linux speck 加密 极简 linux speck加密 ,mark,多谢分享 inux speck加密 ,mark lz,大神 Linux speck 加密 666敏感的意识标记一下。多谢分享 Linux speck 加密 极简 speck 加密,适用于 bootloader,谢谢。 speck 加密,极简,可用于 stm8 和 51 第一次接触加密算法。 Linux speck 加密
Linux speck 加密 极简 speck 对称加解密算法 保存下。Linux speck 加密 极简思路比较开阔,tea xtea aes, 我只用过AES 好东西,谢谢楼主 Linux speck 留个备用 谢谢 xchacha 听说专为arm优化过的
页:
[1]