abdm_fidelius 0.1.0 copy "abdm_fidelius: ^0.1.0" to clipboard
abdm_fidelius: ^0.1.0 copied to clipboard

Dart implementation of ABDM Fidelius encryption (ECDH + HKDF + AES-256-GCM) for India's health data exchange.

example/example.dart

// ignore_for_file: avoid_print

/// Complete example of the abdm_fidelius package.
///
/// Covers:
/// 1. Basic usage — generate keys, encrypt, decrypt
/// 2. Per-curve selection — X25519 and P-256
/// 3. Healthcare context — encrypting a FHIR bundle for ABDM
/// 4. Low-level primitives — step-by-step protocol execution
/// 5. JSON serialization — payload and key pair round-trip
library;

import 'dart:convert';

import 'package:abdm_fidelius/abdm_fidelius.dart';

Future<void> main() async {
  await basicUsage();
  await perCurveSelection();
  await healthcareExample();
  await lowLevelPrimitives();
  await jsonSerialization();
}

// ---------------------------------------------------------------------------
// 1. Basic usage — Weierstrass Curve25519 (ABDM default)
// ---------------------------------------------------------------------------

Future<void> basicUsage() async {
  print('=== 1. Basic Usage (Weierstrass Curve25519) ===\n');

  const fidelius = FideliusCurve25519();

  // Both parties generate key pairs
  final sender = await fidelius.generateKeyPair();
  final receiver = await fidelius.generateKeyPair();

  print('Sender public key:   ${sender.publicKey.substring(0, 20)}...');
  print('Receiver public key: ${receiver.publicKey.substring(0, 20)}...');

  // Sender encrypts with receiver's public key and nonce
  final encrypted = await fidelius.encrypt(
    plaintext: 'Hello from abdm_fidelius!',
    senderKeyPair: sender,
    receiverPublicKey: receiver.publicKey,
    receiverNonce: receiver.nonce,
  );

  print('Encrypted data:      ${encrypted.encryptedData.substring(0, 20)}...');

  // Receiver decrypts with their own key pair
  final decrypted = await fidelius.decrypt(
    payload: encrypted,
    receiverKeyPair: receiver,
  );

  print('Decrypted:           $decrypted');
  print('');
}

// ---------------------------------------------------------------------------
// 2. Per-curve selection — X25519 and P-256
// ---------------------------------------------------------------------------

Future<void> perCurveSelection() async {
  print('=== 2. Per-Curve Selection ===\n');

  // X25519 (RFC 7748 Montgomery form)
  const x25519 = FideliusX25519();
  final xSender = await x25519.generateKeyPair();
  final xReceiver = await x25519.generateKeyPair();

  final xEncrypted = await x25519.encrypt(
    plaintext: 'Encrypted with X25519',
    senderKeyPair: xSender,
    receiverPublicKey: xReceiver.publicKey,
    receiverNonce: xReceiver.nonce,
  );

  final xDecrypted = await x25519.decrypt(
    payload: xEncrypted,
    receiverKeyPair: xReceiver,
  );

  print('X25519 result:  $xDecrypted');

  // P-256 (NIST secp256r1)
  const p256 = FideliusP256();
  final pSender = await p256.generateKeyPair();
  final pReceiver = await p256.generateKeyPair();

  final pEncrypted = await p256.encrypt(
    plaintext: 'Encrypted with P-256',
    senderKeyPair: pSender,
    receiverPublicKey: pReceiver.publicKey,
    receiverNonce: pReceiver.nonce,
  );

  final pDecrypted = await p256.decrypt(
    payload: pEncrypted,
    receiverKeyPair: pReceiver,
  );

  print('P-256 result:   $pDecrypted');
  print('');
}

// ---------------------------------------------------------------------------
// 3. Healthcare context — encrypting a FHIR bundle for ABDM
// ---------------------------------------------------------------------------

Future<void> healthcareExample() async {
  print('=== 3. Healthcare: ABDM Health Data Encryption ===\n');

  // In an ABDM flow:
  //   HIP (Health Information Provider) encrypts patient data
  //   HIU (Health Information User) decrypts after consent

  const fidelius = FideliusCurve25519();

  // HIP generates a key pair and shares publicKey + nonce with HIU
  final hipKeys = await fidelius.generateKeyPair();

  // HIU generates a key pair and shares publicKey + nonce with HIP
  final hiuKeys = await fidelius.generateKeyPair();

  // HIP encrypts a FHIR bundle
  final fhirBundle = jsonEncode({
    'resourceType': 'Bundle',
    'type': 'collection',
    'entry': [
      {
        'resource': {
          'resourceType': 'Patient',
          'name': [
            {
              'given': ['Rahul'],
              'family': 'Sharma',
            },
          ],
        },
      },
      {
        'resource': {
          'resourceType': 'Observation',
          'code': {
            'coding': [
              {'system': 'http://loinc.org', 'code': '8867-4'},
            ],
            'text': 'Heart rate',
          },
          'valueQuantity': {'value': 72, 'unit': 'bpm'},
        },
      },
    ],
  });

  final encrypted = await fidelius.encrypt(
    plaintext: fhirBundle,
    senderKeyPair: hipKeys,
    receiverPublicKey: hiuKeys.publicKey,
    receiverNonce: hiuKeys.nonce,
  );

  print('FHIR bundle encrypted (${fhirBundle.length} chars)');
  print('Payload JSON keys: ${encrypted.toJson().keys.join(', ')}');

  // HIU decrypts with their key pair
  final decrypted = await fidelius.decrypt(
    payload: encrypted,
    receiverKeyPair: hiuKeys,
  );

  final bundle = jsonDecode(decrypted!);
  print('Decrypted bundle type: ${bundle['type']}');
  print('Entries: ${(bundle['entry'] as List).length}');
  print('');
}

