如果您不是簡單地吞下encrypt()
例程中可能的Exception
s,那麼您會更好地瞭解發生了什麼。如果你的函數返回null
那麼很明顯發生異常,你需要知道它是什麼。
事實上,例外的是:
javax.crypto.IllegalBlockSizeException: Input length not multiple of 16 bytes
at com.sun.crypto.provider.CipherCore.finalNoPadding(CipherCore.java:854)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:828)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:313)
at javax.crypto.Cipher.doFinal(Cipher.java:2087)
at Encryption.encrypt(Encryption.java:20)
at Encryption.main(Encryption.java:6)
果然,你的明文只有11的Java字符長,這在你的默認編碼,將是11個字節。
您需要檢查PHP mcrypt_encrypt
函數的實際功能。由於它的工作原理,它顯然使用了一些填充方案。你需要找出它是哪一個,並在你的Java代碼中使用它。
好的 - 我擡頭看mcrypt_encrypt
的手冊頁。它說:
將用給定的密碼和模式加密的數據。如果數據的大小不是n * blocksize
,則數據將填充\0
。
所以你需要在Java中進行復制。這裏有一種方法:
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class Encryption
{
public static void main(String args[]) throws Exception {
System.out.println(encrypt());
}
public static String encrypt() throws Exception {
try {
String data = "Test string";
String key = "1234567812345678";
String iv = "1234567812345678";
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
int blockSize = cipher.getBlockSize();
// We need to pad with zeros to a multiple of the cipher block size,
// so first figure out what the size of the plaintext needs to be.
byte[] dataBytes = data.getBytes();
int plaintextLength = dataBytes.length;
int remainder = plaintextLength % blockSize;
if (remainder != 0) {
plaintextLength += (blockSize - remainder);
}
// In java, primitive arrays of integer types have all elements
// initialized to zero, so no need to explicitly zero any part of
// the array.
byte[] plaintext = new byte[plaintextLength];
// Copy our actual data into the beginning of the array. The
// rest of the array is implicitly zero-filled, as desired.
System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
byte[] encrypted = cipher.doFinal(plaintext);
return new sun.misc.BASE64Encoder().encode(encrypted);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
當我跑,我得到:
iz1qFlQJfs6Ycp+gcc2z4w==
這是你的PHP程序得到了什麼。
更新(2016 6月12日): 從Java 8中,最後的JavaSE附帶有記載的base64編碼解碼器。因此,而不是
return new sun.misc.BASE64Encoder().encode(encrypted);
,你應該這樣做
return Base64.Encoder.encodeToString(encrypted);
另外,使用base64編碼/解碼第三方庫(如commons-codec
)而不是使用無證內部方法。
非常感謝QuantumMechanic。很好解釋。 – user812120
請注意,通常不使用基於零的填充,因爲您無法區分數據末尾的零值字節和填充。您應該使用PKCS#7填充(Java中的「PKCS5Padding」)。另請注意,使用sun。*功能不符合所有Java兼容性準則。 –