2017-01-10 6 views
5

내 목표는 AES가 PowerShell에서 문자열을 암호화하고 Python을 사용하여 UNIX 시스템으로 보내고 문자열을 일반 텍스트로 다시 해독 할 수있게하는 것입니다. 나는 또한 역관계를 할 수 있기를 바랄 것이다. 나는 암호화 사람 또는 PowerShell을/파이썬 프로그래머 아니지만, 이것은 내가 지금까지 코드와 함께 할 수 있었던 것입니다 :PowerShell 및 Python의 AES 암호화

function Create-AesManagedObject($key, $IV) { 
    $aesManaged = New-Object "System.Security.Cryptography.AesManaged" 
    $aesManaged.Mode = [System.Security.Cryptography.CipherMode]::CBC 
    $aesManaged.Padding = [System.Security.Cryptography.PaddingMode]::Zeros 
    $aesManaged.BlockSize = 128 
    $aesManaged.KeySize = 256 
    if ($IV) { 
     if ($IV.getType().Name -eq "String") { 
      $aesManaged.IV = [System.Convert]::FromBase64String($IV) 
     } 
     else { 
      $aesManaged.IV = $IV 
     } 
    } 
    if ($key) { 
     if ($key.getType().Name -eq "String") { 
      $aesManaged.Key = [System.Convert]::FromBase64String($key) 
     } 
     else { 
      $aesManaged.Key = $key 
     } 
    } 
    $aesManaged 
} 

function Encrypt-String($key, $unencryptedString) { 
    $bytes = [System.Text.Encoding]::UTF8.GetBytes($unencryptedString) 
    $aesManaged = Create-AesManagedObject $key $IV 
    $encryptor = $aesManaged.CreateEncryptor() 
    $encryptedData = $encryptor.TransformFinalBlock($bytes, 0, $bytes.Length); 
    [byte[]] $fullData = $aesManaged.IV + $encryptedData 
    $aesManaged.Dispose() 
    [System.Convert]::ToBase64String($fullData) 
} 

function Decrypt-String($key, $encryptedStringWithIV) { 
    $bytes = [System.Convert]::FromBase64String($encryptedStringWithIV) 
    $IV = $bytes[0..15] 
    $aesManaged = Create-AesManagedObject $key $IV 
    $decryptor = $aesManaged.CreateDecryptor(); 
    $unencryptedData = $decryptor.TransformFinalBlock($bytes, 16, $bytes.Length - 16); 
    $aesManaged.Dispose() 
    [System.Text.Encoding]::UTF8.GetString($unencryptedData).Trim([char]0) 
} 

# key passphrase is a 16 byte string that is used to create the AES key. 
$key_passphrase = "MypassphraseKey1" 
# base64 encode the key. The resulting key should be exactly 44 characters (43 characters with a single = of padding) (256 bits) 
$Bytes = [System.Text.Encoding]::Ascii.GetBytes($key_passphrase) 
$key =[Convert]::ToBase64String($Bytes) 

# init is used to create the IV 
$init = "This is an IV123" 
# converts init to a byte array (e.g. T = 84, h = 104) and then sha1 hash it 
$IV = (new-Object Security.Cryptography.SHA1Managed).ComputeHash([Text.Encoding]::UTF8.GetBytes($init))[0..15] 
write-output "IV is equal to $IV" 


write-output "AES key is $key" 
$unencryptedString = "testing" 
$encryptedString = Encrypt-String $key $unencryptedString 
$backToPlainText = Decrypt-String $key $encryptedString 

write-output "Unencrypted string: $unencryptedString" 
write-output "Encrypted string: $encryptedString" 
write-output "Unencrytped string: $backToPlainText" 

파워 쉘 스크립트는 암호화 및 암호 해독을 위해 잘 작동하는 것 같군. 파이썬 쪽에서는 AES 키 값을 정의 할 수 있습니다. 이는 내 키의 암호 구문을 base64로 인코딩 한 것입니다. 그러나 실행시 문자열의 암호화 된 값이 동일하지 않습니다 (예 : PowerShell 출력 UXKWIhtaUgFOvN13bvA4tx4 + 2Hjkv4v6I1G3Xfl6zp0 = 및 Python 출력 BOJ3Ox4fJxR + jFZ0CBQ25Q ==). 나는 이것들이 해독 할 수 있기 위해서 이들을 일치시킬 필요가 있다고 믿지만 나는 오해 할 수있다. 나는 정적 인 IV와 키를 설정하는 것이 안전하지 못하다는 것을 알고 있지만, AES를 사용하는 더 좋은 방법이 없다면, 플랫폼간에 암호화하고 해독 할 수 있도록하기 위해 기꺼이하겠다. 어떤 도움을 주시면 감사하겠습니다.

파이썬 코드

import base64, array 
import Crypto 
import Crypto.Random 
from Crypto.Cipher import AES 

def pad_data(data): 
    if len(data) % 16 == 0: 
     return data 
    databytes = bytearray(data) 
    padding_required = 15 - (len(databytes) % 16) 
    databytes.extend(b'\x80') 
    databytes.extend(b'\x00' * padding_required) 
    return bytes(databytes) 

def unpad_data(data): 
    if not data: 
     return data 

    data = data.rstrip(b'\x00') 
    if data[-1] == 128: # b'\x80'[0]: 
     return data[:-1] 
    else: 
     return data 

