sos_core/crypto/
private_key.rs1use age::x25519::Identity;
3use argon2::password_hash::SaltString;
4use secrecy::{ExposeSecret, SecretBox, SecretString};
5use std::convert::AsRef;
6use std::fmt;
7
8use crate::{
9 crypto::{KeyDerivation, Seed},
10 Result,
11};
12
13#[derive(Clone)]
15pub enum AccessKey {
16 Password(SecretString),
18 Identity(Identity),
20}
21
22impl From<SecretString> for AccessKey {
23 fn from(value: SecretString) -> Self {
24 Self::Password(value)
25 }
26}
27
28impl From<Identity> for AccessKey {
29 fn from(value: Identity) -> Self {
30 Self::Identity(value)
31 }
32}
33
34impl From<AccessKey> for SecretString {
35 fn from(value: AccessKey) -> Self {
36 match value {
37 AccessKey::Password(password) => password,
38 AccessKey::Identity(id) => id.to_string().into(),
39 }
40 }
41}
42
43impl AccessKey {
44 pub fn into_private(
46 self,
47 kdf: &KeyDerivation,
48 salt: &SaltString,
49 seed: Option<&Seed>,
50 ) -> Result<PrivateKey> {
51 match self {
52 Self::Password(ref password) => {
53 let deriver = kdf.deriver();
54 Ok(PrivateKey::Symmetric(
55 deriver.derive(password, salt, seed)?,
56 ))
57 }
58 Self::Identity(id) => Ok(PrivateKey::Asymmetric(id)),
59 }
60 }
61}
62
63impl fmt::Debug for AccessKey {
64 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65 match self {
66 Self::Password(_) => f.debug_struct("Password").finish(),
67 Self::Identity(_) => f.debug_struct("Identity").finish(),
68 }
69 }
70}
71
72impl PartialEq for AccessKey {
73 fn eq(&self, other: &Self) -> bool {
74 match (self, other) {
75 (Self::Password(a), Self::Password(b)) => {
76 a.expose_secret() == b.expose_secret()
77 }
78 (Self::Identity(a), Self::Identity(b)) => {
79 a.to_string().expose_secret() == b.to_string().expose_secret()
80 }
81 _ => false,
82 }
83 }
84}
85
86impl Eq for AccessKey {}
87
88pub enum PrivateKey {
90 Symmetric(DerivedPrivateKey),
92 Asymmetric(Identity),
94}
95
96pub struct DerivedPrivateKey {
98 inner: SecretBox<Vec<u8>>,
99}
100
101impl DerivedPrivateKey {
102 pub fn generate() -> Self {
104 use crate::crypto::csprng;
105 use rand::Rng;
106 let bytes: [u8; 32] = csprng().gen();
107 Self {
108 inner: SecretBox::new(Box::new(bytes.to_vec())),
109 }
110 }
111
112 pub fn from_pem(key: &str) -> Result<Self> {
114 let pem = pem::parse(key)?;
115 let contents = pem.contents();
116 Ok(Self {
117 inner: SecretBox::new(Box::new(contents.to_vec())),
118 })
119 }
120
121 pub fn to_pem(&self) -> String {
123 pem::encode(&pem::Pem::new(
124 "PRIVATE KEY",
125 self.inner.expose_secret().as_slice(),
126 ))
127 }
128
129 pub(crate) fn new(inner: SecretBox<Vec<u8>>) -> Self {
131 Self { inner }
132 }
133}
134
135impl AsRef<[u8]> for DerivedPrivateKey {
136 fn as_ref(&self) -> &[u8] {
137 self.inner.expose_secret()
138 }
139}
140
141impl From<Vec<u8>> for DerivedPrivateKey {
142 fn from(value: Vec<u8>) -> Self {
143 Self {
144 inner: SecretBox::new(value.into()),
145 }
146 }
147}