class SymmetricEncryption::Header
Defines the Header
Structure returned when parsing the header.
Note:
-
Header
only works against binary encrypted data that has not been decoded. -
Decode data first before trying to extract its header.
-
Decoding is not required when encoding is set to `:none`.
Constants
- FLAG_AUTH_TAG
- FLAG_CIPHER_NAME
- FLAG_COMPRESSED
- FLAG_IV
- FLAG_KEY
- MAGIC_HEADER
Encrypted data includes this header prior to encoding when `always_add_header` is true.
- MAGIC_HEADER_SIZE
Attributes
- String
-
Binary auth tag used to encrypt the data.
Usually 16 bytes. Present when using an authenticated encryption mode.
- String
-
Name of the cipher used.
- true|false
-
Whether to compress the data before encryption.
If supplied in the header.
- String
-
IV used to encrypt the data.
If supplied in the header.
- String
-
Key
used to encrypt the data.
If supplied in the header.
- Integer
-
Version of the cipher used.
Public Class Methods
Returns a magic header for this cipher instance that can be placed at the beginning of a file or stream to indicate how the data was encrypted
Parameters
compress [true|false] Whether the data should be compressed before encryption. Default: false iv [String] The iv to to put in the header Default: nil : Exclude from header key [String] The key to to put in the header. The key is encrypted using the global encryption key Default: nil : Exclude key from header version: [Integer (0..255)] Version of the global cipher used to encrypt the data, or the encryption key if supplied. default: The current global encryption cipher version. cipher_name [String] The cipher_name to be used for encrypting the data portion. For example 'aes-256-cbc' `key` if supplied is encrypted with the cipher name based on the cipher version in this header. Intended for use when encrypting large files with a different cipher to the global one. Default: nil : Exclude cipher_name name from header
# File lib/symmetric_encryption/header.rb, line 74 def initialize(version: SymmetricEncryption.cipher.version, compress: false, iv: nil, key: nil, cipher_name: nil, auth_tag: nil) @version = version @compress = compress @iv = iv @key = key @cipher_name = cipher_name @auth_tag = auth_tag end
Returns whether the supplied buffer starts with a symmetric_encryption header Note: The encoding of the supplied buffer is forced to binary if not already binary
# File lib/symmetric_encryption/header.rb, line 39 def self.present?(buffer) return false if buffer.nil? || (buffer == "") buffer.force_encoding(SymmetricEncryption::BINARY_ENCODING) buffer.start_with?(MAGIC_HEADER) end
Public Instance Methods
Returns [SymmetricEncryption::Cipher] the cipher used to decrypt or encrypt the key specified in this header, if supplied.
# File lib/symmetric_encryption/header.rb, line 91 def cipher @cipher ||= SymmetricEncryption.cipher(version) end
# File lib/symmetric_encryption/header.rb, line 100 def compressed? @compress end
Returns [Integer] the offset within the buffer of the data after the header has been read.
Returns 0 if no header is present
# File lib/symmetric_encryption/header.rb, line 124 def parse(buffer, offset = 0) return 0 if buffer.nil? || (buffer == "") || (buffer.length <= MAGIC_HEADER_SIZE + 2) # Symmetric Encryption Header # # Consists of: # 4 Bytes: Magic Header Prefix: @Enc # 1 Byte: The version of the cipher used to encrypt the header. # 1 Byte: Flags: # Bit 1: Whether the data is compressed # Bit 2: Whether the IV is included # Bit 3: Whether the Key is included # Bit 4: Whether the Cipher Name is included # Bit 5: Future use # Bit 6: Future use # Bit 7: Future use # Bit 8: Future use # 2 Bytes: IV Length (little endian), if included. # IV in binary form. # 2 Bytes: Key Length (little endian), if included. # Key in binary form # 2 Bytes: Cipher Name Length (little endian), if included. # Cipher name it UTF8 text buffer.force_encoding(SymmetricEncryption::BINARY_ENCODING) header = buffer.byteslice(offset, MAGIC_HEADER_SIZE) return 0 unless header == MAGIC_HEADER offset += MAGIC_HEADER_SIZE # Remove header and extract flags self.version = buffer.getbyte(offset) offset += 1 unless cipher raise( SymmetricEncryption::CipherError, "Cipher with version:#{version.inspect} not found in any of the configured SymmetricEncryption ciphers" ) end flags = buffer.getbyte(offset) offset += 1 self.compress = (flags & FLAG_COMPRESSED) != 0 if (flags & FLAG_IV).zero? self.iv = nil else self.iv, offset = read_string(buffer, offset) end if (flags & FLAG_KEY).zero? self.key = nil else encrypted_key, offset = read_string(buffer, offset) self.key = cipher.binary_decrypt(encrypted_key) end if (flags & FLAG_CIPHER_NAME).zero? self.cipher_name = nil else self.cipher_name, offset = read_string(buffer, offset) end if (flags & FLAG_AUTH_TAG).zero? self.auth_tag = nil else self.auth_tag, offset = read_string(buffer, offset) end offset end
Returns [String] the encrypted data without header Returns nil if no header is present
The supplied buffer will be updated directly and its header will be stripped if present.
Parameters
buffer String to extract the header from
# File lib/symmetric_encryption/header.rb, line 113 def parse!(buffer) offset = parse(buffer) return if offset.zero? buffer.slice!(0..offset - 1) buffer end
Returns [String] this header as a string
# File lib/symmetric_encryption/header.rb, line 199 def to_s flags = 0 flags |= FLAG_COMPRESSED if compressed? flags |= FLAG_IV if iv flags |= FLAG_KEY if key flags |= FLAG_CIPHER_NAME if cipher_name flags |= FLAG_AUTH_TAG if auth_tag header = "#{MAGIC_HEADER}#{version.chr(SymmetricEncryption::BINARY_ENCODING)}#{flags.chr(SymmetricEncryption::BINARY_ENCODING)}" if iv header << [iv.length].pack("v") header << iv end if key encrypted = cipher.binary_encrypt(key, header: false) header << [encrypted.length].pack("v") header << encrypted end if cipher_name header << [cipher_name.length].pack("v") header << cipher_name end if auth_tag header << [auth_tag.length].pack("v") header << auth_tag end header end
# File lib/symmetric_encryption/header.rb, line 95 def version=(version) @version = version @cipher = nil end
Private Instance Methods
Extracts a string from the supplied buffer. The buffer starts with a 2 byte length indicator in little endian format.
Parameters
buffer [String] offset [Integer] Start position within the buffer.
Returns [string, offset]
string [String] The string copied from the buffer. offset [Integer] The new offset within the buffer.
# File lib/symmetric_encryption/header.rb, line 256 def read_string(buffer, offset) # TODO: Length check # Exception when # - offset exceeds length of buffer # byteslice truncates when too long, but returns nil when start is beyond end of buffer len = buffer.byteslice(offset, 2).unpack("v").first offset += 2 out = buffer.byteslice(offset, len) [out, offset + len] end