Class: Chef::EncryptedDataBagItem::Encryptor::Version1Encryptor

Inherits:
Object
  • Object
show all
Includes:
Assertions
Defined in:
lib/chef/encrypted_data_bag_item/encryptor.rb

Direct Known Subclasses

Version2Encryptor, Version3Encryptor

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Assertions

#assert_aead_requirements_met!, #assert_format_version_acceptable!, #assert_requirements_met!, #assert_valid_cipher!

Constructor Details

#initialize(plaintext_data, key, iv = nil) ⇒ Version1Encryptor

Create a new Encryptor for +data+, which will be encrypted with the given +key+.

=== Arguments:

  • data: An object of any type that can be serialized to json
  • key: A String representing the desired passphrase
  • iv: The optional +iv+ parameter is intended for testing use only. When not supplied, Encryptor will use OpenSSL to generate a secure random IV, which is what you want.

68
69
70
71
72
# File 'lib/chef/encrypted_data_bag_item/encryptor.rb', line 68

def initialize(plaintext_data, key, iv = nil)
  @plaintext_data = plaintext_data
  @key = key
  @iv = iv && Base64.decode64(iv)
end

Instance Attribute Details

#keyObject (readonly)

Returns the value of attribute key


54
55
56
# File 'lib/chef/encrypted_data_bag_item/encryptor.rb', line 54

def key
  @key
end

#plaintext_dataObject (readonly)

Returns the value of attribute plaintext_data


55
56
57
# File 'lib/chef/encrypted_data_bag_item/encryptor.rb', line 55

def plaintext_data
  @plaintext_data
end

Class Method Details

.encryptor_keysObject


129
130
131
# File 'lib/chef/encrypted_data_bag_item/encryptor.rb', line 129

def self.encryptor_keys
  %w{ encrypted_data iv version cipher }
end

Instance Method Details

#algorithmObject

Returns the used encryption algorithm


75
76
77
# File 'lib/chef/encrypted_data_bag_item/encryptor.rb', line 75

def algorithm
  ALGORITHM
end

#encrypted_dataObject

Encrypts and Base64 encodes +serialized_data+


113
114
115
116
117
118
119
# File 'lib/chef/encrypted_data_bag_item/encryptor.rb', line 113

def encrypted_data
  @encrypted_data ||= begin
    enc_data = openssl_encryptor.update(serialized_data)
    enc_data << openssl_encryptor.final
    Base64.encode64(enc_data)
  end
end

#for_encrypted_itemObject

Returns a wrapped and encrypted version of +plaintext_data+ suitable for using as the value in an encrypted data bag item.


81
82
83
84
85
86
87
88
# File 'lib/chef/encrypted_data_bag_item/encryptor.rb', line 81

def for_encrypted_item
  {
    "encrypted_data" => encrypted_data,
    "iv" => Base64.encode64(iv),
    "version" => 1,
    "cipher" => algorithm,
  }
end

#ivObject

Generates or returns the IV.


91
92
93
94
95
96
# File 'lib/chef/encrypted_data_bag_item/encryptor.rb', line 91

def iv
  # Generated IV comes from OpenSSL::Cipher#random_iv
  # This gets generated when +openssl_encryptor+ gets created.
  openssl_encryptor if @iv.nil?
  @iv
end

#openssl_encryptorObject

Generates (and memoizes) an OpenSSL::Cipher object and configures it for the specified iv and encryption key.


100
101
102
103
104
105
106
107
108
109
110
# File 'lib/chef/encrypted_data_bag_item/encryptor.rb', line 100

def openssl_encryptor
  @openssl_encryptor ||= begin
    encryptor = OpenSSL::Cipher.new(algorithm)
    encryptor.encrypt
    # We must set key before iv: https://bugs.ruby-lang.org/issues/8221
    encryptor.key = OpenSSL::Digest::SHA256.digest(key)
    @iv ||= encryptor.random_iv
    encryptor.iv = @iv
    encryptor
  end
end

#serialized_dataObject

Wraps the data in a single key Hash (JSON Object) and converts to JSON. The wrapper is required because we accept values (such as Integers or Strings) that do not produce valid JSON when serialized without the wrapper.


125
126
127
# File 'lib/chef/encrypted_data_bag_item/encryptor.rb', line 125

def serialized_data
  FFI_Yajl::Encoder.encode(:json_wrapper => plaintext_data)
end