php des加密用java解析不了 改個模式 加個IV php金鑰/IV要求都是8位

oktokeep發表於2024-06-08

php des加密用java解析不了 改個模式 加個IV php金鑰/IV要求都是8位

php des加密用java解析不了 Wrong IV length: must be 8 bytes long
PHP的DES加密和Java解密不相容的問題通常是因為PHP預設使用ECB模式,而Java可能預設使用其他模式如CBC,或者使用不同的padding方式。

解決方法:
確保PHP和Java使用相同的加密模式(如CBC)和padding方式(如PKCS5Padding或NoPadding)。
確保兩邊使用相同的金鑰和初始化向量(IV)。

以下是PHP和Java分別使用CBC模式和PKCS5Padding的示例程式碼:
PHP:

<?php
$key = '12345678'; // 金鑰
$iv = '12345678';  // 初始化向量
$data = 'Data to encrypt';
 
$td = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_CBC, '');
mcrypt_generic_init($td, $key, $iv);
 
$encrypted = mcrypt_generic($td, $data);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
 
echo base64_encode($encrypted);
?>

JAVA:

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
 
public class Main {
    public static void main(String[] args) throws Exception {
        String key = "12345678"; // 金鑰
        String iv = "12345678";  // 初始化向量
        String data = "Data to encrypt";
 
        Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "DES");
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes());
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
 
        byte[] encrypted = cipher.doFinal(data.getBytes());
        System.out.println(Base64.getEncoder().encodeToString(encrypted));
    }
}
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
 
public class Main {
    public static void main(String[] args) throws Exception {
        String key = "12345678"; // 金鑰
        String iv = "12345678";  // 初始化向量
        String data = "Data to encrypt";
 
        Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "DES");
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes());
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
 
        byte[] encrypted = cipher.doFinal(data.getBytes());
        System.out.println(Base64.getEncoder().encodeToString(encrypted));
    }
}

在這兩個示例中,我們都使用了CBC模式和PKCS5Padding,並且金鑰和初始化向量都是固定的字串。在實際應用中,你需要確保金鑰和向量的安全性,並且在解密時使用相同的引數。

連結:des加密,url編碼,url解碼,des解密 DES加解密及Wrong key size錯誤處理
https://www.cnblogs.com/oktokeep/p/17917821.html

工具類DEMO:

package com.example.core.mydemo.des;

import com.example.core.mydemo.MD5;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;

/**
 * output:原始字串 = {"phone":"1391111","username":"張三"}
 * des加密 = LHFFScjfDE1kEyz27Y4ffRb0aM98qONoW8HGHzqjCqBqX9fwlPb28w==
 * url編碼 = LHFFScjfDE1kEyz27Y4ffRb0aM98qONoW8HGHzqjCqBqX9fwlPb28w%3D%3D
 * url解碼 = LHFFScjfDE1kEyz27Y4ffRb0aM98qONoW8HGHzqjCqBqX9fwlPb28w==
 * 不相同
 * des解密 = {"phone":"1391111","username":"張三"}
 */
public class CbcIvDesUtls {
    private static String CHARSETNAME="UTF-8";

    static String iv = "12345678";  // 初始化向量

    /**
     * DES加解密及Wrong key size錯誤處理
     * @param key
     * @return
     * @throws UnsupportedEncodingException
     */
    private static byte[] getKeyBytes(String key) throws UnsupportedEncodingException {
        byte[] keyBytes = key.getBytes(CHARSETNAME);
        if (keyBytes.length < 8) {
            byte[] bytes = new byte[8];
            System.arraycopy(keyBytes, 0, bytes, 0, keyBytes.length);
            keyBytes = bytes;
        }
        return keyBytes;
    }

