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

Constructor Details

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

Class Method Details

.auth_tag_sizeObject



96
97
98
# File 'lib/familia/encryption/providers/aes_gcm_provider.rb', line 96

def self.auth_tag_size
  AUTH_TAG_SIZE
end

.available?Boolean

Returns:

  • (Boolean)


33
34
35
# File 'lib/familia/encryption/providers/aes_gcm_provider.rb', line 33

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

.nonce_sizeObject



92
93
94
# File 'lib/familia/encryption/providers/aes_gcm_provider.rb', line 92

def self.nonce_size
  NONCE_SIZE
end

.priorityObject



37
38
39
# File 'lib/familia/encryption/providers/aes_gcm_provider.rb', line 37

def self.priority
  50 # Fallback option
end

Instance Method Details

#algorithmObject



108
109
110
# File 'lib/familia/encryption/providers/aes_gcm_provider.rb', line 108

def algorithm
  ALGORITHM
end

#auth_tag_sizeObject



104
105
106
# File 'lib/familia/encryption/providers/aes_gcm_provider.rb', line 104

def auth_tag_size
  AUTH_TAG_SIZE
end

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



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

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



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

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



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

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



71
72
73
# File 'lib/familia/encryption/providers/aes_gcm_provider.rb', line 71

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

#nonce_sizeObject



100
101
102
# File 'lib/familia/encryption/providers/aes_gcm_provider.rb', line 100

def nonce_size
  NONCE_SIZE
end

#secure_wipe(key) ⇒ Object

Clear key from memory (no security guarantees in Ruby)



88
89
90
# File 'lib/familia/encryption/providers/aes_gcm_provider.rb', line 88

def secure_wipe(key)
  key&.clear
end