Class: SafeDb::ToolBelt::CryptIO

Inherits:
Object
  • Object
show all
Defined in:
lib/utils/ciphers/crypt.io.rb

Overview

CryptIO concentrates on injecting and ingesting crypt properties into and out of a key/value dictionary as well as injecting and ingesting cryptographic materials into and out of text files.

Cryptographic Properties

A crypt properties dictionary acts as output from every encryption event and input to every decryption event. The most common properties include

  • the symmetric key used for the encryption and decryption

  • the iv (initialization vector) that adds another dimension of strength

  • authorization data that thwarts switch attacks by tying context to content

  • the cipher algorithm, its implementation and its encryption strength

  • the various glue strings that allow related ciphertext to occupy a file

Why Pad?

Many ciphers (like Blowfish) constrains plain text lengths to multiples of 8 (or 16) and a common right pad with spaces strategy is employed as a workaround. safe does it diferently.

Why isn’t Space Padding Used?

If safe padded plaintext (ending in one or more spaces) with spaces, the decrypt phase (after right stripping spaces) would return plain text string shorter than the original.

Why Unusual Padding and Separators

Why does safe employ unusual strings for padding and separation.

The separator string must be unusual to make it unlikely for it to occur in any of the map’s key value pairs nor indeed the chunk of text being glued. Were this to happen, the separate and reconstitute phase may not accurately return the same two entities we are employed to unite.

So How is Padding Done?

Instead of single space padding - safe uses an unlikely 7 character padder which is repeated until the multiple is reached.

<-|@|->

So How is Padding Done?

The padder length must be a prime number or infinite loops could occur.

If the padder string is likely to occur in the plain text, another
padder (or strategy) should and could be employed.

Constant Summary collapse

TEXT_PADDER =

The safe text padder. See the class description for an analysis of the use of this type of padder.

"<-|@|->"
INNER_GLUE_STRING =

An unusual string that glues together an encryption dictionary and a chunk of base64 encoded and encrypted ciphertext. The string must be unusual enough to ensure it does not occur within the dictionary metadata keys or values.

"\n<-|@| <  || safe inner crypt material axis ||  > |@|->\n\n"
OUTER_GLUE_STRING =

An unusual string that glues together the asymmetrically encrypted outer encryption key with the outer crypted text.

"\n<-|@| <  || safe outer crypt material axis ||  > |@|->\n\n"
DICT_HEADER_NAME =

Text header for key-value pairs hash map that will be serialized.

"crypt.properties"
DICT_CIPHER_NAME =

Name for the class of cipher employed.

"cipher.class"
DICT_CRYPT_KEY =

Name for the Base64 encoded symmetric (lock/unlock) crypt key.

"encryption.key"
DICT_CRYPT_IV =

Dictionary name for the encryption iv (initialization vector)

"encryption.iv"
DICT_TEXT_DIGEST =

Dictionary name for the Base64 (urlsafe) encoded plaintext digest.

"plaintext.digest"

Class Method Summary collapse

Class Method Details

.inner_crypt_deserialize(hash_map, text_block) ⇒ String

Deserialize an safe formatted text which contains an encryption properties dictionary (serialized in INI format) and a Base64 encoded crypt block which is the subject of the encryption dictionary.

The crypt serialization used a specific “inner glue” as the string that separates the serialized key/value dictionary and the encoded textual block. We now employ this glue to split the serialized dictionary from the textual block.

Parameters:

  • hash_map (String)

    send an instantiated hash (dictionary) which will be populated by this deserialize operation. The dictionary propeties can then be used to decrypt the returned ciphertext.

  • text_block (String)

    the first of a two-part amalgamation is a hash (dictionary) in INI serialized form and the second part is a Base64 encrypted textual block.

    The deserialized key/value pairs will be stuffed into the non nil (usually empty) hash map in the first parameter and the block (in the 2nd part) will be Base64 decoded and returned by this method.

