我使用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中编写类似的添加/删除填充代码。
请帮忙。
答案 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