pbkdf2.bend
bend-osdev-crypto@0.1.0.0 · 118 lines · 12 definitions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25import Base
26import bend-osdev-bytes@0.1.0.0/bytes.bend as B
27import bend-osdev-crypto@0.1.0.0/crypto.bend as Cr
28
29
30def cr.pbkdf2.xor(xs: List<&2, U32>, ys: List<&2, U32>) -> List<&2, U32>:
31 match xs ys:
32 case Con{x, xt} Con{y, yt}:
33 Con{U32.xor(x, y), cr.pbkdf2.xor(xt, yt)}
34 case _ _:
35 Nil{}
36
37
38def cr.pbkdf2.chain(~K: Data, ~compute: K -> B.Octets -> B.Octets, c: Nat, +k: K, u: B.Octets, acc: List<&2, U32>) -> List<&2, U32>:
39 match c:
40 case 0n:
41 acc
42 case 1n+p:
43 +u2 = compute(k, u)
44 cr.pbkdf2.chain(~K, ~compute, p, k, u2, cr.pbkdf2.xor(acc, B.Octets.to_list(u2)))
45
46
47def cr.pbkdf2.block(~K: Data, ~compute: K -> B.Octets -> B.Octets, +k: K, salt: B.Octets, c: Nat, i: U32) -> List<&2, U32>:
48 +u1 = compute(k, B.Octets.append(salt, B.Octets.be32(i)))
49 cr.pbkdf2.chain(~K, ~compute, c, k, u1, B.Octets.to_list(u1))
50
51def cr.pbkdf2.head(xs: List<&2, U32>) -> U32:
52 match xs:
53 case Con{h, t}:
54 h
55 case Nil{}:
56 0
57
58def cr.pbkdf2.tail(xs: List<&2, U32>) -> List<&2, U32>:
59 match xs:
60 case Con{h, t}:
61 t
62 case Nil{}:
63 Nil{}
64
65
66
67def cr.pbkdf2.out(~K: Data, ~compute: K -> B.Octets -> B.Octets, n: Nat, cur: List<&2, U32>, +k: K, +salt: B.Octets, +c: Nat, +i: U32) -> List<&2, U32>:
68 match n:
69 case 0n:
70 Nil{}
71 case 1n+p:
72 match cur:
73 case Con{h, t}:
74 Con{h, cr.pbkdf2.out(~K, ~compute, p, t, k, salt, c, i)}
75 case Nil{}:
76 +blk = cr.pbkdf2.block(~K, ~compute, k, salt, c, U32.add(i, 1))
77 Con{cr.pbkdf2.head(blk), cr.pbkdf2.out(~K, ~compute, p, cr.pbkdf2.tail(blk), k, salt, c, U32.add(i, 1))}
78
79
80
81
82def CrPbkdf2.stream(~K: Data, ~compute: K -> B.Octets -> B.Octets, k: K, salt: B.Octets, c: U32, n: Nat) -> B.Octets:
83 B.Octets.of_list(cr.pbkdf2.out(~K, ~compute, n, Nil{}, k, salt, Nat.sub(U32.to_nat(c), 1n), 0))
84
85def cr.pbkdf2.key(~K: Data, ~compute: K -> B.Octets -> B.Octets, kr: Result<&2, &2, Cr.CrError, K>, salt: B.Octets, c: U32, n: Nat) -> Result<&2, &2, Cr.CrError, B.Octets>:
86 match kr:
87 case Fail{e}:
88 Fail{e}
89 case Done{k}:
90 Done{CrPbkdf2.stream(~K, ~compute, k, salt, c, n)}
91
92def cr.pbkdf2.checked(~K: Data, ~compute: K -> B.Octets -> B.Octets, zero: Bool, fits: Bool, kr: Result<&2, &2, Cr.CrError, K>, salt: B.Octets, c: U32, +n: Nat) -> Result<&2, &2, Cr.CrError, B.Octets>:
93 match zero:
94 case True{}:
95 Fail{Cr.CrTooShort{0n}}
96 case False{}:
97 match fits:
98 case False{}:
99 Fail{Cr.CrBadOutputLength{n}}
100 case True{}:
101 cr.pbkdf2.key(~K, ~compute, kr, salt, c, n)
102
103def cr.pbkdf2.fits(pos: Bool, +n: Nat, +hlen: Nat) -> Bool:
104 match pos:
105 case True{}:
106 Nat.is_le(Nat.div(Nat.add(n, Nat.sub(hlen, 1n)), hlen), 4294967295n)
107 case False{}:
108 False{}
109
110
111
112def CrPbkdf2.pbkdf2(~K: Data, ~key: B.Octets -> Result<&2, &2, Cr.CrError, K>, ~compute: K -> B.Octets -> B.Octets, ~hlen: Nat, password: B.Octets, salt: B.Octets, +c: U32, +n: Nat) -> Result<&2, &2, Cr.CrError, B.Octets>:
113 cr.pbkdf2.checked(~K, ~compute, U32.is_eq(c, 0), cr.pbkdf2.fits(Nat.is_lt(0n, hlen), n, hlen), key(password), salt, c, n)
114
115
116
117def CrPbkdf2.derive(~K: Data, ~key: B.Octets -> Result<&2, &2, Cr.CrError, K>, ~compute: K -> B.Octets -> B.Octets, ~hlen: Nat, ~c: U32, secret: B.Octets, salt: B.Octets, info: B.Octets, n: Nat) -> Result<&2, &2, Cr.CrError, B.Octets>:
118 CrPbkdf2.pbkdf2(~K, ~key, ~compute, ~hlen, secret, salt, c, n)