I found a lot of implementations of AES, Twofish and Serpent in C. But I don\'t really understand the examples. I only understand that some where provided with examples to i
Download OpenSSL/Putty/GnuPG sources. All of them contains source of corresponding encryption algorithm. Also, each algorithm has reference implementation in C, which can be easily found over internet.
The wikipedia article actually links to an excellent tutorial (by X-N20) written in C that walks you through the Maths and provides C implementations on the go, which is quite useful for understanding the process. I'd also recommend reading up on finite field arithmetic.
Serpent and Twofish, having missed out on the AES title, aren't so well documented around the internet. Remember though that each provides reference implementations.
Actually implementing them yourself will require study of their respective papers and probably the reference source code.
Note that your 20 billion comments all relate to the fact that the interface NIST specified for AES was that each cipher provide a 128-bit (16 byte) input block and one of 128-bit, 192-bit and 256-bit key blocks.
In order to securely encrypt in such a way as to resist cryptanalysis properly, you need some careful work. For example, what if your last block is missing a few bytes needed? How do you pad securely? Similarly, depending on the intended usage there are other schemes, particularly for large repetitive data, designed to resist cryptanalysis where you know that the encrypted data likely contains say the contents of c:\windows
. What the commentors are trying to get at is that for any real world usage, to remain secure, these things need consideration.
Edit Since another question has cropped up on this topic, here's a few links:
crypto
.gpg
. Specifically, if you're after AES, you might not find it in here, but you will find camellia and serpent.Trying to answer the -still unanswered- question of killercode
, here is my attempt of achieving the same thing:
Download this TwoFish code (thanks go to Schneier et al.): https://www.schneier.com/code/twofish-reference-c.zip
Use this code (at your own risk of course):
int mode = MODE_CBC;
int keySize = 256;
int result = 0;
keyInstance ki; /* key information, including tables */
cipherInstance ci; /* keeps mode (ECB, CBC) and IV */
BYTE plainText[MAX_BLK_CNT*(BLOCK_SIZE / 8)]; // 64 in size!
BYTE cipherText[MAX_BLK_CNT*(BLOCK_SIZE / 8)];
BYTE decryptOut[MAX_BLK_CNT*(BLOCK_SIZE / 8)];
BYTE iv[BLOCK_SIZE / 8];
int i;
/* select number of bytes to encrypt (multiple of block) */
/* e.g., byteCnt = 16, 32, 48, 64 */
//byteCnt = (BLOCK_SIZE / 8) * (1 + (rand() % MAX_BLK_CNT));
/* generate test data */;
int plainTextLength = 65;
for (i = 0; i < min(plainTextLength, MAX_BLK_CNT*(BLOCK_SIZE / 8)); i++)
plainText[i] = (BYTE)rand();
if (plainTextLength > MAX_BLK_CNT * BLOCK_SIZE / 8) {
::MessageBox(NULL, _T("You need to increase your MAX_BLK_CNT for the plain-text to fit in one call."), _T("Error"), MB_OK);
return;
}
int byteCnt = ceil((double)plainTextLength / (BLOCK_SIZE / 8.0)) * (BLOCK_SIZE / 8);
/* ----------------------- */
/* 'dummy' setup for a 128-bit key */
if (makeKey(&ki, DIR_ENCRYPT, keySize, NULL) != TRUE)
result = 1;
/* ----------------------- */
/* 'dummy' setup for cipher */
if (cipherInit(&ci, mode, NULL) != TRUE)
result = 1;
/* select key bits */
for (i = 0; i < keySize / 32; i++)
ki.key32[i] = 0x10003 * rand();
/* run the key schedule */
reKey(&ki);
/* set up random iv (if needed)*/
if (mode != MODE_ECB)
{
for (i = 0; i < sizeof(iv); i++)
iv[i] = (BYTE)rand();
/* copy the IV to ci */
memcpy(ci.iv32, iv, sizeof(ci.iv32));
}
/* encrypt the bytes */
if (blockEncrypt(&ci, &ki, plainText, byteCnt * 8, cipherText) != byteCnt * 8)
result = 1;
/* ----------------------- */
/* decrypt the bytes */
if (mode != MODE_ECB) /* first re-init the IV (if needed) */
memcpy(ci.iv32, iv, sizeof(ci.iv32));
if (blockDecrypt(&ci, &ki, cipherText, byteCnt * 8, decryptOut) != byteCnt * 8)
result = 1;
/* make sure the decrypt output matches original plaintext */
if (memcmp(plainText, decryptOut, byteCnt))
result = 1;
if (result == 0) ::MessageBox(NULL, _T("Success"), _T("SUCCESS"), MB_OK);
That was my attempt and it seems working quite good.
It is using CBC mode.
I am open to suggestions, if anyone has any.
Of course you might like to make MAX_BLK_CNT
a variable and increase it accordingly, to be able to encrypt a variety of data lengths. Although I am not 100% sure if that is its normal usage.
Cheer! :)