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
-
.binify(string) ⇒ Object
Public: Turn a websafe string back into a binary string.
-
.compare(a, b) ⇒ Object
Public: Use a constant-time comparison algorithm to reduce side-channel attacks.
-
.decrypt(binary, key, iv) ⇒ Object
Public: Decrypt buffer with the given key and initialization vector.
-
.derive_receiver_hmac(master_key) ⇒ Object
Public: Generate the authentication key for messages originating from the channel’s Receiver side.
-
.derive_receiver_key(master_key) ⇒ Object
Public: Generate the encryption key for messages originating from the channel’s Receiver side.
-
.derive_sender_hmac(master_key) ⇒ Object
Public: Generate the authentication key for messages originating from the channel’s Sender side.
-
.derive_sender_key(master_key) ⇒ Object
Public: Generate the encryption key for messages originating from the channel’s Sender side.
-
.deserialize(binary) ⇒ Object
Public: Turn a binary representation into a Ruby object suitable for use in application logic.
-
.encrypt(binary, key) ⇒ Object
Public: Encrypt buffer with the given key.
-
.identify(binary) ⇒ Object
Public: Create a short identifier for potentially sensitive data.
-
.mac(binary, hmac_key) ⇒ Object
Public: Create a message authentication code for the given data.
-
.nonce ⇒ Object
Public: Provide 16 securely random bytes.
-
.serialize(object) ⇒ Object
Public: Turn a JSON-like object into a binary representation suitable for use in crypto functions.
-
.stringify(binary) ⇒ Object
Public: Turn a binary buffer into a websafe string.
-
.zero(*args) ⇒ Object
Public: Overwrite the contents of the buffer with zeroes.
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 |
.nonce ⇒ Object
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 |