From 8706dde5c0bd4bbc06948344ca2523ccb98fa3cd Mon Sep 17 00:00:00 2001 From: "tonu@volk.internalnet" <> Date: Fri, 9 Nov 2001 07:49:57 +0200 Subject: [PATCH] des_encrypt()/des_decrypt() work much better now --- sql/item_strfunc.cc | 139 +++++++++++++++++++------------------------- sql/item_strfunc.h | 4 ++ sql/sql_yacc.yy | 8 ++- 3 files changed, 70 insertions(+), 81 deletions(-) diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index b2c475dc4a0..315db3b83a1 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -202,127 +202,109 @@ void Item_func_concat::fix_length_and_dec() } #define bin_to_ascii(c) ((c)>=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) + 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]; - des_cblock key1; - des_cblock key2; - des_cblock key3; + des_cblock allkeys[3]; // 24 bytes (168 bits) total + des_cblock key1, key2, key3; // 8 bytes each } key; - - if ((null_value=args[0]->null_value)) return 0; if (res->length() == 0) return &empty_string; - String *in_str=args[1]->val_str(&tmp_value); - char *tmp=my_malloc(res->length()+8, MYF(0)); - DBUG_PRINT("info",("DES: key string='%s'",in_str->c_ptr())); - DBUG_PRINT("info",("DES: data string='%s'",res->c_ptr())); - DBUG_PRINT("info",("DES: cipher pointer='%x'",EVP_get_cipherbyname("DES-EDE3-CBC"))); + 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, - (unsigned char *)in_str->c_ptr(), - in_str->length(),1,(uchar *)&key.allkeys,ivec); + (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); - DBUG_PRINT("info",("DES: checkpoint")); + /* 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 unsigned char*)(res->c_ptr()) , - (uchar*)tmp, - res->length(), - ks1, ks2, ks3, &ivec, TRUE); - res->length(res->length()+8-(res->length() % 8)); - DBUG_PRINT("info",("DES: checkpoint")); - DBUG_PRINT("info",("DES: string length='%d' versus '%d'",res->length(),strlen(res->c_ptr()))); - DBUG_PRINT("info",("DES: crypted data string='%s'",tmp)); + (const uchar*)(res->c_ptr()), + (uchar*)(res->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(tmp[i]); -// str->append(bin_to_ascii(tmp[i] & 0x3f)); -// str->append(bin_to_ascii((tmp[i] >> 5) & 0x3f)); - } - DBUG_PRINT("info",("DES: crypted data plain string='%s'",str->c_ptr())); - str->copy(); - DBUG_PRINT("info",("DES: crypted data plain string='%s'",str->c_ptr())); - my_free(tmp,MYF(0)); - return str; + 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)); + } + return str; + } else + return res; #else null_value=1; return 0; #endif /* HAVE_OPENSSL */ } - String *Item_func_des_decrypt::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]; - des_cblock key1; - des_cblock key2; - des_cblock key3; + des_cblock allkeys[3]; // 24 bytes total + des_cblock key1, key2, key3; // 8 bytes each } key; - if ((null_value=args[0]->null_value)) return 0; if (res->length() == 0) return &empty_string; - String *in_str=args[1]->val_str(&tmp_value); - char *tmp=my_malloc(res->length()+8, MYF(0)); - DBUG_PRINT("info",("DES: key string='%s'",in_str->c_ptr())); - DBUG_PRINT("info",("DES: data string='%s'",res->c_ptr())); -/* int EVP_BytesToKey(const EVP_CIPHER *type, EVP_MD *md, - const unsigned char *salt, const unsigned char *data, int datal, - int count, unsigned char *key, unsigned char *iv) -*/ + 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, - (unsigned char *)in_str->c_ptr(), - in_str->length(),1,(uchar *)&key.allkeys,ivec); + (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); - DBUG_PRINT("info",("DES: cipher pointer='%x'",EVP_get_cipherbyname("DES-EDE3-CBC"))); - EVP_BytesToKey(EVP_get_cipherbyname("DES-EDE3-CBC"),EVP_md5(),NULL, - (unsigned char *)in_str->c_ptr(), - in_str->length(),1,(uchar *)&key.allkeys,ivec); - - DBUG_PRINT("info",("DES: checkpoint")); - des_ede3_cbc_encrypt( - (const unsigned char*)(res->c_ptr()) , - (uchar*)tmp, - res->length(), - ks1, ks2, ks3, &ivec, FALSE); - - DBUG_PRINT("info",("DES: checkpoint")); - DBUG_PRINT("info",("DES: string length='%d' versus '%d'",res->length(),strlen(res->c_ptr()))); - DBUG_PRINT("info",("DES: crypted data string='%s'",tmp)); - str->set((const char*)0,(uint)0); - for(uint i=0 ; i < res->length() ; ++i) - { - str->append(tmp[i]); -// str->append(bin_to_ascii(tmp[i] & 0x3f)); -// str->append(bin_to_ascii((tmp[i] >> 5) & 0x3f)); + str->set((const char*)0,(uint)0); + if(mode) { + for(uint i=0 ; i < res->length() ; i+=2) { + str->append((ascii_to_bin(res->c_ptr()[i])) + | (ascii_to_bin(res->c_ptr()[i+1]) << 5 )); } - DBUG_PRINT("info",("DES: crypted data plain string='%s'",str->c_ptr())); - str->copy(); - DBUG_PRINT("info",("DES: crypted data plain string='%s'",str->c_ptr())); - my_free(tmp,MYF(0)); - return str; + } else + str->copy(res->c_ptr()); + // Real decryption + des_ede3_cbc_encrypt( + (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); + return res; #else null_value=1; return 0; @@ -331,7 +313,6 @@ String *Item_func_des_decrypt::val_str(String *str) - /* ** concat with separator. First arg is the separator ** concat_ws takes at least two arguments. diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 7bd587e44a9..96a2f30d5c7 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -228,8 +228,10 @@ class Item_func_des_encrypt :public Item_str_func public: Item_func_des_encrypt(Item *a) :Item_str_func(a) {} 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; } + const char *func_name() const { return "des_encrypt"; } }; class Item_func_des_decrypt :public Item_str_func @@ -238,8 +240,10 @@ class Item_func_des_decrypt :public Item_str_func public: Item_func_des_decrypt(Item *a) :Item_str_func(a) {} 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; } + const char *func_name() const { return "des_decrypt"; } }; class Item_func_encrypt :public Item_str_func diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 7e278481113..0f4111cf4f1 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1612,8 +1612,12 @@ simple_expr: { $$= new Item_func_decode($3,$5.str); } | ENCODE_SYM '(' expr ',' TEXT_STRING ')' { $$= new Item_func_encode($3,$5.str); } - | DES_ENCRYPT '(' expr ',' expr ')' { $$= new Item_func_des_encrypt($3,$5); } - | DES_DECRYPT '(' expr ',' expr ')' { $$= new Item_func_des_decrypt($3,$5); } + | DES_ENCRYPT '(' expr ')' { $$= new Item_func_des_encrypt($3); } + | DES_DECRYPT '(' expr ')' { $$= new Item_func_des_decrypt($3); } + | DES_ENCRYPT '(' expr ',' expr ')' { $$= new Item_func_des_encrypt($3,$5); } + | DES_DECRYPT '(' expr ',' expr ')' { $$= new Item_func_des_decrypt($3,$5); } + | DES_ENCRYPT '(' expr ',' expr ',' expr ')' { $$= new Item_func_des_encrypt($3,$5,$7); } + | DES_DECRYPT '(' expr ',' expr ',' expr ')' { $$= new Item_func_des_decrypt($3,$5,$7); } | EXPORT_SET '(' expr ',' expr ',' expr ')' { $$= new Item_func_export_set($3, $5, $7); } | EXPORT_SET '(' expr ',' expr ',' expr ',' expr ')'