pbkdf2withhmacsha512用于aes加密的php java等效程序

9ceoxa92  于 2021-07-08  发布在  Java
关注(0)|答案(1)|浏览(426)

我正在尝试用openssl在php中使用pbkdf2withhmacsha512。但我不能创建与java创建的加密字符串相同的字符串。我试图加密的数据是atom insta pay。在下面提到的java代码中,我得到的是vnegn6vndj3z4wj4u3+z1g==但是在php中得到的是jquby9xcf+g9yasdnkq7cq==这是完全不同的。

// Java code
    import java.util.logging.Logger;
    import javax.crypto.Cipher;
    import javax.crypto.SecretKey;
    import javax.crypto.SecretKeyFactory;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.PBEKeySpec;
    import javax.crypto.spec.SecretKeySpec;

    public class myEncryption {
        static Logger log = Logger.getLogger(myEncryption.class.getName());
        private static int pswdIterations = 65536;
        private static int keySize = 256;
        private static final byte[] ivBytes = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };

        public static String encrypt(String plainText, String key) {
            try {
                byte[] saltBytes = key.getBytes("UTF-8");
                SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
                PBEKeySpec spec = new PBEKeySpec(key.toCharArray(), saltBytes, pswdIterations, keySize);

                SecretKey secretKey = factory.generateSecret(spec);     
                SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");  

                IvParameterSpec localIvParameterSpec = new IvParameterSpec(ivBytes);
                Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                cipher.init(1, secret, localIvParameterSpec);

                byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes("UTF-8"));

                return byteToHex(encryptedTextBytes);

             }catch (Exception e) {
                log.info("Exception while encrypting data:" + e.toString());
            }

            return null;
        }

        public static String decrypt(String encryptedText, String key) {

            try {

                byte[] saltBytes = key.getBytes("UTF-8");
                byte[] encryptedTextBytes = hex2ByteArray(encryptedText);

                SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
                PBEKeySpec spec = new PBEKeySpec(key.toCharArray(), saltBytes, pswdIterations, keySize);

                SecretKey secretKey = factory.generateSecret(spec);
                SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");

                IvParameterSpec localIvParameterSpec = new IvParameterSpec(ivBytes);
                Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                cipher.init(2, secret, localIvParameterSpec);

                byte[] decryptedTextBytes = (byte[]) null;
                decryptedTextBytes = cipher.doFinal(encryptedTextBytes);

                return new String(decryptedTextBytes);

            }catch (Exception e) {
                log.info("Exception while decrypting data:" + e.toString());
            }

            return null;
        }

        private static String byteToHex(byte[] byData) {
            StringBuffer sb = new StringBuffer(byData.length * 2);

            for (int i = 0; i < byData.length; ++i) {
                int v = byData[i] & 0xFF;
                if (v < 16)
                    sb.append('0');
                sb.append(Integer.toHexString(v));
            }

            return sb.toString().toUpperCase();
        }

        private static byte[] hex2ByteArray(String sHexData) {
            byte[] rawData = new byte[sHexData.length() / 2];
            for (int i = 0; i < rawData.length; ++i) {
                int index = i * 2;
                int v = Integer.parseInt(sHexData.substring(index, index + 2), 16);
                rawData[i] = (byte) v;
            }

            return rawData;
        }
    }

//PHP code
$method = "AES-256-CBC";
$salt = 'A4476C2062FFA58980DC8F79EB6A799E';
$key = 'A4476C2062FFA58980DC8F79EB6A799E';
$data = 'Demo String';

//Converting Array to bytes
$iv = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
$chars = array_map("chr", $iv);
$IVbytes = join($chars);

$salt1 = mb_convert_encoding($salt, "UTF-8"); //Encoding to UTF-8
$key1 = mb_convert_encoding($key, "UTF-8"); //Encoding to UTF-8

//SecretKeyFactory Instance of PBKDF2WithHmacSHA512 Java Equivalent
$hash = openssl_pbkdf2($key1,$salt1,'256','65536', 'sha512'); 

$encrypted = openssl_encrypt($data, $method, $hash, OPENSSL_RAW_DATA, $IVbytes);

echo base64_encode($encrypted);
cczfrluj

cczfrluj1#

php解决方案比java端更“简单”,可以使用key和salt作为直接输入(无需转换它们)。
当您想比较base64编码的密文时,示例代码返回base64编码的密文,而不是java程序发出的十六进制字符串。
这是具有相同结果的输出:

expected:  JQubY9xCf+g9yASdNkq7cQ==
encrypted: JQubY9xCf+g9yASdNkq7cQ==

安全警告:您的代码使用的是静态salt和iv,这使得加密不安全(我希望这只是为了演示)。
代码如下:

<?php
//PHP code
$method = "AES-256-CBC";
$salt = 'A4476C2062FFA58980DC8F79EB6A799E';
$key =  'A4476C2062FFA58980DC8F79EB6A799E';
$data = 'Atom Insta Pay';

//Converting Array to bytes
$iv = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
$chars = array_map("chr", $iv);
$IVbytes = join($chars);

$hash = openssl_pbkdf2($key,$salt,32,65536, 'sha512');
$encrypted = openssl_encrypt($data, $method, $hash, OPENSSL_RAW_DATA, $IVbytes);
echo 'expected:  JQubY9xCf+g9yASdNkq7cQ==' . PHP_EOL;
echo 'encrypted: ' . base64_encode($encrypted);
?>

相关问题