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.

190 lines (170 loc) 5.51 kB
/** * @license * Copyright 2020 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import {SecurityException} from '../exception/security_exception'; import {CryptoFormat} from './crypto_format'; import {PbKeysetKey, PbKeyStatusType, PbOutputPrefixType} from './proto'; import {Constructor} from './util'; /** * Auxiliary class for PrimitiveSet * Entry-objects hold individual instances of primitives in the set. * * @template P * @final */ export class Entry<P> { constructor( private readonly primitive: P, private readonly identifier: Uint8Array, private readonly keyStatus: PbKeyStatusType, private readonly outputPrefixType: PbOutputPrefixType) {} getPrimitive(): P { return this.primitive; } getIdentifier(): Uint8Array { return this.identifier; } getKeyStatus(): PbKeyStatusType { return this.keyStatus; } getOutputPrefixType(): PbOutputPrefixType { return this.outputPrefixType; } } /** * A container class for a set of primitives (i.e. implementations of * cryptographic primitives offered by Tink). It provides also additional * properties for the primitives it holds. In particular, one of the primitives * in the set can be distinguished as "the primary" one. * * PrimitiveSet is an auxiliary class used for supporting key rotation: * primitives in a set correspond to keys in a keyset. Users will usually work * with primitive instances which essentially wrap primitive sets. For example * an instance of an Aead-primitive for a given keyset holds a set of * Aead-primitives corresponding to the keys in the keyset, and uses the set * members to do the actual crypto operations: to encrypt data the primary * Aead-primitive from the set is used, and upon decryption the ciphertext's * prefix determines the identifier of the primitive from the set. * * PrimitiveSet is a public class to allow its use in implementations of custom * primitives. * * @final */ export class PrimitiveSet<P> { private primary: Entry<P>|null = null; // Keys have to be stored as strings as two Uint8Arrays holding the same // digits are still different objects. private readonly identifierToPrimitivesMap: Map<string, Array<Entry<P>>>; constructor(private readonly primitiveType: Constructor<P>) { this.identifierToPrimitivesMap = new Map(); } /** * Returns the type of primitives contained in this set. * */ getPrimitiveType(): Constructor<P> { return this.primitiveType; } /** * Creates an entry in the primitive table and returns it. * * */ addPrimitive(primitive: P, key: PbKeysetKey): Entry<P> { if (!primitive) { throw new SecurityException('Primitive has to be non null.'); } if (!key) { throw new SecurityException('Key has to be non null.'); } const identifier = CryptoFormat.getOutputPrefix(key); const entry = new Entry( primitive, identifier, key.getStatus(), key.getOutputPrefixType()); this.addPrimitiveToMap(entry); return entry; } /** * Returns the entry with the primary primitive. * */ getPrimary(): Entry<P>|null { return this.primary; } /** * Sets given Entry as the primary one. * */ setPrimary(primitive: Entry<P>) { if (!primitive) { throw new SecurityException('Primary cannot be set to null.'); } if (primitive.getKeyStatus() != PbKeyStatusType.ENABLED) { throw new SecurityException('Primary has to be enabled.'); } // There has to be exactly one key enabled with this identifier. const entries = this.getPrimitives(primitive.getIdentifier()); let entryFound = false; const entriesLength = entries.length; for (let i = 0; i < entriesLength; i++) { if (entries[i].getKeyStatus() === PbKeyStatusType.ENABLED) { entryFound = true; break; } } if (!entryFound) { throw new SecurityException( 'Primary cannot be set to an entry which is ' + 'not held by this primitive set.'); } this.primary = primitive; } /** * Returns all primitives using RAW prefix. * */ getRawPrimitives(): Array<Entry<P>> { return this.getPrimitives(CryptoFormat.RAW_PREFIX); } /** * Returns the entries with primitive identified with identifier. * * */ getPrimitives(identifier: Uint8Array): Array<Entry<P>> { const result = this.getPrimitivesFromMap(identifier); if (!result) { return []; } else { return result; } } /** * Returns a set of primitives which corresponds to the given identifier. * * */ private getPrimitivesFromMap(identifier: Uint8Array| string): Array<Entry<P>>|undefined { if (identifier instanceof Uint8Array) { identifier = [...identifier].toString(); } return this.identifierToPrimitivesMap.get(identifier); } /** * Add primitive to map. * */ private addPrimitiveToMap(entry: Entry<P>) { const identifier = entry.getIdentifier(); const id = [...identifier].toString(); const existing = this.getPrimitivesFromMap(id); if (!existing) { this.identifierToPrimitivesMap.set(id, [entry]); } else { existing.push(entry); this.identifierToPrimitivesMap.set(id, existing); } } }