2012-08-14 16 views
13

İlk şey ilk. Bir süre önce bir şifreyi şifrelemek ve şifrenin şifresi çözülmüş bir .net web hizmeti için bir parametre olarak göndermek için Android'de basit bir AES şifrelemesine ihtiyacım vardı.AES şifreleme ve şifre çözme C# .NET

aşağıdaki benim Android şifreleme geçerli:

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

Ve sonra birlikte C# bunu deşifre:

 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); 
    } 
Bu harika çalıştı

ama yapmam çalıştığımda sorunlar geldi iOS'ta aynı. Ben googled Ofcause yüzden iphone/ipad için oldukça yeni gelişen uygulamalar duyuyorum ve neredeyse sağlanan her kod örneği aşağıdaki oldu:

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

}

Belki biraz fazla iyimser olduğunu, ne zaman

:

"EgQVKvCLS4VKLoR0xEGexA=="

sonra iOS bana verir: Android bana böyle bir şey atıyor zaman çünkü burada sorunsuz bir geçiş için umuyordum

"yP42c9gajUra7n0zSEuVJQ==" 

Umarım unuttuğum bir şey mi var, yoksa bazı ayarlar yanlış mı?

[UPDATE] Sonuçlar artık base64 kodlamasından sonra gösteriliyor.

+1

Android sürümü, "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'ye eşit olan bir URL kodlu base64 dizesidir. f5 7d 75 eb 9e 82 16 c9) '. – Joe

+0

Woops, üzgünüm, bundan bahsetmeyi unuttum. Diğer bir yöntemde, iOS sürümünden de sonuçları kodluyorum, ancak kodlamadan önce sonuçlar farklı. – Morten

+0

Soruyu base64 kodlamasından sonraki sonuçları gösterecek şekilde güncellendi. Aynı şifre ve aynı anahtar kullanılır. – Morten

cevap

5

İlk not, bu kodda önemli güvenlik sorunlarınız olduğunu unutmayın. Bir dize şifresi alıyorsun ve bunu bir anahtarın içine bırakıyorsun. Eğer bu insan-yazılabilir dizge ise, o zaman anahtarınızı önemli ölçüde daraltmış olursunuz (AES-128'i AES-40 ya da AES-50 gibi daha fazla, belki daha da kötüsü). PBKDF2'yi kullanarak anahtarı tuzlamanız ve germeniz gerekir. Daha kapsamlı bir tartışma için bkz. Properly encrypting with AES with CommonCrypto.

Ayrıca önemli bir güvenlik sorununuz var, çünkü anahtarınızı IV olarak kullanıyorsunuz (daha fazla aşağıya bakın; bu aslında sizin belirtinizin sebebidir). Bu, bir IV seçip şifreli metninizi tahmin edilebilir hale getirmenin doğru yolu değildir. Aynı anahtar ile şifrelenmiş aynı düz metin aynı sonucu verecektir. Bu hiç IV'e sahip olmamakla benzer. IV'ün rastgele olması gerekiyor. Daha fazla tartışma için yukarıdaki bağlantıya bakın.

Şimdi gerçek semptomunuza. Sorun şu ki, anahtarınızı Java ve C# 'da IV olarak kullanıyorsunuz, ancak iOS'taki IV (0, NULL değil) kullanıyorsunuz (IV opsiyonel değil; sadece 0 geçiyorsunuz). Her durumda aynı IV'ü kullanmanız gerekir.

+0

Bazı güvenlik sorunları olduğunu biliyorum, ancak bu yalnızca geçici bir çözümdür. Bu sadece hızlı bir düzeltme olacak, böylece nihai çözümümüz bitene kadar okunabilir metinleri geçmeyeceğiz. Şu anda herhangi bir şeyi gerçekten test edemiyorum, çünkü bu işte bir problemdir, ancak eğer doğru bir şekilde anlarsam, aşağıdakileri değiştirdiyse düzeltilmelidir: C# -decryption: rijndaelCipher.IV = X; Java şifrelemede: IvParameterSpec ivSpec = yeni IvParameterSpec (X); ... ve NULL parametresini X değerine dönüştürdünüz, burada X ofcause aynı değerdir? Bu arada, cevabınız için çok teşekkür ederim ... – Morten

+0

Yukarıdaki kodunuzda "X" şu anda her yerde ama iOS bir anahtar kopyasıdır. Ya iOS'ta anahtar olabilir ya da C# ve Java'nın 0 olmasını sağlayabilirsiniz. Ben bir statik değer (0'dan başka) yapmazdım. –

+0

Tamam, yardımlarınız için çok teşekkür ederim. Yarın deneyeceğim ve cevabınızı da "kabul" olarak işaretleyeceğim ... – Morten