Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

alpha #2154

Closed
wants to merge 3 commits into from
Closed

alpha #2154

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified packages/react-core/typedoc/documentation.json.gz
Binary file not shown.
Binary file modified packages/react-native/typedoc/documentation.json.gz
Binary file not shown.
Binary file modified packages/react/typedoc/documentation.json.gz
Binary file not shown.
Binary file modified packages/sdk/typedoc/documentation.json.gz
Binary file not shown.
Binary file modified packages/storage/typedoc/documentation.json.gz
Binary file not shown.
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
Loading