[dependencies]# "jwk" adds the JWK conversions, "pem" the SPKI PEM ones (p256 0.13; 0.14 dropped "jwk")p256 = { version = "=0.13.2", features = ["jwk", "pem"] }use p256::pkcs8::{DecodePublicKey, EncodePublicKey, LineEnding};use p256::PublicKey; fn main() -> Result<(), Box<dyn std::error::Error>> { // PEM -> JWK let key = PublicKey::from_public_key_pem(&std::fs::read_to_string("pub.pem")?)?; let jwk = key.to_jwk_string(); // {"kty":"EC","crv":"P-256","x":"…","y":"…"} std::fs::write("out.jwk.json", &jwk)?; println!("{jwk}"); // JWK -> PEM: from_jwk_str also checks that the point is on the curve let key = PublicKey::from_jwk_str(&std::fs::read_to_string("pub.jwk.json")?)?; let pem = key.to_public_key_pem(LineEnding::LF)?; std::fs::write("out.pem", &pem)?; print!("{pem}"); Ok(())}How it works
PublicKey::from_public_key_pem(traitDecodePublicKey) readsBEGIN PUBLIC KEY.to_jwk_string()returns{"kty":"EC","crv":"P-256","x":…,"y":…}.PublicKey::from_jwk_strparses the JWK, checks the curve name and rejects points that are not on the curve.to_public_key_pem(LineEnding::LF)(traitEncodePublicKey) writes the SPKI PEM, identical to the original.
Gotchas
- p256 0.14 has no
jwkfeature: with=0.14.0, Cargo stops withpackage depends on p256 with feature jwk but p256 does not have that feature. JWK support in RustCrypto stayed with the 0.13 line (elliptic-curve 0.13), which is also what jsonwebtoken 11 uses. SecretKey::to_jwk_string()includesd. Publishsecret_key.public_key().to_jwk_string()instead.- The crate is curve-specific: P-384 keys need the
p384crate, RSA keys thersacrate. For mixed key sets, jsonwebtoken'sJwkor a JOSE crate covers all types. LineEnding::LFmatters for byte-exact comparisons:CRLFwrites the same key with Windows line endings.