aboutsummaryrefslogtreecommitdiff
path: root/nearby/crypto/crypto_provider_openssl/src/p256.rs
diff options
context:
space:
mode:
Diffstat (limited to 'nearby/crypto/crypto_provider_openssl/src/p256.rs')
-rw-r--r--nearby/crypto/crypto_provider_openssl/src/p256.rs168
1 files changed, 168 insertions, 0 deletions
diff --git a/nearby/crypto/crypto_provider_openssl/src/p256.rs b/nearby/crypto/crypto_provider_openssl/src/p256.rs
new file mode 100644
index 0000000..9c7b675
--- /dev/null
+++ b/nearby/crypto/crypto_provider_openssl/src/p256.rs
@@ -0,0 +1,168 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use crypto_provider::elliptic_curve::{EcdhProvider, EphemeralSecret};
+use crypto_provider::p256::P256;
+use openssl::bn::{BigNum, BigNumContext};
+use openssl::derive::Deriver;
+use openssl::ec::{EcGroup, EcKey, EcPoint, PointConversionForm};
+use openssl::error::ErrorStack;
+use openssl::nid::Nid;
+use openssl::pkey::{PKey, Private, Public};
+
+/// Public key type for P256 using OpenSSL's implementation.
+#[derive(Debug)]
+pub struct P256PublicKey(PKey<Public>);
+
+impl PartialEq for P256PublicKey {
+ fn eq(&self, other: &Self) -> bool {
+ self.0.public_eq(&other.0)
+ }
+}
+
+/// Custom error type for OpenSSL operations.
+#[derive(Debug)]
+pub enum Error {
+ /// Error from the openssl crate.
+ OpenSslError(ErrorStack),
+ /// Unexpected size for the given input.
+ WrongSize,
+}
+
+impl From<ErrorStack> for Error {
+ fn from(value: ErrorStack) -> Self {
+ Self::OpenSslError(value)
+ }
+}
+
+/// The OpenSSL implementation of P256 public key.
+impl crypto_provider::p256::P256PublicKey for P256PublicKey {
+ type Error = Error;
+
+ fn from_sec1_bytes(bytes: &[u8]) -> Result<Self, Self::Error> {
+ let ecgroup = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1)?;
+ let mut bncontext = BigNumContext::new()?;
+ let ecpoint = EcPoint::from_bytes(&ecgroup, bytes, &mut bncontext)?;
+ let eckey = EcKey::from_public_key(&ecgroup, &ecpoint)?;
+ Ok(Self(eckey.try_into()?))
+ }
+
+ fn to_sec1_bytes(&self) -> Vec<u8> {
+ let ecgroup = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
+ let mut bncontext = BigNumContext::new().unwrap();
+ self.0
+ .ec_key()
+ .unwrap()
+ .public_key()
+ .to_bytes(&ecgroup, PointConversionForm::COMPRESSED, &mut bncontext)
+ .unwrap()
+ }
+
+ fn from_affine_coordinates(x: &[u8; 32], y: &[u8; 32]) -> Result<Self, Self::Error> {
+ let bn_x = BigNum::from_slice(x)?;
+ let bn_y = BigNum::from_slice(y)?;
+ let ecgroup = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1)?;
+ let eckey = EcKey::from_public_key_affine_coordinates(&ecgroup, &bn_x, &bn_y)?;
+ Ok(Self(eckey.try_into()?))
+ }
+
+ fn to_affine_coordinates(&self) -> Result<([u8; 32], [u8; 32]), Self::Error> {
+ let mut bnctx = openssl::bn::BigNumContext::new()?;
+ let ecgroup = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1)?;
+ let p256_key = self.0.ec_key()?;
+ let mut p256x = BigNum::new()?;
+ let mut p256y = BigNum::new()?;
+ p256_key
+ .public_key()
+ .affine_coordinates_gfp(&ecgroup, &mut p256x, &mut p256y, &mut bnctx)?;
+ Ok((
+ p256x.to_vec().try_into().map_err(|_| Error::WrongSize)?,
+ p256y.to_vec().try_into().map_err(|_| Error::WrongSize)?,
+ ))
+ }
+}
+
+/// Private key type for P256 using OpenSSL's implementation.
+pub struct P256EphemeralSecret(PKey<Private>);
+
+impl EphemeralSecret<P256> for P256EphemeralSecret {
+ type Impl = P256Ecdh;
+ type Error = Error;
+
+ fn generate_random<R: rand::Rng + rand::CryptoRng>(_rng: &mut R) -> Self {
+ let ecgroup = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
+ let eckey = EcKey::generate(&ecgroup).unwrap();
+ Self(eckey.try_into().unwrap())
+ }
+
+ fn public_key_bytes(&self) -> Vec<u8> {
+ let ecgroup = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
+ let mut bncontext = BigNumContext::new().unwrap();
+ self.0
+ .ec_key()
+ .unwrap()
+ .public_key()
+ .to_bytes(&ecgroup, PointConversionForm::COMPRESSED, &mut bncontext)
+ .unwrap()
+ }
+
+ fn diffie_hellman(
+ self,
+ other_pub: &<Self::Impl as EcdhProvider<P256>>::PublicKey,
+ ) -> Result<<Self::Impl as EcdhProvider<P256>>::SharedSecret, Self::Error> {
+ let mut deriver = Deriver::new(&self.0)?;
+ deriver.set_peer(&other_pub.0)?;
+ let mut buf = [0_u8; 32];
+ let bytes_written = deriver.derive(&mut buf)?;
+ debug_assert_eq!(bytes_written, 32);
+ Ok(buf)
+ }
+}
+
+#[cfg(test)]
+impl crypto_provider::elliptic_curve::EphemeralSecretForTesting<P256> for P256EphemeralSecret {
+ fn from_private_components(
+ private_bytes: &[u8; 32],
+ public_key: &P256PublicKey,
+ ) -> Result<Self, Self::Error> {
+ let ecgroup = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
+ let private_key_bn = BigNum::from_slice(private_bytes)?;
+ let eckey = EcKey::from_private_components(
+ &ecgroup,
+ &private_key_bn,
+ public_key.0.ec_key()?.public_key(),
+ )?;
+ Ok(Self(eckey.try_into()?))
+ }
+}
+
+/// The OpenSSL implementation of P256 ECDH.
+pub enum P256Ecdh {}
+impl EcdhProvider<P256> for P256Ecdh {
+ type PublicKey = P256PublicKey;
+ type EphemeralSecret = P256EphemeralSecret;
+ type SharedSecret = [u8; 32];
+}
+
+#[cfg(test)]
+mod tests {
+ use super::P256Ecdh;
+ use core::marker::PhantomData;
+ use crypto_provider::p256::testing::*;
+
+ #[apply(p256_test_cases)]
+ fn p256_tests(testcase: CryptoProviderTestCase<P256Ecdh>) {
+ testcase(PhantomData::<P256Ecdh>)
+ }
+}