Module: SimpleSecrets::Primitives

Defined in:
lib/simple_secrets/primitives.rb

Overview

Public: Various methods useful for performing cryptographic operations. WARNING: Using any of these primitives in isolation could be Bad. Take cautious.

Examples

Primitives.nonce
# => "\x02\x0E\xBB\xBE\xA2\xA4\f\x80\x11N\xCDui\xEE<e"

Class Method Summary collapse

Class Method Details

.binify(string) ⇒ Object

Public: Turn a websafe string back into a binary string.

Uses base64url encoding.

string - websafe string

Examples

Primitives.binify('')
# =>

Returns the binary version of this string



248
249
250
251
252
253
# File 'lib/simple_secrets/primitives.rb', line 248

def self.binify string
  raise 'base64url string required.' unless (string.instance_of?(String) && string =~ /^[a-zA-Z0-9_\-]+$/)

  string += '=' while !(string.size % 4).zero?
  Base64.urlsafe_decode64(string)
end

.compare(a, b) ⇒ Object

Public: Use a constant-time comparison algorithm to reduce side-channel attacks.

Short-circuits only when the two buffers aren’t the same length.

a - a binary string b - a binary string

Examples

Primitives.compare('','')
# =>

Returns true if both buffer contents match



220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/simple_secrets/primitives.rb', line 220

def self.compare a, b
  assertBinary(a, b)

  # things must be the same length to compare them.
  return false if a.bytesize != b.bytesize

  # constant-time compare
  #   hat-tip to https://github.com/freewil/scmp for |=
  same = 0;
  (0...a.bytesize).each do |i|
    same |= a.getbyte(i) ^ b.getbyte(i)
  end
  same == 0
end

.decrypt(binary, key, iv) ⇒ Object

Public: Decrypt buffer with the given key and initialization vector.

Uses AES256.

binary - ciphertext key - the 256-bit encryption key iv - the 128-bit initialization vector

Examples

Primitives.decrypt('', '')
# =>

Returns the plaintext binary string



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/simple_secrets/primitives.rb', line 149

def self.decrypt binary, key, iv
  assertBinary(binary, key, iv)
  assert256BitBinary(key)
  assert128BitBinary(iv)

  cipher = OpenSSL::Cipher::AES256.new(:CBC)
  cipher.decrypt
  cipher.key = key
  cipher.iv = iv

  decrypted = ''.force_encoding('BINARY')
  decrypted << cipher.update(binary)
  decrypted << cipher.final
  decrypted
end

.derive_receiver_hmac(master_key) ⇒ Object

Public: Generate the authentication key for messages originating from the channel’s Receiver side.

Uses the ASCII string ‘simple-crypto/receiver-hmac-key’ as the role.

master_key - the 256-bit master key of this secure channel

Examples

Primitives.derive_receiver_hmac(master_key)
# =>

Returns 256-bit receiver hmac key



81
82
83
# File 'lib/simple_secrets/primitives.rb', line 81

def self.derive_receiver_hmac master_key
  derive(master_key, 'simple-crypto/receiver-hmac-key')
end

.derive_receiver_key(master_key) ⇒ Object

Public: Generate the encryption key for messages originating from the channel’s Receiver side.

Uses the ASCII string ‘simple-crypto/receiver-cipher-key’ as the role.

master_key - the 256-bit master key of this secure channel

Examples

Primitives.derive_receiver_key(master_key)
# =>

Returns 256-bit receiver encryption key



99
100
101
# File 'lib/simple_secrets/primitives.rb', line 99

def self.derive_receiver_key master_key
  derive(master_key, 'simple-crypto/receiver-cipher-key')
end

.derive_sender_hmac(master_key) ⇒ Object

Public: Generate the authentication key for messages originating from the channel’s Sender side.

Uses the ASCII string ‘simple-crypto/sender-hmac-key’ as the role.

master_key - the 256-bit master key of this secure channel

Examples

Primitives.derive_sender_hmac(master_key)
# =>

Returns 256-bit sender hmac key



45
46
47
# File 'lib/simple_secrets/primitives.rb', line 45

def self.derive_sender_hmac master_key
  derive(master_key, 'simple-crypto/sender-hmac-key')
end

.derive_sender_key(master_key) ⇒ Object

Public: Generate the encryption key for messages originating from the channel’s Sender side.

Uses the ASCII string ‘simple-crypto/sender-cipher-key’ as the role.

master_key - the 256-bit master key of this secure channel

Examples

Primitives.derive_sender_key(master_key)
# =>

Returns 256-bit sender encryption key



63
64
65
# File 'lib/simple_secrets/primitives.rb', line 63

def self.derive_sender_key master_key
  derive(master_key, 'simple-crypto/sender-cipher-key')
end

.deserialize(binary) ⇒ Object

Public: Turn a binary representation into a Ruby object suitable for use in application logic. This object possibly originated in a different programming environment—it should be JSON-like in structure.

Uses MsgPack data serialization.

binary - a binary string version of the object

Examples

Primitives.deserialize('')
# =>

Returns the Ruby object



310
311
312
313
314
# File 'lib/simple_secrets/primitives.rb', line 310

def self.deserialize binary
  assertBinary(binary)

  MessagePack.unpack(binary)
end

.encrypt(binary, key) ⇒ Object

Public: Encrypt buffer with the given key.

Uses AES256 with a random 128-bit initialization vector.

binary - the plaintext binary string key - the 256-bit encryption key

Examples

Primitives.encrypt('', '')
# =>

Returns a binary string of (IV || ciphertext)



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/simple_secrets/primitives.rb', line 117

def self.encrypt binary, key
  assertBinary(binary)
  assertBinary(key)
  assert256BitBinary(key)

  cipher = OpenSSL::Cipher::AES256.new(:CBC)
  cipher.encrypt
  cipher.key = key
  iv = cipher.iv = OpenSSL::Random.random_bytes(16)

  encrypted = ''.force_encoding('BINARY')
  encrypted << iv
  encrypted << cipher.update(binary)
  encrypted << cipher.final
  encrypted
end

.identify(binary) ⇒ Object

Public: Create a short identifier for potentially sensitive data.

binary - the data to identify

Examples

Primitives.identify('')
# =>

Returns a 6-byte binary string identifier



176
177
178
179
180
181
182
183
# File 'lib/simple_secrets/primitives.rb', line 176

def self.identify binary
  assertBinary(binary)

  hash = OpenSSL::Digest::SHA256.new
  hash << [binary.size].pack("C*")
  hash << binary
  hash.digest[0..5]
end

.mac(binary, hmac_key) ⇒ Object

Public: Create a message authentication code for the given data. Uses HMAC-SHA256.

binary - data to authenticate hmac_key - the authentication key

Examples

Primitives.mac('','')
# =>

Returns a 32-byte MAC binary string



198
199
200
201
202
203
# File 'lib/simple_secrets/primitives.rb', line 198

def self.mac binary, hmac_key
  assertBinary(binary, hmac_key)
  assert256BitBinary(hmac_key)

  OpenSSL::HMAC.digest(OpenSSL::Digest::SHA256.new, hmac_key, binary)
end

.nonceObject

Public: Provide 16 securely random bytes.

Examples

nonce
# => "\x02\x0E\xBB\xBE\xA2\xA4\f\x80\x11N\xCDui\xEE<e"

Returns 16 random bytes in a binary string



27
28
29
# File 'lib/simple_secrets/primitives.rb', line 27

def self.nonce
  OpenSSL::Random.random_bytes 16
end

.serialize(object) ⇒ Object

Public: Turn a JSON-like object into a binary representation suitable for use in crypto functions. This object will possibly be deserialized in a different programming environment—it should be JSON-like in structure.

Uses MsgPack data serialization.

object - any object without cycles which responds to to_msgpack

Examples

Primitives.serialize('')
# =>

Returns the binary version of this object



290
291
292
# File 'lib/simple_secrets/primitives.rb', line 290

def self.serialize object
  object.to_msgpack
end

.stringify(binary) ⇒ Object

Public: Turn a binary buffer into a websafe string.

Uses base64url encoding.

binary - data which needs to be websafe

Examples

Primitives.stringify('')
# =>

Returns the websafe string



268
269
270
271
272
# File 'lib/simple_secrets/primitives.rb', line 268

def self.stringify binary
  assertBinary(binary)

  Base64.urlsafe_encode64(binary).gsub('=','')
end

.zero(*args) ⇒ Object

Public: Overwrite the contents of the buffer with zeroes. This is critical for removing sensitive data from memory.

args - binary strings whose content should be wiped

Examples

Primitives.zero('','')
# =>

Returns an array of references to the strings which have been zeroed



328
329
330
331
332
333
# File 'lib/simple_secrets/primitives.rb', line 328

def self.zero *args
  assertBinary(*args)
  args.each do |buf|
    buf.gsub!(/./,"\x00")
  end
end