如何在.net中加密文件,在android中解密

本文关键字:android 解密 文件 加密 net | 更新日期: 2023-09-27 18:10:38

我一直在做一个项目,我们必须在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

如何在.net中加密文件,在android中解密

所以我发现你的代码和你正在使用的架构的问题。当您选择在不同的语言程序和不同的环境(Android("unix")和Windows)中加密文件时,您需要记住小端和大端的概念。-维基百科的Endianness。

显然,在Java中,it威胁总是使用BIG端序,因此最有效字节(MSB)与c#使用最有效字节(LSB)不同,这一步导致难以跟踪的问题。

我创建了一个基于你的代码,但使用Java而不是android,不能使代码工作,因为我总是有相同的错误信息BadPaddingException: Given final block not properly padded。错误信息并没有说明真正的问题是key文件。
当你在Java中阅读时,它与。net不同,因为当你将密钥转换为字节时,Java架构威胁着MSB,而你的真正密钥使用的是LSB。

所以真正的答案是这个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中的字符串。
引用

-大/小端序-大端序和小端序字节顺序的区别
BadPaddingException:给定的最后块没有正确填充
-提示问题出在关键-给定的最终块没有正确填充
- decode Base64 -在Java中解码Base64字符串

//




用于测试的代码。

    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;
        }
    }