feat: NIP-24
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
import { MessageEncryptor } from "index";
|
||||
import { MessageEncryptor, MessageEncryptorPayload, MessageEncryptorVersion } from "index";
|
||||
|
||||
import { base64 } from "@scure/base";
|
||||
import { secp256k1 } from "@noble/curves/secp256k1";
|
||||
@ -22,26 +22,22 @@ export class Nip4WebCryptoEncryptor implements MessageEncryptor {
|
||||
key,
|
||||
data
|
||||
);
|
||||
const uData = new Uint8Array(result);
|
||||
return `${base64.encode(uData)}?iv=${base64.encode(iv)}`;
|
||||
return {
|
||||
ciphertext: new Uint8Array(result),
|
||||
nonce: iv,
|
||||
v: MessageEncryptorVersion.Nip4
|
||||
} as MessageEncryptorPayload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt the content of the message
|
||||
*/
|
||||
async decryptData(cyphertext: string, sharedSecet: Uint8Array) {
|
||||
|
||||
async decryptData(payload: MessageEncryptorPayload, 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,
|
||||
iv: payload.nonce,
|
||||
},
|
||||
key,
|
||||
data
|
||||
payload.ciphertext
|
||||
);
|
||||
return new TextDecoder().decode(result);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { MessageEncryptor } from "index";
|
||||
import { MessageEncryptor, MessageEncryptorPayload, MessageEncryptorVersion } from "index";
|
||||
|
||||
import { base64 } from "@scure/base";
|
||||
import { randomBytes } from "@noble/hashes/utils";
|
||||
@ -6,12 +6,7 @@ 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 {
|
||||
export class XChaCha20Encryptor implements MessageEncryptor {
|
||||
getSharedSecret(privateKey: string, publicKey: string) {
|
||||
const key = secp256k1.getSharedSecret(privateKey, "02" + publicKey);
|
||||
return sha256(key.slice(1, 33));
|
||||
@ -21,19 +16,18 @@ export class Nip44Encryptor implements MessageEncryptor {
|
||||
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 });
|
||||
return {
|
||||
ciphertext: Uint8Array.from(ciphertext),
|
||||
nonce: nonce,
|
||||
v: MessageEncryptorVersion.XChaCha20,
|
||||
} as MessageEncryptorPayload;
|
||||
}
|
||||
|
||||
decryptData(cyphertext: string, sharedSecret: Uint8Array) {
|
||||
const dt = JSON.parse(cyphertext);
|
||||
if (dt.v !== 1) throw new Error("NIP44: unknown encryption version");
|
||||
decryptData(payload: MessageEncryptorPayload, sharedSecret: Uint8Array) {
|
||||
if (payload.v !== MessageEncryptorVersion.XChaCha20) throw new Error("NIP44: wrong 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;
|
||||
const dst = xchacha20(sharedSecret, payload.nonce, payload.ciphertext, payload.ciphertext);
|
||||
const decoded = new TextDecoder().decode(dst);
|
||||
return decoded;
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import { v4 as uuid } from "uuid";
|
||||
import debug from "debug";
|
||||
|
||||
import { Connection } from "../connection";
|
||||
import { EventSigner, PrivateKeySigner } from "../event-publisher";
|
||||
import { EventSigner, PrivateKeySigner } from "../signer";
|
||||
import { NostrEvent } from "../nostr";
|
||||
import { EventBuilder } from "../event-builder";
|
||||
import EventKind from "../event-kind";
|
||||
@ -138,6 +138,14 @@ export class Nip46Signer implements EventSigner {
|
||||
return await this.#rpc<string>("nip04_decrypt", [otherKey, content]);
|
||||
}
|
||||
|
||||
nip44Encrypt(content: string, key: string): Promise<string> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
nip44Decrypt(content: string, otherKey: string): Promise<string> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
async sign(ev: NostrEvent) {
|
||||
const evStr = await this.#rpc<string>("sign_event", [JSON.stringify(ev)]);
|
||||
return JSON.parse(evStr);
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { WorkQueueItem, processWorkQueue, barrierQueue, unwrap } from "@snort/shared";
|
||||
import { EventSigner } from "../event-publisher";
|
||||
import { HexKey, NostrEvent } from "../nostr";
|
||||
import { EventSigner, HexKey, NostrEvent } from "..";
|
||||
|
||||
const Nip7Queue: Array<WorkQueueItem> = [];
|
||||
processWorkQueue(Nip7Queue);
|
||||
@ -51,6 +50,14 @@ export class Nip7Signer implements EventSigner {
|
||||
);
|
||||
}
|
||||
|
||||
async nip44Encrypt(content: string, key: string): Promise<string> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
async nip44Decrypt(content: string, otherKey: string): Promise<string> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
async sign(ev: NostrEvent): Promise<NostrEvent> {
|
||||
if (!window.nostr) {
|
||||
throw new Error("Cannot use NIP-07 signer, not found!");
|
||||
|
Reference in New Issue
Block a user