javascript - 禁用加密填充
问题描述
如果我使用此代码:
let enc = new TextEncoder();
let data = enc.encode('January February');
let algorithm = {
name: 'AES-CBC', iv: enc.encode('0123456789ABCDEF')
};
crypto.subtle.importKey(
'raw', enc.encode('GHIJKLMNOPQRSTUV'), 'AES-CBC', true, ['encrypt']
).then(
key => crypto.subtle.encrypt(algorithm, key, data)
).then(
ct => console.log(btoa(String.fromCharCode(...new Uint8Array(ct))))
);
我得到这个结果:
q6BAetimbeLcdlSC7GoBbtrh/HM4xs3t1+BzEYxdEIk=
如果我使用这个 PHP 代码,我会得到相同的结果:
echo openssl_encrypt(
'January February', 'aes-128-cbc', 'GHIJKLMNOPQRSTUV', iv: '0123456789ABCDEF'
);
但是 PHP 可以选择禁用填充:
echo openssl_encrypt(
'January February',
'aes-128-cbc',
'GHIJKLMNOPQRSTUV',
OPENSSL_ZERO_PADDING,
'0123456789ABCDEF'
);
结果:
q6BAetimbeLcdlSC7GoBbg==
可以使用 JavaScript 禁用填充吗?如果不是,那么获得相同较短输出的好方法是什么?
解决方案
WebCrypto 默认情况下在 AES-CBC PKCS7 填充的上下文中使用(这里),据我所知,它不能被禁用(s.也是文档SubtleCrypto.encrypt()
)。
仅当明文是块大小的整数倍(AES 为 16 个字节)时,才可以使用不带填充的 AES-CBC 进行加密,如您的示例所示。在这种情况下,PKCS7 附加一个带有填充字节(都是 0x10)的完整块,即在密文中只需要删除最后一个块:
//
// Your code (implicit base64 encoding)
//
$enc = openssl_encrypt('January February', 'aes-128-cbc', 'GHIJKLMNOPQRSTUV', OPENSSL_ZERO_PADDING, '0123456789ABCDEF');
print($enc . PHP_EOL);
//
// Remove last block (explicit Base64 encoding required, since the last block of the ACTUAL ciphertext must be removed)
//
$enc = base64_encode(substr(openssl_encrypt('January February', 'aes-128-cbc', 'GHIJKLMNOPQRSTUV', OPENSSL_RAW_DATA, '0123456789ABCDEF'), 0, -16));
print($enc . PHP_EOL);
和
let enc = new TextEncoder();
let data = enc.encode('January February');
let algorithm = {
name: 'AES-CBC', iv: enc.encode('0123456789ABCDEF')
};
crypto.subtle.importKey(
'raw', enc.encode('GHIJKLMNOPQRSTUV'), 'AES-CBC', true, ['encrypt']
).then(
key => crypto.subtle.encrypt(algorithm, key, data)
).then(
ct => console.log(btoa(String.fromCharCode(...new Uint8Array(ct).slice(0, -16)))) // reomve last block
);
两个代码片段都q6BAetimbeLcdlSC7GoBbg==
作为输出提供。
需要注意的是,解密成本更高,因为必须添加加密DOMException
的填充字节(如果解密后没有有效的 PKCS7 填充,则抛出 a)。
当然有一些 JavaScript 库比低级 WebCrypto API 更舒适,并且还支持不同的填充以及禁用填充,例如CryptoJS:
var data = 'January February';
var key = CryptoJS.enc.Utf8.parse('GHIJKLMNOPQRSTUV');
var iv = CryptoJS.enc.Utf8.parse('0123456789ABCDEF');
var encrypted = CryptoJS.AES.encrypt(
data,
key,
{
iv: iv,
padding: CryptoJS.pad.NoPadding
}
);
console.log(encrypted.toString());
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
推荐阅读
- react-native - 如何在本机反应中更改所有应用程序文本组件的字体大小?
- python - 使用 LSTM 进行预测
- python - 无法从 Webelement Selenium Python 打印文本
- admob - 一些下载后如何显示 Admob 广告,我应该尝试什么逻辑。?
- xml - TSQL XML字段-如何使用同一级别的另一个标签的条件更新标签
- r - RStudio, R, Sports Analytics - 为一行添加多个团队(玩家)
- python - 反向传播 - 神经网络 - 导数
- c++ - 如何将三个 4 位有符号整数(即 5 位)打包成一个 16 位整数?
- javascript - 对象内的 2 个函数/方法中的无限循环
- swift - 尽管嵌入在导航控制器中,为什么后退按钮丢失并且视图以模态方式呈现?