Class: Quonfig::Encryption

Inherits:
Object
  • Object
show all
Defined in:
lib/quonfig/encryption.rb

Constant Summary collapse

CIPHER_TYPE =

32/12

'aes-256-gcm'
SEPARATOR =
'--'
AUTH_TAG_LENGTH =
16

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(key_string_hex) ⇒ Encryption

Returns a new instance of Encryption.



18
19
20
# File 'lib/quonfig/encryption.rb', line 18

def initialize(key_string_hex)
  @key = [key_string_hex].pack('H*')
end

Class Method Details

.generate_new_hex_keyObject

Hexadecimal format ensures that generated keys are representable with plain text

To convert back to the original string with the desired length:

[ value ].pack("H*")


14
15
16
# File 'lib/quonfig/encryption.rb', line 14

def self.generate_new_hex_key
  generate_random_key.unpack1('H*')
end

.generate_random_keyObject



62
63
64
# File 'lib/quonfig/encryption.rb', line 62

def self.generate_random_key
  SecureRandom.random_bytes(key_length)
end

.key_lengthObject



66
67
68
# File 'lib/quonfig/encryption.rb', line 66

def self.key_length
  OpenSSL::Cipher.new(CIPHER_TYPE).key_len
end

Instance Method Details

#decrypt(encrypted_string) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/quonfig/encryption.rb', line 41

def decrypt(encrypted_string)
  encrypted_data, iv, auth_tag = encrypted_string.split(SEPARATOR).map { |p| [p].pack('H*') }

  # Currently the OpenSSL bindings do not raise an error if auth_tag is
  # truncated, which would allow an attacker to easily forge it. See
  # https://github.com/ruby/openssl/issues/63
  raise 'truncated auth_tag' if auth_tag.bytesize != AUTH_TAG_LENGTH

  cipher = OpenSSL::Cipher.new(CIPHER_TYPE)
  cipher.decrypt
  cipher.key = @key
  cipher.iv = iv

  cipher.auth_tag = auth_tag

  # and decrypt it
  decrypted = cipher.update(encrypted_data)
  decrypted << cipher.final
  decrypted
end

#encrypt(clear_text) ⇒ Object



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/quonfig/encryption.rb', line 22

def encrypt(clear_text)
  cipher = OpenSSL::Cipher.new(CIPHER_TYPE)
  cipher.encrypt
  iv = cipher.random_iv

  # load them into the cipher
  cipher.key = @key
  cipher.iv = iv
  cipher.auth_data = ''

  # encrypt the message
  encrypted = cipher.update(clear_text)
  encrypted << cipher.final
  tag = cipher.auth_tag

  # pack and join
  [encrypted, iv, tag].map { |p| p.unpack1('H*') }.join(SEPARATOR)
end