📄 rfcrfc2040.txt
字号:
{
7.5.1 输出缓冲区大小的检查
明文处理的第一步是确保输出缓冲区有足够大的空间存储密文。密文将以块大小的
倍数被产生依赖于被传递给这个操作的明文字符的个数加任意位于密码对象内部缓冲区的
字符。C代码如下:
int plainIndex, cipherIndex, j;
/* Check size of the output buffer. */
if (maxCipherLen < (((pAlg->inputBlockIndex+N)/BB)*BB))
{
*pCipherLen = 0;
return (0);
}
7.5.2 将明文分成块
下一步是填充字符到内部的缓冲区直到一个块被填满。此时,缓冲区指针被复位输
入缓冲区和CBC链接密码块相异或。链接密码块的字节序和输入块相同。例如:第9个输
入字节和第一个密文字节相异或。结果然后被传递给先前描述的RC5块密码。为了减少数
据的移动和字节调整的问题,RC5的输出能被直接的写到CBC链接块。最后,这个输出被
拷贝到由用户提供的密文缓冲区。在返回前,密文的实际大小被传递给调用者。C代码如下:
plainIndex = cipherIndex = 0;
while (plainIndex < N)
{
if (pAlg->inputBlockIndex < BB)
{
pAlg->inputBlock[pAlg->inputBlockIndex]
= P[plainIndex];
pAlg->inputBlockIndex++;
plainIndex++;
}
if (pAlg->inputBlockIndex == BB)
{ /* Have a complete input block, process it. */
pAlg->inputBlockIndex = 0;
for (j = 0 ; j < BB ; j++)
{ /* XOR in the chain block. */
pAlg->inputBlock[j] = pAlg->inputBlock[j]
^ pAlg->chainBlock[j];
}
RC5_Block_Encrypt(pAlg->S, pAlg->R
pAlg->inputBlock,
pAlg->chainBlock);
for (j = 0 ; j < BB ; j++)
{ /* Output the ciphertext. */
C[cipherIndex] = pAlg->chainBlock[j];
cipherIndex++;
}
}
}
*pCipherLen = cipherIndex;
return (1);
} /* End of RC5_CBC_Encrypt_Update */
7.6 最后块的处理
这一步处理明文的最后一个块。对于RC5-CBC,这一步只是做错误检查确保明文长
度确实是块长度的倍数。对于RC5-CBC-Pad,填充的字节被添加到明文。填充的字节都是
相同的其值被置为填充的字节数。例如如果填充了8个字节,填充的字节其值都为16进制
的0x08。将包含1到BB个填充字节。C代码如下:
/* Produce the final block of ciphertext including any
* padding, and then reset the algorithm object.
* Return zero if problems.
*/
int RC5_CBC_Encrypt_Final (pAlg, pCipherLen, maxCipherLen, C)
rc5CBCAlg *pAlg;
int *pCipherLen; /* Gets byte len of C. */
int maxCipherLen; /* Len of C buffer. */
char *C; /* Ciphertext buffer. */
{
int cipherIndex, j;
int padLength;
/* For non-pad mode error if input bytes buffered. */
*pCipherLen = 0;
if ((pAlg->Pad == 0) && (pAlg->inputBlockIndex != 0))
return (0);
if (pAlg->Pad == 0)
return (1);
if (maxCipherLen < BB)
return (0);
padLength = BB - pAlg->inputBlockIndex;
for (j = 0 ; j < padLength ; j++)
{
pAlg->inputBlock[pAlg->inputBlockIndex]
= (unsigned char) padLength;
pAlg->inputBlockIndex++;
}
for (j = 0 ; j < BB ; j++)
{ /* XOR the chain block into the plaintext block. */
pAlg->inputBlock[j] = pAlg->inputBlock[j]
^ pAlg->chainBlock[j];
}
RC5_Block_Encrypt(pAlg->S, pAlg->R,
pAlg->inputBlock, pAlg->chainBlock);
cipherIndex = 0;
for (j = 0 ; j < BB ; j++)
{ /* Output the ciphertext. */
C[cipherIndex] = pAlg->chainBlock[j];
cipherIndex++;
}
*pCipherLen = cipherIndex;
/* Reset the CBC algorithm object. */
return (RC5_CBC_SetIV(pAlg, pAlg->I));
} /* End of RC5_CBC_Encrypt_Final */
8. RC5-CTS的描述
块密码的密码文本偷窃模式在Schneier的应用密码学的195和196页有叙述。这个
模式处理任意长度的明文并且产生于明文长度相匹配的密文。CTS模式除了明文的最后两个
块的处理不同外和CBC一致。下面几步描述了如何处理明文的最后两个块,称作Pn-1和Pn,
Pn-1的长度等于块大小,BB,最后一个块Pn长度是Ln字节。注意Ln从1到BB变化,因
此Pn实际上可以成为一个完整的块。
1、 异或Pn-1和以前的密文块,Cn-2,创建Xn-1。
2、 加密Xn-1得En-1。
3、 选择En-1的前Ln个字节创建Cn。
4、 在Pn末尾用0填充Pn创建长度为BB的P。
5、 异或En-1和P创建Dn。
6、 加密Dn得Cn-1。
7、 密文的最后两部分分别为Cn-1和Cn。
实现CTS加密,RC5-CTS对象必须拥有至多2*BB个字节的明文存储空间当
RC5_CTS_Encrypt_Final规则被调用时单独处理他们。
下面的步骤描述如何解密Cn-1和Cn。
1、 解密Cn得Dn。
2、 在末尾用0填充Cn创建长度为BB的C。
3、 将Dn和C相异或得Xn。
4、 选择Xn的前Ln个字节创建Pn。
5、 将Xn尾部的BB-Ln个字节添加到Cn得En。
6、 解密En得Pn-1。
7、 明文的最后两个部分分别是Pn-1和Pn。
9.测试程序和向量
帮助证实实现的正确性,这一部分提供了测试程序和一组测试向量的结果。
9.1 测试程序和向量
下面用C写的测试程序从输入流中读测试向量结果写到输出流中。下面的子过程给
了一组测试向量用于输入和结果输出。
#include <stdio.h>
#define BLOCK_LENGTH (8 /* bytes */)
#define MAX_KEY_LENGTH (64 /* bytes */)
#define MAX_PLAIN_LENGTH (128 /* bytes */)
#define MAX_CIPHER_LENGTH(MAX_PLAIN_LENGTH + BLOCK_LENGTH)
#define MAX_ROUNDS (20)
#define MAX_S_LENGTH (2 * (MAX_ROUNDS + 1))
typedef struct test_vector
{
int padding_mode;
int rounds;
char keytext[2*MAX_KEY_LENGTH+1];
int key_length;
char key[MAX_KEY_LENGTH];
char ivtext[2*BLOCK_LENGTH+1];
int iv_length;
char iv[BLOCK_LENGTH];
char plaintext[2*MAX_PLAIN_LENGTH+1];
int plain_length;
char plain[MAX_PLAIN_LENGTH];
char ciphertext[2*MAX_CIPHER_LENGTH+1];
int cipher_length;
char cipher[MAX_CIPHER_LENGTH];
RC5_WORD S[MAX_S_LENGTH];
} test_vector;
void show_banner()
{
(void) printf("RC5 CBC Tester.\n");
(void) printf("Each input line should contain the following\n");
(void) printf("test parameters separated by a single space:\n");
(void) printf("- Padding mode flag. Use 1 for RC5_CBC_Pad, else
0.\n");
(void) printf("- Number of rounds for RC5.\n");
(void) printf("- Key bytes in hexadecimal. Two characters per
byte like '01'.\n");
(void) printf("- IV bytes in hexadecimal. Must be 16 hex
characters.\n");
(void) printf("- Plaintext bytes in hexadecimal.\n");
(void) printf("An end of file or format error terminates the
tester.\n");
(void) printf("\n");
}
/* Convert a buffer from ascii hex to bytes.
* Set pTo_length to the byte length of the result.
* Return 1 if everything went OK.
*/
int hex_to_bytes (from, to, pTo_length)
char *from, *to;
int *pTo_length;
{
char *pHex; /* Ptr to next hex character. */
char *pByte; /* Ptr to next resulting byte. */
int byte_length = 0;
int value;
pByte = to;
for (pHex = from ; *pHex != 0 ; pHex += 2) {
if (1 != sscanf(pHex, "%02x", &value))
return (0);
*pByte++ = ((char)(value & 0xFF));
byte_length++;
}
*pTo_length = byte_length;
return (1);
}
/* Convert a buffer from bytes to ascii hex.
* Return 1 if everything went OK.
*/
int bytes_to_hex (from, from_length, to)
char *from, *to;
int from_length;
{
char *pHex; /* Ptr to next hex character. */
char *pByte; /* Ptr to next resulting byte. */
int value;
pHex = to;
for (pByte = from ; from_length > 0 ; from_length--) {
value = *pByte++ & 0xFF;
(void) sprintf(pHex, "%02x", value);
pHex += 2;
}
return (1);
}
/* Return 1 if get a valid test vector. */
int get_test_vector(ptv)
test_vector *ptv;
{
if (1 != scanf("%d", &ptv->padding_mode))
return (0);
if (1 != scanf("%d", &ptv->rounds))
return (0);
if ((ptv->rounds < 0) || (MAX_ROUNDS < ptv->rounds))
return (0);
if (1 != scanf("%s", &ptv->keytext))
return (0);
if (1 != hex_to_bytes(ptv->keytext, ptv->key,
&ptv->key_length))
return (0);
if (1 != scanf("%s", &ptv->ivtext))
return (0);
if (1 != hex_to_bytes(ptv->ivtext, ptv->iv,
&ptv->iv_length))
return (0);
if (BLOCK_LENGTH != ptv->iv_length)
return (0);
if (1 != scanf("%s", &ptv->plaintext))
return (0);
if (1 != hex_to_bytes(ptv->plaintext, ptv->plain,
&ptv->plain_length))
return (0);
return (1);
}
void run_test (ptv)
test_vector *ptv;
{
rc5UserKey *pKey;
rc5CBCAlg *pAlg;
int numBytesOut;
pKey = RC5_Key_Create ();
RC5_Key_Set (pKey, ptv->key_length, ptv->key);
pAlg = RC5_CBC_Create (ptv->padding_mode,
ptv->rounds,
RC5_FIRST_VERSION,
BB,
ptv->iv);
(void) RC5_CBC_Encrypt_Init (pAlg, pKey);
ptv->cipher_length = 0;
(void) RC5_CBC_Encrypt_Update (pAlg,
ptv->plain_length, ptv->plain,
&(numBytesOut),
MAX_CIPHER_LENGTH - ptv->cipher_length,
&(ptv->cipher[ptv->cipher_length]));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -