UNPKG

@microsoft/useragent-sdk

Version:

SDK for building decentralized identity wallets and enterprise agents.

160 lines (146 loc) 6.15 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import CryptoFactory from '../plugin/CryptoFactory'; import PublicKey from '../keys/PublicKey'; import EcPublicKey from '../keys/ec/EcPublicKey'; import { CryptoAlgorithm } from '../keyStore/IKeyStore'; import { SubtleCrypto } from 'webcrypto-core'; import W3cCryptoApiConstants from './W3cCryptoApiConstants'; import JoseConstants from '../protocols/jose/JoseConstants'; /** * Crypto helpers support for plugable crypto layer */ export default class CryptoHelpers { /** * The API which implements the requested algorithm * @param cryptoFactory Crypto suite * @param algorithmName Requested algorithm * @param hash Optional hash for the algorithm */ public static getSubtleCryptoForAlgorithm(cryptoFactory: CryptoFactory, algorithm: any): SubtleCrypto { const jwa = CryptoHelpers.webCryptoToJwa(algorithm) switch (algorithm.name.toUpperCase()) { case 'RSASSA-PKCS1-V1_5': case 'ECDSA': case 'EDDSA': case 'ED25519': return cryptoFactory.getMessageSigner(jwa); case 'RSA-OAEP': case 'RSA-OAEP-256': return cryptoFactory.getKeyEncrypter(jwa); case 'AES-GCM': return cryptoFactory.getSymmetricEncrypter(jwa); case 'HMAC': return cryptoFactory.getMessageAuthenticationCodeSigners(jwa); case 'SHA-256': case 'SHA-384': case 'SHA-512': return cryptoFactory.getMessageDigest(jwa); } throw new Error(`Algorithm '${JSON.stringify(algorithm)}' is not supported`); } /** * Map the JWA algorithm to the W3C crypto API algorithm. * The method restricts the supported algorithms. This can easily be extended. * Based on https://www.w3.org/TR/WebCryptoAPI/ A. Mapping between JSON Web Key / JSON Web Algorithm * @param jwaAlgorithmName Requested algorithm */ public static jwaToWebCrypto(jwa: string, ...args: any): any { const regex = new RegExp('\\d+'); let matches:RegExpExecArray; switch (jwa.toUpperCase()) { case JoseConstants.Rs256: case JoseConstants.Rs384: case JoseConstants.Rs512: matches = <RegExpExecArray>regex.exec(jwa); return { name: W3cCryptoApiConstants.RsaSsaPkcs1V15, hash: { name: `SHA-${CryptoHelpers.getRegexMatch(<RegExpExecArray>matches, 0)}`} }; case JoseConstants.RsaOaep: case JoseConstants.RsaOaep256: return { name: 'RSA-OAEP', hash: 'SHA-256' }; case JoseConstants.AesGcm128: case JoseConstants.AesGcm192: case JoseConstants.AesGcm256: const iv = args[0]; const aad = args[1]; matches = <RegExpExecArray>regex.exec(jwa); const length = parseInt(CryptoHelpers.getRegexMatch(<RegExpExecArray>matches, 0)); return { name: W3cCryptoApiConstants.AesGcm, iv: iv, additionalData: aad, tagLength: 128, length: length }; case JoseConstants.Es256K: return { name: 'ECDSA', namedCurve: 'P-256K', hash: { name: 'SHA-256' }, format: 'DER' }; case JoseConstants.EdDSA: case 'ED25519': return { name: 'EDDSA', namedCurve: 'ed25519', hash: { name: 'SHA-256' } }; } throw new Error(`Algorithm ${JSON.stringify(jwa)} is not supported`); } /** * Maps the subtle crypto algorithm name to the JWA name * @param algorithmName Requested algorithm * @param hash Optional hash for the algorithm */ public static webCryptoToJwa(algorithm: any): string { const hash = algorithm.hash || 'SHA-256'; switch (algorithm.name.toUpperCase()) { case 'RSASSA-PKCS1-V1_5': return `RS${CryptoHelpers.getHash(hash)}`; case 'ECDSA': return `ES256K`; case 'EDDSA': case 'ED25519': return `EdDSA`; case 'RSA-OAEP-256': return 'RSA-OAEP-256'; case 'RSA-OAEP': return `RSA-OAEP-${CryptoHelpers.getHash(hash)}`; case 'AES-GCM': const length = algorithm.length || 128; return `A${length}GCMKW`; case 'HMAC': return `HS${CryptoHelpers.getHash(hash)}`; case 'SHA-256': case 'SHA-384': case 'SHA-512': return `SHA${CryptoHelpers.getHash(hash)}`; } throw new Error(`Algorithm '${JSON.stringify(algorithm)}' is not supported`); } /** * Derive the key import algorithm * @param algorithm used for signature */ public static getKeyImportAlgorithm(algorithm: CryptoAlgorithm, jwk: PublicKey | JsonWebKey): string | RsaHashedImportParams | EcKeyImportParams | HmacImportParams | DhImportKeyParams { const hash = (<any>algorithm).hash || 'SHA-256'; const name = algorithm.name; switch (algorithm.name.toUpperCase()) { case 'RSASSA-PKCS1-V1_5': return <RsaHashedImportParams>{ name, hash: {name: "SHA-256"} }; case 'HMAC': case 'SHA-256': case 'SHA-384': case 'SHA-512': return <RsaHashedImportParams>{ name, hash }; case 'ECDSA': case 'EDDSA': case 'ECDH': case 'ED25519': return <EcKeyImportParams>{ name, namedCurve: (<EcPublicKey>jwk).crv }; case 'RSA-OAEP': case 'RSA-OAEP-256': return {name, hash: 'SHA-256'} case 'AES-GCM': return <RsaHashedImportParams>{ name }; } throw new Error(`Algorithm '${JSON.stringify(algorithm)}' is not supported`); } private static getHash(hash: any) { if (hash.name) { return (hash.name).toUpperCase().replace('SHA-', ''); } return (hash || 'SHA-256').toUpperCase().replace('SHA-', ''); } private static getRegexMatch(matches: RegExpExecArray, index: number): string { return matches[index]; } }