1use crate::{
2 AsymmetricKeyBuilder, Builder, ByteSource, CryptoError, HasAlgorithmIdentifier, HasBuilder,
3 HasByteSource, HasIndex, HasPublicKey, KeyBuilder, PublicAsymmetricKeyBuilder,
4 SecretAsymmetricKeyBuilder, Signer, StorableType, TypeBuilder, TypeBuilderContainer, Verifier,
5};
6use mongodb::bson::{self, Document};
7use once_cell::sync::OnceCell;
8use ring::{
9 rand,
10 signature::{self, Ed25519KeyPair as ExternalEd25519KeyPair, KeyPair},
11};
12use serde::{Deserialize, Serialize};
13use spki::AlgorithmIdentifier;
14use std::convert::TryFrom;
15
16#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
18pub struct RingEd25519SecretAsymmetricKeyBuilder {}
19
20impl TryFrom<TypeBuilderContainer> for RingEd25519SecretAsymmetricKeyBuilder {
21 type Error = CryptoError;
22
23 fn try_from(builder: TypeBuilderContainer) -> Result<Self, Self::Error> {
24 match builder.0 {
25 TypeBuilder::Key(KeyBuilder::Asymmetric(AsymmetricKeyBuilder::Secret(
26 SecretAsymmetricKeyBuilder::RingEd25519(sopakb),
27 ))) => Ok(sopakb),
28 _ => Err(CryptoError::NotDowncastable),
29 }
30 }
31}
32
33impl Builder for RingEd25519SecretAsymmetricKeyBuilder {
34 type Output = RingEd25519SecretAsymmetricKey;
35
36 fn build(&self, bytes: Option<&[u8]>) -> Result<Self::Output, CryptoError> {
37 match bytes {
38 Some(bytes) => Ok(RingEd25519SecretAsymmetricKey {
39 secret_key: OnceCell::new(),
40 pkcs8_doc: bytes.into(),
41 }),
42 None => RingEd25519SecretAsymmetricKey::new(),
43 }
44 }
45}
46
47impl From<RingEd25519SecretAsymmetricKeyBuilder> for TypeBuilder {
48 fn from(b: RingEd25519SecretAsymmetricKeyBuilder) -> TypeBuilder {
49 TypeBuilder::Key(KeyBuilder::Asymmetric(AsymmetricKeyBuilder::Secret(
50 SecretAsymmetricKeyBuilder::RingEd25519(b),
51 )))
52 }
53}
54
55#[derive(Debug)]
56pub struct RingEd25519SecretAsymmetricKey {
57 secret_key: OnceCell<ExternalEd25519KeyPair>,
58 pkcs8_doc: ByteSource,
59}
60
61impl StorableType for RingEd25519SecretAsymmetricKey {}
62
63impl Signer for RingEd25519SecretAsymmetricKey {
64 fn sign(&self, bytes: ByteSource) -> Result<ByteSource, CryptoError> {
65 Ok(self.get_secret_key()?.sign(bytes.get()?).as_ref().into())
66 }
67}
68
69impl HasIndex for RingEd25519SecretAsymmetricKey {
70 type Index = Document;
71
72 fn get_index() -> Option<Self::Index> {
73 Some(bson::doc! {
74 "c": {
75 "builder": {
76 "t": "Key",
77 "c": {
78 "t": "Asymmetric",
79 "c": {
80 "t": "Secret",
81 "c": {
82 "t": "RingEd25519"
83 }
84 }
85 }
86 }
87 }
88 })
89 }
90}
91
92impl HasBuilder for RingEd25519SecretAsymmetricKey {
93 type Builder = RingEd25519SecretAsymmetricKeyBuilder;
94
95 fn builder(&self) -> Self::Builder {
96 RingEd25519SecretAsymmetricKeyBuilder {}
97 }
98}
99
100impl HasByteSource for RingEd25519SecretAsymmetricKey {
101 fn byte_source(&self) -> ByteSource {
102 self.pkcs8_doc.clone()
103 }
104}
105
106impl RingEd25519SecretAsymmetricKey {
107 pub fn new() -> Result<Self, CryptoError> {
108 let rng = rand::SystemRandom::new();
109 let pkcs8_doc = ExternalEd25519KeyPair::generate_pkcs8(&rng).map_err(|e| {
110 CryptoError::InternalError {
111 source: Box::new(e),
112 }
113 })?;
114 Ok(RingEd25519SecretAsymmetricKey {
115 secret_key: OnceCell::new(),
116 pkcs8_doc: pkcs8_doc.as_ref().into(),
117 })
118 }
119
120 fn get_secret_key(&self) -> Result<&ExternalEd25519KeyPair, CryptoError> {
121 self.secret_key.get_or_try_init(|| {
122 ExternalEd25519KeyPair::from_pkcs8(
123 self.pkcs8_doc
124 .get()
125 .map_err(|e| -> CryptoError { e.into() })?,
126 )
127 .map_err(|e| CryptoError::InternalError {
128 source: Box::new(e),
129 })
130 })
131 }
132}
133
134#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
136pub struct RingEd25519PublicAsymmetricKeyBuilder {}
137
138impl TryFrom<TypeBuilderContainer> for RingEd25519PublicAsymmetricKeyBuilder {
139 type Error = CryptoError;
140
141 fn try_from(builder: TypeBuilderContainer) -> Result<Self, Self::Error> {
142 match builder.0 {
143 TypeBuilder::Key(KeyBuilder::Asymmetric(AsymmetricKeyBuilder::Public(
144 PublicAsymmetricKeyBuilder::RingEd25519(sopakb),
145 ))) => Ok(sopakb),
146 _ => Err(CryptoError::NotDowncastable),
147 }
148 }
149}
150
151impl Builder for RingEd25519PublicAsymmetricKeyBuilder {
152 type Output = RingEd25519PublicAsymmetricKey;
153
154 fn build(&self, bytes: Option<&[u8]>) -> Result<Self::Output, CryptoError> {
155 match bytes {
156 Some(bytes) => Ok(RingEd25519PublicAsymmetricKey {
157 public_key: bytes.to_vec(),
158 }),
159 None => {
160 let (pk, _) = RingEd25519PublicAsymmetricKey::new()?;
161 Ok(pk)
162 }
163 }
164 }
165}
166
167impl From<RingEd25519PublicAsymmetricKeyBuilder> for TypeBuilder {
168 fn from(b: RingEd25519PublicAsymmetricKeyBuilder) -> TypeBuilder {
169 TypeBuilder::Key(KeyBuilder::Asymmetric(AsymmetricKeyBuilder::Public(
170 PublicAsymmetricKeyBuilder::RingEd25519(b),
171 )))
172 }
173}
174
175#[derive(Debug)]
176pub struct RingEd25519PublicAsymmetricKey {
177 pub public_key: Vec<u8>,
178}
179
180impl Verifier for RingEd25519PublicAsymmetricKey {
181 fn verify(&self, msg: ByteSource, signature: ByteSource) -> Result<(), CryptoError> {
182 let peer_public_key =
183 signature::UnparsedPublicKey::new(&signature::ED25519, self.public_key.clone());
184 peer_public_key
185 .verify(
186 msg.get().map_err(|e| CryptoError::InternalError {
187 source: Box::new(e),
188 })?,
189 signature.get().map_err(|_e| CryptoError::BadSignature)?,
190 )
191 .map_err(|_e| CryptoError::BadSignature)
192 }
193}
194
195impl StorableType for RingEd25519PublicAsymmetricKey {}
196
197impl HasIndex for RingEd25519PublicAsymmetricKey {
198 type Index = Document;
199
200 fn get_index() -> Option<Self::Index> {
201 Some(bson::doc! {
202 "c": {
203 "builder": {
204 "t": "Key",
205 "c": {
206 "t": "Asymmetric",
207 "c": {
208 "t": "Public",
209 "c": {
210 "t": "RingEd25519"
211 }
212 }
213 }
214 }
215 }
216 })
217 }
218}
219
220impl HasBuilder for RingEd25519PublicAsymmetricKey {
221 type Builder = RingEd25519PublicAsymmetricKeyBuilder;
222
223 fn builder(&self) -> Self::Builder {
224 RingEd25519PublicAsymmetricKeyBuilder {}
225 }
226}
227
228impl HasByteSource for RingEd25519PublicAsymmetricKey {
229 fn byte_source(&self) -> ByteSource {
230 self.public_key.as_slice().into()
231 }
232}
233
234impl HasAlgorithmIdentifier for RingEd25519PublicAsymmetricKey {
235 fn algorithm_identifier<'a>(&self) -> AlgorithmIdentifier<'a> {
236 AlgorithmIdentifier {
237 oid: spki::ObjectIdentifier::new("1.3.101.112"),
238 parameters: None,
239 }
240 }
241}
242
243impl RingEd25519PublicAsymmetricKey {
244 pub fn new() -> Result<(Self, RingEd25519SecretAsymmetricKey), CryptoError> {
245 let secret_key = RingEd25519SecretAsymmetricKey::new()?;
246 let public_key = secret_key.get_secret_key()?.public_key().as_ref().to_vec();
247 Ok((RingEd25519PublicAsymmetricKey { public_key }, secret_key))
248 }
249}
250
251impl HasPublicKey for RingEd25519SecretAsymmetricKey {
252 type PublicKey = RingEd25519PublicAsymmetricKey;
253
254 fn public_key(&self) -> Result<Self::PublicKey, CryptoError> {
255 Ok(RingEd25519PublicAsymmetricKey {
256 public_key: self.get_secret_key()?.public_key().as_ref().to_vec(),
257 })
258 }
259}
260
261impl HasAlgorithmIdentifier for RingEd25519SecretAsymmetricKey {
262 fn algorithm_identifier<'a>(&self) -> AlgorithmIdentifier<'a> {
263 AlgorithmIdentifier {
264 oid: spki::ObjectIdentifier::new("1.3.101.112"),
265 parameters: None,
266 }
267 }
268}
269
270#[cfg(test)]
271mod tests {
272 use crate::key::ring::{RingEd25519PublicAsymmetricKey, RingEd25519PublicAsymmetricKeyBuilder};
273 use crate::{Builder, ByteSource, CryptoError, VectorByteSource, Verifier};
274
275 #[test]
276 fn test_ringed25519publicasymmetrickey_verify() {
277 let public_key_base64 = "gSU9HQSz3Z030COosboySzkMfrBXpOmoXH3wdvReuGA=";
278 let rpak = RingEd25519PublicAsymmetricKeyBuilder {};
279 let public_key: RingEd25519PublicAsymmetricKey = rpak
280 .build(Some(base64::decode(public_key_base64).unwrap().as_ref()))
281 .unwrap();
282
283 let message = ByteSource::Vector(VectorByteSource::new(Some("abc".as_ref())));
284 let signature = ByteSource::Vector(
285 VectorByteSource::new(
286 Some(base64::decode("JixVA5XA4+fH5PE9Czk1yApf8f3oRCcwpB5pzMdVOBgvbWzPNv4h+nulKVvCkANYWX1iNticuX5eNwpx8HpdBw==")
287 .unwrap()
288 .as_ref())
289 )
290 );
291 public_key.verify(message, signature).unwrap();
292 }
293
294 #[test]
295 fn test_ringed25519publicasymmetrickey_verify_with_different_message() {
296 let public_key_base64 = "gSU9HQSz3Z030COosboySzkMfrBXpOmoXH3wdvReuGA=";
297 let rpak = RingEd25519PublicAsymmetricKeyBuilder {};
298 let public_key: RingEd25519PublicAsymmetricKey = rpak
299 .build(Some(base64::decode(public_key_base64).unwrap().as_ref()))
300 .unwrap();
301
302 let message = ByteSource::Vector(VectorByteSource::new(
303 Some("1233".as_ref()), ));
305 let signature = ByteSource::Vector(
306 VectorByteSource::new(
307 Some(base64::decode("JixVA5XA4+fH5PE9Czk1yApf8f3oRCcwpB5pzMdVOBgvbWzPNv4h+nulKVvCkANYWX1iNticuX5eNwpx8HpdBw==")
308 .unwrap()
309 .as_ref())
310 )
311 );
312 assert!(matches!(
313 public_key.verify(message, signature),
314 Err(CryptoError::BadSignature)
315 ));
316 }
317
318 #[test]
319 fn test_sodiumoxideed25519publicasymmetrickey_verify_with_invalid_signature() {
320 let (public_key, _) = RingEd25519PublicAsymmetricKey::new().unwrap();
321
322 let message = ByteSource::Vector(VectorByteSource::new(
323 Some("abc".as_ref()), ));
325 let signature = ByteSource::Vector(
326 VectorByteSource::new(
327 Some(base64::decode("JixVA5XA4+fH5PE9Czk1yApf8f3oRCcwpB5pzMdVOBgvbWzPNv4h+nulKVvCkANYWX1iNticuX5eNwpx8HpdBw==")
328 .unwrap()
329 .as_ref())
330 )
331 );
332 assert!(matches!(
333 public_key.verify(message, signature),
334 Err(CryptoError::BadSignature)
335 ));
336 }
337}