NIP-44: Encrypted payloads
The NIP introduces a new data format for keypair-based encryption. This NIP is versioned to allow multiple algorithm choices to exist simultaneously. This format may be used for many things, but MUST be used in the context of a signed event as described in NIP-01.
Notice on how this documentation is created
Parts of these page are generated with Goose (AI agent) and Claude (LLM). Used resources are the Nostr NIP repository and the code in the Nostr-PHP library. This combination enables Goose and Claude to determine what to explain how to use NIP44 class. All generated content is revised afterward.
The Nostr-PHP library provides NIP-44 encryption functionality through the Nip44
class.
Key Features
- Uses XChaCha20-Poly1305 for encryption
- Implements perfect forward secrecy
- Provides message padding for better privacy
- Prevents message replay attacks
- Includes conversation state tracking
Basic Usage
Setting Up
First, import the Nip44 class:
use NostrPHP\Encryption\Nip44;
Encrypting messages
To encrypt a message, you need:
- Your private key (sender)
- Recipient's public key
- The message to encrypt
$nip44 = new Nip44();
$privateKey = "your-private-key-hex";
$recipientPubkey = "recipient-pubkey-hex";
$message = "Hello, this is a secret message!";
$encryptedMessage = $nip44->encrypt($privateKey, $recipientPubkey, $message);
// Returns: Base64 encoded encrypted message
Decrypting Messages
To decrypt a message, you need:
- Your private key (recipient)
- Sender's public key
- The encrypted message
$nip44 = new Nip44();
$privateKey = "your-private-key-hex";
$senderPubkey = "sender-pubkey-hex";
$encryptedMessage = "base64-encoded-encrypted-message";
$decryptedMessage = $nip44->decrypt($privateKey, $senderPubkey, $encryptedMessage);
// Returns: Original message string
Complete Example
Here's a complete example showing both encryption and decryption:
use NostrPHP\Encryption\Nip44;
// Initialize the NIP-44 handler
$nip44 = new Nip44();
// Keys for Alice and Bob
$alicePrivateKey = "alice-private-key-hex";
$alicePublicKey = "alice-public-key-hex";
$bobPrivateKey = "bob-private-key-hex";
$bobPublicKey = "bob-public-key-hex";
// Alice encrypts a message for Bob
$message = "Hey Bob, this is a secure message using NIP-44!";
$encryptedMessage = $nip44->encrypt($alicePrivateKey, $bobPublicKey, $message);
// Bob decrypts the message from Alice
$decryptedMessage = $nip44->decrypt($bobPrivateKey, $alicePublicKey, $encryptedMessage);
echo $decryptedMessage; // Outputs: "Hey Bob, this is a secure message using NIP-44!"
Integration with Nostr Events
When sending encrypted direct messages using NIP-44, you create an event with kind 4:
use NostrPHP\Encryption\Nip44;
use NostrPHP\Event\Event;
// Initialize NIP-44
$nip44 = new Nip44();
// Your keys and recipient's public key
$privateKey = "your-private-key-hex";
$publicKey = "your-public-key-hex";
$recipientPubkey = "recipient-pubkey-hex";
// Message to encrypt
$message = "This is a private message using NIP-44";
// Encrypt the message
$encryptedContent = $nip44->encrypt($privateKey, $recipientPubkey, $message);
// Create the event
$event = new Event();
$event->kind = 4; // Direct Message event kind
$event->pubkey = $publicKey;
$event->content = $encryptedContent;
$event->tags = [
["p", $recipientPubkey], // Add recipient's pubkey as a "p" tag
];
// Sign the event
$event->sign($privateKey);
// The event is now ready to be published to relays
Conversation State Management
NIP-44 maintains conversation state to ensure message ordering and prevent replay attacks. The state is automatically managed by the library, but you can also explicitly manage it:
use NostrPHP\Encryption\Nip44;
$nip44 = new Nip44();
// Get the current conversation state
$state = $nip44->getConversationState($privateKey, $recipientPubkey);
// Reset conversation state if needed
$nip44->resetConversationState($privateKey, $recipientPubkey);
Decrypting Received Messages
@todo
Error Handling
The encryption/decryption methods may throw exceptions in various cases:
- Invalid key formats
- Corrupted encrypted messages
- Invalid base64 encoding
- Decryption failures
- Invalid conversation states
Always wrap your encryption/decryption operations in try-catch blocks:
use NostrPHP\Encryption\Nip44;
$nip44 = new Nip44();
try {
$decryptedMessage = $nip44->decrypt($privateKey, $senderPubkey, $encryptedMessage);
} catch (\Exception $e) {
// Handle encryption/decryption errors
echo "Error processing message: " . $e->getMessage();
}
Security Considerations
- Always keep private keys secure and never share them
- NIP-44 provides better security than NIP-04:
- Perfect forward secrecy ensures past messages remain secure even if keys are compromised
- Message padding prevents message length analysis
- Conversation state tracking prevents replay attacks
- Use secure methods to store and handle private keys
- Remember that while message content is encrypted, metadata (sender, recipient, timestamp) remains visible