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.

238 lines (218 loc) 8.5 kB
/** * @license * Copyright 2020 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import {SecurityException} from '../exception/security_exception'; import * as KeyManager from '../internal/key_manager'; import {PbEcdsaKeyFormat, PbEcdsaParams, PbEcdsaPrivateKey, PbEcdsaPublicKey, PbKeyData, PbMessage} from '../internal/proto'; import {ProtoBytes} from '../internal/proto_shims'; import * as Util from '../internal/util'; import {Constructor} from '../internal/util'; import * as Bytes from '../subtle/bytes'; import * as ecdsaSign from '../subtle/ecdsa_sign'; import * as EllipticCurves from '../subtle/elliptic_curves'; import {EcdsaPublicKeyManager} from './ecdsa_public_key_manager'; import * as EcdsaUtil from './ecdsa_util'; import {PublicKeySign} from './internal/public_key_sign'; const VERSION = 0; /** * @final */ class EcdsaPrivateKeyFactory implements KeyManager.PrivateKeyFactory { /** */ async newKey(keyFormat: PbMessage|Uint8Array): Promise<PbEcdsaPrivateKey> { if (!keyFormat) { throw new SecurityException('Key format has to be non-null.'); } const keyFormatProto = EcdsaPrivateKeyFactory.getKeyFormatProto(keyFormat); EcdsaUtil.validateKeyFormat(keyFormatProto); const params = keyFormatProto.getParams(); if (!params) { throw new SecurityException('Params not set'); } const curveTypeProto = params.getCurve(); const curveTypeSubtle = Util.curveTypeProtoToSubtle(curveTypeProto); const curveName = EllipticCurves.curveToString(curveTypeSubtle); const keyPair = await EllipticCurves.generateKeyPair('ECDSA', curveName); const jsonPublicKey = await EllipticCurves.exportCryptoKey(keyPair.publicKey!); const jsonPrivateKey = await EllipticCurves.exportCryptoKey(keyPair.privateKey!); return EcdsaPrivateKeyFactory.jsonToProtoKey( jsonPrivateKey, jsonPublicKey, params); } /** */ async newKeyData(serializedKeyFormat: Uint8Array): Promise<PbKeyData> { const key = await this.newKey(serializedKeyFormat); const keyData = (new PbKeyData()) .setTypeUrl(EcdsaPrivateKeyManager.KEY_TYPE) .setValue(key.serializeBinary()) .setKeyMaterialType(PbKeyData.KeyMaterialType.ASYMMETRIC_PRIVATE); return keyData; } getPublicKeyData(serializedPrivateKey: Uint8Array) { const privateKey = deserializePrivateKey(serializedPrivateKey); const publicKey = privateKey.getPublicKey(); if (!publicKey) { throw new SecurityException('Public key not set'); } const publicKeyData = (new PbKeyData()) .setValue(publicKey.serializeBinary()) .setTypeUrl(EcdsaPublicKeyManager.KEY_TYPE) .setKeyMaterialType(PbKeyData.KeyMaterialType.ASYMMETRIC_PUBLIC); return publicKeyData; } /** * Creates a private key proto corresponding to given JSON key pair and with * the given params. * */ private static jsonToProtoKey( jsonPrivateKey: JsonWebKey, jsonPublicKey: JsonWebKey, params: PbEcdsaParams): PbEcdsaPrivateKey { const {x, y} = jsonPublicKey; if (x === undefined) { throw new SecurityException('x must be set'); } if (y === undefined) { throw new SecurityException('y must be set'); } const publicKeyProto = (new PbEcdsaPublicKey()) .setVersion(EcdsaPublicKeyManager.VERSION) .setParams(params) .setX(Bytes.fromBase64(x, true)) .setY(Bytes.fromBase64(y, true)); const {d} = jsonPrivateKey; if (d === undefined) { throw new SecurityException('d must be set'); } const privateKeyProto = (new PbEcdsaPrivateKey()) .setVersion(VERSION) .setPublicKey(publicKeyProto) .setKeyValue(Bytes.fromBase64(d, true)); return privateKeyProto; } /** * The input keyFormat is either deserialized (in case that the input is * Uint8Array) or checked to be an EcdsaKeyFormat-proto (otherwise). * */ private static getKeyFormatProto(keyFormat: PbMessage| Uint8Array): PbEcdsaKeyFormat { if (keyFormat instanceof Uint8Array) { return EcdsaPrivateKeyFactory.deserializeKeyFormat(keyFormat); } else if (keyFormat instanceof PbEcdsaKeyFormat) { return keyFormat; } else { throw new SecurityException( 'Expected ' + EcdsaPrivateKeyManager.KEY_TYPE + ' key format proto.'); } } private static deserializeKeyFormat(keyFormat: Uint8Array): PbEcdsaKeyFormat { let keyFormatProto: PbEcdsaKeyFormat; try { keyFormatProto = PbEcdsaKeyFormat.deserializeBinary(keyFormat); } catch (e) { throw new SecurityException( 'Input cannot be parsed as ' + EcdsaPrivateKeyManager.KEY_TYPE + ' key format proto.'); } if (!keyFormatProto.getParams()) { throw new SecurityException( 'Input cannot be parsed as ' + EcdsaPrivateKeyManager.KEY_TYPE + ' key format proto.'); } return keyFormatProto; } } /** * @final */ export class EcdsaPrivateKeyManager implements KeyManager.KeyManager<PublicKeySign> { private static readonly SUPPORTED_PRIMITIVE = PublicKeySign; static KEY_TYPE: string = 'type.googleapis.com/google.crypto.tink.EcdsaPrivateKey'; keyFactory = new EcdsaPrivateKeyFactory(); async getPrimitive( primitiveType: Constructor<PublicKeySign>, key: PbKeyData|PbMessage) { if (primitiveType !== this.getPrimitiveType()) { throw new SecurityException( 'Requested primitive type which is not ' + 'supported by this key manager.'); } const keyProto = EcdsaPrivateKeyManager.getKeyProto(key); EcdsaUtil.validatePrivateKey( keyProto, VERSION, EcdsaPublicKeyManager.VERSION); const recepientPrivateKey = EcdsaUtil.getJsonWebKeyFromProto(keyProto); const publicKey = keyProto.getPublicKey(); if (!publicKey) { throw new SecurityException('Public key not set'); } const params = publicKey.getParams(); if (!params) { throw new SecurityException('Params not set'); } const hash = Util.hashTypeProtoToString(params.getHashType()); const encoding = EcdsaUtil.encodingTypeProtoToEnum(params.getEncoding()); return ecdsaSign.fromJsonWebKey(recepientPrivateKey, hash, encoding); } doesSupport(keyType: string) { return keyType === this.getKeyType(); } getKeyType() { return EcdsaPrivateKeyManager.KEY_TYPE; } getPrimitiveType() { return EcdsaPrivateKeyManager.SUPPORTED_PRIMITIVE; } getVersion() { return VERSION; } getKeyFactory() { return this.keyFactory; } private static getKeyProto(keyMaterial: PbKeyData| PbMessage): PbEcdsaPrivateKey { if (keyMaterial instanceof PbKeyData) { return EcdsaPrivateKeyManager.getKeyProtoFromKeyData(keyMaterial); } if (keyMaterial instanceof PbEcdsaPrivateKey) { return keyMaterial; } throw new SecurityException( 'Key type is not supported. This key ' + 'manager supports ' + EcdsaPrivateKeyManager.KEY_TYPE + '.'); } private static getKeyProtoFromKeyData(keyData: PbKeyData): PbEcdsaPrivateKey { if (keyData.getTypeUrl() !== EcdsaPrivateKeyManager.KEY_TYPE) { throw new SecurityException( 'Key type ' + keyData.getTypeUrl() + ' is not supported. This key manager supports ' + EcdsaPrivateKeyManager.KEY_TYPE + '.'); } return deserializePrivateKey(keyData.getValue()); } } function deserializePrivateKey(serializedPrivateKey: ProtoBytes): PbEcdsaPrivateKey { let key: PbEcdsaPrivateKey; try { key = PbEcdsaPrivateKey.deserializeBinary(serializedPrivateKey); } catch (e) { throw new SecurityException( 'Input cannot be parsed as ' + EcdsaPrivateKeyManager.KEY_TYPE + ' key-proto.'); } if (!key.getPublicKey() || !key.getKeyValue()) { throw new SecurityException( 'Input cannot be parsed as ' + EcdsaPrivateKeyManager.KEY_TYPE + ' key-proto.'); } return key; }