Module: Legion::Crypt::Cipher

Included in:
Legion::Crypt
Defined in:
lib/legion/crypt/cipher.rb

Instance Method Summary collapse

Instance Method Details

#csObject



50
51
52
# File 'lib/legion/crypt/cipher.rb', line 50

def cs
  @cs ||= Digest::SHA256.digest(fetch_cs)
end

#decrypt(message, iv) ⇒ Object



14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/legion/crypt/cipher.rb', line 14

def decrypt(message, iv)
  until cs.is_a?(String) || Legion::Settings[:client][:shutting_down]
    Legion::Logging.debug('sleeping Legion::Crypt.decrypt due to CS not being set')
    sleep(0.5)
  end

  decipher = OpenSSL::Cipher.new('aes-256-cbc')
  decipher.decrypt
  decipher.key = cs
  decipher.iv = Base64.decode64(iv)
  message = Base64.decode64(message)
  decipher.update(message) + decipher.final
end

#decrypt_from_keypair(message:, **_opts) ⇒ Object



34
35
36
# File 'lib/legion/crypt/cipher.rb', line 34

def decrypt_from_keypair(message:, **_opts)
  private_key.private_decrypt(Base64.decode64(message))
end

#encrypt(message) ⇒ Object



6
7
8
9
10
11
12
# File 'lib/legion/crypt/cipher.rb', line 6

def encrypt(message)
  cipher = OpenSSL::Cipher.new('aes-256-cbc')
  cipher.encrypt
  cipher.key = cs
  iv = cipher.random_iv
  { enciphered_message: Base64.encode64(cipher.update(message) + cipher.final), iv: Base64.encode64(iv) }
end

#encrypt_from_keypair(message:, pub_key: public_key) ⇒ Object



28
29
30
31
32
# File 'lib/legion/crypt/cipher.rb', line 28

def encrypt_from_keypair(message:, pub_key: public_key)
  rsa_public_key = OpenSSL::PKey::RSA.new(pub_key)

  Base64.encode64(rsa_public_key.public_encrypt(message))
end

#fetch_csObject

rubocop:disable Metrics/AbcSize,Metrics/PerceivedComplexity,Metrics/CyclomaticComplexity



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/legion/crypt/cipher.rb', line 54

def fetch_cs # rubocop:disable Metrics/AbcSize,Metrics/PerceivedComplexity,Metrics/CyclomaticComplexity
  if Legion::Settings[:crypt][:vault][:read_cluster_secret] && Legion::Settings[:crypt][:vault][:connected] && Legion::Crypt.exist?('crypt') # rubocop:disable Layout/LineLength
    Legion::Crypt.get('crypt')[:cluster_secret]
  elsif Legion::Settings[:crypt][:cluster_secret].is_a? String
    Legion::Settings[:crypt][:cluster_secret]
  elsif Legion::Transport::Queue.new('node.crypt', passive: true).consumer_count.zero?
    Legion::Settings[:crypt][:cluster_secret] = generate_secure_random
  elsif Legion::Transport::Queue.new('node.crypt', passive: true).consumer_count.positive?
    require 'legion/transport/messages/request_cluster_secret'
    Legion::Logging.info 'Requesting cluster secret via public key'
    start = Time.now
    Legion::Transport::Messages::RequestClusterSecret.new.publish
    sleep_time = 0.001
    until !Legion::Settings[:crypt][:cluster_secret].nil? || (Time.now - start) > Legion::Settings[:crypt][:cluster_secret_timeout]
      sleep(sleep_time)
      sleep_time *= 2 unless sleep_time > 0.5
    end

    if Legion::Settings[:crypt][:cluster_secret].nil?
      Legion::Logging.warn 'Cluster secret is still nil'
    else
      Legion::Logging.info "Received cluster secret in #{((Time.new - start) * 1000.0).round}ms"
    end
  end
rescue StandardError => e
  Legion::Logging.error(e.message)
  Legion::Logging.error(e.backtrace)
ensure
  Legion::Settings[:crypt][:cluster_secret] = generate_secure_random unless Legion::Settings[:crypt].key? :cluster_secret
  nil if Legion::Settings[:crypt][:cluster_secret].nil?

  Legion::Settings[:crypt][:cs_encrypt_ready] = true
  push_cs_to_vault if Legion::Settings[:crypt][:vault][:push_cs_to_vault]

  return Legion::Settings[:crypt][:cluster_secret] # rubocop:disable Lint/EnsureReturn
end

#generate_secure_randomObject



98
99
100
# File 'lib/legion/crypt/cipher.rb', line 98

def generate_secure_random
  SecureRandom.uuid
end

#private_keyObject



42
43
44
45
46
47
48
# File 'lib/legion/crypt/cipher.rb', line 42

def private_key
  @private_key ||= if Legion::Settings[:crypt][:read_private_key] && File.exist?('./legionio.key')
                     OpenSSL::PKey::RSA.new File.read './legionio.key'
                   else
                     OpenSSL::PKey::RSA.new 2048
                   end
end

#public_keyObject



38
39
40
# File 'lib/legion/crypt/cipher.rb', line 38

def public_key
  @public_key ||= private_key.public_key.to_s
end

#push_cs_to_vaultObject



91
92
93
94
95
96
# File 'lib/legion/crypt/cipher.rb', line 91

def push_cs_to_vault
  return false unless Legion::Settings[:crypt][:vault][:connected] && Legion::Settings[:crypt][:cluster_secret]

  Legion::Logging.info 'Pushing Cluster Secret to Vault'
  Legion::Crypt.write('cluster', secret: Legion::Settings[:crypt][:cluster_secret])
end