Class: Fling::Box

Inherits:
Object
  • Object
show all
Defined in:
lib/fling/box.rb

Overview

Simple encryption with password-derived keys

Constant Summary collapse

SALT_SIZE =
32
FINGERPRINT_SIZE =
32
SCRYPT_OPSLIMIT =
2**25
SCRYPT_MEMLIMIT =
2**30

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(password, salt, options = {}) ⇒ Box

Returns a new instance of Box.



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/fling/box.rb', line 28

def initialize(password, salt, options = {})
  opts = {
    scrypt_opslimit: SCRYPT_OPSLIMIT,
    scrypt_memlimit: SCRYPT_MEMLIMIT
  }.merge(options)

  @key = RbNaCl::PasswordHash.scrypt(
    password.force_encoding("BINARY"),
    salt.force_encoding("BINARY"),
    opts[:scrypt_opslimit],
    opts[:scrypt_memlimit],
    RbNaCl::SecretBox::KEYBYTES
  )

  @fingerprint = Encoding.encode(RbNaCl::Hash.blake2b(@key, digest_size: FINGERPRINT_SIZE))
end

Instance Attribute Details

#fingerprintObject (readonly)

Returns the value of attribute fingerprint.



7
8
9
# File 'lib/fling/box.rb', line 7

def fingerprint
  @fingerprint
end

#keyObject (readonly)

Returns the value of attribute key.



7
8
9
# File 'lib/fling/box.rb', line 7

def key
  @key
end

Class Method Details

.decrypt(password, ciphertext, options = {}) ⇒ Object



21
22
23
24
25
26
# File 'lib/fling/box.rb', line 21

def self.decrypt(password, ciphertext, options = {})
  salt = ciphertext[0, SALT_SIZE]
  ciphertext = ciphertext[SALT_SIZE, ciphertext.length - SALT_SIZE]
  box = new(password, salt, options)
  box.decrypt(ciphertext)
end

.encrypt(password, plaintext, options = {}) ⇒ Object



15
16
17
18
19
# File 'lib/fling/box.rb', line 15

def self.encrypt(password, plaintext, options = {})
  salt = RbNaCl::Random.random_bytes(SALT_SIZE)
  box = new(password, salt, options)
  salt + box.encrypt(plaintext)
end

Instance Method Details

#decrypt(ciphertext) ⇒ Object



57
58
59
60
# File 'lib/fling/box.rb', line 57

def decrypt(ciphertext)
  json = encryption_box.decrypt(ciphertext.force_encoding("BINARY"))
  JSON.parse(json)
end

#encrypt(data = {}) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
# File 'lib/fling/box.rb', line 45

def encrypt(data = {})
  # Ensure data is a simple flat hash of strings
  data = data.map do |key, value|
    fail TypeError, "bad key: #{key.inspect}" unless key.is_a?(String) || key.is_a?(Symbol)
    fail TypeError, "bad value: #{value.inspect}" unless value.is_a?(String)
    [key.to_s, value]
  end.flatten

  json = JSON.generate(Hash[*data])
  encryption_box.encrypt(json.force_encoding("BINARY"))
end