redact_crypto/key/
ring.rs

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// SECRET SIGNING KEY \\
17#[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// PUBLIC SIGNING KEY \\
135#[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()), // different message than signature
304        ));
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()), // different message than signature
324        ));
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}