Skip to main content

polymorph_webcrypto_guest/
ecdh.rs

1//! `ecdh` key creation (SP 800-56A ECDH over the NIST prime-order curves).
2//!
3//! Keys minted here drive [`AgreementSecretKey::agree`], whose result
4//! chains into the KDFs (see
5//! [`hkdf_sha2::prepare_from`](crate::hkdf_sha2::prepare_from)), exactly as
6//! X25519's do. The shared secret is the x-coordinate of the agreed point,
7//! so its natural length is the curve's field size: 32 bytes for P-256, 48
8//! bytes for P-384. Unlike X25519's deliberately permissive raw import,
9//! public imports are strict — a point not on the declared variant's curve
10//! fails at import as [`Error::InvalidKey`](crate::Error::InvalidKey).
11//!
12//! [`AgreementSecretKey::agree`]: crate::AgreementSecretKey::agree
13
14use crate::{bindings, AgreementKeyOptions, AgreementPublicKey, AgreementSecretKey, Error};
15
16pub use crate::bindings::ecdh::EcdhVariant;
17
18/// Import a peer's public key as an uncompressed SEC1 point (`04 ‖ x ‖ y`;
19/// 65 bytes for P-256, 97 bytes for P-384).
20pub async fn import_public_key_raw(
21    variant: EcdhVariant,
22    raw: impl Into<Vec<u8>>,
23) -> Result<AgreementPublicKey, Error> {
24    Ok(AgreementPublicKey::from_raw(
25        bindings::ecdh::import_public_key_raw(variant, raw.into()).await?,
26    ))
27}
28
29/// Import a peer's public key from an X.509 SubjectPublicKeyInfo (DER)
30/// whose encoded curve matches the declared variant's.
31pub async fn import_public_key_spki(
32    variant: EcdhVariant,
33    spki: impl Into<Vec<u8>>,
34) -> Result<AgreementPublicKey, Error> {
35    Ok(AgreementPublicKey::from_raw(
36        bindings::ecdh::import_public_key_spki(variant, spki.into()).await?,
37    ))
38}
39
40/// Import a peer's public key from an EC public JWK (as JSON text) whose
41/// `crv` matches the declared variant's curve.
42pub async fn import_public_key_jwk(
43    variant: EcdhVariant,
44    jwk: impl Into<String>,
45) -> Result<AgreementPublicKey, Error> {
46    Ok(AgreementPublicKey::from_raw(
47        bindings::ecdh::import_public_key_jwk(variant, jwk.into()).await?,
48    ))
49}
50
51/// Import a static secret key from a PKCS#8 PrivateKeyInfo (DER) whose
52/// encoded curve matches the declared variant's.
53pub async fn import_secret_key_pkcs8(
54    variant: EcdhVariant,
55    pkcs8: impl Into<Vec<u8>>,
56    options: AgreementKeyOptions,
57) -> Result<AgreementSecretKey, Error> {
58    Ok(AgreementSecretKey::from_raw(
59        bindings::ecdh::import_secret_key_pkcs8(variant, pkcs8.into(), options.lower()).await?,
60    ))
61}
62
63/// Import a static secret key from an EC private JWK (as JSON text) whose
64/// `crv` matches the declared variant's curve.
65pub async fn import_secret_key_jwk(
66    variant: EcdhVariant,
67    jwk: impl Into<String>,
68    options: AgreementKeyOptions,
69) -> Result<AgreementSecretKey, Error> {
70    Ok(AgreementSecretKey::from_raw(
71        bindings::ecdh::import_secret_key_jwk(variant, jwk.into(), options.lower()).await?,
72    ))
73}
74
75/// Generate a fresh random keypair on the declared variant's curve,
76/// returning both halves.
77pub async fn generate_key(
78    variant: EcdhVariant,
79    options: AgreementKeyOptions,
80) -> Result<(AgreementSecretKey, AgreementPublicKey), Error> {
81    let (secret, public) = bindings::ecdh::generate_key(variant, options.lower()).await?;
82    Ok((
83        AgreementSecretKey::from_raw(secret),
84        AgreementPublicKey::from_raw(public),
85    ))
86}