block.bend
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.
34import Base
35import bend-osdev-bytes@0.1.0.0/bytes.bend as B
36import bend-osdev-crypto@0.1.0.0/crypto.bend as Cr
37
38def 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)
46def 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
50def 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
54def 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))