2012-08-14 4 views
13

Erste Sache zuerst. Vor einiger Zeit benötigte ich eine einfache AES-Verschlüsselung in Android, um ein Passwort zu verschlüsseln und es als Parameter für einen .net-Webdienst zu senden, wo das Passwort entschlüsselt wurde.AES-Verschlüsselung in iOS und Android und Entschlüsselung in C#. NET

Das folgende ist meine Android-Verschlüsselung:

private static String Encrypt(String text, String key) 
     throws Exception { 
     Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     byte[] keyBytes= new byte[16]; 
     byte[] b= key.getBytes("UTF-8"); 
     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.ENCRYPT_MODE,keySpec,ivSpec); 

     byte[] results = cipher.doFinal(text.getBytes("UTF-8")); 
     String result = Base64.encodeBytes(results); 
     return result; 
     } 

Und dann entschlüsselte ich es in C# mit:

 public static string Decrypt(string textToDecrypt, string key) 
    { 
     System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding(); 

     RijndaelManaged rijndaelCipher = new RijndaelManaged(); 
     rijndaelCipher.Mode = CipherMode.CBC; 
     rijndaelCipher.Padding = PaddingMode.PKCS7; 

     rijndaelCipher.KeySize = 0x80; 
     rijndaelCipher.BlockSize = 0x80; 

     string decodedUrl = HttpUtility.UrlDecode(textToDecrypt); 
     byte[] encryptedData = Convert.FromBase64String(decodedUrl); 
     byte[] pwdBytes = Encoding.UTF8.GetBytes(key); 
     byte[] keyBytes = new byte[0x10]; 
     int len = pwdBytes.Length; 
     if (len > keyBytes.Length) 
     { 
      len = keyBytes.Length; 
     } 
     Array.Copy(pwdBytes, keyBytes, len); 
     rijndaelCipher.Key = keyBytes; 
     rijndaelCipher.IV = keyBytes; 
     byte[] plainText = rijndaelCipher.CreateDecryptor().TransformFinalBlock(encryptedData, 0, encryptedData.Length); 
     return encoding.GetString(plainText); 
    } 

Dieser arbeitete wie ein Charme, aber die Probleme kamen, als ich versuchte, das zu tun Gleiches in iOS. Ich bin ziemlich neu die Entwicklung von Anwendungen für das iPhone/iPad, so ofcause ich es gegoogelt, und fast jedes Codebeispiel vorgesehen war den folgenden:

- (NSData *)AESEncryptionWithKey:(NSString *)key { 
char keyPtr[kCCKeySizeAES128]; // room for terminator (unused) 
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding) 

// fetch key data 
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding]; 

NSUInteger dataLength = [self length]; 

size_t bufferSize = dataLength + kCCBlockSizeAES128; 
void *buffer = malloc(bufferSize); 

size_t numBytesEncrypted = 0; 

CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, 
             keyPtr, kCCKeySizeAES128, 
             NULL /* initialization vector (optional) */, 
             [self bytes], [self length], /* input */ 
             buffer, bufferSize, /* output */ 
             &numBytesEncrypted); 
if (cryptStatus == kCCSuccess) { 
    //the returned NSData takes ownership of the buffer and will free it on deallocation 
    return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted]; 
} 

free(buffer); //free the buffer; 
return nil; 

}

Vielleicht war ich ein bisschen zu optimistisch, wenn ich hatte gehofft, für einen reibungslosen Übergang hier, weil, wenn das Android wirft mich so etwas wie:

"EgQVKvCLS4VKLoR0xEGexA=="

dann das iOS gibt mir:

"yP42c9gajUra7n0zSEuVJQ==" 

Hoffentlich ist es nur etwas, das ich vergessen habe, oder einige der Einstellungen sind falsch?

[UPDATE] Die Ergebnisse werden nun nach der base64-Codierung angezeigt.

+1

die Android-Version ist eine URL Base64-String codiert, die zu ' "YHH + gTxyIxvAx1cPFLcP0IEW2HcVHQVi9X11656CFsk ="' '(60 71 Fe 81 3c 72 23 1b c0 c7 57 0F 14 b7 0F d0 81 16 D8 77 15 1d 05 62 gleich f5 7d 75 eb 9e 82 16 c9) '. – Joe

+0

Woops, sorry, ich habe vergessen, das zu erwähnen. Ich kodiere das Ergebnis auch aus der iOS-Version, nur in einer anderen Methode, aber die Ergebnisse unterscheiden sich vor der Kodierung. – Morten

+0

Die Frage wurde aktualisiert, um die Ergebnisse nach der base64-Codierung anzuzeigen. Es wird das gleiche Passwort und der gleiche Schlüssel verwendet. – Morten

Antwort

5

Als Erstes bemerken Sie, dass Sie in diesem Code erhebliche Sicherheitsprobleme haben. Sie nehmen ein String-Passwort und legen es einfach in einen Schlüssel. Wenn diese Zeichenfolge menschenähnlich ist, dann haben Sie Ihren Schlüsselraum dramatisch eingeengt (AES-128 wird zu AES-40 oder AES-50, vielleicht sogar noch schlimmer). Sie müssen den Schlüssel mit PBKDF2 salzen und strecken. Eine ausführlichere Diskussion finden Sie unter Properly encrypting with AES with CommonCrypto.

Sie haben auch ein erhebliches Sicherheitsproblem, weil Sie Ihren Schlüssel als IV verwenden (siehe unten, das ist eigentlich die Ursache Ihres Symptoms). Dies ist nicht der richtige Weg, um eine IV auszuwählen und Ihren Chiffrentext vorhersagbar zu machen. Ein identischer Klartext, der mit demselben Schlüssel verschlüsselt ist, ergibt das gleiche Ergebnis. Dies ist ähnlich wie überhaupt keine IV zu haben. Die IV muss zufällig sein. Siehe den obigen Link für mehr Diskussion.

Jetzt zu Ihrem eigentlichen Symptom. Das Problem ist, dass Sie den Schlüssel als IV in Java und C# verwenden, aber Sie verwenden 0 (NULL) als IV für iOS (die IV ist nicht optional; Sie geben nur 0). Sie müssen die gleiche IV in allen Fällen verwenden.

+0

Ich weiß, dass es einige Sicherheitsprobleme gibt, aber es ist nur eine vorübergehende Lösung. Dies soll nur eine schnelle Lösung sein, so dass wir keinen lesbaren Text weitergeben, bis unsere endgültige Lösung abgeschlossen ist. Ich kann momentan nichts wirklich testen, weil es ein Problem bei der Arbeit ist, aber wenn ich es richtig verstehe, sollte es behoben werden, wenn ich Folgendes ändere: In der C# -Entschlüsselung: rijndaelCipher.IV = X; In der Java-Verschlüsselung: IvParameterSpec ivSpec = new IvParameterSpec (X); ... und den NULL-Parameter in X geändert, wobei X ofcause der gleiche Wert ist? Übrigens, vielen Dank für Ihre Antwort ... – Morten

+0

Derzeit "X" in Ihrem obigen Code ist eine Kopie des Schlüssels überall aber iOS. Du kannst entweder den Schlüssel auf iOS setzen oder 0 von C# und Java machen. Ich würde es keinen statischen Wert (anders als 0) machen. –

+0

Okay, vielen Dank für Ihre Hilfe. Ich werde es morgen versuchen und Ihre Antwort als "akzeptiert" markieren ... – Morten

Verwandte Themen