diff --git a/lib/internal/crypto/webcrypto.js b/lib/internal/crypto/webcrypto.js index 706487c060e9c9..7cda5b8028780c 100644 --- a/lib/internal/crypto/webcrypto.js +++ b/lib/internal/crypto/webcrypto.js @@ -9,6 +9,7 @@ const { ReflectApply, ReflectConstruct, SafeSet, + StringPrototypeRepeat, SymbolToStringTag, } = primordials; @@ -685,7 +686,16 @@ async function wrapKey(format, key, wrappingKey, algorithm) { let keyData = await ReflectApply(exportKey, this, [format, key]); if (format === 'jwk') { - keyData = new TextEncoder().encode(JSONStringify(keyData)); + const ec = new TextEncoder(); + const raw = JSONStringify(keyData); + // As per the NOTE in step 13 https://w3c.github.io/webcrypto/#SubtleCrypto-method-wrapKey + // we're padding AES-KW wrapped JWK to make sure it is always a multiple of 8 bytes + // in length + if (algorithm.name === 'AES-KW' && raw.length % 8 !== 0) { + keyData = ec.encode(raw + StringPrototypeRepeat(' ', 8 - (raw.length % 8))); + } else { + keyData = ec.encode(raw); + } } return cipherOrWrap( diff --git a/test/parallel/test-webcrypto-wrap-unwrap.js b/test/parallel/test-webcrypto-wrap-unwrap.js index 06f748ed4c0639..2978d3fec46c3c 100644 --- a/test/parallel/test-webcrypto-wrap-unwrap.js +++ b/test/parallel/test-webcrypto-wrap-unwrap.js @@ -231,6 +231,10 @@ function getFormats(key) { // material length must be a multiple of 8. // If the wrapping algorithm is RSA-OAEP, the exported key // material maximum length is a factor of the modulusLength +// +// As per the NOTE in step 13 https://w3c.github.io/webcrypto/#SubtleCrypto-method-wrapKey +// we're padding AES-KW wrapped JWK to make sure it is always a multiple of 8 bytes +// in length async function wrappingIsPossible(name, exported) { if ('byteLength' in exported) { switch (name) { @@ -239,13 +243,8 @@ async function wrappingIsPossible(name, exported) { case 'RSA-OAEP': return exported.byteLength <= 446; } - } else if ('kty' in exported) { - switch (name) { - case 'AES-KW': - return JSON.stringify(exported).length % 8 === 0; - case 'RSA-OAEP': - return JSON.stringify(exported).length <= 478; - } + } else if ('kty' in exported && name === 'RSA-OAEP') { + return JSON.stringify(exported).length <= 478; } return true; }