UNPKG

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.

120 lines 15.7 kB
/** * @license * Copyright 2020 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import { SecurityException } from '../exception/security_exception'; import * as Bytes from '../subtle/bytes'; import * as EllipticCurves from '../subtle/elliptic_curves'; import { PbEllipticCurveType, PbHashType, PbKeyStatusType, PbOutputPrefixType, PbPointFormat } from './proto'; /** Like the `instanceof` operator, but works with `Constructor`. */ export function isInstanceOf(value, ctor) { return value instanceof ctor; } /** * Validates the given key and throws SecurityException if it is invalid. * */ export function validateKey(key) { if (!key) { throw new SecurityException('Key should be non null.'); } if (!key.getKeyData()) { throw new SecurityException('Key data are missing for key ' + key.getKeyId() + '.'); } if (key.getOutputPrefixType() === PbOutputPrefixType.UNKNOWN_PREFIX) { throw new SecurityException('Key ' + key.getKeyId() + ' has unknown output prefix type.'); } if (key.getStatus() === PbKeyStatusType.UNKNOWN_STATUS) { throw new SecurityException('Key ' + key.getKeyId() + ' has unknown status.'); } } /** * Validates the given keyset and throws SecurityException if it is invalid. * */ export function validateKeyset(keyset) { if (!keyset || !keyset.getKeyList() || keyset.getKeyList().length < 1) { throw new SecurityException('Keyset should be non null and must contain at least one key.'); } let hasPrimary = false; const numberOfKeys = keyset.getKeyList().length; for (let i = 0; i < numberOfKeys; i++) { const key = keyset.getKeyList()[i]; validateKey(key); if (keyset.getPrimaryKeyId() === key.getKeyId() && key.getStatus() === PbKeyStatusType.ENABLED) { if (hasPrimary) { throw new SecurityException('Primary key has to be unique.'); } hasPrimary = true; } } if (!hasPrimary) { throw new SecurityException('Primary key has to be in the keyset and ' + 'has to be enabled.'); } } // Functions which are useful for implementation of // private and public EC keys. /** * Either prolong or shrinks the array representing number in BigEndian encoding * to have the specified size. As webcrypto API assumes that x, y and d values * has exactly the supposed number of bytes, whereas corresponding x, y and * keyValue values in proto might either have some leading zeros or the leading * zeros might be missing. * */ export function bigEndianNumberToCorrectLength(bigEndianNumber, sizeInBytes) { const numberLen = bigEndianNumber.length; if (numberLen < sizeInBytes) { const zeros = new Uint8Array(sizeInBytes - numberLen); return Bytes.concat(zeros, bigEndianNumber); } if (numberLen > sizeInBytes) { for (let i = 0; i < numberLen - sizeInBytes; i++) { if (bigEndianNumber[i] != 0) { throw new SecurityException('Number needs more bytes to be represented.'); } } return bigEndianNumber.slice(numberLen - sizeInBytes, numberLen); } return bigEndianNumber; } export function curveTypeProtoToSubtle(curveTypeProto) { switch (curveTypeProto) { case PbEllipticCurveType.NIST_P256: return EllipticCurves.CurveType.P256; case PbEllipticCurveType.NIST_P384: return EllipticCurves.CurveType.P384; case PbEllipticCurveType.NIST_P521: return EllipticCurves.CurveType.P521; default: throw new SecurityException('Unknown curve type.'); } } export function hashTypeProtoToString(hashTypeProto) { switch (hashTypeProto) { case PbHashType.SHA1: return 'SHA-1'; case PbHashType.SHA256: return 'SHA-256'; case PbHashType.SHA512: return 'SHA-512'; default: throw new SecurityException('Unknown hash type.'); } } export function pointFormatProtoToSubtle(pointFormatProto) { switch (pointFormatProto) { case PbPointFormat.UNCOMPRESSED: return EllipticCurves.PointFormatType.UNCOMPRESSED; case PbPointFormat.COMPRESSED: return EllipticCurves.PointFormatType.COMPRESSED; case PbPointFormat.DO_NOT_USE_CRUNCHY_UNCOMPRESSED: return EllipticCurves.PointFormatType.DO_NOT_USE_CRUNCHY_UNCOMPRESSED; default: throw new SecurityException('Unknown point format.'); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2ludGVybmFsL3V0aWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7R0FJRztBQUVILE9BQU8sRUFBQyxpQkFBaUIsRUFBQyxNQUFNLGlDQUFpQyxDQUFDO0FBQ2xFLE9BQU8sS0FBSyxLQUFLLE1BQU0saUJBQWlCLENBQUM7QUFDekMsT0FBTyxLQUFLLGNBQWMsTUFBTSwyQkFBMkIsQ0FBQztBQUU1RCxPQUFPLEVBQUMsbUJBQW1CLEVBQUUsVUFBVSxFQUF5QixlQUFlLEVBQUUsa0JBQWtCLEVBQUUsYUFBYSxFQUFDLE1BQU0sU0FBUyxDQUFDO0FBVW5JLG9FQUFvRTtBQUNwRSxNQUFNLFVBQVUsWUFBWSxDQUN4QixLQUFjLEVBQUUsSUFBb0I7SUFDdEMsT0FBTyxLQUFLLFlBQVksSUFBSSxDQUFDO0FBQy9CLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxNQUFNLFVBQVUsV0FBVyxDQUFDLEdBQWdCO0lBQzFDLElBQUksQ0FBQyxHQUFHLEVBQUU7UUFDUixNQUFNLElBQUksaUJBQWlCLENBQUMseUJBQXlCLENBQUMsQ0FBQztLQUN4RDtJQUNELElBQUksQ0FBQyxHQUFHLENBQUMsVUFBVSxFQUFFLEVBQUU7UUFDckIsTUFBTSxJQUFJLGlCQUFpQixDQUN2QiwrQkFBK0IsR0FBRyxHQUFHLENBQUMsUUFBUSxFQUFFLEdBQUcsR0FBRyxDQUFDLENBQUM7S0FDN0Q7SUFDRCxJQUFJLEdBQUcsQ0FBQyxtQkFBbUIsRUFBRSxLQUFLLGtCQUFrQixDQUFDLGNBQWMsRUFBRTtRQUNuRSxNQUFNLElBQUksaUJBQWlCLENBQ3ZCLE1BQU0sR0FBRyxHQUFHLENBQUMsUUFBUSxFQUFFLEdBQUcsa0NBQWtDLENBQUMsQ0FBQztLQUNuRTtJQUNELElBQUksR0FBRyxDQUFDLFNBQVMsRUFBRSxLQUFLLGVBQWUsQ0FBQyxjQUFjLEVBQUU7UUFDdEQsTUFBTSxJQUFJLGlCQUFpQixD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USxhQUFhLEVBQUU7UUFDckIsS0FBSyxVQUFVLENBQUMsSUFBSTtZQUNsQixPQUFPLE9BQU8sQ0FBQztRQUNqQixLQUFLLFVBQVUsQ0FBQyxNQUFNO1lBQ3BCLE9BQU8sU0FBUyxDQUFDO1FBQ25CLEtBQUssVUFBVSxDQUFDLE1BQU07WUFDcEIsT0FBTyxTQUFTLENBQUM7UUFDbkI7WUFDRSxNQUFNLElBQUksaUJBQWlCLENBQUMsb0JBQW9CLENBQUMsQ0FBQztLQUNyRDtBQUNILENBQUM7QUFFRCxNQUFNLFVBQVUsd0JBQXdCLENBQUMsZ0JBQStCO0lBRXRFLFFBQVEsZ0JBQWdCLEVBQUU7UUFDeEIsS0FBSyxhQUFhLENBQUMsWUFBWTtZQUM3QixPQUFPLGNBQWMsQ0FBQyxlQUFlLENBQUMsWUFBWSxDQUFDO1FBQ3JELEtBQUssYUFBYSxDQUFDLFVBQVU7WUFDM0IsT0FBTyxjQUFjLENBQUMsZUFBZSxDQUFDLFVBQVUsQ0FBQztRQUNuRCxLQUFLLGFBQWEsQ0FBQywrQkFBK0I7WUFDaEQsT0FBTyxjQUFjLENBQUMsZUFBZSxDQUFDLCtCQUErQixDQUFDO1FBQ3hFO1lBQ0UsTUFBTSxJQUFJLGlCQUFpQixDQUFDLHVCQUF1QixDQUFDLENBQUM7S0FDeEQ7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IDIwMjAgR29vZ2xlIExMQ1xuICogU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcbiAqL1xuXG5pbXBvcnQge1NlY3VyaXR5RXhjZXB0aW9ufSBmcm9tICcuLi9leGNlcHRpb24vc2VjdXJpdHlfZXhjZXB0aW9uJztcbmltcG9ydCAqIGFzIEJ5dGVzIGZyb20gJy4uL3N1YnRsZS9ieXRlcyc7XG5pbXBvcnQgKiBhcyBFbGxpcHRpY0N1cnZlcyBmcm9tICcuLi9zdWJ0bGUvZWxsaXB0aWNfY3VydmVzJztcblxuaW1wb3J0IHtQYkVsbGlwdGljQ3VydmVUeXBlLCBQYkhhc2hUeXBlLCBQYktleXNldCwgUGJLZXlzZXRLZXksIFBiS2V5U3RhdHVzVHlwZSwgUGJPdXRwdXRQcmVmaXhUeXBlLCBQYlBvaW50Rm9ybWF0fSBmcm9tICcuL3Byb3RvJztcblxuLyoqXG4gKiBBIHR5cGUgcmVwcmVzZW50aW5nIHRoZSBjb25zdHJ1Y3RvciBmdW5jdGlvbiBmb3IgYSBnaXZlbiBjbGFzcy4gVW5saWtlXG4gKiBUeXBlU2NyaXB0J3MgYnVpbHQtaW4gYG5ld2AgdHlwZXMsIHRoaXMgd29ya3Mgd2l0aCBhYnN0cmFjdCBjbGFzc2VzLiBJdCBpc1xuICogdXNlZCB0byBkZXNjcmliZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gYSBwcmltaXRpdmUgdHlwZSBvYmplY3QgYW5kIGl0c1xuICogaW5zdGFuY2VzLlxuICovXG5leHBvcnQgdHlwZSBDb25zdHJ1Y3RvcjxUPiA9IEZ1bmN0aW9uJntwcm90b3R5cGU6IFR9O1xuXG4vKiogTGlrZSB0aGUgYGluc3RhbmNlb2ZgIG9wZXJhdG9yLCBidXQgd29ya3Mgd2l0aCBgQ29uc3RydWN0b3JgLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzSW5zdGFuY2VPZjxUPihcbiAgICB2YWx1ZTogdW5rbm93biwgY3RvcjogQ29uc3RydWN0b3I8VD4pOiB2YWx1ZSBpcyBUIHtcbiAgcmV0dXJuIHZhbHVlIGluc3RhbmNlb2YgY3Rvcjtcbn1cblxuLyoqXG4gKiBWYWxpZGF0ZXMgdGhlIGdpdmVuIGtleSBhbmQgdGhyb3dzIFNlY3VyaXR5RXhjZXB0aW9uIGlmIGl0IGlzIGludmFsaWQuXG4gKlxuICovXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVLZXkoa2V5OiBQYktleXNldEtleSkge1xuICBpZiAoIWtleSkge1xuICAgIHRocm93IG5ldyBTZWN1cml0eUV4Y2VwdGlvbignS2V5IHNob3VsZCBiZSBub24gbnVsbC4nKTtcbiAgfVxuICBpZiAoIWtleS5nZXRLZXlEYXRhKCkpIHtcbiAgICB0aHJvdyBuZXcgU2VjdXJpdHlFeGNlcHRpb24oXG4gICAgICAgICdLZXkgZGF0YSBhcmUgbWlzc2luZyBmb3Iga2V5ICcgKyBrZXkuZ2V0S2V5SWQoKSArICcuJyk7XG4gIH1cbiAgaWYgKGtleS5nZXRPdXRwdXRQcmVmaXhUeXBlKCkgPT09IFBiT3V0cHV0UHJlZml4VHlwZS5VTktOT1dOX1BSRUZJWCkge1xuICAgIHRocm93IG5ldyBTZWN1cml0eUV4Y2VwdGlvbihcbiAgICAgICAgJ0tleSAnICsga2V5LmdldEtleUlkKCkgKyAnIGhhcyB1bmtub3duIG91dHB1dCBwcmVmaXggdHlwZS4nKTtcbiAgfVxuICBpZiAoa2V5LmdldFN0YXR1cygpID09PSBQYktleVN0YXR1c1R5cGUuVU5LTk9XTl9TVEFUVVMpIHtcbiAgICB0aHJvdyBuZXcgU2VjdXJpdHlFeGNlcHRpb24oXG4gICAgICAgICdLZXkgJyArIGtleS5nZXRLZXlJZCgpICsgJyBoYXMgdW5rbm93biBzdGF0dXMuJyk7XG4gIH1cbn1cblxuLyoqXG4gKiBWYWxpZGF0ZXMgdGhlIGdpdmVuIGtleXNldCBhbmQgdGhyb3dzIFNlY3VyaXR5RXhjZXB0aW9uIGlmIGl0IGlzIGludmFsaWQuXG4gKlxuICovXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVLZXlzZXQoa2V5c2V0OiBQYktleXNldCkge1xuICBpZiAoIWtleXNldCB8fCAha2V5c2V0LmdldEtleUxpc3QoKSB8fCBrZXlzZXQuZ2V0S2V5TGlzdCgpLmxlbmd0aCA8IDEpIHtcbiAgICB0aHJvdyBuZXcgU2VjdXJpdHlFeGNlcHRpb24oXG4gICAgICAgICdLZXlzZXQgc2hvdWxkIGJlIG5vbiBudWxsIGFuZCBtdXN0IGNvbnRhaW4gYXQgbGVhc3Qgb25lIGtleS4nKTtcbiAgfVxuICBsZXQgaGFzUHJpbWFyeSA9IGZhbHNlO1xuICBjb25zdCBudW1iZXJPZktleXMgPSBrZXlzZXQuZ2V0S2V5TGlzdCgpLmxlbmd0aDtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBudW1iZXJPZktleXM7IGkrKykge1xuICAgIGNvbnN0IGtleSA9IGtleXNldC5nZXRLZXlMaXN0KClbaV07XG4gICAgdmFsaWRhdGVLZXkoa2V5KTtcbiAgICBpZiAoa2V5c2V0LmdldFByaW1hcnlLZXlJZCgpID09PSBrZXkuZ2V0S2V5SWQoKSAmJlxuICAgICAgICBrZXkuZ2V0U3RhdHVzKCkgPT09IFBiS2V5U3RhdHVzVHlwZS5FTkFCTEVEKSB7XG4gICAgICBpZiAoaGFzUHJpbWFyeSkge1xuICAgICAgICB0aHJvdyBuZXcgU2VjdXJpdHlFeGNlcHRpb24oJ1ByaW1hcnkga2V5IGhhcyB0byBiZSB1bmlxdWUuJyk7XG4gICAgICB9XG4gICAgICBoYXNQcmltYXJ5ID0gdHJ1ZTtcbiAgICB9XG4gIH1cbiAgaWYgKCFoYXNQcmltYXJ5KSB7XG4gICAgdGhyb3cgbmV3IFNlY3VyaXR5RXhjZXB0aW9uKFxuICAgICAgICAnUHJpbWFyeSBrZXkgaGFzIHRvIGJlIGluIHRoZSBrZXlzZXQgYW5kICcgK1xuICAgICAgICAnaGFzIHRvIGJlIGVuYWJsZWQuJyk7XG4gIH1cbn1cblxuLy8gRnVuY3Rpb25zIHdoaWNoIGFyZSB1c2VmdWwgZm9yIGltcGxlbWVudGF0aW9uIG9mXG4vLyBwcml2YXRlIGFuZCBwdWJsaWMgRUMga2V5cy5cblxuLyoqXG4gKiBFaXRoZXIgcHJvbG9uZyBvciBzaHJpbmtzIHRoZSBhcnJheSByZXByZXNlbnRpbmcgbnVtYmVyIGluIEJpZ0VuZGlhbiBlbmNvZGluZ1xuICogdG8gaGF2ZSB0aGUgc3BlY2lmaWVkIHNpemUuIEFzIHdlYmNyeXB0byBBUEkgYXNzdW1lcyB0aGF0IHgsIHkgYW5kIGQgdmFsdWVzXG4gKiBoYXMgZXhhY3RseSB0aGUgc3VwcG9zZWQgbnVtYmVyIG9mIGJ5dGVzLCB3aGVyZWFzIGNvcnJlc3BvbmRpbmcgeCwgeSBhbmRcbiAqIGtleVZhbHVlIHZhbHVlcyBpbiBwcm90byBtaWdodCBlaXRoZXIgaGF2ZSBzb21lIGxlYWRpbmcgemVyb3Mgb3IgdGhlIGxlYWRpbmdcbiAqIHplcm9zIG1pZ2h0IGJlIG1pc3NpbmcuXG4gKlxuICovXG5leHBvcnQgZnVuY3Rpb24gYmlnRW5kaWFuTnVtYmVyVG9Db3JyZWN0TGVuZ3RoKFxuICAgIGJpZ0VuZGlhbk51bWJlcjogVWludDhBcnJheSwgc2l6ZUluQnl0ZXM6IG51bWJlcik6IFVpbnQ4QXJyYXkge1xuICBjb25zdCBudW1iZXJMZW4gPSBiaWdFbmRpYW5OdW1iZXIubGVuZ3RoO1xuICBpZiAobnVtYmVyTGVuIDwgc2l6ZUluQnl0ZXMpIHtcbiAgICBjb25zdCB6ZXJvcyA9IG5ldyBVaW50OEFycmF5KHNpemVJbkJ5dGVzIC0gbnVtYmVyTGVuKTtcbiAgICByZXR1cm4gQnl0ZXMuY29uY2F0KHplcm9zLCBiaWdFbmRpYW5OdW1iZXIpO1xuICB9XG4gIGlmIChudW1iZXJMZW4gPiBzaXplSW5CeXRlcykge1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgbnVtYmVyTGVuIC0gc2l6ZUluQnl0ZXM7IGkrKykge1xuICAgICAgaWYgKGJpZ0VuZGlhbk51bWJlcltpXSAhPSAwKSB7XG4gICAgICAgIHRocm93IG5ldyBTZWN1cml0eUV4Y2VwdGlvbihcbiAgICAgICAgICAgICdOdW1iZXIgbmVlZHMgbW9yZSBieXRlcyB0byBiZSByZXByZXNlbnRlZC4nKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGJpZ0VuZGlhbk51bWJlci5zbGljZShudW1iZXJMZW4gLSBzaXplSW5CeXRlcywgbnVtYmVyTGVuKTtcbiAgfVxuICByZXR1cm4gYmlnRW5kaWFuTnVtYmVyO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY3VydmVUeXBlUHJvdG9Ub1N1YnRsZShjdXJ2ZVR5cGVQcm90bzogUGJFbGxpcHRpY0N1cnZlVHlwZSk6XG4gICAgRWxsaXB0aWNDdXJ2ZXMuQ3VydmVUeXBlIHtcbiAgc3dpdGNoIChjdXJ2ZVR5cGVQcm90bykge1xuICAgIGNhc2UgUGJFbGxpcHRpY0N1cnZlVHlwZS5OSVNUX1AyNTY6XG4gICAgICByZXR1cm4gRWxsaXB0aWNDdXJ2ZXMuQ3VydmVUeXBlLlAyNTY7XG4gICAgY2FzZSBQYkVsbGlwdGljQ3VydmVUeXBlLk5JU1RfUDM4NDpcbiAgICAgIHJldHVybiBFbGxpcHRpY0N1cnZlcy5DdXJ2ZVR5cGUuUDM4NDtcbiAgICBjYXNlIFBiRWxsaXB0aWNDdXJ2ZVR5cGUuTklTVF9QNTIxOlxuICAgICAgcmV0dXJuIEVsbGlwdGljQ3VydmVzLkN1cnZlVHlwZS5QNTIxO1xuICAgIGRlZmF1bHQ6XG4gICAgICB0aHJvdyBuZXcgU2VjdXJpdHlFeGNlcHRpb24oJ1Vua25vd24gY3VydmUgdHlwZS4nKTtcbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gaGFzaFR5cGVQcm90b1RvU3RyaW5nKGhhc2hUeXBlUHJvdG86IFBiSGFzaFR5cGUpOiBzdHJpbmcge1xuICBzd2l0Y2ggKGhhc2hUeXBlUHJvdG8pIHtcbiAgICBjYXNlIFBiSGFzaFR5cGUuU0hBMTpcbiAgICAgIHJldHVybiAnU0hBLTEnO1xuICAgIGNhc2UgUGJIYXNoVHlwZS5TSEEyNTY6XG4gICAgICByZXR1cm4gJ1NIQS0yNTYnO1xuICAgIGNhc2UgUGJIYXNoVHlwZS5TSEE1MTI6XG4gICAgICByZXR1cm4gJ1NIQS01MTInO1xuICAgIGRlZmF1bHQ6XG4gICAgICB0aHJvdyBuZXcgU2VjdXJpdHlFeGNlcHRpb24oJ1Vua25vd24gaGFzaCB0eXBlLicpO1xuICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBwb2ludEZvcm1hdFByb3RvVG9TdWJ0bGUocG9pbnRGb3JtYXRQcm90bzogUGJQb2ludEZvcm1hdCk6XG4gICAgRWxsaXB0aWNDdXJ2ZXMuUG9pbnRGb3JtYXRUeXBlIHtcbiAgc3dpdGNoIChwb2ludEZvcm1hdFByb3RvKSB7XG4gICAgY2FzZSBQYlBvaW50Rm9ybWF0LlVOQ09NUFJFU1NFRDpcbiAgICAgIHJldHVybiBFbGxpcHRpY0N1cnZlcy5Qb2ludEZvcm1hdFR5cGUuVU5DT01QUkVTU0VEO1xuICAgIGNhc2UgUGJQb2ludEZvcm1hdC5DT01QUkVTU0VEOlxuICAgICAgcmV0dXJuIEVsbGlwdGljQ3VydmVzLlBvaW50Rm9ybWF0VHlwZS5DT01QUkVTU0VEO1xuICAgIGNhc2UgUGJQb2ludEZvcm1hdC5ET19OT1RfVVNFX0NSVU5DSFlfVU5DT01QUkVTU0VEOlxuICAgICAgcmV0dXJuIEVsbGlwdGljQ3VydmVzLlBvaW50Rm9ybWF0VHlwZS5ET19OT1RfVVNFX0NSVU5DSFlfVU5DT01QUkVTU0VEO1xuICAgIGRlZmF1bHQ6XG4gICAgICB0aHJvdyBuZXcgU2VjdXJpdHlFeGNlcHRpb24oJ1Vua25vd24gcG9pbnQgZm9ybWF0LicpO1xuICB9XG59XG4iXX0=