Returns:

  • (String)

    The encoded block in the 2nd part of the 2nd parameter will be Base64 decoded and returned.

Raises:

  • (ArgumentError)

    if the dictionary hash_map is either nil or empty. Also if the inner glue tying the two parts together is missing an ArgumentError will be thrown.



155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/utils/ciphers/crypt.io.rb', line 155

def self.inner_crypt_deserialize hash_map, text_block

  raise ArgumentError, "Cannot populate a nil hash map." if hash_map.nil?
  assert_contains_glue text_block, INNER_GLUE_STRING

  serialized_map = text_block.split(INNER_GLUE_STRING).first.strip
  encoded64_text = text_block.split(INNER_GLUE_STRING).last.strip
  ini_props_hash = IniFile.new( :content => serialized_map )
  encrypt_values = ini_props_hash[DICT_HEADER_NAME]

  hash_map.merge!( encrypt_values )
  return Base64.decode64( encoded64_text )

end

.inner_crypt_serialize(hash_map, text_chunk) ⇒ String

Serialize and then unify a hash map and a textual chunk using a known but unusual separator string in a manner that protects content integrity during the serialize / deserialize process.

This crypt serialization uses a specific “inner glue” as the string that separates the serialized key/value dictionary and the encoded textual block.

Parameters:

  • hash_map (String)

    this hash (dictionary) will be serialized into INI formatted text using behaviour from Hash and IniFile.

  • text_chunk (String)

    the usually Base64 encrypted textual block to be glued at the bottom of the returned block.

Returns:

  • (String)

    serialized and glued together result of map plus text

Raises:

  • (ArgumentError)

    if the dictionary hash_map is either nil or empty.



111
112
113
114
115
116
117
118
119
# File 'lib/utils/ciphers/crypt.io.rb', line 111

def self.inner_crypt_serialize hash_map, text_chunk

  nil_or_empty_hash = hash_map.nil? || hash_map.empty?
  raise ArgumentError, "Cannot serialize nil or empty properties." if nil_or_empty_hash
  ini_map = IniFile.new
  ini_map[ DICT_HEADER_NAME ] = hash_map
  return ini_map.to_s + INNER_GLUE_STRING + text_chunk

end

.outer_crypt_deserialize(os_material, top_block) ⇒ String

Given two blocks of text that were bounded together by the selfself.outer_crypt_serialize method we must return either the first block (true) or the second (false).

Parameters:

  • crypt_material (String)

    large block of text in two parts that is divided by the outer glue string.

  • top_block (Boolean)

    if true the top (of the two) blocks will be returned otherwise the bottom block is returned.

Returns:

  • (String)

    either the first or second block of text

Raises:

  • (ArgumentError)

    If the outer glue string tying the two parts together is missing an ArgumentError will be thrown.



200
201
202
203
204
205
206
# File 'lib/utils/ciphers/crypt.io.rb', line 200

def self.outer_crypt_deserialize os_material, top_block

  assert_contains_glue os_material, OUTER_GLUE_STRING
  return os_material.split(OUTER_GLUE_STRING).first.strip if top_block
  return os_material.split(OUTER_GLUE_STRING).last.strip

end

.outer_crypt_serialize(crypt_material_x, crypt_material_y) ⇒ String

Using an outer divider (glue) - attach the asymmetrically encrypted outer encryption key with the outer encrypted text.

Parameters:

  • crypt_material_x (String)

    asymmetrically encrypted (encoded) outer encryption key

  • crypt_material_y (String)

    symmetrically encrypted inner metadata and payload crypt

Returns:

  • (String)

    concatenated result of the two crypt materials and divider string



178
179
180
# File 'lib/utils/ciphers/crypt.io.rb', line 178

def self.outer_crypt_serialize crypt_material_x, crypt_material_y
  return crypt_material_x + OUTER_GLUE_STRING + crypt_material_y
end