-
Notifications
You must be signed in to change notification settings - Fork 0
security Ciphers
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.
-
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. Implieslegacy_store_nonce
and notlegacy_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, disablelegacy_validate_nonce
. Impliesuse_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 byenable_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 tolegacy_store_nonce
. Impliessecondary_cipher_type=CBC
and notlegacy_store_nonce
. Default: False -
legacy_store_nonce
: Stores the nonce in plaintext. Exclusive tolegacy_randomized_nonce
. If both this andlegacy_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 toencrypted_nonce
. Disable for compatability with the oldest versions of agutil. Default: True
-
agutil.security.EncryptionCipher
is a configurable cipher that provides
the AES encryption backend for agutil-secure
and the agutil.security
module.
-
EncryptionCipher(key, nonce=
None
, header=None
, **kwargs): (Constructor)Constructs a new
EncryptionCipher
. key and nonce are used to initialize the underlying cipher. If nonce isNone
, a 16-byte nonce will be automatically generated. header should be anagutil.security.CipherHeader
object to specify the cipher settings. If header isNone
, a header will be automatically generated using the provided kwargs (cipher uses default settings if no kwargs are provided). Seeagutil.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 viaEncryptionCipher.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 aBytes
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, callingencrypt()
on the whole plaintext at once, and callingencrypt()
on the plaintext in discrete chunks will ultimately yield the same ciphertext after callingfinish()
. Note: Ciphertext is never complete until you callfinish()
-
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 toencrypt()
. In other words,ciphertext = cipher.encrypt(plaintext) + cipher.finish()
agutil.security.DecryptionCipher
is a configurable cipher that provides
the AES decryption backend for agutil-secure
and the agutil.security
module.
-
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 anEncryptionCipher
. init_data is used to determine cipher configuration and any unused data is buffered until callingdecrypt()
. 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 anagutil.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 isNone
, the cipher expects to find a nonce in the header data. If the header appears invalid, theDecryptionCipher
assumes that the input is in legacy (headerless) format and attempts to continue initialization. Files encrypted byagutil-secure
1.2.0 through 3.1.2 can be handled silently. Files encrypted byagutil-secure
1.1.3 and earlier require legacy_force to beTrue
-
DecryptionCipher.decrypt(data=
b''
):Decrypts the provided ciphertext. data should be a
Bytes
object. This function always returns aBytes
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, callingdecrypt()
on the whole ciphertext at once, and callingdecrypt()
on the ciphertext in discrete chunks will ultimately yield the same plaintext after callingfinish()
. Note: Plaintext is never complete until you callfinish()
-
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 todecrypt()
. In other words,plaintext = cipher.decrypt(ciphertext) + cipher.finish()
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
-
CipherHeader(header=
None
): (Constructor)Creates a new
CipherHeader
. header should be a 15-byte longBytes
object (excludes final hamming weight byte) representing a cipher configuration. If header isNone
, 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 aBitmask
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 aBitmask
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-byteBytes
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.
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
-
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.