We present, for pedagogical purposes, a polymorphic implementation in Haskell of the Cipher Block Chaining mode of operation for a block cipher.

Encryption is an unfold, reflecting the fact that CBC encryption is inherently serial: each block depends on all the previous blocks.

{-# LANGUAGE ScopedTypeVariables #-} encrypt_cbc :: forall block . (block -> block) -> (block -> block -> block) -> block -> [block] -> [block]; encrypt_cbc cipher combine initialization_vector input_plaintext = let { one_encrypt :: (block,[block]) -> Maybe (block,(block,[block])); one_encrypt (previous_ciphertext, plaintext) = case plaintext of { [] -> Nothing; ( (p::block) : (rest::[block]) ) -> let { ciphertext :: block; ciphertext = cipher $ combine p previous_ciphertext; } in Just (ciphertext,(ciphertext,rest)); }} in unfoldr one_encrypt (initialization_vector, input_plaintext);

Decryption is a zip, illustrating that decryption is parallelizable.

decrypt_cbc :: forall block . (block -> block) -> (block -> block -> block) -> block -> [block] -> [block]; decrypt_cbc decipher uncombine initialization_vector ciphertext = let { one_decrypt :: block -> block -> block; one_decrypt previous_ciphertext this_ciphertext = uncombine (decipher this_ciphertext) previous_ciphertext; } in zipWith one_decrypt (initialization_vector:ciphertext) ciphertext;

The `cipher`

and `decipher`

function arguments are the underlying block cipher operating in the encryption and decryption directions respectively.

The `combine`

and `uncombine`

binary operations take two blocks and combine them into one. They are both typically implemented as XOR. It also seems possible to use addition and subtraction modulo N, but I have never seen that explored.

## No comments :

Post a Comment