def encrypt(key, iv, data): 
    aes = AES.new(key, AES.MODE_CBC, iv) 
    data = pad_data(data) 
    return aes.encrypt(data) 

def decrypt(key, iv, data): 
    aes = AES.new(key, AES.MODE_CBC, iv) 
    data = aes.decrypt(data) 
    return unpad_data(data) 

def test_crypto(): 
    key = "MypassphraseKey1" 
    # found using the debugger in the PowerShell ISE to get the value byte value which was converted to hex 
    iv = "\x51\x72\x96\x22\x1b\x5a\x52\x01\x4e\xbc\xdd\x77\x6e\xf0\x38\xb7" 
    msg = b"testing" 

    # hex value of IV in powershell script is 51 72 96 22 1b 5a 52 01 4e bc dd 77 6e f0 38 b7 
    print("Value of IV: " + iv) 

    # base64 encode key 
    b64key = base64.b64encode(key) 
    print("AES key encoded: " + b64key) 

    code = encrypt(key, iv, msg) 
    # convert encrypted string to base64 
    b64encoded = base64.b64encode(code) 
    print("Encrypted string: " + b64encoded) 

    decoded = decrypt(key, iv, code) 
    print("Decoded: " + decoded) 

if __name__ == '__main__': 
    test_crypto() 

답변

4

몇 가지 제안 :

  1. 16 문자 ASCII 문자열 128^16 = 5.19229686e33 가능 키 입력합니다. Base64 인코딩 16 바이트는 24 바이트 (4*ceil(16/3))를 생성합니다. 따라서 192 비트 AES 키 (이론적으로 6.27710174e57 키 조합)를 사용하더라도 1/1208925820422879877545683 (1 조 조 조원에 1 개) 만 사용할 수 있습니다. 실제로 키 크기를 256 비트로 설정하면 코드가이를 무시하고 192 비트 키를 오류없이 허용합니다.

    원시 문자열의 Base64 변환보다는 AES 키를 추출하는 데 Rfc2898DeriveBytes을 사용하십시오. RFC 2898은 암호에서 암호화 키를 안전하게 파생시키기위한 HMAC 기반의 키 유도 함수 인 PBKDF2 (암호 기반 키 유도 함수 2)를 정의하고 높은 반복 횟수로 사용되는 HMAC/SHA1에 대해 키에 대한 무차별 대입 공격을 완화합니다 .

  2. PowerShell에서 암호화 및 암호 해독시에만 TransformFinalBlock()을 호출합니다. 메시지가 한 블록 (16 바이트)보다 긴 경우 전체 메시지를 암호화하거나 해독하지 못한다고 생각합니다. This is a plaintext message. (29 바이트)과 같은 입력 메시지로 시도해보십시오. TransformBlock()TransformFinalBlock()을 모두 사용하고 싶습니다.

  3. 정적 IV가 안전하지 않다는 점에 틀림 없습니다 (동일한 키로 모든 암호화 작업에 대해 고유하고 예측할 수없는 IV의 목적을 무효화). AesManaged은 이미 만족스러운 IV를 생성하는 방법 GenerateIV()을 제공합니다. IV 속성에서 액세스하여 암호문 앞에 추가 할 수 있습니다.

  4. PowerShell 출력의 Base64 인코딩 암호 텍스트는 44 자 (Base64의 경우 16 byte IV + 16 byte ciphered message = 32 bytes -> 44 bytes)입니다. Python Base64 출력은 24 자입니다 (Base64에서 16 bytes -> 24 bytes). 이 출력은 IV 또는 메시지를 포함하지 않습니다 (또는 제한된 출력에 대한 다른 덜 이유). 코드를 보면 encrypt 메서드는 IV를 암호문 앞에 붙이지 않습니다.

  5. 마지막으로이 시점에서 코드는 제대로 작동하고 내부적으로 일관성 있고 상호 호환 가능해야합니다.여기 몇 가지 설계 결정을 다시해야합니다

    • 제로 패딩이 아닌 표준이며 수동으로 구현 한 반면, PKCS #5/#7 같은 잘 정의 된 패딩 방식이 더 바람직하다. Python과 .NET에서이를 구현하기위한 풍부한 구현과 코드 예제가 있습니다.

    • CBC block cipher mode of operation을 사용하고 있습니다. CBC는 기밀성에 대해서는 문제가 없지만 무결성을 제공하지는 않습니다. GCM 또는 EAX와 같은 인증 된 암호화 모드 (AE/AEAD)를 사용해야합니다. 그렇지 않은 경우 암호문을 통해 암호화 키보다 이 다른 공유 암호가있는 HMAC/SHA-256 같은 HMAC 구성을 사용하고 일정 시간 동안 MAC 을 확인하십시오. 방법전에 복호화를 시도합니다.

+1

덕분에, 나는 도움을 주셔서 감사합니다. 일부 제안 사항을 기반으로 파이썬 스크립트를 조정하고 정적 IV를 제거했습니다. PowerShell 출력을 디코딩 할 수있는 파이썬 스크립트가 있고 그 반대도 마찬가지입니다. 나는 다른 제안들도 구현하려고 노력할 것이다. –

+0

@MichaelWilliams 나는 당신이 대답을 upvote해야한다고 생각한다 : 당신이 그것을 받아 들인다면 그것은 아마도 투표권이 있다는 뜻이다. – xverges

+0

죄송합니다. 스택 오버플로가 발생했습니다. 나는 그것이 지금 upvoted되어야한다고 생각한다. –