Amarula.Protocol.Crypto.Crypto (amarula v0.1.0)
View SourceCryptographic utilities for WhatsApp Noise protocol implementation.
This module provides functions for Curve25519 key operations, AES-GCM encryption, SHA256 hashing, HKDF key derivation, and HMAC signing required by the Noise protocol.
Summary
Functions
Decrypt ciphertext using AES-256-CTR.
Decrypt ciphertext using AES-256-GCM.
Encrypt plaintext using AES-256-CTR.
Encrypt plaintext using AES-256-GCM.
Derive the link-code pairing key from the pairing code and salt.
Generate a random IV for AES-GCM encryption.
Generate a Curve25519 key pair using built-in crypto.
Generate a registration ID for Signal protocol.
Generates a Signal Protocol public key by prefixing with key bundle type if needed.
Generate a signed pre-key ID.
HMAC-based Key Derivation Function (HKDF).
HMAC-SHA256 signing.
HMAC-SHA512 (used by app-state value MACs).
Generate random bytes of specified length.
Generate SHA-256 hash of input data.
Calculate shared secret from private and public keys using Curve25519.
Sign data with a 32-byte X25519 private key using XEd25519
(libsignal-compatible, matches Baileys Curve.sign).
Verify an XEd25519 signature against a 32-byte Montgomery (X25519) public key
(libsignal-compatible, matches Baileys Curve.verify).
Types
Functions
Decrypt ciphertext using AES-256-CTR.
Mirrors Baileys aesDecryptCTR. Returns the plaintext as a binary.
@spec aes_decrypt_gcm(binary(), binary(), binary(), binary()) :: decryption_result()
Decrypt ciphertext using AES-256-GCM.
Returns {:ok, plaintext} or {:error, reason}.
Encrypt plaintext using AES-256-CTR.
Used by the link-code (phone-number) pairing flow to wrap ephemeral public
keys. Mirrors Baileys aesEncryptCTR. Returns the ciphertext as a binary.
@spec aes_encrypt_gcm(binary(), binary(), binary(), binary()) :: encryption_result()
Encrypt plaintext using AES-256-GCM.
Returns {:ok, ciphertext} or {:error, reason}.
Derive the link-code pairing key from the pairing code and salt.
PBKDF2-HMAC-SHA256, 131_072 iterations (2 << 16), 32-byte output — matches
Baileys derivePairingCodeKey.
@spec generate_iv(non_neg_integer()) :: binary()
Generate a random IV for AES-GCM encryption.
Creates a 12-byte IV with the counter in the last 4 bytes. According to WhatsApp implementation (Baileys/whatsmeow):
- 8 leading zero bytes
- 4 bytes big-endian counter (bytes 8-11) This matches: 0x0000000000000000 || be32(counter)
@spec generate_key_pair() :: key_pair()
Generate a Curve25519 key pair using built-in crypto.
Returns a map with :private and :public keys as binaries.
@spec generate_registration_id() :: non_neg_integer()
Generate a registration ID for Signal protocol.
Returns a random 14-bit integer (0-16383), matching Baileys implementation. WhatsApp requires registration IDs to be within this range.
Generates a Signal Protocol public key by prefixing with key bundle type if needed.
Signal Protocol expects public keys to be 33 bytes (1 byte type + 32 bytes key). If the key is already 33 bytes, return as-is. Otherwise, prefix with KEY_BUNDLE_TYPE.
This matches Baileys: pubKey.length === 33 ? pubKey : Buffer.concat([KEY_BUNDLE_TYPE, pubKey])
@spec generate_signed_pre_key_id() :: non_neg_integer()
Generate a signed pre-key ID.
Returns a random 16-bit integer.
@spec hkdf(binary(), non_neg_integer(), binary(), binary()) :: binary()
HMAC-based Key Derivation Function (HKDF).
Derives keys from input key material using HKDF with SHA-256. Returns the derived key as a binary.
HMAC-SHA256 signing.
Returns the HMAC signature as a binary.
HMAC-SHA512 (used by app-state value MACs).
@spec random_bytes(non_neg_integer()) :: binary()
Generate random bytes of specified length.
Returns random binary data.
Generate SHA-256 hash of input data.
Returns the hash as a binary.
Sign data with a 32-byte X25519 private key using XEd25519
(libsignal-compatible, matches Baileys Curve.sign).
Returns the signature as a binary (64 bytes).
Verify an XEd25519 signature against a 32-byte Montgomery (X25519) public key
(libsignal-compatible, matches Baileys Curve.verify).
Returns true if signature is valid, false otherwise.