Bouncy Castle and CryptoJS vs Pycryptodome and Cryptography – who's right and how to decrypt the data in Python?

huangapple go评论89阅读模式
英文:

Bouncy Castle and CryptoJS vs Pycryptodome and Cryptography - who's right and how to decrypt the data in Python?

问题

以下是您提供的代码部分的翻译:

JavaScript代码部分:

const CryptoJS = require('crypto-js')

const ivHexString = '4d055a9e07e7db37297dd20cc73c4cc4'
const keyHexString = 'aab60badba8587c95e36c5cf6cf736b9'

const decrypt = u8arr => { 
    const wordArray = arr => CryptoJS.lib.WordArray.create(arr)
    const ciphertext = wordArray(u8arr)
    const iv = CryptoJS.enc.Hex.parse(ivHexString)
    const key = CryptoJS.enc.Hex.parse(keyHexString)
    const cipherTextParam = CryptoJS.lib.CipherParams.create({ ciphertext })
    const cipherParams = {         
        iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    }
    const output = CryptoJS.AES.decrypt(cipherTextParam, key, cipherParams)
    return output.toString(CryptoJS.enc.Base64)
}

const data = 'CYkJIz1qptjyjNh4VpzODnVq94JLIx37B0677lYlMJhFtOA6ZFL7CY0M6wRyZlW5pfSorSEDEUbw9EqDePLUvSCwtTsB6CXnVL2+TNvYaffnV/lpjfEAoHANiUxgbBabY3k3BBUAj8RXDmLIQw/bftJcvXw5egS7U0ucb0lDKByqSrMT1DaFDrOHnjO7r2ahZIgZ2G/wHcNwDjloGPvkjGAbwqWfdHaazflGzGTcgXb/PY4UtThba2t8PZBmF8Injiu8As2jl9mt+oC/QvhgJhuIOqJ69Hnt7EoGX4MNX0e/a5qjCHEMOtC4v3gW6sozuVoozXL3uNYHtfsPfnCD2g=='
const uint8arr = Uint8Array.from(Buffer.from(data, 'base64'))
const d = decrypt(uint8arr)
console.log(d)

Python代码部分:

from Crypto.Cipher import AES
from Crypto.Util import Padding
import base64

def decrypt():
    iv = '4d055a9e07e7db37297dd20cc73c4cc4'
    key = 'aab60badba8587c95e36c5cf6cf736b9'
    data_b64 = 'CYkJIz1qptjyjNh4VpzODnVq94JLIx37B0677lYlMJhFtOA6ZFL7CY0M6wRyZlW5pfSorSEDEUbw9EqDePLUvSCwtTsB6CXnVL2+TNvYaffnV/lpjfEAoHANiUxgbBabY3k3BBUAj8RXDmLIQw/bftJcvXw5egS7U0ucb0lDKByqSrMT1DaFDrOHnjO7r2ahZIgZ2G/wHcNwDjloGPvkjGAbwqWfdHaazflGzGTcgXb/PY4UtThba2t8PZBmF8Injiu8As2jl9mt+oC/QvhgJhuIOqJ69Hnt7EoGX4MNX0e/a5qjCHEMOtC4v3gW6sozuVoozXL3uNYHtfsPfnCD2g=='
    data = base64.b64decode(data_b64)
    iv = bytes.fromhex(iv)
    key = bytes.fromhex(key)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    ct = cipher.decrypt(data)
    t = Padding.unpad(ct, AES.block_size)
    return t

res_b64 = decrypt()
res = base64.b64encode(res_b64)
print(res)

BouncyCastle Java代码部分:

public class CryptoUtil {

    private CryptoUtil() {
        throw new AssertionError();
    }

