@logsn/arweave
Version:
Arweave JS client library
184 lines • 6.63 kB
JavaScript
;
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