📄 rfc2040.txt
字号:
7.5 Processing part of a message The encryption process described here uses the Init-Update-Final paradigm. The update operation can be performed on a sequence of message parts in order to incrementally produce the ciphertext. After the last part is processed, the Final operation is called to pick up any plaintext bytes or padding that are buffered inside the cipher object. An appropriate procedure header for this operation would be: /* 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. */Baldwin & Rivest Informational [Page 15]RFC 2040 RC5, RC5-CBC, RC5-CBC-Pad, and RC5-CTS October 1996 int *pCipherLen;/* Gets byte len of C. */ int maxCipherLen; /* Size of C. */ char *C; /* Ciphertext buffer. */ {7.5.1 Output buffer size check. The first step of plaintext processing is to make sure that the output buffer is big enough hold the ciphertext. The ciphertext will be produced in multiples of the block size and depends on the number of plaintext characters passed to this operation plus any characters that are in the cipher object's internal buffer. In C code this would be: int plainIndex, cipherIndex, j; /* Check size of the output buffer. */ if (maxCipherLen < (((pAlg->inputBlockIndex+N)/BB)*BB)) { *pCipherLen = 0; return (0); }7.5.2 Divide plaintext into blocks The next step is to add characters to the internal buffer until a full block has been constructed. When that happens, the buffer pointers are reset and the input buffer is exclusive-or'ed (XORed) with the CBC chaining block. The byte order of the chaining block is the same as the input block. For example, the ninth input byte is XOR'ed with the first ciphertext byte. The result is then passed to the RC5 block cipher which was described earlier. To reduce data movement and byte alignment problems, the output of RC5 can be directly written into the CBC chaining block. Finally, this output is copied to the ciphertext buffer provided by the user. Before returning, the actual size of the ciphertext is passed back to the caller. In C, this step can be performed by: plainIndex = cipherIndex = 0; while (plainIndex < N) { if (pAlg->inputBlockIndex < BB) { pAlg->inputBlock[pAlg->inputBlockIndex] = P[plainIndex]; pAlg->inputBlockIndex++; plainIndex++; }Baldwin & Rivest Informational [Page 16]RFC 2040 RC5, RC5-CBC, RC5-CBC-Pad, and RC5-CTS October 1996 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 Final block processing This step handles the last block of plaintext. For RC5-CBC, this step just performs error checking to ensure that the plaintext length was indeed a multiple of the block length. For RC5-CBC-Pad, padding bytes are added to the plaintext. The pad bytes are all the same and are set to a byte that represents the number of bytes of padding. For example if there are eight bytes of padding, the bytes will all have the hexadecimal value 0x08. There will be between one and BB padding bytes, inclusive. In C code this would be: /* 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;Baldwin & Rivest Informational [Page 17]RFC 2040 RC5, RC5-CBC, RC5-CBC-Pad, and RC5-CTS October 1996 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. Description of RC5-CTS The Cipher Text Stealing (CTS) mode for block ciphers is described by Schneier on pages 195 and 196 of [6]. This mode handles any length of plaintext and produces ciphertext whose length matches the plaintext length. The CTS mode behaves like the CBC mode for all but the last two blocks of the plaintext. The following steps describe how to handle the last two portions of the plaintext, called Pn-1 and Pn, where the length of Pn-1 equals the block size, BB, and the length of the last block, Pn, is Ln bytes. Notice that Ln ranges from 1 to BB, inclusive, so Pn could in fact be a complete block.Baldwin & Rivest Informational [Page 18]RFC 2040 RC5, RC5-CBC, RC5-CBC-Pad, and RC5-CTS October 1996 1. Exclusive-or Pn-1 with the previous ciphertext block, Cn-2, to create Xn-1. 2. Encrypt Xn-1 to create En-1. 3. Select the first Ln bytes of En-1 to create Cn. 4. Pad Pn with zeros at the end to create P of length BB. 5. Exclusive-or En-1 with P to create to create Dn. 6. Encrypt Dn to create Cn-1 7. The last two parts of the ciphertext are Cn-1 and Cn respectively. To implement CTS encryption, the RC5-CTS object must hold on to (buffer) at most 2*BB bytes of plaintext and process them specially when the RC5_CTS_Encrypt_Final routine is called. The following steps describe how to decrypt Cn-1 and Cn. 1. Decrypt Cn-1 to create Dn. 2. Pad Cn with zeros at the end to create C of length BB. 3. Exclusive-or Dn with C to create Xn. 4. Select the first Ln bytes of Xn to create Pn. 5. Append the tail (BB minus Ln) bytes of Xn to Cn to create En. 6. Decrypt En to create Pn-1. 7. The last two parts of the plaintext are Pn-1 and Pn respectively.9. Test Program and Vectors To help confirm the correctness of an implementation, this section gives a test program and results from a set of test vectors.9.1 Test Program The following test program written in C reads test vectors from its input stream and writes results on its output stream. The following subsections give a set of test vectors for inputs and the resultingBaldwin & Rivest Informational [Page 19]RFC 2040 RC5, RC5-CBC, RC5-CBC-Pad, and RC5-CTS October 1996 outputs. #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"); }Baldwin & Rivest Informational [Page 20]RFC 2040 RC5, RC5-CBC, RC5-CBC-Pad, and RC5-CTS October 1996 /* 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; {Baldwin & Rivest Informational [Page 21]RFC 2040 RC5, RC5-CBC, RC5-CBC-Pad, and RC5-CTS October 1996 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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -