singe/thirdparty/openssl/wycheproof/javascript/webcryptoapi/testcases/AesGcmTest.js
2023-11-16 22:15:24 -06:00

217 lines
6.4 KiB
JavaScript

/**
* @license
* Copyright 2017 Google Inc. All rights reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Tests for AES-GCM implementations of Web Crypto API.
*/
/**
* TODO(thanhb):
* - Tests invalid parameters
*/
goog.provide('wycheproof.webcryptoapi.AES-GCM');
goog.require('goog.testing.TestCase');
goog.require('goog.testing.asserts');
goog.require('goog.testing.jsunit');
goog.require('goog.userAgent.product');
goog.require('wycheproof.BigInteger');
goog.require('wycheproof.TestUtil');
var TestUtil = wycheproof.TestUtil;
var BigInteger = wycheproof.BigInteger;
// Test vector file
var AES_GCM_VECTOR_FILE = '../../testvectors/aes_gcm_test.json';
/**
* A class containing a AES-GCM test case's parameters.
* @param {!number} id Identifier of the test case
* @param {!string} k The key in Base64URL format
* @param {!number} keySize The key's size in bits
* @param {!string} tag The expected tag of the encryption in hex format
* @param {!number} tagSize The tag size in bits
* @param {!ArrayBuffer} iv The initialization vector
* @param {!number} ivSize The iv's size in bits
* @param {!ArrayBuffer} aad The additional authentication data
* @param {!ArrayBuffer} msg The message to be encrypted
* @param {!string} ct The expected ciphertext of the encryption in hex format
* @param {!string} result The expected result of the test
*/
var AesGcmTestCase = function(id, k, keySize, tag, tagSize, iv, ivSize,
aad, msg, ct, result) {
this.id = id;
this.k = k;
this.keySize = keySize;
this.tag = tag;
this.tagSize = tagSize;
this.iv = iv;
this.ivSize = ivSize;
this.aad = aad;
this.msg = msg;
this.ct = ct;
this.result = result;
};
/** AES-GCM wrapper */
var AesGcm = function() {};
/**
* Returns the AES-GCM algorithm name that is accepted by WebCrypto APIs.
* @param {!number} keySize The key's size
*
* @return {!string} The algorithm's name
*/
AesGcm.getAlgName = function(keySize) {
return 'A' + keySize + 'GCM';
};
/**
* Imports a AES-GCM key.
* @param {!string} k The key in Base64URL format
* @param {!number} keySize The key's size in bits
*
* @return {!Promise} A Promise containing the imported key
*/
AesGcm.importKey = function(k, keySize) {
return window.crypto.subtle.importKey(
"jwk",
{
kty: 'oct',
k: k,
alg: AesGcm.getAlgName(keySize),
ext: true,
}, {
name: 'AES-GCM',
},
true,
["encrypt", "decrypt"]
);
};
/**
* Performs AES-GCM encryption.
* @param {!CryptoKey} key The key that is used for encryption
* @param {!ArrayBuffer} aad The additional authentication data
* @param {!ArrayBuffer} msg The message to be encrypted
* @param {!ArrayBuffer} iv The initialization vector
* @param {number} tagSize The tag size in bits
*
* @return {!Promise} A Promise containing the ciphetext
*/
AesGcm.encrypt = function(key, aad, msg, iv, tagSize) {
var alg = {
name: 'AES-GCM',
iv: iv,
tagLength: tagSize
};
if (aad.byteLength > 0) {
alg.additionalData = aad;
}
return window.crypto.subtle.encrypt(alg, key, msg);
};
/**
* Tests AES-GCM encryption.
*
* @return {!Promise}
*/
AesGcm.testEncrypt = function() {
var tc = this;
var promise = new Promise(function(resolve, reject) {
AesGcm.importKey(tc.k, tc.keySize).then(function(key){
AesGcm.encrypt(key, tc.aad, tc.msg, tc.iv, tc.tagSize)
.then(function(ct){
// Fail if the iv is empty and the encryption still succeeds
if (tc.ivSize == 0) {
reject('Failed on test case ' + tc.id + ': 0-length iv should not be accepted');
} else {
var obtainedCt = TestUtil.arrayBufferToHex(ct);
var expectedCt = tc.ct+tc.tag;
if ((tc.result == 'valid' && obtainedCt != expectedCt) ||
(tc.result == 'invalid' && obtainedCt == expectedCt)) {
reject('Failed on test case ' + tc.id);
}
}
resolve();
}).catch(function(err){
// don't expect any exception during encryption
reject('Unexpected exception on test case ' + tc.id + ': ' + err);
});
}).catch(function(err){
reject('Failed to import key in test case ' + tc.id + ': ' + err);
});
});
return promise;
};
/**
* Tests AES-GCM encryption implementation with test vectors from files
*
* @return {!Promise}
*/
function testAesGcmVectors() {
var tv = TestUtil.readJsonTestVectorsFromFile(AES_GCM_VECTOR_FILE);
var testCase = new goog.testing.TestCase();
testCase.promiseTimeout = 2*1000;
for (var i = 0; i < tv['testGroups'].length; i++) {
var tg = tv['testGroups'][i];
var keySizeBit = parseInt(tg['keySize']);
var tagSizeBit = parseInt(tg['tagSize']);
var ivSizeBit = parseInt(tg['ivSize']);
// Only run the tests if the key size is supported
if (SUPPORTED['aesgcm-key-size'].indexOf(keySizeBit) == -1) {
continue;
}
// MS Edge only supports IVs of size 96
if (goog.userAgent.product.EDGE && ivSizeBit != 96) {
continue;
}
for (var j = 0; j < tg['tests'].length; j++){
var tc = tg['tests'][j];
// MS Edge doesn't accept 0-length message
if (goog.userAgent.product.EDGE && tc['msg'].length == 0) {
continue;
}
var k = BigInteger.fromHex(tc['key']).toBase64Url(keySizeBit/8);
var aad = TestUtil.hexToArrayBuffer(tc['aad']);
var msg = TestUtil.hexToArrayBuffer(tc['msg']);
var iv;
if (ivSizeBit == 0) {
iv = new Uint8Array([]).buffer;
} else {
iv = BigInteger.fromHex(tc['iv']).toArrayBuffer(ivSizeBit/8);
}
var ct = tc['ct'];
var tag = tc['tag'];
var result = tc['result'];
var tcId = tc['tcId'];
var test = new AesGcmTestCase(tcId, k, keySizeBit, tag, tagSizeBit,
iv, ivSizeBit, aad, msg, ct, result);
testCase.addNewTest('Test ' + tcId, AesGcm.testEncrypt, test);
}
}
return testCase.runTestsReturningPromise().then(TestUtil.checkTestCaseResult);
}