2017-10-19 36 views
1

나는 손에 문제가 파이썬 AES 암호 해독과 함께 작동하지 않습니다 바이트로 RFC2898에서 파생 된 소금과 암호를 사용하여 AES로 암호화 된 메시지, '암호'및 유도 된 IV가 뒤 따른다. "이것은이다 : 샘플 메시지는 C# 코드이 메시지는 C# 코드를C#을 RFC2898DeriveBytes 작동되지만, 파이썬 PBKDF2 키 생성 및 IV는 AES가 사양이 암호문을 구성 를 따르고 있습니다 암호문을 암호화 해독하는

private static readonly int SALT_SIZE = 256; 
public static void Decrytor(){ 
// Encrypted Message 
      var cipherText = "i+EKwmlAF0VYh4GwDd+bGf3+yreYsPJW2Oq/w9FXjsp7RI3VqRiqtnqiAD4n6U0JJSTe2ct4B7lgrG+dHxeGcXYEYIERXvU0xnUdH+z3mRwmgYOqCU9HRUKy/z3GKISTm8qH030KTYm3YMBjnKpU8gaRcoDPP/nCiB3o5fPdyspgJgT/qt5BuvwYq7n0qg6ez/Wi4447gq/qHwG3wuuYLSBUCfmIkgGaO1KXqv3SsR8EAhrmMBmPDJfjc3sydNqs5B8J9/JvZFEZULTb8rLQZKQvgHhH9/53Bzs3zmoq0RFbgSueUbyeWb9rLAzYieTz8Yj0srG4GtwPrTPoItc6/hvx5stZ6pX8tgyk9Y3baT0JFMtGgxve7yduy8idTCQdAwRc5NOo4+CBk7P/sIw6+Q=="; 
      var key = "password"; 
      // Extract the salt from our cipherText 
      var allTheBytes = Convert.FromBase64String(cipherText); 
      var saltBytes = allTheBytes.Take(SALT_SIZE).ToArray(); 
      var cipherTextBytes = allTheBytes.Skip(SALT_SIZE).Take(allTheBytes.Length - SALT_SIZE).ToArray(); 

      var keyDerivationFunction = new Rfc2898DeriveBytes(key, saltBytes); 
      // Derive the previous IV from the Key and Salt 
      var keyBytes = keyDerivationFunction.GetBytes(32); 
      var ivBytes = keyDerivationFunction.GetBytes(16); 

      // Create a decrytor to perform the stream transform. 
      // Create the streams used for decryption. 
      // The default Cipher Mode is CBC and the Padding is PKCS7 which are both good 
      var aesManaged = new AesManaged(); 
      var decryptor = aesManaged.CreateDecryptor(keyBytes, ivBytes); 
      var memoryStream = new MemoryStream(cipherTextBytes); 
      var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read); 
      var streamReader = new StreamReader(cryptoStream); 

      // Return the decrypted bytes from the decrypting stream. 
      Console.WriteLine("\n{0}\n", streamReader.ReadToEnd()); 
     } 

출력을 다음과 같이 잘 해독되는 을 사용하여 암호화 및 암호입니다"암호 "는"이것은 내 비밀 문자열가 lorem ipsum의가있다 "입니다 내 비밀 문자열가 lorem ipsum의 "

하지만 Python2.7 해당 구현에 따라 메시지를 해독 할 때, 그것은 제대로

import base64 
from Crypto.Cipher import AES 
from Crypto.Protocol import KDF 

def p_decrypt(self, text): 
    text_dec = base64.b64decode(text) 
    salt = text_dec[:256] 
    enc_txt = text_dec[256:] 
    key_bytes = KDF.PBKDF2(self.key, salt, dkLen=32) 
    iv = KDF.PBKDF2(self.key, salt) 
    cipher = AES.new(key_bytes, AES.MODE_CBC, iv) 
    return cipher.decrypt(enc_txt) 
을 처음 몇 글자를 해독하지 않습니다

출력은 다음과 같습니다 "增"J "t 문자열가 lorem ipsum의"

예상 출력 :

나는 "이것은 내 비밀 문자열가 lorem ipsum의는" 문제를 찾으려고했는데, C# RFC2898DeriveBytes 메서드에 의해 생성 된 keyBytes 및 IV를 사용하여 파이썬 코드도 작동하지만 파이썬 코드는 PBKDF2를 사용하여 전체 메시지를 올바르게 해독하지 않습니다. keyBytes 및 IV가 생성되었습니다.

C# 1 RFC2898DeriveBytes 및 파이썬 PBKDF2 둘 것은 HMACSHA1 해싱 ALGO 그러나 C#의 RFC2898DeriveBytes 방법은 다른 keyBytes를 생성 및 Python PBKDF2 반면 IV는 IV 호 대해 생성 keyBytes의 처음 16 바이트를 반환하여 keyBytes 생성된다.

이 문제에 대한 유용한 가이드 라인을 제공합니다.

감사합니다, M Umer

+0

이것은 초기화 벡터를 생성하는 적절한 방법이 아닌 ** **입니다. ** IV는 고유해야하며 비밀이 아니어야합니다. ** CPRNG를 사용하여 IV를 생성하고 (RNGCryptoServiceProvider 참조) 암호화 된 메시지 앞에 추가해야합니다. –

+0

(분명히 위의 내용은 ** 암호화 키가 단 한 번 사용 된 경우 ** 중요하지 않습니다.) –

답변

1

Rfc2898DeriveBytes 그래서 두 개의 연속 호출을 연결하여 함께 추가 모두 길이가 하나의 호출을하는 것과 동일, 스트리밍 응답 개체입니다.

var pbkdf2WithTwoCalls = new Rfc2898DeriveBytes(...) 
var pbkdf2WithOneCall = new Rfc2898DeriveBytes(sameParametersAsAbove); 

byte[] twoCallA = pbkdf2WithTwoCalls.GetBytes(32); 
byte[] twoCallB = pbkdf2WithTwoCalls.GetBytes(16); 

byte[] oneCall = pbkdf2WithOneCall.GetBytes(32 + 16); 

if (!oneCall.SequenceEquals(twoCallA.Concat(twoCallB)) 
    throw new TheUniverseMakesNoSenseException(); 

그래서 파이썬에서 솔루션은, PBKDF2 한 48 바이트 통화를하는 32 바이트 AES 키와 16 바이트 IV으로 분할한다.

암호 해독 응답은 키가 정확하지만 IV가 아니라는 것을 나타냅니다.

+0

위의 파이썬 코드는 키의 처음 16 바이트를 IV로 사용합니다. ** 이것이 암호화에 사용되면 프로세스의 키 절반이 새어 나옵니다! ** 이제이 코드의 또 다른 문제점을 지적합니다. IV가 기본적으로 암호를 사용하기 때문에 기본적으로 IV를 쓸모 없게 만듭니다 , 열쇠처럼. ** IV는 논스 (nonces)를 의미합니다 ** 이것은 한 번만 사용해야 함을 의미합니다. 또한 비밀로 유지되는 것이 아니므로 대개 메시지의 일부입니다. –

+0

@ErwanLegrand Encryption은 IV의 첫 번째 16 바이트를 IV로 사용하지 않습니다. "암호화하는 데 사용 된 경우 프로세스의 키 절반이 누출됩니다!" –

+0

@bartonjs, 그것은 작동, 당신은 정말 내 시간을 절약, 감사합니다 :) –