Class: SimplyAES::Cipher

Inherits:
Object
  • Object
show all
Defined in:
lib/simply-aes/cipher.rb,
lib/simply-aes/cipher/error.rb

Overview

See Also:

Defined Under Namespace

Classes: Error

Constant Summary collapse

LoadError =
Class.new(Error)
DumpError =
Class.new(Error)

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ Cipher #initialize(key, options) ⇒ Cipher

rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity

Overloads:

  • #initialize(key, options) ⇒ Cipher

    Parameters:

    • key (String)

      a 32-byte (256-bit) string If not provided, a secure random key will be generated

    • options (Hash{Symbol=>Object})

    Options Hash (options):

    • (:bytes) (Symbol, SimplyAES::Format)

      The format is used to load provided data, including the given key, and as a default encoder/decoder of encrypted data; this can be overridden in the #load and #dump methods.

    Raises:



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/simply-aes/cipher.rb', line 23

def initialize(*args)
  options = (args.last.is_a?(Hash) ? args.pop.dup : {})

  @format = Format[options.delete(:format) { :bytes }]

  # extract the given key, or securely generate one
  @key   = format.load(args.pop) unless args.empty?
  @key ||= native_cipher.random_key

  # validate initialisation
  fail(ArgumentError, 'invalid key length') unless @key.bytesize == 32
  fail(ArgumentError, 'wrong number of arguments') unless args.empty?
  fail(ArgumentError, "unknown options: #{options}") unless options.empty?
rescue => err
  raise Error, "failed to initialize #{self.class.name} (#{err})"
end

Instance Method Details

#dump(plaintext, options = {}) ⇒ Object Also known as: encrypt

Parameters:

  • plaintext (String)
  • options (Hash{Symbol=>Object}) (defaults to: {})

Options Hash (options):

  • :iv (String) — default: default: secure random iv

    up to 16 bytes, used as an initialisation vector

  • :format (Symbol) — default: default: self.format

Raises:

  • SimplyAES::Cipher::DumpError



55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/simply-aes/cipher.rb', line 55

def dump(plaintext, options = {})
  encipher = native_cipher(:encrypt)

  # ensure a 16-byte initialisation vector
  iv = options.fetch(:iv) { encipher.random_iv }
  fail(ArgumentError, 'iv must be 16 bytes') unless iv.bytesize == 16
  encipher.iv = iv

  ciphertext = encipher.update(plaintext) + encipher.final

  format(options).dump(iv + ciphertext)
rescue => err
  raise DumpError, err.message
end

#format(options = {}) ⇒ SimplyAES::Format

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:



102
103
104
# File 'lib/simply-aes/cipher.rb', line 102

def format(options = {})
  Format[options.fetch(:format) { @format }]
end

#inspectString

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (String)


96
97
98
# File 'lib/simply-aes/cipher.rb', line 96

def inspect
  "<#{self.class.name}:#{__id__}>"
end

#key(options = {}) ⇒ String

Returns formatted string.

Parameters:

  • options (Hash{Symbol=>Object}) (defaults to: {})

Options Hash (options):

  • :format (Symbol) — default: default: self.format

Returns:

  • (String)

    formatted string



44
45
46
# File 'lib/simply-aes/cipher.rb', line 44

def key(options = {})
  format(options).dump(@key.dup)
end

#load(iv_ciphertext, options = {}) ⇒ Object Also known as: decrypt

Parameters:

  • iv_ciphertext (String)
  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • :format (Symbol) — default: default: self.format

Raises:

  • SimplyAES::Cipher::LoadError



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/simply-aes/cipher.rb', line 75

def load(iv_ciphertext, options = {})
  @key || fail(ArgumentError, 'key not provided!')

  # if the IV is given as an argument, inject it to the ciphertext
  given_iv = options[:iv]
  given_iv && (iv_ciphertext = given_iv + iv_ciphertext)

  # shift the 16-byte initialisation vector from the front
  iv, ciphertext = format(options).load(iv_ciphertext).unpack('a16a*')

  decipher = native_cipher(:decrypt)
  decipher.iv = iv

  decipher.update(ciphertext) + decipher.final
rescue => err
  raise LoadError, err.message
end