2015-11-27 42 views
6

Ho un codice seguente in C#. Codifica una matrice di byte con un algoritmo simmetrico AES. Ho bisogno di scrivere l'equivalente Java di questo codice.Equivalente Java della crittografia C# AES

class Program 
{ 
    static void Main(string[] args) 
    { 
     string a = "ABCDEFGHIJKLMNOP"; 
     byte[] bytes = Encoding.ASCII.GetBytes(a); 
     byte[] cipher = encode(bytes, "1111111122222222111111112222222211111111222222221111111122222222", "66666666555555556666666655555555"); 
    } 

    private static byte[] encode(byte[] toEncrypt, string sKey, string sIV) 
    { 
     byte[] IV = new byte[16]; 
     byte[] key = new byte[32]; 
     byte[] array = new byte[toEncrypt.Length]; 
     string s; 

     for (int i = 0; i < IV.Length; ++i) 
     { 
      s = sIV.Substring(i * 2, 2); 
      IV[i] = Convert.ToByte(s, 16); 
     } 

     for (int i = 0; i < key.Length; ++i) 
     { 
      s = sKey.Substring(i * 2, 2); 
      key[i] = Convert.ToByte(s, 16); 
     } 

     MemoryStream filecrypt = new MemoryStream(array); 

     AesManaged encrypt = new AesManaged(); 
     encrypt.Mode = CipherMode.CBC; 
     encrypt.Padding = PaddingMode.None; 
     encrypt.BlockSize = 128; 
     encrypt.KeySize = 256; 

     CryptoStream cs = new CryptoStream(filecrypt, encrypt.CreateEncryptor(key, IV), CryptoStreamMode.Write); 
     cs.Write(toEncrypt, 0, toEncrypt.Length); 
     cs.Close(); 

     return array; 
    } 
} 

Questo è il mio tentativo di scrivere questo in Java. Il codice sembra buono, ma l'output è diverso, qualcosa deve essere sbagliato.

public class Main { 

    public static void main(String [] args) { 
     byte [] code = encode("ABCDEFGHIJKLMNOP".getBytes(), "1111111122222222111111112222222211111111222222221111111122222222", "66666666555555556666666655555555"); 
    } 

    private static byte[] toByteArray(String s) { 
     int len = s.length(); 
     byte[] data = new byte[len/2]; 
     int a; 
     int b; 
     for (int i = 0; i < len; i += 2) { 
      a = (Character.digit(s.charAt(i), 16) << 4); 
      b = Character.digit(s.charAt(i+1), 16); 
      int n = (Character.digit(s.charAt(i), 16) << 4) 
        + Character.digit(s.charAt(i+1), 16); 
       data[i/2] = (byte) (n); 
     } 
     return data; 
    } 

    private static byte[] encode(byte[] toEncrypt, String skey, String siv) 
    { 
     byte[] key = toByteArray(skey); 
     byte[] iv = toByteArray(siv); 

     byte[] array = new byte[toEncrypt.length]; 

     Cipher cipher; 

     try { 
      cipher = Cipher.getInstance("AES/CBC/NoPadding"); 
      cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv)); 
      array = cipher.doFinal(array); 
     } catch (Exception ex) { 
      ex.printStackTrace(); 
     } 
     return array; 
    } 
} 

Qualsiasi indizio e idea sarà molto apprezzato.

+0

Come si guarda l'output in ogni caso? –

+0

Nei debugger (tengo a mente che i byte in Java sono firmati). – Someone

+1

Sarebbe molto più semplice aiutarti se fornissi un programma breve ma completo in ogni lingua, in modo che possiamo vederlo da soli: includi l'input e l'output in ogni caso. Vorrei anche * fortemente * raccomandare di usare nomi più descrittivi di 'b' e' a' per rappresentare la chiave e IV ... –

risposta

2

Si sta inizializzando byte[] array = new byte[toEncrypt.length]; per qualche motivo, ma non si scrive mai il contenuto di toEncrypt prima della crittografia.Si potrebbe utilizzare System.arraycopy(toEncrypt, 0, array, 0, array.length);, ma sarebbe più facile utilizzare solo

byte[] array; 
... 
array = cipher.doFinal(toEncrypt); 
... 
return array; 
+0

errore stupido. E 'stato così, grazie. Non potevo vederlo da solo. – Someone

+0

L'interrogante potrebbe non averti dato i complimenti che meritavi contrassegnando quella risposta come definitiva, ma lo farò con una bella taglia. Godere! –

+0