    public static String getDESStr(String str, String encryptKey, String type, String charset) throws Exception {
        Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        SecretKeySpec secretKeySpec = new SecretKeySpec(encryptKey.getBytes(), "DES");
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes());
        //加密
        if ("ENCRYPT".equals(type)) {
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
            return Base64Encoder.encode(cipher.doFinal(str.getBytes(charset)));
        }else if ("DECRYPT".equals(type)) {
            byte[] encodeByte = Base64Encoder.decode(str.getBytes());
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
            byte[] decoder = cipher.doFinal(encodeByte);
            return new String(decoder, charset);
        }
        return "type error";
    }

    public static void main(String[] args) {
        //java.security.InvalidKeyException: Wrong key size
        //金鑰要求是8位
        String encryptKey = "abcdefgh";

        String type = "ENCRYPT";
        String charset = "UTF-8";

        String str = "{\"phone\":\"1391111\",\"username\":\"張三\"}";

        System.out.println("原始字串 = " + str);
        try {
            //des加密
            String DESStr= getDESStr(str,encryptKey,type,charset);
            System.out.println("des加密 = " + DESStr);
//            url編碼
            DESStr = URLEncoder.encode(DESStr,"UTF-8");
            System.out.println("url編碼 = " + DESStr);

            //url解碼
            String s = URLDecoder.decode(DESStr,"UTF-8");
            System.out.println("url解碼 = " + s);

            //javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher
            /**
             * 報錯原因是因為:解密字串不是url解碼後的,所以會報該錯誤。
             */
//            System.out.println("des解密2 = " + getDESStr(DESStr,encryptKey,"DECRYPT","UTF-8"));

            //des解密
            if(DESStr.equals(s)){
                System.out.println("相同");
            }else{
                System.out.println("不相同");
            }
            System.out.println("des解密 = " + getDESStr(s,encryptKey,"DECRYPT","UTF-8"));

            //ENCRYPT(des加密)  encode(url編碼)  >> decode(url解碼)  encrypt(des解密)

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
package com.example.core.mydemo.des;

import com.example.core.mydemo.MD5;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;

/**
 * output:原始字串 = {"phone":"1391111","username":"張三"}
 * des加密 = LHFFScjfDE1kEyz27Y4ffRb0aM98qONoW8HGHzqjCqBqX9fwlPb28w==
 * url編碼 = LHFFScjfDE1kEyz27Y4ffRb0aM98qONoW8HGHzqjCqBqX9fwlPb28w%3D%3D
 * url解碼 = LHFFScjfDE1kEyz27Y4ffRb0aM98qONoW8HGHzqjCqBqX9fwlPb28w==
 * 不相同
 * des解密 = {"phone":"1391111","username":"張三"}
 */
public class CbcIvDesUtls {
    private static String CHARSETNAME="UTF-8";

    static String iv = "12345678";  // 初始化向量

    /**
     * DES加解密及Wrong key size錯誤處理
     * @param key
     * @return
     * @throws UnsupportedEncodingException
     */
    private static byte[] getKeyBytes(String key) throws UnsupportedEncodingException {
        byte[] keyBytes = key.getBytes(CHARSETNAME);
        if (keyBytes.length < 8) {
            byte[] bytes = new byte[8];
            System.arraycopy(keyBytes, 0, bytes, 0, keyBytes.length);
            keyBytes = bytes;
        }
        return keyBytes;
    }

    public static String getDESStr(String str, String encryptKey, String type, String charset) throws Exception {
        Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        SecretKeySpec secretKeySpec = new SecretKeySpec(encryptKey.getBytes(), "DES");
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes());
        //加密
        if ("ENCRYPT".equals(type)) {
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
            return Base64Encoder.encode(cipher.doFinal(str.getBytes(charset)));
        }else if ("DECRYPT".equals(type)) {
            byte[] encodeByte = Base64Encoder.decode(str.getBytes());
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
            byte[] decoder = cipher.doFinal(encodeByte);
            return new String(decoder, charset);
        }
        return "type error";
    }

    public static void main(String[] args) {
        //java.security.InvalidKeyException: Wrong key size
        //金鑰要求是8位
        String encryptKey = "abcdefgh";

        String type = "ENCRYPT";
        String charset = "UTF-8";

        String str = "{\"phone\":\"1391111\",\"username\":\"張三\"}";

        System.out.println("原始字串 = " + str);
        try {
            //des加密
            String DESStr= getDESStr(str,encryptKey,type,charset);
            System.out.println("des加密 = " + DESStr);
//            url編碼
            DESStr = URLEncoder.encode(DESStr,"UTF-8");
            System.out.println("url編碼 = " + DESStr);

            //url解碼
            String s = URLDecoder.decode(DESStr,"UTF-8");
            System.out.println("url解碼 = " + s);

            //javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher
            /**
             * 報錯原因是因為:解密字串不是url解碼後的,所以會報該錯誤。
             */
//            System.out.println("des解密2 = " + getDESStr(DESStr,encryptKey,"DECRYPT","UTF-8"));

            //des解密
            if(DESStr.equals(s)){
                System.out.println("相同");
            }else{
                System.out.println("不相同");
            }
            System.out.println("des解密 = " + getDESStr(s,encryptKey,"DECRYPT","UTF-8"));

            //ENCRYPT(des加密)  encode(url編碼)  >> decode(url解碼)  encrypt(des解密)

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

工具類DEMO簡化版本:

package com.example.core.mydemo.des;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public class IvDesTest {
    public static void main(String[] args) throws Exception{
        String key = "12345678"; // 金鑰8位
        String iv = "12345678";  // 初始化向量  Wrong IV length: must be 8 bytes long
        String data = "Data to encrypt";

        Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "DES");
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes());
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);

        //加密
        byte[] encrypted = cipher.doFinal(data.getBytes());
        String encryptStr = Base64.getEncoder().encodeToString(encrypted);
        System.out.println("encryptStr=" + encryptStr);

        //解密
        byte[] encodeByte = Base64Encoder.decode(encryptStr.getBytes());
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
        byte[] decoder = cipher.doFinal(encodeByte);
        String decryptStr =  new String(decoder);
        System.out.println("decryptStr=" + decryptStr);
    }
}
package com.example.core.mydemo.des;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public class IvDesTest {
    public static void main(String[] args) throws Exception{
        String key = "12345678"; // 金鑰8位
        String iv = "12345678";  // 初始化向量  Wrong IV length: must be 8 bytes long
        String data = "Data to encrypt";

        Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "DES");
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes());
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);

        //加密
        byte[] encrypted = cipher.doFinal(data.getBytes());
        String encryptStr = Base64.getEncoder().encodeToString(encrypted);
        System.out.println("encryptStr=" + encryptStr);

        //解密
        byte[] encodeByte = Base64Encoder.decode(encryptStr.getBytes());
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
        byte[] decoder = cipher.doFinal(encodeByte);
        String decryptStr =  new String(decoder);
        System.out.println("decryptStr=" + decryptStr);
    }
}

相關文章