1extern crate sodiumoxide;
2extern crate libc;
3
4extern crate rpassword;
5extern crate base64;
6
7use sodiumoxide::crypto::pwhash::*;
8use sodiumoxide::crypto::pwhash;
9use sodiumoxide::crypto::sign::*;
10use sodiumoxide::crypto::sign;
11use sodiumoxide::randombytes::randombytes;
12
13
14use std::fs::File;
15use std::io::{self, BufWriter, Write};
16
17
18pub mod parse_args;
19pub mod generichash;
20pub mod perror;
21pub mod types;
22
23pub use generichash::*;
24pub use parse_args::*;
25pub use perror::*;
26pub use types::*;
27
28
29pub fn gen_keystruct() -> (PubkeyStruct, SeckeyStruct) {
30 let (pk, sk) = gen_keypair();
31 let SecretKey(sk) = sk;
32 let PublicKey(pk) = pk;
33
34 let keynum_vec = randombytes(KEYNUMBYTES);
35 let mut keynum = [0u8; KEYNUMBYTES];
36 keynum.copy_from_slice(keynum_vec.as_slice());
37
38 let kdf_salt_vec = randombytes(SALTBYTES);
39 let mut kdf_salt = [0u8; SALTBYTES];
40 kdf_salt.copy_from_slice(kdf_salt_vec.as_slice());
41
42 let OpsLimit(ops_limit) = OPSLIMIT_SENSITIVE;
43 let MemLimit(mem_limit) = MEMLIMIT_SENSITIVE;
44
45 let p_struct = PubkeyStruct {
46 sig_alg: SIGALG,
47 keynum_pk: KeynumPK {
48 keynum: keynum,
49 pk: pk,
50 },
51 };
52 let s_struct = SeckeyStruct {
53 sig_alg: SIGALG,
54 kdf_alg: KDFALG,
55 chk_alg: CHKALG,
56 kdf_salt: kdf_salt,
57 kdf_opslimit_le: store_usize_le(ops_limit),
58 kdf_memlimit_le: store_usize_le(mem_limit),
59 keynum_sk: KeynumSK {
60 keynum: keynum.clone(),
61 sk: sk,
62 chk: [0; BYTES],
63 },
64 };
65 (p_struct, s_struct)
66}
67
68pub fn get_password(prompt: &str) -> Result<String> {
69 let pwd = rpassword::prompt_password_stdout(prompt)?;
70 if pwd.len() == 0 {
71 println!("<empty>");
72 Ok(pwd)
73 } else if pwd.len() > PASSWORDMAXBYTES {
74 Err(PError::new(ErrorKind::Misc, "passphrase can't exceed 1024 bytes lenght"))
75 } else {
76 Ok(pwd)
77 }
78}
79
80pub fn store_usize_le(x: usize) -> [u8; 8] {
81 let b1: u8 = (x & 0xff) as u8;
82 let b2: u8 = ((x >> 8) & 0xff) as u8;
83 let b3: u8 = ((x >> 16) & 0xff) as u8;
84 let b4: u8 = ((x >> 24) & 0xff) as u8;
85 let b5: u8 = ((x >> 32) & 0xff) as u8;
86 let b6: u8 = ((x >> 40) & 0xff) as u8;
87 let b7: u8 = ((x >> 48) & 0xff) as u8;
88 let b8: u8 = ((x >> 56) & 0xff) as u8;
89 return [b1, b2, b3, b4, b5, b6, b7, b8];
90}
91
92pub fn load_usize_le(x: &[u8]) -> usize {
93 (x[0] as usize) | (x[1] as usize) << 8 | (x[2] as usize) << 16 | (x[3] as usize) << 24 |
94 (x[4] as usize) << 32 | (x[5] as usize) << 40 |
95 (x[6] as usize) << 48 | (x[7] as usize) << 56
96}
97pub fn verify(pk_key: PubkeyStruct,
98 sig: SigStruct,
99 global_sig: &[u8],
100 trusted_comment: &[u8],
101 message: &[u8],
102 quiet: bool,
103 output: bool)
104 -> Result<()> {
105
106 if sig.keynum != pk_key.keynum_pk.keynum {
107 return Err(PError::new(ErrorKind::Verify,
108 format!("Signature key id: {:X} is different from public key: {:X}",
109 load_usize_le(&sig.keynum[..]),
110 load_usize_le(&pk_key.keynum_pk.keynum[..]))));
111 }
112 Signature::from_slice(&sig.sig)
113 .ok_or(PError::new(ErrorKind::Verify,
114 "Couldn't compose message file signature from bytes"))
115 .and_then(|signature| {
116 PublicKey::from_slice(&pk_key.keynum_pk.pk)
117 .ok_or(PError::new(ErrorKind::Verify,
118 "Couldn't compose a public key from bytes"))
119 .and_then(|pk| if sign::verify_detached(&signature, &message, &pk) {
120 Ok(pk)
121 } else {
122 Err(PError::new(ErrorKind::Verify, "Signature verification failed"))
123 })
124 .and_then(|pk| {
125 Signature::from_slice(&global_sig[..])
126 .ok_or(PError::new(ErrorKind::Verify,
127 "Couldn't compose trusted comment signature from bytes"))
128 .and_then(|global_sig| if sign::verify_detached(&global_sig,
129 &trusted_comment,
130 &pk) {
131 let just_comment =
132 String::from_utf8(trusted_comment[SIGNATUREBYTES..]
133 .to_vec())?;
134 if !quiet {
135 println!("Signature and comment signature verified");
136 println!("Trusted comment: {}", just_comment);
137 }
138 if output {
139 print!("{}", String::from_utf8_lossy(&message[..]));
140 }
141 Ok(())
142 } else {
143 return Err(PError::new(ErrorKind::Verify,
144 "Comment signature verification \
145 failed"));
146 })
147 })
148 })
149}
150
151pub fn sign<W>(sk_key: SeckeyStruct,
152 pk_key: Option<PubkeyStruct>,
153 mut sig_buf: W,
154 message: &[u8],
155 hashed: bool,
156 trusted_comment: &str,
157 untrusted_comment: &str)
158 -> Result<()>
159 where W: Write
160{
161
162 let mut sig_str = SigStruct::default();
163 if !hashed {
164 sig_str.sig_alg = sk_key.sig_alg.clone();
165 } else {
166 sig_str.sig_alg = SIGALG_HASHED;
167 }
168 sig_str
169 .keynum
170 .copy_from_slice(&sk_key.keynum_sk.keynum[..]);
171
172 let sk = SecretKey::from_slice(&sk_key.keynum_sk.sk)
173 .ok_or(PError::new(ErrorKind::Sign, "Couldn't generate secret key from bytes"))?;
174
175 let signature = sodiumoxide::crypto::sign::sign_detached(message, &sk);
176
177 sig_str.sig.copy_from_slice(&signature[..]);
178
179 let mut sig_and_trust_comment: Vec<u8> = vec![];
180 sig_and_trust_comment.extend(sig_str.sig.iter());
181 sig_and_trust_comment.extend(trusted_comment.as_bytes().iter());
182
183 let global_sig = sodiumoxide::crypto::sign::sign_detached(&sig_and_trust_comment, &sk);
184
185 if let Some(pk_str) = pk_key {
186 PublicKey::from_slice(&pk_str.keynum_pk.pk[..])
187 .ok_or(PError::new(ErrorKind::Sign, "failed to obtain public key from bytes"))
188 .and_then(|pk|{
189 if !sodiumoxide::crypto::sign::verify_detached(&global_sig, &sig_and_trust_comment, &pk) {
190 Err(PError::new(ErrorKind::Verify,format!("Could not verify signature with the \
191 provided public key ID: {:X}", load_usize_le(&pk_str.keynum_pk.keynum[..]))))
192 } else {
193 println!("\nSignature checked with the public key ID: {:X}",
194 load_usize_le(&pk_str.keynum_pk.keynum[..]));
195 Ok(())
196 }
197 })?;
198 }
199
200 writeln!(sig_buf, "{}", untrusted_comment)?;
201 writeln!(sig_buf, "{}", base64::encode(&sig_str.bytes()))?;
202 writeln!(sig_buf, "{}{}", TRUSTED_COMMENT_PREFIX, trusted_comment)?;
203 writeln!(sig_buf, "{}", base64::encode(&global_sig[..]))?;
204 sig_buf.flush()?;
205 Ok(())
206}
207
208pub fn generate(mut pk_file: BufWriter<File>,
209 mut sk_file: BufWriter<File>,
210 comment: Option<&str>)
211 -> Result<(PubkeyStruct, SeckeyStruct)> {
212 let (pk_str, mut sk_str) = gen_keystruct();
213 sk_str
214 .write_checksum()
215 .map_err(|_| PError::new(ErrorKind::Generate, "failed to hash and write checksum!"))?;
216 write!(io::stdout(),
217 "Please enter a password to protect the secret key.\n")?;
218 let pwd = get_password("Password: ")?;
219 let pwd2 = get_password("Password (one more time): ")?;
220 if pwd != pwd2 {
221 return Err(PError::new(ErrorKind::Generate, "passwords don't match!"));
222 }
223
224 write!(io::stdout(),
225 "Deriving a key from the password in order to encrypt the secret key... ")
226 .map_err(|e| PError::new(ErrorKind::Io, e))
227 .and_then(|_| {
228 io::stdout().flush()?;
229 derive_and_crypt(&mut sk_str, &pwd.as_bytes())
230 })
231 .and(writeln!(io::stdout(), "done").map_err(|e| PError::new(ErrorKind::Io, e)))?;
232
233
234 write!(pk_file, "{}rsign public key: ", COMMENT_PREFIX)?;
235 writeln!(pk_file, "{:X}", load_usize_le(&pk_str.keynum_pk.keynum[..]))?;
236 writeln!(pk_file, "{}", base64::encode(&pk_str.bytes()))?;
237 pk_file.flush()?;
238
239
240 write!(sk_file, "{}", COMMENT_PREFIX)?;
241 if let Some(comment) = comment {
242 writeln!(sk_file, "{}", comment)?;
243 } else {
244 writeln!(sk_file, "{}", SECRETKEY_DEFAULT_COMMENT)?;
245 }
246 writeln!(sk_file, "{}", base64::encode(&sk_str.bytes()))?;
247 sk_file.flush()?;
248
249 Ok((pk_str, sk_str))
250}
251
252pub fn derive_and_crypt(sk_str: &mut SeckeyStruct, pwd: &[u8]) -> Result<()> {
253 let mut stream = [0u8; BYTES + SECRETKEYBYTES + KEYNUMBYTES];
254 pwhash::Salt::from_slice(&sk_str.kdf_salt)
255 .ok_or(PError::new(ErrorKind::Misc, "failed to generate Salt from random bytes"))
256 .and_then(|salt| {
257
258 pwhash::derive_key(&mut stream,
259 &pwd,
260 &salt,
261 OpsLimit(load_usize_le(&sk_str.kdf_opslimit_le)),
262 MemLimit(load_usize_le(&sk_str.kdf_memlimit_le)))
263 .map_err(|_| PError::new(ErrorKind::Misc, "failed to derive key from password"))
264
265 })?;
266 sk_str.xor_keynum(&stream);
267 Ok(())
268}
269
270#[cfg(test)]
271mod tests {
272
273 #[test]
274 fn byte_array_store() {
275 use store_usize_le;
276 assert_eq!([0xFF, 0, 0, 0, 0, 0, 0, 0], store_usize_le(0xFF));
277 }
278 #[test]
279 fn byte_array_load() {
280 use load_usize_le;
281 assert_eq!(255, load_usize_le(&[0xFF, 0, 0, 0, 0, 0, 0, 0]));
282 }
283
284 #[test]
285 fn pk_key_struct_conversion() {
286 use gen_keystruct;
287 use PubkeyStruct;
288 let (pk, _) = gen_keystruct();
289 assert_eq!(pk, PubkeyStruct::from(&pk.bytes()).unwrap());
290 }
291 #[test]
292 fn sk_key_struct_conversion() {
293 use gen_keystruct;
294 use SeckeyStruct;
295 let (_, sk) = gen_keystruct();
296 assert_eq!(sk, SeckeyStruct::from(&sk.bytes()).unwrap());
297 }
298
299 #[test]
300 fn xor_keynum() {
301 use randombytes;
302 use gen_keystruct;
303 let (_, mut sk) = gen_keystruct();
304 let key = randombytes(sk.keynum_sk.len());
305 let original_keynum = sk.keynum_sk.clone();
306 sk.xor_keynum(&key);
307 assert_ne!(original_keynum, sk.keynum_sk);
308 sk.xor_keynum(&key);
309 assert_eq!(original_keynum, sk.keynum_sk);
310
311 }
312 #[test]
313 fn sk_checksum() {
314 use gen_keystruct;
315 let (_, mut sk) = gen_keystruct();
316 assert!(sk.write_checksum().is_ok());
317 assert_eq!(sk.keynum_sk.chk.to_vec(), sk.read_checksum().unwrap());
318
319 }
320}