1#![doc = include_str!("../README.md")]
3mod constants;
4use blake2::Digest;
5use std::io::Read;
6
7use constants::*;
8mod errors;
9pub use errors::*;
10pub use public_key::PublicKeyBox;
11use public_key::{PublicKey, RawPk};
12pub use secret_key::SecretKeyBox;
13use signature::Signature;
14mod keypair;
15pub use keypair::KeyPairBox;
16mod public_key;
17mod secret_key;
18mod signature;
19pub use signature::SignatureBox;
20
21use crate::public_key::verify_prehashed;
22use crate::util::validate_comment;
23mod util;
24fn prehash<R>(data_reader: &mut R) -> Result<Vec<u8>>
25where
26 R: Read,
27{
28 let mut hash = blake2::Blake2b512::new();
29 let mut buf = [0; 2048];
30 loop {
31 let n = data_reader.read(&mut buf)?;
32 if n == 0 {
33 break;
34 }
35 hash.update(&buf[..n]);
36 }
37 Ok(hash.finalize().to_vec())
38}
39pub fn pub_key_from_str(s: &str) -> Result<PublicKeyBox<'_>> {
41 PublicKeyBox::from_str(s)
42}
43pub fn sec_key_from_str(s: &str) -> Result<SecretKeyBox<'_>> {
45 SecretKeyBox::from_str(s)
46}
47pub fn pub_key_from_sec_key<'s>(
51 sec_key: &SecretKeyBox<'s>,
52 password: Option<&[u8]>,
53) -> Result<PublicKeyBox<'s>> {
54 let keynum_sk = sec_key.xor_keynum_sk(password)?;
55 PublicKeyBox::new(
56 None,
57 PublicKey::new(
58 sec_key.sig_alg(),
59 keynum_sk.key_id,
60 RawPk(keynum_sk.pub_key),
61 ),
62 )
63}
64
65pub fn sign<'a, R>(
80 pk: Option<&PublicKeyBox>,
81 sk: &SecretKeyBox,
82 password: Option<&[u8]>,
83 mut data_reader: R,
84 trusted_comment: Option<&'a str>,
85 untrusted_comment: Option<&'a str>,
86) -> Result<SignatureBox<'a>>
87where
88 R: Read,
89{
90 validate_comment(trusted_comment, ErrorKind::SignatureError)?;
91 validate_comment(untrusted_comment, ErrorKind::SignatureError)?;
92 let prehashed = prehash(&mut data_reader)?;
93 let sig = sk.sign(&prehashed, password)?;
94 let mut global_data = sig.to_bytes().to_vec();
95 global_data.extend_from_slice(trusted_comment.unwrap_or("").as_bytes());
96 let global_sig = sk.sign(&global_data, password)?;
97 let keynum_sk = sk.xor_keynum_sk(password)?;
98 let signature = Signature::new(SIGALG_PREHASHED, keynum_sk.key_id, sig, global_sig);
99 let sig_box = SignatureBox::new(untrusted_comment, trusted_comment, signature)?;
100 if let Some(pk) = pk {
101 verify_prehashed(pk, &sig_box, &prehashed)?;
102 }
103 Ok(sig_box)
104}
105pub fn verify<R>(
117 pk: &PublicKeyBox,
118 signature_box: &SignatureBox,
119 mut data_reader: R,
120) -> Result<bool>
121where
122 R: Read,
123{
124 let prehashed = prehash(&mut data_reader)?;
125 verify_prehashed(pk, signature_box, &prehashed)
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131 #[test]
132 fn test() {
133 let KeyPairBox {
134 public_key_box,
135 secret_key_box,
136 } = KeyPairBox::generate(
137 Some(b"password"),
138 Some("pk untrusted comment"),
139 Some("sk untrusted comment"),
140 )
141 .unwrap();
142 let msg = "test";
143 let sig_box = sign(
144 Some(&public_key_box),
145 &secret_key_box,
146 Some(b"password"),
147 msg.as_bytes(),
148 Some("trusted comment"),
149 Some("untrusted comment"),
150 )
151 .unwrap();
152 let v = verify(&public_key_box, &sig_box, msg.as_bytes()).unwrap();
153 assert!(v);
154 }
155 #[test]
156 fn test_sign_rejects_comment_control_characters() {
157 let KeyPairBox {
158 public_key_box,
159 secret_key_box,
160 } = KeyPairBox::generate(Some(b"password"), None, None).unwrap();
161
162 assert!(sign(
163 Some(&public_key_box),
164 &secret_key_box,
165 Some(b"password"),
166 "test".as_bytes(),
167 Some("trusted\ncomment"),
168 Some("untrusted comment"),
169 )
170 .is_err());
171 assert!(sign(
172 Some(&public_key_box),
173 &secret_key_box,
174 Some(b"password"),
175 "test".as_bytes(),
176 Some("trusted comment"),
177 Some("untrusted\0comment"),
178 )
179 .is_err());
180 }
181}