2016-04-25 15 views
2

Ich verschlüssele eine Datei in Java und muss es auf der Clientseite entschlüsseln. Dies ist der Server-Seite Code:CryptoJS entschlüsseln (AES) eine Datei Bytearray aus Java

Key secretKey = new SecretKeySpec("mysecretmysecret".getBytes(), "AES"); 
Cipher cipher = Cipher.getInstance("AES"); 
cipher.init(Cipher.ENCRYPT_MODE, secretKey); 
byte[] outputBytes = cipher.doFinal(read(sampleFile)); 
return outputBytes; 

Auf Client-Seite I Ajax-Anfrage verwenden, um die Datei und verwenden CryptoJS AES zu holen:

var xhr = new XMLHttpRequest(); 
xhr.open('GET', 'file', true); 
xhr.responseType = 'arraybuffer'; 

xhr.onload = function (e) { 
     var encryptedData = this.response; 
     var decrypted = CryptoJS.AES.decrypt(encryptedData, "mysecretmysecret"); 
     console.log(decrypted); 
}; 
xhr.send(); 

Aber diese die Datei nicht entschlüsseln. Ich werde dies in der Konsole entschlüsselt als Wert gedruckt:

W…y.init {words: Array[0], sigBytes: 0} 

ich auch die Umwandlung Arraybuffer zu WordArray versucht haben vorgeschlagen here aber immer noch das gleiche Ergebnis. Ich wäre mehr als froh, wenn mir jemand in die richtige Richtung zeigen und mir sagen könnte, was ich falsch gemacht habe.

Bearbeiten 1: Ich habe das Problem gelöst. Der Code, den ich verwendet habe, wird als Antwort gepostet.

+0

"mysecretmysecret" ist wahrscheinlich nicht so geheim, wenn es dort im Client-Quellcode sitzt. –

+0

@AlexK. Dies ist nur ein POC. Noch nicht in echtem Code. – Sandeep

+0

Verwenden Sie keine Zeichenfolgen als Schlüssel, verwenden Sie Bytearrays. Die Konvertierung von einem String in ein Byte-Array ist mehrdeutig (BoM am Start? \ 0 Terminator? Usw.). Insbesondere bei der Übertragung verschlüsselter Daten zwischen Systemen ** ** ** nicht auf Systemstandards verlassen. Explizit gesetzter Modus, IV/Nonce usw. Sie machen wenig davon und verlassen sich darauf, dass die Standardeinstellungen auf allen Systemen gleich sind. Alle nicht übereinstimmenden Standardwerte verursachen Probleme. – rossum

Antwort

1

Lassen Sie uns rekapitulieren, in Java sind Sie

  • AES,
  • EZB (nicht angegeben, aber meistens die Standard; es ist unsicher!),
  • PKCS # 7-Polsterung (nicht angegeben, aber meistens der Standardwert; es ist das gleiche wie PKCS # 5 Padding) und
  • ein Kennwort von 16 Zeichen als Schlüssel von 16 Byte (abhängig von der Standardsystemcodierung). unter Verwendung von OpenSSL EVP_BytesToKey mit einer einzigen Runde von MD5

Wenn der Schlüssel als String CryptoJS übergeben wird, wird es den Schlüssel aus dem angenommenen Passwort abzuleiten. Da Ihr Chiffretext nicht in einem OpenSSL-kompatiblen Format kodiert ist, schlägt er fehl. Die Sache ist, du brauchst das nicht.

Der folgende Code würde den verschlüsselten Text entschlüsseln, die korrekt von Java kommen, aber es ist nicht sehr sicher:

var passwordWords = CryptoJS.enc.Utf8.parse("mysecretmysecret"); 
var decrypted = CryptoJS.AES.decrypt({ 
    ciphertext: CryptoJS.lib.WordArray.create(encryptedData) // or use some encoding 
}, passwordWords, { 
    mode: CryptoJS.mode.ECB 
}); 
console.log(decrypted.toString(CryptoJS.enc.Utf8)); // in case the plaintext is text 

Der ECB-Modus nicht im Grunde Rollup enthalten ist, so dass Sie, dass einbeziehen müssen werden JavaScript file auf Ihrer Seite nach der CryptoJS-Hauptdatei.
Auch CryptoJS behandelt standardmäßig keinen ArrayBuffer. Sie müssen dazu die shim (Quelle: this answer) einschließen.


Das Problem damit ist seine Unsicherheit. Der ECB-Modus ist sehr unsicher.

  • Nie ECB mode verwenden. Es ist deterministisch und daher nicht semantisch sicher. Sie sollten zumindest einen zufälligen Modus wie CBC oder CTR verwenden. Die IV/Nonce ist nicht geheim, Sie können sie also zusammen mit dem Chiffretext senden. Ein üblicher Weg ist, es vor den Chiffretext zu stellen.

  • Es ist besser, Ihre Chiffrate zu authentifizieren, so dass Angriffe wie padding oracle attack nicht möglich sind. Dies kann mit authentifizierten Modi wie GCM oder EAX oder mit einem encrypt-then-MAC Schema geschehen.

  • Schlüssel können aus Passwörtern abgeleitet werden, aber ein geeignetes Schema wie PBKDF2 sollte verwendet werden. Java und CryptoJS unterstützen beide.

+0

danke @Artjom. Dies ist nur ein POC und ich muss dies mit möglichst wenig Code lösen. Natürlich weiß ich, dass EZB am unsichersten ist, aber ich werde später noch einmal auf die Verhärtung eingehen. – Sandeep

0

So habe ich endlich das gelöst. Danke an Artjom für den Hinweis in die richtige Richtung. Ich habe meinen Java-Code geändert, um CBC mit PKCS5Padding zu verwenden.

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
SecretKeySpec myKey = new SecretKeySpec("mysecretmysecret".getBytes(), "AES"); 
IvParameterSpec IVKey = new IvParameterSpec("mysecretmysecret".getBytes()); 
cipher.init(Cipher.ENCRYPT_MODE, myKey, IVKey); 
byte[] outputBytes = cipher.doFinal(read(sampleFile)); 
return outputBytes; 

Und mein Javascript geht so:

var xhr = new XMLHttpRequest(); 
xhr.open('GET', 'file', true); 
xhr.responseType = 'arraybuffer'; 

xhr.onload = function(e) { 
    var encryptedData = this.response; 
    var passwordWords = CryptoJS.enc.Utf8.parse("mysecretmysecret"); //yes I know, not a big secret! 
    var wordArray = CryptoJS.lib.WordArray.create(encryptedData); 
    var decrypted = CryptoJS.AES.decrypt({ 
     ciphertext: wordArray 
    }, passwordWords, { 
     iv: passwordWords, //yes I used password as iv too. Dont mind. 
     mode: CryptoJS.mode.CBC, 
     padding: CryptoJS.pad.Pkcs7 
    }); 
    console.log(decrypted); //Eureka!! 
}; 

xhr.send(); 

Die decrypted ein WordArray ist.