Skip to content

Hiero Message Box is a simple way for users to set up a message box and receive private messages, for example getting alerts about security communications about their assets or wallet, etc.

License

Notifications You must be signed in to change notification settings

InternetOfPeers/hiero-message-box

Repository files navigation

Hiero Message Box - Private Asynchronous Messaging

Hiero Message Box is a simple way for users to set up a message box and receive private messages, for example getting alerts about security communications about their assets or wallet, etc.

This implementation follows the specifications defined in the HIP-1334.

View the interactive presentation to visualize the message box flow.

Quick start

The repo contains the code both for the sender and the receiver.

The goal is to enable users to send encrypted messages to an account's message box just like this:

npm run send-message -- 0.0.1441 "This is a secret message for you"

Users can create the message box with this command:

npm run setup-message-box

Users can listen for new messages in real-time using this command:

npm run listen-for-new-messages

Users can also check for historical messages using this command:

npm run check-messages -- [start-sequence] [end-sequence]

On first setup, the program generates/derives encryption keys, creates a Hedera topic as your message box, and updates your account memo with the topic ID in HIP-1334 format.

Features

  • Two-Key System: Separates transaction payer from message box owner
    • PAYER_PRIVATE_KEY: Pays for all Hedera transactions
    • MESSAGE_BOX_OWNER_PRIVATE_KEY: Signs messages to prove ownership
    • Enables third-party services to pay for users while maintaining user control
  • Ownership Verification: Cryptographic signatures prove message box ownership
    • First message signed with owner's Hedera private key
    • Senders verify signature against Mirror Node before sending
    • Prevents sending to compromised or fraudulent message boxes
  • Dual Encryption Support: Choose between RSA-2048 or ECIES (Elliptic Curve Integrated Encryption Scheme)
    • RSA Mode: Traditional RSA-2048 keys stored in data/ folder (works with all key types)
    • ECIES Mode: Uses your Hedera operator's SECP256K1 key (no separate key files needed)
  • Automatic Key Management: RSA keys are auto-generated, ECIES keys are derived from your operator credentials
  • Hedera Topics: Creates and manages Hedera topics for message distribution
  • Key Verification: Automatically verifies local keys match the topic's public key
  • Mirror Node API: Uses Hedera Mirror Node for all read operations (account validation, memo retrieval, message polling, topic verification)
  • Real-time Listening: Continuously polls for new encrypted messages every 3 seconds
  • Message Formats: Supports both JSON and CBOR encoding formats for flexibility
  • Chunked Messages: Automatically handles messages larger than 1KB split across multiple chunks by HCS
  • Modular Architecture: Common functions extracted for reusability and maintainability
  • Minimal External Dependencies: Uses only Hashgraph SDK v2.76.0 and native Node.js crypto module

Prerequisites

Installation

  1. Clone or download this repository

  2. Install dependencies:

    npm install
  3. Create a .env file with your Hedera credentials:

    cp .env.example .env
  4. Edit .env and add your Hedera account details:

# Two-Key System Configuration
# PAYER_PRIVATE_KEY: Account that pays for all Hedera transactions
PAYER_ACCOUNT_ID=0.0.xxxxx
PAYER_PRIVATE_KEY=302e020100300506032b657004220420...

# MESSAGE_BOX_OWNER_PRIVATE_KEY: Account that owns and signs the message box
# - If not set, defaults to PAYER_PRIVATE_KEY (operator owns the message box)
# - Allows third-party services to pay for transactions on behalf of users
MESSAGE_BOX_OWNER_ACCOUNT_ID=0.0.xxxxx
MESSAGE_BOX_OWNER_PRIVATE_KEY=302e020100300506032b657004220420...

# Encryption Configuration (optional - defaults to RSA)
# Options: RSA, ECIES
# RSA: Uses RSA-2048 keys (generated and stored in data/ folder)
# ECIES: Uses operator's SECP256K1 key for encryption (derived from MESSAGE_BOX_OWNER_PRIVATE_KEY)
#        Note: ECIES requires SECP256K1 - ED25519 keys are not supported
ENCRYPTION_TYPE=RSA

# Data directory for RSA keys (optional - defaults to ./data)
RSA_DATA_DIR=./data

# Network Configuration (optional - defaults to testnet)
HEDERA_NETWORK=testnet
MIRROR_NODE_URL=https://testnet.mirrornode.hedera.com