@Flame_Phoenix Grazie! Ma mi sto appoggiando a chiudere la domanda, perché è più o meno un errore di battitura e non credo di aver * guadagnato * la taglia che hai offerto. A proposito, perché hai avuto bisogno di offrire la taglia? –

0

Personalmente, se il tuo obiettivo è ottenere semplicemente la crittografia AES con Java, non dovresti basare il tuo codice su una classe C#. Certo potrebbero essere simili, ma Java ha già delle librerie forti.

Con che a parte, vorrei avere il mio libro crittografia qui per spiegare a voi, ma purtroppo il meglio che posso fare ora è solo di fornire con un buon esempi che qualcun altro ha provato:

Spero che questi collegamenti ti aiutino a raggiungere il tuo obiettivo.

Inoltre, per quanto riguarda il codice specifico C#, non riesco a vedere dove si specifica il seguente codice in Java:

encrypt.BlockSize = 128; 
encrypt.KeySize = 256; 

Nel secondo tutorial vi suggerisco di avere un esempio in cui si specificano le dimensioni della chiave. Spero di aver aiutato!

+0

Ho bisogno di basare il mio codice su C#, il codice Java deve funzionare esattamente allo stesso modo. Non è necessario specificare BlockSize e KeySize in Java (quelli sono i valori predefiniti). – Someone

4

Non conosco abbastanza bene C#, ma in generale si desidera che più risultati di crittografia consecutivi siano diversi. Questo è il motivo per cui si specifica una IV iniziale per l'algoritmo AES. Un codice di crittografia potrebbe essere simile al seguente:

public String encrypt(String stringToEncrypt, IvParameterSpec ivSpec) { 
    if (stringToEncrypt == null) { 
     return null; 
    } 
    try { 
     Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     SecretKeySpec keySpec = new SecretKeySpec(key, "AES"); 
     cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec); 
     byte[] data = cipher.doFinal(stringToEncrypt.getBytes("UTF-8")); 
     return String.format("%s:%s", Base64.encode(ivSpec.getIV()), Base64.encode(data)); 
    } catch (Exception e) { 
     throw new RuntimeException("Unable to encrypt the string", e); 
    } 
    } 

vostra chiave e la tua IV dovrebbero essere generati utilizzando SecureRandom come questo offre la migliore entropia in java:

byte[] iv = new byte[32]; 
random.nextBytes(iv); 
byte[] key = new byte[32]; 
random.nextBytes(key); 

Inoltre, si potrebbe desiderare di calcolare una HMAC in seguito - java supporta anche più soluzioni qui. Controllando l'HMAC sul lato del ricevitore è possibile prevenire un attacco oracle di padding.

Per confrontare i risultati di crittografia diversi, li confronterei codificati base64.

Nota: è possibile salvare la quarta accanto al testo cifrato - è solo lì per proteggersi dagli attacchi di pre-computazione.

0
public String notify(String message, String encryptionKey) { 
    Security.addProvider(new BouncyCastleProvider()); 
    // System.out.println(message); 
    byte[] key = Base64.decode(encryptionKey); 
    SecretKeySpec skeySpec = new SecretKeySpec(key, "AES"); 
    byte[] data = Base64.decode(message); 
    String decryptedString = ""; 
    try { 
     Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING"); 
     cipher.init(Cipher.DECRYPT_MODE, skeySpec); 
     byte[] decrypted = cipher.doFinal(data); 
     decryptedString = new String(decrypted); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
    System.out.println(decryptedString); 
    return decryptedString; 
} 

Questo codice dovrebbe decifrare il messaggio cifrato aggiungendo l'imbottitura necessaria - 128bit di default e vi sarà necessario fornire la chiave di crittografia però. Tuttavia questa è la mia versione C# dello stesso codice

void DecryptMessage(string message) 
    { 
     var deserializedMessage = JsonConvert.DeserializeObject<List<string>>(message.ToString()); 
     byte[] decodedEncryptionKey = Convert.FromBase64String(encryptkey); 
     byte[] data = Convert.FromBase64String(deserializedMessage[0]); 
     byte[] iv = new byte[16]; 
     AesCryptoServiceProvider aes = new AesCryptoServiceProvider(); 
     aes.BlockSize = 128; 
     aes.KeySize = 128; 
     aes.Mode = CipherMode.ECB; 
     aes.Padding = PaddingMode.PKCS7; 

     using (ICryptoTransform decrypt = aes.CreateDecryptor(decodedEncryptionKey, iv)) 
     { 
      byte[] dest = decrypt.TransformFinalBlock(data, 0, data.Length); 
      decrypt.Dispose(); 
      Console.WriteLine(Encoding.UTF8.GetString(dest)); 
     } 
    }