Reputation: 1
If I use this code:
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))))
);
I get this result:
q6BAetimbeLcdlSC7GoBbtrh/HM4xs3t1+BzEYxdEIk=
If I use this PHP code, I get the same result:
echo openssl_encrypt(
'January February', 'aes-128-cbc', 'GHIJKLMNOPQRSTUV', iv: '0123456789ABCDEF'
);
However PHP has the option to disable padding:
echo openssl_encrypt(
'January February',
'aes-128-cbc',
'GHIJKLMNOPQRSTUV',
OPENSSL_ZERO_PADDING,
'0123456789ABCDEF'
);
Result:
q6BAetimbeLcdlSC7GoBbg==
Can padding be disabled with JavaScript? If not, what is a good way to get the same shorter output?
Upvotes: 1
Views: 1651
Reputation: 1
Other answer is great, but as an alternative, you can use the builtin Node
crypto
API:
let crypto = require('crypto');
let [pt, key, iv] = ['January February', 'GHIJKLMNOPQRSTUV', '0123456789ABCDEF'];
// default is padding, omit last method if needed
let cipher = crypto.createCipheriv('aes-128-cbc', key, iv).setAutoPadding(false);
let ct = cipher.update(pt, 'utf8', 'base64') + cipher.final('base64');
console.log(ct);
and here is an example using the Deno crypto
library:
import { Aes } from 'http://deno.land/x/crypto/aes.ts';
import { Cbc, Padding } from 'http://deno.land/x/crypto/block-modes.ts';
let te = new TextEncoder;
let [pt, key, iv] = [
te.encode('January February'),
te.encode('GHIJKLMNOPQRSTUV'),
te.encode('0123456789ABCDEF')
];
// default is no padding, omit last argument if needed
let cipher = new Cbc(Aes, key, iv, Padding.PKCS7);
let ct = btoa(String.fromCharCode(...cipher.encrypt(pt)));
console.log(ct);
Upvotes: 0
Reputation: 49276
WebCrypto uses in the context of AES-CBC PKCS7 padding by default (here), which as far as I know cannot be disabled (s. also the documentation of SubtleCrypto.encrypt()
).
Encryption with AES-CBC without padding is only possible if the plaintext is an integer multiple of the block size (16 bytes for AES), as in your example. In this case PKCS7 appends a complete block with padding bytes (which are all 0x10), i.e. in the ciphertext only this last block needs to be removed:
//
// 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);
and
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
);
Both code snippets provide q6BAetimbeLcdlSC7GoBbg==
as output.
It should be noted, that decryption is more expensive because the encrypted padding bytes must be added (if there is no valid PKCS7 padding after decryption, a DOMException
is thrown).
There are of course JavaScript libraries that are more comfortable than the low level WebCrypto API, and that also support different paddings as well as disabling padding, e.g. 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>
Upvotes: 4