SPECK轻量级分组密码算法的密钥扩展过程
我们今天将聚焦于一个在资源受限环境中应用广泛的轻量级分组密码算法——SPECK。它由美国国家安全局(NSA)于2013年发布,以其简洁性、高效性和灵活性著称。其核心之一在于其密钥扩展算法,该过程能够将初始的短密钥(例如128位)扩展为一长串轮密钥(Round Keys),供加密的每一轮使用。
为了让您完全理解,我们的讲解路径将如下:首先概述SPECK算法的基本参数;然后深入到核心——密钥扩展算法的每一步;最后,通过一个具体的数值例子串联起整个过程。
第一部分:SPECK算法家族与基本参数
SPECK并不是一个单一的算法,而是一个算法族。它被设计为支持多种分组大小(如32、48、64、96、128位)和密钥大小(如64、72、96、128、144、192、256位)的组合。不同的组合对应不同的加密轮数。
为了讲解的清晰性,我们选取其中最经典、文档中最常见的一个版本作为示例:
- 分组大小(n):64位。这意味着算法一次加密或解密64位(8字节)的明文/密文。
- 密钥大小(m):128位。初始密钥为128位(16字节)。
- 字长(w):16位。这是算法内部运算的基本单位。对于64位分组,它被划分为4个16位的字。
- 轮数(T):27轮。需要27个轮密钥。
重要概念:在SPECK中,密钥和中间数据都视为由多个w位字组成。对于我们的示例:
- 密钥K = (l₂, l₁, l₀, k₀),共4个16位字(l₂, l₁, l₀, k₀)。其中
k₀通常被视为最右边的字(最低有效字)。 - 轮密钥
rk[i]是单个16位字。
密钥扩展算法的任务,就是用初始的4个16位字密钥 (l₂, l₁, l₀, k₀),生成后续的27个轮密钥字 rk[0] 到 rk[26]。(注意:有时轮密钥从 rk[0] 开始,对应第一轮加密;有时从 rk[1] 开始。我们遵循前者。)
第二部分:密钥扩展算法的核心操作与步骤
SPECK的密钥扩展过程是一个迭代算法,依赖于两个非常简单的位运算操作,这两个操作也出现在其加密轮函数中:
-
循环右移(ROR):将一个字(w位)向右循环移动
α位。在标准SPECK中,α = 7(对于w=16)。- 例如:
ROR(x, 7)将x的每一位向右移7位,最右边的7位移到最左边。
- 例如:
-
循环左移(ROL):将一个字向左循环移动
β位。在标准SPECK中,β = 2(对于w=16)。- 例如:
ROL(x, 2)将x的每一位向左移2位,最左边的2位移到最右边。
- 例如:
-
模加(⊞):两个字进行 模2^w 加法。对于w=16,就是普通的16位整数加法(结果超过65535的部分溢出丢弃)。
现在,我们来看密钥扩展的迭代公式。算法维护两个数组:
k[i]:用于生成轮密钥的序列。l[i]:一个辅助序列。
初始化:
- 设密钥由
m个 w位字组成。在我们的例子中 m=4。我们设置:
注意,k[0] = k₀ l[0] = l₀ l[1] = l₁ l[2] = l₂l数组的下标顺序与初始密钥的书写顺序是反向的,l[2]对应最高字l₂。
迭代生成(对于 i = 0, 1, 2, ...,直到生成足够多的 k[i]):
-
生成下一个轮密钥源
k[i+1]:k[i+1] = (k[i] + ROR(l[i], α)) ⊕ i这里
⊕表示按位异或(XOR),i是当前的轮索引(被视为一个w位常数)。这一步将l[i]循环右移后与k[i]相加,再与轮计数器混淆,产生新的k[i+1]。这个k[i+1]直接就是轮密钥rk[i](对于从0开始的索引,rk[i] = k[i])。 -
更新辅助序列
l[i+1]:l[i+1] = ROL(l[i], β) ⊕ k[i+1]这一步将当前的
l[i]循环左移,然后与刚生成的k[i+1]进行异或,产生用于下一轮迭代的l[i+1]。
停止条件:重复上述迭代,直到计算出 k[0], k[1], ..., k[T-1],这里T=27。因此我们需要迭代到 i = 26,计算出 k[27](但最后一轮加密只需要 k[26])。
第三部分:一个简化的数值演算示例
为了让过程更具体,我们用一个极小化的模型来演算。我们缩小参数以便手动计算:
- 设 字长 w = 4位(代替16位)。
- 设 α = 2, β = 1(代替7和2)。
- 初始密钥为2个字(m=2):
l₀ = 1010₂ (10),k₀ = 1100₂ (12)。
初始化:
k[0] = 1100 (12)
l[0] = 1010 (10)
我们需要生成,比如,3个轮密钥(T=3)。
迭代1 (i=0):
ROR(l[0], 2):l[0] = 1010,循环右移2位 →1010→ROR2位 →**10**10→ 结果是**1010**? 注意4位字:1010循环右移2位:1010-> 后两位10移到前面,前两位10移到后面,结果是**1010**自身? 我们换一个不一样的数字避免恒等。重设l[0] = 0110 (6)。
初始化:k[0]=1100 (12),l[0]=0110 (6)。
ROR(0110, 2):0110-> 右移2位,10到前,01到后,结果为1001 (9)。k[0] + ROR(l[0],2):12 + 9 = 21。模 2^4 = 16,所以21 mod 16 = 5 (0101)。⊕ i:i=0,所以5 ⊕ 0 = 5 (0101)。
因此,k[1] = 0101 (5)。这就是轮密钥rk[0] = 5。- 更新
l[1]:ROL(l[0], 1):0110循环左移1位 →1100 (12)。
⊕ k[1]:12 ⊕ 5 = 1100 ⊕ 0101 = 1001 (9)。
所以,l[1] = 1001 (9)。
迭代2 (i=1):
ROR(l[1], 2):1001->1001-> 右移2位 ->0110 (6)。k[1] + ...:5 + 6 = 11 (1011)。⊕ i:11 ⊕ 1 = 1011 ⊕ 0001 = 1010 (10)。
因此,k[2] = 1010 (10)。这就是轮密钥rk[1] = 10。- 更新
l[2]:ROL(l[1], 1):1001循环左移1位 ->0011 (3)。
⊕ k[2]:3 ⊕ 10 = 0011 ⊕ 1010 = 1001 (9)。
所以,l[2] = 1001 (9)。
迭代3 (i=2):
ROR(l[2], 2):1001-> 同l[1],结果为0110 (6)。k[2] + ...:10 + 6 = 16,模16=0(0000)。⊕ i:0 ⊕ 2 = 0000 ⊕ 0010 = 0010 (2)。
因此,k[3] = 0010 (2)。这就是轮密钥rk[2] = 2。
至此,我们生成了3个轮密钥:rk[0]=5, rk[1]=10, rk[2]=2。整个过程清晰地展示了两个循环移位、模加和异或操作是如何交织,将短暂的初始密钥“拉伸”成一系列看似随机的轮密钥的。
总结
SPECK的密钥扩展算法是其优雅设计的体现。它通过极简的运算(循环移位、模加、异或)和轮计数器的引入,实现了以下目标:
- 密钥雪崩:初始密钥的微小变化,会通过迭代迅速扩散到后续所有轮密钥中。
- 非线性:模加运算提供了非线性特性,防止密钥材料被简单线性分析。
- 效率:所有操作都在字级别进行,在软件和硬件上都能高效实现,非常适合物联网设备等嵌入式平台。
理解了密钥扩展过程,就为掌握SPECK整个加密算法(其轮函数也使用相似操作)奠定了坚实基础。