openssl_encrypt aes 256 with hash in java

问题描述

来自下面的PHP加密函数

$data = "1212312121447";
$cipher = "aes-256-ofb";
$secretKey = "aNdRgUjXn2r5u8x/A?D(G+KbPeShVmYp";
$ivLength = openssl_cipher_iv_length($cipher);
$keyOfb = substr(hash('sha256',$secretKey,true),32);
$ivOfb = substr($keyOfb,$ivLength);
$encryptedOfb = openssl_encrypt($data,$cipher,$keyOfb,OPENSSL_RAW_DATA,$ivOfb);
echo "ofb-encrypted: " . base64_encode($ivOfb . $encryptedOfb);

加密的结果是MyFTCJx8RPzOx7h8QNxEtQgeiNIRwnrJ+uc0V70=

我尝试用 Java 编写这个函数,如下所示:

public static SecretKeySpec hashKey(String key){
        String keyPass = key;
        SecretKeySpec result = null;
        try{
                MessageDigest md = MessageDigest.getInstance("SHA-256");
                md.update(keyPass.getBytes());
                byte[] AesKeyData = Arrays.copyOfRange(md.digest(),32);
                SecretKeySpec keySpec = new SecretKeySpec(AesKeyData,"AES");
                result = keySpec;
                
        }
        catch (Exception e) {
            // Todo: handle exception
            e.printstacktrace();
        }
        return result;
    }

public static String encryptedOFB(String inp){
        String result = "";
        String key = "aNdRgUjXn2r5u8x/A?D(G+KbPeShVmYp";
        SecretKeySpec keyHashed = hashKey(key);
        try{
            byte[] initVectorSize = Arrays.copyOfRange(keyHashed.toString().getBytes(),16);
            Cipher cipher = Cipher.getInstance("AES/OFB/nopadding");
            
            IvParameterSpec iv = new IvParameterSpec(initVectorSize,cipher.getBlockSize());
            cipher.init(Cipher.ENCRYPT_MODE,keyHashed,iv);
            
            byte[] encrypted = cipher.doFinal(inp.getBytes());
            
            ByteArrayOutputStream conc = new ByteArrayOutputStream();
            conc.write(initVectorSize);
            conc.write(encrypted);
            byte[] concEnc = conc.toByteArray();

            result = new String(Base64.getEncoder().encode(concEnc));
            
        }
        catch (Exception e) {
            // Todo: handle exception
            e.printstacktrace();
        }
        return result;
    }

结果是amF2YXguY3J5cHRvLnNwZYUmrJNv8ycvLua0O9g=

为什么我的 java 函数返回的结果与 PHP 不同?

以及如何修复 java 函数以获得与 PHP 相同的结果?

谢谢。

解决方法

IV 确定错误。您必须使用 keyHashed.toString().getBytes() 而不是 keyHashed.getEncoded()。然后你就得到了 PHP 代码的结果。

除此之外,您的密钥派生是不安全的:由于 IV 是密钥的前 16 个字节,因此相同的密码也意味着相同的密钥/IV 对,这是不安全的。对于密码,最好结合使用可靠的密钥派生函数和随机生成的盐。 IV 可以与密钥一起推断或独立随机生成。 Salt(或 IV)不是秘密的,可以与密文一起传递以进行解密,通常是串联的。

编码时(例如inp.getBytes()),应始终指定编码(例如StandardCharsets.UTF_8)。与解码 (new String(...,StandardCharsets.UTF_8)) 类似。否则使用默认编码,会导致跨平台问题。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...