dukelec 发表于 2019-7-14 19:46:30

推荐 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 上很普通的小工具还要破解、被中毒、弹广告。。。

duxingkei 发表于 2019-7-14 20:20:07

666,记得以前有个PTHREAD线程好像也是来自linux,也能移植方便到普通MCU

kinsno 发表于 2019-7-14 21:27:31

Linux      speck   加密   极简,

zhw950 发表于 2019-7-14 21:38:58

收藏,替换我的bootloader试试

tomzbj 发表于 2019-7-14 21:40:20

duxingkei 发表于 2019-7-14 20:20
666,记得以前有个PTHREAD线程好像也是来自linux,也能移植方便到普通MCU

pthread能移植到普通MCU?具体说说?

pazulin 发表于 2019-7-14 21:48:18

本帖最后由 pazulin 于 2019-7-14 21:51 编辑

非常好的参考!谢谢!! 不单单用在bootloader ,很多场合可用

fzkqi 发表于 2019-7-14 21:55:35

保存下。Linux      speck   加密   极简

xiaomu 发表于 2019-7-14 22:04:10

感谢分享,

vavasi 发表于 2019-7-14 22:10:34

谢谢 分享,先支持后看货。

hlmkhqpost 发表于 2019-7-14 23:01:45

mark,备用

bad_fpga 发表于 2019-7-14 23:17:08

speck 加密,学习了

gzhuli 发表于 2019-7-14 23:49:09

XXTEA更简单。

elsonx 发表于 2019-7-14 23:52:18

speck 加密

yanyanyan168 发表于 2019-7-14 23:59:42

多谢分享

wzbwzb 发表于 2019-7-15 00:00:17

收藏了,好东西

dukelec 发表于 2019-7-15 00:09:19

本帖最后由 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);
}

wx-ta 发表于 2019-7-15 00:15:55

有没有人对比下,和aes加密,哪个占用存储资源小

dukelec 发表于 2019-7-15 00:40:04

本帖最后由 dukelec 于 2019-7-15 05:17 编辑

wx-ta 发表于 2019-7-15 00:15
有没有人对比下,和aes加密,哪个占用存储资源小

你这是拿 单车 与 跑车 做比较。。。

这有个比较的报告,文末有总结文字,还有个表:
https://pdfs.semanticscholar.org/bc77/d9dd70bacd6da036445cb6a78fea67b3b5dd.pdf




如果 mcu 自带硬件 aes,那么可以考虑用硬件 aes.

amxx 发表于 2019-7-15 08:26:13

SPECK加密,留个爪,新许哪天会用到。之前在数据传输上倒是用过TEA,不过是在PC上

442502587 发表于 2019-7-15 08:28:15


Linux      speck   加密   极简,

liansh2002 发表于 2019-7-15 08:31:23

一直在用XTEA,不懂密码学,但是感觉算法和XTEA很相似,都是和秘钥做N轮迭代运算得到密文。

lqluocn 发表于 2019-7-15 08:42:20

收藏一下。多谢!

金色大元宝 发表于 2019-7-15 08:44:49

收藏一下,好东西。

a105 发表于 2019-7-15 08:49:34



Linux      speck   加密   极简

落叶知秋 发表于 2019-7-15 08:50:53

感谢分享

chendaon 发表于 2019-7-15 08:53:17

感谢分享,留脚印

cycisok 发表于 2019-7-15 08:59:26

我用TEA加密,单片机端和电脑端的C#算出来加密后的值不一样。有什么算法加 密效果不差,加密后的值一样的吗?这样可以在对方还原。

fnems 发表于 2019-7-15 09:59:37

本帖最后由 fnems 于 2019-7-15 10:00 编辑

liansh2002 发表于 2019-7-15 08:31
一直在用XTEA,不懂密码学,但是感觉算法和XTEA很相似,都是和秘钥做N轮迭代运算得到密文。 ...

很多对称加密都是基于多轮feistel网络迭代来实现位扩散,tea和这个都是。
你觉得眼熟的就是这个feistel网络,可以找维基百科看看。有点对称加密基石的意思。

AES有点不一样,是基于s-box和p-box变换。

wjb444 发表于 2019-7-15 10:05:46

speck   加密   极简谢谢

wx85105157 发表于 2019-7-15 10:06:14

学习一下 对称加密

浮华一生 发表于 2019-7-15 10:16:14

MARK 加密算法

chen849928055 发表于 2019-7-15 10:18:22

mark,收藏下,有机会用上去试试

小溪 发表于 2019-7-15 10:25:05

这比AES有多大的优势呢?

weiwei4 发表于 2019-7-15 10:49:56

speck 加密 ,不错
用来做通信加密应该不错,以后应该用得上

sunrosewang 发表于 2019-7-15 11:00:49

看了一下,这个speck用在BL上很合适,源码也较精简

rtems 发表于 2019-7-15 11:04:09

确实,Linux内核里面有很多好东西,我03年的时候看了list的实现,真是佩服。

EngKing 发表于 2019-7-15 11:12:09

