diff --git a/src/assets.ml b/src/assets.ml index 1826b27e..9313ee49 100644 --- a/src/assets.ml +++ b/src/assets.ml @@ -1,5 +1,4 @@ (* https://docs.taler.net/design-documents/003-tos-rendering.html - https://docs.taler.net/design-documents/003-tos-rendering.html must support `text/plain` and `text/markdown` *) diff --git a/src/crypto.ml b/src/crypto.ml index e43727e0..6e2d12fa 100644 --- a/src/crypto.ml +++ b/src/crypto.ml @@ -281,58 +281,101 @@ type denomination_hash = Hash.DenominationHash.t (* WIP *) module FDH_RSA = struct + open Mirage_crypto_pk + module Kdf = struct module XTR = Hkdf.Make (Digestif.SHA512) module PRF = Hkdf.Make (Digestif.SHA256) - let kdf ~xts ~ikm ~ctx ~len = + let kdf = + fun ~xts ~ikm ~ctx ~len -> let prk = XTR.extract ~salt:xts ikm in let okm = PRF.expand ~prk ~info:ctx len in okm + + let kdf_mod_n ~n ~xts ~ikm ~ctx = + let nbits = Z.numbits n in + let len = ((nbits - 1) / 8) + 1 in + assert (8 * len = nbits); + let rec go ctr = + (* cat ctx ctr_be *) + let ctx = + let ctx_len = String.length ctx in + let b = Bytes.create (ctx_len + 2) in + Bytes.blit_string ctx 0 b 0 ctx_len; + Bytes.set_uint16_be b ctx_len ctr; + Bytes.unsafe_to_string b + in + let okm = kdf ~xts ~ikm ~ctx ~len in + assert (String.length okm = len); + let r = Z_extra.of_octets_be okm in + if Z.gt r n then go (succ ctr) else r + in + go 0 end - let kdf_mod_n ~n ~xts ~ikm ~ctx = - let nbits = Z.numbits n in - let len = ((nbits - 1) / 8) + 1 in - assert (8 * len = nbits); - let rec go ctr = - let ctr_be = - let b = Bytes.create 2 in - Bytes.set_uint16_be b 0 ctr; - Bytes.unsafe_to_string b - in - let ctx = String.cat ctx ctr_be in - let okm = Kdf.kdf ~xts ~ikm ~ctx ~len in - assert (String.length okm = len); - let r = Mirage_crypto_pk.Z_extra.of_octets_be okm in - if Z.gt r n then go (succ ctr) else r - in - go 0 + let gcd_validate r n = + match Z.equal (Z.gcd r n) Z.one with + | true -> () + | false -> Fmt.failwith "RSA key is malicious" let rsa_full_domain_hash pub msg = let xts = RsaPublicKey.to_octets pub in let ctx = "RSA-FDA FTpsW!" in - let r = kdf_mod_n ~n:pub.n ~xts ~ikm:msg ~ctx in - r + let r = Kdf.kdf_mod_n ~n:pub.n ~xts ~ikm:msg ~ctx in + gcd_validate r pub.n; r let rsa_blinding_key_derive (pub : RsaPublicKey.t) bks = let xts = "Blinding KDF extractor HMAC key" in let ctx = "Blinding KDF" in - let r = kdf_mod_n ~n:pub.n ~xts ~ikm:bks ~ctx in - r + let r = Kdf.kdf_mod_n ~n:pub.n ~xts ~ikm:bks ~ctx in + gcd_validate r pub.n; r let rsa_blind pub ~bks ~msg = let data = rsa_full_domain_hash pub msg in let bkey = rsa_blinding_key_derive pub bks in - let r_e = Z.powm bkey pub.e pub.n in + (* can we just use [powm] here instead? *) + let r_e = Z.powm_sec bkey pub.e pub.n in let data_r_e = Z.rem (Z.mul data r_e) pub.n in - Mirage_crypto_pk.Z_extra.to_octets_be data_r_e + Z_extra.to_octets_be data_r_e - (* -let rsa_sign_fdh priv msg = - let pub = Mirage_crypto_pk.Rsa.pub_of_priv priv in - let v = rsa_full_domain_hash pub msg in - let v = Z.to_bits v in - Mirage_crypto_pk.Rsa.PKCS1.sig_encode ~crt_hardening:true ~key:priv v - *) + (* -- WIP crypto -- *) + + (* TODO crypto + not sure about signature scheme used by taler + libgnunetutil crypto_rsa.c use "(flags raw)" => no padding *) + (* decrypt <=> sign *) + let rsa_sign_z priv r = + let data = Z_extra.to_octets_be r in + Rsa.decrypt ~crt_hardening:true ~key:priv data + + (* TODO crypto + look into mirage-crypto for this + use Eqaf for constant time string compare *) + let rsa_verify_z pub r sig_ = + let data = Z_extra.to_octets_be r in + let sig_' = Rsa.encrypt ~key:pub data in + match String.equal sig_ sig_' with + | false -> Fmt.error "RSA signature verification failed" + | true -> Ok () + + let rsa_sign_fdh priv msg = + let pub = Rsa.pub_of_priv priv in + let r = rsa_full_domain_hash pub msg in + rsa_sign_z priv r + + let rsa_unblind pub ~bks ~sig_ = + let bkey = rsa_blinding_key_derive pub bks in + let r_inv = + try Z.invert bkey pub.n + with Division_by_zero -> + (* => gcd(r,n) <> 1, should be already checked for *) + assert false + in + let ubsig = Z.rem (Z.mul sig_ r_inv) pub.n in + ubsig + + let rsa_verify pub ~msg ~sig_ = + let r = rsa_full_domain_hash pub msg in + rsa_verify_z pub r sig_ end diff --git a/test/crypto.ml b/test/crypto.ml index bdf2cd95..0dbf2a02 100644 --- a/test/crypto.ml +++ b/test/crypto.ml @@ -96,6 +96,8 @@ let () = () let () = + (* rsa blinding *) + (* rsa_private_key data is given in gcrypt sexpr format.. *) let message_hash = "XKQMJ4CNTXBFE1V2WR6JS063J7PZQE4XMB5JH3RS5X0THQ1JQSQ69Y7KDBC9TYRJEZH48MEPY2SF4QHQ4VHXC0YQX5935MQEGP0AX6R" in