Move masking of scalars in Curve25519 code to Rust.

This commit is contained in:
Brian Smith 2019-06-25 14:53:54 -10:00
parent 03b9d14d15
commit 65ab723a19
9 changed files with 124 additions and 83 deletions

View File

@ -18,3 +18,4 @@ pub mod ed25519;
pub mod x25519;
mod ops;
mod scalar;

View File

@ -15,10 +15,18 @@
//! EdDSA Signatures.
use super::ops::ELEM_LEN;
use crate::digest;
mod digest;
pub mod signing;
pub mod verification;
/// The length of an Ed25519 public key.
pub const ED25519_PUBLIC_KEY_LEN: usize = ELEM_LEN;
pub fn eddsa_digest(signature_r: &[u8], public_key: &[u8], msg: &[u8]) -> digest::Digest {
let mut ctx = digest::Context::new(&digest::SHA512);
ctx.update(signature_r);
ctx.update(public_key);
ctx.update(msg);
ctx.finish()
}

View File

@ -1,23 +0,0 @@
use crate::digest;
use super::super::ops::{Scalar, UnreducedScalar, SCALAR_LEN};
pub fn eddsa_digest(signature_r: &[u8], public_key: &[u8], msg: &[u8]) -> digest::Digest {
let mut ctx = digest::Context::new(&digest::SHA512);
ctx.update(signature_r);
ctx.update(public_key);
ctx.update(msg);
ctx.finish()
}
pub fn digest_scalar(digest: digest::Digest) -> Scalar {
let mut unreduced = [0u8; digest::SHA512_OUTPUT_LEN];
unreduced.copy_from_slice(digest.as_ref());
unsafe { GFp_x25519_sc_reduce(&mut unreduced) };
let mut scalar = [0u8; SCALAR_LEN];
scalar.copy_from_slice(&unreduced[..SCALAR_LEN]);
scalar
}
extern "C" {
fn GFp_x25519_sc_reduce(s: &mut UnreducedScalar);
}

View File

@ -14,7 +14,7 @@
//! EdDSA Signatures.
use super::{super::ops::*, ED25519_PUBLIC_KEY_LEN};
use super::{super::ops::*, eddsa_digest, ED25519_PUBLIC_KEY_LEN};
use crate::{
digest, error,
io::der,
@ -24,8 +24,6 @@ use crate::{
use core::convert::TryInto;
use untrusted;
use super::digest::*;
/// An Ed25519 key pair, for signing.
pub struct Ed25519KeyPair {
// RFC 8032 Section 5.1.6 calls this *s*.
@ -155,23 +153,19 @@ impl Ed25519KeyPair {
fn from_seed_(seed: &Seed) -> Self {
let h = digest::digest(&digest::SHA512, seed);
let (scalar_encoded, prefix_encoded) = h.as_ref().split_at(SCALAR_LEN);
let (private_scalar, private_prefix) = h.as_ref().split_at(SCALAR_LEN);
let mut scalar = [0u8; SCALAR_LEN];
scalar.copy_from_slice(&scalar_encoded);
unsafe { GFp_x25519_sc_mask(&mut scalar) };
let mut prefix = [0u8; PREFIX_LEN];
prefix.copy_from_slice(prefix_encoded);
let private_scalar =
MaskedScalar::from_bytes_masked(private_scalar.try_into().unwrap()).into();
let mut a = ExtPoint::new_at_infinity();
unsafe {
GFp_x25519_ge_scalarmult_base(&mut a, &scalar);
GFp_x25519_ge_scalarmult_base(&mut a, &private_scalar);
}
Self {
private_scalar: scalar,
private_prefix: prefix,
private_scalar,
private_prefix: private_prefix.try_into().unwrap(),
public_key: PublicKey(a.into_encoded_point()),
}
}
@ -179,6 +173,15 @@ impl Ed25519KeyPair {
/// Returns the signature of the message `msg`.
pub fn sign(&self, msg: &[u8]) -> signature::Signature {
signature::Signature::new(|signature_bytes| {
extern "C" {
fn GFp_x25519_sc_muladd(
s: &mut [u8; SCALAR_LEN],
a: &Scalar,
b: &Scalar,
c: &Scalar,
);
}
let (signature_bytes, _unused) = signature_bytes.split_at_mut(ELEM_LEN + SCALAR_LEN);
let (signature_r, signature_s) = signature_bytes.split_at_mut(ELEM_LEN);
let nonce = {
@ -187,7 +190,7 @@ impl Ed25519KeyPair {
ctx.update(msg);
ctx.finish()
};
let nonce = digest_scalar(nonce);
let nonce = Scalar::from_sha512_digest_reduced(nonce);
let mut r = ExtPoint::new_at_infinity();
unsafe {
@ -195,7 +198,7 @@ impl Ed25519KeyPair {
}
signature_r.copy_from_slice(&r.into_encoded_point());
let hram_digest = eddsa_digest(signature_r, &self.public_key.as_ref(), msg);
let hram = digest_scalar(hram_digest);
let hram = Scalar::from_sha512_digest_reduced(hram_digest);
unsafe {
GFp_x25519_sc_muladd(
signature_s.try_into().unwrap(),
@ -243,9 +246,7 @@ fn unwrap_pkcs8(
}
extern "C" {
fn GFp_x25519_ge_scalarmult_base(h: &mut ExtPoint, a: &Seed);
fn GFp_x25519_sc_mask(a: &mut Scalar);
fn GFp_x25519_sc_muladd(s: &mut Scalar, a: &Scalar, b: &Scalar, c: &Scalar);
fn GFp_x25519_ge_scalarmult_base(h: &mut ExtPoint, a: &Scalar);
}
type Prefix = [u8; PREFIX_LEN];

View File

@ -14,12 +14,10 @@
//! EdDSA Signatures.
use super::super::ops::*;
use super::{super::ops::*, eddsa_digest};
use crate::{error, sealed, signature};
use untrusted;
use super::digest::*;
use core::convert::TryInto;
use untrusted;
/// Parameters for EdDSA signing and verification.
pub struct EdDSAParameters;
@ -57,16 +55,13 @@ impl signature::VerificationAlgorithm for EdDSAParameters {
Ok((signature_r, signature_s))
})?;
// Ensure `s` is not too large.
if (signature_s[SCALAR_LEN - 1] & 0b11100000) != 0 {
return Err(error::Unspecified);
}
let signature_s = Scalar::from_bytes_checked(*signature_s)?;
let mut a = ExtPoint::from_encoded_point_vartime(public_key)?;
a.invert_vartime();
let h_digest = eddsa_digest(signature_r, public_key, msg.as_slice_less_safe());
let h = digest_scalar(h_digest);
let h = Scalar::from_sha512_digest_reduced(h_digest);
let mut r = Point::new_at_infinity();
unsafe { GFp_x25519_ge_double_scalarmult_vartime(&mut r, &h, &a, &signature_s) };

View File

@ -15,6 +15,7 @@
//! Elliptic curve operations on the birationally equivalent curves Curve25519
//! and Edwards25519.
pub use super::scalar::{MaskedScalar, Scalar, SCALAR_LEN};
use crate::{
bssl, error,
limb::{Limb, LIMB_BITS},
@ -62,12 +63,6 @@ impl Elem<T> {
pub type EncodedPoint = [u8; ELEM_LEN];
pub const ELEM_LEN: usize = 32;
pub type Scalar = [u8; SCALAR_LEN];
pub const SCALAR_LEN: usize = 32;
pub type UnreducedScalar = [u8; UNREDUCED_SCALAR_LEN];
const UNREDUCED_SCALAR_LEN: usize = SCALAR_LEN * 2;
// Keep this in sync with `ge_p3` in curve25519/internal.h.
#[repr(C)]
pub struct ExtPoint {

View File

@ -0,0 +1,67 @@
// Copyright 2015-2019 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.
use crate::{digest, error};
use core::convert::TryInto;
#[repr(transparent)]
pub struct Scalar([u8; SCALAR_LEN]);
pub const SCALAR_LEN: usize = 32;
impl Scalar {
// Constructs a `Scalar` from `bytes`, failing if `bytes` encodes a scalar
// that not in the range [0, n).
pub fn from_bytes_checked(bytes: [u8; SCALAR_LEN]) -> Result<Self, error::Unspecified> {
// Ensure `s` is not too large.
if (bytes[SCALAR_LEN - 1] & 0b11100000) != 0 {
return Err(error::Unspecified);
}
Ok(Self(bytes))
}
// Constructs a `Scalar` from `digest` reduced modulo n.
pub fn from_sha512_digest_reduced(digest: digest::Digest) -> Self {
extern "C" {
fn GFp_x25519_sc_reduce(s: &mut UnreducedScalar);
}
let mut unreduced = [0u8; digest::SHA512_OUTPUT_LEN];
unreduced.copy_from_slice(digest.as_ref());
unsafe { GFp_x25519_sc_reduce(&mut unreduced) };
Self((&unreduced[..SCALAR_LEN]).try_into().unwrap())
}
}
#[repr(transparent)]
pub struct MaskedScalar([u8; SCALAR_LEN]);
impl MaskedScalar {
pub fn from_bytes_masked(bytes: [u8; SCALAR_LEN]) -> Self {
extern "C" {
fn GFp_x25519_sc_mask(a: &mut [u8; SCALAR_LEN]);
}
let mut r = Self(bytes);
unsafe { GFp_x25519_sc_mask(&mut r.0) };
r
}
}
impl From<MaskedScalar> for Scalar {
fn from(MaskedScalar(scalar): MaskedScalar) -> Self {
Self(scalar)
}
}
type UnreducedScalar = [u8; UNREDUCED_SCALAR_LEN];
const UNREDUCED_SCALAR_LEN: usize = SCALAR_LEN * 2;

View File

@ -14,7 +14,7 @@
//! X25519 Key agreement.
use super::ops;
use super::{ops, scalar::SCALAR_LEN};
use crate::{agreement, constant_time, cpu, ec, error, rand};
use core::convert::TryInto;
use untrusted;
@ -62,7 +62,8 @@ fn x25519_public_from_private(
#[cfg(target_arch = "arm")]
let cpu_features = private_key.cpu_features;
let private_key = private_key.bytes_less_safe().try_into()?;
let private_key: &[u8; SCALAR_LEN] = private_key.bytes_less_safe().try_into()?;
let private_key = ops::MaskedScalar::from_bytes_masked(*private_key);
#[cfg(target_arch = "arm")]
{
@ -71,19 +72,19 @@ fn x25519_public_from_private(
9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0,
];
x25519_neon(public_out, private_key, &MONTGOMERY_BASE_POINT);
x25519_neon(public_out, &private_key, &MONTGOMERY_BASE_POINT);
return Ok(());
}
}
extern "C" {
fn GFp_x25519_public_from_private_generic(
fn GFp_x25519_public_from_private_generic_masked(
public_key_out: &mut PublicKey,
private_key: &PrivateKey,
);
}
unsafe {
GFp_x25519_public_from_private_generic(public_out, private_key);
GFp_x25519_public_from_private_generic_masked(public_out, &private_key);
}
Ok(())
@ -95,13 +96,14 @@ fn x25519_ecdh(
peer_public_key: untrusted::Input,
) -> Result<(), error::Unspecified> {
let cpu_features = my_private_key.cpu_features;
let my_private_key = my_private_key.bytes_less_safe().try_into()?;
let my_private_key: &[u8; SCALAR_LEN] = my_private_key.bytes_less_safe().try_into()?;
let my_private_key = ops::MaskedScalar::from_bytes_masked(*my_private_key);
let peer_public_key: &[u8; PUBLIC_KEY_LEN] = peer_public_key.as_slice_less_safe().try_into()?;
#[cfg_attr(not(target_arch = "arm"), allow(unused_variables))]
fn scalar_mult(
out: &mut ops::EncodedPoint,
scalar: &ops::Scalar,
scalar: &ops::MaskedScalar,
point: &ops::EncodedPoint,
cpu_features: cpu::Features,
) {
@ -113,20 +115,20 @@ fn x25519_ecdh(
}
extern "C" {
fn GFp_x25519_scalar_mult_generic(
fn GFp_x25519_scalar_mult_generic_masked(
out: &mut ops::EncodedPoint,
scalar: &ops::Scalar,
scalar: &ops::MaskedScalar,
point: &ops::EncodedPoint,
);
}
unsafe {
GFp_x25519_scalar_mult_generic(out, scalar, point);
GFp_x25519_scalar_mult_generic_masked(out, scalar, point);
}
}
scalar_mult(
out.try_into()?,
my_private_key,
&my_private_key,
peer_public_key,
cpu_features,
);
@ -141,11 +143,11 @@ fn x25519_ecdh(
}
#[cfg(target_arch = "arm")]
fn x25519_neon(out: &mut ops::EncodedPoint, scalar: &ops::Scalar, point: &ops::EncodedPoint) {
fn x25519_neon(out: &mut ops::EncodedPoint, scalar: &ops::MaskedScalar, point: &ops::EncodedPoint) {
extern "C" {
fn GFp_x25519_NEON(
out: &mut ops::EncodedPoint,
scalar: &ops::Scalar,
scalar: &ops::MaskedScalar,
point: &ops::EncodedPoint,
);
}
@ -154,8 +156,7 @@ fn x25519_neon(out: &mut ops::EncodedPoint, scalar: &ops::Scalar, point: &ops::E
const ELEM_AND_SCALAR_LEN: usize = ops::ELEM_LEN;
// An X25519 private key as an unmasked scalar.
type PrivateKey = [u8; PRIVATE_KEY_LEN];
type PrivateKey = ops::MaskedScalar;
const PRIVATE_KEY_LEN: usize = ELEM_AND_SCALAR_LEN;
// An X25519 public key as an encoded Curve25519 point.

View File

@ -65,8 +65,6 @@
#endif // BORINGSSL_CURVE25519_64BIT
void GFp_x25519_sc_mask(uint8_t a[32]);
// Low-level intrinsic operations
static uint64_t load_3(const uint8_t *in) {
@ -1793,15 +1791,14 @@ static void sc_muladd(uint8_t *s, const uint8_t *a, const uint8_t *b,
}
void GFp_x25519_scalar_mult_generic(uint8_t out[32],
const uint8_t scalar[32],
const uint8_t point[32]) {
void GFp_x25519_scalar_mult_generic_masked(uint8_t out[32],
const uint8_t scalar_masked[32],
const uint8_t point[32]) {
fe x1, x2, z2, x3, z3, tmp0, tmp1;
fe_loose x2l, z2l, x3l, tmp0l, tmp1l;
uint8_t e[32];
bytes_copy(e, scalar, 32);
GFp_x25519_sc_mask(e);
bytes_copy(e, scalar_masked, 32);
// The following implementation was transcribed to Coq and proven to
// correspond to unary scalar multiplication in affine coordinates given that
// x1 != 0 is the x coordinate of some point on the curve. It was also checked
@ -1872,11 +1869,10 @@ void GFp_x25519_scalar_mult_generic(uint8_t out[32],
fe_tobytes(out, &x2);
}
void GFp_x25519_public_from_private_generic(uint8_t out_public_value[32],
const uint8_t private_key[32]) {
void GFp_x25519_public_from_private_generic_masked(uint8_t out_public_value[32],
const uint8_t private_key_masked[32]) {
uint8_t e[32];
bytes_copy(e, private_key, 32);
GFp_x25519_sc_mask(e);
bytes_copy(e, private_key_masked, 32);
ge_p3 A;
GFp_x25519_ge_scalarmult_base(&A, e);