1#[cfg(all(feature = "pkcs8", feature = "sec1"))]
9mod pkcs8;
10
11use crate::{Curve, Error, FieldBytes, Result, ScalarCore};
12use core::fmt::{self, Debug};
13use crypto_bigint::Encoding;
14use generic_array::GenericArray;
15use subtle::{Choice, ConstantTimeEq};
16use zeroize::{Zeroize, ZeroizeOnDrop};
17
18#[cfg(all(feature = "alloc", feature = "arithmetic"))]
19use {
20 crate::{
21 sec1::{FromEncodedPoint, ToEncodedPoint},
22 AffinePoint,
23 },
24 alloc::vec::Vec,
25 der::Encode,
26 zeroize::Zeroizing,
27};
28
29#[cfg(feature = "arithmetic")]
30use crate::{
31 rand_core::{CryptoRng, RngCore},
32 NonZeroScalar, ProjectiveArithmetic, PublicKey,
33};
34
35#[cfg(feature = "jwk")]
36use crate::jwk::{JwkEcKey, JwkParameters};
37
38#[cfg(all(feature = "arithmetic", any(feature = "jwk", feature = "pem")))]
39use alloc::string::String;
40
41#[cfg(all(feature = "arithmetic", feature = "jwk"))]
42use alloc::string::ToString;
43
44#[cfg(feature = "pem")]
45use pem_rfc7468 as pem;
46
47#[cfg(feature = "sec1")]
48use crate::{
49 sec1::{EncodedPoint, ModulusSize, ValidatePublicKey},
50 FieldSize,
51};
52
53#[cfg(all(docsrs, feature = "pkcs8"))]
54use {crate::pkcs8::DecodePrivateKey, core::str::FromStr};
55
56#[cfg(feature = "pem")]
58pub(crate) const SEC1_PEM_TYPE_LABEL: &str = "EC PRIVATE KEY";
59
60#[derive(Clone)]
84pub struct SecretKey<C: Curve> {
85 inner: ScalarCore<C>,
87}
88
89impl<C> SecretKey<C>
90where
91 C: Curve,
92{
93 #[cfg(feature = "arithmetic")]
95 #[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
96 pub fn random(rng: impl CryptoRng + RngCore) -> Self
97 where
98 C: ProjectiveArithmetic,
99 {
100 Self {
101 inner: NonZeroScalar::<C>::random(rng).into(),
102 }
103 }
104
105 pub fn new(scalar: ScalarCore<C>) -> Self {
107 Self { inner: scalar }
108 }
109
110 pub fn as_scalar_core(&self) -> &ScalarCore<C> {
118 &self.inner
119 }
120
121 #[cfg(feature = "arithmetic")]
129 #[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
130 pub fn to_nonzero_scalar(&self) -> NonZeroScalar<C>
131 where
132 C: Curve + ProjectiveArithmetic,
133 {
134 self.into()
135 }
136
137 #[cfg(feature = "arithmetic")]
139 #[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
140 pub fn public_key(&self) -> PublicKey<C>
141 where
142 C: Curve + ProjectiveArithmetic,
143 {
144 PublicKey::from_secret_scalar(&self.to_nonzero_scalar())
145 }
146
147 pub fn from_be_bytes(bytes: &[u8]) -> Result<Self> {
149 if bytes.len() != C::UInt::BYTE_SIZE {
150 return Err(Error);
151 }
152
153 let inner: ScalarCore<C> = Option::from(ScalarCore::from_be_bytes(
154 GenericArray::clone_from_slice(bytes),
155 ))
156 .ok_or(Error)?;
157
158 if inner.is_zero().into() {
159 return Err(Error);
160 }
161
162 Ok(Self { inner })
163 }
164
165 pub fn to_be_bytes(&self) -> FieldBytes<C> {
167 self.inner.to_be_bytes()
168 }
169
170 #[cfg(all(feature = "sec1"))]
172 #[cfg_attr(docsrs, doc(cfg(feature = "sec1")))]
173 pub fn from_sec1_der(der_bytes: &[u8]) -> Result<Self>
174 where
175 C: Curve + ValidatePublicKey,
176 FieldSize<C>: ModulusSize,
177 {
178 sec1::EcPrivateKey::try_from(der_bytes)?
179 .try_into()
180 .map_err(|_| Error)
181 }
182
183 #[cfg(all(feature = "alloc", feature = "arithmetic", feature = "sec1"))]
185 #[cfg_attr(
186 docsrs,
187 doc(cfg(all(feature = "alloc", feature = "arithmetic", feature = "sec1")))
188 )]
189 pub fn to_sec1_der(&self) -> der::Result<Zeroizing<Vec<u8>>>
190 where
191 C: Curve + ProjectiveArithmetic,
192 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
193 FieldSize<C>: ModulusSize,
194 {
195 let mut private_key_bytes = self.to_be_bytes();
197 let public_key_bytes = self.public_key().to_encoded_point(false);
198
199 let ec_private_key = Zeroizing::new(
200 sec1::EcPrivateKey {
201 private_key: &private_key_bytes,
202 parameters: None,
203 public_key: Some(public_key_bytes.as_bytes()),
204 }
205 .to_vec()?,
206 );
207
208 private_key_bytes.zeroize();
210
211 Ok(ec_private_key)
212 }
213
214 #[cfg(feature = "pem")]
222 #[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
223 pub fn from_sec1_pem(s: &str) -> Result<Self>
224 where
225 C: Curve + ValidatePublicKey,
226 FieldSize<C>: ModulusSize,
227 {
228 let (label, der_bytes) = pem::decode_vec(s.as_bytes()).map_err(|_| Error)?;
229
230 if label != SEC1_PEM_TYPE_LABEL {
231 return Err(Error);
232 }
233
234 Self::from_sec1_der(&*der_bytes).map_err(|_| Error)
235 }
236
237 #[cfg(feature = "pem")]
242 #[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
243 pub fn to_pem(&self, line_ending: pem::LineEnding) -> Result<Zeroizing<String>>
244 where
245 C: Curve + ProjectiveArithmetic,
246 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
247 FieldSize<C>: ModulusSize,
248 {
249 self.to_sec1_der()
250 .ok()
251 .and_then(|der| pem::encode_string(SEC1_PEM_TYPE_LABEL, line_ending, &der).ok())
252 .map(Zeroizing::new)
253 .ok_or(Error)
254 }
255
256 #[cfg(feature = "jwk")]
258 #[cfg_attr(docsrs, doc(cfg(feature = "jwk")))]
259 pub fn from_jwk(jwk: &JwkEcKey) -> Result<Self>
260 where
261 C: JwkParameters + ValidatePublicKey,
262 FieldSize<C>: ModulusSize,
263 {
264 Self::try_from(jwk)
265 }
266
267 #[cfg(feature = "jwk")]
269 #[cfg_attr(docsrs, doc(cfg(feature = "jwk")))]
270 pub fn from_jwk_str(jwk: &str) -> Result<Self>
271 where
272 C: JwkParameters + ValidatePublicKey,
273 FieldSize<C>: ModulusSize,
274 {
275 jwk.parse::<JwkEcKey>().and_then(|jwk| Self::from_jwk(&jwk))
276 }
277
278 #[cfg(all(feature = "arithmetic", feature = "jwk"))]
280 #[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
281 #[cfg_attr(docsrs, doc(cfg(feature = "jwk")))]
282 pub fn to_jwk(&self) -> JwkEcKey
283 where
284 C: Curve + JwkParameters + ProjectiveArithmetic,
285 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
286 FieldSize<C>: ModulusSize,
287 {
288 self.into()
289 }
290
291 #[cfg(all(feature = "arithmetic", feature = "jwk"))]
293 #[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
294 #[cfg_attr(docsrs, doc(cfg(feature = "jwk")))]
295 pub fn to_jwk_string(&self) -> Zeroizing<String>
296 where
297 C: Curve + JwkParameters + ProjectiveArithmetic,
298 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
299 FieldSize<C>: ModulusSize,
300 {
301 Zeroizing::new(self.to_jwk().to_string())
302 }
303}
304
305impl<C> ConstantTimeEq for SecretKey<C>
306where
307 C: Curve,
308{
309 fn ct_eq(&self, other: &Self) -> Choice {
310 self.inner.ct_eq(&other.inner)
311 }
312}
313
314impl<C> Debug for SecretKey<C>
315where
316 C: Curve,
317{
318 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
319 write!(f, "SecretKey<{:?}>{{ ... }}", C::default())
321 }
322}
323
324impl<C> ZeroizeOnDrop for SecretKey<C> where C: Curve {}
325
326impl<C> Drop for SecretKey<C>
327where
328 C: Curve,
329{
330 fn drop(&mut self) {
331 self.inner.zeroize();
332 }
333}
334
335impl<C: Curve> Eq for SecretKey<C> {}
336
337impl<C> PartialEq for SecretKey<C>
338where
339 C: Curve,
340{
341 fn eq(&self, other: &Self) -> bool {
342 self.ct_eq(other).into()
343 }
344}
345
346#[cfg(all(feature = "sec1"))]
347#[cfg_attr(docsrs, doc(cfg(feature = "sec1")))]
348impl<C> TryFrom<sec1::EcPrivateKey<'_>> for SecretKey<C>
349where
350 C: Curve + ValidatePublicKey,
351 FieldSize<C>: ModulusSize,
352{
353 type Error = der::Error;
354
355 fn try_from(sec1_private_key: sec1::EcPrivateKey<'_>) -> der::Result<Self> {
356 let secret_key = Self::from_be_bytes(sec1_private_key.private_key)
357 .map_err(|_| der::Tag::Sequence.value_error())?;
358
359 if let Some(pk_bytes) = sec1_private_key.public_key {
361 let pk = EncodedPoint::<C>::from_bytes(pk_bytes)
362 .map_err(|_| der::Tag::BitString.value_error())?;
363
364 if C::validate_public_key(&secret_key, &pk).is_err() {
365 return Err(der::Tag::BitString.value_error());
366 }
367 }
368
369 Ok(secret_key)
370 }
371}
372
373#[cfg(feature = "arithmetic")]
374#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
375impl<C> From<NonZeroScalar<C>> for SecretKey<C>
376where
377 C: Curve + ProjectiveArithmetic,
378{
379 fn from(scalar: NonZeroScalar<C>) -> SecretKey<C> {
380 SecretKey::from(&scalar)
381 }
382}
383
384#[cfg(feature = "arithmetic")]
385#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
386impl<C> From<&NonZeroScalar<C>> for SecretKey<C>
387where
388 C: Curve + ProjectiveArithmetic,
389{
390 fn from(scalar: &NonZeroScalar<C>) -> SecretKey<C> {
391 SecretKey {
392 inner: scalar.into(),
393 }
394 }
395}