| |
IntroductionRijndael (pronounced rain-dahl) is the block cipher algorithm that has been selected by the U.S. National Institute of Standards and Technology (NIST) as the candidate for the Advanced Encryption Standard (AES). It was selected by contest from a list of five finalists, that were themselves selected from an original list of more than 15 submissions. Rijndael will begin to supplant the Data Encryption Standard (DES) - and later Triple DES - over the next few years in many cryptography applications. The algorithm was designed by two Belgian cryptologists, Vincent Rijmen and Joan Daemen, whose surnames are reflected in the cipher's name. Rijndael has its origins in Square, an earlier collaboration between the two cryptologists. The cipher has a variable block length and key length. The authors currently specify how to use keys with a length of 128, 192 or 256 bits, to encrypt blocks with a length of 128, 192 or 256 bits (all nine combinations of key length and block length are possible). Both block length and key length can be extended very easily to multiples of 32 bits. Documentation and complete specification of the method (as required by NIST) can be found here. Rijndael can be implemented very efficiently on a wide range of processors and in hardware. This C++ implementation presented here is based on the Java implementation used with the Cryptix toolkit found on the Internet here (Java code authors are Raif S. Naffah and Paulo S.L.M. Barreto). This implementation was tested against KAT test published by the authors of the method and the results were identical. ImplementationThe public user interface of the Collapse class CRijndael { public: //Operation Modes enum { ECB=0, CBC=1, CFB=2 }; //CONSTRUCTOR CRijndael(); //DESTRUCTOR virtual ~CRijndael(); //Expand a user-supplied key material into a session key. void MakeKey(char const* key, char const* chain, int keylength=DEFAULT_BLOCK_SIZE, int blockSize=DEFAULT_BLOCK_SIZE); //Encrypt exactly one block of plaintext. void EncryptBlock(char const* in, char* result); //Decrypt exactly one block of ciphertext. void DecryptBlock(char const* in, char* result); //Encrypt a larger block of data void Encrypt(char const* in, char* result, size_t n, int iMode=ECB); //Decrypt a larger block of data void Decrypt(char const* in, char* result, size_t n, int iMode=ECB); //Get Key Length int GetKeyLength(); //Block Size int GetBlockSize(); //Number of Rounds int GetRounds(); //Resets chain block to initial chain block. void ResetChain(); //Null chain block static char const* sm_chain0; }; The The The The The The purposes of the other functions are obvious. Use ExamplesThe use of try { char szHex[33]; //Initialization CRijndael oRijndael; oRijndael.MakeKey("abcdefghabcdefgh", CRijndael::sm_chain0, 16, 16); char szDataIn[] = "aaaaaaaabbbbbbbb"; char szDataOut[17] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; //Encryption oRijndael.EncryptBlock(szDataIn, szDataOut); CharStr2HexStr((unsigned char*)szDataIn, szHex, 16); cout << szHex << endl; CharStr2HexStr((unsigned char*)szDataOut, szHex, 16); cout << szHex << endl; memset(szDataIn, 0, 16); //Decryption oRijndael.DecryptBlock(szDataOut, szDataIn); CharStr2HexStr((unsigned char*)szDataIn, szHex, 16); cout << szHex << endl; } catch(exception& roException) { cout << roException.what() << endl; } In the next code snippet example, a block and key size of 16 bytes are applied to a larger block of data of size 48 bytes (the block of data size should be a multiple of the block size). The initial chain block is a null block. The block "ababababccccccccababababccccccccababababcccccccc" is encrypted and then decrypted back in all the operation modes ( Collapse try { CRijndael oRijndael; oRijndael.MakeKey("1234567890123456", CRijndael::sm_chain0, 16, 16); char szDataIn1[49] = "ababababccccccccababababccccccccababababcccccccc"; char szDataIn[49]; char szDataOut[49]; memset(szDataIn, 0, 49); memset(szDataOut, 0, 49); //Test ECB strcpy(szDataIn, szDataIn1); memset(szDataOut, 0, 49); oRijndael.Encrypt(szDataIn, szDataOut, 48, CRijndael::ECB); memset(szDataIn, 0, 49); oRijndael.Decrypt(szDataOut, szDataIn, 48, CRijndael::ECB); //Test CBC oRijndael.ResetChain(); strcpy(szDataIn, szDataIn1); memset(szDataOut, 0, 49); oRijndael.Encrypt(szDataIn, szDataOut, 48, CRijndael::CBC); memset(szDataIn, 0, 49); oRijndael.ResetChain(); oRijndael.Decrypt(szDataOut, szDataIn, 48, CRijndael::CBC); //Test CFB oRijndael.ResetChain(); strcpy(szDataIn, szDataIn1); memset(szDataOut, 0, 49); oRijndael.Encrypt(szDataIn, szDataOut, 48, CRijndael::CFB); memset(szDataIn, 0, 49); oRijndael.ResetChain(); oRijndael.Decrypt(szDataOut, szDataIn, 48, CRijndael::CFB); } catch(exception& roException) { cout << "Exception: " << roException.what() << endl; } I am interested in any opinions and new ideas about this implementation. The project AES.zip attached to this article is including the source code of the presented History
George Anescu
|
App Programming/Windows API2007. 8. 15. 03:53