Ciphers

AES

Encryption and Decryption

The following two methods provide a basic interface for encrypting and decrypting. Both methods are parametrised over the underlying type for the computations.

For simply using AES, one would instantiate T as UInt8. For more advanced settings that log traces or use masking, refer to the respective chapters.

CryptoSideChannel.AES.AES_encryptFunction
AES_encrypt(plaintext::MVector{16,T}, key::Vector{T})::MVector{16,T} where T

Encrypt a block of 16 bytes with AES.

T must behave similarly to UInt8. For instantiating T with logging or protecting types, see the article on Integer Types.

Arguments

  • plaintext must be a mutable, statically sized Vector of length 16. It contains the text to encrypt.
  • key is a vector containing the key used for the encryption. It must be either of length 16, 24, or 32. Depending on its length, different variants of AES are dispatched:
    • Length 16: AES-128
    • Length 24: AES-196
    • Length 32: AES-256

Returns

A MVector{16,T} containing the 16-byte long encrypted block.

source
CryptoSideChannel.AES.AES_decryptFunction
AES_decrypt(ciphertext::MVector{16,T}, key::Vector{T})::MVector{16,T} where T

Decrypt a block of 16 bytes with AES.

T must behave similarly to UInt8. For instantiating T with logging or protecting types, see the article on Integer Types.

Arguments

  • ciphertext must be a mutable, statically sized Vector of length 16. It contains the data to decrypt.
  • key is a vector containing the key used for the decryption. It must be either of length 16, 24, or 32. Depending on its length, different variants of AES are dispatched:
    • Length 16: AES-128
    • Length 24: AES-196
    • Length 32: AES-256

Returns

A MVector{16,T} containing the 16-byte long decrypted block.

source

This module also exports methods to en-/decrypt data given as a hexadecimal string:

CryptoSideChannel.AES.AES_encrypt_hexFunction
AES_encrypt_hex(plaintext::String, key::String)

Interpret plaintext and key in hexadecimal. Return a string containing the hexadecimal encrypted block. See AES_encrypt for more details.

Example

julia> AES_encrypt_hex("00112233445566778899aabbccddeeff", "000102030405060708090a0b0c0d0e0f")
"69c4e0d86a7b0430d8cdb78070b4c55a"
source
CryptoSideChannel.AES.AES_decrypt_hexFunction
AES_decrypt_hex(ciphertext::String, key::String)

Interpret ciphertext and key in hexadecimal. Return a string containing the hexadecimal decrypted block. See AES_decrypt for more details.

Example

julia> AES_decrypt_hex("69c4e0d86a7b0430d8cdb78070b4c55a", "000102030405060708090a0b0c0d0e0f")
"00112233445566778899aabbccddeeff"
source

AES Internal Functions

CryptoSideChannel.AES.key_expandFunction
key_expand(k::Vector{T})::Vector{T}

Compute the AES key schedule

Arguments

  • k is the key for the AES algorithm. It should be a vector of type T, which must be an UInt8-like type. The key is required to be a valid key for AES-128, AES-196, or AES-256. Hence, k must be either 16, 24, or 32 bytes long.

Returns

An vector of type T containing the whole key schedule.

source
CryptoSideChannel.AES.inv_key_expandFunction
inv_key_expand(k::Vector{T})

Compute the AES key schedule given only the last round key. This is useful for attacks targeting the last round key, or for computing the decryption key on-the-fly.

Warning

This algorithm is currently only implemented for AES-128.

Arguments

  • k is the last round key used in the AES algorithm. It should be a vector of type T, which must be an UInt8-like type. The key is required to be a valid round key for AES. Hence, k must be exactly 16 bytes long.

Returns

An vector of type T containing the whole key schedule. Most importantly, the first 16 bytes of this vector are the original AES-128 key.

Example

julia> key = hex2bytes("000102030405060708090a0b0c0d0e0f")
julia> last_round_key = AES.key_expand(key)[end-15:end]
julia> recovered_key = AES.inv_key_expand(last_round_key)[1:16]
julia> bytes2hex(recovered_key)
"000102030405060708090a0b0c0d0e0f"
source

If multiple encryptions are performed with the same key, it is efficient to only compute the key schedule once. The key schedule can be computed with key_expand manually. Afterwards, the following two functions can be used for en-/decrypting data with AES with the already computed schedule:

CryptoSideChannel.AES.AES_encrypt_expandedFunction
AES_encrypt_expanded(plaintext::MVector{16,T}, key::Vector{T})::MVector{16,T} where T

