Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP]: Rsa keygen #733

Closed
wants to merge 20 commits into from
Closed

[WIP]: Rsa keygen #733

wants to merge 20 commits into from

Conversation

est31
Copy link

@est31 est31 commented Dec 6, 2018

Opened the PR so that I can discuss with @briansmith about the code. Nothing works yet. DON'T MERGE!

List of tasks:

  • Implement division by small primes as suggested here
  • Implement miller-rabin primality test based on FIPS 186-4 C.3.1
  • Tests for the miller-rabin primality test
  • Implement FIPS 186-4 section B 3.3 algorithm to obtain (p,q) prime pair
  • Use (p,q) to create the needed p,q,dP,dQ,qInv,r_i,d_i,t_i
  • DER formatting of the created key
  • Implement primitive for multiplication
  • Implement primitive for inverse modulo m

Important reading:

Fixes #219

@est31 est31 changed the title [WIP]: Rsa keygen new [WIP]: Rsa keygen Dec 6, 2018
@est31 est31 force-pushed the rsa_keygen_new branch 2 times, most recently from c6005ff to 9cd2288 Compare December 6, 2018 08:13
for _ in 1 .. a {
// Step 4.5.1
// TODO figure out how to make this compile
//z_elem = bigint::elem_squared(z_elem, &w_modulus.as_partial());
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@briansmith do you know how this can be made compile? Right now I'm getting sth like:

  --> src/rsa/key_generation.rs:87:22                                                                                  
   |                                                                                                                   
87 |             z_elem = bigint::elem_squared(z_elem, &w_modulus.as_partial());                                       
   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `arithmetic::montgomery::Unencoded`, found enum `arithmetic::montgomery::RInverse`
   |                                                                                                                   
   = note: expected type `rsa::bigint::Elem<_, arithmetic::montgomery::Unencoded>`                                     
              found type `rsa::bigint::Elem<_, arithmetic::montgomery::RInverse>` 

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now: multiply z_elem by w_modulus.oneRR before the loop.

Later: Refactor elem_exp_consttime so that it returns an Elem<R> instead of Elem<Unencoded> by moving the into_unencoded() to the caller.

* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.] */
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a commit that removes all the code from this file, and the other new imported files, that you didn't use.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it okay if I do that once I'm done with the PR? Don't know what else will be needed from the files :).

@@ -370,4 +368,20 @@ static inline uint64_t from_be_u64(uint64_t x) {
return x;
}

static inline void *OPENSSL_memmove(void *dst, const void *src, size_t n) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everywhere you see OPENSSL_memmove and OPENSSL_memset being used, just use memmove and memset.

@@ -99,6 +99,11 @@ Limb LIMBS_less_than_limb(const Limb a[], Limb b, size_t num_limbs) {
return constant_time_select_w(lo, hi, lo);
}

void LIMBS_sub_limb(Limb r[], const Limb a[], const Limb b,
size_t num_limbs) {
limbs_sub_limb(r, a, b, num_limbs);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replace this with

void LIMBS_odd_sub_one(Limb r[], size_t num_limbs) {
    assert(num_limbs > 0);
    assert(!LIMBS_are_even(r, num_limbs));
    r[0] &= ~1;
}

src/limb.rs Outdated
}

