blob: d2cbff067dede82ddb2590e5dc43c07f0b10bc33 [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.aead.AesCtrHmacAeadKeyManagerTest');
goog.setTestOnly('tink.aead.AesCtrHmacAeadKeyManagerTest');
const {Aead} = goog.require('google3.third_party.tink.javascript.aead.internal.aead');
const AesCtrHmacAeadKeyManager = goog.require('tink.aead.AesCtrHmacAeadKeyManager');
const {Mac} = goog.require('google3.third_party.tink.javascript.mac.internal.mac');
const Random = goog.require('google3.third_party.tink.javascript.subtle.random');
const {PbAesCtrHmacAeadKey, PbAesCtrHmacAeadKeyFormat, PbAesCtrKey, PbAesCtrKeyFormat, PbAesCtrParams, PbHashType, PbHmacKey, PbHmacKeyFormat, PbHmacParams, PbKeyData} = goog.require('google3.third_party.tink.javascript.internal.proto');
const KEY_TYPE = 'type.googleapis.com/google.crypto.tink.AesCtrHmacAeadKey';
const VERSION = 0;
/////////////////////////////////////////////////////////////////////////////
// Helper functions for tests
/**
* creates new AesCtrHmacAeadKeyFormat with allowed parameters
* @return {!PbAesCtrHmacAeadKeyFormat}
*/
const createTestKeyFormat = function() {
const KEY_SIZE = 16;
const IV_SIZE = 12;
const TAG_SIZE = 16;
let keyFormat = new PbAesCtrHmacAeadKeyFormat().setAesCtrKeyFormat(
new PbAesCtrKeyFormat());
keyFormat.getAesCtrKeyFormat().setKeySize(KEY_SIZE);
keyFormat.getAesCtrKeyFormat().setParams(new PbAesCtrParams());
keyFormat.getAesCtrKeyFormat().getParams().setIvSize(IV_SIZE);
// set HMAC key
keyFormat.setHmacKeyFormat(new PbHmacKeyFormat());
keyFormat.getHmacKeyFormat().setKeySize(KEY_SIZE);
keyFormat.getHmacKeyFormat().setParams(new PbHmacParams());
keyFormat.getHmacKeyFormat().getParams().setHash(PbHashType.SHA1);
keyFormat.getHmacKeyFormat().getParams().setTagSize(TAG_SIZE);
return keyFormat;
};
/**
* creates new AesCtrHmacAeadKey with allowed parameters
* @return {!PbAesCtrHmacAeadKey}
*/
const createTestKey = function() {
const KEY_SIZE = 16;
const IV_SIZE = 12;
const TAG_SIZE = 16;
let key =
new PbAesCtrHmacAeadKey().setVersion(0).setAesCtrKey(new PbAesCtrKey());
key.getAesCtrKey().setVersion(0);
key.getAesCtrKey().setParams(new PbAesCtrParams());
key.getAesCtrKey().getParams().setIvSize(IV_SIZE);
key.getAesCtrKey().setKeyValue(Random.randBytes(KEY_SIZE));
// set HMAC key
key.setHmacKey(new PbHmacKey());
key.getHmacKey().setVersion(0);
key.getHmacKey().setParams(new PbHmacParams());
key.getHmacKey().getParams().setHash(PbHashType.SHA1);
key.getHmacKey().getParams().setTagSize(TAG_SIZE);
key.getHmacKey().setKeyValue(Random.randBytes(KEY_SIZE));
return key;
};
/**
* creates new PbKeyData with allowed parameters
* @return {!PbKeyData}
*/
const createTestKeyData = function() {
let keyData = new PbKeyData()
.setTypeUrl(KEY_TYPE)
.setValue(createTestKey().serializeBinary())
.setKeyMaterialType(PbKeyData.KeyMaterialType.SYMMETRIC);
return keyData;
};
describe('aes ctr hmac aead key manager test', function() {
/////////////////////////////////////////////////////////////////////////////
// tests for newKey method
// newKey method -- key formats
it('new key bad key format', async function() {
const keyFormat = new PbAesCtrKeyFormat();
const manager = new AesCtrHmacAeadKeyManager();
try {
manager.getKeyFactory().newKey(keyFormat);
} catch (e) {
expect(e.toString())
.toBe('SecurityException: Expected AesCtrHmacAeadKeyFormat-proto');
return;
}
fail('An exception should be thrown.');
});
it('new key bad serialized key', async function() {
// this is not a serialized key format
const serializedKeyFormat = new Uint8Array(4);
const manager = new AesCtrHmacAeadKeyManager();
try {
manager.getKeyFactory().newKey(serializedKeyFormat);
} catch (e) {
expect(e.toString())
.toBe(
'SecurityException: Could not parse the given Uint8Array as a serialized' +
' proto of ' + KEY_TYPE);
return;
}
fail('An exception should be thrown.');
});
// newKey method -- bad parametrs of AES CTR KEY format
it('new key not supported aes ctr key size', async function() {
const /** number */ keySize = 11;
const manager = new AesCtrHmacAeadKeyManager();
let keyFormat = createTestKeyFormat();
keyFormat.getAesCtrKeyFormat().setKeySize(keySize);
try {
manager.getKeyFactory().newKey(keyFormat);
} catch (e) {
expect(e.toString())
.toBe(
'InvalidArgumentsException: unsupported AES key size: ' +
keySize);
return;
}
fail('An exception should be thrown.');
});
it('new key iv size out of range', async function() {
const /** Array<number> */ ivSizeOutOfRange = [10, 18];
const manager = new AesCtrHmacAeadKeyManager();
let keyFormat = createTestKeyFormat();
const ivSizeOutOfRangeLength = ivSizeOutOfRange.length;
for (let i = 0; i < ivSizeOutOfRangeLength; i++) {
keyFormat.getAesCtrKeyFormat().getParams().setIvSize(ivSizeOutOfRange[i]);
try {
manager.getKeyFactory().newKey(keyFormat);
} catch (e) {
expect(e.toString())
.toBe(
'SecurityException: Invalid AES CTR HMAC key format: IV size is ' +
'out of range: ' + ivSizeOutOfRange[i]);
continue;
}
fail('An exception should be thrown.');
}
});
// newKey method -- bad parametrs of HMAC KEY format
it('new key small hmac key size', async function() {
const /** number */ keySize = 11;
const manager = new AesCtrHmacAeadKeyManager();
let keyFormat = createTestKeyFormat();
keyFormat.getHmacKeyFormat().setKeySize(keySize);
try {
manager.getKeyFactory().newKey(keyFormat);
} catch (e) {
expect(e.toString())
.toBe(
'SecurityException: Invalid AES CTR HMAC key format: HMAC key is' +
' too small: ' + keySize);
return;
}
fail('An exception should be thrown.');
});
it('new key hash type unsupported', async function() {
const manager = new AesCtrHmacAeadKeyManager();
let keyFormat = createTestKeyFormat();
keyFormat.getHmacKeyFormat().getParams().setHash(PbHashType.UNKNOWN_HASH);
try {
manager.getKeyFactory().newKey(keyFormat);
} catch (e) {
expect(e.toString()).toBe('SecurityException: Unknown hash type.');
return;
}
fail('An exception should be thrown.');
});
it('new key small tag size', async function() {
const SMALL_TAG_SIZE = 8;
const manager = new AesCtrHmacAeadKeyManager();
let keyFormat = createTestKeyFormat();
keyFormat.getHmacKeyFormat().getParams().setTagSize(SMALL_TAG_SIZE);
try {
manager.getKeyFactory().newKey(keyFormat);
} catch (e) {
expect(e.toString())
.toBe(
'SecurityException: Invalid HMAC params: tag size ' +
SMALL_TAG_SIZE + ' is too small.');
return;
}
fail('An exception should be thrown.');
});
it('new key big tag size for hash type', async function() {
const tagSizes = [
{'hashType': PbHashType.SHA1, 'tagSize': 22},
{'hashType': PbHashType.SHA256, 'tagSize': 34},
{'hashType': PbHashType.SHA512, 'tagSize': 66},
];
const manager = new AesCtrHmacAeadKeyManager();
let keyFormat = createTestKeyFormat();
const tagSizesLength = tagSizes.length;
for (let i = 0; i < tagSizesLength; i++) {
keyFormat.getHmacKeyFormat().getParams().setHash(tagSizes[i]['hashType']);
keyFormat.getHmacKeyFormat().getParams().setTagSize(
tagSizes[i]['tagSize']);
try {
manager.getKeyFactory().newKey(keyFormat);
} catch (e) {
expect(e.toString())
.toBe(
'SecurityException: Invalid HMAC params: tag size ' +
tagSizes[i]['tagSize'] + ' is out of range.');
continue;
}
fail('An exception should be thrown.');
}
});
it('new key via format proto', async function() {
const manager = new AesCtrHmacAeadKeyManager();
const keyFormat = createTestKeyFormat();
const key = /** @type {!PbAesCtrHmacAeadKey}*/ (
manager.getKeyFactory().newKey(keyFormat));
// testing AES CTR key
expect(key.getAesCtrKey().getKeyValue().length)
.toBe(keyFormat.getAesCtrKeyFormat().getKeySize());
expect(key.getAesCtrKey().getVersion()).toBe(0);
expect(key.getAesCtrKey().getParams().getIvSize())
.toBe(keyFormat.getAesCtrKeyFormat().getParams().getIvSize());
// testing HMAC key
expect(key.getHmacKey().getKeyValue().length)
.toBe(keyFormat.getHmacKeyFormat().getKeySize());
expect(key.getHmacKey().getVersion()).toBe(0);
expect(key.getHmacKey().getParams().getHash())
.toBe(keyFormat.getHmacKeyFormat().getParams().getHash());
expect(key.getHmacKey().getParams().getTagSize())
.toBe(keyFormat.getHmacKeyFormat().getParams().getTagSize());
});
it('new key via serialized format proto', async function() {
const manager = new AesCtrHmacAeadKeyManager();
const keyFormat = createTestKeyFormat();
const serializedKeyFormat = keyFormat.serializeBinary();
const key = /** @type {!PbAesCtrHmacAeadKey} */ (
manager.getKeyFactory().newKey(serializedKeyFormat));
// testing AES CTR key
expect(key.getAesCtrKey().getKeyValue().length)
.toBe(keyFormat.getAesCtrKeyFormat().getKeySize());
expect(key.getAesCtrKey().getVersion()).toBe(0);
expect(key.getAesCtrKey().getParams().getIvSize())
.toBe(keyFormat.getAesCtrKeyFormat().getParams().getIvSize());
// testing HMAC key
expect(key.getHmacKey().getKeyValue().length)
.toBe(keyFormat.getHmacKeyFormat().getKeySize());
expect(key.getHmacKey().getVersion()).toBe(0);
expect(key.getHmacKey().getParams().getHash())
.toBe(keyFormat.getHmacKeyFormat().getParams().getHash());
expect(key.getHmacKey().getParams().getTagSize())
.toBe(keyFormat.getHmacKeyFormat().getParams().getTagSize());
});
/////////////////////////////////////////////////////////////////////////////
// tests for NewKeyData method
it('new key data bad serialized key', async function() {
const serializedKeyFormats = [new Uint8Array(1), new Uint8Array(0)];
const aeadKeyManager = new AesCtrHmacAeadKeyManager();
const serializedKeyFormatsLength = serializedKeyFormats.length;
for (let i = 0; i < serializedKeyFormatsLength; i++) {
try {
aeadKeyManager.getKeyFactory().newKeyData(serializedKeyFormats[i]);
} catch (e) {
expect(e.toString())
.toBe(
'SecurityException: Could not parse the given Uint8Array as a ' +
'serialized proto of ' + KEY_TYPE);
continue;
}
fail(
'An exception should be thrown for the string: ' +
serializedKeyFormats[i]);
}
});
it('new key data from valid key', async function() {
const keyFormat = createTestKeyFormat();
const serializedKeyFormat = keyFormat.serializeBinary();
const manager = new AesCtrHmacAeadKeyManager();
const keyData = manager.getKeyFactory().newKeyData(serializedKeyFormat);
expect(keyData.getTypeUrl()).toBe(KEY_TYPE);
expect(keyData.getKeyMaterialType())
.toBe(PbKeyData.KeyMaterialType.SYMMETRIC);
const key = PbAesCtrHmacAeadKey.deserializeBinary(keyData.getValue());
expect(key.getAesCtrKey().getKeyValue().length)
.toBe(keyFormat.getAesCtrKeyFormat().getKeySize());
expect(key.getHmacKey().getKeyValue().length)
.toBe(keyFormat.getHmacKeyFormat().getKeySize());
});
/////////////////////////////////////////////////////////////////////////////
// tests for getPrimitive method
it('get primitive unsupported key data type', async function() {
const aeadKeyManager = new AesCtrHmacAeadKeyManager();
let keyData = createTestKeyData().setTypeUrl('bad type url');
try {
await aeadKeyManager.getPrimitive(Aead, keyData);
} catch (e) {
expect(e.toString())
.toBe(
'SecurityException: Key type ' + keyData.getTypeUrl() +
' is not supported. This key manager supports ' + KEY_TYPE + '.');
return;
}
fail('An exception should be thrown');
});
it('get primitive unsupported key type', async function() {
const aeadKeyManager = new AesCtrHmacAeadKeyManager();
let key = new PbAesCtrKey();
try {
await aeadKeyManager.getPrimitive(Aead, key);
} catch (e) {
expect(e.toString())
.toBe(
'SecurityException: Given key type is not supported. ' +
'This key manager supports ' + KEY_TYPE + '.');
return;
}
fail('An exception should be thrown');
});
it('get primitive bad version', async function() {
const version = 1;
const aeadKeyManager = new AesCtrHmacAeadKeyManager();
let /** PbAesCtrHmacAeadKey */ key = createTestKey();
key.getAesCtrKey().setVersion(version);
try {
await aeadKeyManager.getPrimitive(Aead, key);
} catch (e) {
expect(e.toString())
.toBe(
'SecurityException: Version is out of bound, must be between 0 ' +
'and ' + VERSION + '.');
return;
}
fail('An exception should be thrown');
});
it('get primitive short aes ctr key', async function() {
const keySize = 5;
const aeadKeyManager = new AesCtrHmacAeadKeyManager();
let /** PbAesCtrHmacAeadKey */ key = createTestKey();
key.getAesCtrKey().setKeyValue(new Uint8Array(keySize));
try {
await aeadKeyManager.getPrimitive(Aead, key);
} catch (e) {
expect(e.toString())
.toBe(
'InvalidArgumentsException: unsupported AES key size: ' +
keySize);
return;
}
fail('An exception should be thrown');
});
it('get primitive aes ctr key small iv size', async function() {
const /** Array<number> */ ivSizeOutOfRange = [9, 19];
const manager = new AesCtrHmacAeadKeyManager();
let /** PbAesCtrHmacAeadKey */ key = createTestKey();
const ivSizeOutOfRangeLength = ivSizeOutOfRange.length;
for (let i = 0; i < ivSizeOutOfRangeLength; i++) {
key.getAesCtrKey().getParams().setIvSize(ivSizeOutOfRange[i]);
try {
await manager.getPrimitive(Aead, key);
} catch (e) {
expect(e.toString())
.toBe(
'SecurityException: Invalid AES CTR HMAC key format: IV size is ' +
'out of range: ' + ivSizeOutOfRange[i]);
continue;
}
fail('An exception should be thrown.');
}
});
it('get primitive short hmac key', async function() {
const keySize = 5;
const aeadKeyManager = new AesCtrHmacAeadKeyManager();
let /** PbAesCtrHmacAeadKey */ key = createTestKey();
key.getHmacKey().setKeyValue(new Uint8Array(keySize));
try {
await aeadKeyManager.getPrimitive(Aead, key);
} catch (e) {
expect(e.toString())
.toBe(
'SecurityException: Invalid AES CTR HMAC key format: HMAC key is' +
' too small: ' + keySize);
return;
}
fail('An exception should be thrown');
});
it('get primitive hmac key unsupported hash type', async function() {
const aeadKeyManager = new AesCtrHmacAeadKeyManager();
let /** PbAesCtrHmacAeadKey */ key = createTestKey();
key.getHmacKey().getParams().setHash(PbHashType.UNKNOWN_HASH);
try {
await aeadKeyManager.getPrimitive(Aead, key);
} catch (e) {
expect(e.toString()).toBe('SecurityException: Unknown hash type.');
return;
}
fail('An exception should be thrown');
});
it('get primitive hmac key small tag size', async function() {
const SMALL_TAG_SIZE = 9;
const aeadKeyManager = new AesCtrHmacAeadKeyManager();
let /** PbAesCtrHmacAeadKey */ key = createTestKey();
key.getHmacKey().getParams().setTagSize(SMALL_TAG_SIZE);
try {
await aeadKeyManager.getPrimitive(Aead, key);
} catch (e) {
expect(e.toString())
.toBe(
'SecurityException: Invalid HMAC params: tag size ' +
SMALL_TAG_SIZE + ' is too small.');
return;
}
fail('An exception should be thrown');
});
it('get primitive hmac big tag size', async function() {
const tagSizes = [
{'hashType': PbHashType.SHA1, 'tagSize': 22},
{'hashType': PbHashType.SHA256, 'tagSize': 34},
{'hashType': PbHashType.SHA512, 'tagSize': 66},
];
const manager = new AesCtrHmacAeadKeyManager();
let /** PbAesCtrHmacAeadKey */ key = createTestKey();
const tagSizesLength = tagSizes.length;
for (let i = 0; i < tagSizesLength; i++) {
key.getHmacKey().getParams().setHash(tagSizes[i]['hashType']);
key.getHmacKey().getParams().setTagSize(tagSizes[i]['tagSize']);
try {
await manager.getPrimitive(Aead, key);
} catch (e) {
expect(e.toString())
.toBe(
'SecurityException: Invalid HMAC params: tag size ' +
tagSizes[i]['tagSize'] + ' is out of range.');
continue;
}
fail('An exception should be thrown.');
}
});
// tests for getting primitive from valid key/keyData
it('get primitive from key', async function() {
const aeadKeyManager = new AesCtrHmacAeadKeyManager();
const key = createTestKey();
const plaintext = Random.randBytes(8);
const aad = Random.randBytes(8);
const /** Aead */ primitive = await aeadKeyManager.getPrimitive(Aead, key);
const ciphertext = await primitive.encrypt(plaintext, aad);
const decryptedCiphertext = await primitive.decrypt(ciphertext, aad);
expect(decryptedCiphertext).toEqual(plaintext);
});
it('get primitive from key data', async function() {
const aeadKeyManager = new AesCtrHmacAeadKeyManager();
const keyData = createTestKeyData();
const plaintext = Random.randBytes(8);
const aad = Random.randBytes(8);
const /** Aead */ primitive =
await aeadKeyManager.getPrimitive(Aead, keyData);
const ciphertext = await primitive.encrypt(plaintext, aad);
const decryptedCiphertext = await primitive.decrypt(ciphertext, aad);
expect(decryptedCiphertext).toEqual(plaintext);
});
it('get primitive unsupported primitive', async function() {
const manager = new AesCtrHmacAeadKeyManager();
const keyData = createTestKeyData();
try {
await manager.getPrimitive(Mac, keyData);
} catch (e) {
expect(e.toString())
.toBe(
'SecurityException: Requested primitive type which is not ' +
'supported by this key manager.');
return;
}
fail('An exception should be thrown.');
});
/////////////////////////////////////////////////////////////////////////////
// tests for getVersion, getKeyType and doesSupport methods
it('get version should be zero', async function() {
const manager = new AesCtrHmacAeadKeyManager();
expect(manager.getVersion()).toBe(0);
});
it('get key type should be aes ctr hmac aead key', async function() {
const manager = new AesCtrHmacAeadKeyManager();
expect(manager.getKeyType()).toBe(KEY_TYPE);
});
it('does support should support aes ctr hmac aead key', async function() {
const manager = new AesCtrHmacAeadKeyManager();
expect(manager.doesSupport(KEY_TYPE)).toBe(true);
});
it('get primitive type should be aead', async function() {
const manager = new AesCtrHmacAeadKeyManager();
expect(manager.getPrimitiveType()).toBe(Aead);
});
});