Skip to content

Commit

Permalink
Add LocalWallet
Browse files Browse the repository at this point in the history
  • Loading branch information
MananTank committed Feb 28, 2024
1 parent 81e681f commit 0fe12ec
Show file tree
Hide file tree
Showing 23 changed files with 2,078 additions and 34 deletions.
80 changes: 80 additions & 0 deletions packages/thirdweb/src/crypto/aes/decrypt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { getCachedTextDecoder, getCachedTextEncoder } from "../utils/cache";
import {
decryptCryptoJSCipherBase64,
parseCryptoJSCipherBase64,
} from "./utils/crypto-js-compat";
import { base64ToUint8Array } from "../utils/uint8array-extras";
import { universalCrypto } from "../utils/universal-crypto";

/**
* Decrypts ciphertext encrypted with aesEncrypt() using supplied password.
*
* @param ciphertext - Ciphertext to be decrypted.
* @param password - Password to use to decrypt ciphertext.
* @returns Decrypted plaintext.
*
* @example
* const plaintext = await aesDecrypt(ciphertext, 'pw');
*/
export async function aesDecrypt(
ciphertext: string,
password: string,
): Promise<string> {
const crypto = await universalCrypto();
// encode password as UTF-8
const pwUtf8 = getCachedTextEncoder().encode(password);
// hash the password
const pwHash = await crypto.subtle.digest("SHA-256", pwUtf8);

const cipherUint8Array = base64ToUint8Array(ciphertext);

// iv
const iv = cipherUint8Array.slice(0, 12);

// specify algorithm to use
const alg = { name: "AES-GCM", iv };

// generate key from pw
const key = await crypto.subtle.importKey("raw", pwHash, alg, false, [
"decrypt",
]);

// ciphertext
const ctUint8 = cipherUint8Array.slice(12);

try {
// decrypt ciphertext using key
const plainBuffer = await crypto.subtle.decrypt(alg, key, ctUint8);
// return the plaintext from ArrayBuffer
return getCachedTextDecoder().decode(plainBuffer);
} catch (e) {
throw new Error("Decrypt failed");
}
}

/**
* Decrypts ciphertext encrypted with aesEncrypt() OR "crypto-js".AES using supplied password.
*
* @param ciphertext - Ciphertext to be decrypted.
* @param password - Password to use to decrypt ciphertext.
* @returns Decrypted plaintext.
*
* @example
* const plaintext = await aesDecryptCompat(ciphertext, 'pw');
*/
export async function aesDecryptCompat(
ciphertext: string,
password: string,
): Promise<string> {
// determine if we're dealing with a legacy (cryptojs) ciphertext
const cryptoJs = parseCryptoJSCipherBase64(ciphertext);
if (cryptoJs.salt && cryptoJs.ciphertext) {
return decryptCryptoJSCipherBase64(
cryptoJs.salt,
cryptoJs.ciphertext,
password,
);
}
// otherwise assume it's a ciphertext generated by aesEncrypt()
return aesDecrypt(ciphertext, password);
}
47 changes: 47 additions & 0 deletions packages/thirdweb/src/crypto/aes/encrypt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {
concatUint8Arrays,
uint8ArrayToBase64,
} from "../utils/uint8array-extras";
import { getCachedTextEncoder } from "../utils/cache";
import { universalCrypto } from "../utils/universal-crypto";

/**
* Encrypts plaintext using AES-GCM with supplied password, for decryption with aesDecrypt().
*
* @param plaintext - Plaintext to be encrypted.
* @param password - Password to use to encrypt plaintext.
* @returns Encrypted ciphertext.
*
* @example
* const ciphertext = await aesEncrypt('my secret text', 'pw');
*/
export async function aesEncrypt(
plaintext: string,
password: string,
): Promise<string> {
const crypto = await universalCrypto();
const textEncoder = getCachedTextEncoder();
// encode password as UTF-8
const pwUtf8 = textEncoder.encode(password);
// hash the password
const pwHash = await crypto.subtle.digest("SHA-256", pwUtf8);

// get 96-bit random iv
const iv = crypto.getRandomValues(new Uint8Array(12));

// specify algorithm to use
const alg = { name: "AES-GCM", iv };

// generate key from pw
const key = await crypto.subtle.importKey("raw", pwHash, alg, false, [
"encrypt",
]);

// encode plaintext as UTF-8
const ptUint8 = textEncoder.encode(plaintext);
// encrypt plaintext using key
const ctBuffer = await crypto.subtle.encrypt(alg, key, ptUint8);

// iv+ciphertext base64-encoded
return uint8ArrayToBase64(concatUint8Arrays([iv, new Uint8Array(ctBuffer)]));
}
Loading

0 comments on commit 0fe12ec

Please sign in to comment.