ssh_key/public/
ecdsa.rs
1use crate::{
4 checked::CheckedSum, decode::Decode, encode::Encode, reader::Reader, writer::Writer, Algorithm,
5 EcdsaCurve, Error, Result,
6};
7use core::fmt;
8use sec1::consts::{U32, U48, U66};
9
10pub type EcdsaNistP256PublicKey = sec1::EncodedPoint<U32>;
12
13pub type EcdsaNistP384PublicKey = sec1::EncodedPoint<U48>;
15
16pub type EcdsaNistP521PublicKey = sec1::EncodedPoint<U66>;
18
19#[cfg_attr(docsrs, doc(cfg(feature = "ecdsa")))]
26#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
27pub enum EcdsaPublicKey {
28 NistP256(EcdsaNistP256PublicKey),
30
31 NistP384(EcdsaNistP384PublicKey),
33
34 NistP521(EcdsaNistP521PublicKey),
36}
37
38impl EcdsaPublicKey {
39 const MAX_SIZE: usize = 133;
45
46 pub fn from_sec1_bytes(bytes: &[u8]) -> Result<Self> {
50 match bytes {
51 [tag, rest @ ..] => {
52 let point_size = match sec1::point::Tag::from_u8(*tag)? {
53 sec1::point::Tag::CompressedEvenY | sec1::point::Tag::CompressedOddY => {
54 rest.len()
55 }
56 sec1::point::Tag::Uncompressed => rest.len() / 2,
57 _ => return Err(Error::Algorithm),
58 };
59
60 match point_size {
61 32 => Ok(Self::NistP256(EcdsaNistP256PublicKey::from_bytes(bytes)?)),
62 48 => Ok(Self::NistP384(EcdsaNistP384PublicKey::from_bytes(bytes)?)),
63 66 => Ok(Self::NistP521(EcdsaNistP521PublicKey::from_bytes(bytes)?)),
64 _ => Err(Error::Length),
65 }
66 }
67 _ => Err(Error::Length),
68 }
69 }
70
71 pub fn as_sec1_bytes(&self) -> &[u8] {
73 match self {
74 EcdsaPublicKey::NistP256(point) => point.as_bytes(),
75 EcdsaPublicKey::NistP384(point) => point.as_bytes(),
76 EcdsaPublicKey::NistP521(point) => point.as_bytes(),
77 }
78 }
79
80 pub fn algorithm(&self) -> Algorithm {
82 Algorithm::Ecdsa {
83 curve: self.curve(),
84 }
85 }
86
87 pub fn curve(&self) -> EcdsaCurve {
89 match self {
90 EcdsaPublicKey::NistP256(_) => EcdsaCurve::NistP256,
91 EcdsaPublicKey::NistP384(_) => EcdsaCurve::NistP384,
92 EcdsaPublicKey::NistP521(_) => EcdsaCurve::NistP521,
93 }
94 }
95}
96
97impl AsRef<[u8]> for EcdsaPublicKey {
98 fn as_ref(&self) -> &[u8] {
99 self.as_sec1_bytes()
100 }
101}
102
103impl Decode for EcdsaPublicKey {
104 fn decode(reader: &mut impl Reader) -> Result<Self> {
105 let curve = EcdsaCurve::decode(reader)?;
106
107 let mut buf = [0u8; Self::MAX_SIZE];
108 let key = Self::from_sec1_bytes(reader.read_byten(&mut buf)?)?;
109
110 if key.curve() == curve {
111 Ok(key)
112 } else {
113 Err(Error::Algorithm)
114 }
115 }
116}
117
118impl Encode for EcdsaPublicKey {
119 fn encoded_len(&self) -> Result<usize> {
120 [
121 self.curve().encoded_len()?,
122 4, self.as_ref().len(),
124 ]
125 .checked_sum()
126 }
127
128 fn encode(&self, writer: &mut impl Writer) -> Result<()> {
129 self.curve().encode(writer)?;
130 self.as_ref().encode(writer)
131 }
132}
133
134impl fmt::Display for EcdsaPublicKey {
135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136 write!(f, "{:X}", self)
137 }
138}
139
140impl fmt::LowerHex for EcdsaPublicKey {
141 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142 for byte in self.as_sec1_bytes() {
143 write!(f, "{:02x}", byte)?;
144 }
145 Ok(())
146 }
147}
148
149impl fmt::UpperHex for EcdsaPublicKey {
150 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
151 for byte in self.as_sec1_bytes() {
152 write!(f, "{:02X}", byte)?;
153 }
154 Ok(())
155 }
156}
157
158#[cfg(feature = "p256")]
159#[cfg_attr(docsrs, doc(cfg(feature = "p256")))]
160impl TryFrom<EcdsaPublicKey> for p256::ecdsa::VerifyingKey {
161 type Error = Error;
162
163 fn try_from(key: EcdsaPublicKey) -> Result<p256::ecdsa::VerifyingKey> {
164 p256::ecdsa::VerifyingKey::try_from(&key)
165 }
166}
167
168#[cfg(feature = "p256")]
169#[cfg_attr(docsrs, doc(cfg(feature = "p256")))]
170impl TryFrom<&EcdsaPublicKey> for p256::ecdsa::VerifyingKey {
171 type Error = Error;
172
173 fn try_from(public_key: &EcdsaPublicKey) -> Result<p256::ecdsa::VerifyingKey> {
174 match public_key {
175 EcdsaPublicKey::NistP256(key) => {
176 p256::ecdsa::VerifyingKey::from_encoded_point(key).map_err(|_| Error::Crypto)
177 }
178 _ => Err(Error::Algorithm),
179 }
180 }
181}
182
183#[cfg(feature = "p256")]
184#[cfg_attr(docsrs, doc(cfg(feature = "p256")))]
185impl From<p256::ecdsa::VerifyingKey> for EcdsaPublicKey {
186 fn from(key: p256::ecdsa::VerifyingKey) -> EcdsaPublicKey {
187 EcdsaPublicKey::from(&key)
188 }
189}
190
191#[cfg(feature = "p256")]
192#[cfg_attr(docsrs, doc(cfg(feature = "p256")))]
193impl From<&p256::ecdsa::VerifyingKey> for EcdsaPublicKey {
194 fn from(key: &p256::ecdsa::VerifyingKey) -> EcdsaPublicKey {
195 EcdsaPublicKey::NistP256(key.to_encoded_point(false))
196 }
197}