Class: Darrrr::EncryptedData

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/darrrr/cryptors/default/encrypted_data.rb

Constant Summary collapse

CIPHER_OPTIONS =
[:encrypt, :decrypt].freeze
CIPHER =
"aes-256-gcm".freeze
CIPHER_VERSION =
0
IV_LENGTH =
12
AUTH_TAG_LENGTH =
16
PROTOCOL_VERSION =
0

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(token_object) ⇒ EncryptedData

token_object: an EncryptedDataIO instance instance.

Raises:



21
22
23
24
25
26
# File 'lib/darrrr/cryptors/default/encrypted_data.rb', line 21

def initialize(token_object)
  raise TokenFormatError, "Version must be #{PROTOCOL_VERSION}. Supplied: #{token_object.version}" unless token_object.version == CIPHER_VERSION
  raise TokenFormatError, "Auth Tag must be 16 bytes" unless token_object.auth_tag.length == AUTH_TAG_LENGTH
  raise TokenFormatError, "IV must be 12 bytes" unless token_object.iv.length == IV_LENGTH
  @token_object = token_object
end

Instance Attribute Details

#token_objectObject (readonly)

Returns the value of attribute token_object.



14
15
16
# File 'lib/darrrr/cryptors/default/encrypted_data.rb', line 14

def token_object
  @token_object
end

Class Method Details

.build(data) ⇒ Object

data: the value to encrypt.

returns an EncryptedData instance.



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/darrrr/cryptors/default/encrypted_data.rb', line 43

def build(data)
  cipher = cipher(:encrypt)
  iv = SecureRandom.random_bytes(EncryptedData::IV_LENGTH)
  cipher.iv = iv
  cipher.auth_data = ""

  ciphertext = cipher.update(data.to_s) + cipher.final

  token = EncryptedDataIO.new.tap do |edata|
    edata.version = CIPHER_VERSION
    edata.auth_tag = cipher.auth_tag.bytes
    edata.iv = iv.bytes
    edata.ciphertext = ciphertext.bytes
  end

  new(token)
end

.cipher(mode) ⇒ Object

DRY helper for generating cipher objects



78
79
80
81
82
83
84
85
86
87
# File 'lib/darrrr/cryptors/default/encrypted_data.rb', line 78

def cipher(mode)
  unless CIPHER_OPTIONS.include?(mode)
    raise ArgumentError, "mode must be `encrypt` or `decrypt`"
  end

  OpenSSL::Cipher.new(EncryptedData::CIPHER).tap do |cipher|
    cipher.send(mode)
    cipher.key = [Darrrr..instance_variable_get(:@symmetric_key)].pack("H*")
  end
end

.parse(serialized_data) ⇒ Object

serialized_data: the binary representation of a token.

returns an EncryptedData instance.



64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/darrrr/cryptors/default/encrypted_data.rb', line 64

def parse(serialized_data)
  data = new(EncryptedDataIO.new.read(serialized_data))

  # be extra paranoid, oracles and stuff
  if data.num_bytes != serialized_data.bytesize
    raise CryptoError, "Encypted data field includes unexpected extra bytes"
  end

  data
rescue IOError => e
  raise RecoveryTokenSerializationError, e.message
end

Instance Method Details

#decryptObject



29
30
31
32
33
34
35
36
37
# File 'lib/darrrr/cryptors/default/encrypted_data.rb', line 29

def decrypt
  cipher = self.class.cipher(:decrypt)
  cipher.iv = self.iv.to_binary_s
  cipher.auth_tag = self.auth_tag.to_binary_s
  cipher.auth_data = ""
  cipher.update(self.ciphertext.to_binary_s) + cipher.final
rescue OpenSSL::Cipher::CipherError => e
  raise CryptoError, "Unable to decrypt data: #{e}"
end