2015-09-01 10 views
5

Pracowałem nad projektem, w którym musimy bezpiecznie przechowywać plik PDF na karcie SD. Chcemy to zaszyfrować w .net, ponieważ musi zostać przeniesione przez API. Zaimplementowałem w .NET, ale nie można odszyfrować w systemie Android.Jak zaszyfrować plik w .net i odszyfrować w Androidzie

kod do zaszyfrowania pliku

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

Kod do odszyfrowania plikowi

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(); 

     } 
    } 

Próbowałem w Android za pomocą poniższego kodu

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

Po uruchomieniu tego kodu otrzymuję błąd:

error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt 
+1

Dwie rzeczy, które wyskakują: 1) nie powinny obcinać tablicy kluczy arbitralnie; 2) PKCS7 jest schematem dopełnienia używanym w kodzie .NET, a PKCS5 w kodzie androida. – dbugger

+0

Zauważyłem również wyściółkę. PKCS5 jest podzbiorem PKCS7, więc nie ma gwarancji, że twój kod odszyfrowujący będzie w stanie go rozszyfrować (może faktycznie działać przez pewien czas, ale może być uznany za fuksa). –

+0

Co można zrobić, aby rozwiązać ten problem. Każdy kod lub biblioteka, która może pomóc – user3036123

Odpowiedz

3

Znalazłem problem z kodem i architekturą, której używasz. Po wybraniu plików kryptograficznych w różnych programach językowych iw różnych środowiskach (Android ("unix") i Windows) trzeba pamiętać o koncepcji małego i dużego endianina. - the wikipedia Endianness.


Aperently w Javie zawsze zagraża BIG endianem, więc bajt najbardziej znaczący (MSB) różni się od C# przy użyciu najmniejszego znacznika bajtowego (LSB), co powoduje trudny do wykrycia problem.

Stworzyłem kod na podstawie twojego, ale używając Java, a nie Androida i nie mogłem sprawić, aby kod działał, ponieważ zawsze miałem ten sam komunikat o błędzie BadPaddingException: Given final block not properly padded. Komunikat o błędzie nie powiedział wiele o prawdziwym problemie, który był plikiem key.
Podczas czytania w Javie różni się od .NET, ponieważ po konwersji klucza na bajtowe zagrożenia architektury Java z MSB, gdy twój prawdziwy klucz używa LSB.

Więc prawdziwa odpowiedź to to 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
coś takiego:

//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

Powodzenia z systemem!.

Ps .: Miałem problem z dekodowaniem, ponieważ problem występuje podczas dekodowania i dekodowania tablicy bajtów. Znalazłem ścieżkę, w której powinieneś użyć Apache Commons Base64 do dekodowania łańcucha znaków w Javie.
Referencje

-duży/little endian - Difference between Big Endian and little Endian Byte order
-Error z wyściełany - BadPaddingException: Given final block not properly padded
-The przechylić problemu jest kluczem - Given final block not properly padded
-decode Base64 - Decoding a Base64 string in Java




Kod, którego użyłem do przetestowania.

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

    }