我用一个AES加密/解密的例子做了以下观察,这对我来说是非常反直觉的。
我尝试在CBC模式下用AES加密和解密一个简单的有效负载。我的理解是,根据以下回答,初始化向量不必是秘密的:https://security.stackexchange.com/a/17046.在我看到的大多数例子中,初始化向量是加密负载的非随机部分。
但是通过改变初始化向量,我能够在加密过程中改变消息。
例如,请参阅我从https://stackoverflow.com/a/21928790/669561.复制和改编的python示例,我设置了一个硬编码的iv
用于加密
,并稍微调整了iv
用于decrypt
。通过此更改,我可以将消息从Hello world
更改为Hello!世界"
.
import base64
import hashlib
from Crypto.Cipher import AES
class AESCipher(object):
def __init__(self, key):
self.bs = AES.block_size
self.key = hashlib.sha256(key.encode()).digest()
def encrypt(self, raw):
raw = self._pad(raw)
#iv = Random.new().read(AES.block_size)
# | here is the difference to the iv from decrypt
iv = b'\xe2\xe0l3H\xc42*N\xb0\x152\x98\x9cBh'
cipher = AES.new(self.key, AES.MODE_CBC, iv)
code = cipher.encrypt((raw.encode()))
return base64.b64encode(iv + code)
def decrypt(self, enc):
enc = base64.b64decode(enc)
#iv = enc[:AES.block_size]
# | here is the difference to the iv from encrypt
iv = b'\xe2\xe0l3H\xc52*N\xb0\x152\x98\x9cBh'
cipher = AES.new(self.key, AES.MODE_CBC, iv)
return self._unpad(cipher.decrypt(enc[AES.block_size:])).decode('utf-8')
def _pad(self, s):
return s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs)
@staticmethod
def _unpad(s):
return s[:-ord(s[len(s) - 1:])]
if __name__ == '__main__':
text = "hello world"
print(text) # -> "hello world"
aes = AESCipher("F56hnXWaUWMh6ThQZ5l3mBg9zHFx6vQg")
payload = aes.encrypt(text)
print(aes.decrypt(payload)) # -> "hello!world"
这个简单例子的结果对我来说完全是反直觉的。似乎有人在中间可以采取有效载荷,改变iv
轻微,这样做改变解密的消息,甚至不知道秘密密钥!
根据我的理解,仅仅通过更改初始化向量来更改加密消息的内容应该不那么容易。更改初始化向量将导致完全不同的结果!
我的思维有问题吗?
你能帮我澄清我的误解吗?
AES和一般的分组密码通常只提供“保密性”——它们不保证完整性。
你的观察是正确的——在解密后改变静脉注射确实会改变结果明文。您还会注意到,在我的案例中,更改密文本身的字节仍然可以在AES-CBC下成功解密(尽管是不同的明文)。
您需要的是一种方法来验证IV和密文在初始加密操作发生后是否未被修改。
实现这一目标的两种最常见的方法是:
您可能会发现这个Python中的AES-GCM加密示例很有用。我把它包括在下面:
from Crypto.Hash import SHA256, HMAC
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from Crypto.Protocol.KDF import PBKDF2
import base64
ALGORITHM_NONCE_SIZE = 12
ALGORITHM_TAG_SIZE = 16
ALGORITHM_KEY_SIZE = 16
PBKDF2_SALT_SIZE = 16
PBKDF2_ITERATIONS = 32767
PBKDF2_LAMBDA = lambda x, y: HMAC.new(x, y, SHA256).digest()
def encryptString(plaintext, password):
# Generate a 128-bit salt using a CSPRNG.
salt = get_random_bytes(PBKDF2_SALT_SIZE)
# Derive a key using PBKDF2.
key = PBKDF2(password, salt, ALGORITHM_KEY_SIZE, PBKDF2_ITERATIONS, PBKDF2_LAMBDA)
# Encrypt and prepend salt.
ciphertextAndNonce = encrypt(plaintext.encode('utf-8'), key)
ciphertextAndNonceAndSalt = salt + ciphertextAndNonce
# Return as base64 string.
return base64.b64encode(ciphertextAndNonceAndSalt)
def decryptString(base64CiphertextAndNonceAndSalt, password):
# Decode the base64.
ciphertextAndNonceAndSalt = base64.b64decode(base64CiphertextAndNonceAndSalt)
# Get the salt and ciphertextAndNonce.
salt = ciphertextAndNonceAndSalt[:PBKDF2_SALT_SIZE]
ciphertextAndNonce = ciphertextAndNonceAndSalt[PBKDF2_SALT_SIZE:]
# Derive the key using PBKDF2.
key = PBKDF2(password, salt, ALGORITHM_KEY_SIZE, PBKDF2_ITERATIONS, PBKDF2_LAMBDA)
# Decrypt and return result.
plaintext = decrypt(ciphertextAndNonce, key)
return plaintext.decode('utf-8')
def encrypt(plaintext, key):
# Generate a 96-bit nonce using a CSPRNG.
nonce = get_random_bytes(ALGORITHM_NONCE_SIZE)
# Create the cipher.
cipher = AES.new(key, AES.MODE_GCM, nonce)
# Encrypt and prepend nonce.
ciphertext, tag = cipher.encrypt_and_digest(plaintext)
ciphertextAndNonce = nonce + ciphertext + tag
return ciphertextAndNonce
def decrypt(ciphertextAndNonce, key):
# Get the nonce, ciphertext and tag.
nonce = ciphertextAndNonce[:ALGORITHM_NONCE_SIZE]
ciphertext = ciphertextAndNonce[ALGORITHM_NONCE_SIZE:len(ciphertextAndNonce) - ALGORITHM_TAG_SIZE]
tag = ciphertextAndNonce[len(ciphertextAndNonce) - ALGORITHM_TAG_SIZE:]
# Create the cipher.
cipher = AES.new(key, AES.MODE_GCM, nonce)
# Decrypt and return result.
plaintext = cipher.decrypt_and_verify(ciphertext, tag)
return plaintext
问题内容: 我目前有一个密钥库,其中只有我应该知道的特定密码。现在,我需要将对该密钥库的访问权授予其他人,因此我想: 1)更改密码,以便我可以与他人共享该密码并让他们签名 2)创建一个不同的密码并允许他们使用它进行签名。 这可能吗?以及-如果是-怎么样? 问题答案: 密钥库只有一个密码。您可以使用keytool进行更改: 要更改密钥的密码:
问题内容: 我有一个关于在AES加密中使用初始化向量的问题。我引用以下文章/帖子将加密功能构建到程序中: [1] 基于Java256位AES密码的加密 [2]http://gmailassistant.sourceforge.net/src/org/freeshell/zs/common/Encryptor.java.html 我最初从第一个链接开始关注erickson的解决方案,但是据我所知,我
本文向大家介绍thinkphp微信开发(消息加密解密),包括了thinkphp微信开发(消息加密解密)的使用技巧和注意事项,需要的朋友参考一下 使用thinkphp官方的WeChat包,使用不同模式可以成功,但是安全模式就是不行,现将分析解决结果做下记录。 分析问题: 解密微信服务器消息老是不成功,下载下微信公众平台官方给出的解密文件和WechatCrypt.class.php
我已经编写了一个Java程序,它要求用户指定一个随机密钥(以base 64编码),指定要加密的纯文本文件,以及输出文件的名称(加密的文本文件)。 然后反向解密(密钥输入加密文件名输出解密文件)。 这遵循与OpenSSL提供的非常相似的行为。 我的java代码使用模式。 我已经使用文件输出流事先将随机生成的初始化向量(16 字节 IV)附加到我的密文中。然后我相信密码输出流在 IV 之后写入密文。
使用Python-GnuPG我想 null 不幸的是,加密返回错误: 但它仍然生成加密ASCII铠甲消息,如果解密结果为对象,则bool值为属性,并包含以下属性: 不确定错误发生的确切位置以及如何处理
有没有办法将PostgreSQL密码加密方法从MD5更改为SHA? 如果是,你能告诉我怎么做吗? 我正在使用PostgreSQL 9.5