2017-01-10 3 views
5

Mein Ziel ist es, in AES eine Zeichenfolge in PowerShell verschlüsseln zu können, sie an ein UNIX-System mit verfügbarem Python zu senden und die Zeichenfolge wieder in reinen Text zu entschlüsseln. Ich würde auch gern in der Lage sein, das Gegenteil zu tun. Ich bin kein Krypto-Typ oder ein Powershell/Python-Programmierer, aber das ist, was ich in der Lage gewesen mit dem Code zu tun, so weit:AES-Verschlüsselung in PowerShell und Python

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" 

Der Powershell-Skript scheint gut für die Verschlüsselung und Entschlüsselung zu arbeiten. Für die Python-Seite kann ich den gleichen AES-Schlüsselwert definieren, da er nur base64-kodiert für die Passphrase meines Schlüssels ist. Allerdings erhalte ich bei der Ausführung nicht den gleichen verschlüsselten Wert der Zeichenfolge (z. B. PowerShell-Ausgaben UXKWIhtaUgFOvN13bvA4tx4 + 2Hjkv4v6I1G3Xfl6zp0 = und Python gibt BOJ3Ox4fJxR + jFZ0CBQ25Q == aus). Ich glaube, dass diese übereinstimmen müssten, um entschlüsseln zu können, aber ich könnte mich irren. Ich weiß, dass das Setzen einer statischen IV und des Schlüssels es unsicher macht, aber ich bin dazu bereit, um plattformübergreifend verschlüsseln und entschlüsseln zu können (es sei denn, es gibt eine bessere Methode, AES zu verwenden). Jede Hilfe wäre willkommen.

Python-Code

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

Antwort

4

Ein paar Vorschläge:

  1. A 16 Zeichen ASCII-String ist 128^16 = 5.19229686e33 möglich Tasteneingaben. Base64-Codierung von 16 Bytes ergibt 24 Bytes (4*ceil(16/3)). Obwohl Sie also einen 192-Bit-AES-Schlüssel verwenden (theoretisch 6.27710174e57 Tastenkombinationen), können Sie nur 1/1208925820422879877545683 [eine über eine Billion Billionen] davon verwenden. Tatsächlich haben Sie die Schlüsselgröße auf 256 Bit festgelegt, und anscheinend ignoriert der Code das/erlaubt den 192-Bit-Schlüssel ohne einen Fehler.

    Verwenden Sie Rfc2898DeriveBytes, um Ihren AES-Schlüssel anstelle einer Base64-Umwandlung einer Raw-Zeichenfolge abzuleiten. RFC 2898 definiert PBKDF2 (Password-Based Key Derivation Function 2), eine HMAC-basierte Schlüsselableitungsfunktion zum sicheren Ableiten von Verschlüsselungsschlüsseln aus Passwörtern und bietet HMAC/SHA1 mit einer hohen Anzahl von Iterationen, um Brute-Force-Angriffe gegen Ihren Schlüssel zu minimieren .

  2. Sie rufen nur TransformFinalBlock() zum Verschlüsseln und Entschlüsseln in PowerShell auf. Ich kann mir vorstellen, dass dies die gesamte Nachricht nicht verschlüsseln oder entschlüsseln kann, wenn die Nachricht länger als ein Block (16 Bytes) ist. Versuchen Sie dies mit einer Eingabe Nachricht wie This is a plaintext message. (29 Bytes). Ich glaube, dass Sie beide TransformBlock() und TransformFinalBlock() verwenden möchten.

  3. Sie haben Recht, dass eine statische IV unsicher ist (vereitelt den Zweck einer IV, die für jeden Verschlüsselungsvorgang mit demselben Schlüssel eindeutig und nicht vorhersehbar sein sollte). AesManaged bietet bereits eine Methode GenerateIV(), um eine zufriedenstellende IV zu generieren, auf die Sie über die IV-Eigenschaft zugreifen und dem Chiffretext voranstellen können.

  4. Ihre PowerShell-Ausgabe des Base64-codierten Verschlüsselungstexts besteht aus 44 Zeichen (16 byte IV + 16 byte ciphered message = 32 bytes -> 44 bytes in Base64). Ihre Python Base64-Ausgabe hat 24 Zeichen (16 bytes -> 24 bytes in Base64). Entweder enthält diese Ausgabe nicht die IV oder die Nachricht (oder einen anderen, weniger wahrscheinlichen Grund für die begrenzte Ausgabe). Wenn Sie den Code betrachten, fügt Ihre encrypt Methode die IV nicht dem Chiffretext voran.

  5. Schließlich sollte zu diesem Zeitpunkt Ihr Code funktionieren und sowohl intern konsistent als auch kompatibel sein.Hier sollten Sie ein paar Design-Entscheidungen überdenken:

    • Zero-padding ist nicht-Standard und während Sie es manuell implementiert haben, eine wohldefinierte Padding-Verfahren wie PKCS #5/#7 ist wünschenswerter. Es gibt zahlreiche Implementierungen und Codebeispiele für die Implementierung in Python und .NET.

    • Sie verwenden die CBC block cipher mode of operation. Während CBC für die Vertraulichkeit gut ist, bietet es keine Integrität. Sie sollten einen authentifizierten Verschlüsselungsmodus (AE/AEAD) wie GCM oder EAX verwenden. Wenn Sie nicht können, stellen Sie einen Message Authentication Code (MAC) über den Verschlüsselungstext bereit, indem Sie eine HMAC-Konstruktion wie HMAC/SHA-256 mit einem gemeinsamen Schlüssel verwenden und den MAC mit einer konstanten Zeit verifizieren Methodevor versucht Entschlüsselung.

+1

Danke, ich schätze die Hilfe. Ich habe das Python-Skript basierend auf einigen Ihrer Vorschläge angepasst und die statische IV entfernt. Ich weiß, dass das Python-Skript in der Lage ist, die Powershell-Ausgabe zu dekodieren und umgekehrt. Ich werde auch an der Umsetzung der anderen Vorschläge arbeiten. –

+0

@MichaelWilliams Ich denke, dass Sie die Antwort auffrischen sollten: Wenn Sie es akzeptierten, bedeutet es wahrscheinlich, dass es eine Stimme verdient. – xverges

+0

Sorry, neu zu Stack-Überlauf. Ich glaube, es sollte jetzt aufgewertet werden. –