📄 rfcrfc2040.txt
字号:
这个步骤转换了b-byte密钥为一个存储在L数组中的字序列。在一个小端字节序的
处理器上通过将L数组置零再拷贝K的b个字节实现。下面的代码将在所有的处理器上获得
这个效果:
int i, j, k, LL, t, T;
RC5_WORD L[256/WW]; /* Based on max key size */
RC5_WORD A, B;
/* LL is number of elements used in L. */
LL = (b + WW - 1) / WW;
for (i = 0 ; i < LL ; i++) {
L[i] = 0;
}
for (i = 0 ; i < b ; i++) {
t = (K[i] & 0xFF) << (8*(i%4)); /* 0, 8, 16, 24*/
L[i/WW] = L[i/WW] + t;
}
5.4 初始化扩展密钥表
这一步使用一个基于Pw加Qw再模2的W次方的算术级的固定伪随机数模式来填充
S表。元素S[i]等于i*Qw+Pw模2的W次方。这个表可以被预计算和按所需进行拷贝或在空
闲时间计算。C代码如下:
T = 2*(R+1);
S[0] = Pw;
for (i = 1 ; i < T ; i++) {
S[i] = S[i-1] + Qw;
}
5.5 混合密钥
这一步混合密钥K到扩展密钥S。混合函数的循环次数K为被初始化的L元素的个
数的3倍,表示为LL,S中的元素个数表示为T。每个循环类似一个加密内部循环的反复因
为两个变量A和B是由这个加密循环的第一部分和第二部分更新的。
A和B的初始值为0,i作为S数组的索引,j作为L数组的索引。第一个循环左移
式的局部结果通过计算S[i],A和B的和得到。然后将这个结果循环左移3位后赋给A。接
着将A的值赋给S[i]。第二个循环左移的局部结果通过计算L[i],A和B的和得到。然后
将这个结果循环左移A+B位后赋给B。接着将B的值赋给L[j]。在循环结束前i、j的值
加1模各自对应的数组的长度。C代码如下:
i = j = 0;
A = B = 0;
if (LL > T)
k = 3 * LL; /* Secret key len > expanded key. */
else
k = 3 * T; /* Secret key len < expanded key. */
for ( ; k > 0 ; k--) {
A = ROTL(S[i] + A + B, 3, W);
S[i] = A;
B = ROTL(L[j] + A + B, A + B, W);
L[j] = B;
i = (i + 1) % T;
j = (j + 1) % LL;
}
return;
} /* End of RC5_Key_Expand */
6. RC5块密码的描述
这部分通过解释对一个简单输入块进行加密操作的步骤来说明RC5块密码。解密处理
与加密处理步骤相反,因此在此不对此进行解释。RC5密码的参数有一个版本号,V,一个轮
数,R,一个以位计数的字尺寸,W。此处的描述对应RC5的原始版本(V=16 十六进制数)囊括
了R的任意正值和W的值16,32和64。
这一处理的输入是密钥扩展表,S,轮数,R,输入缓冲区的指针,in,和输出缓冲区
的指针,out。一个可能的C代码程序头定义如下:
void RC5_Block_Encrypt (S, R, in, out)
RC5_WORD *S;
int R;
char *in;
char *out;
{
6.1 加载A和B的值
这一步转换输入字节为两个无符号整数称作A和B。当RC5被用作64位块密码A和B
是32位的值。第一个输入的字节作为A的低位字节。第四个输入的字节作为A的高位字字
节,第五个输入字节作为B的低位字节,最后一个输入的字节作为B的高位字节。这种转换
对于小端字节序处理器是非常有效率的例如Intel系列。C代码表达如下:
int i;
RC5_WORD A, B;
A = in[0] & 0xFF;
A += (in[1] & 0xFF) << 8;
A += (in[2] & 0xFF) << 16;
A += (in[3] & 0xFF) << 24;
B = in[4] & 0xFF;
B += (in[5] & 0xFF) << 8;
B += (in[6] & 0xFF) << 16;
B += (in[7] & 0xFF) << 24;
6.2 重申轮函数
这一步将扩展密钥与输入混合在一起做基本的加密操作。扩展密钥数组的头两个字]
被分别填充到A和B,然后轮函数被重复R次。
轮函数的前半部分基于A、B和扩展密钥中下一个未用的字的值为A计算一个新的
值。首先A与B异或然后将此结果循环左移B次。循环每次循环W位(例如:对于有64
位块密码的RC5版本循环32位)。实际的循环次数至少是B的W位以2为底的对数。接着
加扩展密钥数组的下一个未用的字形成A的新值。
轮函数的后半部分操作是相同的除了A、B的角色互换一下。特别B保存A与B异
或的结果然后将此结果循环左移A次,接着加上下一个扩展密钥数组中未用的字成为B的
新值。
用C代码表达的一种方式如下:
A = A + S[0];
B = B + S[1];
for (i = 1 ; i <= R ; i++) {
A = A ^ B;
A = ROTL(A, B, W) + S[2*i];
B = B ^ A;
B = ROTL(B, A, W) + S[(2*i)+1];
}
6.3 存储A和B的值
最后一步是转换A和B为一个字节序列。这是打开操作的反变换。C代码可能的表
达如下:
out[0] = (A >> 0) & 0xFF;
out[1] = (A >> 8) & 0xFF;
out[2] = (A >> 16) & 0xFF;
out[3] = (A >> 24) & 0xFF;
out[4] = (B >> 0) & 0xFF;
out[5] = (B >> 8) & 0xFF;
out[6] = (B >> 16) & 0xFF;
out[7] = (B >> 24) & 0xFF;
return;
} /* End of RC5_Block_Encrypt */
7. RC5-CBC和RC5-CBC-Pad模式的描述
这部分描述了RC5密码的CBC和CBC-Pad模式。这一描述是基于RC5密钥对象和
较早的RC5块密码。
7.1 创建密码对象
密码对象需要明了填充模式,轮数,扩展密钥,初始向量,CBC链接块和输入缓冲
区。C代码可能的结构定义形式如下:
/* Definition of the RC5 CBC algorithm object.
*/
typedef struct rc5CBCAlg
{
int Pad; /* 1 = RC5-CBC-Pad, 0 = RC5-CBC. */
int R; /* Number of rounds. */
RC5_WORD *S; /* Expanded key. */
unsigned char I[BB]; /* Initialization vector. */
unsigned char chainBlock[BB];
unsigned char inputBlock[BB];
int inputBlockIndex; /* Next inputBlock byte. */
} rc5CBCAlg;
创建一个密码算法对象,参数必须被检查然后为扩展密钥表分配空间。扩展密钥使用
早先描述的方法来进行初始化。最后,状态变量(填充模式、轮数和输入缓冲区)被赋予初
始值。C代码可能的实现方式如下:
/* Allocate and initialize the RC5 CBC algorithm object.
* Return 0 if problems.
*/
rc5CBCAlg *RC5_CBC_Create (Pad, R, Version, bb, I)
int Pad; /* 1 = RC5-CBC-Pad, 0 = RC5-CBC. */
int R; /* Number of rounds. */
int Version; /* RC5 version number. */
int bb; /* Bytes per RC5 block == IV len. */
char *I; /* CBC IV, bb bytes long. */
{
rc5CBCAlg *pAlg;
int index;
if ((Version != RC5_FIRST_VERSION) ||
(bb != BB) || (R < 0) || (255 < R))
return ((rc5CBCAlg *) 0);
pAlg = (rc5CBCAlg *) malloc (sizeof(*pAlg));
if (pAlg == ((rc5CBCAlg *) 0))
return ((rc5CBCAlg *) 0);
pAlg->S = (RC5_WORD *) malloc (BB * (R + 1));
if (pAlg->S == ((RC5_WORD *) 0)) {
free (pAlg);
return ((rc5CBCAlg *) 0);
}
pAlg->Pad = Pad;
pAlg->R = R;
pAlg->inputBlockIndex = 0;
for (index = 0 ; index < BB ; index++)
pAlg->I[index] = I[index];
return (pAlg);
}
7.2 撤消密码对象
撤消密码是创建它的反变换所关心的问题是在将存储空间返回给存储管理者之前将
其值置为0。C代码的可能实现方式如下:
/* Zero and free an RC5 algorithm object.
*/
void RC5_CBC_Destroy (pAlg)
rc5CBCAlg *pAlg;
{
RC5_WORD *to;
int count;
if (pAlg == ((rc5CBCAlg *) 0))
return;
if (pAlg->S == ((RC5_WORD *) 0))
return;
to = pAlg->S;
for (count = 0 ; count < (1 + pAlg->R) ; count++)
{
*to++ = 0; /* Two expanded key words per round. */
*to++ = 0;
}
free (pAlg->S);
for (count = 0 ; count < BB ; count++)
{
pAlg->I[count] = (unsigned char) 0;
pAlg->inputBlock[count] = (unsigned char) 0;
pAlg->chainBlock[count] = (unsigned char) 0;
}
pAlg->Pad = 0;
pAlg->R = 0;
pAlg->inputBlockIndex = 0;
free (pAlg);
}
7.3 为密码对象设置初始向量
对于CBC密码对象,算法的状态依赖于扩展密钥,CBC链接块和任何内部缓存的
输入。经常相同的密钥被许多管理者使用每一个拥有独一无二的初始向量。消除创建新的密
码对象的系统开销,提供一个允许调用者为一个以存在的密码对象改变初始向量的操作将更
有意义。C代码的可能实现方式如下:
/* Setup a new initialization vector for a CBC operation
* and reset the CBC object.
* This can be called after Final without needing to
* call Init or Create again.
* Return zero if problems.
*/
int RC5_CBC_SetIV (pAlg, I)
rc5CBCAlg *pAlg;
char *I; /* CBC Initialization vector, BB bytes. */
{
int index;
pAlg->inputBlockIndex = 0;
for (index = 0 ; index < BB ; index++)
{
pAlg->I[index] = pAlg->chainBlock[index] = I[index];
pAlg->inputBlock[index] = (unsigned char) 0;
}
return (1);
}
7.4 绑定一个密钥到一个密码对象
绑定一个密钥到一个密码对象的操作执行了密钥扩展。密钥扩展可能是在密钥上进
行的一个操作,但是当他们操作时修改扩展密钥将使之不能为正确的为密码工作。扩展密钥
后,这个操作必须用初始向量初始化CBC链接块并且为接受第一个字符准备缓冲区。C代
码的操作如下:
/* Initialize the encryption object with the given key.
* After this routine, the caller frees the key object.
* The IV for this CBC object can be changed by calling
* the SetIV routine. The only way to change the key is
* to destroy the CBC object and create a new one.
* Return zero if problems.
*/
int RC5_CBC_Encrypt_Init (pAlg, pKey)
rc5CBCAlg *pAlg;
rc5UserKey *pKey;
{
if ((pAlg == ((rc5CBCAlg *) 0)) ||
(pKey == ((rc5UserKey *) 0)))
return (0);
RC5_Key_Expand (Key->keyLength, pKey->keyBytes,
pAlg->R, pAlg->S);
return (RC5_CBC_SetIV(pAlg, pAlg->I));
}
7.5 消息的处理部分
此处的加密操作使用Init-Update-Final过程描述。Update操作被用于消息部分的一
个序列为了递增的产生密文。在最后部分被处理后,Final被调用获得任意的明文字节或填
充被缓存在密码对象内的明文字节。这个操作的一个合适的程序头如下:
/* Encrypt a buffer of plaintext.
* The plaintext and ciphertext buffers can be the same.
* The byte len of the ciphertext is put in *pCipherLen.
* Call this multiple times passing successive
* parts of a large message.
* After the last part has been passed to Update,
* call Final.
* Return zero if problems like output buffer too small.
*/
int RC5_CBC_Encrypt_Update (pAlg, N, P,
pCipherLen, maxCipherLen, C)
rc5CBCAlg *pAlg; /* Cipher algorithm object. */
int N; /* Byte length of P. */
char *P; /* Plaintext buffer. */
int *pCipherLen;/* Gets byte len of C. */
int maxCipherLen; /* Size of C. */
char *C; /* Ciphertext buffer. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -