Skip to main content

emissary_core/crypto/
mod.rs

1// Permission is hereby granted, free of charge, to any person obtaining a
2// copy of this software and associated documentation files (the "Software"),
3// to deal in the Software without restriction, including without limitation
4// the rights to use, copy, modify, merge, publish, distribute, sublicense,
5// and/or sell copies of the Software, and to permit persons to whom the
6// Software is furnished to do so, subject to the following conditions:
7//
8// The above copyright notice and this permission notice shall be included in
9// all copies or substantial portions of the Software.
10//
11// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
16// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17// DEALINGS IN THE SOFTWARE.
18
19use crate::{
20    crypto::dsa::{DsaPublicKey, DsaSignature},
21    error::Error,
22};
23
24use data_encoding::{Encoding, Specification};
25use ed25519_dalek::Signer;
26use lazy_static::lazy_static;
27use p256::ecdsa::signature::Verifier as _;
28use rand_core::{CryptoRng, RngCore};
29use zeroize::Zeroize;
30
31use alloc::{string::String, vec::Vec};
32use core::convert::TryInto;
33
34pub mod aes;
35pub mod chachapoly;
36pub mod dsa;
37pub mod hmac;
38pub mod noise;
39pub mod sha256;
40pub mod siphash;
41
42// Taken from `ire` which is licensed under MIT
43//
44// Credits to str4d
45lazy_static! {
46    pub static ref I2P_BASE64: Encoding = {
47        let mut spec = Specification::new();
48        spec.symbols
49            .push_str("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-~");
50        spec.padding = Some('=');
51        spec.encoding().unwrap()
52    };
53    pub static ref I2P_BASE32: Encoding = {
54        let mut spec = Specification::new();
55        spec.symbols.push_str("abcdefghijklmnopqrstuvwxyz234567");
56        spec.encoding().unwrap()
57    };
58}
59
60/// Base64 encode `data`
61pub fn base64_encode<T: AsRef<[u8]>>(data: T) -> String {
62    I2P_BASE64.encode(data.as_ref())
63}
64
65/// Base64 decode `data`
66pub fn base64_decode<T: AsRef<[u8]>>(data: T) -> Option<Vec<u8>> {
67    I2P_BASE64.decode(data.as_ref()).ok()
68}
69
70/// Base32 decode `data`.
71pub fn base32_encode(data: impl AsRef<[u8]>) -> String {
72    I2P_BASE32.encode(data.as_ref())
73}
74
75/// Base32 decode `data`.
76#[allow(unused)]
77pub fn base32_decode(data: impl AsRef<[u8]>) -> Option<Vec<u8>> {
78    I2P_BASE32.decode(data.as_ref()).ok()
79}
80
81/// Trait describing the expected API from secret keys.
82pub trait SecretKey {
83    /// Perform Diffie-Hellman key exchange between `self` and `public_key`.
84    fn diffie_hellman<T: AsRef<x25519_dalek::PublicKey>>(&self, public_key: &T) -> [u8; 32];
85}
86
87/// Signing key kind.
88///
89/// https://geti2p.net/spec/common-structures#key-certificates
90pub enum SigningKeyKind {
91    /// DSA-SHA1.
92    DsaSha1(usize),
93
94    /// ECDSA-SHA256-P256.
95    EcDsaSha256P256(usize),
96
97    /// EdDSA-SHA512-Ed25519
98    EdDsaSha512Ed25519(usize),
99}
100
101impl TryFrom<u16> for SigningKeyKind {
102    type Error = ();
103
104    fn try_from(value: u16) -> Result<Self, Self::Error> {
105        match value {
106            0 => Ok(SigningKeyKind::DsaSha1(128)),
107            1 => Ok(SigningKeyKind::EcDsaSha256P256(64)),
108            7 => Ok(SigningKeyKind::EdDsaSha512Ed25519(32)),
109            _ => Err(()),
110        }
111    }
112}
113
114/// Private key kind.
115///
116/// https://geti2p.net/spec/common-structures#key-certificates
117pub enum PrivateKeyKind {
118    /// ElGamal.
119    ElGamal(usize),
120
121    /// P256.
122    P256(usize),
123
124    /// X25519.
125    X25519(usize),
126}
127
128impl TryFrom<u16> for PrivateKeyKind {
129    type Error = ();
130
131    fn try_from(value: u16) -> Result<Self, Self::Error> {
132        match value {
133            0 => Ok(PrivateKeyKind::ElGamal(256)),
134            1 => Ok(PrivateKeyKind::P256(64)),
135            4 => Ok(PrivateKeyKind::X25519(32)),
136            _ => Err(()),
137        }
138    }
139}
140
141/// Static public key.
142#[derive(Debug, Clone)]
143pub enum StaticPublicKey {
144    /// x25519
145    X25519(x25519_dalek::PublicKey),
146}
147
148impl StaticPublicKey {
149    /// Try to create [`StaticPublicKey`] from `bytes`.
150    pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
151        let key: [u8; 32] = bytes.try_into().ok()?;
152
153        Some(Self::X25519(x25519_dalek::PublicKey::from(key)))
154    }
155
156    /// Convert [`StaticPublicKey`] to a byte vector.
157    pub fn to_vec(&self) -> Vec<u8> {
158        match self {
159            Self::X25519(key) => key.to_bytes().to_vec(),
160        }
161    }
162}
163
164impl From<[u8; 32]> for StaticPublicKey {
165    fn from(value: [u8; 32]) -> Self {
166        StaticPublicKey::X25519(x25519_dalek::PublicKey::from(value))
167    }
168}
169
170impl AsRef<[u8]> for StaticPublicKey {
171    fn as_ref(&self) -> &[u8] {
172        match self {
173            Self::X25519(key) => key.as_ref(),
174        }
175    }
176}
177
178impl AsRef<x25519_dalek::PublicKey> for StaticPublicKey {
179    fn as_ref(&self) -> &x25519_dalek::PublicKey {
180        match self {
181            Self::X25519(key) => key,
182        }
183    }
184}
185
186/// Static private key.
187#[derive(Clone)]
188pub enum StaticPrivateKey {
189    /// X25519.
190    X25519(x25519_dalek::StaticSecret),
191}
192
193impl StaticPrivateKey {
194    /// Create new [`StaticPrivateKey`].
195    pub fn random(csprng: impl RngCore + CryptoRng) -> Self {
196        Self::X25519(x25519_dalek::StaticSecret::random_from_rng(csprng))
197    }
198
199    /// Get public key.
200    pub fn public(&self) -> StaticPublicKey {
201        match self {
202            Self::X25519(key) => StaticPublicKey::X25519(x25519_dalek::PublicKey::from(key)),
203        }
204    }
205
206    /// Perform Diffie-Hellman and return the shared secret as byte vector.
207    pub fn diffie_hellman<T: AsRef<x25519_dalek::PublicKey>>(&self, public_key: &T) -> Vec<u8> {
208        match self {
209            Self::X25519(key) => key.diffie_hellman(public_key.as_ref()).to_bytes().to_vec(),
210        }
211    }
212
213    /// Try to create [`StaticPublicKey`] from `bytes`.
214    pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
215        let key: [u8; 32] = bytes.try_into().ok()?;
216
217        Some(StaticPrivateKey::X25519(x25519_dalek::StaticSecret::from(
218            key,
219        )))
220    }
221}
222
223impl From<[u8; 32]> for StaticPrivateKey {
224    fn from(value: [u8; 32]) -> Self {
225        StaticPrivateKey::X25519(x25519_dalek::StaticSecret::from(value))
226    }
227}
228
229impl AsRef<[u8]> for StaticPrivateKey {
230    fn as_ref(&self) -> &[u8] {
231        match self {
232            Self::X25519(key) => key.as_ref(),
233        }
234    }
235}
236
237impl SecretKey for StaticPrivateKey {
238    fn diffie_hellman<T: AsRef<x25519_dalek::PublicKey>>(&self, public_key: &T) -> [u8; 32] {
239        match self {
240            Self::X25519(key) => key.diffie_hellman(public_key.as_ref()).to_bytes(),
241        }
242    }
243}
244
245/// Ephemeral private key.
246pub enum EphemeralPrivateKey {
247    /// X25519.
248    X25519(x25519_dalek::ReusableSecret),
249}
250
251impl EphemeralPrivateKey {
252    /// Create new [`EphemeralPrivateKey`].
253    pub fn random(csprng: impl RngCore + CryptoRng) -> Self {
254        Self::X25519(x25519_dalek::ReusableSecret::random_from_rng(csprng))
255    }
256
257    /// Get associated public key.
258    pub fn public(&self) -> EphemeralPublicKey {
259        match self {
260            Self::X25519(key) => EphemeralPublicKey::X25519(x25519_dalek::PublicKey::from(key)),
261        }
262    }
263
264    /// Perform Diffie-Hellman and return the shared secret as byte vector.
265    pub fn diffie_hellman<T: AsRef<x25519_dalek::PublicKey>>(&self, public_key: &T) -> Vec<u8> {
266        match self {
267            Self::X25519(key) => key.diffie_hellman(public_key.as_ref()).to_bytes().to_vec(),
268        }
269    }
270
271    /// Zeroize private key.
272    pub fn zeroize(self) {
273        match self {
274            Self::X25519(mut key) => key.zeroize(),
275        }
276    }
277}
278
279impl SecretKey for EphemeralPrivateKey {
280    fn diffie_hellman<T: AsRef<x25519_dalek::PublicKey>>(&self, public_key: &T) -> [u8; 32] {
281        match self {
282            Self::X25519(key) => key.diffie_hellman(public_key.as_ref()).to_bytes(),
283        }
284    }
285}
286
287/// Ephemeral public key.
288#[derive(Clone)]
289pub enum EphemeralPublicKey {
290    /// X25519.
291    X25519(x25519_dalek::PublicKey),
292}
293
294impl EphemeralPublicKey {
295    /// Convert [`EphemeralPublicKey`] to a byte vector.
296    pub fn to_vec(&self) -> Vec<u8> {
297        match self {
298            Self::X25519(key) => key.as_bytes().to_vec(),
299        }
300    }
301
302    /// Try to create [`EphemeralPublicKey`] from `bytes`.
303    pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
304        let key: [u8; 32] = bytes.try_into().ok()?;
305
306        Some(Self::X25519(x25519_dalek::PublicKey::from(key)))
307    }
308}
309
310impl AsRef<[u8]> for EphemeralPublicKey {
311    fn as_ref(&self) -> &[u8] {
312        match self {
313            Self::X25519(key) => key.as_ref(),
314        }
315    }
316}
317
318impl AsRef<x25519_dalek::PublicKey> for EphemeralPublicKey {
319    fn as_ref(&self) -> &x25519_dalek::PublicKey {
320        match self {
321            Self::X25519(key) => key,
322        }
323    }
324}
325
326impl Zeroize for EphemeralPublicKey {
327    fn zeroize(&mut self) {
328        match self {
329            Self::X25519(key) => key.zeroize(),
330        }
331    }
332}
333
334/// Signing private key.
335#[derive(Clone)]
336pub enum SigningPrivateKey {
337    /// EdDSA.
338    Ed25519(ed25519_dalek::SigningKey),
339}
340
341impl SigningPrivateKey {
342    /// Generate random [`SigningPrivateKey`].
343    pub fn random(mut csprng: impl RngCore + CryptoRng) -> Self {
344        Self::Ed25519(ed25519_dalek::SigningKey::generate(&mut csprng))
345    }
346
347    /// Try to create [`SigningPrivateKey`] from `bytes`.
348    pub fn from_bytes(key: &[u8]) -> Option<Self> {
349        let key: [u8; 32] = key.to_vec().try_into().ok()?;
350        let key = ed25519_dalek::SigningKey::from_bytes(&key);
351
352        Some(SigningPrivateKey::Ed25519(key))
353    }
354
355    /// Sign `message`.
356    pub fn sign(&self, message: &[u8]) -> Vec<u8> {
357        match self {
358            Self::Ed25519(key) => key.sign(message).to_bytes().to_vec(),
359        }
360    }
361
362    /// Get verifying key.
363    pub fn public(&self) -> SigningPublicKey {
364        match self {
365            Self::Ed25519(key) => SigningPublicKey::Ed25519(key.verifying_key()),
366        }
367    }
368
369    /// Get signature length.
370    pub fn signature_len(&self) -> usize {
371        match self {
372            Self::Ed25519(_) => 64usize,
373        }
374    }
375}
376
377impl From<[u8; 32]> for SigningPrivateKey {
378    fn from(value: [u8; 32]) -> Self {
379        SigningPrivateKey::Ed25519(ed25519_dalek::SigningKey::from(value))
380    }
381}
382
383impl AsRef<[u8]> for SigningPrivateKey {
384    fn as_ref(&self) -> &[u8] {
385        match self {
386            Self::Ed25519(key) => key.as_bytes(),
387        }
388    }
389}
390
391/// Signing public key.
392#[derive(Debug, Clone, PartialEq, Eq)]
393pub enum SigningPublicKey {
394    /// EdDSA.
395    Ed25519(ed25519_dalek::VerifyingKey),
396
397    /// ECDSA-SHA256-P256
398    //
399    // Taken from `ire` which is licensed under MIT
400    //
401    // Credits to str4d
402    P256(p256::EncodedPoint, p256::ecdsa::VerifyingKey),
403
404    /// DSA-SHA1.
405    //
406    // Taken from `ire` which is licensed under MIT
407    //
408    // Credits to str4d
409    DsaSha1(DsaPublicKey),
410}
411
412impl SigningPublicKey {
413    /// Create signing public key from bytes.
414    //
415    // TODO: verify it's valid point on the curve
416    pub fn from_bytes(key: &[u8; 32]) -> Option<Self> {
417        Some(SigningPublicKey::Ed25519(
418            ed25519_dalek::VerifyingKey::from_bytes(key).ok()?,
419        ))
420    }
421
422    /// Attempt to construct `SigningPublicKey::P256` from `data`.
423    pub fn p256(data: &[u8]) -> Option<Self> {
424        let encoded = p256::EncodedPoint::from_untagged_bytes(data.into());
425
426        Some(Self::P256(
427            encoded,
428            p256::ecdsa::VerifyingKey::from_encoded_point(&encoded).ok()?,
429        ))
430    }
431
432    /// Attempt to construct `SigningPublicKey::P256` from `data`.
433    pub fn dsa_sha1(data: &[u8]) -> Option<Self> {
434        DsaPublicKey::from_bytes(data).map(Self::DsaSha1)
435    }
436
437    /// Verify `signature` of `message`.
438    pub fn verify(&self, message: &[u8], signature: &[u8]) -> crate::Result<()> {
439        match self {
440            Self::Ed25519(key) => {
441                let signature: [u8; 64] = signature.try_into().map_err(|_| Error::InvalidData)?;
442                let signature = ed25519_dalek::Signature::from_bytes(&signature);
443
444                key.verify_strict(message, &signature).map_err(From::from)
445            }
446            Self::P256(_, vk) => {
447                let signature =
448                    p256::ecdsa::Signature::try_from(signature).map_err(|_| Error::InvalidData)?;
449
450                vk.verify(message, &signature).map_err(|_| Error::InvalidData)
451            }
452            Self::DsaSha1(public_key) => {
453                let signature = DsaSignature::from_bytes(signature).ok_or(Error::InvalidData)?;
454
455                match public_key.verify(message, &signature) {
456                    true => Ok(()),
457                    false => Err(Error::InvalidData),
458                }
459            }
460        }
461    }
462
463    /// Get signature length.
464    pub fn signature_len(&self) -> usize {
465        match self {
466            Self::Ed25519(_) => 64usize,
467            Self::P256(_, _) => 64usize,
468            Self::DsaSha1(_) => 40usize,
469        }
470    }
471}
472
473impl AsRef<[u8]> for SigningPublicKey {
474    fn as_ref(&self) -> &[u8] {
475        match self {
476            Self::Ed25519(key) => key.as_bytes(),
477            Self::P256(pk, _) => &pk.as_bytes()[1..],
478            Self::DsaSha1(key) => key.as_bytes(),
479        }
480    }
481}