使用OpenResty的resty.aes模块解密Java Cipher.getInstance(“AES / CBC / NoPadding”)的结果失败

时间:2017-08-03 04:18:21

标签: java nginx encryption lua

我正在开发一个nginx(openresty)Lua模块,其中一个要求是破译遗留Java程序生成的加密字符串。但我的Lua代码未能破译它,我在这里寻求帮助。

Java加密和解密代码没问题:

<widget id="com.yourapp.hybrid" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">

输出Java代码:

public class AesCbc {
    private static String PLAIN = "usr/passwd@bizdb:127.0.0.1:5432";

    public static void main(String[] args) throws Exception {
        Cipher aesCipher = Cipher.getInstance("AES/CBC/NoPadding");
        SecretKeySpec keySpec = new SecretKeySpec("1234567890ABCDEF".getBytes(), "AES");
        IvParameterSpec iv = new IvParameterSpec("fedcba0987654321".getBytes());

        aesCipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
        byte[] rawBytes = PLAIN.getBytes();
        byte[] aligned;
        int mod = rawBytes.length % 16; // prevent javax.crypto.IllegalBlockSizeException
        if (mod == 0) {
            aligned = new byte[rawBytes.length];
        } else {
            aligned = new byte[rawBytes.length + 16 - mod];
        }
        System.arraycopy(rawBytes, 0, aligned, 0, rawBytes.length);
        byte[] cipherBytes = aesCipher.doFinal(aligned);
        String base64Result = Base64.getEncoder().encodeToString(cipherBytes);
        System.out.println("cipher:[" + base64Result + "], rawBytes.length=" + rawBytes.length + ", mod=" + mod);

        aesCipher.init(Cipher.DECRYPT_MODE, keySpec, iv);
        cipherBytes = Base64.getDecoder().decode(base64Result);
        aligned = aesCipher.doFinal(cipherBytes);
        int posNil;
        for (posNil = 0; posNil < aligned.length; posNil++) {
            if (aligned[posNil] == 0x00)
                break;
        }
        rawBytes = new byte[posNil];
        System.arraycopy(aligned, 0, rawBytes, 0, posNil);
        String plain = new String(rawBytes);
        System.out.println("plain:[" + plain + "], posNil=" + posNil + ", aligned.length=" + aligned.length);
    }
}

我的Lua测试文件在nginx.conf-&gt; http-&gt;服务器部分中声明:

cipher:[l1buytGEL4RKa/RezInQ3dJxvMtL6nyE2wTi7VyoS4w=], rawBytes.length=31, mod=15
plain:[usr/passwd@bizdb:127.0.0.1:5432], posNil=31, aligned.length=32

conf / aescbc.lua的内容:

            location /aescbc {
                    content_by_lua_file conf/aescbc.lua;
            }

使用“curl http://127.0.0.1:8080/aescbc”进行测试时,nginx错误日志:

-- aescbc.lua

local aes = require "resty.aes"
local str = require "resty.string"
local aes128Cbc = aes:new("1234567890ABCDEF", nil, aes.cipher(128, "cbc"), {iv="fedcba0987654321"})

-- result of AesCbc.java for my test
local BASE64CIPHER = "l1buytGEL4RKa/RezInQ3dJxvMtL6nyE2wTi7VyoS4w="

local cipherBytes = ngx.decode_base64(BASE64CIPHER)
if not cipherBytes then
    ngx.log(ngx.WARN, "decode base64 [" .. BASE64CIPHER .. "] failed")
    return
end

local aligned = aes128Cbc:decrypt(cipherBytes)
if not aligned then
    ngx.log(ngx.WARN, "decrypt cipherBytes [" .. str.to_hex(cipherBytes) .. "] failed")
    return
end

ngx.log(ngx.NOTICE, "aligned [" .. str.to_hex(aligned) .. "]")
return

我认为我使用resty.aes肯定有问题,但是如何解决呢?

1 个答案:

答案 0 :(得分:2)

在搜索网页,阅读手册页并进行了几天的实验后,问题就解决了。所以我自己回答:

resty.aes模块使用OpenSSL的默认PKCS7填充算法,并且没有方法在当前版本的resty.aes中设置 NoPadding 选项。所以我做了一个补丁:(添加 padding 参数并在aes中调用 EVP_CIPHER_CTX_set_padding():new)

$ diff ./lualib/resty/aes.lua.orig ./lualib/resty/aes.lua
79a80
> int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *x, int padding);
128c129
< function _M.new(self, key, salt, _cipher, _hash, hash_rounds)
---
> function _M.new(self, key, salt, _cipher, _hash, hash_rounds, padding)
177a179,184
>     end
> 
>     if padding then
>         -- 0:NoPadding, 1:PKCS7(default), 2:ISO7816_4, 3:ANSI923, 4:ISO10126, 5:ZERO
>         C.EVP_CIPHER_CTX_set_padding(encrypt_ctx, padding);
>         C.EVP_CIPHER_CTX_set_padding(decrypt_ctx, padding);

对lua测试代码进行了一些小修改:

$ cat ./nginx/conf/aescbc.lua 
-- aescbc.lua

local aes = require "resty.aes"
local str = require "resty.string"
local aes128Cbc = aes:new("1234567890ABCDEF", nil, aes.cipher(128, "cbc"), {iv="fedcba0987654321"}, nil, 0)

-- result of AesCbc.java for my test
local BASE64CIPHER = "l1buytGEL4RKa/RezInQ3dJxvMtL6nyE2wTi7VyoS4w="

local cipherBytes = ngx.decode_base64(BASE64CIPHER)
if not cipherBytes then
    ngx.log(ngx.WARN, "decode base64 [" .. BASE64CIPHER .. "] failed")
    return
end

local aligned = aes128Cbc:decrypt(cipherBytes)
if not aligned then
    ngx.log(ngx.WARN, "decrypt cipherBytes [" .. str.to_hex(cipherBytes) .. "] failed")
    return
end

ngx.log(ngx.NOTICE, "aligned [" .. str.to_hex(aligned) .. "], len=" .. aligned:len())

local plain 
local idx = aligned:find('\0')
if idx then
    plain = aligned:sub(1, idx - 1)
else
    plain = aligned
end

ngx.log(ngx.NOTICE, "plain [" .. plain .. "], len=" .. plain:len())

return

测试的nginx错误日志:

2017/08/07 15:17:55 [notice] 34632#0: *21 [lua] aescbc.lua:22: aligned [7573722f7061737377644062697a64623a3132372e302e302e313a3534333200], len=32, client: 127.0.0.1, server: , request: "GET /aescbc HTTP/1.1", host: "127.0.0.1:8080"
2017/08/07 15:17:55 [notice] 34632#0: *21 [lua] aescbc.lua:32: plain [usr/passwd@bizdb:127.0.0.1:5432], len=31, client: 127.0.0.1, server: , request: "GET /aescbc HTTP/1.1", host: "127.0.0.1:8080"