elliptic_curve/
secret_key.rs
1#[cfg(all(feature = "pkcs8", feature = "sec1"))]
9mod pkcs8;
10
11use crate::{Curve, Error, FieldBytes, Result, ScalarPrimitive};
12use core::fmt::{self, Debug};
13use generic_array::typenum::Unsigned;
14use subtle::{Choice, ConstantTimeEq};
15use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
16
17#[cfg(feature = "arithmetic")]
18use crate::{rand_core::CryptoRngCore, CurveArithmetic, NonZeroScalar, PublicKey};
19
20#[cfg(feature = "jwk")]
21use crate::jwk::{JwkEcKey, JwkParameters};
22
23#[cfg(feature = "pem")]
24use pem_rfc7468::{self as pem, PemLabel};
25
26#[cfg(feature = "sec1")]
27use {
28 crate::{
29 sec1::{EncodedPoint, ModulusSize, ValidatePublicKey},
30 FieldBytesSize,
31 },
32 sec1::der,
33};
34
35#[cfg(all(feature = "alloc", feature = "arithmetic", feature = "sec1"))]
36use {
37 crate::{
38 sec1::{FromEncodedPoint, ToEncodedPoint},
39 AffinePoint,
40 },
41 alloc::vec::Vec,
42 sec1::der::Encode,
43};
44
45#[cfg(all(feature = "arithmetic", any(feature = "jwk", feature = "pem")))]
46use alloc::string::String;
47
48#[cfg(all(feature = "arithmetic", feature = "jwk"))]
49use alloc::string::ToString;
50
51#[cfg(all(doc, feature = "pkcs8"))]
52use {crate::pkcs8::DecodePrivateKey, core::str::FromStr};
53
54#[derive(Clone)]
78pub struct SecretKey<C: Curve> {
79 inner: ScalarPrimitive<C>,
81}
82
83impl<C> SecretKey<C>
84where
85 C: Curve,
86{
87 const MIN_SIZE: usize = 24;
91
92 #[cfg(feature = "arithmetic")]
94 pub fn random(rng: &mut impl CryptoRngCore) -> Self
95 where
96 C: CurveArithmetic,
97 {
98 Self {
99 inner: NonZeroScalar::<C>::random(rng).into(),
100 }
101 }
102
103 pub fn new(scalar: ScalarPrimitive<C>) -> Self {
105 Self { inner: scalar }
106 }
107
108 pub fn as_scalar_primitive(&self) -> &ScalarPrimitive<C> {
116 &self.inner
117 }
118
119 #[cfg(feature = "arithmetic")]
127 pub fn to_nonzero_scalar(&self) -> NonZeroScalar<C>
128 where
129 C: CurveArithmetic,
130 {
131 self.into()
132 }
133
134 #[cfg(feature = "arithmetic")]
136 pub fn public_key(&self) -> PublicKey<C>
137 where
138 C: CurveArithmetic,
139 {
140 PublicKey::from_secret_scalar(&self.to_nonzero_scalar())
141 }
142
143 pub fn from_bytes(bytes: &FieldBytes<C>) -> Result<Self> {
145 let inner: ScalarPrimitive<C> =
146 Option::from(ScalarPrimitive::from_bytes(bytes)).ok_or(Error)?;
147
148 if inner.is_zero().into() {
149 return Err(Error);
150 }
151
152 Ok(Self { inner })
153 }
154
155 pub fn from_slice(slice: &[u8]) -> Result<Self> {
162 if slice.len() == C::FieldBytesSize::USIZE {
163 Self::from_bytes(FieldBytes::<C>::from_slice(slice))
164 } else if (Self::MIN_SIZE..C::FieldBytesSize::USIZE).contains(&slice.len()) {
165 let mut bytes = Zeroizing::new(FieldBytes::<C>::default());
166 let offset = C::FieldBytesSize::USIZE.saturating_sub(slice.len());
167 bytes[offset..].copy_from_slice(slice);
168 Self::from_bytes(&bytes)
169 } else {
170 Err(Error)
171 }
172 }
173
174 pub fn to_bytes(&self) -> FieldBytes<C> {
176 self.inner.to_bytes()
177 }
178
179 #[cfg(feature = "sec1")]
181 pub fn from_sec1_der(der_bytes: &[u8]) -> Result<Self>
182 where
183 C: Curve + ValidatePublicKey,
184 FieldBytesSize<C>: ModulusSize,
185 {
186 sec1::EcPrivateKey::try_from(der_bytes)?
187 .try_into()
188 .map_err(|_| Error)
189 }
190
191 #[cfg(all(feature = "alloc", feature = "arithmetic", feature = "sec1"))]
193 pub fn to_sec1_der(&self) -> der::Result<Zeroizing<Vec<u8>>>
194 where
195 C: CurveArithmetic,
196 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
197 FieldBytesSize<C>: ModulusSize,
198 {
199 let private_key_bytes = Zeroizing::new(self.to_bytes());
200 let public_key_bytes = self.public_key().to_encoded_point(false);
201
202 let ec_private_key = Zeroizing::new(
203 sec1::EcPrivateKey {
204 private_key: &private_key_bytes,
205 parameters: None,
206 public_key: Some(public_key_bytes.as_bytes()),
207 }
208 .to_der()?,
209 );
210
211 Ok(ec_private_key)
212 }
213
214 #[cfg(feature = "pem")]
222 pub fn from_sec1_pem(s: &str) -> Result<Self>
223 where
224 C: Curve + ValidatePublicKey,
225 FieldBytesSize<C>: ModulusSize,
226 {
227 let (label, der_bytes) = pem::decode_vec(s.as_bytes()).map_err(|_| Error)?;
228
229 if label != sec1::EcPrivateKey::PEM_LABEL {
230 return Err(Error);
231 }
232
233 Self::from_sec1_der(&der_bytes).map_err(|_| Error)
234 }
235
236 #[cfg(feature = "pem")]
241 pub fn to_sec1_pem(&self, line_ending: pem::LineEnding) -> Result<Zeroizing<String>>
242 where
243 C: CurveArithmetic,
244 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
245 FieldBytesSize<C>: ModulusSize,
246 {
247 self.to_sec1_der()
248 .ok()
249 .and_then(|der| {
250 pem::encode_string(sec1::EcPrivateKey::PEM_LABEL, line_ending, &der).ok()
251 })
252 .map(Zeroizing::new)
253 .ok_or(Error)
254 }
255
256 #[cfg(feature = "jwk")]
258 pub fn from_jwk(jwk: &JwkEcKey) -> Result<Self>
259 where
260 C: JwkParameters + ValidatePublicKey,
261 FieldBytesSize<C>: ModulusSize,
262 {
263 Self::try_from(jwk)
264 }
265
266 #[cfg(feature = "jwk")]
268 pub fn from_jwk_str(jwk: &str) -> Result<Self>
269 where
270 C: JwkParameters + ValidatePublicKey,
271 FieldBytesSize<C>: ModulusSize,
272 {
273 jwk.parse::<JwkEcKey>().and_then(|jwk| Self::from_jwk(&jwk))
274 }
275
276 #[cfg(all(feature = "arithmetic", feature = "jwk"))]
278 pub fn to_jwk(&self) -> JwkEcKey
279 where
280 C: CurveArithmetic + JwkParameters,
281 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
282 FieldBytesSize<C>: ModulusSize,
283 {
284 self.into()
285 }
286
287 #[cfg(all(feature = "arithmetic", feature = "jwk"))]
289 pub fn to_jwk_string(&self) -> Zeroizing<String>
290 where
291 C: CurveArithmetic + JwkParameters,
292 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
293 FieldBytesSize<C>: ModulusSize,
294 {
295 Zeroizing::new(self.to_jwk().to_string())
296 }
297}
298
299impl<C> ConstantTimeEq for SecretKey<C>
300where
301 C: Curve,
302{
303 fn ct_eq(&self, other: &Self) -> Choice {
304 self.inner.ct_eq(&other.inner)
305 }
306}
307
308impl<C> Debug for SecretKey<C>
309where
310 C: Curve,
311{
312 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
313 f.debug_struct(core::any::type_name::<Self>())
314 .finish_non_exhaustive()
315 }
316}
317
318impl<C> ZeroizeOnDrop for SecretKey<C> where C: Curve {}
319
320impl<C> Drop for SecretKey<C>
321where
322 C: Curve,
323{
324 fn drop(&mut self) {
325 self.inner.zeroize();
326 }
327}
328
329impl<C: Curve> Eq for SecretKey<C> {}
330
331impl<C> PartialEq for SecretKey<C>
332where
333 C: Curve,
334{
335 fn eq(&self, other: &Self) -> bool {
336 self.ct_eq(other).into()
337 }
338}
339
340#[cfg(feature = "sec1")]
341impl<C> TryFrom<sec1::EcPrivateKey<'_>> for SecretKey<C>
342where
343 C: Curve + ValidatePublicKey,
344 FieldBytesSize<C>: ModulusSize,
345{
346 type Error = der::Error;
347
348 fn try_from(sec1_private_key: sec1::EcPrivateKey<'_>) -> der::Result<Self> {
349 let secret_key = Self::from_slice(sec1_private_key.private_key)
350 .map_err(|_| der::Tag::Sequence.value_error())?;
351
352 if let Some(pk_bytes) = sec1_private_key.public_key {
354 let pk = EncodedPoint::<C>::from_bytes(pk_bytes)
355 .map_err(|_| der::Tag::BitString.value_error())?;
356
357 if C::validate_public_key(&secret_key, &pk).is_err() {
358 return Err(der::Tag::BitString.value_error());
359 }
360 }
361
362 Ok(secret_key)
363 }
364}
365
366#[cfg(feature = "arithmetic")]
367impl<C> From<NonZeroScalar<C>> for SecretKey<C>
368where
369 C: CurveArithmetic,
370{
371 fn from(scalar: NonZeroScalar<C>) -> SecretKey<C> {
372 SecretKey::from(&scalar)
373 }
374}
375
376#[cfg(feature = "arithmetic")]
377impl<C> From<&NonZeroScalar<C>> for SecretKey<C>
378where
379 C: CurveArithmetic,
380{
381 fn from(scalar: &NonZeroScalar<C>) -> SecretKey<C> {
382 SecretKey {
383 inner: scalar.into(),
384 }
385 }
386}