    public static byte[] encryptAes(byte[] data, char[] password) throws Exception {
        ParametersWithIV key = (ParametersWithIV) getAesPasswdKey(password);
        BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESFastEngine()));
        cipher.init(true, key);
        byte[] result = new byte[cipher.getOutputSize(data.length)];
        int len = cipher.processBytes(data, 0, data.length, result, 0);
        cipher.doFinal(result, len);
        return result;
    }

    public static byte[] decryptAes(byte[] data, char[] password) throws Exception {
        ParametersWithIV key = (ParametersWithIV) getAesPasswdKey(password);
        BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESFastEngine()));
        cipher.init(false, key);
        byte[] result = new byte[cipher.getOutputSize(data.length)];
        int len = cipher.processBytes(data, 0, data.length, result, 0);
        int doFinalLen = cipher.doFinal(result, len);
        byte[] ret = new byte[len + doFinalLen];
        System.arraycopy(result, 0, ret, 0, ret.length);
        return ret;
    }

    private static CipherParameters getAesPasswdKey(char[] passwd) throws Exception {
        PBEParametersGenerator generator = new PKCS12ParametersGenerator(new SHA1Digest());
        generator.init(PBEParametersGenerator.PKCS12PasswordToBytes(passwd), SALT, 1);
        ParametersWithIV key = (ParametersWithIV) generator.generateDerivedParameters(128, 128);
        return key;
    }
}

请注意,这些翻译仅包括代码部分,不包括任何问题的答案。如有其他疑问,请随时提出。

英文:

Let me explain. I have some data encrypted by Bouncy Caste library (AES 128 CBC).
I am able to decompress the data using Crypto.js:

var CryptoJS = require('crypto-js')
const ivHexString = '4d055a9e07e7db37297dd20cc73c4cc4'
const keyHexString = 'aab60badba8587c95e36c5cf6cf736b9'
const decrypt = u8arr => { 
const wordArray = arr => CryptoJS.lib.WordArray.create(arr)
const ciphertext = wordArray(u8arr)
const iv = CryptoJS.enc.Hex.parse(ivHexString)
const key = CryptoJS.enc.Hex.parse(keyHexString)
const cipherTextParam = CryptoJS.lib.CipherParams.create({ ciphertext })
const cipherParams = {         
iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
}
const output = CryptoJS.AES.decrypt(cipherTextParam, key, cipherParams)
return output.toString(CryptoJS.enc.Base64)
}
const data = 'CYkJIz1qptjyjNh4VpzODnVq94JLIx37B0677lYlMJhFtOA6ZFL7CY0M6wRyZlW5pfSorSEDEUbw9EqDePLUvSCwtTsB6CXnVL2+TNvYaffnV/lpjfEAoHANiUxgbBabY3k3BBUAj8RXDmLIQw/bftJcvXw5egS7U0ucb0lDKByqSrMT1DaFDrOHnjO7r2ahZIgZ2G/wHcNwDjloGPvkjGAbwqWfdHaazflGzGTcgXb/PY4UtThba2t8PZBmF8Injiu8As2jl9mt+oC/QvhgJhuIOqJ69Hnt7EoGX4MNX0e/a5qjCHEMOtC4v3gW6sozuVoozXL3uNYHtfsPfnCD2g=='
const uint8arr = Uint8Array.from(Buffer.from(data, 'base64'))
const d = decrypt(uint8arr)
console.log(d)

This is working good. The expected result is:

GskdZkH4vRC7gEDVv4kUlAXSHq3tekrZNuFWjUozgIlXzEf4Rh9mJ5L9kth4tVhQjWV4SbLQW1f6CdLJxh50TlfMR/hGH2Ynkv2S2Xi1WFRXzEf4Rh9mJ5L9ktl4tVhQ+niKb+1lVdx8dCiV4xnQutN1Eid64etnzF6UJ6BTaeGK3RZaoUpcu+fto1nDUx6RdgAp4M92vat6clPWajgtK1fMR/9GH2Ynkv2S2Xi1WFBIyfXPaM+JaxYsnsc4pTQNtvSMkbqQo+PlpIJAZlWMXVfMR/hGH2Ynkv2S2Xi1WFeVGC5QrBQeBALoJlpAGdqFrIp35WiRWDU3UMSxwDarhFfMR/hGH2Ynkv2S2Xi1WFVXzEf4Rh9mJ5L9ktl4tVhQV8xH+EYfZieS/ZLZeLVYUBwSa9DLPkiPZXJ+x81Mh3FXzEfxRh9mJ5L9ktl4tVhQV8xH+EYfZieS/ZLZeLVYUFfMR/hGH2Ynkv2S2Xi1WFCVGC5QrBQeBALoJlpAGdqFKq+2KRLLij4Qyq8AwPWFWVfMR/hGH2Ynkv2S23i1WFBXzEf4Rh9mJ5L9ktl4tVhQV8xH+EYfZieS/ZLZeLVYUFfMR/hGH2Ynkv2S2Xi1WFBXzEf4Rh9mJ5L9ktl4tVhQV8xH+EYfZieS/ZLZeLVYUFfMR/hGH2Ynkv2S2Xi1WFDl4Bu9+CbKVf/6Ejs8DGhzV8xH+EYfZiSS/ZLZeLVYU4K+nTPoDTMVTK5DI+bog7JXzEf4Rh9mL5L9ktl4tVhQV8xH+EYfZieS/ZLZeLVYUFfMR/hGH2Ynkv2S2Xi1WFCsinfjaJFYNTdQxLHANquEtvSMkbqQo+PlpIJAZlWMXlfMR/hGH2Ynkv2S2Xi1WFdXzEf4Rh9mJ5L9ktl4tVhQV8xH+EYfZieS/ZLZeLVYUFfMR/hGH2Ynkv2S2Xi1WFBIKVmlTvuPp/T1N+pUVoVcV8xH+UYfZieS/ZLZeLVYULb0jJG6kKPj5aSCQGZVjFsP43HVf60huYpvjDeUhvLsV8xH+EYfZiWS/ZLZeLVYUNZFUaRKlsWc+Dla7Jkk5UxXzEf6Rh9mJ5L9ktl4tVhQV8xH+EYfZieS/ZLZeLVYUFfMR/hGH2Ynkv2S2Xi1WFBXzEf4Rh9mJ5L9ktl4tVhQV8xH+EYfZieS/ZLZeLVYUFfMR/hGH2Ynkv2S2Xi1WFBXzEf4Rh9mJ5L9ktl4tVhQV8xH+EYfZieS/ZLZeLVYUFfMR/hGH2Ynkv2S2Xi1WFC0BeMZJPiM+p+jMftg7+sgV8xH+EYfZieS/ZLdeLVYUGjv8WjY//toLtuXgUMWHMRXzEf4Rh9mJZL9ktl4tVhYgr6dM+gNMxVMrkMj5uiDsmt3P+pMcByZ1iwi8ZV+obIqr7YvEsuKPhDKrwDA9YVRIv1lNtKTvDFOh0k5AV9dXlfMR/hGH2Yukv2S2Xi1WFBXzEf4Rh9mJ5L9ktl4tVhQV8xH+EYfZieS/ZLZeLVYUEjJ9c9oz4lrFiyexzilNA0cEmvQyz5Ij2VyfsfNTId3dgAp6c92vat6clPQajgtLC57yGqV/omI/MZSGIHlLIFXzEf4Rh9mI5L9ktl4tVhQEQYdm99FDxrZnWQFEj7G7VfMR/hGH2Yikv2S2Xi1WFCNZXhJstBbV/oJ0snGHnRO9aUARZUzsGNlLY32LpF1cZUYLlCsFB4HAugmWkAZ2oVXzEf+Rh9mJ5L9ktl4tVhQoZM0BA==

But the result in Pycryptodome or Cryptograhy is different and they complain about padding:

from Crypto.Cipher import AES
from Crypto.Util import Padding
import base64
def decrypt():
iv = '4d055a9e07e7db37297dd20cc73c4cc4'
key = 'aab60badba8587c95e36c5cf6cf736b9'
data_b64 =  'CYkJIz1qptjyjNh4VpzODnVq94JLIx37B0677lYlMJhFtOA6ZFL7CY0M6wRyZlW5pfSorSEDEUbw9EqDePLUvSCwtTsB6CXnVL2+TNvYaffnV/lpjfEAoHANiUxgbBabY3k3BBUAj8RXDmLIQw/bftJcvXw5egS7U0ucb0lDKByqSrMT1DaFDrOHnjO7r2ahZIgZ2G/wHcNwDjloGPvkjGAbwqWfdHaazflGzGTcgXb/PY4UtThba2t8PZBmF8Injiu8As2jl9mt+oC/QvhgJhuIOqJ69Hnt7EoGX4MNX0e/a5qjCHEMOtC4v3gW6sozuVoozXL3uNYHtfsPfnCD2g=='
data = base64.b64decode(data_b64)
iv = bytes.fromhex(iv)
key = bytes.fromhex(key)
cipher = AES.new(key, AES.MODE_CBC, iv)
ct = cipher.decrypt(data)
t = Padding.unpad(ct, AES.block_size)
return t
res_b64 = decrypt()
res = base64.b64encode(res_b64)
print(res)

Do they have diffrent padding implementations? Where is the difference?

BouncyCastle code (without salt):

public class CryptoUtil {
private CryptoUtil() {
throw new AssertionError();
}
public static byte[] encryptAes(byte[] data, char[] password) throws Exception {
ParametersWithIV key = (ParametersWithIV) getAesPasswdKey(password);
BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESFastEngine()));
cipher.init(true, key);
byte[] result = new byte[cipher.getOutputSize(data.length)];
int len = cipher.processBytes(data, 0, data.length, result, 0);
cipher.doFinal(result, len);
return result;
}
public static byte[] decryptAes(byte[] data, char[] password) throws Exception {
ParametersWithIV key = (ParametersWithIV) getAesPasswdKey(password);
BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESFastEngine()));
cipher.init(false, key);
byte[] result = new byte[cipher.getOutputSize(data.length)];
int len = cipher.processBytes(data, 0, data.length, result, 0);
int doFinalLen = cipher.doFinal(result, len);
byte[] ret = new byte[len + doFinalLen];
System.arraycopy(result, 0, ret, 0, ret.length);
return ret;
}
private static CipherParameters getAesPasswdKey(char[] passwd) throws Exception {
PBEParametersGenerator generator = new PKCS12ParametersGenerator(new SHA1Digest());
generator.init(PBEParametersGenerator.PKCS12PasswordToBytes(passwd), SALT, 1);
ParametersWithIV key = (ParametersWithIV) generator.generateDerivedParameters(128, 128);
return key;
}
}

答案1

得分: 1

原始数据在两种实现中都以相同的方式解密 - 但当将所有的data解释为密文时,它并没有正确的PKCS7填充 - 至少最后的16个字节在两种情况下都是3137f423fe539c956832f442480a3690。这不是正确的PKCS7填充...最后一个字节应该在01-10(十六进制)范围内,并且然后以它表示的字节数进行'倒序'重复。

然而,Crypto-JS实现返回112个字节的密文,预期应返回256 - 16,因为那是密文的长度 - 如果data实际上是原始AES密文的话。但它不是。

英文:

The raw data is decrypted in an identical manner in both implementations - but it does not have correct PKCS7-padding - at least not when interpreting all of the data as ciphertext. The last 16 bytes are, in both cases, 3137f423fe539c956832f442480a3690. This is not correct PKCS7-padding... The last byte should be in the range 01-10 (hex), and then repeated 'backwards' for the number of bytes is represents.

The Crypto-JS implementation though, returns 112 bytes of ciphertext, it was expected to return 256 - 16, since that's the length of the cipher text - if the data was in fact raw AES cipher-text. But it's not.

huangapple
  • 本文由 发表于 2023年6月22日 16:06:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/76529763.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定