// ---------------------------------------------------------------------------
// 4. Low-level primitives — step-by-step protocol execution
// ---------------------------------------------------------------------------

Future<void> lowLevelPrimitives() async {
  print('=== 4. Low-Level Primitives ===\n');

  // Generate key pairs using the primitive function
  final senderKeys = await generateKeyPair(FideliusCurveType.curve25519);
  final receiverKeys = await generateKeyPair(FideliusCurveType.curve25519);

  // Step 1: Decode keys and derive shared secret
  final senderPriv = decodeBase64Strict(senderKeys.privateKey, 'sender priv');
  final receiverPub = decodeBase64Strict(
    receiverKeys.publicKey,
    'receiver pub',
  );

  final sharedSecret = await deriveSharedSecret(
    privateKeyBytes: senderPriv,
    publicKeyBytes: receiverPub,
    curve: FideliusCurveType.curve25519,
  );
  print('Shared secret: ${sharedSecret.length} bytes');

  // Step 2: XOR nonces into salt + IV
  final senderNonce = decodeBase64Strict(senderKeys.nonce, 'sender nonce');
  final receiverNonce = decodeBase64Strict(
    receiverKeys.nonce,
    'receiver nonce',
  );
  final (:salt, :iv) = xorAndSplitNonces(senderNonce, receiverNonce);
  print('HKDF salt: ${salt.length} bytes, AES-GCM IV: ${iv.length} bytes');

  // Step 3: HKDF key derivation
  final aesKey = await deriveKey(sharedSecret: sharedSecret, salt: salt);
  print('AES-256 key: ${aesKey.length} bytes');

  // Step 4: AES-GCM encrypt
  final plaintext = utf8.encode('Low-level encryption test');
  final ciphertext = await aesGcmEncrypt(
    plaintext: plaintext,
    key: aesKey,
    iv: iv,
  );
  print('Ciphertext + tag: ${ciphertext.length} bytes');

  // Step 5: AES-GCM decrypt
  final decrypted = await aesGcmDecrypt(
    ciphertext: ciphertext,
    key: aesKey,
    iv: iv,
  );
  print('Decrypted: ${utf8.decode(decrypted!)}');

  // DER encoding
  final rawPub = decodeBase64Strict(senderKeys.publicKey, 'pub');
  final der = encodeX509SpkiDer(rawPub, FideliusCurveType.curve25519);
  print('DER-encoded public key: ${der.length} bytes');

  final decoded = decodeX509SpkiDer(der);
  print(
    'Round-trip DER: ${decoded.length} bytes (matches raw: ${decoded.length == rawPub.length})',
  );
  print('');
}

// ---------------------------------------------------------------------------
// 5. JSON serialization — payload and key pair round-trip
// ---------------------------------------------------------------------------

Future<void> jsonSerialization() async {
  print('=== 5. JSON Serialization ===\n');

  const fidelius = FideliusCurve25519();
  final sender = await fidelius.generateKeyPair();
  final receiver = await fidelius.generateKeyPair();

  // Key pair JSON (safe — excludes private key)
  final pubJson = sender.toJson();
  print('Public JSON keys: ${pubJson.keys.join(', ')}');
  print('Has privateKey?   ${pubJson.containsKey('privateKey')}');

  // Full key pair JSON (includes private key — for local storage only)
  final fullJson = sender.toJsonWithPrivateKey();
  final restored = FideliusKeyPair.fromJson(fullJson);
  print('Restored nonce matches: ${restored.nonce == sender.nonce}');

  // Encrypted payload JSON
  final encrypted = await fidelius.encrypt(
    plaintext: 'Serialization test',
    senderKeyPair: sender,
    receiverPublicKey: receiver.publicKey,
    receiverNonce: receiver.nonce,
  );

  final payloadJson = jsonEncode(encrypted.toJson());
  print('Payload JSON: ${payloadJson.substring(0, 50)}...');

  // Reconstruct from JSON
  final parsed = FideliusEncryptedPayload.fromJson(
    jsonDecode(payloadJson) as Map<String, dynamic>,
  );

  final decrypted = await fidelius.decrypt(
    payload: parsed,
    receiverKeyPair: receiver,
  );
  print('Decrypted from JSON: $decrypted');
  print('');
}
0
likes
160
points
59
downloads

Documentation

API reference

Publisher

verified publisherpensievelabs.org

Weekly Downloads

Dart implementation of ABDM Fidelius encryption (ECDH + HKDF + AES-256-GCM) for India's health data exchange.

Homepage
Repository (GitHub)
View/report issues

Topics

#abdm #fidelius #encryption #ecdh #healthcare

License

MIT (license)

Dependencies

args, cryptography, pointycastle

More

Packages that depend on abdm_fidelius