Encrypt a block of 16 bytes with AES, given an already expanded key schedule

Arguments

  • plaintext must be a mutable, statically sized Vector of length 16. It contains the text to encrypt.
  • key_schedule is a vector containing all round keys for the encryption. This vector can be obtained with the function key_expand. Based on the length of this vector, the different versions of AES are dispatched.

Returns

A MVector{16,T} containing the 16-byte long encrypted block.

source
CryptoSideChannel.AES.AES_decrypt_expandedFunction
AES_decrypt_expanded(ciphertext::MVector{16,T}, key::Vector{T})::MVector{16,T} where T

Decrypt a block of 16 bytes with AES, given an already expanded key schedule.

Arguments

  • plaintext must be a mutable, statically sized Vector of length 16. It contains the text to decrypt.
  • key_schedule is a vector containing all round keys for the decryption. This vector can be obtained with the function key_expand. Based on the length of this vector, the different versions of AES are dispatched.

Returns

A MVector{16,T} containing the 16-byte long decrypted block.

source

SPECK

Encryption and Decryption

CryptoSideChannel.SPECK.SPECK_encryptFunction
SPECK_encrypt(plaintext::Tuple{T, T}, key::Tuple{T, T}; rounds = 32)::Tuple{T,T} where T

Encrypt plaintext using key with SPECK.

Arguments

  • plaintext is 128-bit data, split into two shares of type T. Each share should contain 64 bits of the plaintext. T can be either UInt64 or a similar custom integer type.
  • key is the 128-bit key, split into two shares of type T. Each share should contain 64 bits of the plaintext. T can be either UInt64 or a similar custom integer type.
  • rounds is the number of rounds to execute. Defaults to 32, since this is the number of rounds mentioned in the original specification of SPECK.

Returns

A Tuple{T,T} containing the 128-bit encrypted data in two shares of 64 bit.

Note

T can be a custom integer type, but note that T must behave like UInt64. This includes truncating overflows in additions at 64 bit.

Example

The example is a SPECK128 test vector from the original SPECK paper

julia> key = (0x0f0e0d0c0b0a0908, 0x0706050403020100)
julia> plaintext = (0x6c61766975716520, 0x7469206564616d20)
julia> SPECK.SPECK_encrypt(plaintext, key)
(0xa65d985179783265, 0x7860fedf5c570d18)

source
CryptoSideChannel.SPECK.SPECK_decryptFunction
SPECK_decrypt(ciphertext::Tuple{T, T}, key::Tuple{T, T}; rounds = 32)::Tuple{T,T} where T

Decrypt ciphertext using key with SPECK.

Arguments

  • ciphertext is 128-bit data, split into two shares of type T. Each share should contain 64 bits of the plaintext. T can be either UInt64 or a similar custom integer type.
  • key is the 128-bit key, split into two shares of type T. Each share should contain 64 bits of the plaintext. T can be either UInt64 or a similar custom integer type.
  • rounds is the number of rounds to execute. Defaults to 32, since this is the number of rounds mentioned in the original specification of SPECK.

Returns

A Tuple{T,T} containing the 128-bit encrypted data in two shares of 64 bit.

Note

T can be a custom integer type, but note that T must behave like UInt64. This includes truncating overflows in additions at 64 bit.

Example

The example is a SPECK128 test vector from the original SPECK paper

julia> key = (0x0f0e0d0c0b0a0908, 0x0706050403020100)
julia> plaintext = (0x6c61766975716520, 0x7469206564616d20)
julia> SPECK.SPECK_decrypt(ciphertext, key)
(0x6c61766975716520, 0x7469206564616d20)

source

Internal Functions

CryptoSideChannel.SPECK.SPECK_key_expandFunction
SPECK_key_expand(key::Tuple{T, T}, rounds)::Vector{T} where T

Expand the key according to the SPECK key schedule. The result is a vector of length rounds, containing each round key. The first round key is the second component of key.

source
CryptoSideChannel.SPECK.SPECK_encrypt_expandedFunction
SPECK_encrypt_expanded(pt::Tuple{T, T}, key_schedule::Vector{T}})::Tuple{T,T} where T

Encrypts data with SPECK, given an already expanded key schedule. This schedule can be created with the function SPECK_key_expand.

source
CryptoSideChannel.SPECK.SPECK_decrypt_expandedFunction
SPECK_decrypt_expanded(ct::Tuple{T, T}, key_schedule::Vector{T})::Tuple{T,T} where T

Decrypts data with SPECK, given an already expanded key schedule. This schedule can be created with the function SPECK_key_expand.

source