jedisct1 / rust-minisign

A pure Rust implementation of the Minisign signature tool.
Other
92 stars 15 forks source link

Sign and verify test times out #1

Closed MarkMcCaskey closed 5 years ago

MarkMcCaskey commented 5 years ago

Hello! Thanks for maintaining this crate!!

While implementing things for wapm, I was running in to some issues, so I decided to make a test case. After making the test case, I noticed a new issue:

#[cfg(test)]
mod test {
    #[test]
    fn sanity_check() {
        let public_key = "untrusted comment: minisign public key 3013F76F7B1F0672
RWRyBh97b/cTMGoJsnKDGmleEpeCGBg9AMxJYeSYsIXYo09Hq6mg7irv";
        let private_key = "untrusted comment: minisign encrypted secret key
RWRTY0IyUIpMvYs4tqNv2cTpBMGYhg2sCN8aCzICPKRNlK19UR4AAAACAAAAAAAAAEAAAAAAArdUKPFVxDpsyIJK5yVkB3f/t1oIL8HUfXDI2TEKgfEbll/bfhGt7zf+8m7DEpVu6S18Nx7lyDyiDgEMSEhS4SeJg0cn4ckpHNO15OZuVt0SGpG1EjsXtGS1xnj+MaCh91xbAqdQrzY=";

        let data = std::fs::File::open("/Users/mark/hello.txt").unwrap();

        let pub_key = minisign::PublicKey::from_base64(&public_key.lines().skip(1).next().unwrap())
            .expect("PK");
        let priv_key = minisign::SecretKeyBox::from_string(&private_key)
            .unwrap()
            .into_secret_key(Some("a".to_string()))
            .expect("priv key");

        let sig = minisign::sign(Some(&pub_key), &priv_key, &data, false, None, None)
            .expect("sign")
            .to_string();

        let sig_box = minisign::SignatureBox::from_string(&sig).expect("sig box");
        assert!(minisign::verify(&pub_key, &sig_box, &data, true, false).is_ok());
    }
}

This appears to get stuck in an infinite loop. If it's not an infinite loop, it's very slow. I've let it sit for about 10 minutes or so.

hello.txt is just a file with hello in it.

I briefly looked over the code and wasn't able to identify the location of the problem

jedisct1 commented 5 years ago

The encoded secret key contains the required memory and iterations required to derive a key from the password.

How did you create that key? Although valid, the memory parameter is far more than expected. Also, key derivation is way slower in debug mode than in release mode.

I'll add some sanity checks.

jedisct1 commented 5 years ago

Looks like the key was created by a non-Rust implementation. Which is ok, but if they are used in Rust, only use release mode. The generated code in debug mode is very slow.

MarkMcCaskey commented 5 years ago

Thanks for following up!

That's interesting! I always thought cargo test ran in release mode by default. When running in release mode the test terminates quickly.

I generated this key pair with minisign 0.8. The exact invocation was minisign -G -f if that matters.

It seems that may be the issue I was having before!

I'm seeing the error thread 'test::sanity_check' panicked at 'priv key: PError { kind: KDF, err: StringError("scrypt parameters too high") }', src/libcore/result.rs:997:5 in my updated test, which would explain why the signature was failing to verify before

MarkMcCaskey commented 5 years ago

Hmm, so I generated a new key pair using rsign2 (installed from cargo):

#[cfg(test)]
mod test {
    #[test]
    fn sanity_check() {
        let public_key = "untrusted comment: minisign public key: 2CEA8FF81E67D102
RWQC0Wce+I/qLFqCofdCWxpyboWjbmKPFsZOEV6NEj0vcAEy/9IqZgkS";
        let private_key = "untrusted comment: rsign encrypted secret key
RWRTY0IyOj19OGbiN9l+lStXBFlKm55v1O/Qbf0GaPxOYO9D+B8AABAAAAAAAAAAAAIAAAAAefAJP+rH/VvDR8QYqZhnJYk27b7o6oASDHOkITBhjN0kcxEfjiU1kTRT1XvmfpU8d0YpvdMpTLW+FdnrMfF5glrigyCiIQMpSkVWMsRUl/GX+skqh/ysixklCnWs5J+RWC1iYvZZViI=";

        let data = std::fs::File::open("/Users/mark/hello.txt").unwrap();

        let pub_key = minisign::PublicKey::from_base64(&public_key.lines().skip(1).next().unwrap())
            .expect("PK");
        let priv_key = minisign::SecretKeyBox::from_string(&private_key)
            .unwrap()
            .into_secret_key(Some("a".to_string()))
            .expect("priv key");

        let sig = minisign::sign(Some(&pub_key), &priv_key, &data, false, None, None)
            .expect("sign")
            .to_string();

        let sig_box = minisign::SignatureBox::from_string(&sig).expect("sig box");
        println!(
            "{:?}",
            minisign::verify(&pub_key, &sig_box, &data, true, false)
        );
        assert!(minisign::verify(&pub_key, &sig_box, &data, true, false).is_ok());
    }
}

and the test is failing

running 1 test
test test::sanity_check ... FAILED

failures:

---- test::sanity_check stdout ----
Err(PError { kind: Verify, err: StringError("Signature verification failed") })
thread 'test::sanity_check' panicked at 'assertion failed: minisign::verify(&pub_key, &sig_box, &data, true, false).is_ok()', src/main.rs:32:9
note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.

failures:
    test::sanity_check

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out

Perhaps I'm misusing the API? I'll see if I can make any changes to fix it

MarkMcCaskey commented 5 years ago

Okay, I fixed it!

Adding let data = std::fs::File::open("/Users/mark/hello.txt").unwrap(); or data.seek(::std::io::SeekFrom::Start(0)); before verifying the signature worked!

thanks, thanks!