【问题标题】:Decrypting AES CBC data from PyCrypto with Powershell使用 Powershell 从 PyCrypto 解密 AES CBC 数据
【发布时间】:2018-05-13 18:41:34
【问题描述】:

我正在做一个项目,我将使用 PyCrypto 的 AES 模块加密一串数据,然后使用 Powershell 对其进行解密。

我写了一个简单的加密函数来做我需要的:

import base64

from Crypto import Random
from Crypto.Cipher import AES

key = "SuperSecret" #Insecure and just for testing
plaintext = "Secret message please don't look"

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

def padKey(s): #Pad key to 32 bytes for AES256
    return (s * (int(32/len(s))+1))[:32]

class AESCipher:

    def __init__(self, key):
        self.key = key

    def encrypt(self, raw):
        raw = pad(raw)
        iv = Random.new().read( AES.block_size )
        cipher = AES.new( self.key, AES.MODE_CBC, iv )
        return base64.b64encode( iv + cipher.encrypt( raw ) )

paddedKey = padKey(key)
cipher = AESCipher(paddedKey)

encrypted = str(cipher.encrypt(plaintext))
encrypted = encrypted[2:-1]

print("Key:", paddedKey)
print("Plaintext:",plaintext)
print("Encrypted and B64:",encrypted)

我在使用 Powershell 解密和解码输出时遇到了一些问题,我需要一些帮助。我能够找到一个我一直在在线使用的简单解密脚本,但输出都是垃圾:

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

示例输出:

PS C:\> Decrypt-String 'SuperSecretSuperSecretSuperSecre' $encryptedString
���H�'G zM۞� �i�ZtCI���H~N�GG��A�Pc��aF��`)��GS�N�2{�[.

相关:Using PowerShell to decrypt a Python encrypted String

【问题讨论】:

  • 见此行:if ($key.getType().Name -eq "String") {。因此,base64 编码您的密钥(字符串)或使用字节。
  • 你好!我刚刚尝试将 B64 编码的密钥传递给 Powershell 函数,但输出仍然失败。
  • 抱歉,我已经用 'U3VwZXJTZWNyZXRTdXBlclNlY3JldFN1cGVyU2VjcmU=' 作为键测试了你的 powershell 代码,我得到了你的 Python 的 plaintext 字符串作为结果(加上一些垃圾,因为不同的填充方法 - 请参阅 Maarten 的 answer
  • 成功了!非常感谢!

标签: python powershell encryption aes pycrypto


【解决方案1】:

用解决方案解决这个问题(感谢@Maarten 和@t.m.adam)。这个问题是双重的。首先,密钥需要以 Base64 格式传递给 Powershell,并且我需要的填充移至 PKCS7。最终代码如下:

Python 加密:

import base64

from Crypto import Random
from Crypto.Cipher import AES

key = "SuperSecret" #Insecure and just for testing
plaintext = "Secret message please don't look"

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

def padKey(s): #Pad key to 32 bytes for AES256
    return (s * (int(32/len(s))+1))[:32]

class AESCipher:

    def __init__(self, key):
        self.key = key

    def encrypt(self, raw):
        raw = pad(raw)
        iv = Random.new().read( AES.block_size )
        cipher = AES.new( self.key, AES.MODE_CBC, iv )
        return base64.b64encode( iv + cipher.encrypt( raw ) )

paddedKey = padKey(key)
cipher = AESCipher(paddedKey)

encrypted = str(cipher.encrypt(plaintext))
encrypted = encrypted[2:-1]

print("Key:", base64.b64encode(paddedKey))
print("Plaintext:",plaintext)
print("Encrypted and B64:",encrypted)

Powershell 解密:

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]::PKCS7
    $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 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)
}

用法:

PS C:> $key = 'U3VwZXJTZWNyZXRTdXBlclNlY3JldFN1cGVyU2VjcmU='
PS C:> $encryptedString = 'Opgtr8XEcvkcYT5UzsFjZR4Wt5DI++fU4Gm0dTM/22m+xyObjP162rFphIS/xkS4I7ErJfshwI7T4X1MNz
wMog=='
PS C:> Decrypt-String $key $encryptedString
Secret message please don't look

【讨论】:

    【解决方案2】:

    在 Python 代码中,以下内容是完全不必要的,应该删除:

    encrypted = str(cipher.encrypt(plaintext))
    encrypted = encrypted[2:-1]
    

    在您的 PowerShell 代码中,您需要使用 PKCS7 而不是 Zeros 进行填充。

    在 PowerShell 代码中,您不会在任何地方使用零来实现键填充。这是必需的(如果没有它,我不确定你如何让它工作)。

    【讨论】:

    • 嘿!感谢您的回复。该切片只是为了删除一些 Python 格式,因为 B64 字符串的输出类似于b'<...>'。至于 PKCS7 填充,会引发一个新错误,"Padding is invalid and cannot be removed."。我也不确定您所说的键盘填充是什么意思。
    • 好吧,我没有在 Python 代码中编写 padKey 方法来进行零填充。而且我也看不到您如何在 PowerShell 代码中加载/生成密钥。
    • padKey 函数只是重复密钥直到它长 32 个字节(即 'secret' -> 'secretsecretsecretsecretsecretse')。密钥通过命令行参数与编码和加密数据一起传递给 Powershell 解密器函数。
    • 只要你 100% 确定它是正确的,否则你可能会像现在这样把垃圾拿回来。打印出 Python 和 PowerShell 代码的十六进制密钥并进行比较!密钥通常不包含字符,顺便说一下,您可以改用基于密码的加密 (PBE)。
    • 所以连同@t.m.adam 评论,改变填充似乎已经做到了!感谢您的帮助!
    猜你喜欢
    • 2013-08-11
    • 1970-01-01
    • 1970-01-01
    • 2010-10-28
    • 2015-08-22
    • 1970-01-01
    • 1970-01-01
    • 2017-09-28
    • 1970-01-01
    相关资源
    最近更新 更多