Skip to content
This repository has been archived by the owner on Sep 10, 2022. It is now read-only.

security Ciphers

Aaron Graubert edited this page Sep 18, 2018 · 3 revisions

EncryptionCipher, DecryptionCipher, CipherHeader, and Bitmask

For AES encryption, agutil.security and agutil-secure now use configurable ciphers designed for forward and backwards compatibility. EncryptionCipher objects store a header in their output which stores all settings needed for a DecryptionCipher to properly decrypt ciphertext.

Cipher Configuration
  • configure_cipher(**kwargs):

    Uses keyword arguments to determine cipher configuration and returns a CipherHeader reflecting the settings. Keyword arguments:

    • cipher_type: The AES cipher mode to use. Defaults to EAX. Ciphers can be given as the AES.MODE enumeration or a string value (Ex: 'EAX' or 9)
    • secondary_cipher_type: The AES cipher mode to use for the legacy cipher. Cannot be CCM, EAX, GCM, SIV, or OCB. Defaults to CBC
    • store_nonce: Stores nonce data in output. If this is disabled, the nonce must be communicated separately. Default: True
    • encrypted_nonce: Use a legacy cipher to encrypt the primary cipher's nonce. Implies legacy_store_nonce and not legacy_randomized_nonce. Default: False
    • store_tag: Stores a message tag to verify message authenticity. If this is disabled, the validity and integrity of the message cannot be guaranteed. Default: True
    • tag_length: The length (in bytes) of tne message tag. Default: 16
    • chunk_length: The length (in blocks of 256 bytes) of plaintext for each chunk. The cipher stream will emit one chunk of ciphertext each time a full plaintext chunk is read. Ciphertext and plaintext chunks are not necessarily the same size. Default: 16 blocks (4096 bytes)
    • encrypted_tag: Use a legacy cipher to encrypt the message authentication block. Default: False
    • enable_streaming: Configure the cipher to be able to encrypt data as it becomes available. Implied value depends on cipher type. If streaming is disabled, either explicitly, or implicitly (by using a cipher which does not support output), the entire plaintext must be encrypted before any output will be produced be produced. Default: True
    • cipher_nonce_length: Sets the length of the nonce for CTR, CCM, and OCB ciphers. Please check the Pycryptodome docs for allowed sizes. For ciphers besides these three, this parameter is ignored and a 16-byte nonce is used. Default: Largest allowed nonce based on cipher type.
    • ccm_message_length: Sets the length of the message for a CCM cipher. If this parameter is provided, it will imply enable_streaming. CCM ciphers cannot enable streaming without this setting. Maximum value: 65535
    • ctr_initial_value: Sets the initial value of the counter for a CTR cipher. Maximum value: 65535. Default: 1.
    • enable_compatability: Outputs data in a legacy format compataible with older versions of agutil. For compatability with the oldest versions of agutil, disable legacy_validate_nonce. Implies use_legacy_ciphers and disables all non-legacy configuration options. Default: False
    • use_legacy_ciphers: Outputs data in the default modern format, but uses a legacy cipher configuration. Required by enable_compatability. Default: False
    • legacy_randomized_nonce: Do not store Nonce or IV in output. Instead, a CBC mode cipher will be used and a special data block will be stored to allow Decryption without the IV. Exclusive to legacy_store_nonce. Implies secondary_cipher_type=CBC and not legacy_store_nonce. Default: False
    • legacy_store_nonce: Stores the nonce in plaintext. Exclusive to legacy_randomized_nonce. If both this and legacy_randomized_nonce are False, the nonce must be communicated separately. Default: True
    • legacy_validate_nonce: Stores data in the EXData block so that the key and nonce can be validated during Decryption. Exclusive to encrypted_nonce. Disable for compatability with the oldest versions of agutil. Default: True

security.EncryptionCipher

agutil.security.EncryptionCipher is a configurable cipher that provides the AES encryption backend for agutil-secure and the agutil.security module.

API
  • EncryptionCipher(key, nonce=None, header=None, **kwargs): (Constructor)

    Constructs a new EncryptionCipher. key and nonce are used to initialize the underlying cipher. If nonce is None, a 16-byte nonce will be automatically generated. header should be an agutil.security.CipherHeader object to specify the cipher settings. If header is None, a header will be automatically generated using the provided kwargs (cipher uses default settings if no kwargs are provided). See agutil.security.configure_cipher for details on different cipher configuration options. Note: If a nonce was not provided and your configuration disabled storing the nonce, you can access the nonce via EncryptionCipher.nonce.

  • EncryptionCipher.encrypt(data):

    Passes the provided data though the internal cipher and returns ciphertext. data should be a Bytes object. This function always returns a Bytes object, but the size of the output depends on the length of data and the cipher settings. You may call this function as many times as you wish, with any amount of data in each call and any total plaintext size. For any given plaintext, calling encrypt() on the whole plaintext at once, and calling encrypt() on the plaintext in discrete chunks will ultimately yield the same ciphertext after calling finish(). Note: Ciphertext is never complete until you call finish()

  • EncryptionCipher.finish():

    Encrypts any remaining data in the internal buffer and returns final output. Complete ciphertext is produced by appending the output from finish() to the concatenation of the output from any calls to encrypt(). In other words, ciphertext = cipher.encrypt(plaintext) + cipher.finish()

