Skip to content

Commit

Permalink
copy nip44 code from chebizarro/dart-nip44
Browse files Browse the repository at this point in the history
  • Loading branch information
frnandu committed Dec 25, 2024
1 parent 5683fda commit a5a9bb8
Show file tree
Hide file tree
Showing 6 changed files with 1,516 additions and 278 deletions.
278 changes: 0 additions & 278 deletions packages/ndk/lib/objectbox-model.json

This file was deleted.

105 changes: 105 additions & 0 deletions packages/ndk/lib/shared/nips/nip44/nip44.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:elliptic/ecdh.dart';
import 'package:elliptic/elliptic.dart';
import 'utils.dart';

/// NIP-44 encryption and decryption functions.
class Nip44 {
static Future<String> encryptMessage(
String plaintext,
String senderPrivateKey,
String recipientPublicKey, {
Uint8List? customNonce,
Uint8List? customConversationKey,
}) async {
// Step 1: Compute Shared Secret
final sharedSecret = customConversationKey ??
computeSharedSecret(senderPrivateKey, recipientPublicKey);

// Step 2: Derive Conversation Key
final conversationKey =
customConversationKey ?? deriveConversationKey(sharedSecret);

// Step 3: Generate or Use Custom Nonce
final nonce = customNonce ?? secureRandomBytes(32);

// Step 4: Derive Message Keys
final keys = deriveMessageKeys(conversationKey, nonce);
final chachaKey = keys['chachaKey']!;
final chachaNonce = keys['chachaNonce']!;
final hmacKey = keys['hmacKey']!;

// Step 5: Pad Plaintext
final paddedPlaintext = pad(utf8.encode(plaintext));

// Step 6: Encrypt
final ciphertext =
await encryptChaCha20(chachaKey, chachaNonce, paddedPlaintext);

// Step 7: Calculate MAC
final mac = calculateMac(hmacKey, nonce, ciphertext);

// Step 8: Construct Payload
return constructPayload(nonce, ciphertext, mac);
}

static Future<String> decryptMessage(
String payload,
String recipientPrivateKey,
String senderPublicKey, {
Uint8List? customConversationKey,
}) async {
// Step 1: Compute Shared Secret
final sharedSecret = customConversationKey ??
computeSharedSecret(recipientPrivateKey, senderPublicKey);

// Step 2: Derive Conversation Key
final conversationKey =
customConversationKey ?? deriveConversationKey(sharedSecret);

// Step 3: Parse Payload
final parsed = parsePayload(payload);
final nonce = parsed['nonce'];
final ciphertext = parsed['ciphertext'];
final mac = parsed['mac'];

// Step 4: Derive Message Keys
final keys = deriveMessageKeys(conversationKey, nonce);
final chachaKey = keys['chachaKey']!;
final chachaNonce = keys['chachaNonce']!;
final hmacKey = keys['hmacKey']!;

// Step 5: Verify MAC
verifyMac(hmacKey, nonce, ciphertext, mac);

// Step 6: Decrypt
final paddedPlaintext =
await decryptChaCha20(chachaKey, chachaNonce, ciphertext);

// Step 7: Unpad Plaintext
final plaintextBytes = unpad(paddedPlaintext);

return utf8.decode(plaintextBytes);
}

static Uint8List computeSharedSecret(String privateKeyHex, String publicKeyHex) {
final ec = getS256();
final privateKey = PrivateKey.fromHex(ec, privateKeyHex);
final publicKey =
PublicKey.fromHex(ec, checkPublicKey(publicKeyHex));
final sec = computeSecret(privateKey, publicKey);
return Uint8List.fromList(sec);
}

static Uint8List deriveConversationKey(Uint8List sharedSecret) {
final salt = utf8.encode('nip44-v2');

final conversationKey = hkdfExtract(
ikm: sharedSecret,
salt: Uint8List.fromList(salt),
);

return conversationKey;
}
}
Loading

0 comments on commit a5a9bb8

Please sign in to comment.