class EYAML::EncryptionManager

Constants

FORMAT_REGEX
FORMAT_VERSION

Public Class Methods

new(yaml, public_key, private_key = nil) click to toggle source
# File lib/eyaml/encryption_manager.rb, line 19
def initialize(yaml, public_key, private_key = nil)
  @tree = yaml
  @public_key = RbNaCl::Util.hex2bin(public_key)
  @private_key = private_key && RbNaCl::Util.hex2bin(private_key.strip)
end
new_keypair() click to toggle source
# File lib/eyaml/encryption_manager.rb, line 9
def new_keypair
  private_key = RbNaCl::PrivateKey.generate

  [
    RbNaCl::Util.bin2hex(private_key.public_key),
    RbNaCl::Util.bin2hex(private_key)
  ]
end

Public Instance Methods

decrypt() click to toggle source
# File lib/eyaml/encryption_manager.rb, line 25
def decrypt
  traverse(@tree) do |text|
    encrypted?(text) ? decrypt_text(text) : text
  end
end
encrypt() click to toggle source
# File lib/eyaml/encryption_manager.rb, line 31
def encrypt
  traverse(@tree) do |text|
    encrypted?(text) ? text : encrypt_text(text)
  end
end

Private Instance Methods

decrypt_text(ciphertext) click to toggle source
# File lib/eyaml/encryption_manager.rb, line 51
def decrypt_text(ciphertext)
  captures = ciphertext.match(FORMAT_REGEX).named_captures
  wire_version = captures.fetch("version")
  old_session_public_key = Base64.decode64(captures.fetch("session_public_key"))
  nonce = Base64.decode64(captures.fetch("nonce"))
  text = Base64.decode64(captures.fetch("text"))

  raise UnsupportedVersionError, "EYAML only supports version 1" unless wire_version == FORMAT_VERSION

  box = decryption_box(old_session_public_key)
  box.decrypt(nonce, text)
end
decryption_box(public_key_encrypted_with) click to toggle source
# File lib/eyaml/encryption_manager.rb, line 68
def decryption_box(public_key_encrypted_with)
  @decryption_box ||= {}
  @decryption_box[public_key_encrypted_with] ||= RbNaCl::Box.new(public_key_encrypted_with, @private_key)
end
encrypt_text(plaintext) click to toggle source
# File lib/eyaml/encryption_manager.rb, line 39
def encrypt_text(plaintext)
  nonce = RbNaCl::Random.random_bytes(encryption_box.nonce_bytes)
  ciphertext = encryption_box.encrypt(nonce, plaintext)

  [
    "EJ[#{FORMAT_VERSION}",
    Base64.strict_encode64(session_public_key),
    Base64.strict_encode64(nonce),
    "#{Base64.strict_encode64(ciphertext)}]"
  ].join(":")
end
encrypted?(text) click to toggle source
# File lib/eyaml/encryption_manager.rb, line 81
def encrypted?(text)
  FORMAT_REGEX.match?(text)
end
encryption_box() click to toggle source
# File lib/eyaml/encryption_manager.rb, line 64
def encryption_box
  @encryption_box ||= RbNaCl::Box.new(@public_key, session_private_key)
end
session_private_key() click to toggle source
# File lib/eyaml/encryption_manager.rb, line 73
def session_private_key
  @session_private_key ||= RbNaCl::PrivateKey.generate
end
session_public_key() click to toggle source
# File lib/eyaml/encryption_manager.rb, line 77
def session_public_key
  @session_public_key ||= session_private_key.public_key
end
traverse(tree, &block) click to toggle source
# File lib/eyaml/encryption_manager.rb, line 85
def traverse(tree, &block)
  tree.map do |key, value|
    if value.is_a?(Hash)
      next [key, traverse(value, &block)]
    end
    # TODO(es): Add tests for keys with an underscore prefix not doing a nested skip
    if key.start_with?("_")
      next [key, value]
    end

    [key, block.call(value)]
  end.to_h
end