UNPKG

@logsn/arweave

Version:
184 lines 6.63 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); const ArweaveUtils = __importStar(require("../utils")); class WebCryptoDriver { keyLength = 4096; publicExponent = 0x10001; hashAlgorithm = "sha256"; driver; constructor() { if (!this.detectWebCrypto()) { throw new Error("SubtleCrypto not available!"); } this.driver = crypto.subtle; } async generateJWK() { let cryptoKey = await this.driver.generateKey({ name: "RSA-PSS", modulusLength: 4096, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: { name: "SHA-256", }, }, true, ["sign"]); let jwk = await this.driver.exportKey("jwk", cryptoKey.privateKey); return { kty: jwk.kty, e: jwk.e, n: jwk.n, d: jwk.d, p: jwk.p, q: jwk.q, dp: jwk.dp, dq: jwk.dq, qi: jwk.qi, }; } async sign(jwk, data, { saltLength } = {}) { let signature = await this.driver.sign({ name: "RSA-PSS", saltLength: 32, }, await this.jwkToCryptoKey(jwk), data); return new Uint8Array(signature); } async hash(data, algorithm = "SHA-256") { let digest = await this.driver.digest(algorithm, data); return new Uint8Array(digest); } async verify(publicModulus, data, signature) { const publicKey = { kty: "RSA", e: "AQAB", n: publicModulus, }; const key = await this.jwkToPublicCryptoKey(publicKey); const digest = await this.driver.digest("SHA-256", data); const salt0 = await this.driver.verify({ name: "RSA-PSS", saltLength: 0, }, key, signature, data); const salt32 = await this.driver.verify({ name: "RSA-PSS", saltLength: 32, }, key, signature, data); // saltN's salt-length is derived from a formula described here // https://developer.mozilla.org/en-US/docs/Web/API/RsaPssParams const saltN = await this.driver.verify({ name: "RSA-PSS", saltLength: Math.ceil((key.algorithm.modulusLength - 1) / 8) - digest.byteLength - 2, }, key, signature, data); return salt0 || salt32 || saltN; } async jwkToCryptoKey(jwk) { return this.driver.importKey("jwk", jwk, { name: "RSA-PSS", hash: { name: "SHA-256", }, }, false, ["sign"]); } async jwkToPublicCryptoKey(publicJwk) { return this.driver.importKey("jwk", publicJwk, { name: "RSA-PSS", hash: { name: "SHA-256", }, }, false, ["verify"]); } detectWebCrypto() { if (typeof crypto === "undefined") { return false; } const subtle = crypto?.subtle; if (subtle === undefined) { return false; } const names = [ "generateKey", "importKey", "exportKey", "digest", "sign", ]; return names.every((name) => typeof subtle[name] === "function"); } async encrypt(data, key, salt) { const initialKey = await this.driver.importKey("raw", typeof key == "string" ? ArweaveUtils.stringToBuffer(key) : key, { name: "PBKDF2", length: 32, }, false, ["deriveKey"]); // const salt = ArweaveUtils.stringToBuffer("salt"); // create a random string for deriving the key // const salt = this.driver.randomBytes(16).toString('hex'); const derivedkey = await this.driver.deriveKey({ name: "PBKDF2", salt: salt ? ArweaveUtils.stringToBuffer(salt) : ArweaveUtils.stringToBuffer("salt"), iterations: 100000, hash: "SHA-256", }, initialKey, { name: "AES-CBC", length: 256, }, false, ["encrypt", "decrypt"]); const iv = new Uint8Array(16); crypto.getRandomValues(iv); const encryptedData = await this.driver.encrypt({ name: "AES-CBC", iv: iv, }, derivedkey, data); return ArweaveUtils.concatBuffers([iv, encryptedData]); } async decrypt(encrypted, key, salt) { const initialKey = await this.driver.importKey("raw", typeof key == "string" ? ArweaveUtils.stringToBuffer(key) : key, { name: "PBKDF2", length: 32, }, false, ["deriveKey"]); // const salt = ArweaveUtils.stringToBuffer("pepper"); const derivedkey = await this.driver.deriveKey({ name: "PBKDF2", salt: salt ? ArweaveUtils.stringToBuffer(salt) : ArweaveUtils.stringToBuffer("salt"), iterations: 100000, hash: "SHA-256", }, initialKey, { name: "AES-CBC", length: 256, }, false, ["encrypt", "decrypt"]); const iv = encrypted.slice(0, 16); const data = await this.driver.decrypt({ name: "AES-CBC", iv: iv, }, derivedkey, encrypted.slice(16)); // We're just using concat to convert from an array buffer to uint8array return ArweaveUtils.concatBuffers([data]); } } exports.default = WebCryptoDriver; //# sourceMappingURL=webcrypto-driver.js.map