使用 AES-256 和 PKCS7 填充加密

Posted

技术标签:

【中文标题】使用 AES-256 和 PKCS7 填充加密【英文标题】:Encrypting with AES-256 and PKCS7 padding 【发布时间】:2017-08-29 04:12:15 【问题描述】:

我想使用 python 来加密一些数据并且遇到了 pycrypto 作为一种可能的工具。为了加密数据,我需要:

    输入密码字符串 SHA-256 字符串,为 AES-256 提供密钥 将敏感数据表示为 9 位字符 (ascii) 的字符串,如果存在,则以 ascii 0 开头(数据将始终采用这种格式)。 在 ecb 模式下使用 AES-256、NO SALT、使用 RFC2315 中的 PKCS7 填充加密数据字符串。 将密文表示为 Base64 (RFC 4648),需要 24 个字符

使用 pycrypto,步骤 1-3 相当简单。 4给我带来了一点麻烦。我不确定 PKCS7 填充是什么,我不确定如何确保加密不使用 SALT。我希望有人能指出我正确的方向:第 4 步。

【问题讨论】:

Encrypt & Decrypt using PyCrypto AES 256 的可能重复项(参见 pad 和 unpad 功能) A salt 在第 4 步中绝对没有意义。也许作者的意思是初始化向量 (IV),但这不可用,因为您正在尝试使用不使用四。 Salt 可能在第 2 步中有意义。这个提议的方案非常糟糕...... 您永远不应该使用简单的哈希函数来保护您的用户密码。您需要使用强散列方案,如 PBKDF2、bcrypt、scrypt 和 Argon2。确保使用高成本因数/迭代次数。通常选择成本以使单次迭代至少需要 100 毫秒。查看更多:How to securely hash passwords? 切勿使用ECB mode。它是确定性的,因此在语义上不安全。您至少应该使用像CBC 或CTR 这样的随机模式。最好对您的密文进行身份验证,以免像padding oracle attack 这样的攻击是不可能的。这可以通过 GCM 或 EAX 等经过身份验证的模式或encrypt-then-MAC 方案来完成。 【参考方案1】:

PyCrypto 没有内置的填充功能。但它很容易实现。注意:当输入已经是正确的大小时,PKCS7 Padding 将添加一个额外的字节块,这个函数也是如此。 PKCS#7 填充在这里解释。

def pad(m):
    return m+chr(16-len(m)%16)*(16-len(m)%16)

KEY = sha256(passphrase).digest()  #returns 256 bit key
cipher = AES.new(KEY,AES.MODE_ECB) #creates a AES-256 instance using ECB mode
ciphertext = cipher.encrypt(pad(data)).encode('base64')

希望这就是您正在寻找的。 在解密过程中,unpad函数可能会派上用场。

def unpad(ct):
    return ct[:-ct[-1]]

在 Python 3 中,unpad 函数可能需要强制转换(取决于使用情况),如下所示:

def unpad(ct):
    return ct[:-ord(ct[-1])]

附言,

ECB 加密模式不是加密安全的。请使用更高的模式,例如 CBC、OFB 或 GCM。

GCM 或 Galois/Counter 模式同时提供数据机密性和身份验证(即使对于不需要加密的关联数据)。

这是迄今为止最安全的模式,除非您使用相同的 nonce 两次

【讨论】:

如果消息是字节数组,如何使用pad @Fuseldieb 在this other answer 中显示(是的,我知道,迟到了,但对于其他读者来说更多)。 警告:上面没有检查完整的填充,也没有验证最后一个字节,这意味着它也没有检测到填充错误。现在不应该依赖这些(使用 MAC 或经过身份验证的密码),但这不是 PKCS#7 取消填充的方式。这很容易,但不是那么容易,Sayooj。【参考方案2】:

如果消息是字节数组

def pkcs7padding(data, block_size=16):
  if type(data) != bytearray and type(data) != bytes:
    raise TypeError("Only support bytearray/bytes !")
  pl = block_size - (len(data) % block_size)
  return data + bytearray([pl for i in range(pl)])

def pkcs5padding(data):
    return pkcs7padding(data, 8)

【讨论】:

虽然此代码 sn-p 可能是解决方案,但 including an explanation 确实有助于提高您的帖子质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。

以上是关于使用 AES-256 和 PKCS7 填充加密的主要内容,如果未能解决你的问题,请参考以下文章

Unity——AES-256-CBC加密解密

具有 PKCS7 填充编码数据的 AES 256 具有一半 ECB 和一半 CBC 块

JAVA AES CBC 加密 解密

java使用AES-256-ECB(PKCS7Padding)解密——微信支付退款通知接口指定解密方式

AES加解密 对称加密

在 ubuntu/linux/unix 中是不是有带有 cbc 加密的 aes 256?