详谈RC5加密
参考文章:
背景与历史
RC5是Ron Rivest开发的对称密钥块加密算法。RC5的主要特性是很快,只是用基本的计算机运算(加、异或、移位等),轮数可变,密钥位数可变,从而大大增加灵活性。需要不同安全性的应用程序可以相应设置这些值。RC5的另一个重要特性是执行所需的内存更少。
RC5工作的基本原理
RC5的字长(即输入明文块的长度)、轮数和密钥8位字节数都是可变的。一旦确认之后,这些值在执行特定的加密算法时保持不变。这些变量在执行特定的RC5实例之前是可变的,可以从取值范围中选择。而DES的块长只能是64位,密钥长度只能是56位;IDEA的块长只能是64位,密钥长度只能是128位。下表列出了RC5一些参数的取值范围:
(1)明文块长可以是32、64或者128位(使用2个块)
(2)密钥长度为0~2040位(指定了8位密钥的取值)
RC5的输出是密文,与输入明文具有相同的参数。由于RC5算法的三个参数可以改变数值,因此RC5算法的特定实例记作RC5-w/r/b,其中w为字长(位),r为轮数,b为密钥的8位字节数。这样,RC5-32/16/16表示为RC5的块长为64位(注:RC5使用两个字块)、16轮加密和16字节密钥。Ron Rivest推荐的最低安全版本为RC5-32/16/16。
RC5 算法流程概述
- 分组大小:两个 w-bit(32-bit)字 = 一共64位
- 输入:两个32-bit字 (A,B)
- 密钥扩展:生成 2r+2 个32-bit子密钥
- 加密轮数:r轮
每一轮:
- A = ((A ⊕ B) <<< B) + S[2i]
- B = ((B ⊕ A) <<< A) + S[2i+1]
解密就是逆过程。
操作原理(这边以RC5-32/12/16为例)
由于使用上述记法,RC5初看起来比较复杂。首先介绍RC5的工作原理,为了便于理解RC5算法,假设输入明文块的长度为64位,其他块长的操作原理是一样的。
在一次性初始操作中,输入明文块分成两个32位块A和B,前两个子密钥(稍后会介绍如何生成)S[0]和S[1]分别加进A和B,分别产生C和D,表示一次性操作结束。
然后开始各轮,每一轮完成系列操作:
(1)位异或运算;
(2)循环左移;
(3)对C和D增加下一个子密钥,先是加法运算,然后将结果用2的w次方求模(由于这里w=32,因此为2的32次方)。
RC5 的工作原理,如下图所示:
从上图可以看出,初始操作有两步,然后是几轮操作,轮数可以取0~255。也可以从中看出,一个块的输出是另一个块的输入,是整个逻辑很难破译。
加密代码如下:
1 | //循环位移操作 |
1 | uint32_t A = in[0] + S[0]; |
扩展密钥
子密钥生成
这一步使用两个常量P和Q。生成的子密钥数组称为S,第一个子密钥为S[0]用P值初始化。
每个后续子密钥(S[1],S[2],…)根据前面的子密钥和常量Q求出,用2的32次方
求模。这个过程要进行2(r+1)-1次,其中r位轮数。下图显示了子密钥生成的数学形式:
这个过程把主密钥 K 扩展为 S[0..25] 子密钥。
分步讲解:
1 | void generateSubkeys(uint8_t* K, uint32_t* S) |
将字节数组 K 转换成 4个32位整数 L[0..3]
1 | uint32_t L[c] = { 0 }; |
示意:
1 | K[0..15] --> L[0..3] |
例如:
1 | K[0]=0xAA K[1]=0xBB K[2]=0xCC K[3]=0xDD |
初始化子密钥数组 S[0..25]
1 | S[0] = 0xB7E15163; |
这里用两个“幻数”:
- PW = 0xB7E15163 (2^w * (e - 2))
- QW = 0x9E3779B9 (2^w * (Golden Ratio - 1)) 这是RC5官方定义。
这一部分按照原理来说的话应该是(S[i-1] + 0x9E3779B9)% (1<<32)
(% (1<<32)就是取2的32次方的mod)
但这个代码里面没有,为什么呢?
因为我用的是uint32_t类型
在 C 语言里 uint32_t 类型是无符号32位整数。
当超过 2^32 时,会自动溢出并回绕到模 2^32 的余数。
子密钥混合
子密钥混合阶段将子密钥S[],S[],…与原密钥L[],L[],…混合。其数学形式如下图所示:
如上图所示,首先初始化i,j,A和B;其次将子密钥与A和B相加,并左移3位,赋给A和该子密钥,将原密钥与A和B相加,并左移A加B位,赋给B和该原密钥;最后,将i加1,并用2(r+1)求模,将j加1,并用c求模,循环3×n次结束。
注:c是原密钥中最后一个子密钥部分,<<<表示循环左移。
代码实现
1 | uint32_t A = 0, B = 0; |
整体加解密代码实现(以RC5-32/12/16为例)
1 |
|