2017-01-10 18 views
5

私の目標は、AESがPowerShellで文字列を暗号化し、利用可能なPythonでUNIXシステムに送信し、その文字列をプレーンテキストに復号化することです。私はその逆をすることもできるようにしたいと思います。私は暗号男やPowerShellの/ Pythonプログラマではないけど、これは私がこれまでのコードで行うことができたものです: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" 

PowerShellスクリプトは、暗号化と復号化に正常に動作しているようです。 Python側では、私の鍵のパスフレーズのbase64でエンコードされているだけなので、同じAES鍵の値を定義できます。しかし、実行時に文字列の暗号化された同じ値を取得しません(たとえば、PowerShellはUXKWIhtaUgFOvN13bvA4tx4 + 2Hjkv4v6I1G3Xfl6zp0 =とPython出力BOJ3Ox4fJxR + jFZ0CBQ25Q ==を出力します)。復号化できるようにするには一致させる必要があると思いますが、誤解を招く可能性があります。私は静的なIVとキーを設定することは安全ではないことを知っていますが、AESを使用した方が良い方法がない限り、プラットフォーム間で暗号化と復号化を行うためにはやりたいです。どんな助けもありがとう。

Pythonコード

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兆,000億を超える)しか使用できません。実際には、キーサイズを256ビットに設定しています。明らかに、コードはそれを無視している/エラーなしで192ビットキーを許可しています。

    生の文字列のBase64変換ではなく、Rfc2898DeriveBytesを使用してAESキーを取得します。 RFC 2898は、パスワードから暗号鍵を安全に導出するためのHMACベースの鍵導出関数であるPBKDF2(Password-Based Key Derivation Function 2)を定義し、高い反復回数で使用されるHMAC/SHA1に鍵に対するブルートフォース攻撃を軽減する。

  2. PowerShellで暗号化と復号化を行う場合にのみTransformFinalBlock()を呼び出します。私は、メッセージが1ブロック(16バイト)よりも長い場合、これが完全なメッセージの暗号化または復号化に失敗すると考えています。 This is a plaintext message.(29バイト)のような入力メッセージでこれを試してみてください。 TransformBlock()TransformFinalBlock()の両方を使用したいと考えています。

  3. 静的なIVは安全ではありません(同じキーを使用するすべての暗号化操作で一意で予測不可能なIVの目的に反します)。 AesManagedは既に満足のいくIVを生成するためのメソッドGenerateIV()を提供しています。これはIVプロパティからアクセスして、暗号テキストの前に追加することができます。

  4. Base64でエンコードされた暗号テキストのPowerShell出力は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)を使用する必要があります。暗号化キーよりもの暗号テキストにメッセージ認証コード(MAC)をの別の共有秘密のHMAC/SHA-256などのHMAC構造を使用して指定し、一定時間でMAC を確認してください方法の前に復号化を試みます。

+1

おかげで、私は援助を感謝しています。私はいくつかの提案に基づいてPythonスクリプトを調整し、静的IVを削除しました。私は、PowerShellの出力をデコードできるPythonスクリプトを持っていることを知っています。私は他の提案も実装するつもりです。 –

+0

@MichaelWilliams私はあなたが答えをアップヴォートするべきだと思います。あなたがそれを受け入れたら、それはおそらく投票に値するということです。 – xverges

+0

申し訳ありません、新しいスタックオーバーフローです。私はそれが今upvotedされるべきだと思います。 –