我在php中用AES加密法加密了文件,代码如下。
$ALGORITHM = 'AES-128-CBC';
$IV = '12dasdq3g5b2434b';
$password = '123';
openssl_encrypt($contenuto, $ALGORITHM, $password, 0, $IV);
现在我正在尝试在Android中解密它,但我总是面临InvalidKey异常:密钥长度不是128/192/256位错误。这是Android代码:
String initializationVector = "12dasdq3g5b2434b";
String password = "123";
FileInputStream fis = new FileInputStream(cryptFilepath);
FileOutputStream fos = new FileOutputStream(outputFilePath);
byte[] key = (password).getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key,16);
SecretKeySpec sks = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, sks, new IvParameterSpec(initializationVector.getBytes()));
CipherInputStream cis = new CipherInputStream(fis, cipher);
int b;
byte[] d = new byte[16];
while((b = cis.read(d)) != -1) {
fos.write(d, 0, b);
}
fos.flush();
fos.close();
cis.close();
有人能建议我怎么做吗?任何帮助都将不胜感激。
在迈克尔的回答的帮助下,我写下了成功解密文件的代码。
在应用级别build.gradle文件中添加以下依赖项:
implementation 'commons-io:commons-io:2.7'
implementation 'commons-codec:commons-codec:1.13'
Java代码:
public static void decrypt(String path, String outPath) throws Exception {
String password = "123";
String initializationVector = "12dasdq3g5b2434b";
byte[] key = new byte[16]; // 16 bytes for aes cbc 128
System.arraycopy(password.getBytes(StandardCharsets.UTF_8), 0, key, 0, password.getBytes(StandardCharsets.UTF_8).length);
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(initializationVector.getBytes(StandardCharsets.UTF_8));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] input_file;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
input_file = Files.readAllBytes(Paths.get(path));
} else {
input_file = org.apache.commons.io.FileUtils.readFileToByteArray(new File(path));
}
byte[] decodedBytes;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
decodedBytes = Base64.getDecoder().decode(input_file);
} else {
decodedBytes = org.apache.commons.codec.binary.Base64.decodeBase64(input_file);
}
byte[] decryptedtext = cipher.doFinal(decodedBytes);
FileOutputStream fos = new FileOutputStream(outPath);
fos.write(decryptedtext);
fos.flush();
fos.close();
}
我希望这会有所帮助。
以下完整的工作示例展示了如何处理密码问题和进行Base64解码,这些示例只处理字符串而不是文件。请记住@Topaco所说的openssl以Base64编码输出,需要转换为字节格式,然后文件才能与CipherInputStream一起用于解密!
第三点(不是真正的错误)是,在Java/Android端,您不需要为字符串到字节数组的转换设置字符集,只需添加StandardCharset即可。UTF_8和你对这一点很满意。
当心没有适当的异常处理!
这是我的PHP代码示例:
<?php
// https://stackoverflow.com/questions/63113746/decrypt-file-using-aes-method-in-android
$ALGORITHM = 'AES-128-CBC';
$IV = '12dasdq3g5b2434b';
$password = '123';
$plaintext = "my content to encrypt";
echo 'plaintext: ' . $plaintext . PHP_EOL;
$ciphertext = openssl_encrypt($plaintext, $ALGORITHM, $password, 0, $IV);
echo 'ciphertext: ' . $ciphertext . PHP_EOL;
$decryptedtext = openssl_decrypt($ciphertext, $ALGORITHM, $password, 0, $IV);
echo 'decryptedtext: ' . $decryptedtext . PHP_EOL;
?>
PHP端的输出:
plaintext: my content to encrypt
ciphertext: DElx3eON2WX0MCj2GS8MnD+kn5NOu1i5IOTcrpKegG4=
decryptedtext: my content to encrypt
样本Java代码:
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class DecryptInJava {
public static void main(String[] args) throws NoSuchPaddingException, NoSuchAlgorithmException,
InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
System.out.println("https://stackoverflow.com/questions/63113746/decrypt-file-using-aes-method-in-android");
String password = "123";
String initializationVector = "12dasdq3g5b2434b";
String ciphertext = "DElx3eON2WX0MCj2GS8MnD+kn5NOu1i5IOTcrpKegG4="; // password 123 in openssl
// openssl encodes the output in base64 encoding, so first we have to decode it
byte[] ciphertextByte = Base64.getDecoder().decode(ciphertext);
// creating a key filled with 16 'x0'
byte[] key = new byte[16]; // 16 bytes for aes cbc 128
// copying the password to the key, leaving the x0 at the end
System.arraycopy(password.getBytes(StandardCharsets.UTF_8), 0, key, 0, password.getBytes(StandardCharsets.UTF_8).length);
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(initializationVector.getBytes(StandardCharsets.UTF_8));
// don't use just AES because that defaults to AES/ECB...
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] decryptedtext = cipher.doFinal(ciphertextByte);
System.out.println("decryptedtext: " + new String(decryptedtext));
}
}
Java端的输出:
decryptedtext: my content to encrypt
问题中发布的原始代码使用流来读取、解密和写入相应的文件。这样就可以处理大于可用内存的文件。
然而,最初发布的代码缺少Base64解码,这是必要的,因为PHP代码的密文是Base64编码的。
使用Apache Commons编解码器的< code>Base64InputStream类可以轻松实现Base64解码,该类在< code>FileInputStream和< code>CipherInputStream之间运行,因此易于集成:
import org.apache.commons.codec.binary.Base64InputStream;
...
public static void decrypt(String ciphertextFilepath, String decryptedFilePath) throws Exception {
String password = "123";
String initializationVector = "12dasdq3g5b2434b";
byte[] key = new byte[16];
byte[] passwordBytes = password.getBytes(StandardCharsets.UTF_8);
System.arraycopy(passwordBytes, 0, key, 0, passwordBytes.length);
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(initializationVector.getBytes(StandardCharsets.UTF_8));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
try (FileInputStream fis = new FileInputStream(ciphertextFilepath);
Base64InputStream b64is = new Base64InputStream(fis);
CipherInputStream cis = new CipherInputStream(b64is, cipher);
FileOutputStream fos = new FileOutputStream(decryptedFilePath)) {
int read;
byte[] buffer = new byte[16]; // 16 bytes for testing, in practice use a suitable size (depending on your RAM size), e.g. 64 Mi
while((read = cis.read(buffer)) != -1) {
fos.write(buffer, 0, read);
}
}
}
其他修复的错误/优化点是(另请参阅其他答案/评论):
编辑:考虑IV,参见@Michael Fehr的评论。
通常为每次加密生成新的随机IV。IV不是秘密的,通常放在密文之前,结果是Base64编码。接受者可以将两部分分开,因为静脉注射的大小是已知的(对应于块大小)。此构造还可以与Base64InputStream
类结合使用,其中IV必须在Base64InputStream
实例化和
...
try (FileInputStream fis = new FileInputStream(ciphertextFilepath);
Base64InputStream b64is = new Base64InputStream(fis)){
byte[] iv = b64is.readNBytes(16); // 16 bytes for AES
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
try (CipherInputStream cis = new CipherInputStream(b64is, cipher);
FileOutputStream fos = new FileOutputStream(decryptedFilePath)) {
...
如果在加密过程中IV和密文分别进行Base64编码,然后连接,用分隔符分隔(参见@Michael Fehr的评论),则IV的确定必须在FileInpuStream
和Base64InpuStream
实例化之间完成(分隔符也必须刷新)。
但这总是给我以下的例外- 我的键盘生成逻辑- 我的加密逻辑- Base64 Util方法-
问题内容: 因此,我正在为自己开发一个个人项目,并且正在尝试加密手机上的文件。这些文件可以是任何文件,例如文档,照片等。现在,我正在尝试使其正常运行。每当我运行加密时,它似乎都可以正常工作并加密文件。当我运行解密时,有时它可以工作,而其他时候则不起作用。当它失败时,我通常会收到“在确定密码时出错,填充块已损坏”错误。我也没有使用不同的测试文件,所以它不像某些文件可以工作,而其他文件则不能。我每次都
我试图在Android和PHP端使用AES加密/解密数据,并累犯空答案。 首先,我在Android中生成了对称密钥: 在服务器端,我试图解密数据。我可以解密(从RSA)秘密的AES密钥,并得到它的字符串表示。在客户端(Android)和服务器端(PHP)上是一样的。但是如何使用这个字符串AES密钥来解密数据呢?我尝试了这个(PHP): PHP中的结果: 怎么啦?
我正在Android中进行AES加密和解密,我使用下面的Android代码片段发布请求。 申请职位 我成功地从上述请求中获得了Base64加密响应字符串,但当我尝试使用以下代码段解密响应字符串时,它会返回无法读取的字符串,如字符和方框。 解密 解密的输出 ��]ة*�]��O Z Q2_ 响应应为JSON格式,但实际输出如上所述。 请使用Base 64共享用于使用AES 256位安全密钥解密数据的
问题内容: 有没有一个很好的示例,说明如何在Android上使用AES 加密和解密图像及其他文件? 问题答案: 并像这样调用它们: 这应该可行,我现在在项目中使用类似的代码。
null 解密: 错误日志: