英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论