当前位置: 首页 > 知识库问答 >
问题:

AES 256-CBC上的密钥和iv问题

严信瑞
2023-03-14

我从Python得到一个加密的base64字符串。

格式是AES 256 CBC,但当我尝试使用Android解密时,它将解密字符串返回为nil。

# coding=utf-8
import base64
from random import choice
from string import letters

try:
    from Crypto import Random
    from Crypto.Cipher import AES
except ImportError:
    import crypto
    import sys

    sys.modules['Crypto'] = crypto
    from crypto.Cipher import AES
    from crypto import Random


class AESCipher(object):
    def __init__(self, key):
        self.bs = 32
        self.key = key

    def encrypt(self, raw):
        _raw = raw
        raw = self._pad(raw)

        print raw, ';'
        print _raw, ';'

        iv = "".join([choice(letters[:26]) for i in xrange(16)])
        print " iv :", iv
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        return base64.b64encode(iv + cipher.encrypt(raw))

    def decrypt(self, enc):
        enc = base64.b64decode(enc)
        iv = enc[:AES.block_size]
        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):
        a = (self.bs - len(s) % self.bs)
        b = chr(self.bs - len(s) % self.bs)
        return s + a * b

    @staticmethod
    def _unpad(s):
        return s[:-ord(s[len(s) - 1:])]
def encrypt(k, t):
    o = AESCipher(k)
    return o.encrypt(t)


def decrypt(k, t):
    o = AESCipher(k)
    return o.decrypt(t)


def main():
    k = "qwertyuiopasdfghjklzxcvbnmqwerty"
    s1 = "Hello World!"

    d2 = encrypt(k, s1)

    print " Password :", k
    print "Encrypted :", d2
    print "    Plain :", decrypt(k, d2)

if __name__ == '__main__':
    main()

这里我使用https://github.com/fukata/aes-256-cbc-example

final String aEcodedSting = "aWVnZWphbnBleWJlemdteeAal+cw04QPYRuuIC3J1/zbkZZSCqxGLo/a26ZiieOk";
String decrypted = AESUtil.decrypt(aEcodedSting);
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.vinu.aessamble/com.example.vinu.aessamble.MainActivity}: 
java.lang.RuntimeException: javax.crypto.BadPaddingException: error:1e06b065:Cipher functions:EVP_DecryptFinal_ex:BAD_DECRYPT
Password : qwertyuiopasdfghjklzxcvbnmqwerty
Encrypted : aWVnZWphbnBleWJlemdteeAal+cw04QPYRuuIC3J1/zbkZZSCqxGLo/a26ZiieOk
iv : iegejanpeybezgmy
plainText : ser456&*(

共有1个答案

满玉泽
2023-03-14

存在4个问题:

  1. python输出与java输入之间的差异
  2. 不同的IV和密钥
  3. 不同的密钥创建
  4. 填充

1)当前您的python代码输出是iv+encrypted_data的base64编码

return base64.b64encode(iv + cipher.encrypt(raw))

你应该这样修

// Decode base64
byte[] array = Base64.decode(src);
// Get only encrypted data (removing first 16 byte, namely the IV)
byte[] encrypted = Arrays.copyOfRange(array, 16, array.length);
// Decrypt data
decrypted = new String(cipher.doFinal(encrypted));

2)输入和输出必须使用相同的IV和key,因此应该从python控制台输出中复制它们:

iv : qbmocwtttkttpqvv
Password : qwertyuiopasdfghjklzxcvbnmqwerty
Encrypted : anZxZHVpaWJpb2FhaWdqaCK0Un7H9J4UlXRizOJ7s8lchAWAPdH4GRf5tLAkCmm6
    Plain : Hello World!

并粘贴到java代码中:

