1 # The block-cipher interface. 2 # 3 # A block cipher (template arguments, in this order): 4 # ~K: Data its key schedule 5 # ~Blk: Data a block 6 # ~bsize: Nat the block size in bytes 7 # ~key: B.Octets -> Result<&2, &2, CrError, K> 8 # the key schedule of a raw 9 # key, refusing a key of a 10 # length the cipher does not 11 # take (CrBadKeyLength{got}) 12 # ~enc: K -> Blk -> Blk encrypt one block 13 # ~dec: K -> Blk -> Blk decrypt one block 14 # and its block format, the bytes of a block: 15 # ~blk_of: B.Octets -> Maybe<&2, Blk> bsize bytes as a block (None 16 # for any other length) 17 # ~blk_to: Blk -> B.Octets the bsize bytes of a block 18 # ~bxor: Blk -> Blk -> Blk two blocks XORed 19 # A generic algorithm takes only the arguments it uses (CBC encryption: ~K, 20 # ~Blk, ~enc, ~bxor). A value of K is only ever made by ~key, so every K is a 21 # valid key, and every value of Blk is a block. 22 # 23 # Laws, for every key schedule and block (README.md, "Laws"): 24 # round_trip dec(k, enc(k, b)) == b 25 # round_trip_dual enc(k, dec(k, b)) == b (the cipher is a permutation; 26 # where the cipher proves it) 27 # format blk_of(blk_to(b)) == Some{b} 28 # xor bxor(bxor(a, b), b) == a 29 # key_length a key of a length the cipher does not take is refused 30 # 31 # The formats of the existing ciphers: inst_cm.bend (cipher-modes' 128-bit 32 # CmBlock) and inst_lc.bend (legacy-ciphers' 64-bit LcBlock64). Modes over 33 # any block cipher are in modes.bend. 34 import Base 35 import bend-osdev-bytes@0.1.0.0/bytes.bend as B 36 import ./crypto.bend as Cr 37 38 def cr.blk.enc(~K: Data, ~Blk: Data, ~enc: K -> Blk -> Blk, ~blk_to: Blk -> B.Octets, m: Maybe<&2, Blk>, +k: K, +n: Nat) -> Result<&2, &2, Cr.CrError, B.Octets>: 39 match m: 40 case None{}: 41 Fail{Cr.CrBadBlockSize{n}} 42 case Some{b}: 43 Done{blk_to(enc(k, b))} 44 45 # One block of bytes encrypted (CrBadBlockSize for another length) 46 def CrBlockCipher.encrypt_octets(~K: Data, ~Blk: Data, ~enc: K -> Blk -> Blk, ~blk_of: B.Octets -> Maybe<&2, Blk>, ~blk_to: Blk -> B.Octets, +k: K, +o: B.Octets) -> Result<&2, &2, Cr.CrError, B.Octets>: 47 cr.blk.enc(~K, ~Blk, ~enc, ~blk_to, blk_of(o), k, B.Octets.len(o)) 48 49 # One block of bytes decrypted 50 def CrBlockCipher.decrypt_octets(~K: Data, ~Blk: Data, ~dec: K -> Blk -> Blk, ~blk_of: B.Octets -> Maybe<&2, Blk>, ~blk_to: Blk -> B.Octets, +k: K, +o: B.Octets) -> Result<&2, &2, Cr.CrError, B.Octets>: 51 cr.blk.enc(~K, ~Blk, ~dec, ~blk_to, blk_of(o), k, B.Octets.len(o)) 52 53 # The key schedule of a raw key, then one block of bytes encrypted 54 def CrBlockCipher.encrypt_with(~K: Data, ~Blk: Data, ~key: B.Octets -> Result<&2, &2, Cr.CrError, K>, ~enc: K -> Blk -> Blk, ~blk_of: B.Octets -> Maybe<&2, Blk>, ~blk_to: Blk -> B.Octets, key_o: B.Octets, +o: B.Octets) -> Result<&2, &2, Cr.CrError, B.Octets>: 55 Result.bind(&2, &2, Cr.CrError, K, B.Octets, key(key_o), k => CrBlockCipher.encrypt_octets(~K, ~Blk, ~enc, ~blk_of, ~blk_to, k, o))