blob: 1bce682efa6e12bb2529ba4dc70d5d7375d048ac [file] [log] [blame]
 // Copyright 2016 Brian Smith. // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. //! Elliptic curve operations on P-256 & P-384. use self::ops::*; use arithmetic::montgomery::*; use crate::{der, ec, error, pkcs8}; use untrusted; // NIST SP 800-56A Step 3: "If q is an odd prime p, verify that // yQ**2 = xQ**3 + axQ + b in GF(p), where the arithmetic is performed modulo // p." // // That is, verify that (x, y) is on the curve, which is true iif: // // y**2 == x**3 + a*x + b (mod q) // // Or, equivalently, but more efficiently: // // y**2 == (x**2 + a)*x + b (mod q) // fn verify_affine_point_is_on_the_curve( ops: &CommonOps, (x, y): (&Elem, &Elem), ) -> Result<(), error::Unspecified> { verify_affine_point_is_on_the_curve_scaled(ops, (x, y), &ops.a, &ops.b) } // Use `verify_affine_point_is_on_the_curve` instead of this function whenever // the affine coordinates are available or will become available. This function // should only be used then the affine coordinates are never calculated. See // the notes for `verify_affine_point_is_on_the_curve_scaled`. // // The value `z**2` is returned on success because it is useful for ECDSA // verification. // // This function also verifies that the point is not at infinity. fn verify_jacobian_point_is_on_the_curve( ops: &CommonOps, p: &Point, ) -> Result, error::Unspecified> { let z = ops.point_z(p); // Verify that the point is not at infinity. ops.elem_verify_is_not_zero(&z)?; let x = ops.point_x(p); let y = ops.point_y(p); // We are given Jacobian coordinates (x, y, z). So, we have: // // (x/z**2, y/z**3) == (x', y'), // // where (x', y') are the affine coordinates. The curve equation is: // // y'**2 == x'**3 + a*x' + b == (x'**2 + a)*x' + b // // Substituting our Jacobian coordinates, we get: // // / y \**2 / / x \**2 \ / x \ // | ---- | == | | ---- | + a | * | ---- | + b // \ z**3 / \ \ z**2 / / \ z**2 / // // Simplify: // // y**2 / x**2 \ x // ---- == | ---- + a | * ---- + b // z**6 \ z**4 / z**2 // // Multiply both sides by z**6: // // z**6 / x**2 \ z**6 // ---- * y**2 == | ---- + a | * ---- * x + (z**6) * b // z**6 \ z**4 / z**2 // // Simplify: // // / x**2 \ // y**2 == | ---- + a | * z**4 * x + (z**6) * b // \ z**4 / // // Distribute z**4: // // / z**4 \ // y**2 == | ---- * x**2 + z**4 * a | * x + (z**6) * b // \ z**4 / // // Simplify: // // y**2 == (x**2 + z**4 * a) * x + (z**6) * b // let z2 = ops.elem_squared(&z); let z4 = ops.elem_squared(&z2); let z4_a = ops.elem_product(&z4, &ops.a); let z6 = ops.elem_product(&z4, &z2); let z6_b = ops.elem_product(&z6, &ops.b); verify_affine_point_is_on_the_curve_scaled(ops, (&x, &y), &z4_a, &z6_b)?; Ok(z2) } // Handles the common logic of point-is-on-the-curve checks for both affine and // Jacobian cases. // // When doing the check that the point is on the curve after a computation, // to avoid fault attacks or mitigate potential bugs, it is better for security // to use `verify_affine_point_is_on_the_curve` on the affine coordinates, // because it provides some protection against faults that occur in the // computation of the inverse of `z`. See the paper and presentation "Fault // Attacks on Projective-to-Affine Coordinates Conversion" by Diana Maimuţ, // Cédric Murdica, David Naccache, Mehdi Tibouchi. That presentation concluded // simply "Check the validity of the result after conversion to affine // coordinates." (It seems like a good idea to verify that // z_inv * z == 1 mod q too). // // In the case of affine coordinates (x, y), `a_scaled` and `b_scaled` are // `a` and `b`, respectively. In the case of Jacobian coordinates (x, y, z), // the computation and comparison is the same, except `a_scaled` and `b_scaled` // are (z**4 * a) and (z**6 * b), respectively. Thus, performance is another // reason to prefer doing the check on the affine coordinates, as Jacobian // computation requires 3 extra multiplications and 2 extra squarings. // // An example of a fault attack that isn't mitigated by a point-on-the-curve // check after multiplication is given in "Sign Change Fault Attacks On // Elliptic Curve Cryptosystems" by Johannes Blömer, Martin Otto, and // Jean-Pierre Seifert. fn verify_affine_point_is_on_the_curve_scaled( ops: &CommonOps, (x, y): (&Elem, &Elem), a_scaled: &Elem, b_scaled: &Elem, ) -> Result<(), error::Unspecified> { let lhs = ops.elem_squared(y); let mut rhs = ops.elem_squared(x); ops.elem_add(&mut rhs, a_scaled); ops.elem_mul(&mut rhs, x); ops.elem_add(&mut rhs, b_scaled); if !ops.elems_are_equal(&lhs, &rhs) { return Err(error::Unspecified); } Ok(()) } pub(crate) fn key_pair_from_pkcs8( curve: &ec::Curve, template: &pkcs8::Template, input: untrusted::Input, ) -> Result { let (ec_private_key, _) = pkcs8::unwrap_key(template, pkcs8::Version::V1Only, input)?; let (private_key, public_key) = ec_private_key.read_all(error::Unspecified, |input| { // https://tools.ietf.org/html/rfc5915#section-3 der::nested(input, der::Tag::Sequence, error::Unspecified, |input| { let version = der::small_nonnegative_integer(input)?; if version != 1 { return Err(error::Unspecified); } let private_key = der::expect_tag_and_get_value(input, der::Tag::OctetString)?; // [0] parameters (optional). if input.peek(der::Tag::ContextSpecificConstructed0 as u8) { let actual_alg_id = der::expect_tag_and_get_value(input, der::Tag::ContextSpecificConstructed0)?; if actual_alg_id != template.curve_oid() { return Err(error::Unspecified); } } // [1] publicKey. The RFC says it is optional, but we require it // to be present. let public_key = der::nested( input, der::Tag::ContextSpecificConstructed1, error::Unspecified, der::bit_string_with_no_unused_bits, )?; Ok((private_key, public_key)) }) })?; key_pair_from_bytes(curve, private_key, public_key) } pub fn key_pair_from_bytes( curve: &ec::Curve, private_key_bytes: untrusted::Input, public_key_bytes: untrusted::Input, ) -> Result { let private_key = ec::PrivateKey::from_bytes(curve, private_key_bytes)?; let mut public_key_check = [0; ec::PUBLIC_KEY_MAX_LEN]; { // Borrow `public_key_check`. let public_key_check = &mut public_key_check[..curve.public_key_len]; (curve.public_from_private)(public_key_check, &private_key)?; if public_key_bytes != &*public_key_check { return Err(error::Unspecified); } } Ok(ec::KeyPair { private_key, public_key: public_key_check, }) } pub mod curve; pub mod ecdh; pub mod ecdsa; #[macro_use] mod ops; mod private_key; mod public_key;