2015-09-01 8 views
5

Ho lavorato a progetti in cui dobbiamo conservare in modo sicuro un pdf nella scheda SD Android. Vogliamo che questo sia crittografato in .net perché deve essere trasferito tramite API. Ho implementato in .NET ma non riesco a decodificare in Android.Come crittografare un file in .net e decifrare in android

codice per crittografare un file

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

codice per decriptare file di

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

     } 
    } 

ho provato in Android usando sotto il codice

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

Quando si esegue questo codice ottengo errore:

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

Due cose che saltano fuori: 1) non devono troncare arbitrariamente l'array di chiavi; 2) PKCS7 è lo schema di riempimento utilizzato nel codice .NET e PKCS5 nel codice di Android. – dbugger

+0

Ho notato anche l'imbottitura. PKCS5 è un sottoinsieme di PKCS7 quindi non vi è alcuna garanzia che il codice di decifrazione sia in grado di decifrarlo (potrebbe effettivamente funzionare una parte del tempo ma potrebbe essere considerato un caso). –

+0

Cosa si può fare per risolvere questo problema. Qualsiasi codice o libreria che possa aiutare – user3036123

risposta

3

Quindi ho trovato il problema con il codice e l'architettura che si sta utilizzando. Quando si sceglie di crittografare i file in programmi di lingue diverse e in ambienti diversi (Android ("unix") e Windows) è necessario ricordare il concetto di piccolo e grande endian. - the wikipedia Endianness.

Apertura in Java la minaccia sempre con BIG endian quindi il byte più significativo (MSB) è diverso dal C# utilizzando il byte meno significativo (LSB), questo passaggio causa un problema difficile da tracciare.

Ho creato un codice basato sul tuo ma utilizzando Java e non Android e non ho potuto far funzionare il codice perché ho sempre avuto lo stesso messaggio di errore BadPaddingException: Given final block not properly padded. Il messaggio di errore non ha detto molto sul vero problema che era il file key.
Quando si legge in Java è diverso da .NET perché quando si converte la chiave in byte le minacce dell'architettura Java con MSB quando la propria chiave reale utilizza LSB.

Quindi la vera risposta è proprio questo 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
Qualcosa di simile a questo:

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

Buona fortuna con il vostro sistema!.

Ps: ho avuto un problema con la decodifica perché il problema si verifica quando decodificare e decodificare una matrice di byte. Ho trovato un percorso che dovresti usare Apache Commons Base64 per decodificare la stringa in Java.
Riferimenti

-Big/little endian - Difference between Big Endian and little Endian Byte order
-Errore imbottito - BadPaddingException: Given final block not properly padded
-Il punta il problema è nella chiave - Given final block not properly padded
-decode Base64 - Decoding a Base64 string in Java




Il codice che ho usato per testare.

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

    }