@meteorwallet/utils
Advanced tools
Comparing version 0.29.0 to 0.30.0
@@ -1,34 +0,12 @@ | ||
interface EncryptionResult { | ||
interface IEncryptionResult { | ||
payload: string; | ||
salt: string; | ||
} | ||
/** | ||
* Encrypts a data object that can be any serializable value using | ||
* a provided password. | ||
* | ||
* @param {string} cipherKey - password to use for encryption | ||
* @param dataObj - data to encrypt | ||
* @returns {Promise<string>} cypher text | ||
*/ | ||
declare function encrypt<R>(cipherKey: string, dataObj: R): Promise<EncryptionResult>; | ||
/** | ||
* Given a password and a cypher text, decrypts the text and returns | ||
* the resulting value | ||
* @param {string} cipherKey - password to decrypt with | ||
* @param {string} salt | ||
* @param {string} payload | ||
*/ | ||
declare function decrypt<R>(cipherKey: string, salt: string, payload: string): Promise<R>; | ||
/** | ||
* Generates a random string for use as a salt in CryptoKey generation | ||
* @param {number} byteCount - Number of bytes to generate | ||
* @returns {string} randomly generated string | ||
*/ | ||
declare function generateSalt(byteCount?: number): string; | ||
export declare const encrypt_decrypt_utils: { | ||
encrypt: typeof encrypt; | ||
decrypt: typeof decrypt; | ||
generateSalt: typeof generateSalt; | ||
}; | ||
interface IEncryptionUtils { | ||
encrypt: <R>(cipherKey: string, dataObj: R) => Promise<IEncryptionResult>; | ||
decrypt: <R>(cipherKey: string, salt: string, payload: string) => Promise<R>; | ||
generateSalt: (byteCount?: number) => string; | ||
} | ||
export declare const encrypt_decrypt_utils: IEncryptionUtils; | ||
export {}; | ||
//# sourceMappingURL=encrypt_decrypt.utils.d.ts.map |
@@ -0,1 +1,5 @@ | ||
import { gcm } from "@noble/ciphers/aes"; | ||
import { utf8ToBytes } from "@noble/ciphers/utils"; | ||
import { pbkdf2 } from "@noble/hashes/pbkdf2"; | ||
import { sha256 } from "@noble/hashes/sha2"; | ||
/** | ||
@@ -5,69 +9,27 @@ * Encrypts a data object that can be any serializable value using | ||
* | ||
* @param {string} cipherKey - password to use for encryption | ||
* @param {string} password - password to use for encryption | ||
* @param dataObj - data to encrypt | ||
* @returns {Promise<string>} cypher text | ||
* @returns {Promise<IEncryptionResult>} encrypted result with salt | ||
*/ | ||
async function encrypt(cipherKey, dataObj) { | ||
const salt = generateSalt(); | ||
const passwordDerivedKey = await keyFromPassword(cipherKey, salt); | ||
const encryptionResult = await encryptWithKey(passwordDerivedKey, dataObj); | ||
const { iv, data } = encryptionResult; | ||
async function encrypt(password, dataObj) { | ||
const salt = crypto.getRandomValues(new Uint8Array(24)); | ||
const aes = gcm(keyFromPasswordAndSalt(password, Buffer.from(salt).toString("base64")), salt); | ||
const payload = aes.encrypt(utf8ToBytes(JSON.stringify(dataObj))); | ||
return { | ||
salt, | ||
payload: JSON.stringify({ | ||
iv, | ||
data, | ||
}), | ||
payload: Buffer.from(payload).toString("base64"), | ||
salt: Buffer.from(salt).toString("base64"), | ||
}; | ||
} | ||
/** | ||
* Encrypts the provided serializable javascript object using the | ||
* provided CryptoKey and returns an object containing the cypher text and | ||
* the initialization vector used. | ||
* @param {CryptoKey} key - CryptoKey to encrypt with | ||
* @param dataObj - Serializable javascript object to encrypt | ||
* @returns {EncryptWithKeyResult} | ||
*/ | ||
async function encryptWithKey(key, dataObj) { | ||
const data = JSON.stringify(dataObj); | ||
const dataBuffer = Buffer.from(data, "utf-8"); | ||
const vector = crypto.getRandomValues(new Uint8Array(16)); | ||
const buf = await crypto.subtle.encrypt({ | ||
name: "AES-GCM", | ||
iv: vector, | ||
}, key, dataBuffer); | ||
const buffer = new Uint8Array(buf); | ||
const vectorStr = Buffer.from(vector).toString("base64"); | ||
const vaultStr = Buffer.from(buffer).toString("base64"); | ||
return { | ||
data: vaultStr, | ||
iv: vectorStr, | ||
}; | ||
} | ||
/** | ||
* Given a password and a cypher text, decrypts the text and returns | ||
* the resulting value | ||
* @param {string} cipherKey - password to decrypt with | ||
* @param {string} salt | ||
* @param {string} password - password to decrypt with | ||
* @param {string} salt in base64 | ||
* @param {string} payload | ||
*/ | ||
async function decrypt(cipherKey, salt, payload) { | ||
const { iv, data } = JSON.parse(payload); | ||
const key = await keyFromPassword(cipherKey, salt); | ||
return await decryptWithKey(key, { data, iv }); | ||
} | ||
/** | ||
* Given a CryptoKey and an EncryptionResult object containing the initialization | ||
* vector (iv) and data to decrypt, return the resulting decrypted value. | ||
* @param {CryptoKey} key - CryptoKey to decrypt with | ||
* @param {EncryptWithKeyResult} payload - payload returned from an encryption method | ||
*/ | ||
async function decryptWithKey(key, payload) { | ||
const encryptedData = Buffer.from(payload.data, "base64"); | ||
const vector = Buffer.from(payload.iv, "base64"); | ||
async function decrypt(password, salt, payload) { | ||
const aes = gcm(keyFromPasswordAndSalt(password, salt), Buffer.from(salt, "base64")); | ||
try { | ||
const result = await crypto.subtle.decrypt({ name: "AES-GCM", iv: vector }, key, encryptedData); | ||
const decryptedData = new Uint8Array(result); | ||
const decryptedStr = Buffer.from(decryptedData).toString("utf-8"); | ||
return JSON.parse(decryptedStr); | ||
const decrypted = aes.decrypt(Buffer.from(payload, "base64")); | ||
return JSON.parse(Buffer.from(decrypted).toString("utf-8")); | ||
} | ||
@@ -78,62 +40,6 @@ catch (_error) { | ||
} | ||
/** | ||
* Generate a CryptoKey from a password and random salt | ||
* @param {string} password - The password to use to generate key | ||
* @param {string} salt - The salt string to use in key derivation | ||
*/ | ||
async function keyFromPassword(password, salt) { | ||
const passBuffer = Buffer.from(password, "utf-8"); | ||
const saltBuffer = Buffer.from(salt, "base64"); | ||
const key = await crypto.subtle.importKey("raw", passBuffer, { name: "PBKDF2" }, false, [ | ||
"deriveBits", | ||
"deriveKey", | ||
]); | ||
return await crypto.subtle.deriveKey({ | ||
name: "PBKDF2", | ||
salt: saltBuffer, | ||
iterations: 10000, | ||
hash: "SHA-256", | ||
}, key, { name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"]); | ||
function keyFromPasswordAndSalt(password, salt) { | ||
return pbkdf2(sha256, password, salt, { c: 32, dkLen: 32 }); | ||
} | ||
/** | ||
* Converts a hex string into a buffer. | ||
* @param {string} str - hex encoded string | ||
* @returns {Uint8Array} | ||
*/ | ||
function serializeBufferFromStorage(str) { | ||
const stripStr = str.slice(0, 2) === "0x" ? str.slice(2) : str; | ||
const buf = new Uint8Array(stripStr.length / 2); | ||
for (let i = 0; i < stripStr.length; i += 2) { | ||
const seg = stripStr.substr(i, 2); | ||
buf[i / 2] = Number.parseInt(seg, 16); | ||
} | ||
return buf; | ||
} | ||
/** | ||
* Converts a buffer into a hex string ready for storage | ||
* @param {Uint8Array} buffer - Buffer to serialize | ||
* @returns {string} hex encoded string | ||
*/ | ||
function serializeBufferForStorage(buffer) { | ||
let result = "0x"; | ||
const len = buffer.length || buffer.byteLength; | ||
for (let i = 0; i < len; i++) { | ||
result += unprefixedHex(buffer[i]); | ||
} | ||
return result; | ||
} | ||
/** | ||
* Converts a number into hex value, and ensures proper leading 0 | ||
* for single characters strings. | ||
* @param {number} num - number to convert to string | ||
* @returns {string} hex string | ||
*/ | ||
function unprefixedHex(num) { | ||
let hex = num.toString(16); | ||
while (hex.length < 2) { | ||
hex = `0${hex}`; | ||
} | ||
return hex; | ||
} | ||
/** | ||
* Generates a random string for use as a salt in CryptoKey generation | ||
@@ -140,0 +46,0 @@ * @param {number} byteCount - Number of bytes to generate |
import { convertToNamingStyle } from "./string_utils/convertToNamingStyle"; | ||
import { getTextLogicalParts } from "./string_utils/getTextLogicalParts"; | ||
import { inspectTextNaming } from "./string_utils/inspectTextNaming"; | ||
@@ -12,4 +13,5 @@ export declare const notNullEmpty: (str: string | null | undefined) => str is string; | ||
inspectTextNaming: typeof inspectTextNaming; | ||
getTextLogicalParts: typeof getTextLogicalParts; | ||
}; | ||
export {}; | ||
//# sourceMappingURL=string.utils.d.ts.map |
import { convertToNamingStyle } from "./string_utils/convertToNamingStyle"; | ||
import { getTextLogicalParts } from "./string_utils/getTextLogicalParts"; | ||
import { inspectTextNaming } from "./string_utils/inspectTextNaming"; | ||
@@ -18,2 +19,3 @@ export const notNullEmpty = (str) => { | ||
inspectTextNaming, | ||
getTextLogicalParts, | ||
}; |
{ | ||
"name": "@meteorwallet/utils", | ||
"version": "0.29.0", | ||
"version": "0.30.0", | ||
"description": "Utility functions used in Meteor Wallet", | ||
@@ -45,3 +45,6 @@ "files": [ | ||
}, | ||
"dependencies": {}, | ||
"dependencies": { | ||
"@noble/ciphers": "1.0.0", | ||
"@noble/hashes": "1.5.0" | ||
}, | ||
"repository": { | ||
@@ -48,0 +51,0 @@ "type": "git", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
51487
2
1120
+ Added@noble/ciphers@1.0.0
+ Added@noble/hashes@1.5.0
+ Added@noble/ciphers@1.0.0(transitive)
+ Added@noble/hashes@1.5.0(transitive)