2015-11-17 116 views
2

我在加密/解密交叉語言時遇到了一些問題。Python AES加密填充導致C#解密中的問題

這裏是我的Python代碼一些文本加密:

class AESCipher: 
    def __init__(self, key, iv): 
     self.key = base64.b64decode(key) 
     self.iv = base64.b64decode(iv) 
    def encrypt(self, raw): 

     BS = 16 
     pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS) 
     raw = pad(raw) 


     cipher = AES.new(self.key, AES.MODE_CBC, self.iv) 
     res = self.iv + cipher.encrypt(raw) 
     return base64.b64encode(res) 

    def decrypt(self, enc): 
     enc = base64.b64decode(enc) 
     unpad = lambda s : s[:-ord(s[len(s)-1:])] 
     cipher = AES.new(self.key, AES.MODE_CBC, self.iv) 
     return unpad(cipher.decrypt(enc[16:])) 

crypt = AESCipher("key", "iv") 
print "{0}".format(crypt.encrypt("Hallow")) 

和C#解密:

public static string DecryptStringFromBase64(string base64String) 
{ 
    byte[] bytes = Decrypt(Convert.FromBase64String(base64String)); 
    var utf8 = Encoding.UTF8.GetString(bytes); 
    return utf8; 
} 

public static byte[] Decrypt(byte[] bytes) 
{ 
    AesManaged algorithm = new AesManaged(); 
    algorithm.IV = Convert.FromBase64String("IV"); 
    algorithm.Key = Convert.FromBase64String("KEY"); 

    byte[] ret = null; 
    using (var decryptor = algorithm.CreateDecryptor()) 
    { 
     using (MemoryStream msDecrypted = new MemoryStream()) 
     { 
      using (CryptoStream csEncrypt = new CryptoStream(msDecrypted, decryptor, CryptoStreamMode.Write)) 
      { 
       csEncrypt.Write(bytes, 0, bytes.Length); 
      } 
      ret = msDecrypted.ToArray(); 
     } 
    } 
    return ret; 
} 

然而解密值永遠是不正確的是這樣的:

decrypted text with garbage at the start

我覺得這跟這個有關係填充,有人可以建議如何解決這個問題嗎?

回答

4

問題不是填充。這是你沒有切掉的IV。 IV不必是保密的,但它應該隨機生成每個加密。既然你已經包括了四成Python的密文,你有解密過程中使用它在C#中(當然解密,應在排除IV實際的密文進行):

C#

public static string DecryptStringFromBase64(string base64String) 
{ 
    byte[] bytes = Decrypt(Convert.FromBase64String(base64String)); 
    var utf8 = Encoding.UTF8.GetString(bytes); 
    return utf8; 
} 

public static byte[] Decrypt(byte[] bytes) 
{ 
    byte[] iv = new byte[16]; // change 
    Array.copy(bytes, iv, 16); // change 
    AesManaged algorithm = new AesManaged(); 
    algorithm.IV = iv; // change 
    algorithm.Key = Convert.FromBase64String("KEY"); 

    byte[] ret = null; 
    using (var decryptor = algorithm.CreateDecryptor()) 
    { 
     using (MemoryStream msDecrypted = new MemoryStream()) 
     { 
      using (CryptoStream csEncrypt = new CryptoStream(msDecrypted, decryptor, CryptoStreamMode.Write)) 
      { 
       csEncrypt.Write(bytes, 16, bytes.Length - 16); // change 
      } 
      ret = msDecrypted.ToArray(); 
     } 
    } 
    return ret; 
} 

Python代碼也不是沒有問題。你不需要傳入IV,因爲你將它放入密文中。所以你可以創建一個新的隨機IV。此外,unpad功能不正確(或至少不必要的複雜)。

class AESCipher: 
    def __init__(self, key): 
     self.key = base64.b64decode(key) 

    def encrypt(self, raw): 

     BS = 16 
     pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS) 
     raw = pad(raw) 

     iv = Random.new().read(BS) 

     cipher = AES.new(self.key, AES.MODE_CBC, iv) 
     res = iv + cipher.encrypt(raw) 
     return base64.b64encode(res) 

    def decrypt(self, enc): 
     enc = base64.b64decode(enc) 
     BS = 16 
     iv = enc[:BS] 
     unpad = lambda s : s[:-ord(s[-1])] 
     cipher = AES.new(self.key, AES.MODE_CBC, iv) 
     return unpad(cipher.decrypt(enc[BS:])) 

crypt = AESCipher("key", "iv") 
print "{0}".format(crypt.encrypt("Hallow")) 

不要忘記驗證您的密文。否則,可能會針對您的系統啓動填充oracle攻擊,從而使攻擊可以通過多個在線查詢解密每個密文。

可以使用經認證的模式,如GCM或EAX,或者採用具有很強的MAC像HMAC-SHA256一個加密-然後-MAC方案。

+0

我這給了一個鏡頭和線'csEncrypt.Write(字節,16,bytes.Length); //更改'拋出錯誤: '在mscorlib.dll中發生類型'System.ArgumentException'的未處理異常 附加信息:偏移量和長度超出數組的邊界或者計數大於元素的數量從索引到源集合的末尾.' – TomSelleck

+0

對不起,我認爲第三個參數是結束索引,但它是一個計數。它現在應該工作。 –

+0

工作對我很好,謝謝,只需要改變'algorithm.Key = Convert.FromBase64String(「KEY」);''algorithm.Key = Encoding.UTF8.GetBytes(key);' – Milen