2012-08-14 12 views
13

Pierwsza rzecz pierwsza. Jakiś czas temu potrzebowałem prostego szyfrowania AES w Androidzie, aby zaszyfrować hasło i wysłać je jako parametr usługi internetowej .net, w której hasło zostało odszyfrowane.Szyfrowanie AES w iOS i Androidzie oraz deszyfrowanie w C# .NET

Poniżej moja Android szyfrowania:

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

I wtedy rozszyfrował go w C#:

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

To działało jak uroku, ale problemy pojawiły się, gdy próbowałem zrobić to samo w iOS. Jestem całkiem nowe aplikacje rozwijających dla iPhone/iPad, więc ofcause google go, a prawie każda próbka kodu pod warunkiem, był następujący:

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

}

Może byłem trochę zbyt optymistyczne, gdy miałem nadzieję na płynne przejście tutaj, bo gdy Android rzuca mi coś takiego:

"EgQVKvCLS4VKLoR0xEGexA=="

następnie iOS daje mi:

"yP42c9gajUra7n0zSEuVJQ==" 

Mam nadzieję, że jest to coś, o czym zapomniałem, lub niektóre ustawienia są nieprawidłowe?

[AKTUALIZACJA] Wyniki są teraz wyświetlane po kodowaniu base64.

+1

Wersja dla Androida to łańcuch podstawowy o adresie URL, który jest równy "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 f5 7d 75 eb 9e 82 16 c9) '. – Joe

+0

Woops, przepraszam, zapomniałem o tym wspomnieć. Koduje również wynik z wersji iOS, tylko w innej metodzie, ale wyniki są inne przed kodowaniem. – Morten

+0

Zaktualizowano pytanie, aby wyświetlić wyniki po kodowaniu base64. Używane jest to samo hasło i ten sam klucz. – Morten

Odpowiedz

5

Na wstępie należy zauważyć, że w tym kodzie występują istotne problemy z zabezpieczeniami. Podejmujesz hasło smyczkowe i po prostu wpuszczasz je do klucza. Jeśli ten ciąg znaków nadaje się do postaci ludzkiej, to dramatycznie ograniczyłeś swój keyspace (zmieniając AES-128 w bardziej podobny do AES-40 lub AES-50, może nawet gorzej). Musisz solić i rozciągać klucz za pomocą PBKDF2. Zobacz Properly encrypting with AES with CommonCrypto, aby uzyskać pełniejszą dyskusję.

Masz również znaczący problem z bezpieczeństwem, ponieważ używasz klucza jako IV (więcej informacji poniżej, to w rzeczywistości jest przyczyną Twojego objawu). To nie jest właściwy sposób wybierania IV i sprawia, że ​​tekst zaszyfrowany jest przewidywalny. Identyczny tekst jawny zaszyfrowany za pomocą tego samego klucza da taki sam wynik. Jest to podobne do braku IV. IV musi być losowa. Zobacz powyższy link, aby uzyskać więcej dyskusji.

Teraz do rzeczywistych objawów. Problem polega na tym, że używasz klucza jako IV w Javie i C#, ale używasz 0 (NULL) jako IV na iOS (IV nie jest opcjonalne, tylko mijasz 0). Musisz użyć tego samego IV we wszystkich przypadkach.

+0

Wiem, że są pewne problemy z bezpieczeństwem, ale jest to tylko tymczasowe rozwiązanie. To jest tylko szybkie rozwiązanie, więc nie przekazujemy czytelnego tekstu, dopóki nasze ostateczne rozwiązanie nie zostanie ukończone. Nie mogę teraz niczego przetestować, ponieważ jest to problem w działaniu, ale jeśli dobrze go zrozumiem, powinien zostać naprawiony, jeśli zmienię następujące: W C# -decryption: rijndaelCipher.IV = X; W szyfrowaniu Java: IvParameterSpec ivSpec = new IvParameterSpec (X); ... i zmienił parametr NULL na X, gdzie Xzużycia ma tę samą wartość? Przy okazji, dziękuję bardzo za odpowiedź ... – Morten

+0

Obecnie "X" w powyższym kodzie jest kopią klucza wszędzie oprócz iOS. Możesz albo uczynić go kluczem na iOS, albo uczynić go 0 C# i Java. Nie zrobiłbym tej wartości statycznej (innej niż 0). –

+0

OK, dziękuję bardzo za pomoc. Wypróbuję to jutro i zaznaczę twoją odpowiedź jako "zaakceptowaną" ... – Morten

Powiązane problemy