Мне нужно зашифровать файл с помощью AES-128 в PHP и расшифровать его на Android.
Я использую следующий код. Я успешно зашифровал и расшифровал его с помощью PHP-кода, но мне нужно расшифровать его с помощью Android из моего приложения.
PHP-код:
$key= "asdfghjklzxccvbn";
$in_filename = $_FILES["fileToUpload"]["tmp_name"];
$aes_filename =$target_dir."encry_".$_FILES["fileToUpload"]["name"];
$decry_filename =$target_dir."decry_".$_FILES["fileToUpload"]["name"];
//encrypt file
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = '1234567890123456';
$fin = fopen($in_filename, "rb");
$fcrypt = fopen($aes_filename, 'wb');
fwrite($fcrypt, $iv);
$opts = array('iv'=>$iv, 'key'=>$key, 'mode'=>'cbc');
stream_filter_append($fcrypt, 'mcrypt.rijndael-128', STREAM_FILTER_WRITE, $opts);
while (!feof($fin))
{
fwrite($fcrypt, fread($fin, 8192));
}
fclose($fcrypt);
fclose($fin);
Мой Android-код для дешифрования зашифрованного файла:
// encripted file stored in android device for decrypt
String uri= Environment.getExternalStorageDirectory().toString();
uri=uri+"/encry_file.mp4";
File file = new File(uri.toString());
FileInputStream fis = new FileInputStream(file);
spec =getIV();
FileOutputStream fos = new FileOutputStream(Environment.getExternalStorageDirectory().toString() + "/decrypted.mp4");
SecretKeySpec sks = new SecretKeySpec("asdfghjklzxccvbn".getBytes(),
"AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, sks, spec);
CipherInputStream cis = new CipherInputStream(fis, cipher);
int b;
byte[] d = new byte[8192];
while ((b = cis.read(d)) != -1) {
fos.write(d, 0, b);
}
fos.flush();
fos.close();
cis.close();
получить функцию iv
public AlgorithmParameterSpec getIV() {
byte[] iv = { 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6 };
IvParameterSpec ivParameterSpec;
ivParameterSpec = new IvParameterSpec(iv);
return ivParameterSpec;
}
Андроид код будет генерировать файл, но он не читается. проверьте мой код, я делаю правильные коды или если он содержит какие-либо проблемы. помогите мне решить его
Режим и отступы не совпадают. Вы используете AES/CBC/ZeroPadding (нотацию Java) в PHP, но в Java вы используете Cipher.getInstance("AES")
который (возможно) по умолчанию использует Cipher.getInstance("AES/ECB/PKCS5Padding")
. Всегда используйте полное описание шифрования:
Cipher cipher = Cipher.getInstance("AES/CBC/ZeroPadding", "BC");
(Это не решает проблему.)
Вы не используете тот же IV. Символ '1' и байт 1 - это не одно и то же, потому что '1' - фактически байт 49.
byte[] iv = { 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50, 51, 52, 53, 54 };
Поскольку BouncyCastles/SpongyCastles ZeroPadding
не совсем то же самое, что и заполнение нулей mcrypt, вы должны использовать Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
чтобы проанализировать последние 16 байтов дешифрования и удалить конечные 0x00 байт.
Вот как это сделать в вашем случае:
int b;
byte[] d = new byte[8192];
byte[] p = null;
int holdOff;
while ((b = cis.read(d)) != -1) {
holdOff = Math.max(b - cipher.getBlockSize(), 0);
if (p != null) {
fos.write(p, 0, p.length);
Arrays.fill(p, 0);
}
if (p == null) {
p = new byte[cipher.getBlockSize()];
}
System.arraycopy(d, holdOff, p, 0, p.length);
fos.write(d, 0, holdOff);
}
// here p contains the end of the plaintext followed by padding bytes
// remove padding:
int i = cipher.getBlockSize() - 1;
while(i >= 0 && p[i] == 0) {
i--;
}
// write remaining bytes
fos.write(Arrays.copyOf(p, i+1), 0, i+1);
fos.flush();
fos.close();
cis.close();
Идея заключается в том, что вы не записываете последние 16 байтов в файл и обрабатываете их отдельно, потому что последний 16-байтовый файл расшифровки может содержать 0x00 байт, которые необходимо удалить.
Всегда произвольно генерируйте IV для каждого шифрования. Он не должен быть секретным, но он должен быть непредсказуемым. Вы можете отправить его вместе с зашифрованным текстом, например, поставив его перед зашифрованным текстом.
Аутентифицируйте свои зашифрованные тексты, запустив над ним HMAC (encrypt-then-MAC). Прежде чем приступать к расшифровке, вам необходимо проверить MAC на стороне приемника, чтобы убедиться, что он был обработан на этом пути.