📄 rfc2040.txt
字号:
/* 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 Convert secret key from bytes to words This step converts the b-byte key into a sequence of words stored in the array L. On a little-endian processor this is accomplished by zeroing the L array and copying in the b bytes of K. The following C code will achieve this effect on all processors: 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 Initialize the expanded key table This step fills in the S table with a fixed (key independent) pseudo-random pattern using an arithmetic progression based on Pw and Qw modulo 2**W. The element S[i] equals i*Qw + Pw modulo 2**W. This table could be precomputed and copied as needed or computed on the fly. In C code it can be computed by:Baldwin & Rivest Informational [Page 8]RFC 2040 RC5, RC5-CBC, RC5-CBC-Pad, and RC5-CTS October 1996 T = 2*(R+1); S[0] = Pw; for (i = 1 ; i < T ; i++) { S[i] = S[i-1] + Qw; }5.5 Mix in the secret key This step mixes the secret key, K, into the expanded key, S. First the number of iterations of the mixing function, k, is set to three times the maximum of the number of initialized elements of L, called LL, and the number of elements in S, called T. Each iteration is similar to an interation of the encryption inner loop in that two variables A and B are updated by the first and second halves of the iteration. Initially A and B are zero as are the indexes into the S array, i, and the L array, j. In the first half of the iteration, a partial result is computed by summing S[i], A and B. The new value for A is this partial result rotated left three bits. The A value is then placed into S[i]. The second half of the iteration computes a second partial result that is the sum of L[j], A and B. The second partial result is then rotated left by A+B bit positions and set to be the new value for B. The new B value is then placed into L[j]. At the end of the iteration, i and j are incremented modulo the size of their respective arrays. In C code: 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 */Baldwin & Rivest Informational [Page 9]RFC 2040 RC5, RC5-CBC, RC5-CBC-Pad, and RC5-CTS October 19966. Description of RC5 Block Cipher This section describes the RC5 block cipher by explaining the steps required to perform an encryption of a single input block. The decryption process is the reverse of these steps so it will not be explained. The RC5 cipher is parameterized by a version number, V, a round count, R, and a word size in bits, W. This description corresponds to original version of RC5 (V = 16 decimal) and covers any positive value for R and the values 16, 32, and 64 for W. The inputs to this process are the expanded key table, S, the number of rounds, R, the input buffer pointer, in, and the output buffer pointer, out. A possible C code procedure header for this would be: void RC5_Block_Encrypt (S, R, in, out) RC5_WORD *S; int R; char *in; char *out; {6.1 Loading A and B values This step converts input bytes into two unsigned integers called A and B. When RC5 is used as a 64 bit block cipher A and B are 32 bit values. The first input byte becomes the least significant byte of A, the fourth input byte becomes the most significant byte of A, the fifth input byte becomes the least significant byte of B and the last input byte becomes the most significant byte of B. This conversion can be very efficient for little-endian processors such as the Intel family. In C code this could be expressed as: 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;Baldwin & Rivest Informational [Page 10]RFC 2040 RC5, RC5-CBC, RC5-CBC-Pad, and RC5-CTS October 19966.2 Iterating the round function This step mixes the expanded key with the input to perform the fundamental encryption operation. The first two words of the expanded key are added to A and B respectively, and then the round function is repeated R times. The first half of the round function computes a new value for A based on the values of A, B, and the next unused word in the expanded key table. Specifically, A is XOR'ed with B and then this first partial result is rotated to the left by an amount specified by B to form the second partial result. The rotation is performed on a W bit boundary (i.e., 32 bit rotation for the version of RC5 that has a 64 bit block size). The actual rotation amount only depends on the least significant log base-2 of W bits of B. The next unused word of the expanded key table is then added to the second partial result and this becomes the new value for A. The second half of the round function is identical except the roles of A and B are switched. Specifically, B is exclusive or'ed with A and then this first partial result is rotated to the left by an amount specified by A to form the second partial result. The next unused word of the expanded key table is then added to the second partial result and this becomes the new value for B. One way to express this in C code is: 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 Storing the A and B values The final step is to convert A and B back into a sequence of bytes. This is the inverse of the load operation. An expression of this in C code could be: 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;Baldwin & Rivest Informational [Page 11]RFC 2040 RC5, RC5-CBC, RC5-CBC-Pad, and RC5-CTS October 1996 out[6] = (B >> 16) & 0xFF; out[7] = (B >> 24) & 0xFF; return; } /* End of RC5_Block_Encrypt */7. Description of RC5-CBC and RC5-CBC-Pad This section describes the CBC and CBC-Pad modes of the RC5 cipher. This description is based on the RC5 key objects and RC5 block cipher described earlier.7.1 Creating cipher objects The cipher object needs to keep track of the padding mode, the number of rounds, the expanded key, the initialization vector, the CBC chaining block, and an input buffer. A possible structure definition for this in C code would be: /* 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; To create a cipher algorithm object, the parameters must be checked and then space allocated for the expanded key table. The expanded key is initialized using the method described earlier. Finally, the state variables (padding mode, number of rounds, and the input buffer) are set to their initial values. In C this could be accomplished by: /* 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. */ {Baldwin & Rivest Informational [Page 12]RFC 2040 RC5, RC5-CBC, RC5-CBC-Pad, and RC5-CTS October 1996 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 Destroying cipher objects Destroying the cipher object is the inverse of creating it with care being take to zero memory before returning it to the memory manager. In C this could be accomplished by: /* 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++)Baldwin & Rivest Informational [Page 13]RFC 2040 RC5, RC5-CBC, RC5-CBC-Pad, and RC5-CTS October 1996 { 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 Setting the IV for cipher objects For CBC cipher objects, the state of the algorithm depends on the expanded key, the CBC chain block, and any internally buffered input. Often the same key is used with many messages that each have a unique initialization vector. To avoid the overhead of creating a new cipher object, it makes more sense to provide an operation that allows the caller to change the initialization vector for an existing cipher object. In C this could be accomplished by the following code: /* 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 Binding a key to a cipher object The operation that binds a key to a cipher object performs the key expansion. Key expansion could be an operation on keys, but that would not work correctly for ciphers that modify the expanded key asBaldwin & Rivest Informational [Page 14]RFC 2040 RC5, RC5-CBC, RC5-CBC-Pad, and RC5-CTS October 1996 they operate. After expanding the key, this operation must initialize the CBC chain block from the initialization vector and prepare the input buffer to receive the first character. In C this could be done by: /* 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)); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -