Module: DoorMat::Crypto::SymmetricStore

Defined in:
lib/door_mat/crypto/symmetric_store.rb

Class Method Summary collapse

Class Method Details

.cipherObject



47
48
49
# File 'lib/door_mat/crypto/symmetric_store.rb', line 47

def cipher
  OpenSSL::Cipher.new('aes-256-gcm')
end

.decode_key(key) ⇒ Object



52
53
54
55
56
# File 'lib/door_mat/crypto/symmetric_store.rb', line 52

def decode_key(key)
  Base64.strict_decode64(key.to_str).tap do |decoded_key|
    raise ArgumentError, "Key must be exactly 32 bytes in length" if decoded_key.bytesize != 32
  end
end

.decrypt(ciphertext, key) ⇒ Object



33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/door_mat/crypto/symmetric_store.rb', line 33

def decrypt(ciphertext, key)
  return "" if ciphertext.to_str.blank?

  c = cipher()
  c.decrypt
  c.key = decode_key(key.to_str)
  encoding, auth_tag, iv, encrypted_string = ciphertext.to_str.split('--').map { |s| Base64.strict_decode64(s) }
  c.iv = iv
  c.auth_tag = auth_tag
  plaintext_str = c.update(encrypted_string) + c.final
  plaintext_str.force_encoding(encoding)
end

.encrypt(plaintext, key = nil) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/door_mat/crypto/symmetric_store.rb', line 7

def encrypt(plaintext, key=nil)
  c = cipher()
  c.encrypt
  key = if key.nil?
          c.random_key
        else
          c.key = decode_key(key.to_str)
        end
  iv = c.random_iv
  plaintext_str = plaintext.to_str
  if plaintext_str.blank?
    return {
        key: Base64.strict_encode64(key),
        ciphertext: ""
    }
  end
  encrypted_string = c.update(plaintext_str) + c.final
  encoding = plaintext_str.encoding.name

  {
      key: Base64.strict_encode64(key),
      ciphertext: [encoding, c.auth_tag, iv, encrypted_string].map { |s| Base64.strict_encode64(s)}.join('--')
  }
end

.random_keyObject



59
60
61
62
63
# File 'lib/door_mat/crypto/symmetric_store.rb', line 59

def random_key
  c = cipher()
  c.encrypt
  Base64.strict_encode64(c.random_key)
end