使用Java和Bouncy Castle进行Rijndael 256加密

Rijndael 256 encryption with Java & Bouncy Castle

我正在开发一个使用纯PHP构建的项目,正在对登录进行重做,但是数据库中的用户使用Rijndael-256加密,我尝试了很多事情,但似乎没有任何效果,并且 我觉得我与这段代码非常接近,但是它不起作用,我真的迷路了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private final String key ="...";

public String decrypt(String password, String cypherKey) {
    try {
        password = password.substring(0, password.lenght() - 1); // 1
        byte[] passwordBytes = password.getBytes("UTF-8");
        byte[] key = cypherKey.getBytes("UTF-8");

        RijndaelEngine rijndaelEngine = new RijndaelEngine(256);
        KeyParameter keyParam = new KeyParameter(key);
        rijndaelEngine.init(false, keyParam); // 2
        PaddedBufferedBlockCipher bufferedBlock = new PaddedBufferedBlockCipher(rijndaelEngine, new ZeroBytePadding());

        byte[] decryptedBytes = new byte[bufferedBlock.getOutputSize(passwordBytes.length)];
        int processed = bufferedBlock.processBytes(passwordBytes, 0, passwordBytes.length, decryptedBytes, 0);

        return String.valueOf(bufferedBlock.doFinal(decryptedBytes, processed));
    } catch (Exeption e) {
        e.printStackTrace();
    }

    return""; // I know this is awful but i was trying something and left this like that
}

* 1)我不知道这是否正确,但是所有加密的密码都以等号结尾,并且我使用加密工具进行了测试,我认为这不是必需的

2)False是解密模式

堆栈跟踪:org.bouncycastle.crypto.DataLengthException:解密中的最后一个块不完整

我现在正在进行这种解密两个星期,我真的很拼命:(

PHP代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
function fnEncrypt($sValue)
{
    include("constants.php");

    return trim(
        base64_encode(
            mcrypt_encrypt(

                MCRYPT_RIJNDAEL_256,
                $SecretKey, $sValue,
                MCRYPT_MODE_ECB,


                mcrypt_create_iv(
                    mcrypt_get_iv_size(
                        MCRYPT_RIJNDAEL_256,  
                        MCRYPT_MODE_ECB
                    ),


                    MCRYPT_RAND)
                )
            )
        );
}

function fnDecrypt($sValue)
{
    include("constants.php");

    return trim(
        mcrypt_decrypt(
            MCRYPT_RIJNDAEL_256,  
            $sSecretKey,  
            base64_decode($sValue),  
            MCRYPT_MODE_ECB,

            mcrypt_create_iv(
                mcrypt_get_iv_size(
                    MCRYPT_RIJNDAEL_256,
                    MCRYPT_MODE_ECB
                ),  
                MCRYPT_RAND
            )
        )
    );
}


decrypt方法中,必须首先对密文进行Base64解码(1)。 另外,未正确确定解密的文本的长度(2a),并且相应的字节阵列的长度没有相应地调整(2b)。 最后,从字节数组(3)确定UTF8字符串存在问题。 修改decrypt方法的主体,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//password = password.substring(0, password.lenght() - 1); // 1                             // Remove
//byte[] passwordBytes = password.getBytes("UTF-8");                                        // Remove
byte[] passwordBytes = Base64.getDecoder().decode(password);                                // Base64-decode the ciphertext (1)
byte[] key = cypherKey.getBytes("UTF-8");

RijndaelEngine rijndaelEngine = new RijndaelEngine(256);
KeyParameter keyParam = new KeyParameter(key);
rijndaelEngine.init(false, keyParam); // 2
PaddedBufferedBlockCipher bufferedBlock = new PaddedBufferedBlockCipher(rijndaelEngine, new ZeroBytePadding());

byte[] decryptedBytes = new byte[bufferedBlock.getOutputSize(passwordBytes.length)];
int processed = bufferedBlock.processBytes(passwordBytes, 0, passwordBytes.length, decryptedBytes, 0);
processed += bufferedBlock.doFinal(decryptedBytes, processed);                              // Refresh the parameter containing the length of the decrypted data (2a)
decryptedBytes = Arrays.copyOfRange(decryptedBytes, 0, processed);                          // Reduce the byte-array accordingly (2b)

//return String.valueOf(bufferedBlock.doFinal(decryptedBytes, processed));                  // Remove          
return new String(decryptedBytes,"UTF-8");                                                 // Create a UTF-8 string from the byte-array (3)

与导入java.util.Base64org.bouncycastle.util.Arrays

即使这可能是遗留代码,也有两个关于安全性的注意事项:密码通常不应加密,而应加密。 此外,欧洲央行是不安全的。


这是我的解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/**
     * Step 1: password and key are converted to bytes in order to be processed by the cypher.
     *
     * Step 2: a KeyParameter is created with the key bytes.
     *
     * Step 3: a PaddedBufferedBlockCipher statement is assigned with Rijndael 256 algorithm and ZeroBytePadding, this padder adds NULL byte padding to a block.
     *
     * Step 4: the bufferedBlockCipher is then initialized with parameters"true" meaning Encryption mode, and the KeyParameter.
     * This initialization prepares the bufferedBlock with the parameters needed for encryption.
     *
     * Step 5: a variable"buffer" stores the length in bytes the output should have
     *
     * Step 6: the processed bytes are calculated and stored, buffer now stores the value of the password
     *
     * Step 7: the encryption is finalized, the plus equals sign ensures that the output is multiple of 32
     *
     * Step 8: the buffer and processedBytes are converted into an array of bytes and then a String
     *
     * @param password
     *
     * @return
     */


    public String encrypt(String password) throws InvalidCipherTextException {
        byte[] data = password.getBytes();
        byte[] encryptionKey = key.getBytes();

        KeyParameter keyParameter = new KeyParameter(encryptionKey);

        PaddedBufferedBlockCipher bufferedBlockCipher = new PaddedBufferedBlockCipher(new RijndaelEngine(256), new ZeroBytePadding());
        bufferedBlockCipher.init(true, keyParameter);

        byte[] buffer = new byte[bufferedBlockCipher.getOutputSize(data.length)];
        int processedBytes = bufferedBlockCipher.processBytes(data, 0, data.length, buffer, 0);
        processedBytes += bufferedBlockCipher.doFinal(buffer, processedBytes);

        byte[] result = Arrays.copyOfRange(buffer, 0, processedBytes);
        String output = Base64.encodeBase64String(result);

        return output;
    }