• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 Brian Smith.
2 //
3 // Permission to use, copy, modify, and/or distribute this software for any
4 // purpose with or without fee is hereby granted, provided that the above
5 // copyright notice and this permission notice appear in all copies.
6 //
7 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
8 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
10 // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 
15 //! Functionality shared by operations on private keys (ECC keygen and
16 //! ECDSA signing).
17 
18 use super::{ops::*, verify_affine_point_is_on_the_curve};
19 use crate::{
20     arithmetic::montgomery::R,
21     ec, error,
22     limb::{self, LIMB_BYTES},
23     rand,
24 };
25 
26 /// Generates a random scalar in the range [1, n).
random_scalar( ops: &PrivateKeyOps, rng: &dyn rand::SecureRandom, ) -> Result<Scalar, error::Unspecified>27 pub fn random_scalar(
28     ops: &PrivateKeyOps,
29     rng: &dyn rand::SecureRandom,
30 ) -> Result<Scalar, error::Unspecified> {
31     let num_limbs = ops.common.num_limbs;
32     let mut bytes = [0; ec::SCALAR_MAX_BYTES];
33     let bytes = &mut bytes[..(num_limbs * LIMB_BYTES)];
34     generate_private_scalar_bytes(ops, rng, bytes)?;
35     scalar_from_big_endian_bytes(ops, bytes)
36 }
37 
generate_private_scalar_bytes( ops: &PrivateKeyOps, rng: &dyn rand::SecureRandom, out: &mut [u8], ) -> Result<(), error::Unspecified>38 pub fn generate_private_scalar_bytes(
39     ops: &PrivateKeyOps,
40     rng: &dyn rand::SecureRandom,
41     out: &mut [u8],
42 ) -> Result<(), error::Unspecified> {
43     // [NSA Suite B Implementer's Guide to ECDSA] Appendix A.1.2, and
44     // [NSA Suite B Implementer's Guide to NIST SP 800-56A] Appendix B.2,
45     // "Key Pair Generation by Testing Candidates".
46     //
47     // [NSA Suite B Implementer's Guide to ECDSA]: doc/ecdsa.pdf.
48     // [NSA Suite B Implementer's Guide to NIST SP 800-56A]: doc/ecdh.pdf.
49 
50     // TODO: The NSA guide also suggests, in appendix B.1, another mechanism
51     // that would avoid the need to use `rng.fill()` more than once. It works
52     // by generating an extra 64 bits of random bytes and then reducing the
53     // output (mod n). Supposedly, this removes enough of the bias towards
54     // small values from the modular reduction, but it isn't obvious that it is
55     // sufficient. TODO: Figure out what we can do to mitigate the bias issue
56     // and switch to the other mechanism.
57 
58     let candidate = out;
59 
60     // XXX: The value 100 was chosen to match OpenSSL due to uncertainty of
61     // what specific value would be better, but it seems bad to try 100 times.
62     for _ in 0..100 {
63         // NSA Guide Steps 1, 2, and 3.
64         //
65         // Since we calculate the length ourselves, it is pointless to check
66         // it, since we can only check it by doing the same calculation.
67 
68         // NSA Guide Step 4.
69         //
70         // The requirement that the random number generator has the
71         // requested security strength is delegated to `rng`.
72         rng.fill(candidate)?;
73 
74         // NSA Guide Steps 5, 6, and 7.
75         if check_scalar_big_endian_bytes(ops, candidate).is_err() {
76             continue;
77         }
78 
79         // NSA Guide Step 8 is done in `public_from_private()`.
80 
81         // NSA Guide Step 9.
82         return Ok(());
83     }
84 
85     Err(error::Unspecified)
86 }
87 
88 // The underlying X25519 and Ed25519 code uses an [u8; 32] to store the private
89 // key. To make the ECDH and ECDSA code similar to that, we also store the
90 // private key that way, which means we have to convert it to a Scalar whenever
91 // we need to use it.
92 #[inline]
private_key_as_scalar(ops: &PrivateKeyOps, private_key: &ec::Seed) -> Scalar93 pub fn private_key_as_scalar(ops: &PrivateKeyOps, private_key: &ec::Seed) -> Scalar {
94     // This cannot fail because we know the private key is valid.
95     scalar_from_big_endian_bytes(ops, private_key.bytes_less_safe()).unwrap()
96 }
97 
check_scalar_big_endian_bytes( ops: &PrivateKeyOps, bytes: &[u8], ) -> Result<(), error::Unspecified>98 pub fn check_scalar_big_endian_bytes(
99     ops: &PrivateKeyOps,
100     bytes: &[u8],
101 ) -> Result<(), error::Unspecified> {
102     debug_assert_eq!(bytes.len(), ops.common.num_limbs * LIMB_BYTES);
103     scalar_from_big_endian_bytes(ops, bytes).map(|_| ())
104 }
105 
106 // Parses a fixed-length (zero-padded) big-endian-encoded scalar in the range
107 // [1, n). This is constant-time with respect to the actual value *only if* the
108 // value is actually in range. In other words, this won't leak anything about a
109 // valid value, but it might leak small amounts of information about an invalid
110 // value (which constraint it failed).
scalar_from_big_endian_bytes( ops: &PrivateKeyOps, bytes: &[u8], ) -> Result<Scalar, error::Unspecified>111 pub fn scalar_from_big_endian_bytes(
112     ops: &PrivateKeyOps,
113     bytes: &[u8],
114 ) -> Result<Scalar, error::Unspecified> {
115     // [NSA Suite B Implementer's Guide to ECDSA] Appendix A.1.2, and
116     // [NSA Suite B Implementer's Guide to NIST SP 800-56A] Appendix B.2,
117     // "Key Pair Generation by Testing Candidates".
118     //
119     // [NSA Suite B Implementer's Guide to ECDSA]: doc/ecdsa.pdf.
120     // [NSA Suite B Implementer's Guide to NIST SP 800-56A]: doc/ecdh.pdf.
121     //
122     // Steps 5, 6, and 7.
123     //
124     // XXX: The NSA guide says that we should verify that the random scalar is
125     // in the range [0, n - 1) and then add one to it so that it is in the range
126     // [1, n). Instead, we verify that the scalar is in the range [1, n). This
127     // way, we avoid needing to compute or store the value (n - 1), we avoid the
128     // need to implement a function to add one to a scalar, and we avoid needing
129     // to convert the scalar back into an array of bytes.
130     scalar_parse_big_endian_fixed_consttime(ops.common, untrusted::Input::from(bytes))
131 }
132 
public_from_private( ops: &PrivateKeyOps, public_out: &mut [u8], my_private_key: &ec::Seed, ) -> Result<(), error::Unspecified>133 pub fn public_from_private(
134     ops: &PrivateKeyOps,
135     public_out: &mut [u8],
136     my_private_key: &ec::Seed,
137 ) -> Result<(), error::Unspecified> {
138     let elem_and_scalar_bytes = ops.common.num_limbs * LIMB_BYTES;
139     debug_assert_eq!(public_out.len(), 1 + (2 * elem_and_scalar_bytes));
140     let my_private_key = private_key_as_scalar(ops, my_private_key);
141     let my_public_key = ops.point_mul_base(&my_private_key);
142     public_out[0] = 4; // Uncompressed encoding.
143     let (x_out, y_out) = (&mut public_out[1..]).split_at_mut(elem_and_scalar_bytes);
144 
145     // `big_endian_affine_from_jacobian` verifies that the point is not at
146     // infinity and is on the curve.
147     big_endian_affine_from_jacobian(ops, Some(x_out), Some(y_out), &my_public_key)
148 }
149 
affine_from_jacobian( ops: &PrivateKeyOps, p: &Point, ) -> Result<(Elem<R>, Elem<R>), error::Unspecified>150 pub fn affine_from_jacobian(
151     ops: &PrivateKeyOps,
152     p: &Point,
153 ) -> Result<(Elem<R>, Elem<R>), error::Unspecified> {
154     let z = ops.common.point_z(p);
155 
156     // Since we restrict our private key to the range [1, n), the curve has
157     // prime order, and we verify that the peer's point is on the curve,
158     // there's no way that the result can be at infinity. But, use `assert!`
159     // instead of `debug_assert!` anyway
160     assert!(ops.common.elem_verify_is_not_zero(&z).is_ok());
161 
162     let x = ops.common.point_x(p);
163     let y = ops.common.point_y(p);
164 
165     let zz_inv = ops.elem_inverse_squared(&z);
166 
167     let x_aff = ops.common.elem_product(&x, &zz_inv);
168 
169     // `y_aff` is needed to validate the point is on the curve. It is also
170     // needed in the non-ECDH case where we need to output it.
171     let y_aff = {
172         let zzzz_inv = ops.common.elem_squared(&zz_inv);
173         let zzz_inv = ops.common.elem_product(&z, &zzzz_inv);
174         ops.common.elem_product(&y, &zzz_inv)
175     };
176 
177     // If we validated our inputs correctly and then computed (x, y, z), then
178     // (x, y, z) will be on the curve. See
179     // `verify_affine_point_is_on_the_curve_scaled` for the motivation.
180     verify_affine_point_is_on_the_curve(ops.common, (&x_aff, &y_aff))?;
181 
182     Ok((x_aff, y_aff))
183 }
184 
big_endian_affine_from_jacobian( ops: &PrivateKeyOps, x_out: Option<&mut [u8]>, y_out: Option<&mut [u8]>, p: &Point, ) -> Result<(), error::Unspecified>185 pub fn big_endian_affine_from_jacobian(
186     ops: &PrivateKeyOps,
187     x_out: Option<&mut [u8]>,
188     y_out: Option<&mut [u8]>,
189     p: &Point,
190 ) -> Result<(), error::Unspecified> {
191     let (x_aff, y_aff) = affine_from_jacobian(ops, p)?;
192     let num_limbs = ops.common.num_limbs;
193     if let Some(x_out) = x_out {
194         let x = ops.common.elem_unencoded(&x_aff);
195         limb::big_endian_from_limbs(&x.limbs[..num_limbs], x_out);
196     }
197     if let Some(y_out) = y_out {
198         let y = ops.common.elem_unencoded(&y_aff);
199         limb::big_endian_from_limbs(&y.limbs[..num_limbs], y_out);
200     }
201 
202     Ok(())
203 }
204