今天花了一两个小时写这个程序,忍不住把她发到自己的博客上与人分享分享,算是作为整理一下自己的思路。如果认为写得太菜的话请各位高手见谅见谅。
这里演示了我自己用libtomcrypt-0.96加密库写的一个DES加密小程序,此DES程序只在Ubuntu10.10 (Linux 2.6.35-28-generic #49-Ubuntu SMP Tue Mar 1 14:40:58 UTC 2011) 测试过,程序是用标准C写的,如果没有意外发生的话应该可以用支持标准C的编译器编译通过。个人懒得把全部文件放上,也免得只是一个简单的程序搞得复杂,只把我的设计思路放上就好了。我想代码就是最好的说明了。
PS: 记得如果你发现BUG的话记得告知一声, 此程序还没有经过完整测试, 只测试了对ASCII码和二进制文件的输入, 所以我假设为可以对所有文件加密.
Revision History
=============
May 3, 2011
FIX BUG 1: 解决文件最大只能加解密2GB的问题(在32位系统), 经过测试,index永远少于8, 这可以使得程序可以加解密任何文件大小, 把这句'index %= group_size; '添加到在加解密函数中while循环的if()语句就可以了。
//下面是des_encrypt_plain()的修改状况,des_decrypt_cipher()对着来修改就行了 while ((c = getchar()) != EOF) { pt[index % group_size] = c; /* NOTE: here `++index' is equal to number of characters * has read, and it's the next index for pt[] */ if (++index % group_size == 0) { // one group enough /* Encrypt and Output ciphertext to STDOUT */ des_ecb_encrypt(pt, ct, &skey); for (i = 0; i < group_size; i++) putchar(ct[i]); /* Revision 1 * This make the program can encrypt/decrypt * any size * of file from STDIN, if not, * this program can only encrypt/decrypt * maximumal size is 2^(INT_MAX - 1) Byte */ index %= group_size; // 添加了这句,使index永远小于8而不会有溢出 } // testing code: track the value of 'index' NDEBUG ? : fprintf(stderr, "index: %d/n", index); }
用户接口, README 文件上的Usage
============================
INSTALL Linux: $ make mydes Windows: Create a project name 'mydes' and include mydes.c mydes_lib.*, and G__des.h des.h file in libtomcrypt-0.96 Usage $ ./mydes -[k|e|d] # generate des key $ ./mydes -k < .key > .key.des #! ./mydes -k abcdabcd > .key.des # Cause interface is not alignment # encrypt plaintext, ASCII or Binary file $ ./mydes -e < mesg > mesg.des # decrypt ciphertext, ASCII or Binary file $ ./mydes -d < mesg.des > mesg ./od # convert mesg/mesg.des to char|O|HEX $ ./od -[c|o|x] # e.g. $ ./od -x < mesg.des > mesg.des.hex
Makefile
========
EXE = test_des mydes od CC = gcc #CFLAGS = -g -Wall -ansi INCLUDE = -I. all: $(EXE) # mydes mydes: mydes.o mydes_lib.o G__des.o $(CC) -o $@ $^ mydes.o: mydes.c $(CC) $(INCLUDE) $(CFLAGS) -c $< mydes_lib.o: mydes_lib.c mydes_lib.h $(CC) $(INCLUDE) $(CFLAGS) -c $< # od od: od.c $(CC) $(INCLUDE) $(CFLAGS) $< -o $@ # test_des G__des.o: G__des.c des.h $(CC) $(INCLUDE) $(CFLAGS) -c $< test_des.o: test_des.c $(CC) $(INCLUDE) $(CFLAGS) -c $< test_des: test_des.o G__des.o $(CC) -o $@ $^ test: ./mydes -k < .key > .key.des # generate key ./mydes -e < mesg > mesg.des # encrypt plaintext ./mydes -d < mesg.des > mesg # decrypt ciphertext clean: rm -f *.o *.obj reclean: clean rm -f $(EXE)
把main函数的文件mydes.c附上
========================
/* mydes.c * author: Dooit.Lee@gmail.com */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "mydes_lib.h" int Usage() { fprintf(stderr, "Usage: ./mydes -[k|e|d] < infile > outfile/n" "------------------ Example --------------------/n" "Generate key: ./mydes -k < .key > .key.des/n" "Encrypt plaintext: ./mydes -e < mesg > mesg.des/n" "Decrypt ciphertext: ./mydes -d < mesg.des > mesg/n" "------------------------------------------------/n"); return EXIT_FAILURE; } typedef int (*des_handler)(); /* // It's not nice to use this structure or array below, Just KISS struct opt { const char *name, const char *help, void (*handler)(); }; des_handler dh[] = { des_generate_skey, des_encrypt_plain, des_decrypt_cipher, Usage }; */ des_handler get_des_handler(const char *arg); int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "%s: ", argv[0]); return Usage(); } return (*(get_des_handler(argv[1])))(); } des_handler get_des_handler(const char *arg) { if (!strcmp(arg, "-k")) { return des_generate_skey; } else if (!strcmp(arg, "-e")) { return des_encrypt_plain; } else if (!strcmp(arg, "-d")) { return des_decrypt_cipher; } else if (!strcmp(arg, "-t")) { return des_test_skey; } else { return Usage; } }
然后是mydes.c当中includle的头文件mydes_lib.h
======================================
/* mydes_lib.h * author: Dooit.Lee@gmail.com * Convention: return 0 as Success, 1 as Failed */ #ifndef mydes_lib_h #define mydes_lib_h #define KEYLEN 8 #define NDEBUG 1 /* Not debug macro */ // skey_path as file .key.des, see mydes_lib.c: des_test_skey() /* * Purpose: Get key from STDIN, output skey to STDOUT * RETURN: 0 as success, 1 as failed * Usage: ./mydes -k < .key > .key.des */ int des_generate_skey(); /* * Purpose: Test and check where file '.key.des' is same as skey * with same key input from STDIN * RETURN: 0 as success, 1 as failed * Usage: ./mydes -t < same-key-as-above * NOTE: use file .key.des as default key */ int des_test_skey(); /* * Purpose: encrypt plaintext from STDIN and output ciphertext to STDOUT * use file .key.des as default key * RETURN: 0 as success, 1 as failed * Usage: ./mydes -e < mesg > mesg.des * NOTE: use file .key.des as default key */ int des_encrypt_plain(); /* * Purpose: decrypt ciphertext from STDIN and output plaintext to STDOUT * RETURN: 0 as success, 1 as failed * Usage: ./mydes -d < mesg.des > mesg * NOTE: use file .key.des as default key */ int des_decrypt_cipher(); #endif
mydes_lib.c: mydes_lib.h声明的函数中的实现 (核心部分,包括加密和解密的函数,感谢The C Programming Language带给我的灵感)
===================================
/* mydes_lib.c * author: Dooit.Lee@gmail.com * Convention: return 0 as Success, 1 as Failed */ #include <stdio.h> #include <stdlib.h> #include <string.h> /* for memcmp() in des_test_skey() */ #include "mydes_lib.h" #include "des.h" static const char *skey_path = ".key.des"; /* file .key.des */ static int des_get_skey_from_file(des_key *skey_ptr); static int des_get_skey_from_stdin(des_key *skey_ptr); /* * get key from STDIN, output skey to STDOUT * Usage: ./mydes -k < .key > .key.des */ int des_generate_skey() { des_key skey; char *charptr = NULL; int i; if (!des_get_skey_from_stdin(&skey)) { /* Output skey to STDOUT */ charptr = (char *)&skey; for (i = 0; i < sizeof(skey); i++) { printf("%c", charptr[i]); } return 0; } else { return 1; // failed } } /* * Purpose: Test and check where file '.key.des' is same as skey * with same key input from STDIN * RETURN: 0 as success, 1 as failed * Usage: ./mydes -t < same-key-as-above * NOTE: use file .key.des as default key */ int des_test_skey() { des_key skey; FILE *f; // int i; int skey_size = sizeof(skey); char str[2000] = ""; // char *charptr = NULL; // testing code: print skey_path NDEBUG ? : fprintf(stderr, "skey_path: %s/n", skey_path); if (!des_get_skey_from_stdin(&skey)) { f = fopen(skey_path, "rb"); if (f != NULL) { if (skey_size == fread(str, 1, skey_size, f)) { /* compare skey and str's memory */ // charptr = (char *)&skey; if (!memcmp((void *)str, (void *)&skey, skey_size)) { fprintf(stderr, "size (%d) and content" " both matched/n", skey_size); printf("des_test_skey: Passed/n"); return 0; } else { fprintf(stderr, "error: skey and %s/'s " "size (%d) matched, but " "content does not matched: " "check if you inputed the " "right key/n", skey_path, skey_size); printf("des_test_skey: Failed/n"); return 1; } } else { fprintf(stderr, "error: '%s'/'s size (%d) is " "not equal to skey_size (%d)/n", skey_path, strlen(str), skey_size); printf("des_test_skey: Failed/n"); return 1; } } else { fprintf(stderr, "Can't open skey file '%s'/n", skey_path); return 1; } } else { return 1; // failed } } /* * encrypt plaintext from STDIN and output ciphertext to STDOUT * use file .key.des as default key * Usage: ./mydes -e < mesg > mesg.des */ int des_encrypt_plain() { des_key skey; unsigned char pt[8], ct[8]; /* plaintext and ciphertext */ int index = 0; /* index one group to encrypt */ const int group_size = sizeof(pt) / sizeof(*pt); int c; /* use to read character from STDIN */ int i; if (!des_get_skey_from_file(&skey)) { /* read plaintext from STDIN until EOF */ while ((c = getchar()) != EOF) { pt[index % group_size] = c; /* NOTE: here `++index' is equal to number of characters * has read, and it's the next index for pt[] */ if (++index % group_size == 0) { // one group enough /* Encrypt and Output ciphertext to STDOUT */ des_ecb_encrypt(pt, ct, &skey); for (i = 0; i < group_size; i++) putchar(ct[i]); } } /* Process the remain input (index % group_size) */ if (index % group_size != 0) { /* filling the rest of pt[] with '/0' */ for (i = index % group_size; i < group_size; i++) pt[i] = '/0'; /* Encrypt and Output the rest ciphertext to STDOUT */ des_ecb_encrypt(pt, ct, &skey); for (i = 0; i < group_size; i++) putchar(ct[i]); } return 0; /* Encrypt STDIN: Done */ } else { return 1; /* Error: Can't get skey file */ } } /* * decrypt ciphertext from STDIN and output plaintext to STDOUT * use file .key.des as default key * Usage: ./mydes -d < mesg.des > mesg */ int des_decrypt_cipher() { des_key skey; unsigned char pt[8], ct[8]; /* plaintext and ciphertext */ int index = 0; /* index one group to encrypt */ const int group_size = sizeof(pt) / sizeof(*pt); int c; /* use to read character from STDIN */ int i; if (!des_get_skey_from_file(&skey)) { /* read ciphertext from STDIN until EOF */ while ((c = getchar()) != EOF) { ct[index % group_size] = c; /* NOTE: here `++index' is equal to number of characters * has read, and it's the next index for pt[] */ if (++index % group_size == 0) { // one group enough /* Encrypt and Output ciphertext to STDOUT */ des_ecb_decrypt(ct, pt, &skey); for (i = 0; i < group_size; i++) putchar(pt[i]); } } /* No remain input, Which means (index % group_size) is always * equal to 0 */ return 0; /* Decrypt STDIN: Done */ } else { return 1; /* Error: Can't get skey file */ } } /* * RETURN: 0 as success, 1 as failed (which is keylen invalid) */ static int des_get_skey_from_file(des_key *skey_ptr) { FILE *f; if ((f = fopen(skey_path, "rb")) != NULL) { // testing code: check if sizeof(*skey_ptr) is availabe NDEBUG ? : fprintf(stderr, "sizeof(*skey_ptr): %d/n", sizeof(*skey_ptr)); /* read skey from 'FILE *f' into 'skey_ptr' */ if (sizeof(*skey_ptr) == fread((void *)skey_ptr, 1, sizeof(*skey_ptr), f)) { return 0; } else { fprintf(stderr, "skey file '%s'/'s size is not " "match to sizeof(skey) (%d)/n", skey_path, sizeof(*skey_ptr)); return 1; } } else { fprintf(stderr, "Can't open skey file '%s'/n", skey_path); return 1; } } /* * RETURN: 0 as success, 1 as failed (which is keylen invalid) */ static int des_get_skey_from_stdin(des_key *skey_ptr) { char str[1000] = ""; unsigned char key[KEYLEN]; int i; /* read key from STDIN */ scanf("%s", str); // testing code: print key and keylen from STDIN NDEBUG ? : fprintf(stderr, "key: '%s', keylen: %d/n", str, strlen(str)); /* check if keylen (strlen(str)) is valid */ if (strlen(str) != KEYLEN) { fprintf(stderr, "error: keylen is invalid: " "Your keylen is %d, available keylen is %d/n", strlen(str), KEYLEN); return 1; } /* Store key from 'str' to key[KEYLEN] */ for (i = 0; i < sizeof(key) / sizeof(*key); i++) { key[i] = (unsigned char)str[i]; } // testing code: print the key[KEYLEN] and check things go right if (!NDEBUG) { fprintf(stderr, "key in key[%d]:", KEYLEN); for (i = 0; i < sizeof(key) / sizeof(*key); i++) fprintf(stderr, " %c", key[i]); fprintf(stderr, "/n"); } /* get skey */ des_setup(key, sizeof(key), 0, skey_ptr); // testing code: print sizeof(skey) NDEBUG ? : fprintf(stderr, "sizeof(skey): %d/n", sizeof(*skey_ptr)); return 0; }
至于G__des.c, des.h的加密实现文件自己到库libtomcrypt-0.96去找吧
====================================================
整个程序演示完毕,这里SHOW一下运行结果
===================================
[xxx@xxx-desktop:src]$ cat plain.ZN 你好! 这是一个中文语言的明文, 用于测试DES加密程序对中文的加密 [xxx@xxx-desktop:src]$ cat plain.ZN | ./mydes -e | ./mydes -d 你好! 这是一个中文语言的明文, 用于测试DES加密程序对中文的加密 [xxx@xxx-desktop:src]$ echo "Hello, my name is Dooit.Lee. This is a small/ > DES encryption program. If you discover any bug(s), you can leave your / > message or send me a mail to dooit.lee@gmail.com. Enjoy your code." | / > ./mydes -e | ./mydes -d Hello, my name is Dooit.Lee. This is a small DES encryption program. If you discover any bug(s), you can leave your message or send me a mail to dooit.lee@gmail.com. Enjoy your code.