Class: Familia::Encryption::Providers::AESGCMProvider

Inherits:
Familia::Encryption::Provider show all
Defined in:
lib/familia/encryption/providers/aes_gcm_provider.rb

Constant Summary collapse

ALGORITHM =
'aes-256-gcm'.freeze
NONCE_SIZE =
12
AUTH_TAG_SIZE =
16

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Familia::Encryption::Provider

#initialize

Constructor Details

This class inherits a constructor from Familia::Encryption::Provider

Class Method Details

.auth_tag_sizeObject



94
95
96
# File 'lib/familia/encryption/providers/aes_gcm_provider.rb', line 94

def self.auth_tag_size
  AUTH_TAG_SIZE
end

.available?Boolean

Returns:

  • (Boolean)


31
32
33
# File 'lib/familia/encryption/providers/aes_gcm_provider.rb', line 31

def self.available?
  true # OpenSSL is always available
end

.nonce_sizeObject



90
91
92
# File 'lib/familia/encryption/providers/aes_gcm_provider.rb', line 90

def self.nonce_size
  NONCE_SIZE
end

.priorityObject



35
36
37
# File 'lib/familia/encryption/providers/aes_gcm_provider.rb', line 35

def self.priority
  50 # Fallback option
end

Instance Method Details

#algorithmObject



106
107
108
# File 'lib/familia/encryption/providers/aes_gcm_provider.rb', line 106

def algorithm
  ALGORITHM
end

#auth_tag_sizeObject



102
103
104
# File 'lib/familia/encryption/providers/aes_gcm_provider.rb', line 102

def auth_tag_size
  AUTH_TAG_SIZE
end

#decrypt(ciphertext, key, nonce, auth_tag, additional_data = nil) ⇒ Object



56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/familia/encryption/providers/aes_gcm_provider.rb', line 56

def decrypt(ciphertext, key, nonce, auth_tag, additional_data = nil)
  validate_key_length!(key)
  cipher = create_cipher(:decrypt)
  cipher.key = key
  cipher.iv = nonce
  cipher.auth_tag = auth_tag
  cipher.auth_data = additional_data.to_s if additional_data

  cipher.update(ciphertext) + cipher.final
rescue OpenSSL::Cipher::CipherError
  raise EncryptionError, 'Decryption failed - invalid key or corrupted data'
end

#derive_key(master_key, context, personal: nil) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
# File 'lib/familia/encryption/providers/aes_gcm_provider.rb', line 73

def derive_key(master_key, context, personal: nil)
  validate_key_length!(master_key)
  info = personal ? "#{context}:#{personal}" : context
  OpenSSL::KDF.hkdf(
    master_key,
    salt: 'FamiliaEncryption',
    info: info,
    length: 32,
    hash: 'SHA256'
  )
end

#encrypt(plaintext, key, additional_data = nil) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/familia/encryption/providers/aes_gcm_provider.rb', line 39

def encrypt(plaintext, key, additional_data = nil)
  validate_key_length!(key)
  nonce = generate_nonce
  cipher = create_cipher(:encrypt)
  cipher.key = key
  cipher.iv = nonce
  cipher.auth_data = additional_data.to_s if additional_data

  ciphertext = cipher.update(plaintext.to_s) + cipher.final

  {
    ciphertext: ciphertext,
    auth_tag: cipher.auth_tag,
    nonce: nonce
  }
end

#generate_nonceObject



69
70
71
# File 'lib/familia/encryption/providers/aes_gcm_provider.rb', line 69

def generate_nonce
  OpenSSL::Random.random_bytes(NONCE_SIZE)
end

#nonce_sizeObject



98
99
100
# File 'lib/familia/encryption/providers/aes_gcm_provider.rb', line 98

def nonce_size
  NONCE_SIZE
end

#secure_wipe(key) ⇒ Object

Clear key from memory (no security guarantees in Ruby)



86
87
88
# File 'lib/familia/encryption/providers/aes_gcm_provider.rb', line 86

def secure_wipe(key)
  key&.clear
end