Class: Keyring::Encryptor::AES::Base

Inherits:
Object
  • Object
show all
Defined in:
lib/keyring/encryptor/aes.rb

Direct Known Subclasses

AES128CBC, AES192CBC, AES256CBC

Class Method Summary collapse

Class Method Details

.build_cipherObject



7
8
9
# File 'lib/keyring/encryptor/aes.rb', line 7

def self.build_cipher
  OpenSSL::Cipher.new(cipher_name)
end

.decrypt(key, message) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/keyring/encryptor/aes.rb', line 27

def self.decrypt(key, message)
  cipher = build_cipher
  cipher.decrypt

  message = Base64.strict_decode64(message)

  hmac = message[0...32]
  encrypted_payload = message[32..-1]
  iv = encrypted_payload[0...16]
  encrypted = encrypted_payload[16..-1]

  expected_hmac = hmac_digest(key.signing_key, encrypted_payload)

  unless verify_signature(expected_hmac, hmac)
    raise InvalidAuthentication, "Expected HMAC to be #{Base64.strict_encode64(expected_hmac)}; got #{Base64.strict_encode64(hmac)} instead" # rubocop:disable Layout/LineLength
  end

  cipher.iv = iv
  cipher.key = key.encryption_key
  cipher.update(encrypted) + cipher.final
end

.encrypt(key, message) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
# File 'lib/keyring/encryptor/aes.rb', line 15

def self.encrypt(key, message)
  cipher = build_cipher
  cipher.encrypt
  iv = cipher.random_iv
  cipher.iv  = iv
  cipher.key = key.encryption_key
  encrypted = cipher.update(message) + cipher.final
  hmac = hmac_digest(key.signing_key, "#{iv}#{encrypted}")

  Base64.strict_encode64("#{hmac}#{iv}#{encrypted}")
end

.hmac_digest(key, bytes) ⇒ Object



49
50
51
# File 'lib/keyring/encryptor/aes.rb', line 49

def self.hmac_digest(key, bytes)
  OpenSSL::HMAC.digest("sha256", key, bytes)
end

.key_sizeObject



11
12
13
# File 'lib/keyring/encryptor/aes.rb', line 11

def self.key_size
  @key_size ||= build_cipher.key_len
end

.verify_signature(expected, actual) ⇒ Object



53
54
55
56
57
58
59
60
# File 'lib/keyring/encryptor/aes.rb', line 53

def self.verify_signature(expected, actual)
  expected_bytes = expected.bytes.to_a
  actual_bytes = actual.bytes.to_a

  actual_bytes.inject(0) do |accum, byte|
    accum | byte ^ expected_bytes.shift
  end.zero?
end