class Gitlab::License::Encryptor

Attributes

key[RW]

Public Class Methods

new(key) click to toggle source
# File lib/gitlab/license/encryptor.rb, line 10
def initialize(key)
  raise KeyError, 'No RSA encryption key provided.' if key && !key.is_a?(OpenSSL::PKey::RSA)

  @key = key
end

Public Instance Methods

decrypt(data) click to toggle source
# File lib/gitlab/license/encryptor.rb, line 40
def decrypt(data)
  raise KeyError, 'Provided key is not a public key.' unless key.public?

  json_data = Base64.decode64(data.chomp)

  begin
    encryption_data = JSON.parse(json_data)
  rescue JSON::ParserError
    raise DecryptionError, 'Encryption data is invalid JSON.'
  end

  unless %w[data key iv].all? { |key| encryption_data[key] }
    raise DecryptionError, 'Required field missing from encryption data.'
  end

  encrypted_data  = Base64.decode64(encryption_data['data'])
  encrypted_key   = Base64.decode64(encryption_data['key'])
  aes_iv          = Base64.decode64(encryption_data['iv'])

  begin
    # Decrypt the AES key using asymmetric RSA encryption.
    aes_key = self.key.public_decrypt(encrypted_key)
  rescue OpenSSL::PKey::RSAError
    raise DecryptionError, 'AES encryption key could not be decrypted.'
  end

  # Decrypt the data using symmetric AES encryption.
  cipher = OpenSSL::Cipher::AES128.new(:CBC)
  cipher.decrypt

  begin
    cipher.key = aes_key
  rescue OpenSSL::Cipher::CipherError
    raise DecryptionError, 'AES encryption key is invalid.'
  end

  begin
    cipher.iv = aes_iv
  rescue OpenSSL::Cipher::CipherError
    raise DecryptionError, 'AES IV is invalid.'
  end

  begin
    data = cipher.update(encrypted_data) + cipher.final
  rescue OpenSSL::Cipher::CipherError
    raise DecryptionError, 'Data could not be decrypted.'
  end

  data
end
encrypt(data) click to toggle source
# File lib/gitlab/license/encryptor.rb, line 16
def encrypt(data)
  raise KeyError, 'Provided key is not a private key.' unless key.private?

  # Encrypt the data using symmetric AES encryption.
  cipher = OpenSSL::Cipher::AES128.new(:CBC)
  cipher.encrypt
  aes_key = cipher.random_key
  aes_iv  = cipher.random_iv

  encrypted_data = cipher.update(data) + cipher.final

  # Encrypt the AES key using asymmetric RSA encryption.
  encrypted_key = key.private_encrypt(aes_key)

  encryption_data = {
    'data' => Base64.encode64(encrypted_data),
    'key' => Base64.encode64(encrypted_key),
    'iv' => Base64.encode64(aes_iv)
  }

  json_data = JSON.dump(encryption_data)
  Base64.encode64(json_data)
end