mini_sign/
lib.rs

1mod constants;
2use blake2::Digest;
3use std::io::Read;
4
5use constants::*;
6mod errors;
7pub use errors::*;
8pub use public_key::PublicKeyBox;
9use public_key::{PublicKey, RawPk};
10pub use secret_key::SecretKeyBox;
11use signature::Signature;
12mod keypair;
13pub use keypair::KeyPairBox;
14mod public_key;
15mod secret_key;
16mod signature;
17pub use signature::SignatureBox;
18mod util;
19fn prehash<R>(data_reader: &mut R) -> Result<Vec<u8>>
20where
21    R: Read,
22{
23    let mut hash = blake2::Blake2b512::new();
24    let mut buf = [0; 2048];
25    loop {
26        let n = data_reader.read(&mut buf)?;
27        if n == 0 {
28            break;
29        }
30        hash.update(&buf[..n]);
31    }
32    Ok(hash.finalize().to_vec())
33}
34/// Create a new public key from a string in the minisign format pub key file
35pub fn pub_key_from_str(s: &str) -> Result<PublicKeyBox> {
36    PublicKeyBox::from_str(s)
37}
38/// Create a new secret key from a string in the minisign format key file
39pub fn sec_key_from_str(s: &str) -> Result<SecretKeyBox> {
40    SecretKeyBox::from_str(s)
41}
42/// Create a new public key from a secret key
43///
44/// default comment is None
45pub fn pub_key_from_sec_key<'s>(
46    sec_key: &SecretKeyBox<'s>,
47    password: Option<&[u8]>,
48) -> Result<PublicKeyBox<'s>> {
49    let keynum_sk = sec_key.xor_keynum_sk(password)?;
50    let pk_box = PublicKeyBox::new(
51        None,
52        PublicKey::new(
53            sec_key.secret_key.sig_alg,
54            keynum_sk.key_id,
55            RawPk(keynum_sk.pub_key),
56        ),
57    );
58    Ok(pk_box)
59}
60/// minisign some data
61/// # Arguments
62/// * `pk` - The public key to verify the signature(optional)
63/// * `sk` - The secret key to sign the data
64/// * `password` - The password to decrypt the secret key
65/// * `data_reader` - The data to sign
66/// * `trusted_comment` - The trusted comment for the signature
67/// * `untrusted_comment` - The untrusted comment for the signature
68/// # Returns
69/// A Result containing the signature
70/// # Errors
71/// * `ErrorKind::Io` - If there is an error reading the data
72/// * `ErrorKind::SecretKey` - If there is an error decrypting the secret key,password is wrong
73/// * `ErrorKind::PublicKey` - If the public key is invalid or not matching the secret key
74pub fn sign<'a, R>(
75    pk: Option<&PublicKeyBox>,
76    sk: &SecretKeyBox,
77    password: Option<&[u8]>,
78    mut data_reader: R,
79    trusted_comment: Option<&'a str>,
80    untrusted_comment: Option<&'a str>,
81) -> Result<SignatureBox<'a>>
82where
83    R: Read,
84{
85    let prehashed = prehash(&mut data_reader)?;
86    let sig = sk.sign(&prehashed, password)?;
87    let mut global_data = sig.to_bytes().to_vec();
88    global_data.extend_from_slice(trusted_comment.unwrap_or("").as_bytes());
89    let global_sig = sk.sign(&global_data, password)?;
90    let keynum_sk = sk.xor_keynum_sk(password)?;
91    let signature = Signature::new(SIGALG_PREHASHED, keynum_sk.key_id, sig, global_sig);
92    let sig_box = SignatureBox::new(untrusted_comment, trusted_comment, signature);
93    if let Some(pk) = pk {
94        verify_prehashed(pk, &sig_box, &prehashed)?;
95    }
96    Ok(sig_box)
97}
98/// Verify a minisign signature
99/// # Arguments
100/// * `pk` - The public key to verify the signature
101/// * `signature_box` - The signature to verify
102/// * `data_reader` - The data to verify
103/// # Returns
104/// A Result containing a boolean, true if the signature is valid
105/// # Errors
106/// * `ErrorKind::Io` - If there is an error reading the data
107/// * `ErrorKind::PublicKey` - If the public key is invalid or not matching the signature
108/// * `ErrorKind::PrehashedMismatch` - If the signature is not prehashed
109pub fn verify<R>(
110    pk: &PublicKeyBox,
111    signature_box: &SignatureBox,
112    mut data_reader: R,
113) -> Result<bool>
114where
115    R: Read,
116{
117    let prehashed = prehash(&mut data_reader)?;
118    verify_prehashed(pk, signature_box, &prehashed)
119}
120fn verify_prehashed(
121    pk: &PublicKeyBox,
122    signature_box: &SignatureBox,
123    prehashed: &[u8],
124) -> Result<bool> {
125    if !signature_box.is_prehashed() {
126        return Err(SError::new(
127            ErrorKind::PrehashedMismatch,
128            "SignatureBox is not prehashed",
129        ));
130    }
131    if !pk.self_verify()? {
132        return Err(SError::new(
133            ErrorKind::PublicKey,
134            "public key self verification failed",
135        ));
136    }
137    if pk.public_key.key_id != *signature_box.key_id() {
138        return Err(SError::new(
139            ErrorKind::PublicKey,
140            "public key key_id mismatch",
141        ));
142    }
143    pk.verify(
144        prehashed,
145        &signature_box.signature,
146        signature_box.trusted_comment(),
147    )
148}
149#[cfg(test)]
150mod tests {
151
152    use super::*;
153    #[test]
154    fn test() {
155        let KeyPairBox {
156            public_key_box,
157            secret_key_box,
158        } = KeyPairBox::generate(
159            Some(b"password"),
160            Some("pk untrusted comment"),
161            Some("sk untrusted comment"),
162        )
163        .unwrap();
164        let msg = "test";
165        let sig_box = sign(
166            Some(&public_key_box),
167            &secret_key_box,
168            Some(b"password"),
169            msg.as_bytes(),
170            Some("trusted comment"),
171            Some("untrusted comment"),
172        )
173        .unwrap();
174        let v = verify(&public_key_box, &sig_box, msg.as_bytes()).unwrap();
175        assert_eq!(v, true);
176    }
177}