Aes256-cbc 编码/解密错误

Aes256-cbc 编码/解密错误

我一直在使用 gibberish.aes javascript 代码来加密一些字符串,但是当使用诸如 £ 或 á 之类的密码时,openssl 命令行不想解密它并会产生随机性,但它在 javascript 本身中运行良好,有人知道这里发生了什么吗?

例子:

加密文件:U2FsdGVkX18EWZNx70TPi0dYuiQG+7Zpg5RiGa2/mQsWU4A6JhWMwt3+mP1y6+xIQYN45t65oB+VntZfEd6EArB0X4nPmCJ18jBfO57a1jE=

密码:password£

答案1

有多种方法可以将这些字符表示为字节 - 例如,字母“š”{c5 a1}在使用 UTF-8(JavaScript 使用)编码时变为,但它也可以是{f0}ISO-8859-13 或 Windows-1257,或{61 01}UTF-16LE。

因此,您需要确保始终使用相同的文本编码来存储密码(最好是 UTF-8)。具体怎么做取决于编程语言和加密库。某些 API 要求以字节数组形式提供密码,原因正是如此 — 强制开发人员选择特定的编码。

在源代码文件(.py 等)中直接指定带重音字符的密码时,文本编辑器会将它们编码为字节 - 确保您知道它使用的编码,并尽可能尝试使用 UTF-8。如果不可能,请使用\x\u转义来编写带重音字符。例如(Py2/Py3):

passphrase = u"password£".encode("utf-8")

passphrase = u"password\u00A3".encode("utf-8")

passphrase = b"password\xC2\xA3"        # byte array – already encoded

在某些语言中,编译器/解释器将再次解码源文件,因此请确保它知道编辑器使用了什么编码(例如,在 Python 中# encoding: utf-8在顶部添加一行)。

当直接在命令行上工作时,从按键到字节的编码由你的终端应用程序,因此请确保它处于 UTF-8 模式。命令行 shell (bash) 也应该有 $LANG 告诉它使用 UTF-8。(终端内运行的所有程序都已接收一系列字节;它们无法控制终端使用的编码。)

如果有疑问,请尝试将密码发送到“hexdump”工具,hd例如xxd

  • 良好 (UTF-8):

    $ echo -n password£á | hexdump -C
    00000000  70 61 73 73 77 6f 72 64 c2 a3 c3 a1              |password....|
    
  • 错误(ISO-8859-1):

    $ echo -n password£á | hexdump -C
    00000000  70 61 73 73 77 6f 72 64 a3 e1                    |password..|
    

我使用以下方法测试了您的输入:

echo "U2FsdGVkX18EWZNx70TPi0dYuiQG+7Zpg5RiGa2/mQsWU4A6JhWMwt3+mP1y6+xIQYN45t65oB+VntZfEd6EArB0X4nPmCJ18jBfO57a1jE=" \
  | base64 -d \
  | openssl enc -aes-256-cbc -d -md md5 -k "password£"

也:

#!/usr/bin/env python3

from base64 import b64decode
from Crypto.Hash import MD5
from Crypto.Cipher import AES

def OpenSSL_parse_enc_header(data):
    if data[0:8] != b"Salted__":
        raise ValueError("missing OpenSSL header")
    salt = data[8:16]
    data = data[16:]
    return salt, data

def OpenSSL_EVP_BytesToKey(passphrase, salt, key_size, iv_size):
    buf = b""
    hash = b""
    while len(buf) < key_size + iv_size:
        hash = MD5.new(hash + passphrase + salt).digest()
        buf += hash
    key = buf[0:key_size]
    iv = buf[key_size:key_size+iv_size]
    return key, iv

def PKCS7_remove_padding(data, block_size):
    if len(data) % block_size != 0:
        raise ValueError("data is not padded")
    pad_len = data[-1]
    if pad_len < 1 or pad_len > block_size:
        raise ValueError("PKCS#7 padding incorrect")
    if data[-pad_len:] != bytes([pad_len] * pad_len):
        raise ValueError("PKCS#7 padding incorrect")
    return data[:-pad_len]

enc_data = b64decode("U2FsdGVkX18EWZNx70TPi0dYuiQG+7Zpg5RiGa2/mQsWU4"
                     "A6JhWMwt3+mP1y6+xIQYN45t65oB+VntZfEd6EArB0X4nP"
                     "mCJ18jBfO57a1jE=")
kdf_salt, enc_data = OpenSSL_parse_enc_header(enc_data)

passphrase = "password£".encode("utf-8")
key, iv = OpenSSL_EVP_BytesToKey(passphrase,
                                 kdf_salt,
                                 key_size=256//8,
                                 iv_size=AES.block_size)

plain_data = AES.new(key, AES.MODE_CBC, iv=iv).decrypt(enc_data)
plain_data = PKCS7_remove_padding(plain_data, AES.block_size)
print(plain_data)

在两种情况下,它都会返回此文本(具有有效的 PKCS#7 填充,因此解密成功):

L3scoV8yhgA9tqbXBA2SXTczghGUSGTDsWkakCwgK6jk13TAUfXi

相关内容