我正在开发一个Android项目,我必须从PHP服务器中的文件解密字符串,使用PHP完成加密。(AES 128算法)
加密代码:
function aes128Encrypt($key, $data) {
$key = md5($key);
return mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, str_repeat("\0", 16));
}
我从URL获取字符串的代码:
String myUri = "http://www.example.com/lib2.php";
HttpClient httpClient = new DefaultHttpClient();
HttpGet get = new HttpGet(myUri);
HttpResponse response = httpClient.execute(get);
String bodyHtml = "";
String xmlFile = "";
bodyHtml = EntityUtils.toString(response.getEntity());
System.out.println(bodyHtml);
xmlFile = decrypt(bodyHtml);
System.out.println(xmlFile);
decrypt()方法:
public static String decrypt(String encData) throws Exception
{
Key key = generateKey();
Cipher c = Cipher.getInstance(algo + "/CBC/PKCS7Padding");
//Cipher c = Cipher.getInstance(algo);
IvParameterSpec ivSpec = new IvParameterSpec(ivbytes);
c.init(Cipher.DECRYPT_MODE, key , ivSpec);
//byte[] decValue = Base64.decode(encData , Base64.NO_PADDING);
//byte[] decFin = Base64.decode(decValue, Base64.NO_PADDING);
//byte[] decFinal = c.doFinal(decValue);
byte[] decFinal = c.doFinal(encData.getBytes());
String getAns = new String(decFinal, "UTF8");
return getAns;
}
在generateKey()中:
public static Key generateKey()
{
try {
MessageDigest digest = java.security.MessageDigest
.getInstance("MD5");
digest.update(myChar.getBytes());
key1 = digest.digest();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
Key key = new SecretKeySpec(key1,algo);
return key;
}
}
Logcat显示以下异常:
javax.crypto.IllegalBlockSizeException: last block incomplete in decryption
在第c.doFinal()
行
我注释掉的代码也是我用来检查的代码。这段代码有什么问题?任何帮助将不胜感激。
答案 0 :(得分:2)
你的狙击手期待填充“/ CBC / PKCS7Padding”。这与消息编码无关(BASE64)。要么在java端更改预期的chipher,要么在php端使用padding进行加密。
指定Chipers algorithm/mode/padding
或algortihm
,有关详细信息,请参阅http://docs.oracle.com/javase/7/docs/api/javax/crypto/Cipher.html。
您正在指定带填充的chiper但实际上在php端执行零填充,
摘自http://www.php.net/manual/de/function.mcrypt-encrypt.php:
# creates a cipher text compatible with AES (Rijndael block size = 128)
# to keep the text confidential
# only suitable for encoded input that never ends with value 00h
# (because of default zero padding)
$ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key,
$plaintext, MCRYPT_MODE_CBC, $iv);
答案 1 :(得分:1)
问题可能是您将PHP服务器中的值视为Java String
的方式。 PHP mcrypt_encrypt
函数返回二进制字符串,其中每个字节可以包含任何值。 PHP mcrypt_encrypt
不使用任何字符编码。因此,使用EntityUtils.toString()
已经是一个错误 - 使用String.getBytes()
而不指定编码通常也是如此。
您只需使用getContent()
或writeTo(OutputStream outstream)
来获取二进制密文。如果您选择第一个选项,则可以在其周围包裹CipherInputStream
。使用"AES/CBC/NoPadding"
密码对其进行初始化,您可以直接解密纯文本字符串。请注意,您可能必须从结果中修剪一定数量的00
值字节才能获得明文。
答案 2 :(得分:0)
我通过避免重用密码来解决我的问题。每次我再次启动它。刚刚开始就足够了。
try {
SecretKeyFactory factory = SecretKeyFactory
.getInstance(SECRET_KEY_ALGORITHM);
KeySpec spec = new PBEKeySpec(ps, salt, ITERATIONS, KEY_LENGTH);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), ALGORITHM);
// Build encryptor and get IV
ecipher = Cipher.getInstance(TRANSFORMATION);
ecipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(iv));
// Build decryptor
dcipher = Cipher.getInstance(TRANSFORMATION);
dcipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
} catch (Exception e) {
e.printStackTrace();
}