組織:中國互動出版網(http://www.china-pub.com/)
RFC文檔中文翻譯計劃(http://www.china-pub.com/compters/emook/aboutemook.htm)
E-mail:ouyang@china-pub.com
譯者:金鳳(phoenix_jin take.a.bow@263.net)
譯文發布時間:2001-9-10
版權:本中文翻譯文檔版權歸中國互動出版網所有。可以用於非商業用途自由轉載,但必須
保留本文檔的翻譯及版權信息。
Network Working Group R. Baldwin
Request for Comments: 2040 RSA Data Security, Inc.
Category: Informational R. Rivest
MIT Laboratory for Computer Science
and RSA Data Security, Inc.
October 1996
RC5,RC5-CBC,RC5-CBC-PAD和RC5-CTS算法
( RFC2040 ——The RC5, RC5-CBC, RC5-CBC-Pad, and RC5-CTS Algorithms )
本備忘錄的狀態
本文檔講述了一種Internet社區的Internet標準跟蹤協議,它需要進一步進行討論和建議以得到改進。請參考最新版的“Internet正式協議標準” (STD1)來獲得本協議的標準化程度和狀態。本備忘錄的發布不受任何限製。
版權聲明
Copyright (C) The Internet Society (2001).
目錄
1.實現概述 2
2.總覽 3
3.術語和符號 3
4. RC5密鑰的描述 4
4.1 創建一個RC5密鑰 4
4.2 銷毀一個RC5密鑰 5
4.3 設置一個RC5密鑰 5
5.設置一個RC5密鑰 6
5.1 初始常量定義 7
5.2 接口定義 7
5.3 轉換密鑰從字節到字 8
5.4 初始化擴展密鑰表 8
5.5 混合密鑰 8
6. RC5塊密碼的描述 9
6.1 加載A和B的值 9
6.2 重申輪函數 10
6.3 存儲A和B的值 10
7. RC5-CBC和RC5-CBC-Pad模式的描述 11
7.1 創建密碼對象 11
7.2 撤消密碼對象 12
7.3 為密碼對象設置初始向量 13
7.5 消息的處理部分 14
7.5.1 輸出緩衝區大小的檢查 15
7.5.2 將明文分成塊 15
7.6 最後塊的處理 16
8. RC5-CTS的描述 17
9.測試程序和向量 18
9.1 測試程序和向量 18
9.2 測試向量 22
9.3 測試結果 23
10.安全考慮 25
11. ASN.1標識符 26
12.參考 26
13.作者地址 27
1.實現概述
這個文檔定義了四種形式的密碼算法擁有足夠的信息以確保不同實現間的協同工作能力。第一種是原始的RC5塊加密,RC5密碼使用固定的輸入長度使用一個依賴密鑰的轉換產生一個固定長度的輸出塊。第二種是,RC5-CBC,是RC5的塊密碼鏈接模式。它能處理長度是RC5塊尺寸倍數的消息。第三種是,RC5-CBC-Pad,處理任意長度的明文,盡管密文將比明文長但長度至多長一個RC5塊。RC5-CTS密碼是RC5算法的密文挪用模式,處理任意長度的明文且密文的長度匹配明文的長度。RC5密碼是1994由麻薩諸塞技術研究所的Ronald L. Rivest教授發明的。它是一種非常快速且簡單的算法由塊尺寸,輪數,和密鑰長度參數化。這些參數能被調整以滿足不同的安全目的,性能和出口能力。合並的RSA數據安全已經歸檔了RC5密碼的專利的申請和RC5,RC5-CBC,RC5-CBC-Pad,RC5-CTS並分類了各種變更。
2.總覽
這個備忘錄是對存在的出版資料的重述。RC5的描述是遵從Rivest教授原始的RC5論文中的符號和解釋順序。CBC模式出現在參考著作中例如Bruce Schneier寫的。CBC-Pad模式與公鑰加密標準(PKCS #5)相同。參考C代碼被包括隻是為了清楚等同於英語的描述。密碼將以一種倒置的麵向對象的風格來解釋。首先,RC5密鑰將伴隨著密鑰擴展算法出現。接著RC5塊密碼將被解釋,最後,將規定RC5-CBC和RC5-CBC-Pad密碼。為了簡短,隻有加密過程被描述。解密可以通過轉化加密的步驟來實現。此處的麵向對象的描述應該使得實現交互性係統更加容易,盡管並不像參考文獻中的功能描述那樣簡單。有兩個對象類,密鑰和密碼算法。兩個類用同一種方式共享創建和撤消這些對象的操作確保秘密信息沒有被返回給存儲管理者。密鑰也擁有一個“set”操作拷貝一個秘密密鑰到對象。密碼對象的“set”操作定義了輪數,和初始向量。在這個備忘錄描述了對於密碼對象四個操作。綁定一個密鑰到密碼對象,為每一個密碼對象設置一個新的初始向量沒有改變密鑰,一個消息的加密部分(對於長的消息要執行多次),和處理消息的最後一個部分可以進行填充或檢查消息的長度。總之,密碼將根據這些操作被解釋:
RC5_Key_Create - 創建一個密鑰對象.
RC5_Key_Destroy - 撤消一個密鑰的對象.
RC5_Key_Set - 綁定一個用戶密鑰到密鑰對象.
RC5_CBC_Create - 創建一個密碼對象.
RC5_CBC_Destroy - 撤消一個密碼對象.
RC5_CBC_Encrypt_Init - 綁定一個密鑰對象到一個密碼對象.
RC5_CBC_SetIV - 設置一個初始向量不用改變密鑰.
RC5_CBC_Encrypt_Update - 一個消息的處理部分.
RC5_CBC_Encrypt_Final - 消息末尾的處理.
3.術語和符號
術語“word”指的是一個特殊長度位數的字符串既可以作為一個無符號整數也可以作為一個位向量。例如一個“word”可以是32位也可以是64位取決於需要的RC5密碼塊的的尺寸。一個32位字將產生一個64位的塊。為了取得最好的性能RC5子長度應和CPU的寄存器的長度相匹配。術語“byte”指8位二進製位數。
下麵的變量在此備忘錄中將以如下定義使用:
W 這個變量表示的是RC5以二進製位數計算的字的尺寸。是塊尺寸的一半在此備忘錄中字的尺寸采用的是32和64。
WW 此變量是RC5以字節計算的字尺寸。
B 此變量是以位計算的塊尺寸。是2倍的字尺寸。當RC5被用作64位的塊密碼。B是64,W是32。0<B<257。在簡單的代碼中,B被用作一個代替密碼係統參數的變量,但是這個使用應該是上下文明顯的。
BB 此變量是以字節計算的塊尺寸。BB=B/8。
b 這個變量是密鑰的字節長度。B0<=b<256。
K 作為一個 b個字節長的密鑰序列,通過K[0],...,K[b-1]索引。
R 此變量是一個內部RC5轉換的輪數。0<=R<256。
T 此變量是一個擴展密鑰表的字數。總是2*(R+1)。 1<T<513。
S 作為擴展密鑰表的字數組,通過S[0],..,S[T-1]索引。
N 此變量是明文消息的字節長度。
P 作為名文消息以一個N字節數組形式存儲,通過P[0],..,P[N-1]索引。
C 作為密文輸出以一個字節數組形式存儲,通過C[0],C[1],...索引。
I 作為CBC模式的初始向量以一個字節數組形式存儲,通過I[0],..,I[BB-1]索引。
4. RC5密鑰的描述
像大多數密碼塊,RC5將一個小的用戶密鑰擴展為一個內部密鑰表。用戶密鑰的字節長度是密碼的參數之一。因此RC5的用戶密鑰對象必須能擁有可變長度密鑰。一個C的可能的結構是:
/* RC5的用戶密鑰對像的定義. */
typedef struct rc5UserKey
{
int keyLength; /* In Bytes. */
unsigned char *keyBytes;
} rc5UserKey;
對密鑰的基本操作是創建,銷毀和設置。為了避免將密鑰資料暴露給一個應用的其他部分,密鑰的銷毀操作應該在將分配給密鑰的空間釋放給存儲管理者之前將該存儲空間置零。一個一般的密鑰對象可以支持其他的操作像產生一個新的隨機密鑰和從協商的密鑰信息中獲取密鑰。
4.1 創建一個RC5密鑰
創建一個密鑰,密鑰對象的存儲空間必須被分配和初始化。下麵的C代碼假設一個稱作“malloc”的函數將從堆返回一個未初始化的存儲空間塊,或0指出一個錯誤。
/* 分配和初始化一個RC5用戶密鑰.
* 如果有問題返回0.
*/
rc5UserKey *RC5_Key_Create ()
{
rc5UserKey *pKey;
pKey = (rc5UserKey *) malloc (sizeof(*pKey));
if (pKey != ((rc5UserKey *) 0))
{
pKey->keyLength = 0;
pKey->keyBytes = (unsigned char *) 0;
}
return (pKey);
}
4.2 銷毀一個RC5密鑰
為了銷毀一個密鑰,存儲空間必須被置零和被釋放給一個存儲管理者。以下C代碼假設稱作“free”的函數將返回一個存儲塊給堆。
/* 置零且釋放一個RC5用戶密鑰.
*/
void RC5_Key_Destroy (pKey)
rc5UserKey *pKey;
{
unsigned char *to;
int count;
if (pKey == ((rc5UserKey *) 0))
return;
if (pKey->keyBytes == ((unsigned char *) 0))
return;
to = pKey->keyBytes;
for (count = 0 ; count < pKey->keyLength ; count++)
*to++ = (unsigned char) 0;
free (pKey->keyBytes);
pKey->keyBytes = (unsigned char *) 0;
pKey->keyLength = 0;
free (pKey);
4.3 設置一個RC5密鑰
設置一個密鑰對象將密鑰拷貝到一個從堆分配的存儲空間。
/* 設置RC5用戶密鑰的值.
* 拷貝密鑰字節以便調用者能置零和釋放原來的值.
* 如果出現問題返回0
*/
int RC5_Key_Set (pKey, keyLength, keyBytes)
rc5UserKey *pKey;
int keyLength;
unsigned char *keyBytes;
{
unsigned char *keyBytesCopy;
unsigned char *from, *to;
int count;
keyBytesCopy = (unsigned char *) malloc (keyLength);
if (keyBytesCopy == ((unsigned char *) 0))
return (0);
from = keyBytes;
to = keyBytesCopy;
for (count = 0 ; count < keyLength ; count++)
*to++ = *from++;
pKey->keyLength = count;
pKey->keyBytes = keyBytesCopy;
return (1);
}
5.設置一個RC5密鑰
這部分描述了密鑰擴展算法。作為特殊的定義,示例代碼假設塊的大小為64位。幾個編程參數依賴於塊大小。
/*定義 RC5 為一個 64 位塊密碼. */
/* The "unsigned int" will be 32 bits on all but */
/* the oldest compilers, which will make it 16 bits. */
/* On a DEC Alpha "unsigned long" is 64 bits, not 32. */
#define RC5_WORD unsigned int
#define W (32)
#define WW (W / 8)
#define ROT_MASK (W - 1)
#define BB ((2 * W) / 8) /* Bytes per block */
/* Define macros used in multiple procedures. */
/* These macros assumes ">>" is an unsigned operation, */
/* and that x and s are of type RC5_WORD. */
#define SHL(x,s) ((RC5_WORD)((x)<<((s)&ROT_MASK)))
#define SHR(x,s,w) ((RC5_WORD)((x)>>((w)-((s)&ROT_MASK))))
#define ROTL(x,s,w) ((RC5_WORD)(SHL((x),(s))|SHR((x),(s),(w))))
5.1 初始常量定義
兩個常量,Pw和Qw,定義為可以使用任意大小的W表達式如下:
Pw=Odd((e-2)*2**W)
Qw=Odd((phi-1)*2**W)
e是自然對數的底(2.71828...),phi是黃金比例(1.61803...),2**W是2的W此方,Odd(x)等於x如果x是奇數或等於x+1如果x是偶數。W等於16,32和64,Pw和Qw常量是下麵的16進製值:
#define P16 0xb7e1
#define Q16 0x9e37
#define P32 0xb7e15163
#define Q32 0x9e3779b9
#define P64 0xb7e151628aed2a6b
#define Q64 0x9e3779b97f4a7c15
#if W == 16
#define Pw P16 /* Select 16 bit word size */
#define Qw Q16
#endif
#if W == 32
#define Pw P32 /* Select 32 bit word size */
#define Qw Q32
#endif
#if W == 64
#define Pw P64 /* Select 64 bit word size */
#define Qw Q64
#endif
5.2 接口定義
密鑰擴展規則轉換b-byte密鑰,K,為一個擴展密鑰,S,是一個T=2*(R+1)個字的序列。擴展算法使用了兩個常量是來自常量e和phi.這些被用於初始化S,然後使用K進行修改。使用這個規則的一個C代碼程序頭如下:
/* Expand an RC5 user key.
*/
void RC5_Key_Expand (b, K, R, S)
int b; /* Byte length of secret key */
char *K; /* Secret key */
int R; /* Number of rounds */
RC5_WORD *S; /* Expanded key buffer, 2*(R+1) words */
{
5.3 轉換密鑰從字節到字
這個步驟轉換了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. */
{
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
#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]));
ptv->cipher_length += numBytesOut;
(void) RC5_CBC_Encrypt_Final (pAlg,
&(numBytesOut),
MAX_CIPHER_LENGTH - ptv->cipher_length,
&(ptv->cipher[ptv->cipher_length]));
ptv->cipher_length += numBytesOut;
bytes_to_hex (ptv->cipher, ptv->cipher_length,
ptv->ciphertext);
RC5_Key_Destroy (pKey);
RC5_CBC_Destroy (pAlg);
}
void show_results (ptv)
test_vector *ptv;
{
if (ptv->padding_mode)
printf ("RC5_CBC_Pad ");
else
printf ("RC5_CBC ");
printf ("R = %2d ", ptv->rounds);
printf ("Key = %s ", ptv->keytext);
printf ("IV = %s ", ptv->ivtext);
printf ("P = %s ", ptv->plaintext);
printf ("C = %s", ptv->ciphertext);
printf ("\n");
}
int main(argc, argv)
int argc;
char *argv[];
{
test_vector tv;
test_vector *ptv = &tv;
show_banner();
while (get_test_vector(ptv)) {
run_test(ptv);
show_results(ptv);
}
return (0);
}
9.2 測試向量
下麵的文本是前一節測試程序的輸入文件。輸出在下一節中給出。
0 00 00 0000000000000000 0000000000000000
0 00 00 0000000000000000 ffffffffffffffff
0 00 00 0000000000000001 0000000000000000
0 00 00 0000000000000000 0000000000000001
0 00 00 0102030405060708 1020304050607080
0 01 11 0000000000000000 0000000000000000
0 02 00 0000000000000000 0000000000000000
0 02 00000000 0000000000000000 0000000000000000
0 08 00 0000000000000000 0000000000000000
0 08 00 0102030405060708 1020304050607080
0 12 00 0102030405060708 1020304050607080
0 16 00 0102030405060708 1020304050607080
0 08 01020304 0000000000000000 ffffffffffffffff
0 12 01020304 0000000000000000 ffffffffffffffff
0 16 01020304 0000000000000000 ffffffffffffffff
0 12 0102030405060708 0000000000000000 ffffffffffffffff
0 08 0102030405060708 0102030405060708 1020304050607080
0 12 0102030405060708 0102030405060708 1020304050607080
0 16 0102030405060708 0102030405060708 1020304050607080
0 08 01020304050607081020304050607080
0102030405060708 1020304050607080
0 12 01020304050607081020304050607080
0102030405060708 1020304050607080
0 16 01020304050607081020304050607080
0102030405060708 1020304050607080
0 12 0102030405 0000000000000000 ffffffffffffffff
0 08 0102030405 0000000000000000 ffffffffffffffff
0 08 0102030405 7875dbf6738c6478 0808080808080808
1 08 0102030405 0000000000000000 ffffffffffffffff
0 08 0102030405 0000000000000000 0000000000000000
0 08 0102030405 7cb3f1df34f94811 1122334455667701
1 08 0102030405 0000000000000000
ffffffffffffffff7875dbf6738c647811223344556677
9.3 測試結果
下麵的文本是測試程序運行於前一節給定輸入的輸出文本。
RC5 CBC 測試器。
每個輸入行應該包含下麵用空格號分隔的測試參數:
-填充模式標誌。使用1表示RC5-CBC-Pad,其餘用0表示。
-RC5的輪數。
-16進製的密鑰。每字節兩個字符像‘01’。
-16進製的初始向量。必須是16進製的字節。
-16進製的明文字節。
到達文件末尾或格式錯誤終止測試器。
RC5_CBC R = 0 Key = 00 IV = 0000000000000000
P = 0000000000000000 C = 7a7bba4d79111d1e
RC5_CBC R = 0 Key = 00 IV = 0000000000000000
P = ffffffffffffffff C = 797bba4d78111d1e
RC5_CBC R = 0 Key = 00 IV = 0000000000000001
P = 0000000000000000 C = 7a7bba4d79111d1f
RC5_CBC R = 0 Key = 00 IV = 0000000000000000
P = 0000000000000001 C = 7a7bba4d79111d1f
RC5_CBC R = 0 Key = 00 IV = 0102030405060708
P = 1020304050607080 C = 8b9ded91ce7794a6
RC5_CBC R = 1 Key = 11 IV = 0000000000000000
P = 0000000000000000 C = 2f759fe7ad86a378
RC5_CBC R = 2 Key = 00 IV = 0000000000000000
P = 0000000000000000 C = dca2694bf40e0788
RC5_CBC R = 2 Key = 00000000 IV = 0000000000000000
P = 0000000000000000 C = dca2694bf40e0788
RC5_CBC R = 8 Key = 00 IV = 0000000000000000
P = 0000000000000000 C = dcfe098577eca5ff
RC5_CBC R = 8 Key = 00 IV = 0102030405060708
P = 1020304050607080 C = 9646fb77638f9ca8
RC5_CBC R = 12 Key = 00 IV = 0102030405060708
P = 1020304050607080 C = b2b3209db6594da4
RC5_CBC R = 16 Key = 00 IV = 0102030405060708
P = 1020304050607080 C = 545f7f32a5fc3836
RC5_CBC R = 8 Key = 01020304 IV = 0000000000000000
P = ffffffffffffffff C = 8285e7c1b5bc7402
RC5_CBC R = 12 Key = 01020304 IV = 0000000000000000
P = ffffffffffffffff C = fc586f92f7080934
RC5_CBC R = 16 Key = 01020304 IV = 0000000000000000
P = ffffffffffffffff C = cf270ef9717ff7c4
RC5_CBC R = 12 Key = 0102030405060708 IV = 0000000000000000
P = ffffffffffffffff C = e493f1c1bb4d6e8c
RC5_CBC R = 8 Key = 0102030405060708 IV = 0102030405060708
P = 1020304050607080 C = 5c4c041e0f217ac3
RC5_CBC R = 12 Key = 0102030405060708 IV = 0102030405060708
P = 1020304050607080 C = 921f12485373b4f7
RC5_CBC R = 16 Key = 0102030405060708 IV = 0102030405060708
P = 1020304050607080 C = 5ba0ca6bbe7f5fad
RC5_CBC R = 8 Key = 01020304050607081020304050607080
IV = 0102030405060708
P = 1020304050607080 C = c533771cd0110e63
RC5_CBC R = 12 Key = 01020304050607081020304050607080
IV = 0102030405060708
P = 1020304050607080 C = 294ddb46b3278d60
RC5_CBC R = 16 Key = 01020304050607081020304050607080
IV = 0102030405060708
P = 1020304050607080 C = dad6bda9dfe8f7e8
RC5_CBC R = 12 Key = 0102030405 IV = 0000000000000000
P = ffffffffffffffff C = 97e0787837ed317f
RC5_CBC R = 8 Key = 0102030405 IV = 0000000000000000
P = ffffffffffffffff C = 7875dbf6738c6478
RC5_CBC R = 8 Key = 0102030405 IV = 7875dbf6738c6478
P = 0808080808080808 C = 8f34c3c681c99695
RC5_CBC_Pad R = 8 Key = 0102030405 IV = 0000000000000000
P = ffffffffffffffff C = 7875dbf6738c64788f34c3c681c99695
RC5_CBC R = 8 Key = 0102030405 IV = 0000000000000000
P = 0000000000000000 C = 7cb3f1df34f94811
RC5_CBC R = 8 Key = 0102030405 IV = 7cb3f1df34f94811
P = 1122334455667701 C = 7fd1a023a5bba217
RC5_CBC_Pad R = 8 Key = 0102030405 IV = 0000000000000000
P = ffffffffffffffff7875dbf6738c647811223344556677
C = 7875dbf6738c64787cb3f1df34f948117fd1a023a5bba217
10.安全考慮
RC5密碼相對來說是比較新的所以鑒定的評論仍在進行。然而,密碼的簡單結構使它易於分析而且有希望更容易的評定它的的強度。迄今為止的評論是有前途的。早期的結果暗示12輪64位塊大小的RC5將有足夠的能力抗拒線性和差分密碼分析。128位的塊版本還未像64位的塊版本進行多次研究。但是明顯的16輪是一個合適的最小值。小於64位的塊尺寸學術上的興趣但是不應被用於密碼安全。更大的安全可以通過增加輪數獲得其代價是減少密碼的吞吐量。
密鑰的長度幫助決定密碼對窮舉攻擊的抵抗力。一個128位的密鑰長度應該幾十年的時間裏為抗拒資金雄厚的對手的窮舉攻擊提供保護。12輪的RC5,密鑰的建立時間和數據加密時間對於所有長度小於832位的密鑰來說都是相同的。因此沒有因為不需要為了性能要求而選擇短密鑰。對於大的密鑰,因為用戶的密鑰表,L,將比擴展密鑰表,S,長所以密鑰擴展的步驟會運行的比較慢。然而,加密時間將不會改變因此它隻是一個輪數的函數。
未了配合出口規則可能需要選擇密鑰隻有40個未知位。進行這一步處理的簡單方式是選擇一個簡單的5個字節的密鑰。這應該被避免因為對手可以容易的預計算密鑰搜索信息。另一個一般的機製是選擇128位的密鑰出版頭88位。這個方法揭示了大量的通往用戶密鑰表,L,的路徑。且是否RC5密鑰擴展表在這種情況下提供了足夠的安全還未進行研究。盡管它可能是好的。一個與40位密鑰限製一致的一種保守的方法是選擇128位的種子值,出版這個種子的前88位,通過像MD5的散列函數運行整個種子值,使用這個散列函數的128位的輸出作為RC5的密鑰。
在有40位未知密鑰和88位已知密鑰的情況下,對於64位RC5塊版本應該有12輪或更高的輪數,否則增加給密鑰的88位的值可能被丟失。
密鑰的生存期也是影響安全的關鍵。對於高安全的應用,任何64位塊密碼的密鑰應該在加密了2**32個塊後被改變(2**64個塊對於128位的塊密碼)。這將幫助防範線性和差分密碼分析。對於64位的塊,這個規則將推薦在2**40個字節被加密後改變密鑰。進一步的討論見Schneier應用密碼學183頁。
11. ASN.1標識符
對於使用ASN.1描述的應用,有必要為這些與他們參數塊格式相一致的密碼定義算法標識符。一個算法標識符的ASN.1的定義已經存在,以下列出作為參考。
AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameters ANY DEFINED BY algorithm OPTIONAL
}
The values for the algorithm field are:
RC5_CBC OBJECT IDENTIFIER ::=
{ iso (1) member-body (2) US (840) rsadsi (113549)
encryptionAlgorithm (3) RC5CBC (8) }
RC5_CBC_Pad OBJECT IDENTIFIER ::=
{ iso (1) member-body (2) US (840) rsadsi (113549)
encryptionAlgorithm (3) RC5CBCPAD (9) }
The structure of the parameters field for these algorithms is given
below. NOTE: if the iv field is not included, then the
initialization vector defaults to a block of zeros whose size depends
on the blockSizeInBits field.
RC5_CBC_Parameters ::= SEQUENCE {
version INTEGER (v1_0(16)),
rounds INTEGER (8..127),
blockSizeInBits INTEGER (64, 128),
iv OCTET STRING OPTIONAL
}
12.參考
[1] Kaliski, Burton S., and Yinqun Lisa Yin, "On Differential and
Linear Cryptanalysis of the RC5 Encryption Algorithm", In Advances
in Cryptology - Crypto '95, pages 171-184, Springer-Verlag, New
York, 1995.
[2] Rivest, Ronald L., "The RC5 Encryption Algorithm", In
Proceedings of the Second International Workshop on Fast Software
Encryption, pages 86-96, Leuven Belgium, December 1994.
[3] Rivest, Ronald L., "RC5 Encryption Algorithm", In Dr. Dobbs
Journal, number 226, pages 146-148, January 1995.
[4] Rivest, Ronald L., "The MD5 Message-Digest Algorithm", RFC1321.
[5] RSA Laboratories, "Public Key Cryptography Standards (PKCS)",RSA Data Security Inc. See ftp.rsa.com.
[6] Schneier, Bruce, "Applied Cryptography", Second Edition, JohnWiley and Sons, New York, 1996. Errata: on page 195, line 13, thereference number should be [402].
[7] Business Software Alliance, Matt Blaze et al., "Minimum KeyLength for Symmetric Ciphers to Provide Adequate CommercialSecurity", http://www.bsa.org/bsa/cryptologists.html.
[8] RSA Data Security Inc., "RC5 Reference Code in C", See the website: www.rsa.com, for availability. Not available with the firstdraft of this document.
13.作者地址
Robert W. Baldwin
RSA Data Security, Inc.
100 Marine Parkway
Redwood City, CA 94065
phones: (415) 595-8782
Fax: (415) 595-1873
EMail: baldwin@rsa.com, or baldwin@lcs.mit.edu
Ronald L. Rivest
Massachusetts Institute of Technology
Laboratory for Computer Science
NE43-324
545 Technology Square
Cambridge, MA 02139-1986
phones: (617) 253-5880
EMail: rivest@theory.lcs.mit.edu
RFC2040——The RC5, RC5-CBC, RC5-CBC-Pad, and RC5-CTS Algorithms
RC5,RC5-CBC,RC5-CBC-PAD和RC5-CTS算法
RFC文檔中文翻譯計劃
彩神彩票 © 1998-2024。
京ICP備34881403號
京公網安備11010802041807號