Class: Discordrb::Voice::XChaCha20AEAD

Inherits:
Object
  • Object
show all
Defined in:
lib/discordrb/voice/sodium.rb

Overview

High-level wrapper class

Constant Summary collapse

KEY_BYTES =
Sodium.crypto_aead_xchacha20poly1305_ietf_keybytes
NONCE_BYTES =
Sodium.crypto_aead_xchacha20poly1305_ietf_npubbytes
TAG_BYTES =
Sodium.crypto_aead_xchacha20poly1305_ietf_abytes

Class Method Summary collapse

Class Method Details

.decrypt(ciphertext, add, nonce, key) ⇒ String

Decrypts a ciphertext using XChaCha20-Poly1305

Parameters:

  • ciphertext (String)

    the encrypted data (with tag)

  • key (String)

    32-byte decryption key

  • nonce (String)

    24-byte nonce

  • add (String)

    optional associated data

Returns:

  • (String)

    decrypted plaintext

Raises:

  • (ArgumentError)


133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/discordrb/voice/sodium.rb', line 133

def self.decrypt(ciphertext, add, nonce, key)
  raise ArgumentError, 'Invalid key size' unless key.bytesize == KEY_BYTES
  raise ArgumentError, 'Invalid nonce size' unless nonce.bytesize == NONCE_BYTES

  c_ptr = FFI::MemoryPointer.from_string(ciphertext)
  ad_ptr = FFI::MemoryPointer.from_string(add)

  m_ptr = FFI::MemoryPointer.new(:uchar, ciphertext.bytesize - TAG_BYTES)
  mlen_p = FFI::MemoryPointer.new(:ulong_long)

  result = Sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(
    m_ptr, mlen_p,
    nil,
    c_ptr, ciphertext.bytesize,
    ad_ptr, add.bytesize,
    FFI::MemoryPointer.from_string(nonce),
    FFI::MemoryPointer.from_string(key)
  )

  raise 'Decryption failed' unless result.zero?

  m_ptr.read_string(mlen_p.read_ulong_long)
end

.encrypt(message, add, nonce, key) ⇒ String

Encrypts a message using XChaCha20-Poly1305

Parameters:

  • message (String)

    plaintext to encrypt

  • key (String)

    32-byte encryption key

  • nonce (String)

    24-byte nonce

  • add (String)

    optional associated data

Returns:

  • (String)

    ciphertext (includes the auth tag)

Raises:

  • (ArgumentError)


101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/discordrb/voice/sodium.rb', line 101

def self.encrypt(message, add, nonce, key)
  raise ArgumentError, 'Invalid key size' unless key.bytesize == KEY_BYTES
  raise ArgumentError, 'Invalid nonce size' unless nonce.bytesize == NONCE_BYTES

  message_ptr = FFI::MemoryPointer.from_string(message)
  ad_ptr = FFI::MemoryPointer.from_string(add)

  c_len = message.bytesize + TAG_BYTES
  ciphertext = FFI::MemoryPointer.new(:uchar, c_len)
  clen_p = FFI::MemoryPointer.new(:ulong_long)

  result = Sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(
    ciphertext, clen_p,
    message_ptr, message.bytesize,
    ad_ptr, add.bytesize,
    nil,
    FFI::MemoryPointer.from_string(nonce),
    FFI::MemoryPointer.from_string(key)
  )

  raise 'Encryption failed' unless result.zero?

  ciphertext.read_string(clen_p.read_ulong_long)
end

.generate_keyString

Generates a random key

Returns:



84
85
86
# File 'lib/discordrb/voice/sodium.rb', line 84

def self.generate_key
  SecureRandom.random_bytes(KEY_BYTES)
end

.generate_nonceString

Generates a random nonce

Returns:



90
91
92
# File 'lib/discordrb/voice/sodium.rb', line 90

def self.generate_nonce
  SecureRandom.random_bytes(NONCE_BYTES)
end