【问题标题】:Rijndael 256 encryption with Java & Bouncy Castle使用 Java 和 Bouncy Castle 进行 Rijndael 256 加密
【发布时间】:2020-01-17 18:58:39
【问题描述】:

我正在开发一个用纯 php 构建的项目,我正在对登录进行返工,但数据库中的用户是 Rijndael-256 中的密码,我尝试了很多东西,但似乎没有工作,我觉得我很接近这段代码,但它不起作用,我真的迷路了

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 代码:

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 
            ) 
        ) 
    ); 
}

【问题讨论】:

  • 如果可能,发送 PHP 代码进行加密。对于解密的实现,必须知道加密的细节。 Rijndael-256(256 位是块大小)相当不寻常(可能与 AES-256 混淆,其中 256 位是密钥大小)。等号表示 Base64 编码。
  • 我上传了php代码,使用的方法在php中已被弃用,所以我认为这是一个大问题
  • 仅供参考:ECB 不使用 IV,这是导致它对包括此在内的几乎所有用途都不安全的原因之一,但对于确实使用 IV 的模式,您必须在(每个)加密并存储或传输它并使用相同的,而不是创建一个新的,在解密
  • 我知道这个方法不安全,系统是几年前有人做的,我们被雇来重建它,正如我在另一条评论中所说,老用户必须访问该页面没有任何问题,因此我必须输入密码并将其与存储在 DB 中的密码匹配

标签: java encryption rijndael


【解决方案1】:

decrypt-方法中,密文必须首先经过 Base64 解码 (1)。此外,解密文本的长度没有正确确定(2a),相应的字节数组的长度也没有相应调整(2b)。最后,从字节数组中确定 UTF8 字符串存在问题 (3)。修改decrypt-方法的主体如下:

//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

尽管这可能是遗留代码,但有两个关于安全性的注意事项:密码通常不应该加密,而是hashed。此外,ECB 是不安全的。

【讨论】:

  • 次要:new String (decryptedBytes, 0, processed, charset) 不需要 copyOfRange
  • 谢谢,我找到了解决方案,使用与我相同的代码,但在加密模式下,并修改了一些东西,我知道加密不安全,但系统真的很旧,我们受雇重建网页,但重要的是老用户有权访问他们的帐户
【解决方案2】:

这是我的解决方案:

/**
     * 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;
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-09-01
    • 2021-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-26
    • 2017-02-19
    • 1970-01-01
    相关资源
    最近更新 更多