import { RSASigner } from "encryption/low-level/asymmetric/rsa/sign"; import { HalfCryptoKeyPair } from "encryption/types"; import { encodeJSONAsBinary } from "encoding/json/binary"; import { JSONValue } from "encoding/json/types"; import { b64Encode, b64Decode } from "encoding/base64"; import { KeyEncoder, ExportedKey } from "encoding/key"; import { VerificationError } from "error"; export interface SignedData { data: JSONValue; signature: string; } export interface AsymmetricDataSignerI { sign(jsonableInput: JSONValue): Promise; verify(signedObject: SignedData): Promise; } export function AsymmetricDataSigner( signingKeyPair: CryptoKeyPair | HalfCryptoKeyPair ): AsymmetricDataSignerI { const signer = RSASigner(signingKeyPair); function deepCopy(jsonableInput: JSONValue): JSONValue { return JSON.parse(JSON.stringify(jsonableInput)); } return { async sign(jsonableInput: JSONValue): Promise { const clonedInput = deepCopy(jsonableInput); const result = await signer.signBinary( encodeJSONAsBinary(clonedInput) ); return { data: clonedInput, signature: b64Encode(result) }; }, async verify(signedObject: SignedData): Promise { const { data, signature } = signedObject; const verificationSucceeded = await signer.verifyBinary( b64Decode(signature), encodeJSONAsBinary(data) ); if (!verificationSucceeded) { throw new VerificationError("Failed to verify signed data."); } return data; } }; } AsymmetricDataSigner.getDefaultAlgorithm = RSASigner.getDefaultAlgorithm; AsymmetricDataSigner.generateKeyPair = RSASigner.generateKeyPair; AsymmetricDataSigner.verifyAgainst = async function( publicKeyObj: ExportedKey, signedObject: SignedData ): Promise { const publicKey = await KeyEncoder().decode( publicKeyObj, RSASigner.getDefaultAlgorithm(), ["verify"], false ); const dataSigner = AsymmetricDataSigner({ publicKey }); return await dataSigner.verify(signedObject); };