RbNaCl Documentation

repository·main·Indexed 21 days ago

https://github.com/rubycrypto/rbnacl

A Ruby binding for libsodium (version 1.0.0 or higher) providing high-level, secure-by-default cryptographic APIs. It supports features including public-key and secret-key encryption (SimpleBox, SealedBox, SecretBox), digital signatures (Ed25519), authenticators (MACs), hash functions, and AEAD primitives such as ChaCha20-Poly1305. Compatible with Ruby 2.6 through 3.4 and JRuby 9.4 and 10.0.

Tokens
7K
Snippets
31
Records
38
Agent score
75%

What's inside RbNaCl

  1. Overview of RbNaCl cryptographic features

    main

    RbNaCl provides high-level, secure-by-default cryptographic APIs. Supported features include:

    • SimpleBox: Easy-to-use public-key or secret-key encryption.
    • Secret-key Encryption: Authenticated symmetric encryption using a single shared key.
    • Public-key Encryption: Securely sending messages to a public key that only the corresponding secret key can decrypt.
    • Digital Signatures: Signing messages with a private key for verification with a public key.
    • Authenticators (MACs): Creating codes to check message authenticity.
    • Hash Functions: Computing secure, fixed-length codes from messages.
  2. Install the RbNaCl gem

    main

    Once libsodium is installed, you can add RbNaCl to your Ruby project.

    Using Bundler: Add this to your Gemfile:

    gem 'rbnacl'

    Then run:

    bundle

    Manual Installation:

    gem install rbnacl

    Usage in code:

    require 'rbnacl'
    gem install rbnacl
  3. How Sealed Boxes work for anonymous encryption

    main

    Sealed boxes allow a sender to anonymously send messages to a recipient using only the recipient's public key.

    Key characteristics:

    • Anonymity: The recipient can decrypt the message but cannot verify the identity of the sender.
    • Ephemeral Keys: Encryption uses an ephemeral key pair; the secret part is destroyed immediately after encryption. This means the sender cannot decrypt their own message later.
    • Integrity: The recipient can verify the integrity of the message.
    • Unlinkability: Without additional data, a message cannot be correlated with the identity of the sender.
  4. Use RbNaCl::SimpleBox for easy authenticated encryption

    main

    The RbNaCl::SimpleBox class provides a high-level wrapper around RbNaCl::Box (public-key encryption) or RbNaCl::SecretBox (symmetric encryption). It simplifies the encryption process by automatically generating a 24-byte random nonce for every encryption operation and prepending that nonce to the resulting ciphertext.

    When decrypting, SimpleBox automatically extracts the nonce from the beginning of the message.

    Key Characteristics:

    • Overhead: The resulting ciphertext is 40 bytes longer than the original plaintext (24 bytes for the nonce + 16 bytes for the authenticator).
    • Security Note: While it provides confidentiality, it does not protect against message reordering or replay attacks by an active adversary.
    • Collision Resistance: The 24-byte random nonce makes the probability of a collision negligible.
    # Example of using SimpleBox with a secret key
    secret_key = RbNaCl::SecretBox.new(your_32_byte_key)
    simple_box = RbNaCl::SimpleBox.new(secret_key)
    
    # Encrypt
    encrypted = simple_box.box("my secret message")
    
    # Decrypt
    decrypted = simple_box.open(encrypted)
  5. Use Authenticated Encryption with Associated Data (AEAD) primitives

    main

    RbNaCl provides AEAD (Authenticated Encryption with Associated Data) implementations, specifically wrappers for ChaCha20-Poly1305 (both the original and the IETF versions). AEAD constructions encrypt a message and compute an authentication tag for both the encrypted message and optional additional data, ensuring both confidentiality and integrity.

    To use an AEAD primitive, you must initialize it with a valid secret key. You then use a nonce (number of bytes defined by the specific implementation) to encrypt or decrypt messages.

    Error Handling

    • RbNaCl::LengthError: Raised if the provided key or nonce does not match the expected byte length for the specific primitive.
    • RbNaCl::CryptoError: Raised during decryption if the ciphertext fails authentication (e.g., if the data was tampered with or the wrong key/nonce was used).
    # Example conceptual usage of an AEAD primitive
    # Note: Actual class names like RbNaCl::AEAD::Chacha20Poly1305IETF are used for specific implementations
    
    aead = RbNaCl::AEAD::Chacha20Poly1305IETF.new(secret_key)
    nonce = RbNaCl::Random.random_bytes(aead.nonce_bytes)
    additional_data = "some metadata"
    
    # Encrypt
    ciphertext = aead.encrypt(nonce, "my secret message", additional_data)
    
    # Decrypt
    decrypted_message = aead.decrypt(nonce, ciphertext, additional_data)
  6. Avoid using rbnacl-libsodium with RbNaCl 6.0+

    main
    If you are using rbnacl version 6.0 or higher, you must not have rbnacl-libsodium as a dependency. rbnacl now expects libsodium to be installed via your system's package manager. If RBNACL_LIBSODIUM_GEM_LIB_PATH is defined, the library will raise an error during initialization.
  7. Convert Ed25519 SigningKey to a Curve25519 PrivateKey

    main

    If you need to use the Ed25519 key for encryption (X25519), you can convert it using to_curve25519_private_key. This returns an RbNaCl::Boxes::Curve25519XSalsa20Poly1305::PrivateKey object.

    Note: It is recommended to use distinct keys for signing and encryption.

    curve25519_private_key = signing_key.to_curve25519_private_key
  8. Export Ed25519 VerifyKey bytes or convert to Curve25519

    main

    A VerifyKey provides methods to export its raw data or convert it for use in other cryptographic contexts.

    • to_bytes: Returns the raw public key as a byte string.
    • to_curve25519_public_key: Returns a new RbNaCl::Boxes::Curve25519XSalsa20Poly1305::PublicKey converted from this Ed25519 key.

    Note: It is recommended to use distinct keys for signing and encryption as encouraged by libsodium documentation.

    # Get raw bytes
    raw_bytes = verify_key.to_bytes
    
    # Convert to Curve25519 public key for encryption/decryption tasks
    curve25519_key = verify_key.to_curve25519_public_key
  9. Initialize RbNaCl::SimpleBox

    main

    You can instantiate a SimpleBox in three ways:

    1. Directly with a Box object: Pass an existing RbNaCl::SecretBox or RbNaCl::Box instance to the constructor.
    2. From a secret key: Use self.from_secret_key(secret_key) to create a symmetric SimpleBox using a 32-byte string.
    3. From a keypair: Use self.from_keypair(public_key, private_key) to create an asymmetric SimpleBox using public and private keys.
    # 1. From an existing box
    box = RbNaCl::SecretBox.new(key)
    simple_box = RbNaCl::SimpleBox.new(box)
    
    # 2. From a secret key (32 bytes)
    simple_box = RbNaCl::SimpleBox.from_secret_key(secret_key)
    
    # 3. From a keypair
    simple_box = RbNaCl::SimpleBox.from_keypair(public_key, private_key)
  10. Sign messages with Ed25519

    main

    An Ed25519::SigningKey instance provides two ways to sign data:

    1. sign(message): Returns only the 64-byte signature as a String. The method automatically handles binary encoding to prevent issues with multi-byte UTF-8 characters.
    2. sign_attached(message): Returns a single String containing the 64-byte signature prepended to the original message.

    Ed25519 signatures are deterministic, meaning signing the same message with the same key will always produce the same signature.

    signing_key = RbNaCl::Signatures::Ed25519::SigningKey.generate
    message = "Hello, world!"
    
    # Get just the signature (64 bytes)
    signature = signing_key.sign(message)
    
    # Get the signature prepended to the message
    attached = signing_key.sign_attached(message)