因为工作以及满足个人好奇心的需要,通过网上查找资料,自己做了一个利用openssl提供的AES接口加/解密文件的小工具,贴出来以备忘:
/***************/
1.CBC和ECB两种模式加密都进行了人工填充,对于不足128bit的内容,全部补足128bit,用‘0’填充
2.加密后的文件头4个Byte,记录了填充数据的长度
/***************/
/*aes.h*/
1 2 3 4 5 6 7 8 9 10 |
#include <openssl/aes.h> #include "openssl/evp.h" int openssl_aes_cbc_encrypt(char* in, size_t len, char* out); int openssl_aes_cbc_decrypt(char* in, size_t len, char* out); int openssl_aes_ecb_enrypt(char* in, size_t len,char* out); int openssl_aes_ecb_decrypt(char* in,size_t len, char* out); /**每个接口都将输入数据的长度传递进去,因为交给上一层去获取数据长度,会更准确一些**/ |
/*aes.c*/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
#include <stdlib.h> #include <string.h> #include <stdio.h> #include "aes.h" /**DEBUG是一个以16进制打印数据的宏,为了方便调试,具体实现在hexdump里面**/ #define DEBUGFLAG 0 #define DEBUG(str,len) {if(DEBUGFLAG) hexdump((str),(len));} const unsigned char key[AES_BLOCK_SIZE]={0}; unsigned char iv[AES_BLOCK_SIZE]={0}; //初始化向量 void hexdump(char* str, size_t len) { unsigned int i; unsigned char*p=(unsigned char*)str; printf("hexdump %d bytes data:\n",len); for(i=1;i<=len;i++) { printf("%2X ",p[i]); if(i%16==0) printf("\n"); } printf("\n"); } /**AES CBC模式加密**/ int openssl_aes_cbc_encrypt(char* in, size_t len, char* out) { AES_KEY aes; char* aesIn; /**为了填充数据为AES_BLOCK_SIZE的整数倍, 单独申请一个变量用于存放填充后的要加密的数据**/ int blockNum,aesInLen; if(AES_set_encrypt_key(key, 128, &aes) < 0) /**设置加密密钥**/ { return -1; } /**判断原始数据长度是否AES_BLOCK_SIZE的整数倍**/ if((len%AES_BLOCK_SIZE)!=0) { /**不是整数倍,用'0'填充**/ blockNum=len/AES_BLOCK_SIZE+1; aesInLen=blockNum*AES_BLOCK_SIZE; aesIn=(char*)calloc(aesInLen,1); memcpy(aesIn,in,len); } else { aesInLen=len; aesIn=(char*)calloc(aesInLen,1); memcpy(aesIn,in,len); } DEBUG(aesIn,aesInLen) AES_cbc_encrypt((unsigned char*)aesIn, (unsigned char*)out, aesInLen, &aes, iv, AES_ENCRYPT); DEBUG(out,aesInLen) return aesInLen; /**返回填充后加密数据的长度**/ } /**AES CBC模式解密**/ int openssl_aes_cbc_decrypt(char* in, size_t len, char* out) { AES_KEY aes; if(AES_set_decrypt_key(key, 128, &aes) < 0) { return -1; } DEBUG(in,len) AES_cbc_encrypt((unsigned char*)in, (unsigned char*)out, len, &aes, iv, AES_DECRYPT); DEBUG(out,len) return 0; } /**AES ECB模式加密**/ int openssl_aes_ecb_enrypt(char* in, size_t len, char* out) { int i; int blockNum; int aesInLen; char* aesIn; AES_KEY aes; if(AES_set_encrypt_key(key, 128, &aes) < 0) { return -1; } if((len%AES_BLOCK_SIZE)!=0) { blockNum=len/AES_BLOCK_SIZE+1; aesInLen=blockNum*AES_BLOCK_SIZE; aesIn=(char*)calloc(aesInLen,1); memcpy(aesIn,in,len); //for(i=len;i<blockNum*AES_BLOCK_SIZE;i++) // aesIn[i]='0'; } else { blockNum=len/AES_BLOCK_SIZE; aesInLen=len; aesIn=(char*)calloc(aesInLen,1); memcpy(aesIn,in,len); } /**由于ECB每次只处理AES_BLOCK_SIZE大小的数据,所以要通过循环来完成所有数据对加密,解密也是一样的道理**/ for(i=0;i<blockNum;i++) { AES_ecb_encrypt((unsigned char*)aesIn,(unsigned char*)out,&aes,AES_ENCRYPT); aesIn+=AES_BLOCK_SIZE; out+=AES_BLOCK_SIZE; } return aesInLen; } /**AES ECB模式解密**/ int openssl_aes_ecb_decrypt(char* in,size_t len, char* out) { unsigned int i; AES_KEY aes; if(AES_set_decrypt_key(key, 128, &aes) < 0) { return -1; } for(i=0;i<len/AES_BLOCK_SIZE;i++) { AES_ecb_encrypt((unsigned char*)in, (unsigned char*)out, &aes, AES_DECRYPT); in+=AES_BLOCK_SIZE; out+=AES_BLOCK_SIZE; } return 0; } |
/*main.c*/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
#include <stdio.h> #include <string.h> #include <ctype.h> #include "aes.h" #pragma comment(lib,"libeay32.lib") #pragma comment(lib,"ssleay32.lib") void usage(); int main(int argc,char *argv[]) { char offset[4]={'0'}; /**用于存放填充字节数的数组**/ char *src,*dst; int inlen,outlen,size; FILE *srcFile; FILE *dstFile; if(argc!=5) { usage(); return 0; } if((srcFile=fopen(argv[3],"rb"))==NULL) { printf("open srcFile failed\n"); return -1; } if((dstFile=fopen(argv[4],"wb+"))==NULL) { printf("open dstFile failed\n"); return -2; } fseek(srcFile,0,SEEK_END); inlen=ftell(srcFile); /**获取输入文件的大小**/ if(inlen<0) { printf("srcFile operate failed\n"); } fseek(srcFile,0,SEEK_SET); /**返回文件开始**/ argv[2]++; switch(argv[2][0]) { case 'e'|'E': src=(char*)calloc(inlen,1); size=fread(src,1,inlen,srcFile); printf("input %d byte\n",size); outlen=(inlen/16+1)*16; /**输出变量申请的空间额外增加16字节,防止出错**/ dst=(char*)calloc(outlen,1); if(strcmp(argv[1],"-cbc")==0) { size=openssl_aes_cbc_encrypt(src,inlen,dst); sprintf(offset,"%d",size-inlen); /**获取填充的字节数,记录到输出文件的前4个字节内**/ fwrite(offset,sizeof(char),4,dstFile); } else if(strcmp(argv[1],"-ecb")==0) { size=openssl_aes_ecb_enrypt(src,inlen, dst); sprintf(offset,"%d",size-inlen); fwrite(offset,sizeof(char),4,dstFile); } else{ usage(); return 0; } break; case 'd'|'D': fread(offset,sizeof(char),4,srcFile); inlen-=4; src=(char*)calloc(inlen,1); size=fread(src,1,inlen,srcFile); /**从加密后的文件中获取填充的字节数,用于恢复原始文件**/ printf("input %d byte\n",size); size=size-atoi(offset); /**得到原始文件的大小**/ outlen=(inlen/16+1)*16; dst=(char*)calloc(outlen,1); if(strcmp(argv[1],"-cbc")==0) { openssl_aes_cbc_decrypt(src,inlen,dst); } else if(strcmp(argv[1],"-ecb")==0) { openssl_aes_ecb_decrypt(src,inlen,dst); } else{ usage(); return 0; } break; default: usage(); break; } size=fwrite(dst,1,size,dstFile); /**输出加密后的文件或者解密后的文件,由于size已经做了调整, 所以解密后的文件大小和原始文件应该一致**/ printf("output %d byte\n",size); fclose(srcFile); fclose(dstFile); free(src); free(dst); } void usage() { printf("aes -cbc/-ecb -e/-d input output\n "); getc(stdin); } |