diff --git a/src/common/lib/crypto/node-driver.ts b/src/common/lib/crypto/node-driver.ts index 40f2303..8211b0c 100644 --- a/src/common/lib/crypto/node-driver.ts +++ b/src/common/lib/crypto/node-driver.ts @@ -1,7 +1,7 @@ import { JWKInterface } from "../wallet"; import CryptoInterface, { SignatureOptions } from "./crypto-interface"; import { pemTojwk, jwkTopem } from "./pem"; -import * as crypto from "crypto"; +import * as crypto from "node:crypto"; export default class NodeCryptoDriver implements CryptoInterface { public readonly keyLength = 4096; @@ -63,22 +63,42 @@ export default class NodeCryptoDriver implements CryptoInterface { signature: Uint8Array ): Promise { return new Promise((resolve, reject) => { - const publicKey = { + const publicJwk = { kty: "RSA", e: "AQAB", n: publicModulus, }; - const pem = this.jwkToPem(publicKey); + const pem = this.jwkToPem(publicJwk); //? + const keyObject = crypto.createPublicKey({ + key: pem, + format: 'pem', + }) + + const verify = crypto.createVerify(this.hashAlgorithm) + verify.update(data) + const verifyResult = verify.verify( + { + key: keyObject, + padding: crypto.constants.RSA_PKCS1_PSS_PADDING, + }, + signature, + ) - resolve( - crypto.createVerify(this.hashAlgorithm).update(data).verify( - { - key: pem, - padding: crypto.constants.RSA_PKCS1_PSS_PADDING, - }, - signature + if (!verifyResult) { + const details = { + asymmetricKeyType: keyObject.asymmetricKeyType, + modulusLength: keyObject.asymmetricKeyDetails?.modulusLength, + } + console.warn( + "Transaction Verification Failed! \n" + + `Details: ${JSON.stringify(details, null, 2)} \n` + + "N.B. ArweaveJS is only guaranteed to verify txs created using ArweaveJS." ) + } + + resolve( + verifyResult ); }); } diff --git a/src/common/lib/crypto/webcrypto-driver.ts b/src/common/lib/crypto/webcrypto-driver.ts index 07d3604..7efc015 100644 --- a/src/common/lib/crypto/webcrypto-driver.ts +++ b/src/common/lib/crypto/webcrypto-driver.ts @@ -107,22 +107,37 @@ export default class WebCryptoDriver implements CryptoInterface { // saltN's salt-length is derived from a formula described here // https://developer.mozilla.org/en-US/docs/Web/API/RsaPssParams + const saltLengthN = Math.ceil( + ((key.algorithm as RsaHashedKeyGenParams).modulusLength - 1) / 8 + ) - digest.byteLength - 2; + const saltN = await this.driver.verify( { name: "RSA-PSS", - saltLength: - Math.ceil( - ((key.algorithm as RsaHashedKeyGenParams).modulusLength - 1) / 8 - ) - - digest.byteLength - - 2, + saltLength: saltLengthN, }, key, signature, data ); - return salt0 || salt32 || saltN; + const result = salt0 || salt32 || saltN; + + if (!result) { + const details = { + algorithm: key.algorithm.name, + modulusLength: (key.algorithm as RsaHashedKeyAlgorithm).modulusLength, + keyUsages: key.usages, + saltLengthsAttempted: `0, 32, ${saltLengthN}` + } + console.warn( + "Transaction Verification Failed! \n", + `Details: ${JSON.stringify(details, null, 2)} \n`, + "N.B. ArweaveJS is only guaranteed to verify txs created using ArweaveJS.", + ) + } + + return result } private async jwkToCryptoKey(jwk: JWKInterface): Promise {