lua-resty-string icon indicating copy to clipboard operation
lua-resty-string copied to clipboard

lua aes ECB 128 decrypt error

Open lilien1010 opened this issue 8 years ago • 17 comments

I tryed encrypt a text with a key with PHP code,then it is OK when decrypt it with Java and Object-C ,

 mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $bindkey, $text, MCRYPT_MODE_ECB )

I dont know why do you need a sha1 when I just want want decrypt a ECB mode string

local aes_default = aes:new(key,nil, aes.cipher(128,"ecb"),aes.hash.sha1)

lilien1010 avatar Aug 05 '15 08:08 lilien1010

I have the same question. @lilien1010 Did you have the solution already?

pbby avatar Mar 30 '16 06:03 pbby

Maybe due to a different padding used by PHP?

agentzh avatar Mar 30 '16 19:03 agentzh

@agentzh Thanks for answering. I do not know much about the encryption algorithm. but i tested on many sites with aes tool, like:

They have the same encrypted string, when the cipher is aes, the key is secret, the data is hello, and the mode is ecb, just the issue owner says. I got hex: ebb28eae23f5d293629d02af7e3f4756 base64: 67KOriP10pNinQKvfj9HVg==

then, I tested with the aes of lua-resty-string lib, there is my code

local aes = require "resty.aes"
local str = require "resty.string"

local data = "hello"
local aes_128_ecb, err = aes:new("secret", nil, aes.cipher(128,"ecb"), nil)
if err  then
    ngx.say(err)
    ngx.exit(200)
end
local encrypted = aes_128_ecb:encrypt(data)
ngx.say("AES 128 EBC Encrypted HEX: ", str.to_hex(encrypted))
ngx.say("AES 128 EBC Decrypted: ", aes_128_ecb:decrypt(encrypted))

the result is:

AES 128 EBC Encrypted HEX: daae45d76f329165629d839f0c7f009f
AES 128 EBC Decrypted: hello

The result is not matched, and I do it on a wrong way?

pbby avatar Mar 31 '16 06:03 pbby

@surfire91 Maybe this is helpful: https://github.com/openresty/lua-resty-string/issues/10#issuecomment-11960797

agentzh avatar Mar 31 '16 19:03 agentzh

(I have removed my code. It may misleading you.)

puImp7Im avatar Apr 01 '16 04:04 puImp7Im

@WiLdWiNd-WH I got a error bad key length as your way.

Maybe ecb mode don't need a iv ?

pbby avatar Apr 05 '16 02:04 pbby

@agentzh I think #10 is a question, not a solution......

pbby avatar Apr 05 '16 12:04 pbby

I'm pretty sure, as @agentzh said, this is issue with different padding. Some info:

  1. AES-128 key/secret size is fixed 128 bits or 16 bytes, now your key secret is only 6 bytes, so it needs to be padded (or possibly hashed with hash function that provides 16 bytes of data). Simplest way to pad is just zero-pad, aka add needed number of \0 to end of that key.
  2. AES is a block cipher and the size of the block is fixed 16 bytes. Now your data hello is only 5 bytes, so it needs to be padded to 16 bytes, now again, simplest way to pad is to zero pad.

Let me illustrate this using my lua-resty-nettle:

lua-resty-nettle doesn't pad any keys or data automatically (at least by now, but I may implement padding mechanisms later). Now to get the results you want, I need to pad myself:

local function hex(str,spacer)
    return (string.gsub(str,"(.)", function (c)
        return string.format("%02X%s",string.byte(c), spacer or "")
    end))
end

local aes = require "resty.nettle.aes"
local aes128 = aes.new "secret\0\0\0\0\0\0\0\0\0\0"
local ciphertext = aes128:encrypt "hello\0\0\0\0\0\0\0\0\0\0\0"
print("aes128 ecb encrypt", #ciphertext, hex(ciphertext))
local aes128 = aes.new "secret\0\0\0\0\0\0\0\0\0\0"
local plaintext = aes128:decrypt(ciphertext)
print("aes128 ecb decrypt", #plaintext, plaintext)

And when I run this I get this output (just like in PHP):

aes128 ecb encrypt  16  EBB28EAE23F5D293629D02AF7E3F4756
aes128 ecb decrypt  5   hello

I'm not sure about how lua-resty-string does the padding, so I cannot say for sure. But maybe this helps you to understand. There are more moving parts in the method signature in lua-resty-string so I cannot say for sure, what happens inside. The hash-parameter may use some default, I don't know (maybe it auto hashes the secret).

bungle avatar Apr 05 '16 12:04 bungle

And the IV thing, AES in ECB mode doesn't support it as far as I know because it doesn't perform chaining between blocks. It is the worst mode to use if the data you are trying to encrypt is more that 16 bytes (also the most simple and stupid).

bungle avatar Apr 05 '16 13:04 bungle

@bungle Thanks I got that, php do auto padding on background.

pbby avatar Apr 07 '16 06:04 pbby

For PHP mycrypt the padding is \0 and openssl use PKCS#5 padding, so if you use openssl api's to decrypt php's encrypt result you can disabled default padding.

  1. openssl
  2. PKCS#5 padding

Or using my aes-php

Wang avatar Aug 16 '16 12:08 Wang

@Wang hai shi ni niubi!!!

qqlee avatar Jun 15 '17 12:06 qqlee

Hi, @agentzh
I run into this issue today, thought that this API suit should use zeropadding defaultlly. I suggest add an flag parameter in new() function to set padding rules ,which is by default PKCS#5 to compatite with current version; and can select other ways to padding, like zero paddings. this could make it much user-friendly I paste my simple code example below, and if u agree with it, I'll make a pull request for it

-- key too long
if padding_mode == ZERO_PADDING then
if #key > _cipherLength then
    return nil
else
    -- padding key with 0x00, work for all of 128,192,256 bits
    key = key.."\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
end
ffi_copy(gen_key, key, _cipherLength)

`

haorenfsa avatar Aug 16 '17 12:08 haorenfsa

@haorenfsa What do you think of this pending pull request?

https://github.com/openresty/lua-resty-string/pull/35

agentzh avatar Aug 16 '17 19:08 agentzh

@agentzh #35 is about data padding. and I think there's some problem with the key. I did some test, found this module even not compatite with openssl enc -aes-256-xxx cmds, and then I found that my issue (also most people's I guess) lies on that the parameter key we input is usually the real key we want to use, while aes.lua take our input key and use md5 to regenarate another string, and use it as the key, which is some random md5 value. and that causes this module not compatite with all others like php openssl. for example, a common php openssl aes api usage is like:

openssl_encrypt('data here', 'AES-256-ECB', 'some_key');

and the actual key used to encrypt is "some_key\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"

while in ngx.resty.aes if u input 'some_key' as key, then after md5 the real key is actually "3d70412c7e9ea2d96fa23d4f1f1f0a1c"

And thus bad time comes........

haorenfsa avatar Aug 17 '17 05:08 haorenfsa

@haorenfsa That sounds like a bug to me. We should not do MD5 on the key unless explicitly dictated.

agentzh avatar Aug 17 '17 05:08 agentzh

@agentzh yes, exactlly

haorenfsa avatar Aug 17 '17 06:08 haorenfsa