Linux      speck   加密

john78 发表于 2019-7-15 11:16:08

实际怎么使用?

longwu537 发表于 2019-7-15 11:53:35

好东西,收藏了

dukelec 发表于 2019-7-15 12:31:09

本帖最后由 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 代码的好处之一是:大小端都兼容,不会因为大小端不同而出错。

dukelec 发表于 2019-7-15 12:33:18

小溪 发表于 2019-7-15 10:25
这比AES有多大的优势呢?

aes stm8s103 级别的 8 位机装不下。

tarchen 发表于 2019-7-15 13:24:50

好动动,下载留用。

迅得电子 发表于 2019-7-15 13:32:29

好东西,mark    speck 加密

正十七 发表于 2019-7-15 13:41:23

好东西,先mark一下,speck 加密   

liurangzhou 发表于 2019-7-15 13:59:19

mark                           

powerlabor001 发表于 2019-7-15 14:31:36

咱是不是也跟风mark一把。

rifjft 发表于 2019-7-15 15:11:31

这分享是好东西呀,研究中{:lol:}

heimareed 发表于 2019-7-15 21:38:32

dukelec 发表于 2019-7-15 12:33
aes stm8s103 级别的 8 位机装不下。

终于等到了这个回复,以前一直用AES的。回头试下Speck~

crazydtone 发表于 2019-7-15 23:11:07

谢谢楼主推荐呢{:handshake:}
有个问题呢,在Flash中存储的是明文吗?
对于加密,是对编译软件生成文件进行加密,需要一个上位机进行加密,然后在MCU端解密,再把明文写道flash中吗?

flash3g 发表于 2019-7-15 23:37:30

crazydtone 发表于 2019-7-15 23:11
谢谢楼主推荐呢
有个问题呢,在Flash中存储的是明文吗?
对于加密,是对编译软件生成文件进行 ...

对的,是这样。

yyj_sd 发表于 2019-7-16 08:22:22

楼主高手。收藏下备用!

mpuhome 发表于 2019-7-16 08:34:53

speck 加密

在途中 发表于 2019-7-16 08:39:27

speck通讯加密收藏下

dgtg 发表于 2019-7-16 14:12:50

Mark,收藏下!

ground 发表于 2019-7-16 15:15:42

speck   加密   极简

mypc16888 发表于 2019-7-18 21:53:23

spek 加密

gamep 发表于 2019-7-19 12:54:27

mark

linux 加密算法

XXTEA更简单

dragonbbc 发表于 2019-7-19 13:14:12

mark, 回头用得上再来研究

huangqi412 发表于 2019-7-19 17:04:36

收藏加密算法

ruxz@263.net 发表于 2019-7-19 22:16:08

Linux      speck   加密   极简,

chengong 发表于 2019-7-20 01:33:22

收藏了.好

122402902 发表于 2019-7-20 01:43:56

学习了 谢谢 后续可以用

llysc 发表于 2019-7-20 08:59:56

已收藏,多谢楼主!

ordman 发表于 2019-8-7 11:05:09

谢谢分享!
下载试试。

leifeng 发表于 2019-8-7 11:39:37

Linux      speck   加密

security 发表于 2019-8-7 11:45:47

看起来很高科技。
惭愧啊,工作十余年,从来没碰过 Linux,更不用说看源码了。

yunhuisong 发表于 2019-8-7 11:53:14


Linux      speck   加密   极简

aohu_2012 发表于 2019-8-7 12:07:59

linux speck加密 ,mark,多谢分享

hameyou 发表于 2021-1-2 22:58:06

inux speck加密 ,mark

fengyunyu 发表于 2021-1-2 23:57:15

lz,大神

makesoft 发表于 2021-1-3 07:49:26

Linux      speck   加密

Z11 发表于 2021-1-3 08:14:26

666敏感的意识标记一下。多谢分享 Linux      speck   加密   极简

569350810 发表于 2021-1-3 12:03:05

speck 加密,适用于 bootloader,谢谢。

sunliezhi 发表于 2021-1-3 12:07:50

speck 加密,极简,可用于 stm8 和 51

motata2006 发表于 2021-1-5 13:41:11

第一次接触加密算法。

waymcu 发表于 2021-1-5 14:00:54

Linux      speck   加密

zhq0571 发表于 2021-1-5 15:25:17


Linux      speck   加密   极简

wgainn 发表于 2021-1-6 00:04:39

speck 对称加解密算法

jjj 发表于 2021-1-6 09:34:39

保存下。Linux      speck   加密   极简思路比较开阔,tea xtea aes, 我只用过AES

asbzhang 发表于 2021-1-6 09:56:02

好东西,谢谢楼主

钛50 发表于 2021-1-6 10:42:24

Linux      speck 留个备用 谢谢

bugkillbug 发表于 2021-1-6 11:08:11

xchacha 听说专为arm优化过的
页: [1]
查看完整版本: 推荐 Linux 源码中的 speck 加密,极简,可用于 stm8 和 51