For mainnet, change to:

HEDERA_NETWORK=mainnet
MIRROR_NODE_URL=https://mainnet.mirrornode.hedera.com

Usage

Choosing an Encryption Method

The Hiero Message Box supports two encryption methods:

Feature RSA (Default) ECIES
Key Management Generate & store PEM files Uses your operator key
Key Type Support All (ED25519, SECP256K1) SECP256K1 only
Public Key Size 294 bytes 33-65 bytes
Setup Time ~50ms (key generation) <1ms (key derivation)
Security RSA-2048 + AES-256-CBC ECDH + AES-256-GCM
Files to Backup data/rsa_*.pem None (uses .env)

Use RSA if:

  • You already have a message box and want to keep it
  • Your Hedera account uses ED25519 keys
  • You prefer separate encryption keys from your operator key

Use ECIES if:

  • Your Hedera account uses SECP256K1 keys
  • You want to use your Hedera key for everything
  • You want faster setup with no key file management

To enable ECIES, add to your .env:

ENCRYPTION_TYPE=ECIES

Note: ED25519 keys cannot use ECIES (signature algorithm, no ECDH support). The system will prompt to switch to RSA if needed.

Setup Message Box

npm run setup-message-box

The setup process:

  1. Loads/generates encryption keys (RSA: data/*.pem, ECIES: derived from HEDERA_PRIVATE_KEY)
  2. Checks existing message box in account memo
  3. Verifies keys can decrypt messages
  4. Creates new topic if needed, publishes public key
  5. Updates account memo with topic ID: [HIP-1334:0.0.xxxxx]

Listen for New Messages

Start the listener to continuously poll for and receive encrypted messages:

npm run listen-for-new-messages
# or
npm start

Note: npm start runs setup then starts listening.

Polls Mirror Node every 3 seconds, automatically detects and decrypts messages. Press Ctrl+C to stop.

Check Messages

Retrieve and read messages from your message box in a specific range:

npm run check-messages -- [start-sequence] [end-sequence]

Examples:

# Get all messages from sequence 2 onwards (default)
npm run check-messages

# Get all messages from sequence 5 onwards
npm run check-messages -- 5

# Get messages from sequence 5 to 10 (inclusive)
npm run check-messages 5 10

Retrieves and decrypts messages in the specified range with timestamps and sequence numbers.

Send Encrypted Messages

Send an encrypted message to another account:

npm run send-message -- <account-id> <message> [--cbor]

Examples:

npm run send-message -- 0.0.1441 "Hello, secret message!"
npm run send-message -- 0.0.1441 "Hello, secret message!" --cbor

Note: Use -- to separate npm options from script arguments.

Message Formats

  • JSON (default): Human-readable, easy to debug (~510 bytes typical message)
  • CBOR (optional): Binary format, ~3-5% smaller (~491 bytes), best for high-volume scenarios

Both formats are auto-detected when reading messages.

How it works

  1. Fetches recipient's account memo and public key from topic
  2. Auto-detects encryption type (RSA or ECIES)
  3. Encrypts message (RSA: AES-256+RSA-2048, ECIES: ECDH+AES-256-GCM)
  4. Sends encrypted payload to topic (JSON or CBOR)

Recipients automatically detect and decrypt messages when polling.

Large Messages

HCS automatically splits messages >1KB into chunks. This application transparently reassembles them before decryption—no size limit.

Remove Message Box

To remove your message box configuration (clears your account memo):

npm run remove-message-box

Clears account memo but doesn't delete the topic or keys.

Encryption Methods

RSA Mode

Hybrid encryption: AES-256-CBC for messages + RSA-2048-OAEP for key exchange. Supports all key types, works with any length messages.

ECIES Mode

Uses ECDH (secp256k1) + AES-256-GCM. Provides smaller public keys (33 bytes vs 294), and derives keys from your operator credentials. Requires SECP256K1 (ED25519 not supported).

Architecture

Modular Design

The codebase is organized into three main modules:

  1. lib/crypto.js: Cryptographic operations

    • Environment variable loading from .env file
    • RSA hybrid encryption/decryption (AES-256-CBC + RSA-2048-OAEP)
    • ECIES encryption/decryption (ECDH + AES-256-GCM)
    • Encryption type detection and routing
    • Custom CBOR encoder/decoder implementation (RFC 8949 compliant)
    • Message signing and signature verification (ED25519, ECDSA_SECP256K1)
    • DER encoding helpers for public/private keys
  2. lib/hedera.js: Hedera blockchain operations

    • Client initialization (testnet/mainnet)
    • Account memo read (via Mirror Node) and update (via Hedera SDK)
    • Account validation and public key retrieval using Mirror Node API
    • Topic creation and message submission
    • Mirror Node URL configuration
    • Topic message queries with pagination support
    • Hedera key parsing and public key derivation (SECP256K1, ED25519)
    • Transaction execution and signing helpers
  3. lib/message-box.js: Core message box logic

    • Two-key system support (payer and owner separation)
    • Message box setup with ownership signature generation
    • RSA key pair generation and management
    • ECIES key derivation from operator credentials
    • Public key publishing with cryptographic signature proof
    • Signature verification before sending messages
    • Message encryption and sending (JSON/CBOR formats, auto-detecting encryption type)
    • Real-time message polling with sequence tracking
    • Automatic format and encryption type detection and decoding
    • Canonical JSON serialization for deterministic signatures

Mirror Node API

Uses Hedera Mirror Node REST API for all read operations (cost-free):

  • Account validation and memo retrieval
  • Topic verification and public key retrieval
  • Message polling with pagination
  • Historical message queries

Message Format

All messages submitted to the topic use either JSON or CBOR encoding with a type field:

Public Key Message (first message in topic, always JSON):

RSA format with ownership proof:

{
  "payload": {
    "encryptionType": "RSA",
    "publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhki...",
    "type": "HIP-1334_PUBLIC_KEY"
  },
  "proof": {
    "accountId": "0.0.12345",
    "signerPublicKey": "a1b2c3d4...",
    "signerKeyType": "ED25519",
    "signature": "d5e6f7g8..."
  }
}

ECIES format with ownership proof:

{
  "payload": {
    "encryptionType": "ECIES",
    "publicKey": {
      "curve": "secp256k1",
      "key": "03a1b2c3d4e5f6...",
      "type": "ECIES"
    },
    "type": "HIP-1334_PUBLIC_KEY"
  },
  "proof": {
    "accountId": "0.0.12345",
    "signerPublicKey": "02a1b2c3d4...",
    "signerKeyType": "ECDSA_SECP256K1",
    "signature": "d5e6f7g8..."
  }
}

The proof section contains a cryptographic signature of the payload using the message box owner's Hedera private key. Senders verify this signature against the account's public key from Mirror Node before sending messages, preventing fraudulent message boxes.

Encrypted Message (JSON format):

RSA:

{
  "type": "HIP-1334_ENCRYPTED_MESSAGE",
  "format": "json",
  "data": {
    "type": "RSA",
    "encryptedKey": "base64...",
    "iv": "base64...",
    "encryptedData": "base64..."
  }
}

ECIES:

{
  "type": "HIP-1334_ENCRYPTED_MESSAGE",
  "format": "json",
  "data": {
    "type": "ECIES",
    "ephemeralPublicKey": "hex...",
    "iv": "base64...",
    "encryptedData": "base64...",
    "authTag": "base64...",
    "curve": "secp256k1"
  }
}

Encrypted Message (CBOR format): Same structure as JSON, more compact.

Messages are auto-detected (format: JSON/CBOR/plain, encryption: RSA/ECIES) and decrypted accordingly.

File Structure

./
├── src/
│   ├── setup-message-box.js        # Setup message box for account
│   ├── check-messages.js           # Check existing messages inside the message box
│   ├── listen-for-new-messages.js  # Listener/Receiver application
│   ├── send-message.js             # Sender application
│   ├── remove-message-box.js       # Remove message box configuration
│   └── lib/
│       ├── common.js               # Common utilities (encryption, env loading, CBOR)
│       ├── hedera.js               # Hedera SDK wrappers, client init, key parsing
│       └── message-box.js          # Core message box logic (setup, send, poll)
├── data/
│   ├── rsa_private.pem             # RSA private key (auto-generated, RSA mode only)
│   └── rsa_public.pem              # RSA public key (auto-generated, RSA mode only)
├── docs/                           # Documentation and presentations
├── package.json                    # Dependencies and scripts
├── .env                            # Hedera credentials and config (not committed)
├── .env.example                    # Example environment file
└── .gitignore                      # Git ignore rules

Available NPM Scripts

npm start                                           # Setup message box and start listening for new messages
npm run setup-message-box                           # Setup/verify message box configuration
npm run listen-for-new-messages                     # Start polling for new messages
npm run check-messages -- [start] [end]             # Read message history (defaults to all messages)
npm run send-message -- <account id> <msg> [--cbor] # Send encrypted message to account
npm run remove-message-box                          # Remove message box (clear account memo)
npm run format                                      # Format code with Prettier
npm test                                            # Run integration tests

Note: Use -- to separate npm options from script arguments when passing parameters.

Testing

Run the integration test suite to verify all functionality:

npm test

The test suite covers:

  • Message box setup (new and existing)
  • Sending messages (JSON and CBOR formats)
  • Retrieving and decrypting messages
  • Message box reuse (idempotency)
  • Signature verification
  • Message box removal

See test/README.md for detailed test documentation.

Configuration Files

Environment Variables (.env)

Required variables:

# Transaction payer
PAYER_ACCOUNT_ID=0.0.xxxxx
PAYER_PRIVATE_KEY=302e020100300506032b657004220420...

# Message box owner
MESSAGE_BOX_OWNER_ACCOUNT_ID=0.0.xxxxx
MESSAGE_BOX_OWNER_PRIVATE_KEY=302e020100300506032b657004220420...

# Data directory for RSA keys
RSA_DATA_DIR=./data

Optional variables:

# Encryption type (defaults to RSA)
ENCRYPTION_TYPE=RSA  # or ECIES

# Network (defaults to testnet)
HEDERA_NETWORK=testnet
MIRROR_NODE_URL=https://testnet.mirrornode.hedera.com

Encryption Keys

RSA Mode:

  • data/rsa_private.pem: Your private key for decryption (keep secure!)
  • data/rsa_public.pem: Your public key (published to the topic for others to use)

ECIES Mode:

  • No separate key files needed
  • Keys are derived from HEDERA_PRIVATE_KEY in .env
  • Requires SECP256K1 key type

Security Notes

  • Never commit .env or private keys
  • Two-key system: Separates payment from ownership
    • PAYER_PRIVATE_KEY: Pays for transactions
    • MESSAGE_BOX_OWNER_PRIVATE_KEY: Proves ownership via signatures
    • Enables third-party payment while maintaining user control
  • RSA mode: private key in data/rsa_private.pem for local decryption only
  • ECIES mode: operator key in .env used for transactions and decryption
  • Signature verification: Message box ownership uses cryptographic signatures with canonical JSON serialization
    • First message signed with owner's Hedera private key
    • Senders verify signature against account's public key from Mirror Node
    • Ensures deterministic signature verification regardless of JSON property ordering
    • Keys are sorted alphabetically before signing to prevent signature mismatch
    • Prevents sending messages to compromised or fraudulent message boxes

Troubleshooting

Common Issues

  • Missing credentials: Ensure .env exists with valid PAYER_ACCOUNT_ID, PAYER_PRIVATE_KEY, MESSAGE_BOX_OWNER_ACCOUNT_ID, and MESSAGE_BOX_OWNER_PRIVATE_KEY
  • Message box not found: Recipient needs to run npm run setup-message-box
  • Cannot decrypt: Keys don't match topic—restore original keys or create new message box
  • Signature verification failed: Message box signature doesn't match recipient's public key—possible fraudulent message box
  • Encryption mismatch: ENCRYPTION_TYPE in .env doesn't match message box
  • ECIES with ED25519: ED25519 doesn't support ECIES—use RSA or SECP256K1 account
  • Mirror Node errors: Check internet and verify MIRROR_NODE_URL matches network

Migration Guide

Switching Encryption Types

  1. Update ENCRYPTION_TYPE in .env (RSA or ECIES)
  2. Run npm run setup-message-box to create new message box
  3. Old message box remains accessible with original keys

Note: ECIES requires SECP256K1 key (not ED25519).

Additional Documentation

References

License

MIT

About

Hiero Message Box is a simple way for users to set up a message box and receive private messages, for example getting alerts about security communications about their assets or wallet, etc.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Contributors 2

  •  
  •