jump to navigation

Utilizing rijndael source code March 6, 2007

Posted by TSAI HONG-BIN in Programming.
add a comment

I hate to admit that I’m not a code guru, well, sadly my code has proven everything.


#include
#include
#include
#include
#include "rijndael-api-fst.h"

#define KEYSIZE 256
#define IVSIZE 64

int getiv(BYTE *iv){
FILE *fp;
fp = fopen("key.16", "rb");
if(fgets(iv, (IVSIZE/4)+1, fp) > 0){
return 1;
}
else{
return 0;
}
return 1;
}

int getkey(BYTE *keydata){
FILE *fp;
fp = fopen("key.256","rb");

if(fgets(keydata, (KEYSIZE/4)+1, fp) >0){
return 1;
}
else{
printf("read key error\n");
return 0;
}

return 1;
}

int encrypt(char *file){
char cfile[32];
sprintf(cfile, "%s.enc", file);
int bytesRead=0;
int ret = 0;
BYTE key[KEYSIZE/4+1];
memset(key, '', sizeof(key)); // clean up key space
BYTE IV[IVSIZE/4+1];
memset(IV, '', sizeof(IV));
getkey(key); // read keyMaterial from keyfile
getiv(IV);
keyInstance keyInst;
cipherInstance cipherInst;

BYTE pbuf[1024], cbuf[1024];
memset(pbuf, '', sizeof pbuf); // clean up plaintext space
memset(cbuf, '', sizeof cbuf); // clean up ciphertext space

makeKey(&keyInst, DIR_ENCRYPT, KEYSIZE, key); // run rijndael key schedule
cipherInit(&cipherInst, MODE_CBC, NULL); // initiate cipher mode

FILE *fp;
fp = fopen(file, "rb");

FILE *cfp;
cfp = fopen(cfile, "wb");

for(;;){
bytesRead = fread(pbuf, 1, (sizeof pbuf), fp); // read 1024 bytes from file at a time

if (bytesRead \n");

}

int main(int argc, char *argv[]){
if (argc > 1){
if( strcmp( argv[1], "encrypt") == 0){
printf("start encrypting file %s\n", argv[2]);
encrypt(argv[2]);
}
else if( strcmp( argv[1], "decrypt") == 0){
decrypt(argv[2]);
}
else{
usage();
return 0;
}
}
else{
usage();
return 0;
}
return 1;
}

Utilizing rijndael source code (bug fix) March 6, 2007

Posted by TSAI HONG-BIN in Programming.
1 comment so far

I downloaded the source code of Rijndael algorithm from the following link.
http://www.cis.syr.edu/~wedu/minix/code.html
It should be an optimized version of Rijndael implementation, especially it is employed and integrated into OpenSSL (aes_core.c).

My purpose is to write a small file encryption tool, using Rijndael obviously, and only Rijndael, in C. Finally I made it, so it’s about time to share my experience here. Somehow I find a problem in this version of Rijndael implementation, don’t know if I can call it a bug but it doesn’t work correctly in CBC mode. I’ll show what my problem is and how I fix it. And later on I’ll share my source code.

in rijndael-api-fst.c, function blockEncrypt()


case MODE_CBC:
iv = cipher->IV;
for (i = numBlocks; i > 0; i--) {
((u32*)block)[0] = ((u32*)input)[0] ^ ((u32*)iv)[0];
((u32*)block)[1] = ((u32*)input)[1] ^ ((u32*)iv)[1];
((u32*)block)[2] = ((u32*)input)[2] ^ ((u32*)iv)[2];
((u32*)block)[3] = ((u32*)input)[3] ^ ((u32*)iv)[3];
rijndaelEncrypt(key->rk, key->Nr, block, outBuffer);
iv = outBuffer;
input += 16;
outBuffer += 16;
}
break;

You can see the Initial Vector is assigned each iteration, HOWEVER, only assigned in this execution cycle. Since I’m working on file encryption, surely I cannot fix the buffer size in advance because the file size is unknown. I made a loop to continuously read 1024 bytes from input file until the feof(fp) is reached. Therefore, in each cycle of loop I’ll have at most 1024 bytes of data in buffer to be encrypted. Since Rijndael is a 128-bit block cipher, I got numBlocks=64 (in maximum) during each blockEnrypt execution. Well, now, you may find out what problem I’m addressing here. Ya, cipher->IV is not updated. Let me trace the code this way.

1. execute the problem with IV = {0};
2. file size > 1024 bytes;
3. goto blockEncrypt()
4. run rijndaelEncrypt()
5. iv is updated as last outBuffer
6. after 64 blocks is executed, break.
7. next 1024 bytes file buffer come in
8. start blockEncrypt()
9. .. wow-oh! what’s the IV now?

Right, the Initial Vector in CBC mode is not connected, it refreshed each time blockEncrypt() is called. So I simply add one line. Now the code looks like this


case MODE_CBC:
iv = cipher->IV;
for (i = numBlocks; i > 0; i--) {
((u32*)block)[0] = ((u32*)input)[0] ^ ((u32*)iv)[0];
((u32*)block)[1] = ((u32*)input)[1] ^ ((u32*)iv)[1];
((u32*)block)[2] = ((u32*)input)[2] ^ ((u32*)iv)[2];
((u32*)block)[3] = ((u32*)input)[3] ^ ((u32*)iv)[3];
rijndaelEncrypt(key->rk, key->Nr, block, outBuffer);
iv = outBuffer;
memcpy(cipher->IV, outBuffer, 16);
input += 16;
outBuffer += 16;
}
break;

This problem exists in blockDecrypt() as well, this time it doesn’t update iv, instead of cipher->IV, in each decrypt iteration. I will just give my version of blockDerypt here.


case MODE_CBC:
iv = cipher->IV;
for (i = numBlocks; i > 0; i--) {
rijndaelDecrypt(key->rk, key->Nr, input, block);
((u32*)block)[0] ^= ((u32*)iv)[0];
((u32*)block)[1] ^= ((u32*)iv)[1];
((u32*)block)[2] ^= ((u32*)iv)[2];
((u32*)block)[3] ^= ((u32*)iv)[3];
iv = input;
memcpy(outBuffer, block, 16);
memcpy(cipher->IV, input, 16);
input += 16;
outBuffer += 16;
}
break;

So, if you’ve been suffered from similar problem, hope this message is helpful to you. If you find my article incorrect, please let me know. The original authors and copyright statement of this implementation is in the readme file. Enjoy. 🙂

c-faq review and a chinese translation (1.12) February 15, 2007

Posted by TSAI HONG-BIN in Programming.
add a comment

please refer to http://c-faq.com/decl/auto.html for original document.

1.12 What’s the auto keyword good for?

Nothing; it’s archaic. [One can imagine stylistic uses such as emphasizing that a variable must be automatic, and supposedly some compilers have used it to force a variable not to be in a register.] (It’s a holdover from C’s typeless predecessor language B, where in the absence of keywords like int a declaration always needed a storage class.) See also question 20.37.

 

關鍵字 auto 有什麼好處

沒有,那已廢棄不用。auto可以做為字面上強調該變數必需為自動(automatic),也許某些編輯器以此來強迫變數不要存放在register裡。C語言的前身B語言沒有類似 int 的關鍵字,因此用auto來做 storage class。

 

c-faq review and a chinese translation (1.11) February 15, 2007

Posted by TSAI HONG-BIN in Programming.
add a comment

please refer to http://c-faq.com/decl/extern.html for the origin

1.11 What does extern mean in a function declaration?


extern
is significant only with data declarations. In function declarations, it can be used as a stylistic hint to indicate that the function’s definition is probably in another source file, but there is no formal difference between

extern int f();

and

int f();

See also question 1.10.

References: ISO Sec. 6.1.2.2, Sec. 6.5.1
Rationale Sec. 3.1.2.2
H&S Secs. 4.3,4.3.1 pp. 75-6

函式宣告時的 extern 代表什麼意思?

extern 只有在資料宣告時有意義。在函式宣告時,它可以拿來當作字面上的提示,表示該函式的可能定義在其他源碼,但其實

extern int f();

int f();

並沒有什麼差別。

is Documentation skill a requirement? (2) February 12, 2007

Posted by TSAI HONG-BIN in Programming.
add a comment

Writing documentation is somewhat like telling a story. You have to focus on the 6-Wh, What, Why, How, Who, Where, When. Maybe more emphasis on What, Why and How, but if possible, it would be great to answer all the 6 questions.

There are certain levels of documentations. 1) commented inline with source code, explaining variables, parameters, functions…etc. 2) noted in a seperate file, explaining the program from a “higher” aspect of view such as the co-relationship between classes, objects, members. 3) written down as an independent document or usually called “white paper,” which explains what problem this program means to solve, what algorithm this program applies, what’s the expectation of this program in the future…etc. Each level of documentation has different purpose and focus, and last but not least, different target audience.

Since in my last post I mentioned that software engineers are more or less linguists, this line is definitely not joking those who are able to write excellent programs but have no idea how to have a casual talk with gals. One who wants to write a program, must learn its programming language first. But by knowing languages and grammers may only allow you to write a homework. If you want to implement something cleverly, you have to “understand” the language. It’s undoubtedly a challenge, especially when it is a machine that you want to communicate with via the programming language. The syntax must be accurate, logical must be correct, and even there are times you have to deal with memory management. Assume that now you’re able to write masterwork, there’s still one step to go. Yes, documentation. By writing documentation, you’re no longer talking to machine (compiler, to be exactly), but to human readers.

Why is documentation a necessary step? I believe one of the most important feature is to let your program “live long and prosper.” You may hear from your C language lecturer that a source code cannot be reused is useless. Though usually this guideline is employed to urge you to “modulize” your program, it is somehow applicable to the case that a million-line source code contains no documentation.

(to be continue)