class MasterCrypt
Constants
- VERSION
Public Class Methods
Decrypts encrypted data with a provided secret key
@param encrypted_data [String] Base64 representation of encrypted data @param secret_key [String] Secret key to be used to decrypt data
@return [String] Decrypted plaintext data
@raise [MasterCrypt::CryptoError] When secret key or encrypted data is invalid
# File lib/master_crypt.rb, line 88 def decrypt(encrypted_data, secret_key) encrypted_data64, encrypted_random_keys64_joined = Base64.strict_decode64(encrypted_data).split("|", 2) encrypted_random_keys64 = encrypted_random_keys64_joined.split(":") key = find_key(encrypted_random_keys64, secret_key) box = RbNaCl::SimpleBox.from_secret_key(key) ciphertext = Base64.strict_decode64(encrypted_data64) box.decrypt(ciphertext).force_encoding(Encoding::UTF_8) rescue RbNaCl::CryptoError => e raise CryptoError, e.message end
Encrypts plaintext data with a list of secret keys
@param plaintext [String] Plaintext data to be encrypted @param secret_keys [Array<String>] A list of secret keys to be used for encrypting data
@return [String] Base64 representation of encrypted data
@raise [ArgumentError] When secret keys are missing or blank
# File lib/master_crypt.rb, line 54 def encrypt(plaintext, secret_keys) raise ArgumentError, "At least 1 secret key is required" if !secret_keys.is_a?(Array) || secret_keys.empty? raise ArgumentError, "Secret keys must not be blank" unless secret_keys.select(&:empty?).empty? # there's no point in using the same key multiple times secret_keys.uniq! random_key = RbNaCl::Random.random_bytes(RbNaCl::SecretBox.key_bytes) # encrypt data with random_key box = RbNaCl::SimpleBox.from_secret_key(random_key) encrypted_data = box.encrypt(plaintext) encrypted_data64 = Base64.strict_encode64(encrypted_data) # encrypt random_kets with each secret encrypted_random_keys64 = secret_keys.collect do |secret| key = generate_key_from_secret(secret) box = RbNaCl::SimpleBox.from_secret_key(key) encrypted_random_key = box.encrypt(random_key) encrypted_random_key64 = Base64.strict_encode64(encrypted_random_key) encrypted_random_key64 end # encrypted_data|encrypted_random_key1:encrypted_random_key2:... Base64.strict_encode64(encrypted_data64 + "|" + encrypted_random_keys64.join(":")) end
Create a new MasterCrypt
object with a master key which is used in `master_key_encrypt` and `master_key_decrypt`
@param [String] Master key
@return [MasterCrypt] A MasterCrypt
object with a stored master key
# File lib/master_crypt.rb, line 15 def initialize(master_key) raise ArgumentError, "Master key must not be blank" if master_key.nil? || master_key.empty? @master_key = master_key end
Private Class Methods
# File lib/master_crypt.rb, line 104 def find_key(encrypted_random_keys64, secret) secret_key = generate_key_from_secret(secret) box = RbNaCl::SimpleBox.from_secret_key(secret_key) encrypted_random_keys64.each do |encrypted_random_key64| encrypted_random_key = Base64.strict_decode64(encrypted_random_key64) begin random_key = box.decrypt(encrypted_random_key) return random_key rescue RbNaCl::CryptoError end end raise CryptoError, "Invalid secret key '#{secret}'" end
# File lib/master_crypt.rb, line 119 def generate_key_from_secret(secret) Digest::SHA2.hexdigest(secret)[0...32].force_encoding(Encoding::BINARY) end
Public Instance Methods
Decrypts encrypted data with the master key
@param encrypted_data [String] Base64 representation of encrypted data
@return [String] Decrypted plaintext data
@raise [MasterCrypt::CryptoError] When master key or encrypted data is invalid
# File lib/master_crypt.rb, line 41 def master_key_decrypt(encrypted_data) self.class.decrypt(encrypted_data, @master_key) end
Encrypts plaintext data with the master key and an optional list of additional secret keys
@param plaintext [String] Plaintext data to be encrypted @param secret_keys [Array<String>] Optional list of additional secret keys to be used for encrypting data
@return [String] Base64 representation of encrypted data
@raise [ArgumentError] When secret keys are missing or blank
# File lib/master_crypt.rb, line 30 def master_key_encrypt(plaintext, secret_keys = []) self.class.encrypt(plaintext, [@master_key] + Array(secret_keys)) end