使用自定义填充将Java Tripple DES代码转换为PHP代码

时间:2016-01-26 01:18:33

标签: java php

我使用JAVA使用DES算法解密/加密字符串。我有一个客户需要解密我的应用程序生成的安全字符串。消费者应用程序是用PHP构建的。我试图将我的Java代码转换为PHP代码,但由于我对PHP的理解有限而面临问题。 我面临着在PHP中创建自定义填充的问题,并且还意识到PHP" mcrypt_decrypt"方法来"数据"作为字符数组而不是Java中的字节数组。

以下是使用Java代码供参考。

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

public class JEncrytion
{   
    private static final char[] hexDigits = {
        '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
    };
       /**
     * Returns a string of hexadecimal digits from a byte array. Each
     * byte is converted to 2 hex symbols.
     * <p>
     * If offset and length are omitted, the whole array is used.
     */
    public static String toString(byte[] ba, int offset, int length) {
        char[] buf = new char[length * 2];
        int j = 0;
        int k;

        for (int i = offset; i < offset + length; i++) {
            k = ba[i];
            buf[j++] = hexDigits[(k >>> 4) & 0x0F];
            buf[j++] = hexDigits[ k        & 0x0F];
        }
        return new String(buf);
    }
    public static String toString(byte[] ba) {
        return toString(ba, 0, ba.length);
    }
      /**
     * Returns the number from 0 to 15 corresponding to the hex digit <i>ch</i>.
     */
    public static int fromDigit(char ch) {
        if (ch >= '0' && ch <= '9')
            return ch - '0';
        if (ch >= 'A' && ch <= 'F')
            return ch - 'A' + 10;
        if (ch >= 'a' && ch <= 'f')
            return ch - 'a' + 10;

        throw new IllegalArgumentException("invalid hex digit '" + ch + "'");
    }
    /**
     * Returns a byte array from a string of hexadecimal digits.
     */
    public static byte[] fromString(String hex) {
        int len = hex.length();
        byte[] buf = new byte[((len + 1) / 2)];

        int i = 0, j = 0;
        if ((len % 2) == 1)
            buf[j++] = (byte) fromDigit(hex.charAt(i++));

        while (i < len) {
            buf[j++] = (byte) ((fromDigit(hex.charAt(i++)) << 4) |
                                fromDigit(hex.charAt(i++)));
        }
        return buf;
    }
    //Add padding to make key 24 bytes length i.e. 192 bits length
    public static byte [] addPaddingToKey (byte [] keyBytes) {
        byte[] key;
        int keyLength = keyBytes.length;
        int paddingLenght = 24 - keyLength;
        if (paddingLenght != 0) {
            key = new byte[24];
            //copy original key
            System.arraycopy(keyBytes, 0, key, 0, keyLength);
            //Adding 0 as padding for remaining
            System.arraycopy(keyBytes, 0, key, keyLength, paddingLenght);
        } else {
            key = keyBytes;
        }
        return key;
    }
    //Add padding to input value to 
    public static byte[] addPadding(byte[] inData, int offset, int len) {

        byte[] bp = null;
        int padChars = 8;               // start with max padding value
        int partial = (len + 1) % padChars;     // calculate how many extra bytes exist
        if (partial == 0) padChars = 1;         // if none, set to only pad with length byte
        else padChars = padChars - partial + 1; // calculate padding size to include length

        bp = new byte[len + padChars];
        bp[0] = Byte.parseByte(Integer.toString(padChars));
        System.arraycopy(inData, offset, bp, 1, len);
        return bp;
    }
    //remove padding added while decryption
     public static byte[] removePadding(byte[] inData) {

            byte[] bp = null;
            int dataLength = 0;
            int padLength = 0;
            padLength = inData[0];
            dataLength = inData.length - padLength;
            bp = new byte[dataLength];
            System.arraycopy(inData, 1, bp, 0, dataLength);      
            return bp;
      } 
     //Get SecretKey object 
    public static SecretKey getSecretKey(String secretString) {
            SecretKey myDesKey = null;
            try {
                //get bytes from key
                byte [] keyBytes = secretString.getBytes();
                //add padding to key to meet 24 bytes requirement
                byte [] bytes = addPaddingToKey(keyBytes);
                //Generate DES key 
                myDesKey = new SecretKeySpec(bytes,"DESede" );

            }catch (Exception e) {
                e.printStackTrace();    
            }
            return myDesKey;
    }
     //encrypt data
     public static byte[] encrypt(byte[] text, String secretString) {
         byte[] textEncrypted = null;
            try {
                 //Generate DES key 
                SecretKey myDesKey = getSecretKey(secretString);

                Cipher desCipher;
                // Create the cipher  for DES-EDE3
                desCipher = Cipher.getInstance("DESede/ECB/NoPadding");

                // Initialize the cipher for encryption
                desCipher.init(Cipher.ENCRYPT_MODE, myDesKey);

                //Add padding to make it multiple of 8
                text  = addPadding (text, 0 , text.length);

                // encrypt the text
                textEncrypted = desCipher.doFinal(text);

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

            return textEncrypted;

          } 
     //Decrypt given encrypted bytes
    public static byte[] decrypt (byte [] textEncrypted, String secretString){
        byte[] textDecrypted = null;
        try {            
            //Generate DES key 
            SecretKey myDesKey = getSecretKey(secretString);

            Cipher desCipher;
            // Create the cipher  for DES-EDE3
            desCipher = Cipher.getInstance("DESede/ECB/NoPadding");


            // Initialize the same cipher for decryption
            desCipher.init(Cipher.DECRYPT_MODE, myDesKey);

            // Decrypt the text
            textDecrypted = desCipher.doFinal(textEncrypted);

            //remove padding which was added during encryption
            textDecrypted  = removePadding (textDecrypted);

        }catch (Exception e) {
            e.printStackTrace();    
        }
        return textDecrypted;
    } 
    public static void main(String[] argv) {        
        try{
            String secretString = "hg34sdfg4ertertr";
            String plainTextString = "{\"name\":\"Test\"}";
            byte[] plainText = plainTextString.getBytes();
            //Encrypt given plain text
            byte [] encryptedText = encrypt(plainText, secretString);
            //Convert into hex

            String hexStr = toString(encryptedText);
            System.out.println("Encrypted String "+hexStr);        
            byte [] decryptedText = decrypt(encryptedText, secretString);
            System.out.println(" decrypted string "+new String (decryptedText));

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

    }
}

以下是我在Google搜索中尝试的PHP代码,并使用http://phpfiddle.org进行了测试:

<?php
function byteStr2byteArray($s) {
    return array_slice(unpack("C*", "\0".$s), 1);
}

function Encrypt($data, $secret)
{    
  //Generate a key from a hash
  $key = md5(utf8_encode($secret), true);

  //Take first 8 bytes of $key and append them to the end of $key.
  $key .= substr($key, 0, 8);
  //Pad to make multiple of 8 bytes
  $blockSize = 8;
  $len = strlen($data);
  $pad = $blockSize - ($len % $blockSize);
  $data .= str_repeat(chr(0), $pad);

  //Encrypt data
  $encData = mcrypt_encrypt('tripledes', $key, $data, 'ecb');

  //return base64_encode($encData);
return bin2hex($encData);
}

function Decrypt($data, $secret)
{

    //Generate a key from a hash
    $key = md5(utf8_encode($secret), true);

    //Take first 8 bytes of $key and append them to the end of $key.
    $key .= substr($key, 0, 8);

    //$data = base64_decode($data);
    $data = hex2bin($data);
    $data = mcrypt_decrypt('tripledes', $key, $data, 'ecb');

    $block = 8;
    $len = strlen($data);
    $pad = ord($data[$len-1]);

    return substr($data, 0, strlen($data) - $pad);
}

$secretKey = 'hg34sdfg4ertertr';
$json = "{\"name\":\"Test\"}";
$textToEncrypt = json_encode($json);
$encrypted = Encrypt($textToEncrypt, $secretKey);
echo strtoupper($encrypted);

/*Line break*/
echo "<br />";
/*Decryption*/
$textToDecrypt = $encrypted;
$decrypted = Decrypt($textToDecrypt, $secretKey);
echo $decrypted;

?>

然而,PHP代码中的加密字符串与Java代码不同。以下是生成的加密字符串

的示例
Plain Text: {"name":"Test"}
PHP: 30AEE71A51DA55050F524356878EAF79522643B97EAF4C07 
Java: 27A211EE2B2032BA1F83D20AE920903F

我理解为什么它不一样,因为我无法在PHP中编写类似的添加/删除填充代码。

请帮忙。

1 个答案:

答案 0 :(得分:0)

在我浏览this帖子之后,我获得了PHP填充逻辑的基础知识,然后我改变了JAVA和PHP代码,如下所示,然后就可以了。

Java代码:

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

public class PHPEncryption
{   
    private static final char[] hexDigits = {
        '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
    };
       /**
     * Returns a string of hexadecimal digits from a byte array. Each
     * byte is converted to 2 hex symbols.
     * <p>
     * If offset and length are omitted, the whole array is used.
     */
    public static String toString(byte[] ba, int offset, int length) {
        char[] buf = new char[length * 2];
        int j = 0;
        int k;

        for (int i = offset; i < offset + length; i++) {
            k = ba[i];
            buf[j++] = hexDigits[(k >>> 4) & 0x0F];
            buf[j++] = hexDigits[ k        & 0x0F];
        }
        return new String(buf);
    }
    public static String toString(byte[] ba) {
        return toString(ba, 0, ba.length);
    }
      /**
     * Returns the number from 0 to 15 corresponding to the hex digit <i>ch</i>.
     */
    public static int fromDigit(char ch) {
        if (ch >= '0' && ch <= '9')
            return ch - '0';
        if (ch >= 'A' && ch <= 'F')
            return ch - 'A' + 10;
        if (ch >= 'a' && ch <= 'f')
            return ch - 'a' + 10;

        throw new IllegalArgumentException("invalid hex digit '" + ch + "'");
    }
    /**
     * Returns a byte array from a string of hexadecimal digits.
     */
    public static byte[] fromString(String hex) {
        int len = hex.length();
        byte[] buf = new byte[((len + 1) / 2)];

        int i = 0, j = 0;
        if ((len % 2) == 1)
            buf[j++] = (byte) fromDigit(hex.charAt(i++));

        while (i < len) {
            buf[j++] = (byte) ((fromDigit(hex.charAt(i++)) << 4) |
                                fromDigit(hex.charAt(i++)));
        }
        return buf;
    }

    //Add padding to input value to 
    public static byte[] addPadding(byte[] inData, int offset, int len) {

        byte[] bp = null;
        int padChars = 8;               // start with max padding value
        int partial = (len + 1) % padChars;     // calculate how many extra bytes exist
        if (partial == 0) padChars = 1;         // if none, set to only pad with length byte
        else padChars = padChars - partial + 1; // calculate padding size to include length

        bp = new byte[len + padChars];
        //bp[0] = Byte.parseByte(Integer.toString(padChars));
        System.arraycopy(inData, offset, bp, 0, len);
        return bp;
    }
    //remove padding added while decryption
     public static byte[] removePadding(byte[] inData) {

            byte[] bp = null;
            int dataLength = 0;
            int padLength = 0;
            //loop in to find out pad lenght
            for(int i=inData.length -1 ; i > -1  ; i--) {
                byte currentData = inData[i];
                if(i != inData.length -1) {
                    //check for current and previous data and both must be 0
                    byte previousData = inData[i+1];
                    if(previousData == currentData && currentData == 0) {
                        padLength++;
                    } else {
                        //break the loop
                        break;
                    }
                } else {
                    //if last data is null then increase the pad length
                    if(currentData == 0) {
                        padLength++;
                    }
                }
            }
            dataLength = inData.length - padLength;
            bp = new byte[dataLength];
            System.arraycopy(inData, 0, bp, 0, dataLength);      
            return bp;
      } 
     //Get SecretKey object 
    public static SecretKey getSecretKey(String secretString) {
            SecretKey myDesKey = null;
            try {
                //get bytes from key
                byte [] keyBytes = secretString.getBytes();

                //Generate DES key 
                myDesKey = new SecretKeySpec(keyBytes,"DESede" );

            }catch (Exception e) {
                e.printStackTrace();    
            }
            return myDesKey;
    }
     //encrypt data
     public static byte[] encrypt(byte[] text, String secretString) {
         byte[] textEncrypted = null;
            try {
                 //Generate DES key 
                SecretKey myDesKey = getSecretKey(secretString);

                Cipher desCipher;
                // Create the cipher  for DES-EDE3
                desCipher = Cipher.getInstance("DESede/ECB/NoPadding");

                // Initialize the cipher for encryption
                desCipher.init(Cipher.ENCRYPT_MODE, myDesKey);

                //Add padding to make it multiple of 8
                text  = addPadding (text, 0 , text.length);

                // encrypt the text
                textEncrypted = desCipher.doFinal(text);

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

            return textEncrypted;

          } 
     //Decrypt given encrypted bytes
    public static byte[] decrypt (byte [] textEncrypted, String secretString){
        byte[] textDecrypted = null;
        try {            
            //Generate DES key 
            SecretKey myDesKey = getSecretKey(secretString);

            Cipher desCipher;
            // Create the cipher  for DES-EDE3
            desCipher = Cipher.getInstance("DESede/ECB/NoPadding");


            // Initialize the same cipher for decryption
            desCipher.init(Cipher.DECRYPT_MODE, myDesKey);

            // Decrypt the text
            textDecrypted = desCipher.doFinal(textEncrypted);

            //remove padding which was added during encryption
            textDecrypted  = removePadding (textDecrypted);

        }catch (Exception e) {
            e.printStackTrace();    
        }
        return textDecrypted;
    } 
    public static void main(String[] argv) {        
        try{
            String secretString = "1234567890qwertyuiopasdf"; //key must be 24 chars
            String plainTextString = "Hello World";
            byte[] plainText = plainTextString.getBytes();
            //Encrypt given plain text
            byte [] encryptedText = encrypt(plainText, secretString);
            //Convert into hex

            String hexStr = toString(encryptedText);
            System.out.println("Encrypted String "+hexStr);        
            byte [] decryptedText = decrypt(encryptedText, secretString);
            System.out.println("Decrypted string "+new String (decryptedText));

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

    }
}

PHP代码:

<?php
function Encrypt($data, $secret) {    
  // get the amount of bytes to pad
    $extra = 8 - (strlen($data) % 8);
    // add the zero padding
    if($extra > 0) {
        for($i = 0; $i < $extra; $i++) {
            $data .= "\0";
        }
    } 
  //Encrypt data
  $encData = mcrypt_encrypt('tripledes',$secret, $data, 'ecb');
  //return hex format
  return bin2hex($encData);
}

function Decrypt($data, $secret) {
    $data = hex2bin($data);
    $data = mcrypt_decrypt('tripledes', $secret, $data, 'ecb');
    return $data;
}

$secretKey = '1234567890qwertyuiopasdf'; //key must be 24 chars

$textToEncrypt = "Hello World";

$encrypted = Encrypt($textToEncrypt, $secretKey);
echo strtoupper($encrypted);

/*Line break*/
echo "<br />";
/*Decryption*/
$textToDecrypt = $encrypted;
$decrypted = Decrypt($textToDecrypt, $secretKey);
echo $decrypted;

?>

现在两者都在进行相同的加密和解密。以下是样本输出 爪哇:

Encrypted String 753DE4F18233AD9BCD8CA71D3E501EEF
Decrypted string Hello World

PHP:

753DE4F18233AD9BCD8CA71D3E501EEF
Hello World