private static final String ENCRYPTION_KEY = "qwertyuiopasdfghjklzxcvbnmqwerty";
private static final String ENCRYPTION_IV = "qbmocwtttkttpqvv";
static Key makeKey() {
    try {
        byte[] key = ENCRYPTION_KEY.getBytes("UTF-8");
        return new SecretKeySpec(key, "AES");
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }

    return null;
}
public static String decrypt(String src) {
    String decrypted = "";
    try {
        Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
        cipher.init(Cipher.DECRYPT_MODE, makeKey(), makeIv());
        byte[] array = Base64.decode(src);
        byte[] encrypted = Arrays.copyOfRange(array, 16, array.length);
        decrypted = new String(cipher.doFinal(encrypted));
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
    return decrypted;
}
encrypted: aWVnZWphbnBleWJlemdteeAal+cw04QPYRuuIC3J1/zbkZZSCqxGLo/a26ZiieOk
decrypted: ser456&*(

您的输入由前16个字节的IV和后16个字节的加密文本组成,因此您可以利用这一点。

public static String decrypt(String src) {
    String decrypted = "";
    try {
        Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
        // Decode input
        byte[] array = Base64.decode(src);
        // Read first 16 bytes (IV data)
        byte[] ivData = Arrays.copyOfRange(array, 0, 16);
        // Read last 16 bytes (encrypted text)
        byte[] encrypted = Arrays.copyOfRange(array, 16, array.length);
        // Init the cipher with decrypt mode, key, and IV bytes array (no more hardcoded)
        cipher.init(Cipher.DECRYPT_MODE, makeKey(), new IvParameterSpec(ivData));
        // Decrypt same old way
        decrypted = new String(cipher.doFinal(encrypted));
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
    return decrypted;
}

而且,正如这里所说的

Python代码使用32字节的块大小进行填充,这意味着Java仍然无法解密所有可能的密文的一半。AES块大小为16字节,这应该在Python实现中更改

class AESCipher(object):
    def __init__(self, key):
        self.bs = AES.block_size
        self.key = key
 类似资料:
  • 我将AES与salt和IV一起用于加密和解密一个唯一的ID,但它给出了javax。加密。解密时出现BadPaddingException。 每次解密数据时给出的完整错误堆栈跟踪 加密方法- 解密方法 我是JCA的新手。

  • 使用EVP_BytesToKey()返回错误的key和iv可能出了什么问题? 我试过用iter计数值做实验,但似乎没有一个能产生工作键和IV。我假设命令行默认的iter计数是1。 同样确认的是,如果我用命令行显示的工作键和iv覆盖从EVP_BytesToKey()返回的内容和硬代码无符号char数组,我的其余代码工作正常,解密正确。 有人能帮忙吗?

  • 我试图在CBC模式下使用AES和Crypto++库加密(和解密)一个文件 以下是我已经做的: 为了加密文件,我以二进制模式打开它,并将内容转储为字符串: 当我将尝试解密此文件时,我如何分别提取iv和密文?IV是16字节长,但在这里我完全迷失了,我不知道如何做。

  • 问题内容: 我正在尝试在NodeJs中解密。它在Java中工作。但是我无法在Node中实现相同的功能。 节点版本:8.4 请找到我的NodeJs代码: 请找到有效的Java解密代码 我得到了不同的解密文本。在NodeJ中,我无法获得与Java中相同的结果。另外,我无法修改Java加密代码。所以我必须弄清楚Node中的解密。 你能帮我这个忙吗? 问题答案: 这是Java和Node.js中的完整示例,

  • 我如何才能确定密钥的加密(AES256或3DES 256)……因为这两个密钥都将是32个字符(每个字符8位*32个字符)=256位和Mime编码。 实例 MQAyAEgAOgA5ADUAMwA3AD8AQgBFAD4A--- g1EOWGFb JjCZ7BbH2RergtKUtDfXrNb --- AES密钥是在Openssl中制作的,而3DES密钥是使用Java和以下API制作的。

  • 我试图让AES-256 CBC加密在PHP、Ruby(使用SymmetricEncryption)和Javascript(使用CryptoJS)中工作。至于前两个: 但是根据这个答案上面的键/iv只提供128位的安全性。 PHP和Ruby将密钥和IV作为二进制字符串。他们不假设它是十六进制编码的。所以,尽管这个密钥中有256位,但安全性实际上只有128位,因为每个字符在十六进制编码的字符串中只有4