UNPKG

pooja-docucomb-tink-crypto

Version:

A multi-language, cross-platform library that provides cryptographic APIs that are secure, easy to use correctly, and hard(er) to misuse.

351 lines (289 loc) 11.8 kB
/** * @license * Copyright 2020 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import {Aead} from '../aead'; import {SecurityException} from '../exception/security_exception'; import {CryptoFormat} from './crypto_format'; import * as PrimitiveSet from './primitive_set'; import {PbKeysetKey, PbKeyStatusType, PbOutputPrefixType} from './proto'; describe('primitive set test', function() { ///////////////////////////////////////////////////////////////////////////// // tests for addPrimitive method it('add primitive unknown crypto format', function() { const primitive = new DummyAead1(); const key = createKey().setOutputPrefixType(PbOutputPrefixType.UNKNOWN_PREFIX); const primitiveSet = new PrimitiveSet.PrimitiveSet(Aead); try { primitiveSet.addPrimitive(primitive, key); } catch (e: any) { expect(e.toString()).toBe(ExceptionText.unknownPrefixType()); return; } fail('An exception should be thrown.'); }); it('add primitive multiple times should work', function() { const key = createKey(); const primitiveSet = new PrimitiveSet.PrimitiveSet(Aead); for (let i = 0; i < 4; i++) { let primitive; if (i % 2 === 0) { primitive = new DummyAead1(); } else { primitive = new DummyAead2(); } const result = primitiveSet.addPrimitive(primitive, key); expect(result.getPrimitive()).toEqual(primitive); expect(result.getKeyStatus()).toBe(key.getStatus()); expect(result.getOutputPrefixType()).toBe(key.getOutputPrefixType()); expect(result.getIdentifier()).toEqual(CryptoFormat.getOutputPrefix(key)); } }); ///////////////////////////////////////////////////////////////////////////// // tests for getPrimitives method it('get primitives which were not added', function() { // Fill in the structure with some primitives. const numberOfAddedPrimitives = 12; const primitiveSet = initPrimitiveSet(numberOfAddedPrimitives); const key = createKey(/* opt_keyId = */ numberOfAddedPrimitives + 1); const identifier = CryptoFormat.getOutputPrefix(key); const result = primitiveSet.getPrimitives(identifier); expect(result).toEqual([]); }); it('get primitives different identifiers', function() { // Fill in the structure with some primitives. const n = 100; const primitiveSet = new PrimitiveSet.PrimitiveSet(Aead); const added = []; for (let id = 0; id < n; id++) { const legacyKeyType = ((id % 2) < 1); const enabledKey = ((id % 4) < 2); const key = createKey(id, legacyKeyType, enabledKey); let primitive; if ((id % 8) < 4) { primitive = new DummyAead1(); } else { primitive = new DummyAead2(); } const res = primitiveSet.addPrimitive(primitive, key); added.push({key, entry: res}); } // Test that getPrimitives return correct value for them. const addedLength = added.length; for (let i = 0; i < addedLength; i++) { const identifier = CryptoFormat.getOutputPrefix(added[i].key); // Should return a set containing only one primitive as each added // primitive has different identifier. const expectedResult = [added[i].entry]; const result = primitiveSet.getPrimitives(identifier); expect(result).toEqual(expectedResult); } }); it('get primitives same identifiers', function() { // Fill in the structure with some primitives. const numberOfAddedPrimitives = 50; const primitiveSet = initPrimitiveSet(numberOfAddedPrimitives); // Add a group of primitives with same identifier. const n = 12; const keyId = 0xABCDEF98; const legacyKeyType = false; const expectedResult = []; for (let i = 0; i < n; i++) { const enabledKey = ((i % 2) < 1); const key = createKey(keyId, legacyKeyType, enabledKey); let primitive; if ((i % 4) < 2) { primitive = new DummyAead1(); } else { primitive = new DummyAead2(); } const res = primitiveSet.addPrimitive(primitive, key); expectedResult.push(res); } const identifier = CryptoFormat.getOutputPrefix(createKey(keyId, legacyKeyType)); const result = primitiveSet.getPrimitives(identifier); expect(result).toEqual(expectedResult); }); ///////////////////////////////////////////////////////////////////////////// // tests for getRawPrimitives method it('get raw primitives', function() { const numberOfAddedPrimitives = 20; const primitiveSet = initPrimitiveSet(numberOfAddedPrimitives); // No RAW primitives were added. const expectedResult: Array<PrimitiveSet.Entry<Aead>> = []; let result = primitiveSet.getRawPrimitives(); expect(result).toEqual(expectedResult); // Add RAW primitives and check the result again after each adding. const key = createKey().setOutputPrefixType(PbOutputPrefixType.RAW); let addResult = primitiveSet.addPrimitive(new DummyAead1(), key); expectedResult.push(addResult); result = primitiveSet.getRawPrimitives(); expect(result).toEqual(expectedResult); key.setStatus(PbKeyStatusType.DISABLED); addResult = primitiveSet.addPrimitive(new DummyAead2(), key); expectedResult.push(addResult); result = primitiveSet.getRawPrimitives(); expect(result).toEqual(expectedResult); }); ///////////////////////////////////////////////////////////////////////////// // tests for setPrimary and getPrimary methods it('set primary to nonholded entry', function() { const primitiveSet = new PrimitiveSet.PrimitiveSet(Aead); const entry = new PrimitiveSet.Entry( new DummyAead1(), new Uint8Array(10), PbKeyStatusType.ENABLED, PbOutputPrefixType.TINK); try { primitiveSet.setPrimary(entry); } catch (e: any) { expect(e.toString()).toBe(ExceptionText.setPrimaryToMissingEntry()); return; } fail('An exception should be thrown.'); }); it('set primary to entry with disabled key status', function() { const key = createKey(/* opt_keyId = */ 0x12345678, /* opt_legacy = */ false, /* opt_enabled = */ false); const primitiveSet = new PrimitiveSet.PrimitiveSet(Aead); const primary = primitiveSet.addPrimitive(new DummyAead1(), key); try { primitiveSet.setPrimary(primary); } catch (e: any) { expect(e.toString()).toBe(ExceptionText.setPrimaryToDisabled()); return; } fail('An exception should be thrown.'); }); it('set and get primary', function() { const primitiveSet = new PrimitiveSet.PrimitiveSet(Aead); expect(primitiveSet.getPrimary()).toBe(null); const key1 = createKey(/* opt_keyId = */ 0xBBBCCC); const result = primitiveSet.addPrimitive(new DummyAead1(), key1); // Check that primary remains unset, set it to newly added and verify that // it was set. expect(primitiveSet.getPrimary()).toBe(null); primitiveSet.setPrimary(result); expect(primitiveSet.getPrimary()).toEqual(result); const key2 = createKey(/* opt_keyId = */ 0xAAABBB); // Add new primitive, check that it does not change primary. const result2 = primitiveSet.addPrimitive(new DummyAead2(), key2); expect(primitiveSet.getPrimary()).toEqual(result); // Change the primary and verify the change. primitiveSet.setPrimary(result2); expect(primitiveSet.getPrimary()).toEqual(result2); }); it('set primary, raw primitives', function() { const primitiveSet = new PrimitiveSet.PrimitiveSet(Aead); for (let i = 0; i < 3; i++) { const key = createKey(i).setOutputPrefixType(PbOutputPrefixType.RAW); primitiveSet.addPrimitive(new DummyAead1(), key); } const primaryKey = createKey(255).setOutputPrefixType(PbOutputPrefixType.RAW); const primaryEntry = primitiveSet.addPrimitive(new DummyAead1(), primaryKey); primitiveSet.setPrimary(primaryEntry); }); it('get primary type', function() { const primitiveSet = new PrimitiveSet.PrimitiveSet(Aead); expect(primitiveSet.getPrimitiveType()).toEqual(Aead); }); }); // Helper classes and functions used for testing purposes. class ExceptionText { static unknownPrefixType(): string { return 'SecurityException: Unsupported key prefix type.'; } static addingNullPrimitive(): string { return 'SecurityException: Primitive has to be non null.'; } static addingNullKey(): string { return 'SecurityException: Key has to be non null.'; } static setPrimaryToNull(): string { return 'SecurityException: Primary cannot be set to null.'; } static setPrimaryToMissingEntry(): string { return 'SecurityException: Primary cannot be set to an entry which is ' + 'not held by this primitive set.'; } static setPrimaryToDisabled(): string { return 'SecurityException: Primary has to be enabled.'; } } /** @final */ class DummyAead1 extends Aead { encrypt(plaintext: Uint8Array, aad: Uint8Array): Promise<Uint8Array> { throw new SecurityException( 'Not implemented, intentended just for testing.'); } decrypt(ciphertext: Uint8Array, aad: Uint8Array): Promise<Uint8Array> { throw new SecurityException( 'Not implemented, intentended just for testing.'); } } /** @final */ class DummyAead2 extends Aead { encrypt(plaintext: Uint8Array, aad: Uint8Array): Promise<Uint8Array> { throw new SecurityException( 'Not implemented, intentended just for testing.'); } decrypt(ciphertext: Uint8Array, aad: Uint8Array): Promise<Uint8Array> { throw new SecurityException( 'Not implemented, intentended just for testing.'); } } /** * Function for creating primitive sets for testing purposes. * Returns a primitive set containing n values with keyIds from {0, .. , n-1}. * There are different combinations of * primitive types ({DummyAead1, DummyAead2}), * key status (enabled, disabled), * and key types (legacy, tink). */ function initPrimitiveSet(n: number): PrimitiveSet.PrimitiveSet<Aead> { const primitiveSet = new PrimitiveSet.PrimitiveSet<Aead>(Aead); // Set primary. const primaryKey = createKey(/* opt_id = */ 0, /* opt_legacy = */ false, /* opt_enabled = */ true); const primary = primitiveSet.addPrimitive(new DummyAead1(), primaryKey); primitiveSet.setPrimary(primary); // Add n-1 other keys to primitive set. for (let id = 1; id < n; id++) { const legacyKeyType = ((id % 2) < 1); const enabledKey = ((id % 4) < 2); const key = createKey(id, legacyKeyType, enabledKey); let primitive; if ((id % 8) < 4) { primitive = new DummyAead1(); } else { primitive = new DummyAead2(); } primitiveSet.addPrimitive(primitive, key); } return primitiveSet; } /** * Function for creating keys for testing purposes. * If doesn't set otherwise it generates a key with id 0x12345678, which is * ENABLED and with prefix type TINK. */ function createKey( opt_keyId: number = 0x12345678, opt_legacy: boolean = false, opt_enabled: boolean = true): PbKeysetKey { const key = new PbKeysetKey(); if (opt_enabled) { key.setStatus(PbKeyStatusType.ENABLED); } else { key.setStatus(PbKeyStatusType.DISABLED); } if (opt_legacy) { key.setOutputPrefixType(PbOutputPrefixType.LEGACY); } else { key.setOutputPrefixType(PbOutputPrefixType.TINK); } key.setKeyId(opt_keyId); return key; }