···3030(** Group prime N *)
3131let n = Z.of_string_base 16 n_hex
32323333+(** Length of N in bytes *)
3434+let n_len = (Z.numbits n + 7) / 8
3535+3336(** {1 Utility Functions} *)
34373538(** Hash data using SHA-512 *)
···6265 if pad > 0 && String.length s < pad then
6366 String.make (pad - String.length s) '\x00' ^ s
6467 else s
6868+6969+(** Pad a Z value to n_len bytes *)
7070+let pad_z z = bytes_of_z ~pad:n_len z
7171+7272+(** XOR of H(N) and H(g), used in proof computation *)
7373+let hash_xor_ng =
7474+ let h_n = hash (bytes_of_z n) in
7575+ let h_g = hash (bytes_of_z g) in
7676+ String.init (String.length h_n) (fun i ->
7777+ Char.chr (Char.code h_n.[i] lxor Char.code h_g.[i]))
65786679(** Compute k = H(N | PAD(g)) *)
6780let compute_k () =
···98111 let public_key t = t.big_a
99112100113 let compute_session_key t ~salt ~big_b =
101101- if Z.(equal (big_b mod n) zero) then Error (`Msg "Invalid B value")
102102- else
103103- let k = compute_k () in
104104- let n_len = (Z.numbits n + 7) / 8 in
105105- let a_pad = bytes_of_z ~pad:n_len t.big_a in
106106- let b_pad = bytes_of_z ~pad:n_len big_b in
107107- let u = z_of_bytes (hash (a_pad ^ b_pad)) in
108108- if Z.(equal u zero) then Error (`Msg "Invalid u value")
109109- else
110110- let x = compute_x ~salt ~username:t.username ~password:t.password in
111111- (* S = (B - k * g^x)^(a + u * x) mod N *)
112112- let base = Z.((big_b - (k * powm g x n)) mod n) in
113113- let base = if Z.(lt base zero) then Z.(base + n) else base in
114114- let exp = Z.((t.a + (u * x)) mod (n - one)) in
115115- let s = Z.powm base exp n in
116116- let session_key = hash (bytes_of_z s) in
117117- Ok session_key
114114+ let ( let* ) = Result.bind in
115115+ let* () =
116116+ if Z.(equal (big_b mod n) zero) then Error (`Msg "Invalid B value")
117117+ else Ok ()
118118+ in
119119+ let k = compute_k () in
120120+ let u = z_of_bytes (hash (pad_z t.big_a ^ pad_z big_b)) in
121121+ let* () =
122122+ if Z.(equal u zero) then Error (`Msg "Invalid u value") else Ok ()
123123+ in
124124+ let x = compute_x ~salt ~username:t.username ~password:t.password in
125125+ (* S = (B - k * g^x)^(a + u * x) mod N *)
126126+ let base = Z.((big_b - (k * powm g x n)) mod n) in
127127+ let base = if Z.(lt base zero) then Z.(base + n) else base in
128128+ let exp = Z.((t.a + (u * x)) mod (n - one)) in
129129+ let s = Z.powm base exp n in
130130+ Ok (hash (bytes_of_z s))
118131119132 let compute_proof t ~salt ~big_b ~session_key =
120120- let h_n = hash (bytes_of_z n) in
121121- let h_g = hash (bytes_of_z g) in
122122- let h_xor =
123123- String.init (String.length h_n) (fun i ->
124124- Char.chr (Char.code h_n.[i] lxor Char.code h_g.[i]))
125125- in
126133 let h_user = hash t.username in
127127- let n_len = (Z.numbits n + 7) / 8 in
128134 hash
129129- (h_xor ^ h_user ^ salt
130130- ^ bytes_of_z ~pad:n_len t.big_a
131131- ^ bytes_of_z ~pad:n_len big_b
132132- ^ session_key)
135135+ (hash_xor_ng ^ h_user ^ salt ^ pad_z t.big_a ^ pad_z big_b ^ session_key)
133136134137 let verify_proof t ~m1 ~m2 ~session_key =
135135- let n_len = (Z.numbits n + 7) / 8 in
136136- let expected = hash (bytes_of_z ~pad:n_len t.big_a ^ m1 ^ session_key) in
138138+ let expected = hash (pad_z t.big_a ^ m1 ^ session_key) in
137139 String.equal expected m2
138140end
139141···159161 let salt t = t.salt
160162161163 let compute_session_key t ~big_a =
162162- if Z.(equal (big_a mod n) zero) then Error (`Msg "Invalid A value")
163163- else
164164- let n_len = (Z.numbits n + 7) / 8 in
165165- let a_pad = bytes_of_z ~pad:n_len big_a in
166166- let b_pad = bytes_of_z ~pad:n_len t.big_b in
167167- let u = z_of_bytes (hash (a_pad ^ b_pad)) in
168168- if Z.(equal u zero) then Error (`Msg "Invalid u value")
169169- else
170170- (* S = (A * v^u)^b mod N *)
171171- let s = Z.(powm (big_a * powm t.verifier u n) t.b n) in
172172- let session_key = hash (bytes_of_z s) in
173173- Ok session_key
164164+ let ( let* ) = Result.bind in
165165+ let* () =
166166+ if Z.(equal (big_a mod n) zero) then Error (`Msg "Invalid A value")
167167+ else Ok ()
168168+ in
169169+ let u = z_of_bytes (hash (pad_z big_a ^ pad_z t.big_b)) in
170170+ let* () =
171171+ if Z.(equal u zero) then Error (`Msg "Invalid u value") else Ok ()
172172+ in
173173+ (* S = (A * v^u)^b mod N *)
174174+ let s = Z.(powm (big_a * powm t.verifier u n) t.b n) in
175175+ Ok (hash (bytes_of_z s))
174176175177 let verify_proof t ~big_a ~m1 ~session_key =
176176- let h_n = hash (bytes_of_z n) in
177177- let h_g = hash (bytes_of_z g) in
178178- let h_xor =
179179- String.init (String.length h_n) (fun i ->
180180- Char.chr (Char.code h_n.[i] lxor Char.code h_g.[i]))
181181- in
182178 let h_user = hash t.username in
183183- let n_len = (Z.numbits n + 7) / 8 in
184179 let expected =
185180 hash
186186- (h_xor ^ h_user ^ t.salt
187187- ^ bytes_of_z ~pad:n_len big_a
188188- ^ bytes_of_z ~pad:n_len t.big_b
189189- ^ session_key)
181181+ (hash_xor_ng ^ h_user ^ t.salt ^ pad_z big_a ^ pad_z t.big_b
182182+ ^ session_key)
190183 in
191184 String.equal expected m1
192185193186 let compute_proof _t ~big_a ~m1 ~session_key =
194194- let n_len = (Z.numbits n + 7) / 8 in
195195- hash (bytes_of_z ~pad:n_len big_a ^ m1 ^ session_key)
187187+ hash (pad_z big_a ^ m1 ^ session_key)
196188end