使用 PHP mcrypt 加密,使用 Android 解密。这个解密对吗?
我这样做是正确的还是有错误?我仍在尝试实现的测试程序正在运行,没有任何异常或错误。但它没有做它必须做的事情,我找不到问题。
这是尝试解密的 Android 代码:
private static final int IO_BUFFER_SIZE = 4 * 1024;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try {
AssetManager am = this.getAssets();
InputStream is = am.open("2000_1.jpg_encrypted"); // get the encrypted image from assets folder
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] b = new byte[IO_BUFFER_SIZE];
int read;
while ((read = is.read(b)) != -1) { //convert inputstream to bytearrayoutputstream
baos.write(b, 0, read);
}
//START
long start = System.currentTimeMillis()/1000L; // start
//byte[] keyStart = "MARTIN_123_MARTIN_123".getBytes(); // specific key value
KeyGenerator kgen = KeyGenerator.getInstance("AES/CBC/PKCS5Padding"); //aes
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
//sr.setSeed(keyStart);
kgen.init(128, sr);
//SecretKey skey = kgen.generateKey();
//byte[] key = skey.getEncoded();
byte[] key = "MARTIN_123_MARTIN_123".getBytes("UTF-8");
byte[] iv = "1234567890123456".getBytes("UTF-8");
byte[] decryptedData = decrypt(key, iv, b);
//END
long end = System.currentTimeMillis()/1000L; // end
Log.d("TEST","Time start "+ String.valueOf(start)); //showing the strat in ms
Log.d("TEST","Time end "+ String.valueOf(end)); //showing the end in ms
Bitmap bitmap = BitmapFactory.decodeByteArray(decryptedData , 0, decryptedData .length); //decoding bytearrayoutputstream to bitmap
//String filepath = Environment.getExternalStorageDirectory()+"bitmap";
FileOutputStream fos = new FileOutputStream("sdcard/DCIM/100ANDRO");
fos.write(decryptedData);
fos.close();
is.close(); // close the inputstream
baos.close(); // close the bytearrayoutputstream
}
catch(Exception e){
e.fillInStackTrace();
}
}
//decrypt
private byte[] decrypt(byte[] raw, byte[] iv, byte[] encrypted) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivspec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivspec);
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}
这是加密的 PHP 代码:
$folder = $this->getConfiguration()->getAppRootDir() . '/temp_encryption_testing/';
$files = array(
'007FRAMESUPERIOR.jpg',
'2000_1.jpg',
'APLICACIONdescargaliga.jpg',
'APPCOMMENTS.pdf',
'AUDIOVISUALFOTO02.jpg'
);
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$key = "MARTIN_123_MARTIN_123";
foreach($files as $file)
{
$input_file = $folder . $file;
$text = file_get_contents($input_file);
//$text = "Meet me at 11 o'clock behind the monument.";
echo strlen($text) . "\n";
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_ECB, $iv);
echo strlen($crypttext) . "\n";
file_put_contents($input_file . '_encrypted', $crypttext);
}
如有任何帮助,我们将不胜感激:)
Am I doing it right or is there a mistake? The test program I'm still trying to implement is running without any exceptions or errors. But it's not doing the thing it has to do and I can't find the problem.
Here is the Android code that attempts to decrypt:
private static final int IO_BUFFER_SIZE = 4 * 1024;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try {
AssetManager am = this.getAssets();
InputStream is = am.open("2000_1.jpg_encrypted"); // get the encrypted image from assets folder
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] b = new byte[IO_BUFFER_SIZE];
int read;
while ((read = is.read(b)) != -1) { //convert inputstream to bytearrayoutputstream
baos.write(b, 0, read);
}
//START
long start = System.currentTimeMillis()/1000L; // start
//byte[] keyStart = "MARTIN_123_MARTIN_123".getBytes(); // specific key value
KeyGenerator kgen = KeyGenerator.getInstance("AES/CBC/PKCS5Padding"); //aes
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
//sr.setSeed(keyStart);
kgen.init(128, sr);
//SecretKey skey = kgen.generateKey();
//byte[] key = skey.getEncoded();
byte[] key = "MARTIN_123_MARTIN_123".getBytes("UTF-8");
byte[] iv = "1234567890123456".getBytes("UTF-8");
byte[] decryptedData = decrypt(key, iv, b);
//END
long end = System.currentTimeMillis()/1000L; // end
Log.d("TEST","Time start "+ String.valueOf(start)); //showing the strat in ms
Log.d("TEST","Time end "+ String.valueOf(end)); //showing the end in ms
Bitmap bitmap = BitmapFactory.decodeByteArray(decryptedData , 0, decryptedData .length); //decoding bytearrayoutputstream to bitmap
//String filepath = Environment.getExternalStorageDirectory()+"bitmap";
FileOutputStream fos = new FileOutputStream("sdcard/DCIM/100ANDRO");
fos.write(decryptedData);
fos.close();
is.close(); // close the inputstream
baos.close(); // close the bytearrayoutputstream
}
catch(Exception e){
e.fillInStackTrace();
}
}
//decrypt
private byte[] decrypt(byte[] raw, byte[] iv, byte[] encrypted) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivspec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivspec);
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}
Here is the PHP code that encrypts:
$folder = $this->getConfiguration()->getAppRootDir() . '/temp_encryption_testing/';
$files = array(
'007FRAMESUPERIOR.jpg',
'2000_1.jpg',
'APLICACIONdescargaliga.jpg',
'APPCOMMENTS.pdf',
'AUDIOVISUALFOTO02.jpg'
);
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$key = "MARTIN_123_MARTIN_123";
foreach($files as $file)
{
$input_file = $folder . $file;
$text = file_get_contents($input_file);
//$text = "Meet me at 11 o'clock behind the monument.";
echo strlen($text) . "\n";
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_ECB, $iv);
echo strlen($crypttext) . "\n";
file_put_contents($input_file . '_encrypted', $crypttext);
}
Any help will be appreciated :)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您正在尝试使用随机生成的密钥进行解密(将种子添加到
SecureRandom
仅补充随机状态)。那肯定会失败。如果“MARTIN_123_MARTIN_123”.getBytes() 是您的密钥(或者更确切地说:它的前 16 个字节),您应该将其直接传递给您的解密方法:
好的,根据您的评论,我可以看到您正在使用 AES-256/ECB/ZeroBytePadding 使用 PHP:mcrypt 进行加密(mcrypt 隐含零字节填充)。
首先:ECB 不是安全模式 - 特别是对于图像(尽管 JPG 可能没有 BMP 那么糟糕)。如果您决定更改为 CBC,请记住您需要通过将 IV, fx 添加到加密数据前面来传输它。但如果您想解密 CBC,则需要在
Cipher.getInstance()
调用中指明它(您当前使用AES/CBC/PKCS5Padding
)。除非您知道数据的长度,否则零字节填充实际上是不可移除的。因此,在加密数据之前,您必须传输长度或添加 PKCS#7 填充。
最后:使用 AES-256 进行加密。它使用 32 字节密钥。根据 mcrypt-documentation 如果密钥太,它会添加 \0s简短,因此您要么必须使用实际的 32 字节密钥,要么也将 \0 添加到 Android 端。
在 Android 端将代码更改为:
在 PHP 端:
You are trying to decrypt with a randomly generated key (adding a seed to a
SecureRandom
only supplements the random state). That is sure to fail.If
"MARTIN_123_MARTIN_123".getBytes()
is your key (or rather: the first 16 bytes of it), you should just pass that directly to your decrypt-method:Okay, from your comment, I can see that you are encrypting with PHP:mcrypt using AES-256/ECB/ZeroBytePadding (zero-byte padding is implicit with mcrypt).
First of all: ECB is not a safe mode - especially for images (though JPGs are probably not quite as bad as BMPs). If you decide to change to CBC, remember that you need to transmit the IV, f.x. by prepending it to the encrypted data. But if you want to decrypt CBC, you need to indicate it in your
Cipher.getInstance()
-call (you currently useAES/CBC/PKCS5Padding
).Zero-byte-padding is not really removable unless you know the length of the data. So you must either transmit the length or add PKCS#7 padding before encrypting the data.
Finally: you encrypt using AES-256. That uses a 32-byte key. According to the mcrypt-documentation it adds \0s if the key is too short, so you will either have to use an actual 32-byte key or add \0s to the Android-side, too.
Change your code to this on the Android side:
And on the PHP side: