feat: nip44

This commit is contained in:
2023-06-14 15:03:07 +01:00
parent ecd957792d
commit c2a3a706de
10 changed files with 262 additions and 57 deletions

View File

@ -0,0 +1,52 @@
import { MessageEncryptor } from "index";
import { base64 } from "@scure/base";
import { secp256k1 } from "@noble/curves/secp256k1";
export class Nip4WebCryptoEncryptor implements MessageEncryptor {
getSharedSecret(privateKey: string, publicKey: string) {
const sharedPoint = secp256k1.getSharedSecret(privateKey, "02" + publicKey);
const sharedX = sharedPoint.slice(1, 33);
return sharedX;
}
async encryptData(content: string, sharedSecet: Uint8Array) {
const key = await this.#importKey(sharedSecet);
const iv = window.crypto.getRandomValues(new Uint8Array(16));
const data = new TextEncoder().encode(content);
const result = await window.crypto.subtle.encrypt(
{
name: "AES-CBC",
iv: iv,
},
key,
data
);
const uData = new Uint8Array(result);
return `${base64.encode(uData)}?iv=${base64.encode(iv)}`;
}
/**
* Decrypt the content of the message
*/
async decryptData(cyphertext: string, sharedSecet: Uint8Array) {
const key = await this.#importKey(sharedSecet);
const cSplit = cyphertext.split("?iv=");
const data = base64.decode(cSplit[0]);
const iv = base64.decode(cSplit[1]);
const result = await window.crypto.subtle.decrypt(
{
name: "AES-CBC",
iv: iv,
},
key,
data
);
return new TextDecoder().decode(result);
}
async #importKey(sharedSecet: Uint8Array) {
return await window.crypto.subtle.importKey("raw", sharedSecet, { name: "AES-CBC" }, false, ["encrypt", "decrypt"]);
}
}

View File

@ -0,0 +1,40 @@
import { MessageEncryptor } from "index";
import { base64 } from "@scure/base";
import { randomBytes } from '@noble/hashes/utils'
import { streamXOR as xchacha20 } from '@stablelib/xchacha20'
import { secp256k1 } from "@noble/curves/secp256k1";
import { sha256 } from '@noble/hashes/sha256'
export enum Nip44Version {
Reserved = 0x00,
XChaCha20 = 0x01
}
export class Nip44Encryptor implements MessageEncryptor {
getSharedSecret(privateKey: string, publicKey: string) {
const key = secp256k1.getSharedSecret(privateKey, '02' + publicKey)
return sha256(key.slice(1, 33));
}
encryptData(content: string, sharedSecret: Uint8Array) {
const nonce = randomBytes(24)
const plaintext = new TextEncoder().encode(content)
const ciphertext = xchacha20(sharedSecret, nonce, plaintext, plaintext);
const ctb64 = base64.encode(Uint8Array.from(ciphertext))
const nonceb64 = base64.encode(nonce)
return JSON.stringify({ ciphertext: ctb64, nonce: nonceb64, v: Nip44Version.XChaCha20 })
}
decryptData(cyphertext: string, sharedSecret: Uint8Array) {
const dt = JSON.parse(cyphertext)
if (dt.v !== 1) throw new Error('NIP44: unknown encryption version')
const ciphertext = base64.decode(dt.ciphertext)
const nonce = base64.decode(dt.nonce)
const plaintext = xchacha20(sharedSecret, nonce, ciphertext, ciphertext)
const text = new TextDecoder().decode(plaintext)
return text;
}
}