security.DecryptionCipher

agutil.security.DecryptionCipher is a configurable cipher that provides the AES decryption backend for agutil-secure and the agutil.security module.

API
  • DecryptionCipher(init_data, key, nonce=None, legacy_force=False): (Constructor)

    Initializes a new DecryptionCipher. init_data should be the some or all of the ciphertext produced by an EncryptionCipher. init_data is used to determine cipher configuration and any unused data is buffered until calling decrypt(). init_data needs to be at least 16 bytes, but depending on the inferred configuration, it may need to be longer to properly initialize the cipher. The constructor will raise an agutil.security.HeaderLengthError if init_data was too short. 64 bytes is almost always enough data to initialize the cipher. If the constructor fails due to init_data length, try again with more data. key and nonce are used to initialize the underlying cipher. If nonce is None, the cipher expects to find a nonce in the header data. If the header appears invalid, the DecryptionCipher assumes that the input is in legacy (headerless) format and attempts to continue initialization. Files encrypted by agutil-secure 1.2.0 through 3.1.2 can be handled silently. Files encrypted by agutil-secure 1.1.3 and earlier require legacy_force to be True

  • DecryptionCipher.decrypt(data=b''):

    Decrypts the provided ciphertext. data should be a Bytes object. This function always returns a Bytes object, but the size of the output depends on the length of data and the cipher settings. You may call this function as many times as you wish, with any amount of data in each call and any total ciphertext size. For any given cipher, calling decrypt() on the whole ciphertext at once, and calling decrypt() on the ciphertext in discrete chunks will ultimately yield the same plaintext after calling finish(). Note: Plaintext is never complete until you call finish()

  • DecryptionCipher.finish():

    Decrypts any remaining data in the internal buffer and returns final output. Complete plaintext is produced by appending the output from finish() to the concatenation of the output from any calls to decrypt(). In other words, plaintext = cipher.decrypt(ciphertext) + cipher.finish()

security.CipherHeader

agutil.security.CipherHeader stores the configuration of an EncryptionCipher or DecryptionCipher and can be used to produce the 16-byte cipher header representing the configuration

API
  • CipherHeader(header=None): (Constructor)

    Creates a new CipherHeader. header should be a 15-byte long Bytes object (excludes final hamming weight byte) representing a cipher configuration. If header is None, a blank header is produced. Note: The default (blank) header is valid in the sense that it follows the cipher header format, but it is not suitable for immediate use in a cipher. After initializing a blank header, you must set its attributes into a valid cipher configuration.

  • CipherHeader.valid: (Property, readonly)

    Returns True if the header is in a valid state. False otherwise

  • CipherHeader.weight: (Property, readonly)

    Returns the hamming weight of the header

  • CipherHeader.data: (Property, readonly)

    Returns the 16-byte representation of this header

  • CipherHeader.legacy_bitmask: (Property)

    Returns a Bitmask object containing the state of the legacy cipher bitmask. You may also assign a Bitmask object to this property to overwrite the bitmask

  • CipherHeader.control_bitmask: (Property)

    Returns a Bitmask object containing the state of the main cipher bitmask. You may also assign a Bitmask object to this property to overwrite the bitmask

  • CipherHeader.exdata_size: (Property)

    Returns the size (in bytes) of the extra data block. You may also assign an integer (maximum 255) to this property

  • CipherHeader.cipher_id: (Property)

    Returns the ID of the primary cipher. You may also assign an integer (maximum 255) to this property

  • CipherHeader.secondary_id: (Property)

    Returns the ID of the legacy cipher. You may also assign an integer (maximum 255) to this property

  • CipherHeader.cipher_data: (Property)

    Returns the 6-byte cipher_data segment as a Bytes object. You may also assign a 6-byte Bytes object to this property

  • CipherHeader.use_modern_cipher: (Property, readonly)

    Returns True if the current header configuration would enable the use of the primary (modern) cipher.

security.Bitmask

agutil.security.Bitmask allows reading and manipulating a single-byte bitmask using pythons [] indexing API. This class uses an agutil.search_range to perform underlying bit manipulations and queries

API
  • Bitmask(n=0, values=None): (Constructor)

    Constructs a new Bitmask. n should represent the integer value of the bitmask to start from. 0 is an empty mask with no bits set. Alternatively, values may be a list of 8 boolean values to initialize the bitmask.

  • Bitmask.__getitem__(i):

    Gets the value of bit i (Big Endian).

  • Bitmask.__setitem__(i, v):

    Sets the value of bit i (Big Endian). If v evaluates to False, the bit is un-set instead

  • Bitmask.set_range(start, stop, value=True):

    Sets the bits in the range [start, stop). If value evaluates to False, the bits are un-set instead.