bcl module
Python library that provides a simple interface for symmetric (i.e., secret-key) and asymmetric (i.e., public-key) encryption/decryption primitives.
This library exports a number of classes (derived from bytes
) for
representing keys, nonces, plaintexts, and ciphertexts. It also exports
two classes symmetric
and asymmetric
that have only static
methods (for key generation and encryption/decryption).
- class bcl.bcl.raw[source]
Bases:
bytes
Wrapper class for a raw bytes-like object that represents a key, nonce, plaintext, or ciphertext. The derived classes
secret
,public
,nonce
,plain
, andcipher
all inherit the methods defined in this class.>>> s = secret.from_base64('1P3mjNnadofjTUkzTmipYl+xdo9z/EaGLbWcJ8MAPBQ=') >>> s.hex() 'd4fde68cd9da7687e34d49334e68a9625fb1768f73fc46862db59c27c3003c14' >>> n = nonce.from_base64('JVN9IKBLZi3lEq/eDgkV+y6n4v7x2edI') >>> c = symmetric.encrypt(s, 'abc'.encode(), n) >>> c.to_base64() 'JVN9IKBLZi3lEq/eDgkV+y6n4v7x2edI9dvFXD+om1dHB6UUCt1y4BqrBw=='
- classmethod from_base64(s: str) bcl.bcl.raw [source]
Convert Base64 UTF-8 string representation of a raw value.
- class bcl.bcl.nonce(argument: Optional[Union[bytes, bytearray, int]] = None)[source]
Bases:
bcl.bcl.raw
Wrapper class for a bytes-like object that represents a nonce.
>>> n = nonce() >>> n = nonce(bytes(n)) >>> isinstance(n, nonce) and isinstance(n, bytes) True
While the constructor works like the constructor for bytes-like objects in also accepting an integer argument, an instance can only have the exact length permitted for a nonce.
>>> nonce(nonce.length).hex() '000000000000000000000000000000000000000000000000'
The constructor for this class checks that the supplied bytes-like object or integer argument satisfy the conditions for a valid nonce.
>>> nonce('abc') Traceback (most recent call last): ... TypeError: nonce constructor argument must be a bytes-like object or an integer >>> try: ... nonce(bytes([1, 2, 3])) ... except ValueError as e: ... str(e) == 'nonce must have exactly ' + str(nonce.length) + ' bytes' True >>> try: ... nonce(123) ... except ValueError as e: ... str(e) == 'nonce must have exactly ' + str(nonce.length) + ' bytes' True
- class bcl.bcl.key[source]
Bases:
bcl.bcl.raw
Wrapper class for a bytes-like object that represents a key. The derived classes
secret
andpublic
inherit the methods defined in this class.Any
key
objects (including instances of classes derived fromkey
) have a few features and behaviors that distinguish them from bytes-like objects.Comparison of keys (using the built-in
==
and!=
operators via the__eq__
and__ne__
methods) is performed in constant time.Keys of different types are not equivalent even if their binary representation is identical.
>>> b = 'd6vGTIjbxZyMolCW+/p1QFF5hjsYC5Q4x07s+RIMKK8=' >>> secret.from_base64(b) == public.from_base64(b) False >>> secret.from_base64(b) != public.from_base64(b) True
Consistent with the above property, keys having different classes are distinct when used as keys or items within containers.
>>> b = 'd6vGTIjbxZyMolCW+/p1QFF5hjsYC5Q4x07s+RIMKK8=' >>> len({secret.from_base64(b), public.from_base64(b)}) 2
- __eq__(other: bcl.bcl.key) bool [source]
Compare two keys (including their subclass). The portion of the method that compares byte values runs in constant time.
>>> key(bytes([0] * 32)) == key(bytes([1] * 32)) False >>> key(bytes([1] * 32)) == key(bytes([1] * 32)) True >>> secret(bytes([0] * 32)) == public(bytes([0] * 32)) False
- __ne__(other: bcl.bcl.key) bool [source]
Compare two keys (including their subclass). The portion of the method that compares byte values runs in constant time.
>>> key(bytes([0] * 32)) != key(bytes([1] * 32)) True >>> key(bytes([1] * 32)) != key(bytes([1] * 32)) False >>> secret(bytes([0] * 32)) != public(bytes([0] * 32)) True
- class bcl.bcl.secret(argument: Optional[Union[bytes, bytearray, int]] = None)[source]
Bases:
bcl.bcl.key
Wrapper class for a bytes-like object that represents a secret key. The constructor for this class can be used to generate an instance of a secret key or to convert a bytes-like object into a secret key.
>>> s = secret() >>> s = secret(bytes(s)) >>> isinstance(s, secret) and isinstance(s, key)and isinstance(s, bytes) True
While the constructor works like the constructor for bytes-like objects in also accepting an integer argument, an instance can only have the exact length permitted for a secret key.
>>> secret(secret.length).hex() '0000000000000000000000000000000000000000000000000000000000000000'
The constructor for this class checks that the supplied bytes-like object or integer argument satisfy the conditions for a valid secret key.
>>> secret('abc') Traceback (most recent call last): ... TypeError: secret key constructor argument must be a bytes-like object or an integer >>> try: ... secret(bytes([1, 2, 3])) ... except ValueError as e: ... str(e) == 'secret key must have exactly ' + str(secret.length) + ' bytes' True >>> try: ... secret(123) ... except ValueError as e: ... str(e) == 'secret key must have exactly ' + str(secret.length) + ' bytes' True
The methods
symmetric.encrypt
,symmetric.decrypt
, andasymmetric.decrypt
only accept key parameters that are objects of this class.
- class bcl.bcl.public(argument: Optional[Union[bytes, bytearray, int]] = None)[source]
Bases:
bcl.bcl.key
Wrapper class for a bytes-like object that represents a public key. The constructor for this class can be used to generate an instance of a public key or to convert a bytes-like object into a public key.
>>> p = public() >>> p = public(bytes(p)) >>> isinstance(p, public) and isinstance(p, key)and isinstance(p, bytes) True
While the constructor works like the constructor for bytes-like objects in also accepting an integer argument, an instance can only have the exact length permitted for a public key.
>>> public(public.length).hex() '0000000000000000000000000000000000000000000000000000000000000000'
The constructor for this class checks that the supplied bytes-like object or integer argument satisfy the conditions for a valid public key.
>>> public('abc') Traceback (most recent call last): ... TypeError: public key constructor argument must be a bytes-like object or an integer >>> try: ... public(bytes([1, 2, 3])) ... except ValueError as e: ... length = crypto_box_PUBLICKEYBYTES ... str(e) == 'public key must have exactly ' + str(length) + ' bytes' True >>> try: ... public(123) ... except ValueError as e: ... length = crypto_box_PUBLICKEYBYTES ... str(e) == 'public key must have exactly ' + str(length) + ' bytes' True
The method
asymmetric.encrypt
only accepts key parameters that are objects of this class.
- class bcl.bcl.plain[source]
Bases:
bcl.bcl.raw
Wrapper class for a bytes-like object that represents a plaintext.
>>> x = plain(os.urandom(1024)) >>> x == plain.from_base64(x.to_base64()) True
The methods
symmetric.decrypt
andasymmetric.decrypt
return objects of this class.
- class bcl.bcl.cipher[source]
Bases:
bcl.bcl.raw
Wrapper class for a bytes-like object that represents a ciphertext.
>>> c = cipher(os.urandom(1024)) >>> c == cipher.from_base64(c.to_base64()) True
The methods
symmetric.encrypt
andasymmetric.encrypt
return objects of this class, and the methodssymmetric.decrypt
andasymmetric.decrypt
can only be applied to objects of this class.
- class bcl.bcl.symmetric[source]
Bases:
object
Symmetric (i.e., secret-key) encryption/decryption primitives. This class encapsulates only static methods and should not be instantiated.
>>> x = 'abc'.encode() >>> s = symmetric.secret() >>> isinstance(s, key) and isinstance(s, secret) True >>> s == secret.from_base64(s.to_base64()) True >>> c = symmetric.encrypt(s, x) >>> isinstance(c, raw) and isinstance(c, cipher) True >>> c == cipher.from_base64(c.to_base64()) True >>> symmetric.decrypt(s, c) == x True >>> isinstance(symmetric.decrypt(s, c), plain) True
Encryption is non-deterministic if no
nonce
parameter is supplied.>>> symmetric.encrypt(s, x) == symmetric.encrypt(s, x) False
Deterministic encryption is possible by supplying a
nonce
parameter.>>> n = nonce() >>> symmetric.encrypt(s, x, n) == symmetric.encrypt(s, x, n) True
- static secret() bcl.bcl.secret [source]
Generate a
secret
key.
- static encrypt(secret_key: bcl.bcl.secret, plaintext: Union[bcl.bcl.plain, bytes, bytearray], noncetext: Optional[bcl.bcl.nonce] = None) bcl.bcl.cipher [source]
Encrypt a plaintext (a bytes-like object) using the supplied
secret
key (and an optionalnonce
, if applicable).>>> m = plain(bytes([1, 2, 3])) >>> s = symmetric.secret() >>> c = symmetric.encrypt(s, m) >>> m == symmetric.decrypt(s, c) True
All parameters supplied to this method must have appropriate types.
>>> c = symmetric.encrypt(bytes([0, 0, 0]), m) Traceback (most recent call last): ... TypeError: can only encrypt using a symmetric secret key >>> c = symmetric.encrypt(s, 'abc') Traceback (most recent call last): ... TypeError: can only encrypt a plaintext object or bytes-like object >>> c = symmetric.encrypt(s, m, bytes([0, 0, 0])) Traceback (most recent call last): ... TypeError: nonce parameter must be a nonce object
- static decrypt(secret_key: bcl.bcl.secret, ciphertext: bcl.bcl.cipher) bcl.bcl.plain [source]
Decrypt a ciphertext (an instance of
cipher
) using the suppliedsecret
key.>>> m = plain(bytes([1, 2, 3])) >>> s = symmetric.secret() >>> c = symmetric.encrypt(s, m) >>> m == symmetric.decrypt(s, c) True
All parameters supplied to this method must have appropriate types.
>>> c = symmetric.decrypt(bytes([0, 0, 0]), m) Traceback (most recent call last): ... TypeError: can only decrypt using a symmetric secret key >>> c = symmetric.decrypt(s, 'abc') Traceback (most recent call last): ... TypeError: can only decrypt a ciphertext >>> symmetric.decrypt(s, cipher(c + bytes([0, 0, 0]))) Traceback (most recent call last): ... RuntimeError: ciphertext failed verification
- class bcl.bcl.asymmetric[source]
Bases:
object
Asymmetric (i.e., public-key) encryption/decryption primitives. This class encapsulates only static methods and should not be instantiated.
>>> x = 'abc'.encode() >>> s = asymmetric.secret() >>> isinstance(s, key) and isinstance(s, secret) True >>> p = asymmetric.public(s) >>> isinstance(p, key) and isinstance(p, public) True >>> p == public.from_base64(p.to_base64()) True >>> c = asymmetric.encrypt(p, x) >>> asymmetric.decrypt(s, c) == x True
- static secret() bcl.bcl.secret [source]
Generate a
secret
key.>>> s = symmetric.secret() >>> isinstance(s, key) and isinstance(s, secret) True
- static public(secret_key: bcl.bcl.secret) bcl.bcl.public [source]
Generate a
public
key using asecret
key.>>> s = asymmetric.secret() >>> p = asymmetric.public(s) >>> isinstance(p, key) and isinstance(p, public) True
- static encrypt(public_key: bcl.bcl.public, plaintext: Union[bcl.bcl.plain, bytes, bytearray]) bcl.bcl.cipher [source]
Encrypt a plaintext (any bytes-like object) using the supplied
public
key.>>> m = plain(bytes([1, 2, 3])) >>> s = asymmetric.secret() >>> p = asymmetric.public(s) >>> c = asymmetric.encrypt(p, m) >>> m == asymmetric.decrypt(s, c) True
All parameters supplied to this method must have appropriate types.
>>> c = asymmetric.encrypt(s, m) Traceback (most recent call last): ... TypeError: can only encrypt using a public key >>> c = asymmetric.encrypt(p, 'abc') Traceback (most recent call last): ... TypeError: can only encrypt a plaintext object or bytes-like object
- static decrypt(secret_key: bcl.bcl.secret, ciphertext: bcl.bcl.cipher) bcl.bcl.plain [source]
Decrypt a ciphertext (an instance of
cipher
) using the suppliedsecret
key.>>> m = plain(bytes([1, 2, 3])) >>> s = asymmetric.secret() >>> p = asymmetric.public(s) >>> c = asymmetric.encrypt(p, m) >>> m == asymmetric.decrypt(s, c) True
All parameters supplied to this method must have appropriate types.
>>> c = asymmetric.decrypt(p, m) Traceback (most recent call last): ... TypeError: can only decrypt using an asymmetric secret key >>> c = asymmetric.decrypt(s, 'abc') Traceback (most recent call last): ... TypeError: can only decrypt a ciphertext >>> try: ... asymmetric.decrypt(s, cipher(bytes([0]))) ... except ValueError as e: ... length = crypto_box_SEALBYTES ... str(e) == 'asymmetric ciphertext must have at least ' + str(length) + ' bytes' True