#[cfg(feature = "rsa_keygen")]
pub fn limbs_copy(r: &mut [Limb], a: &[Limb]) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can do the copying in pure Rust code. (In ring, we can copy secret values from one place to another in Rust, we just don't do any arithmetic in Rust get.)

src/limb.rs Outdated


#[cfg(feature = "rsa_keygen")]
pub fn limbs_rshift(r: &mut [Limb], n: u16) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should have secret_shift in the name.

@@ -67,7 +67,7 @@ struct Width<M> {
}

/// All `BoxedLimbs<M>` are stored in the same number of limbs.
struct BoxedLimbs<M> {
pub struct BoxedLimbs<M> {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make the primality test code a submodule of bigint so that we don't need to increase the visibility of things in bigint.

@@ -0,0 +1,147 @@
// Copyright 2018 Brian Smith.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you copied some of my code, please keep this copyright line. Please add your own copyright line.

/// Implementation of the algorithm as it
/// is described in FIPS 186-4 C.3.1
fn miller_rabin_test(
w: &[u64],
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have written this whole thing in terms of Limb but it would be a lot clearer to write it in terms of bigint::Nonnegative, I think.

// Step 1.
let mut w_m1 = vec![0; w.len()];
limb::limbs_sub_limb(&mut w_m1, w, 1);
let a = limb::limbs_count_low_zero_bits(&w_m1);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// for w: &Nonnegative
let w_minus_1 = w.odd_minus_1()?;
let a = w.trailing_zeros();

// preparation
let boxed_w = bigint::BoxedLimbs::<()>::minimal_width_from_unpadded(&w);
let w_modulus = bigint::Modulus::from_boxed_limbs(boxed_w)?.0;
let boxed_m = bigint::BoxedLimbs::<()>::minimal_width_from_unpadded(&m);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see Modulus::from_nonnegative_with_bit_length().

unsafe {
let b_mut_ptr = (&mut b[..]).as_mut_ptr() as * mut u8;
let b_mut_slice = core::slice::from_raw_parts_mut(b_mut_ptr, b.len() * 8);
rng.fill(b_mut_slice)?;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be factored out into a impl Elem { fn random(rng: &SecureRandom) -> Result<Self, error::Unspecified> } method.

// TODO figure out how to make this compile
//z_elem = bigint::elem_squared(z_elem, &w_modulus.as_partial());
// Step 4.5.2
if limb::limbs_equal_limbs_consttime(&z_elem.limbs, &w_m1) == LimbMask::True {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You will need to convert w_m1 to an Elem<W> and then use the Elem comparison functions.

continue;
}
// Step 4.5.1
if z_elem.is_one() {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You will need to create a value oneR: Elem<W, R> with value 1 * w_modulus.oneRR and then compare using the element comparison functions.

///
/// Implementation of the algorithm as it
/// is described in FIPS 186-4 C.3.1
fn miller_rabin_test(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this function's type should be something like like fn miller_rabin_test<M: Prime>(w: Nonnegative, iterations: u32, rng: &SecureRandom) -> Result<Modulus<M>, error::Unspecified>.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What should the returned modulus contain? Will we need that value somewhere? To me it seems that only bool yes/no output is needed.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What should the returned modulus contain? Will we need that value somewhere? To me it seems that only bool yes/no output is needed.

At least, for example, we need to calculate q**-1 (mod p) to construct the RSA key. IIUC, this function already constructs the Modulus for the prime so we might as well return it. OTOH, if the function doesn't end up constructing the Modulus already then we can just return a ().

@briansmith
Copy link
Owner

briansmith commented Dec 6, 2018

OK, I can see now that this is going to be a lot of work from both of us. Before we do any more work, let's clarify the IPR part:

  1. Who is the copyright holder for new the code that contributing? Please add the Copyright lines that says who the copyright holder is, to the tops of the files with new code before we continue.
  2. Do you have the permission of the copyright holder to contribute this code?
  3. Please add the contributor statement at https://github.com/briansmith/ring#contributing to the end of every commit message (you can skip the ones that only add unmodified BoringSSL code).

@briansmith
Copy link
Owner

briansmith commented Dec 6, 2018

In order for me to effectively review this code, we need to refactor it into at least two parts: low-level routines and high-level routines. The M-R test itself should be a high-level routine that takes a Nonnegative, does some operations on Nonnegatives, Elems, and Moduluss, and returns a Modulus. There probably should not be any mention of Limb or u64 in the M-R code at all.

Anything that deals with Limb or &[Limb] or BoxedLimbs needs to be encapsulated in a new extension of the bigint API. For example, subtracting 1 from an odd number m to produce an even m - 1 needs to be a method of Nonnegative. Counting the trailing zeros of a Nonnegative needs to be a method of Nonnegative. When possible, use the standard Rust names for these functions, e.g. trailing_zeros().

@est31 est31 force-pushed the rsa_keygen_new branch 2 times, most recently from f4a92ba to 6e0cdf1 Compare December 7, 2018 10:28
@est31
Copy link
Author

est31 commented Dec 7, 2018

Ready again for review @briansmith .

@est31 est31 force-pushed the rsa_keygen_new branch 3 times, most recently from 34aa5c3 to 97f3c18 Compare December 9, 2018 15:37
@est31
Copy link
Author

est31 commented Dec 9, 2018

Rebased. ATM blocked on getting advice: #219 (comment)

I agree to license my contributions to each file under the terms given
at the top of each file I changed.
I agree to license my contributions to each file under the terms given
at the top of each file I changed.
We still need to do a few more checks to generate
the (p,q) primes in a valid fashion.

I agree to license my contributions to each file under the terms given
at the top of each file I changed.
I agree to license my contributions to each file under the terms given
at the top of each file I changed.
I agree to license my contributions to each file under the terms given
at the top of each file I changed.
I agree to license my contributions to each file under the terms given
at the top of each file I changed.
Some lower level stuff is still left TODO.

I agree to license my contributions to each file under the terms given
at the top of each file I changed.
I agree to license my contributions to each file under the terms given
at the top of each file I changed.
@est31
Copy link
Author

est31 commented Dec 25, 2018

Rebased. Multiplication still left to do, waiting on input by @briansmith .

I agree to license my contributions to each file under the terms given
at the top of each file I changed.
@est31
Copy link
Author

est31 commented Jan 1, 2019

@briansmith any news? you said:

I can probably come up with a special case thing for the N = P * Q calculation.

I stopped my work on porting the multiplication functions due to that, waiting for your input. Should I continue?

@briansmith
Copy link
Owner

I stopped my work on porting the multiplication functions due to that, waiting for your input. Should I continue?

I don't know when I'll be able to write the multiplication code. It is fine to use bn_mul_normal from BoringSSL in the meantime if that would unblock you.

@est31
Copy link
Author

est31 commented Jan 2, 2019

Thanks for the info. You have a concrete idea how to implement it. That's great to hear! I guess I'll wait then.

@briansmith
Copy link
Owner

For future reference: https://eprint.iacr.org/2018/367.pdf

@briansmith
Copy link
Owner

@est31 Are you planning to finish this? If so, please email me at brian@briansmith.org to discuss the IPR stuff. Otherwise, let's just close this.

@est31
Copy link
Author

est31 commented Feb 9, 2019

@briansmith no my intention is not to close this PR. I've put already a ton of time into it and closing would mean that the time was wasted which I don't want it to be. I've also sent you an E-Mail.

@briansmith
Copy link
Owner

Regarding the divisibility check, check out section "3.2 Fast Divisibility Check with a Single Multiplication" in https://arxiv.org/pdf/1902.01961.pdf. Note in particular that reference [5] may or may not a better starting point than the new method that paper presents.

@est31
Copy link
Author

est31 commented Feb 14, 2019

@briansmith do you think I need to implement that before merging? Otherwise I'd leave it as a post-merge project.

@est31
Copy link
Author

est31 commented Feb 23, 2019

@briansmith is the IPR stuff cleared now? I haven't gotten any E-Mail replies.

@est31
Copy link
Author

est31 commented Sep 4, 2019

Still no reaction...

So now I stand before the choice of bumping this yet again, waiting more time, or simply closing for being ghosted by the maintainer. I choose to close it, because I'm doubtful it'll ever be merged: At the start of this PR, it got tons of reactions by the maintainer and judging from that the general view was that this feature is wanted and the PR welcome. The atmosphere was quite positive until this comment which suggested to close the PR without any reason. It took me quite by surprise because I was waiting for @briansmith to contribute their part like they said above, and now I'm expected to finish it while the IPR situation is still not clear. There has neither been a yes nor a no in all the months since that communication and this kind of treatment is simply not okay. Also, given that I have invested so much time into my PR, the suggestion to "just close this" is quite insulting.

Of course, ultimately it's their project and up to them to accept or reject stuff.

I've considered closing this multiple times already but every time I stopped in the last moment, hoping that maybe if I wait a little there'd be a reply or something. After all I'm throwing away a ton of work and invested time here. What a shame :/.

In retrospect, I probably shouldn't have started this project without previously doing smaller PRs to change readmes or whatever to probe how receptive the maintainer is. I used to do this but in this case, I let my guard down. My fault. Ultimately, I don't need RSA keygen as much as I used to, as I made it for rcgen which is using multiple other encryption algorithms now. But it would still have been cool to have contributed such a major thing to a crypto library.

That your contribution gets rejected is always a risk of open source but it still hurts every time, especially as I have spent a good deal of time with it. Time to move on.

PS: For all the people who want to add RSA key generation support, first a warning. I don't know why the maintainer has ghosted me, maybe it's because of IPR, maybe it's because the maintainer doesn't like RSA and hopes to be able to wait until RSA is deprecated, never having to worry about key generation at all. Who knows what the reason is. So before you waste time, please make sure you are ready to take the risk of your change being rejected like my PR was. I also suggest not looking at my PR or building onto it unless there are confirmations by the maintainer that this is okay (I'd personally be okay with it). Sorry that I couldn't help you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add RSA key generation
2 participants