我一直致力于项目,我们必须在Android sd卡中安全地保存pdf。 我们希望在.net中加密它,因为它必须通过API传输。 我在.NET中实现但无法在android中解密。
加密文件的代码
public static void EncryptFile(string inputFile, string outputFile)
{
try
{
string password = @"myKey123"; // Your Key Here
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = UE.GetBytes(password);
string cryptFile = outputFile;
FileStream fsCrypt = new FileStream(cryptFile, FileMode.Create);
RijndaelManaged RMCrypto = new RijndaelManaged();
RMCrypto.Mode = CipherMode.CBC; //remember this parameter
RMCrypto.Padding = PaddingMode.PKCS7; //remember this parameter
RMCrypto.KeySize = 0x80;
RMCrypto.BlockSize = 0x80;
CryptoStream cs = new CryptoStream(fsCrypt,
RMCrypto.CreateEncryptor(key, key),
CryptoStreamMode.Write);
FileStream fsIn = new FileStream(inputFile, FileMode.Open);
int data;
while ((data = fsIn.ReadByte()) != -1)
{
cs.WriteByte((byte)data);
}
fsIn.Close();
cs.Close();
fsCrypt.Close();
}
catch
{
Console.WriteLine("Encryption failed!", "Error");
}
}
解密文件的代码
public static void DecryptFile(string inputFile, string outputFile)
{
{
string password = @"myKey123"; // Your Key Here
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = UE.GetBytes(password);
FileStream fsCrypt = new FileStream(inputFile, FileMode.Open);
RijndaelManaged RMCrypto = new RijndaelManaged();
RMCrypto.Mode = CipherMode.CBC; //remember this parameter
RMCrypto.Padding = PaddingMode.PKCS7; //remember this parameter
RMCrypto.KeySize = 0x80;
RMCrypto.BlockSize = 0x80;
CryptoStream cs = new CryptoStream(fsCrypt,
RMCrypto.CreateDecryptor(key, key),
CryptoStreamMode.Read);
FileStream fsOut = new FileStream(outputFile, FileMode.Create);
int data;
while ((data = cs.ReadByte()) != -1)
fsOut.WriteByte((byte)data);
fsOut.Close();
cs.Close();
fsCrypt.Close();
}
}
我在Android中尝试使用以下代码
public static byte[] decodeFile(String key, byte[] fileData) throws Exception
{
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); //this parameters should not be changed
byte[] keyBytes = new byte[16];
byte[] b = key.getBytes("UTF-16");
System.out.println("RAM"+b);
int len = b.length;
if (len > keyBytes.length)
len = keyBytes.length;
System.arraycopy(b, 0, keyBytes, 0, len);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(keyBytes);
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
byte[] decrypted = cipher.doFinal(fileData);
return decrypted;
}
运行此代码时出现错误:
error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
答案 0 :(得分:4)
所以我发现你的代码和你正在使用的架构存在问题。
当您选择不同语言程序和不同环境(Android(" unix")和Windows)中的加密文件时,您需要记住小端和大端的概念。
- the wikipedia Endianness。
在Java中它始终存在威胁BIG端,因此最有意义的字节(MSB)与使用最小有效字节(LSB)的C#不同,这一步骤导致难以追踪的问题。
我创建了一个基于你的代码但是使用Java而不是android并且无法使代码工作,因为我总是有相同的错误消息BadPaddingException: Given final block not properly padded
。错误消息并没有说明key
文件的真正问题。
当你用Java阅读时,它与.NET的不同之处在于,当你将密钥转换为字节时,当你的真实密钥使用LSB时,Java架构会威胁到MSB。
所以真正的回答是you need to convert your key to array of bytes telling to use the Least significative byte so you always have the same array of bytes in .NET and in Java
像这样的东西:
//the bKey it's the array of bytes and the key it's the String your are using.
byte[] bKey = key.getBytes("UTF-16LE");
I found the issue with the LE because i read the array of bytes from .NET and from Java and they are different so this gave me the start to find this issue
祝你的系统好运!
Ps。:解码时出现问题,因为在解码和解码字节数组时遇到了问题。我找到了一条路径,您应该使用Apache Commons Base64来解码Java中的字符串。
参考
-Big / Little endian - Difference between Big Endian and little Endian Byte order
-with with padded - BadPaddingException: Given final block not properly padded
- 问题出在密钥的提示 - Given final block not properly padded
- 解码Base64 - Decoding a Base64 string in Java
我用来测试的代码。
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class HelloWorld {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
Path p = Paths
.get("C:\\Users\\casilva\\workspace\\StackOverflow\\src\\tst.enc");
byte[] a = Files.readAllBytes(p);
byte[] result = decodeFile("myKey123", a);
System.out.println("Result=" + new String(result, "UTF-8"));
}
public static byte[] decodeFile(String key, byte[] fileData)
throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] bKey = key.getBytes("UTF-16LE");
SecretKeySpec keySpec = new SecretKeySpec(bKey, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(bKey);
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
byte[] decrypted = cipher.doFinal(fileData);
return decrypted;
}
}