@hashgraph/cryptography
Version:
Cryptographic utilities and primitives for the Hiero SDK
135 lines (122 loc) • 3.81 kB
JavaScript
import * as hex from "../encoding/hex.js";
import * as utf8 from "../encoding/utf8.js";
import SparkMD5 from "spark-md5";
import { Buffer } from "buffer";
// this will be executed in browser environment so we can use window.crypto
/* eslint-disable n/no-unsupported-features/node-builtins */
export const CipherAlgorithm = {
Aes128Ctr: "AES-128-CTR",
Aes128Cbc: "AES-128-CBC",
};
/**
* @param {string} algorithm
* @param {Uint8Array} key
* @param {Uint8Array} iv
* @param {Uint8Array} data
* @returns {Promise<Uint8Array>}
*/
export async function createCipheriv(algorithm, key, iv, data) {
let algorithm_;
switch (algorithm.toUpperCase()) {
case CipherAlgorithm.Aes128Ctr:
algorithm_ = {
name: "AES-CTR",
counter: iv,
length: 128,
};
break;
case CipherAlgorithm.Aes128Cbc:
algorithm_ = {
name: "AES-CBC",
iv: iv,
};
break;
default:
throw new Error(
"(BUG) non-exhaustive switch statement for CipherAlgorithm",
);
}
const key_ = await window.crypto.subtle.importKey(
"raw",
key,
algorithm_.name,
false,
["encrypt"],
);
return new Uint8Array(
// https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/encrypt#return_value
/** @type {ArrayBuffer} */ (
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
await window.crypto.subtle.encrypt(algorithm_, key_, data)
),
);
}
/**
* @param {string} algorithm
* @param {Uint8Array} key
* @param {Uint8Array} iv
* @param {Uint8Array} data
* @returns {Promise<Uint8Array>}
*/
export async function createDecipheriv(algorithm, key, iv, data) {
let algorithm_;
switch (algorithm.toUpperCase()) {
case CipherAlgorithm.Aes128Ctr:
algorithm_ = {
name: "AES-CTR",
counter: iv,
length: 128,
};
break;
case CipherAlgorithm.Aes128Cbc:
algorithm_ = {
name: "AES-CBC",
iv,
};
break;
default:
throw new Error(
"(BUG) non-exhaustive switch statement for CipherAlgorithm",
);
}
const key_ = await window.crypto.subtle.importKey(
"raw",
key,
algorithm_.name,
false,
["decrypt"],
);
let decrypted;
try {
decrypted = await window.crypto.subtle.decrypt(algorithm_, key_, data);
} catch (error) {
const message =
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
error != null && /** @type {Error} */ (error).message != null
? // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
/** @type {Error} */ (error).message
: "";
throw new Error(`Unable to decrypt: ${message}`);
}
return new Uint8Array(
// https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/encrypt#return_value
/** @type {ArrayBuffer} */ (
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
decrypted
),
);
}
/**
* @param {string} passphrase
* @param {string} iv
* @returns {Promise<Uint8Array>}
*/
export async function messageDigest(passphrase, iv) {
const pass = utf8.encode(passphrase);
const sliced = hex.decode(iv).slice(0, 8);
const result = SparkMD5.ArrayBuffer.hash(
// @ts-ignore
Buffer.concat([Buffer.from(pass), Buffer.from(sliced)]),
);
return Promise.resolve(hex.decode(result));
}