From a0d9711074a4cf35d4487b96dfee0c09ca1cf63f Mon Sep 17 00:00:00 2001 From: "tonu@volk.internalnet" <> Date: Mon, 26 Nov 2001 15:54:33 +0200 Subject: [PATCH] des_encrypt()/des_decrypt() are now ASCII protected and pass testsuite --- mysql-test/r/func_encrypt.result | Bin 0 -> 6966 bytes mysql-test/t/func_encrypt.test | 46 +++++++++++ sql/item_strfunc.cc | 136 +++++++++++++++++-------------- sql/item_strfunc.h | 4 +- 4 files changed, 122 insertions(+), 64 deletions(-) create mode 100644 mysql-test/r/func_encrypt.result create mode 100644 mysql-test/t/func_encrypt.test diff --git a/mysql-test/r/func_encrypt.result b/mysql-test/r/func_encrypt.result new file mode 100644 index 0000000000000000000000000000000000000000..637582a42794b9b34ad3f6ea48be5a750f0d1af3 GIT binary patch literal 6966 zcmd5=d5o0h83#eZPjN+!csA2wWI=uJcMeIYJG(nGJF_#hv%51pGgj9*zPY}+@0oNl zu||}o38Ixk@Bq|Gh0+MEl-8?N5-%)HaavX20)! z-skx}zu)hD-mg+pb!D|wUZ_Nixx7wS4u#XIE*aCQ^<=4B($yC#k)j$Z!&{#{sq5P7 zx^Oxdp1)8@W=m?ZtV?FgIbB^>4W%n;N!K1#OT%h5Qf%bQ?ehi`s;*E;Ml@Yfjp|~# zx-M18x4vZl#8L@;gR#FxnW1?T%{x5F5)V&2 z^T=dNJ<>w%(Mgwlw3Y1D$(O#`QvR_?SU{|`3cg7{`#PQzjzra1yu}(4ld%u+M5|RK zCubSSmg`7O(n3tDR=TW-VwVw~*t*-i?x8(mEu%xEdNLjZ)7c1s6;}@X1 zLcO>m{W4B_m=JNAk{K*eO_nidaT>vSS)fM7P(Q-ViBdc&6WC9il(MKSVY6Vu%@egko&oTm2nQ@Dby-lq{0~wRLcJ(X1GI+2&|NSvBb4^1{k1+KBQ$47;P5}s!l`B9Ob2vm2e7cz|u0cGavBH&EnDy zxeXFV3RDm5c8eh%=K;XAmjy5;9)^e>*^nPMxS8~zZc*a>P-i#dkeh}z;9>*!F#`(F ze$fH{XT&9%G(sCVgxzFZ-{U(1LqNe1Zewxo2R8^x*dOXQiU9mnsnERi(xgnlGe7QN zE*2kWCQsrp@I(;GK$o%vm{>_gYCMIDk_jr@%qa}WCbF^w3Lj(!L0J!RqM+2H3S`ib zH9jOgtS$>UN1>zK2C5vQRp`VQbK*k7f*FCqS@5nrFeoF#xCx5RU=14>CLwMWQOQLP zH~A2jz<*UbMMVzDGVO;wVpM~UH?f_iAbS&0$NfeQuoU-k7jQDiBh(K3=oS^|pj&X^ zK{Z^2o?w!fP1x~^IT?uonNgH#xRZ2)x)iEn75kv)eq5pnX=O4iqCwZ3q=4SJ7iqJ zNofW2QnDZo(7_%tNGu`*7zZI{C!nJj9mq}6(nrHs5(}w<@418p#V{iV&{YI#EP)@o zh?~S@6{`2ypv8)I+M!wLEan3M>cz zpnZ&kMFw#P0xt#)V9=`x0q)?i3iWY2lEM!CDpOUO!6P*|g{*?H0;pDkI=i4#B^r@% zs*wVCVs4zLvI2QI1t&(-2MA@bD&0sRIN^{aHEI^HKX`}+3V^+77(A*3$k_qGPEz1O z*~wzy4?gg}jPye6gv0ZvvVr8kG_%(6a#|p|U8v-2{hfK+aA$HJsr31e6z) zaX0~0$(afIt#KpxzX|f_Mcqswm+(s$oWybL2DWt&0-eiZD`>?9o=FJkl#jbt4@yxJ zfi(hL7L~CPVbYLEKqpK4;T*NYsWT)Ic$14|!JqQ9KoOj?UO+8MV^F0JhoI^z??VA_ zr4%iLwuV4YcESnxjR;dfgZCl}>VjAmSm9y=Yyd^M8+8*m3qkM4)vfYA@Utk-Vk#Ug zLpi+dfDiz1@w|Twut!I@uY5!K^xLar zmzFN54S568+uk`j@apVl;Lrorxj&maVn@{_p6t^v|M(=2df7*#Q_rof6^{KIl>64q z{pmf*!`sRmwOwEm`LZ|3K>pMCEw(_d-VH)g); zUhn$k>6eT<{Ijl6)>V}q%JxsTFTCNc3#Xm@>=`{b{{Fem!;j3%&ADrL<<_?1={KzX z(_;@$x#<0wZ_i#DKIPJ^d&yO9n zdg84Qs-Zaxkmh^&xaGt*`}p-!R{lm=a?X*!l&c<7Ru8vrI&J0KFMRrVTjJV77e`+C z^xz$N>2*7Q0y zz1RJ~WlwCoe%q?;uikvshui7s&S#vj%%29Xlr@V{%d|dOGf70dijh; zt{ojZ8Y8OcD`)!;JD=KrxAptQ8S0jmbIv+pMef9pNBy%-pZWZh>@OZY?9~m=UH-{O z+Q^*&^#_k`diK=QPB^;$LS^B+M=!iWn>ORDQ?6L}V4G>}=CPei4lR2AoT+=)-Fn5e z+n=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.') #define ascii_to_bin(c) ((c)<=57 ? (c)-46 : (c)<=90 ? (c)-53 : (c)-59) - + +/* + Function des_encrypt() by tonu@spam.ee + Works only if compiled with OpenSSL library support. + Output always starts with magic char "1" and all + encrypted output is encoded into ASCII-protected + container. + Original input is returned as output if input string + begins with magic "1". Credit card number always begin + with 4,5 or 6. + Encryption result is longer than original by formula: + new_length=(8-(original_length % 8))*2+1 +*/ + String *Item_func_des_encrypt::val_str(String *str) { String *res =args[0]->val_str(str); #ifdef HAVE_OPENSSL des_key_schedule ks1, ks2, ks3; des_cblock ivec={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; - union { - des_cblock allkeys[3]; // 24 bytes (168 bits) total + struct { des_cblock key1, key2, key3; // 8 bytes each - } key; + } keyblock; if ((null_value=args[0]->null_value)) return 0; if (res->length() == 0) return &empty_string; - String *keystr=args[1]->val_str(&tmp_value); - int32 mode=0; - if(arg_count == 3 && !args[2]->null_value) - mode=args[2]->val_int(); - // We make good 24-byte (168 bit) key from given plaintext key with MD5 - EVP_BytesToKey(EVP_get_cipherbyname("DES-EDE3-CBC"),EVP_md5(),NULL, + if(res->c_ptr()[0]!='1') { // Skip encryption if already encrypted + String *keystr=args[1]->val_str(&tmp_value); + /* We make good 24-byte (168 bit) key from given plaintext key with MD5 */ + EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL, (uchar *)keystr->c_ptr(), - keystr->length(),1,(uchar *)&key.allkeys,ivec); - // Here we set all 64-bit (56 actually) one by one - des_set_key_unchecked(&key.key1,ks1); - des_set_key_unchecked(&key.key2,ks2); - des_set_key_unchecked(&key.key3,ks3); - /* The problem: DES algorithm requires original data to be in 8-bytes - * chunks. Missing bytes get filled with zeros and result of encryption - * can be up to 7 bytes longer than original string. When decrypted, - * we do not know the size of original string :( - * We add one byte with value 0x0..0x7 to original plaintext marking - * change of string length */ - uchar tail=8-(res->length() % 8); // 1..8 - for(int i=0 ; i < (tail-1) ; ++i) res->append('*'); - res->append(tail-1); // Write tail length 0..7 to last pos - // Real encryption - des_ede3_cbc_encrypt( - (const uchar*)(res->c_ptr()), - (uchar*)(res->c_ptr()), + (int)keystr->length(),1,(uchar *)&keyblock,ivec); + des_set_key_unchecked(&keyblock.key1,ks1); // Here we set all 64-bit keys + des_set_key_unchecked(&keyblock.key2,ks2); // (56 effective) one by one + des_set_key_unchecked(&keyblock.key3,ks3); + /* + The problem: DES algorithm requires original data to be in 8-bytes + chunks. Missing bytes get filled with zeros and result of encryption + can be up to 7 bytes longer than original string. When decrypted, + we do not know the size of original string :( + We add one byte with value 0x0..0x7 to original plaintext marking + change of string length + */ + uchar tail= 7-( res->length() %8); // 0..7 marking real offsets 1..8 + for(int i=0 ; i < tail ; ++i) res->append('*'); + res->append(tail); // Write tail length 0..7 to last pos + str->length(res->length()); + des_ede3_cbc_encrypt( // Real encryption + (const uchar*)(res->c_ptr()), + (uchar*)(str->c_ptr()), res->length(), ks1, ks2, ks3, &ivec, TRUE); - if(mode) { - // In case of ASCII mode we should convert binary string into ASCII - str->set((const char*)0,(uint)0); - for(uint i=0 ; i < res->length() ; ++i) { - str->append(bin_to_ascii((uchar)res->c_ptr()[i] & 0x3f)); - str->append(bin_to_ascii(((uchar)res->c_ptr()[i] >> 5 ) & 0x3f)); + res->set((const char*)"1",(uint)1); + for(uint i=0 ; i < str->length() ; ++i) + { + res->append(bin_to_ascii((uchar)str->c_ptr()[i] & 0x3f)); + res->append(bin_to_ascii(((uchar)str->c_ptr()[i] >> 5 ) & 0x3f)); } - return str; - } else - return res; + } + return res; #else null_value=1; return 0; @@ -267,43 +276,46 @@ String *Item_func_des_decrypt::val_str(String *str) #ifdef HAVE_OPENSSL des_key_schedule ks1, ks2, ks3; des_cblock ivec={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; - union { - des_cblock allkeys[3]; // 24 bytes total + struct { des_cblock key1, key2, key3; // 8 bytes each - } key; + } keyblock; + if ((null_value=args[0]->null_value)) return 0; if (res->length() == 0) return &empty_string; - String *keystr=args[1]->val_str(&tmp_value); - int32 mode=0; - if(arg_count == 3 && !args[2]->null_value) - mode=args[2]->val_int(); - // We make good 24-byte (168 bit) key from given plaintext key with MD5 - EVP_BytesToKey(EVP_get_cipherbyname("DES-EDE3-CBC"),EVP_md5(),NULL, - (uchar *)keystr->c_ptr(), - keystr->length(),1,(uchar *)&key.allkeys,ivec); - // Here we set all 64-bit keys (56 effective) one by one - des_set_key_unchecked(&key.key1,ks1); - des_set_key_unchecked(&key.key2,ks2); - des_set_key_unchecked(&key.key3,ks3); - str->set((const char*)0,(uint)0); - if(mode) { - for(uint i=0 ; i < res->length() ; i+=2) { + + if(res->c_ptr()[0]=='1') // Skip decryption if not encrypted + { + str->set((const char*)0,(uint)0); + for(uint i=1 ; i < res->length() ; i+=2) + { str->append((ascii_to_bin(res->c_ptr()[i])) - | (ascii_to_bin(res->c_ptr()[i+1]) << 5 )); + | (ascii_to_bin(res->c_ptr()[i+1]) << 5 )); } - } else - str->copy(res->c_ptr()); - // Real decryption - des_ede3_cbc_encrypt( + + String *keystr=args[1]->val_str(&tmp_value); + int32 mode=0; + if(arg_count == 3 && !args[2]->null_value) + mode=args[2]->val_int(); + /* We make good 24-byte (168 bit) key from given plaintext key with MD5 */ + EVP_BytesToKey(EVP_des_ede3_cbc(),EVP_md5(),NULL, + (uchar *)keystr->c_ptr(), + (int)keystr->length(),1,(uchar *)&keyblock,ivec); + des_set_key_unchecked(&keyblock.key1,ks1); // Here we set all 64-bit keys + des_set_key_unchecked(&keyblock.key2,ks2); // (56 effective) one by one + des_set_key_unchecked(&keyblock.key3,ks3); + res->length(str->length()); + des_ede3_cbc_encrypt( // Real decryption (const uchar*)(str->c_ptr()), (uchar*)(res->c_ptr()), str->length(), ks1, ks2, ks3, &ivec, FALSE); - uchar tail=(res->c_ptr()[str->length()-1]) & 0x7; - res->length(str->length()-tail-1); + uchar tail=(res->c_ptr()[res->length()-1]) & 0x7; + if((res->length() > ((uint)1+tail))) // We should avoid negative length + res->length(res->length()-1-tail); // (can happen with wrong key) + } return res; #else null_value=1; diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 96a2f30d5c7..31c832c8ddb 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -230,7 +230,7 @@ public: Item_func_des_encrypt(Item *a, Item *b): Item_str_func(a,b) {} Item_func_des_encrypt(Item *a, Item *b, Item *c): Item_str_func(a,b,c) {} String *val_str(String *); - void fix_length_and_dec() { maybe_null=1; max_length = 13; } + void fix_length_and_dec() { maybe_null=1; max_length = args[0]->max_length; } const char *func_name() const { return "des_encrypt"; } }; @@ -242,7 +242,7 @@ public: Item_func_des_decrypt(Item *a, Item *b): Item_str_func(a,b) {} Item_func_des_decrypt(Item *a, Item *b, Item *c): Item_str_func(a,b,c) {} String *val_str(String *); - void fix_length_and_dec() { maybe_null=1; max_length = 13; } + void fix_length_and_dec() { maybe_null=1; max_length = args[0]->max_length; } const char *func_name() const { return "des_decrypt"; } };