blob: 71283fbc0711755d35cd52e22d9efbd7e047e012 [file] [log] [blame]
// 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.
//
////////////////////////////////////////////////////////////////////////////////
goog.module('tink.subtle.AesCtrTest');
goog.setTestOnly('tink.subtle.AesCtrTest');
const AesCtr = goog.require('tink.subtle.AesCtr');
const Bytes = goog.require('tink.subtle.Bytes');
const Random = goog.require('tink.subtle.Random');
const TestCase = goog.require('goog.testing.TestCase');
const testSuite = goog.require('goog.testing.testSuite');
testSuite({
setUp() {
// Use a generous promise timeout for running continuously.
TestCase.getActiveTestCase().promiseTimeout = 1000 * 1000; // 1000s
},
tearDown() {
// Reset the timeout.
TestCase.getActiveTestCase().promiseTimeout = 1000; // 1s
},
async testBasic() {
// Set longer time for promiseTimout as the test sometimes takes longer than
// 1 second in Firefox.
const key = Random.randBytes(16);
for (let i = 0; i < 100; i++) {
const msg = Random.randBytes(20);
const cipher = await AesCtr.newInstance(key, 16);
let ciphertext = await cipher.encrypt(msg);
let plaintext = await cipher.decrypt(ciphertext);
assertEquals(Bytes.toHex(msg), Bytes.toHex(plaintext));
}
},
async testProbabilisticEncryption() {
const cipher = await AesCtr.newInstance(Random.randBytes(16), 16);
const msg = Random.randBytes(20);
const aad = Random.randBytes(20);
const results = new Set();
for (let i = 0; i < 100; i++) {
const ciphertext = await cipher.encrypt(msg, aad);
results.add(Bytes.toHex(ciphertext));
}
assertEquals(100, results.size);
},
async testConstructor() {
try {
await AesCtr.newInstance(123, 16); // IV size too short
fail('Should throw an exception.');
} catch (e) {
assertEquals(
'CustomError: input must be a non null Uint8Array', e.toString());
}
try {
await AesCtr.newInstance(Random.randBytes(16), 11); // IV size too short
fail('Should throw an exception.');
} catch (e) {
assertEquals(
'CustomError: invalid IV length, must be at least 12 and at most 16',
e.toString());
}
try {
await AesCtr.newInstance(Random.randBytes(16), 17); // IV size too long
fail('Should throw an exception.');
} catch (e) {
assertEquals(
'CustomError: invalid IV length, must be at least 12 and at most 16',
e.toString());
}
try {
await AesCtr.newInstance(
Random.randBytes(24), 12); // 192-bit keys not supported
fail('Should throw an exception.');
} catch (e) {
assertEquals('CustomError: unsupported AES key size: 24', e.toString());
}
},
async testConstructor_invalidIvSizes() {
try {
await AesCtr.newInstance(Random.randBytes(16), NaN);
fail('Should throw an exception.');
} catch (e) {
assertEquals(
'CustomError: invalid IV length, must be an integer', e.toString());
}
try {
await AesCtr.newInstance(Random.randBytes(16), undefined);
fail('Should throw an exception.');
} catch (e) {
assertEquals(
'CustomError: invalid IV length, must be an integer', e.toString());
}
try {
await AesCtr.newInstance(Random.randBytes(16), 12.5);
fail('Should throw an exception.');
} catch (e) {
assertEquals(
'CustomError: invalid IV length, must be an integer', e.toString());
}
try {
await AesCtr.newInstance(Random.randBytes(16), 0);
fail('Should throw an exception.');
} catch (e) {
assertEquals(
'CustomError: invalid IV length, must be at least 12 and at most 16',
e.toString());
}
},
async testType() {
try {
await AesCtr.newInstance('blah', 12);
fail('Should throw an exception.');
} catch (e) {
assertEquals(
'CustomError: input must be a non null Uint8Array', e.toString());
}
const cipher = await AesCtr.newInstance(Random.randBytes(16), 12);
try {
await cipher.encrypt('blah');
fail('Should throw an exception.');
} catch (e) {
assertEquals(
'CustomError: input must be a non null Uint8Array', e.toString());
}
try {
await cipher.encrypt(123);
fail('Should throw an exception.');
} catch (e) {
assertEquals(
'CustomError: input must be a non null Uint8Array', e.toString());
}
try {
await cipher.decrypt('blah');
fail('Should throw an exception.');
} catch (e) {
assertEquals(
'CustomError: input must be a non null Uint8Array', e.toString());
}
try {
await cipher.decrypt(123);
fail('Should throw an exception.');
} catch (e) {
assertEquals(
'CustomError: input must be a non null Uint8Array', e.toString());
}
},
async testWithTestVectors() {
// Test data from NIST SP 800-38A pp 55.
const NIST_TEST_VECTORS = [
{
'key': '2b7e151628aed2a6abf7158809cf4f3c',
'message':
'6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51' +
'30c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710',
'ciphertext':
'874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff' +
'5ae4df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee',
'iv': 'f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'
},
];
for (let i = 0; i < NIST_TEST_VECTORS.length; i++) {
const testVector = NIST_TEST_VECTORS[i];
const key = Bytes.fromHex(testVector['key']);
const iv = Bytes.fromHex(testVector['iv']);
const msg = Bytes.fromHex(testVector['message']);
const ciphertext = Bytes.fromHex(testVector['ciphertext']);
const aesctr = await AesCtr.newInstance(key, iv.length);
const plaintext = await aesctr.decrypt(Bytes.concat(iv, ciphertext));
assertEquals(Bytes.toHex(msg), Bytes.toHex(plaintext));
}
},
});