class Donjon::EncryptedFile

Constants

PADDING

random bytes added to the data to encrypt to obfuscate it

Public Class Methods

new(path:, actor:) click to toggle source
# File lib/donjon/encrypted_file.rb, line 8
def initialize(path:, actor:)
  @path = path
  @actor = actor
end

Public Instance Methods

exist?() click to toggle source
# File lib/donjon/encrypted_file.rb, line 13
def exist?
  _base_path.exist?
end
read() click to toggle source
# File lib/donjon/encrypted_file.rb, line 21
def read
  path = _path_for(@actor)
  exist? or raise 'file does not exist'
  path.exist? or raise 'you were not granted access'
  data = path.binread
  _decrypt_from(@actor, data)
end
readable?() click to toggle source
# File lib/donjon/encrypted_file.rb, line 17
def readable?
  _path_for(@actor).exist?
end
write(data) click to toggle source
# File lib/donjon/encrypted_file.rb, line 29
def write(data)
  if data.nil?
    _base_path.rmtree if exist?
    return
  end

  User.each(@actor.repo) do |user|
    payload = _encrypt_for(user, data)
    path = _path_for(user)
    path.parent.mkpath
    path.binwrite(payload)
  end
end

Private Instance Methods

_base_path() click to toggle source
# File lib/donjon/encrypted_file.rb, line 88
def _base_path
  @actor.repo.join(@path)
end
_decrypt_from(user, data) click to toggle source
# File lib/donjon/encrypted_file.rb, line 56
def _decrypt_from(user, data)
  encrypted_key  = data[0...256]
  encrypted_data = data[256..-1]

  decrypted_pw = user.key.private_decrypt(encrypted_key)

  assert(decrypted_pw.size == 32)
  payload = Gibberish::AES::CBC.new(decrypted_pw).decrypt(encrypted_data, binary: true)
  encoding = payload[0...32].strip
  payload[32...-PADDING].force_encoding(encoding)
end
_encrypt_for(user, data) click to toggle source
# File lib/donjon/encrypted_file.rb, line 68
def _encrypt_for(user, data)
  encoding = data.encoding
  data = data.dup.force_encoding(Encoding::BINARY)

  encoding_field = ("%-32s" % encoding).force_encoding(Encoding::BINARY)
  payload = encoding_field + data + OpenSSL::Random.random_bytes(PADDING)
  password = OpenSSL::Random.random_bytes(32)
  encrypted_data = Gibberish::AES::CBC.new(password).encrypt(payload, binary: true)

  encrypted_key = user.key.public_encrypt(password)

  assert(encrypted_key.size == 256)
  encrypted_key + encrypted_data
end
_log_key(message, key) click to toggle source
# File lib/donjon/encrypted_file.rb, line 83
def _log_key(message, key)
  puts "#{message}: #{key.bytesize} bytes"
  puts key.bytes.map { |b| "%02x" % b }.join(":")
end
_path_for(user) click to toggle source
# File lib/donjon/encrypted_file.rb, line 92
def _path_for(user)
  _base_path.join("#{user.name}.db")
end