check.bend

bend-osdev-blowfish@0.1.0.0 · 104 lines · 0 definitions

1# Blowfish: six of Schneier's vectors (keys of 8, 1, 3 and 24 bytes), both
2# ways (the ciphertext, then the plaintext decrypted back), and Blowfish
3# through modes64.bend's CBC over 16 KB both ways.
4import Base
5import bend-osdev-bytes@0.1.1.0/bytes.bend as B
6import bend-osdev-cipher-core@0.1.0.0/cipher_core.bend as L
7import bend-osdev-cipher-core@0.1.0.0/modes64.bend as X
8import bend-osdev-blowfish@0.1.0.0/blowfish.bend as BF
9
10def err(e: L.LcError) -> String:
11  match e:
12    case L.LcBadKeyLength{n}:
13      "bad key " ++ Nat.show(n)
14    case L.LcBadIvLength{n}:
15      "bad iv " ++ Nat.show(n)
16    case L.LcNotBlockMultiple{n}:
17      "not whole blocks " ++ Nat.show(n)
18
19def b64.of(m: Maybe<&2, L.LcBlock64>) -> L.LcBlock64:
20  match m:
21    case None{}:
22      L.LcBlock64.zero()
23    case Some{b}:
24      b
25
26def b64(o: B.Octets) -> L.LcBlock64:
27  b64.of(L.LcBlock64.of_octets(o))
28
29def key(~K: Data, r: Result<&2, &2, L.LcError, K>, d: K) -> K:
30  match r:
31    case Fail{e}:
32      d
33    case Done{k}:
34      k
35
36def both64(~K: Data, ~enc: K -> L.LcBlock64 -> L.LcBlock64, ~dec: K -> L.LcBlock64 -> L.LcBlock64, +k: K, b: L.LcBlock64) -> String:
37  +c = enc(k, b)
38  L.LcBlock64.hex(c) ++ " " ++ L.LcBlock64.hex(dec(k, c))
39
40def blowfish_key(k: B.Octets) -> BF.LcBlowfishKey:
41  key(~BF.LcBlowfishKey, BF.LcBlowfish.key_any(k), BF.LcBlowfishKey{Nil{}})
42
43def blowfish(k: B.Octets, b: B.Octets) -> String:
44  both64(~BF.LcBlowfishKey, ~BF.LcBlowfish.encrypt, ~BF.LcBlowfish.decrypt, blowfish_key(k), b64(b))
45
46# n bytes, byte i = 7i + 3 (mod 256)
47def big.go(n: Nat, +i: U32, acc: List<&2, U32>) -> List<&2, U32>:
48  match n:
49    case 0n:
50      B.rev(acc)
51    case 1n+p:
52      big.go(p, U32.add(i, 1), Con{U32.and(255, U32.add(U32.mul(i, 7), 3)), acc})
53
54def big(n: Nat) -> B.Octets:
55  B.Octets.of_list(big.go(n, 0, Nil{}))
56
57def verdict(b: Bool) -> String:
58  match b:
59    case True{}:
60      "ok"
61    case False{}:
62      "differs"
63
64def last8(r: Result<&2, &2, L.LcError, B.Octets>) -> String:
65  match r:
66    case Fail{e}:
67      err(e)
68    case Done{+o}:
69      B.Octets.hex(B.Octets.drop(Nat.sub(B.Octets.len(o), 8n), o))
70
71def same64(r: Result<&2, &2, L.LcError, B.Octets>, +m: B.Octets) -> String:
72  match r:
73    case Fail{e}:
74      err(e)
75    case Done{o}:
76      verdict(B.Octets.is_eq(o, m))
77
78def cbc64(~K: Data, ~enc: K -> L.LcBlock64 -> L.LcBlock64, ~dec: K -> L.LcBlock64 -> L.LcBlock64, +k: K, n: Nat) -> String:
79  +m = big(n)
80  +c = X.Lc64.cbc_encrypt(~K, ~enc, k, B.Octets.zeros(8n), m)
81  last8(c) ++ " " ++ same64(Result.bind(&2, &2, L.LcError, B.Octets, B.Octets, c, x => X.Lc64.cbc_decrypt(~K, ~dec, k, B.Octets.zeros(8n), x)), m)
82
83def blowfish_cbc(k: B.Octets, n: Nat) -> String:
84  cbc64(~BF.LcBlowfishKey, ~BF.LcBlowfish.encrypt, ~BF.LcBlowfish.decrypt, blowfish_key(k), n)
85
86# BEGIN GENERATED by gen/vectors.py: check
87def main() -> IO(Unit):
88  do IO<Unit>:
89    IO.print(blowfish(B.Octets.of_list([0, 0, 0, 0, 0, 0, 0, 0]), B.Octets.of_list([0, 0, 0, 0, 0, 0, 0, 0])))
90    IO.print(blowfish(B.Octets.of_list([255, 255, 255, 255, 255, 255, 255, 255]), B.Octets.of_list([255, 255, 255, 255, 255, 255, 255, 255])))
91    IO.print(blowfish(B.Octets.of_list([254, 220, 186, 152, 118, 84, 50, 16]), B.Octets.of_list([1, 35, 69, 103, 137, 171, 205, 239])))
92    IO.print(blowfish(B.Octets.of_list([240]), B.Octets.of_list([254, 220, 186, 152, 118, 84, 50, 16])))
93    IO.print(blowfish(B.Octets.of_list([240, 225, 210]), B.Octets.of_list([254, 220, 186, 152, 118, 84, 50, 16])))
94    IO.print(blowfish(B.Octets.of_list([240, 225, 210, 195, 180, 165, 150, 135, 120, 105, 90, 75, 60, 45, 30, 15, 0, 17, 34, 51, 68, 85, 102, 119]), B.Octets.of_list([254, 220, 186, 152, 118, 84, 50, 16])))
95    IO.print(blowfish_cbc(B.Octets.of_list([1, 35, 69, 103, 137, 171, 205, 239]), 16384n))
96
97#|4ef997456198dd78 0000000000000000
98#|51866fd5b85ecb8a ffffffffffffffff
99#|0aceab0fc6a0a28d 0123456789abcdef
100#|f9ad597c49db005e fedcba9876543210
101#|e9c2b70a1bc65cf3 fedcba9876543210
102#|05044b62fa52d080 fedcba9876543210
103#|d9e0b4045974d5f0 ok
104# END GENERATED: check