Class: Nuckle::SecretBox
- Inherits:
-
Object
- Object
- Nuckle::SecretBox
- Defined in:
- lib/nuckle/secret_box.rb
Overview
Symmetric authenticated encryption: XSalsa20-Poly1305.
Compatible with NaCl crypto_secretbox / libsodium crypto_secretbox_xsalsa20poly1305.
Constant Summary collapse
- KEYBYTES =
32- NONCEBYTES =
24- ZEROBYTES =
32- BOXZEROBYTES =
16- MACBYTES =
16
Instance Method Summary collapse
-
#decrypt(nonce, ciphertext) ⇒ String
(also: #open)
Decrypt ciphertext with 24-byte nonce.
-
#encrypt(nonce, plaintext) ⇒ String
(also: #box)
Encrypt plaintext with 24-byte nonce.
-
#initialize(key) ⇒ SecretBox
constructor
A new instance of SecretBox.
-
#key_bytes ⇒ Integer
Required key length in bytes.
-
#nonce_bytes ⇒ Integer
Required nonce length in bytes.
Constructor Details
Instance Method Details
#decrypt(nonce, ciphertext) ⇒ String Also known as: open
Decrypt ciphertext with 24-byte nonce.
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/nuckle/secret_box.rb', line 63 def decrypt(nonce, ciphertext) nonce = nonce.b ciphertext = ciphertext.b raise ArgumentError, "nonce must be #{NONCEBYTES} bytes" unless nonce.bytesize == NONCEBYTES raise CryptoError, "ciphertext too short" if ciphertext.bytesize < MACBYTES mac = ciphertext.byteslice(0, MACBYTES) ct = ciphertext.byteslice(MACBYTES..) # Generate Poly1305 key from first 32 bytes of XSalsa20 keystream poly_key = Internals::Salsa20.xsalsa20_stream(@key, nonce, ZEROBYTES) # Verify MAC expected_mac = Internals::Poly1305.mac(poly_key, ct) raise CryptoError, "decryption failed" unless Util.verify16(mac, expected_mac) # Decrypt padded = ("\x00" * ZEROBYTES + ct).b m = Internals::Salsa20.xsalsa20_xor(@key, nonce, padded) m.byteslice(ZEROBYTES..) end |
#encrypt(nonce, plaintext) ⇒ String Also known as: box
Encrypt plaintext with 24-byte nonce.
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/nuckle/secret_box.rb', line 36 def encrypt(nonce, plaintext) nonce = nonce.b plaintext = plaintext.b raise ArgumentError, "nonce must be #{NONCEBYTES} bytes" unless nonce.bytesize == NONCEBYTES # Pad with 32 zero bytes padded = ("\x00" * ZEROBYTES + plaintext).b c = Internals::Salsa20.xsalsa20_xor(@key, nonce, padded) # First 32 bytes of c: bytes 0..31 of XSalsa20 keystream XOR'd with zeros # → bytes 0..31 ARE the keystream. Use first 32 as Poly1305 one-time key. poly_key = c.byteslice(0, ZEROBYTES) mac = Internals::Poly1305.mac(poly_key, c.byteslice(ZEROBYTES..)) # Return: 16-byte MAC + ciphertext (skip first 16 zero bytes of c) # Actually NaCl convention: c[0..15] are zeros, c[16..31] replaced by mac mac + c.byteslice(ZEROBYTES..) end |
#key_bytes ⇒ Integer
Returns required key length in bytes.
28 |
# File 'lib/nuckle/secret_box.rb', line 28 def key_bytes = KEYBYTES |
#nonce_bytes ⇒ Integer
Returns required nonce length in bytes.
26 27 |
# File 'lib/nuckle/secret_box.rb', line 26 def nonce_bytes = NONCEBYTES # @return [Integer] required key length in bytes |