From 8f3ddfb7f7f0de36dfc6d814a27fabdd56c712c3 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Wed, 11 Nov 2020 18:55:03 +0100 Subject: [PATCH] crypto: fix passing TypedArray to webcrypto AES methods Refs: https://www.w3.org/TR/WebCryptoAPI/#subtlecrypto-interface Fixes: https://github.com/nodejs/node/issues/36083 --- lib/internal/crypto/aes.js | 8 +++- .../test-webcrypto-encrypt-decrypt-aes.js | 40 ++++++++++++++++++- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/lib/internal/crypto/aes.js b/lib/internal/crypto/aes.js index f0814c725469e6..ab3ee099cd0d69 100644 --- a/lib/internal/crypto/aes.js +++ b/lib/internal/crypto/aes.js @@ -1,6 +1,7 @@ 'use strict'; const { + ArrayBufferIsView, ArrayBufferPrototypeSlice, ArrayFrom, ArrayPrototypeIncludes, @@ -8,6 +9,7 @@ const { MathFloor, Promise, SafeSet, + TypedArrayPrototypeSlice, } = primordials; const { @@ -183,8 +185,10 @@ function asyncAesGcmCipher( let tag; switch (mode) { case kWebCryptoCipherDecrypt: - tag = ArrayBufferPrototypeSlice(data, -tagByteLength); - data = ArrayBufferPrototypeSlice(data, 0, -tagByteLength); + const slice = ArrayBufferIsView(data) ? + TypedArrayPrototypeSlice : ArrayBufferPrototypeSlice; + tag = slice(data, -tagByteLength); + data = slice(data, 0, -tagByteLength); break; case kWebCryptoCipherEncrypt: tag = tagByteLength; diff --git a/test/parallel/test-webcrypto-encrypt-decrypt-aes.js b/test/parallel/test-webcrypto-encrypt-decrypt-aes.js index ec1635c991ce13..38d2b70bcb0567 100644 --- a/test/parallel/test-webcrypto-encrypt-decrypt-aes.js +++ b/test/parallel/test-webcrypto-encrypt-decrypt-aes.js @@ -6,7 +6,7 @@ if (!common.hasCrypto) common.skip('missing crypto'); const assert = require('assert'); -const { subtle } = require('crypto').webcrypto; +const { getRandomValues, subtle } = require('crypto').webcrypto; async function testEncrypt({ keyBuffer, algorithm, plaintext, result }) { const key = await subtle.importKey( @@ -196,3 +196,41 @@ async function testDecrypt({ keyBuffer, algorithm, result }) { await Promise.all(variations); })().then(common.mustCall()); } + +{ + (async function() { + const secretKey = await subtle.generateKey( + { + name: 'AES-GCM', + length: 256, + }, + false, + ['encrypt', 'decrypt'], + ); + + const iv = getRandomValues(new Uint8Array(12)); + const aad = getRandomValues(new Uint8Array(32)); + + const encrypted = await subtle.encrypt( + { + name: 'AES-GCM', + iv, + additionalData: aad, + tagLength: 128 + }, + secretKey, + getRandomValues(new Uint8Array(32)) + ); + + await subtle.decrypt( + { + name: 'AES-GCM', + iv, + additionalData: aad, + tagLength: 128, + }, + secretKey, + new Uint8Array(encrypted), + ); + })().then(common.mustCall()); +}