这是之前接到的一个工作内容,项目原本的登录操作是获得账号和密码以后,对密码进行一遍MD5加密,然后传递账号和密文到cgi文件。在c中获取到账户以后,从数据库中获取到密码,对密码进行一次MD5的加密,然后将该密文与post过来的密文进行对比,进行登录验证。也就是说,虽然进行了一次密码加密,但是在get/post的过程中,该密文是可见的,不符合客户的保密需求。
经过协商以后决定,在传递的过程中不再对密码进行传输,而是将账号与session进行组合,组合成一个新的字符串以后,将密码当做密钥,进行一次AES的加密操作,以及一次MD5的加密操作生成用来POST的密文。而C中,获取到账号和密文以后,将账号和session组合,然后利用c中openssl的接口进行AES加密,MD5加密的操作获取新的密文,然后将该密文和传送得到的密文进行对比,进行登录验证。如此一来,密码的作用就仅仅是两边进行加密操作的密钥,而传送的验证字符串,更是进行了两次加密操作,大大提高了保密性。
在工作的过程中,遇到的最大难题到并非是加密的操作,而是JS中AES加密的密文和Object C中利用openSSL的AES加密的密文总是无法相同,而直到最后也没有解决JS和openssl的结果不同的问题,幸运的是,在工作的过程中,意外发现直接利用linux的aes加密命令却能获得和JS相同的密文(echo -n "secretsecretsecret" | openssl enc -e -a -aes-256-cbc -K 12345678 -iv 12345678)。于是,在CGI中添加了调用linux命令将结果写到文件中,然后读取文件的方式实现了这个操作。如果有人解决了这个问题,希望能够联系我,也可以发送邮件,我的邮箱地址是:[email protected]
首先是JS的,在JS的aes加密过程中,用了好几个不同的CryptoJs的库,虽然也是可以的到加密解密的实现,但是得到结果并不符合我的需要,直到使用Mark Percival 写的脚本:放上地址(https://github.com/mdp/gibberish-aes),放上代码:
1 printf("<script type=\"text/javascript\" src=\"/bh/pjs/crypto-js-3.1.6/gibberish-aes.js\"></script>\n"); 2 printf("<script type=\"text/javascript\" src=\"/bh/pjs/crypto-js-3.1.6/jquery.md5.js\"></script>\n"); 3 4 printf("//--------------------------------aes MD5 加密-------------------------------------------------------------------------------\n"); 5 printf(" var plaintText = document.frm.UserName.value + session_tmp;\n"); 6 printf(" var keyStr = document.frm.UserPwd.value;\n"); 7 printf(" var addZero;\n"); 8 /* 利用网上流传比较多的CryptoJS的aes加密,解密 9 * printf(" var key = CryptoJS.enc.Utf8.parse(keyStr);\n"); 10 * printf(" plaintText = ‘00112233445566778899aabbccddeeff‘;\n"); 11 12 * printf(" var encryptedData = CryptoJS.AES.encrypt(plaintText, key, {\n"); 13 * printf(" mode: CryptoJS.mode.ECB,\n"); 14 * printf(" padding: CryptoJS.pad.Pkcs7\n"); 15 * printf(" padding: CryptoJS.pad.NoPadding\n"); 16 * printf(" });\n"); 17 * printf(" var encryptedBase64Str = encryptedData.toString();\n"); 18 * printf(" var encryptedStr = encryptedData.ciphertext.toString();\n"); 19 * //解密 20 * printf(" var encryptedHexStr = CryptoJS.enc.Hex.parse(encryptedStr);\n"); 21 * printf(" var encryptedBase64Str = CryptoJS.enc.Base64.stringify(encryptedHexStr);\n"); 22 * //printf(" var decryptedStr = CryptoJS.AES.decrypt(CryptoJS.lib.CipherParams.create({ ciphertext: CryptoJS.enc.Hex.parse(encryptedStr) }), key, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 }).toString();"); 23 * printf(" var decryptedData = CryptoJS.AES.decrypt(encryptedBase64Str, key, { \n"); 24 * printf(" mode: CryptoJS.mode.ECB,\n"); 25 * printf(" padding: CryptoJS.pad.Pkcs7\n"); 26 * printf(" });\n"); 27 * printf(" var decryptedStr = decryptedData.toString(CryptoJS.enc.Utf8); \n"); 28 * printf(" console.log(\"jiemi:\"+decryptedStr); \n"); 29 */ 30 31 printf("\n /*AES加密前,将密钥转为16进制,将向量为sessio,再手动补位*/\n"); 32 printf(" var keyStr16 = stringToHex(keyStr);\n"); 33 printf(" var keyStr_iv = session_tmp;\n"); 34 printf(" console.log(\"plaint:\"+plaintText+\", len1:\"+plaintText.length+\", len2:\"+addZero+\", keyStr:\"+keyStr);\n"); 35 printf(" for(addZero = 64 - keyStr16.length;addZero > 0;addZero--){\n"); 36 printf(" keyStr16 = keyStr16 + \"0\";\n"); 37 printf(" };\n"); 38 printf(" for(addZero = 32 - keyStr_iv.length;addZero > 0;addZero--){\n"); 39 printf(" keyStr_iv = keyStr_iv + \"0\";\n"); 40 printf(" };\n"); 41 printf(" console.log(\"plaintText\"+plaintText+\"keyStr:\"+keyStr16+\"keyStr_iv:\"+keyStr_iv);\n"); 42 43 printf("\n /*AES加密,Gibberrish私有库*/\n"); 44 printf(" GibberishAES.size(256);\n"); 45 printf(" var password = GibberishAES.h2a(keyStr16);\n"); 46 printf(" var iv = GibberishAES.h2a(keyStr_iv);\n"); 47 printf(" var plaintext = GibberishAES.s2a(plaintText);\n"); 48 printf(" var plaintext_enc = GibberishAES.rawEncrypt(plaintext, password, iv);\n"); 49 printf(" var plaintext_str64 = GibberishAES.Base64.encode(plaintext_enc);\n"); 50 printf(" console.log(\"plaintext_str64 is :\"+plaintext_str64);\n"); 51 52 53 printf("\n /*密文转为Base64格式*/\n"); 54 printf(" plaintext_str64_str = plaintext_str64.toString();\n"); 55 printf(" plaintext_str64_str = plaintext_str64_str.substr(0,plaintext_str64_str.length-1);\n"); 56 57 printf("\n /*MD5 加密*/\n"); 58 printf(" plaintText = $.md5(plaintext_str64_str);\n"); 59 printf(" console.log(\"MD5_Str:\"+plaintText);\n"); 60 printf(" if(document.frm.UserPwd.value!=\"\"){document.frm.UserPwd.value = plaintText;}\n");
插入Object C的代码,在Object C中,我利用openssl实现了AES的ebc和cbc两种方式的加密,但是可能是openssl的加密函数与命令实现时进行的补位操作不同,导致的到的密文也是不相同的:
1 #include <openssl/aes.h> 2 #include <openssl/md5.h> 3 //---------------------------------- aes 加密 ------------------------- 4 5 /* 利用openssl接口带有的AES函数进行的ecb加密解密 6 * char key[16],*text=NULL,temp_plaint[256],temp_session[256]; 7 * //memset(text,0,sizeof(text)); 8 * memset(temp_session,0,sizeof(temp_session)); 9 * memset(temp_plaint,0,sizeof(temp_plaint)); 10 * memset(key,0,16); 11 * if(strlen(password)<16){ 12 * int fixZero = 16-strlen(password); 13 * char *fix = "0"; 14 * for(i =0; i<fixZero;i++){ 15 * strcat(password,fix); 16 * } 17 * } 18 * memcpy(key,password,strlen(password)); 19 20 * //user = "admin6291494661564876577"; 21 * //strcpy(text,user); 22 * //text = user; 23 * //sprintf(temp_session,"%llu",session); 24 * //strcat(text,temp_session); 25 * text = "super"; 26 27 * AES_KEY aes_key; 28 * AES_set_encrypt_key((unsigned char *)key, 128, &aes_key); 29 30 * int text_len = strlen(text); 31 * int blk_num = (text_len / AES_BLOCK_SIZE) + 1; 32 * int alg_len = blk_num * AES_BLOCK_SIZE; 33 34 * //uint8_t *alg_s = (typeof(alg_s)) malloc(alg_len); 35 * unsigned char *alg_s = malloc(alg_len); 36 * memcpy(alg_s, text, text_len); 37 * int pad = AES_BLOCK_SIZE - text_len % AES_BLOCK_SIZE; 38 39 * for (i = text_len; i < alg_len; i++) { 40 * alg_s[i] = pad; 41 * } 42 43 * int enc_len = alg_len; 44 45 * unsigned char *enc_s = malloc(enc_len); 46 * memset(enc_s, 0, enc_len); 47 * for (i = 0; i < blk_num; i++) { 48 * //AES_ecb_encrypt(OFFOF(alg_s, i * AES_BLOCK_SIZE), OFFOF(enc_s, i * AES_BLOCK_SIZE), &aes_key, AES_ENCRYPT); 49 * AES_ecb_encrypt(alg_s + i * AES_BLOCK_SIZE, enc_s + i * AES_BLOCK_SIZE, &aes_key, AES_ENCRYPT); 50 * trace("%02x ,%d\n",enc_s[i],i); 51 * } 52 53 * int t =0; 54 * for (i = 0; i < enc_len; i++) { 55 * if(t) t += sprintf(temp_plaint + t,"%02x", enc_s[i]); 56 * else t = sprintf(temp_plaint,"%02x", enc_s[i]); 57 * } 58 59 60 * //解密 61 * AES_set_decrypt_key(key, 128, &aes_key); 62 * int dec_len = enc_len; 63 * uint8_t *dec_s = (typeof(dec_s)) malloc(dec_len); 64 * for (i = 0; i < blk_num; i++) { 65 * AES_ecb_encrypt(OFFOF(enc_s, i * AES_BLOCK_SIZE), OFFOF(dec_s, i * AES_BLOCK_SIZE), &aes_key, AES_DECRYPT); 66 * } 67 */ 68 69 /* 利用openssl接口带有的AES函数进行的cbc加密解密 70 * unsigned char pt[64] = "secretsecretsecret"; 71 * unsigned char kt[64] = "1234567800000000000000000000000000000000000000000000000000000000"; 72 * unsigned char it[33] = "12345678000000000000000000000000"; 73 * // char pt[64] = "secretsecretsecret"; 74 * //char kt[65] = "1234567800000000000000000000000000000000000000000000000000000000"; 75 * //char it[33] = "12345678000000000000000000000000"; 76 * // char kt[64] = "12345678"; 77 * // char it[32] = "12345678"; 78 79 * unsigned char plainText[AES_BLOCK_SIZE * 4]; 80 * unsigned char cipherText[AES_BLOCK_SIZE * 4]; 81 * unsigned char keyText[AES_BLOCK_SIZE*4]; 82 * unsigned char ivText[AES_BLOCK_SIZE*2]; 83 * unsigned char ivdecText[AES_BLOCK_SIZE*2]; 84 * AES_KEY aes_key; 85 * char plainText[AES_BLOCK_SIZE * 4]; 86 * char cipherText[AES_BLOCK_SIZE * 4]; 87 * char keyText[AES_BLOCK_SIZE * 4]; 88 * char ivText[AES_BLOCK_SIZE * 2]; 89 * char ivdecText[AES_BLOCK_SIZE * 2]; 90 91 * memset(plainText,0,sizeof(plainText)); 92 * memset(cipherText,0,sizeof(cipherText)); 93 * memset(keyText,0,sizeof(keyText)); 94 * memset(ivText,0,sizeof(ivText)); 95 * memset(ivdecText,0,sizeof(ivdecText)); 96 97 * memcpy(plainText,pt,strlen(pt)); 98 * memcpy(keyText,kt,strlen(kt)); 99 * memcpy(ivText,it,strlen(it)); 100 * memcpy(ivdecText,it,strlen(it)); 101 102 * // strcpy(plainText,pt); 103 * // strcpy(keyText,kt); 104 * // strcpy(ivText,it); 105 * //strcpy(ivdecText,ivText); 106 * // strcpy(ivdecText,it); 107 108 * // strncpy(plainText,pt,strlen(pt)); 109 * // strncpy(keyText,kt,strlen(kt)); 110 * // strncpy(ivText,it,strlen(it)); 111 * // strncpy(ivdecText,it,strlen(it)); 112 113 * for(i = 0;i < sizeof(plainText);++i){ 114 * if(plainText[i] == 0) break; 115 * } 116 * AES_set_encrypt_key((unsigned char*)keyText,256,&aes_key); 117 * AES_cbc_encrypt((unsigned char *)plainText,(unsigned char *)cipherText,sizeof(plainText),&aes_key,(unsigned char *)ivText,AES_ENCRYPT); 118 119 * char temw[256]; 120 * for(i = 0;i < sizeof(cipherText);++i){ 121 * if(cipherText[i] == 0) break; 122 * sprintf(&temw[i],"%02x",cipherText[i]&0xff); 123 * } 124 * char plainba64[256]; 125 * memset(plainba64,0,strlen(plainba64)); 126 * int t_len; 127 * base64_encode((unsigned char *)temw,(unsigned char *)plainba64,strlen(temw),&t_len); 128 * AES_set_decrypt_key((unsigned char *)keyText,256,&aes_key); 129 * AES_cbc_encrypt((unsigned char *)cipherText,(unsigned char *)plainText,sizeof(cipherText),&aes_key,(unsigned char *)ivdecText,AES_DECRYPT); 130 * for(i = 0;i < sizeof(plainText);++i){ 131 * if(plainText[i] == 0) break; 132 * } 133 */ 134 135 /*将session,明文, key,iv合成字符串*/ 136 int t = 0,cmd = 0,wlen = 0; 137 char buff_CBC[256],buff_CBC_cmd[256],userText[256],keyText[65],temp_session[256],file[256],buff_ret[1024],*cbcText_f; 138 FILE *fp = NULL; 139 SlasRes sr; 140 141 memset(keyText,0,sizeof(keyText)); 142 memset(buff_ret,0,sizeof(buff_ret)); 143 memset(temp_session,0,sizeof(temp_session)); 144 145 /*session*/ 146 sprintf(temp_session,"%llu",session); 147 strcpy(buff_CBC,temp_session); 148 strcat(buff_CBC,","); 149 150 /*mingwen*/ 151 strcpy(userText,user); 152 strcat(userText,temp_session); 153 strcat(buff_CBC,userText); 154 strcat(buff_CBC,","); 155 156 /*key,转换成16进制*/ 157 for(i = 0;i<strlen(password);i++){ 158 if(password[i] == 0) break; 159 if(t) t += sprintf(keyText+t,"%02x",password[i]); 160 else t = sprintf(keyText,"%02x",password[i]); 161 } 162 strcat(buff_CBC,keyText); 163 strcat(buff_CBC,","); 164 165 /*iv*/ 166 strcat(buff_CBC,temp_session); 167 //trace("\nbuff_CBC:%s\n",buff_CBC); 168 169 cmd = CMD_PASS_CBC_ENC; 170 memcpy(buff_CBC_cmd, &cmd, sizeof(int)); 171 memcpy(buff_CBC_cmd+sizeof(int),buff_CBC,strlen(buff_CBC)); 172 wlen = strlen(buff_CBC)+4; 173 ret = CGIServerData((char *)buff_CBC_cmd,(int *)&wlen,&sr); 174 if(ret != 0 || sr.error || sr.state){ 175 printf("error"); 176 goto _END_; 177 } 178 179 strcpy(file,"/var/tmp/sess/sess_"); 180 strcat(file,temp_session); 181 182 fp = fopen(file, "r"); 183 if(NULL == fp){ 184 printf("error"); 185 unlink(file); 186 goto _END_; 187 } 188 189 fread(buff_ret,1024,1,fp); 190 cbcText_f = memmem(buff_ret,1024,"ffff",4); 191 /* if(cbcText == NULL){ 192 printf("error"); 193 goto _END_; 194 } 195 */ 196 197 //-------------------------------- MD5 加密--------------------------------- 198 199 char *data; 200 unsigned char md[16]; 201 memset(md,0,sizeof(md)); 202 char tmp[3]={‘\0‘},buf[33]={‘\0‘}; 203 204 data = cbcText_f+4; 205 data[strlen(data)-1] = ‘\0‘; 206 207 //trace("date:%s,%d",data,strlen(data)); 208 MD5_CTX ctx; 209 MD5_Init(&ctx); 210 MD5_Update(&ctx,data,strlen(data)); 211 MD5_Final(md,&ctx); 212 213 for (i = 0; i < 16; i++){ 214 sprintf(tmp,"%02x",md[i]&0xff); 215 strcat(buf,tmp); 216 }