1use std::cmp;
2use std::convert::TryInto;
3use std::fmt::Write as fmtWrite;
4use std::fs;
5use std::io::{Cursor, Read};
6use std::path::Path;
7
8use ct_codecs::{Base64, Decoder, Encoder};
9
10use crate::crypto::util::fixed_time_eq;
11use crate::errors::*;
12use crate::helpers::*;
13use crate::keynum::*;
14use crate::{constants::*, SecretKey};
15
16#[derive(Clone, Debug)]
25pub struct PublicKeyBox(String);
26
27impl From<PublicKeyBox> for String {
28 fn from(pkb: PublicKeyBox) -> String {
29 pkb.0
30 }
31}
32
33impl From<String> for PublicKeyBox {
34 fn from(s: String) -> PublicKeyBox {
35 PublicKeyBox(s)
36 }
37}
38
39impl ToString for PublicKeyBox {
40 fn to_string(&self) -> String {
41 self.0.to_string()
42 }
43}
44
45impl From<PublicKeyBox> for PublicKey {
46 fn from(pkb: PublicKeyBox) -> PublicKey {
47 pkb.into_public_key().unwrap()
48 }
49}
50
51impl PublicKeyBox {
52 pub fn from_string(s: &str) -> Result<PublicKeyBox> {
54 Ok(s.to_string().into())
55 }
56
57 pub fn into_string(self) -> String {
59 self.into()
60 }
61
62 pub fn into_public_key(self) -> Result<PublicKey> {
64 PublicKey::from_box(self)
65 }
66
67 pub fn to_bytes(&self) -> Vec<u8> {
69 self.to_string().as_bytes().to_vec()
70 }
71}
72
73#[derive(Clone, Debug)]
75pub struct PublicKey {
76 pub(crate) sig_alg: [u8; TWOBYTES],
77 pub(crate) keynum_pk: KeynumPK,
78}
79
80impl PublicKey {
81 pub fn keynum(&self) -> &[u8] {
83 &self.keynum_pk.keynum[..]
84 }
85
86 pub fn from_bytes(buf: &[u8]) -> Result<PublicKey> {
90 let mut buf = Cursor::new(buf);
91 let mut sig_alg = [0u8; TWOBYTES];
92 let mut keynum = [0u8; KEYNUM_BYTES];
93 let mut pk = [0u8; PUBLICKEY_BYTES];
94 buf.read_exact(&mut sig_alg)?;
95 buf.read_exact(&mut keynum)?;
96 buf.read_exact(&mut pk)?;
97 Ok(PublicKey {
98 sig_alg,
99 keynum_pk: KeynumPK { keynum, pk },
100 })
101 }
102
103 pub fn from_secret_key(sk: &SecretKey) -> Result<PublicKey> {
105 let sig_alg = sk.sig_alg;
106 let keynum = sk.keynum_sk.keynum;
107 let pk = sk.keynum_sk.sk[PUBLICKEY_BYTES..].try_into().map_err(|_| {
108 PError::new(
109 ErrorKind::Misc,
110 "secret key does not contain public key".to_string(),
111 )
112 })?;
113
114 Ok(PublicKey {
115 sig_alg,
116 keynum_pk: KeynumPK { keynum, pk },
117 })
118 }
119
120 pub fn to_bytes(&self) -> Vec<u8> {
124 let mut iters = Vec::new();
125 iters.push(self.sig_alg.iter());
126 iters.push(self.keynum_pk.keynum.iter());
127 iters.push(self.keynum_pk.pk.iter());
128 let v: Vec<u8> = iters
129 .iter()
130 .flat_map(|b| {
131 let b = b.clone();
132 b.cloned()
133 })
134 .collect();
135 v
136 }
137
138 pub fn from_box(pk_box: PublicKeyBox) -> Result<PublicKey> {
140 let s = pk_box.0;
141 let mut lines = s.lines();
142 lines.next().ok_or_else(|| {
143 PError::new(ErrorKind::Io, "Missing comment in public key".to_string())
144 })?;
145 let encoded_pk = lines.next().ok_or_else(|| {
146 PError::new(
147 ErrorKind::Io,
148 "Missing encoded key in public key".to_string(),
149 )
150 })?;
151 if encoded_pk.len() != PK_B64_ENCODED_LEN {
152 return Err(PError::new(
153 ErrorKind::Io,
154 "Base64 conversion failed - was an actual public key given?".to_string(),
155 ));
156 }
157 let decoded_buf = Base64::decode_to_vec(encoded_pk.trim(), None).map_err(|e| {
158 PError::new(
159 ErrorKind::Io,
160 format!("Base64 conversion failed - was an actual public key given?: {e}"),
161 )
162 })?;
163 PublicKey::from_bytes(&decoded_buf)
164 }
165
166 pub fn to_box(&self) -> Result<PublicKeyBox> {
168 let mut s = String::new();
169 write!(s, "{COMMENT_PREFIX}minisign public key: ")?;
170 writeln!(s, "{:016X}", load_u64_le(&self.keynum_pk.keynum[..]))?;
171 writeln!(s, "{}", self.to_base64())?;
172 Ok(s.into())
173 }
174
175 pub fn from_base64(pk_string: &str) -> Result<PublicKey> {
177 let encoded_string = pk_string.to_string();
178 if encoded_string.trim().len() != PK_B64_ENCODED_LEN {
179 return Err(PError::new(
180 ErrorKind::Io,
181 "base64 conversion failed - was an actual public key given?".to_string(),
182 ));
183 }
184 let decoded_string =
185 Base64::decode_to_vec(encoded_string.as_bytes(), None).map_err(|e| {
186 PError::new(
187 ErrorKind::Io,
188 format!("base64 conversion failed - was an actual public key given?: {e}"),
189 )
190 })?;
191 PublicKey::from_bytes(&decoded_string)
192 }
193
194 pub fn to_base64(&self) -> String {
196 Base64::encode_to_string(self.to_bytes().as_slice()).unwrap()
197 }
198
199 pub fn from_file<P>(pk_path: P) -> Result<PublicKey>
201 where
202 P: AsRef<Path>,
203 {
204 let s = fs::read_to_string(pk_path)?;
205 PublicKey::from_box(s.into())
206 }
207}
208
209impl cmp::PartialEq for PublicKey {
210 fn eq(&self, other: &PublicKey) -> bool {
211 fixed_time_eq(&self.keynum_pk.pk, &other.keynum_pk.pk)
212 }
213}
214
215impl cmp::Eq for PublicKey {}