Symmetric cryptography¶
The symmetric
module provides the
function to perform encryption and decryption operation and also MACs.
Naturally, the functions with the suffix _encrypt
are for encryption and
_decrypt
for decryption. The underlying block cipher used is Advanced
Encryption Standard
(AES).
There are also lower level primitives such as XOR
, pad
and
unpad
.
Finally, there is a hash function sha256_hash
, and functions create_mac
and verify_mac
for creating and verifying Message
Authentication Codes (MACs), respectively.
- pv080_crypto.symmetric.pad(data: bytes, block_size: int) bytes [source]¶
Appends PKCS7 padding to
data
so that its size is a multiple ofblock_size
.- Parameters:
data – The unpadded data which we want to pad.
block_size – The block size in bits, usually given by the cipher that we want to use.
- Returns:
The padded data.
Example:
>>> import secrets >>> key = secrets.token_bytes(16) >>> pt = b'message' >>> padded_pt = pad(pt, 128) >>> ct = aes_ecb_encrypt(key, padded_pt)
- pv080_crypto.symmetric.unpad(padded_data: bytes, block_size: int) bytes [source]¶
Removes PKCS7 padding from
padded_data
.- Parameters:
padded_data – The padded data which we want to unpad.
block_size – The block size in bits, usually given by the cipher that we want to use.
- Returns:
The unpadded data.
Example:
>>> import secrets >>> key = secrets.token_bytes(16) >>> pt = b'message' >>> padded_pt = pad(pt, 128) >>> ct = aes_ecb_encrypt(key, padded_pt) >>> decrypted = aes_ecb_decrypt(key, ct) >>> assert unpad(decrypted, 128) == pt
- pv080_crypto.symmetric.aes_ecb_encrypt(key: bytes, padded_plaintext: bytes) bytes [source]¶
Encrypts
padded_plaintext
withkey
using AES-ECB.- Parameters:
key – The encryption key of size 128, 192, or 256 bits.
padded_plaintext – The bytes to be encrypted (must be padded to 128 bits).
- Returns:
The bytes of the encrypted ciphertext.
Example:
>>> import secrets >>> key = secrets.token_bytes(16) >>> pt = b'message' >>> padded_pt = pad(pt, 128) >>> ct = aes_ecb_encrypt(key, padded_pt)
- pv080_crypto.symmetric.aes_ecb_decrypt(key: bytes, ciphertext: bytes) bytes [source]¶
Decrypts
ciphertext
withkey
using AES-ECB.- Parameters:
key – The encryption key of size 128, 192, or 256 bits.
ciphertext – The bytes to be decrypted.
- Returns:
The bytes of the padded plaintext.
Example:
>>> import secrets >>> key = secrets.token_bytes(16) >>> pt = b'message' >>> padded_pt = pad(pt, 128) >>> ct = aes_ecb_encrypt(key, padded_pt) >>> decrypted = aes_ecb_decrypt(key, ct) >>> assert unpad(decrypted, 128) == pt
- pv080_crypto.symmetric.aes_cbc_encrypt(key: bytes, iv: bytes, padded_plaintext: bytes) bytes [source]¶
Encrypts
padded_plaintext
withkey
using AES-CBC andiv
.- Parameters:
key – The encryption key of size 128, 192, or 256 bits.
iv – The initialization vector (must be of size 128 bits).
padded_plaintext – The bytes to be encrypted (must be padded to 128 bits).
- Returns:
The bytes of the encrypted ciphertext.
Example:
>>> import secrets >>> key = secrets.token_bytes(16) >>> iv = secrets.token_bytes(16) >>> pt = b'message' >>> padded_pt = pad(pt, 128) >>> ct = aes_cbc_encrypt(key, iv, padded_pt)
- pv080_crypto.symmetric.aes_cbc_decrypt(key: bytes, iv: bytes, ciphertext: bytes) bytes [source]¶
Decrypts
ciphertext
withkey
using AES-CBC andiv
.- Parameters:
key – The encryption key of size 128, 192, or 256 bits.
iv – The initialization vector (must be of size 128 bits).
ciphertext – The bytes to be decrypted.
- Returns:
The bytes of the padded plaintext.
Example:
>>> import secrets >>> key = secrets.token_bytes(16) >>> iv = secrets.token_bytes(16) >>> pt = b'message' >>> padded_pt = pad(pt, 128) >>> ct = aes_cbc_encrypt(key, iv, padded_pt) >>> decrypted = aes_cbc_decrypt(key, iv, ct) >>> assert unpad(decrypted, 128) == pt
- pv080_crypto.symmetric.XOR(array1: bytes, array2: bytes) bytes [source]¶
Performs the bitwise XOR operation on two given bytestrings.
- Parameters:
array1 – The first operand.
array2 – The second operand.
- Returns:
The bitwise XOR of
array1
andarray2
.
Example:
>>> xor = XOR(bytes.fromhex('01ff'), bytes.fromhex('03fe')) >>> assert xor == bytes.fromhex('0201')
- pv080_crypto.symmetric.chacha20_encrypt(key: bytes, nonce: bytes, plaintext: bytes) bytes [source]¶
Use ChaCha20 to encrypt
plaintext
usingkey
andnonce
.- Parameters:
key – The bytes of the key (size 32 bytes).
nonce – The bytes of the nonce (size 16 bytes).
- Returns:
The bytes of the ciphertext.
Example:
>>> import secrets >>> key = secrets.token_bytes(32) >>> nonce = secrets.token_bytes(16) >>> ciphertext = chacha20_encrypt(key=key, nonce=nonce, plaintext=b"message")
- pv080_crypto.symmetric.chacha20_decrypt(key: bytes, nonce: bytes, ciphertext: bytes) bytes [source]¶
Use ChaCha20 to decrypt
ciphertext
usingkey
andnonce
.- Parameters:
key – The bytes of the key (size 32 bytes).
nonce – The bytes of the nonce (size 16 bytes).
- Returns:
The bytes of the plaintext.
Example:
>>> import secrets >>> key = secrets.token_bytes(32) >>> nonce = secrets.token_bytes(16) >>> message = b"hello world" >>> ciphertext = chacha20_encrypt(key=key, nonce=nonce, plaintext=message) >>> assert message == chacha20_decrypt(key=key, nonce=nonce, ciphertext=ciphertext)
- pv080_crypto.symmetric.aes_encrypt(key: bytes, plaintext: bytes) bytes [source]¶
Use AES-CBC to encrypt
plaintext
usingkey
. The function also appends PKCS#7 padding and prepends a random IV to the ciphertext.- Parameters:
key – The bytes of the key (16, 24, or 32 bytes in size).
plaintext – The plaintext bytes to be encrypted.
- Returns:
The bytes of the ciphertext.
Example:
>>> import secrets >>> key = secrets.token_bytes(16) >>> ciphertext = aes_encrypt(key=key, plaintext=b"my message")
- pv080_crypto.symmetric.aes_decrypt(key: bytes, ciphertext: bytes) bytes [source]¶
Use AES-CBC to decrypt
ciphertext
usingkey
. Theciphertext
should be encrypted usingaes_encrypt
.- Parameters:
key – The bytes of the key (16, 24, or 32 bytes).
ciphertext – The ciphertext bytes to be decrypted.
- Returns:
The bytes of the plaintext.
Example:
>>> import secrets >>> key = secrets.token_bytes(16) >>> message = b"hello world" >>> ciphertext = aes_encrypt(key=key, plaintext=message) >>> assert message == aes_decrypt(key=key, ciphertext=ciphertext)
- pv080_crypto.symmetric.sha256_hash(data: bytes) bytes [source]¶
Compute the SHA256 hash of the given data.
- Parameters:
data – The bytes of the data to hash.
- Returns:
The digest of the data (32 bytes).
Example:
>>> message = b"Hello world" >>> digest = sha256_hash(message) >>> print(digest.hex(sep=' ')) '64 ec 88 ca 00 b2 68 e5 ba 1a 35 67 8a 1b 53 16 d2 12 f4 f3 66 b2 47 72 32 53 4a 8a ec a3 7f 3c'
- pv080_crypto.symmetric.create_mac(key: bytes, data: bytes) bytes [source]¶
Calculate Message Authentication Code of
data
(using AES-CBC), i.e. encryptdata
usingkey
and AES-CBC with initialization vector equal to zero bytes.- Parameters:
key – The bytes of the key (16, 24, or 32 bytes).
data – The data that will be MAC’d.
- Returns:
The MAC value (16 bytes).
Example:
>>> import secrets >>> key = secrets.token_bytes(32) >>> mac = create_mac(key=key, data=b"some data to MAC")
- pv080_crypto.symmetric.verify_mac(key: bytes, data: bytes, mac: bytes) bool [source]¶
Verify that the MAC (using AES-CBC) of
data
matchesmac
.- Parameters:
key – The bytes of the key (16, 24, or 32 bytes).
data – The data that will be MAC’ed.
mac – The value against which we verify (16 bytes).
- Returns:
True
if the verification succeeds,False
otherwise.
Example:
>>> import secrets >>> key = secrets.token_bytes(32) >>> data=b"some data to MAC" >>> mac = create_mac(key=key, data=data) >>> assert verify_mac(key=key, data=data, mac=mac)