199 lines
3.4 KiB
TypeScript
199 lines
3.4 KiB
TypeScript
import sodium from "libsodium-wrappers"
|
|
|
|
export type KeyPair = {
|
|
publicKey: Uint8Array
|
|
privateKey: Uint8Array
|
|
}
|
|
|
|
export type EncryptedPayload = {
|
|
nonce: Uint8Array
|
|
cipher: Uint8Array
|
|
}
|
|
|
|
export type EncryptedPrivateKey = {
|
|
nonce: Uint8Array
|
|
cipher: Uint8Array
|
|
salt: Uint8Array
|
|
}
|
|
|
|
export const useCryptoStore = () => {
|
|
|
|
let ready = false
|
|
|
|
const init = async (): Promise<void> => {
|
|
if (!ready) {
|
|
await sodium.ready
|
|
ready = true
|
|
}
|
|
}
|
|
|
|
/**
|
|
* USER KEY PAIR
|
|
*/
|
|
const generateUserKeyPair = (): KeyPair => {
|
|
|
|
const pair = sodium.crypto_box_keypair()
|
|
|
|
return {
|
|
publicKey: pair.publicKey,
|
|
privateKey: pair.privateKey
|
|
}
|
|
}
|
|
|
|
/**
|
|
* MASTER KEY
|
|
*/
|
|
const generateMasterKey = (): Uint8Array => {
|
|
return sodium.randombytes_buf(
|
|
sodium.crypto_secretbox_KEYBYTES
|
|
)
|
|
}
|
|
|
|
/**
|
|
* ENCRYPT PRIVATE KEY
|
|
*/
|
|
const encryptPrivateKey = (
|
|
privateKey: Uint8Array,
|
|
masterKey: Uint8Array
|
|
): EncryptedPayload => {
|
|
|
|
const nonce = sodium.randombytes_buf(
|
|
sodium.crypto_secretbox_NONCEBYTES
|
|
)
|
|
|
|
const cipher = sodium.crypto_secretbox_easy(
|
|
privateKey,
|
|
nonce,
|
|
masterKey
|
|
)
|
|
|
|
return { nonce, cipher }
|
|
}
|
|
|
|
/**
|
|
* DECRYPT PRIVATE KEY
|
|
*/
|
|
const decryptPrivateKey = (
|
|
encrypted: EncryptedPayload,
|
|
masterKey: Uint8Array
|
|
): Uint8Array => {
|
|
|
|
return sodium.crypto_secretbox_open_easy(
|
|
encrypted.cipher,
|
|
encrypted.nonce,
|
|
masterKey
|
|
)
|
|
}
|
|
|
|
/**
|
|
* LIST KEY
|
|
*/
|
|
const generateListKey = (): Uint8Array => {
|
|
|
|
return sodium.randombytes_buf(
|
|
sodium.crypto_aead_xchacha20poly1305_ietf_KEYBYTES
|
|
)
|
|
}
|
|
|
|
/**
|
|
* ENCRYPT LIST DATA
|
|
*/
|
|
const encryptList = (
|
|
data: string,
|
|
listKey: Uint8Array
|
|
): EncryptedPayload => {
|
|
|
|
const nonce = sodium.randombytes_buf(
|
|
sodium.crypto_aead_xchacha20poly1305_ietf_NPUBBYTES
|
|
)
|
|
|
|
const cipher = sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(
|
|
sodium.from_string(data),
|
|
null,
|
|
null,
|
|
nonce,
|
|
listKey
|
|
)
|
|
|
|
return { nonce, cipher }
|
|
}
|
|
|
|
/**
|
|
* DECRYPT LIST DATA
|
|
*/
|
|
const decryptList = (
|
|
encrypted: EncryptedPayload,
|
|
listKey: Uint8Array
|
|
): string => {
|
|
|
|
const decrypted = sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(
|
|
null,
|
|
encrypted.cipher,
|
|
null,
|
|
encrypted.nonce,
|
|
listKey
|
|
)
|
|
|
|
return sodium.to_string(decrypted)
|
|
}
|
|
|
|
/**
|
|
* ENCRYPT LIST KEY FOR USER
|
|
*/
|
|
const encryptListKeyForUser = (
|
|
listKey: Uint8Array,
|
|
recipientPublicKey: Uint8Array,
|
|
senderPrivateKey: Uint8Array
|
|
): EncryptedPayload => {
|
|
|
|
const nonce = sodium.randombytes_buf(
|
|
sodium.crypto_box_NONCEBYTES
|
|
)
|
|
|
|
const cipher = sodium.crypto_box_easy(
|
|
listKey,
|
|
nonce,
|
|
recipientPublicKey,
|
|
senderPrivateKey
|
|
)
|
|
|
|
return { nonce, cipher }
|
|
}
|
|
|
|
/**
|
|
* DECRYPT LIST KEY
|
|
*/
|
|
const decryptListKey = (
|
|
encrypted: EncryptedPayload,
|
|
senderPublicKey: Uint8Array,
|
|
recipientPrivateKey: Uint8Array
|
|
): Uint8Array => {
|
|
|
|
return sodium.crypto_box_open_easy(
|
|
encrypted.cipher,
|
|
encrypted.nonce,
|
|
senderPublicKey,
|
|
recipientPrivateKey
|
|
)
|
|
}
|
|
|
|
return {
|
|
|
|
init,
|
|
|
|
generateUserKeyPair,
|
|
|
|
generateMasterKey,
|
|
|
|
encryptPrivateKey,
|
|
decryptPrivateKey,
|
|
|
|
generateListKey,
|
|
|
|
encryptList,
|
|
decryptList,
|
|
|
|
encryptListKeyForUser,
|
|
decryptListKey
|
|
}
|
|
} |