diff --git a/src/lib.rs b/src/lib.rs index 645628d0a31bbfba0a1943a4c426d0a14975ef26..79a0f709cc664cbac2eada01044090d72d1c56e9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2327,3 +2327,161 @@ fn test_random() { average_ones); } } + +#[cfg(test)] +mod tests { + use super::*; + + use crate::pep::Session; + + // $ sq --force key generate --cannot-authenticate \ + // --expires never --userid '' \ + // --export alice.pgp + const ALICE_PGP: &'static str = "\ +-----BEGIN PGP PRIVATE KEY BLOCK----- +Comment: 64E7 981D 4220 C6D2 6638 EA7C B72F C47E 011B C764 +Comment: + +xVgEZDcXhRYJKwYBBAHaRw8BAQdAu8SZs5zqYLLBaMpfbIuRg9CDuQNnkxGqCEiv +MnD0czYAAQD2c2gL/jPZzZHbBQ2OHycdNOep79BLfs6ZBYiTodrukBDvwsALBB8W +CgB9BYJkNxeFAwsJBwkQty/EfgEbx2RHFAAAAAAAHgAgc2FsdEBub3RhdGlvbnMu +c2VxdW9pYS1wZ3Aub3Jn37FPCmBUoG7ZfDm0Q7haM6zbXc/00GediXbjruMVCU8D +FQoIApsBAh4BFiEEZOeYHUIgxtJmOOp8ty/EfgEbx2QAAKL8AQD3bT5GYlfah/jx +agUUPAU9awR17PJiF6qWZjhk0wX5GgEAyn0OjvpkCh8IUVXpgtmuN8NoBHXvLrPH +FPpmBRhuEQfNEzxhbGljZUBleGFtcGxlLm9yZz7CwA4EExYKAIAFgmQ3F4UDCwkH +CRC3L8R+ARvHZEcUAAAAAAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5v +cmfHWWYTVAdC9hBB3QvxZv+gKmr8p8yP48nf/4pMJHCbeQMVCggCmQECmwECHgEW +IQRk55gdQiDG0mY46ny3L8R+ARvHZAAAkPcA/06QXtr0odpnQTQAzbgnDHCTisPv +TeWhbP8Bu6dPSIjPAP9aZPn+s+Pdc52SEHBOQyM5dyWpbzvgLgwzNCetez6vDcdY +BGQ3F4UWCSsGAQQB2kcPAQEHQFda1LIxdqccxiIgIbHXral59VRIPqrBnCSUckTe +lZsSAAD/f7zaMPxIrEVkSkevdsdg5Om0Cgyz+SF8f9/763kPWF4SHMLAvwQYFgoB +MQWCZDcXhQkQty/EfgEbx2RHFAAAAAAAHgAgc2FsdEBub3RhdGlvbnMuc2VxdW9p +YS1wZ3Aub3Jn7pAplEnQhQvvgDihCw52kKa/JT50MTuZPkDY5bpsVhMCmwK+oAQZ +FgoAbwWCZDcXhQkQ2W9Jvvf+shBHFAAAAAAAHgAgc2FsdEBub3RhdGlvbnMuc2Vx +dW9pYS1wZ3Aub3JnOmJvUfEy2ymUu3MyS+J92P2nuaBYjpJ2L6hcuf8Bm+gWIQQV +Suent38vsP649abZb0m+9/6yEAAApsYA/0Pdfn61X/u1GEVhCc0bKkBVYHwlXEJa +nQ+9KBVaJFWnAQCh5bNyeV+8MU9odXZWxa8sg1VeDkFCTppWTsZTH9UHBRYhBGTn +mB1CIMbSZjjqfLcvxH4BG8dkAABsNAEA9SQeJIPp9SMFJY2nCcclv0u/KxfZTBOJ +1jfMU8LrJZAA/34fNxcn99iv23yIv1QnZtBogP5cfcxxhnaHlVPnaDAMx10EZDcX +hRIKKwYBBAGXVQEFAQEHQLgFZFFGd+IWWAehV4i7b23SLLsxlaWsacPSkFswfl59 +AwEIBwAA/1Wj3K1G1S95h+0jhugeYnj1LZLWO4PiaiiSBCN3IxNoD8rCwAAEGBYK +AHIFgmQ3F4UJELcvxH4BG8dkRxQAAAAAAB4AIHNhbHRAbm90YXRpb25zLnNlcXVv +aWEtcGdwLm9yZxtd7Kn2Jmj5NYfdhBVEL2qLvRZAvnfp5oveXeradLAhApsMFiEE +ZOeYHUIgxtJmOOp8ty/EfgEbx2QAAMDtAQC5fuVHyLfl1SqncTZaZkdaoSEqHdZA +4RICLYzXmmut2gD/U5k61iRwqBWiepJ1IBNQKJvq4j0CWr0LaUk4FtGi6go= +=qYY6 +-----END PGP PRIVATE KEY BLOCK----- +"; + + // $ echo hi, pep | sq encrypt --recipient-file alice.pgp --signer-file alice.pgp > msg.pgp + // $ sq decrypt --recipient-file alice.pgp --dump-session-key msg.pgp + // Session key: 09B40F05C8F12C7FF6F409698E2358C221654CDC7E300872686FEF1E16EF2385 + // Encrypted using AES-256 + // Compressed using ZIP + // No key to check checksum from 154AE7A7B77F2FB0FEB8F5A6D96F49BEF7FEB210 + // hi, pep + // 1 unknown checksum. + // $ sq packet dump --session-key 09B40F05C8F12C7FF6F409698E2358C221654CDC7E300872686FEF1E16EF2385 msg.pgp + // Public-Key Encrypted Session Key Packet, new CTB, 94 bytes + // Version: 3 + // Recipient: 003F542BE1540CD4 + // Pk algo: ECDH + // + // Sym. Encrypted and Integrity Protected Data Packet, new CTB, 300 bytes + // │ Version: 1 + // │ Session key: 09B40F05C8F12C7FF6F409698E2358C221654CDC7E300872686FEF1E16EF2385 + // │ Symmetric algo: AES-256 + // │ Decryption successful + // │ + // ├── Compressed Data Packet, new CTB, 256 bytes + // │ │ Algorithm: ZIP + // │ │ + // │ ├── One-Pass Signature Packet, new CTB, 13 bytes + // │ │ Version: 3 + // │ │ Type: Binary + // │ │ Pk algo: EdDSA + // │ │ Hash algo: SHA512 + // │ │ Issuer: D96F49BEF7FEB210 + // │ │ Last: true + // │ │ + // │ ├── Literal Data Packet, new CTB, 14 bytes + // │ │ Format: Binary data + // │ │ Content: "hi, pep\n" + // │ │ + // │ └── Signature Packet, new CTB, 212 bytes + // │ Version: 4 + // │ Type: Binary + // │ Pk algo: EdDSA + // │ Hash algo: SHA512 + // │ Hashed area: + // │ Signature creation time: 2023-04-12 20:42:56 UTC (critical) + // │ Issuer: D96F49BEF7FEB210 + // │ Notation: salt@notations.sequoia-pgp.org + // │ 00000000 a3 9e a8 6a 74 da a0 e6 8a 92 9d 06 8a 08 ad c6 + // │ 00000010 68 35 48 0a a8 f4 79 cf 2f 4e 58 94 95 93 42 31 + // │ Issuer Fingerprint: 154AE7A7B77F2FB0FEB8F5A6D96F49BEF7FEB210 + // │ Intended Recipient: 64E7981D4220C6D26638EA7CB72FC47E011BC764 + // │ Digest prefix: 843B + // │ Level: 0 (signature over data) + // │ + // └── Modification Detection Code Packet, new CTB, 20 bytes + // Digest: 430056320490BE00DD9695E9DA5964207E54844B + // Computed digest: 430056320490BE00DD9695E9DA5964207E54844B + const CTEXT: &'static str = "\ +-----BEGIN PGP MESSAGE----- + +wV4DAD9UK+FUDNQSAQdAjozAEPDG+bvHV3YjHuBcJMhPfltHaK83R6kSyvIYSHUw +4k+spf7kJJ73EMrhgzlf92Ems0RZXTeCDOKKDFAP1yfXP1ZIX3WVHraMsOg3zQSc +0sBsAVbTDJEvN8Y94sDQtZkj7gObqTyyQZAe+oj2ZXxY+b+uGJ+9sAP26mdubfZ+ +HyduxJC2nlImUwC/TMInblDyJNUiOJz5i9Wa73I8A0EkGFsdWbXQ5RkK82oQx8Bi +UYr+5DzpYhuKgqgEA46KdQv9L92sUzv/tyRaLH3i6sSmzioWDuSGPxBf6sGrywWc +tCgdoM9Lnwuhbv60Qobm1MfLMCwwkbXsy0rH6Pel5kWPnBrNWEi3hNhzMGeDKD9S +izKTrCcA1NbpFL7nndShmIlRFZ5q+XNdyWB0STFaPV5uzfCnxXpNrz7m4EXOFSZP +k4tPxebef5BpUqRxdEhHQab24bTKrI1cWa9pJdpWQrssEPE7y7pNB83p/I+fKqYv +7ykni6KBcL+Bcyf6d3xx +=PALz +-----END PGP MESSAGE----- +"; + + const MSG: &'static str = "hi, pep\n"; + + #[test] + fn decrypt() -> Result<()> { + // This uses an in-memory keystore. + let session = Session::new(); + + let rc = pgp_import_keydata( + session, + ALICE_PGP.as_ptr() as *const c_char, ALICE_PGP.len(), + std::ptr::null_mut(), + std::ptr::null_mut(), + std::ptr::null_mut()); + assert_eq!(rc, Error::KeyImported.into()); + + let mut plaintext: *mut c_char = std::ptr::null_mut(); + let mut plaintext_len: size_t = 0; + + let mut keylist: *mut StringListItem = std::ptr::null_mut(); + + let rc = pgp_decrypt_and_verify( + session, + CTEXT.as_ptr() as *const c_char, CTEXT.len(), + std::ptr::null(), 0, // dsigtext, dsigsize + &mut plaintext, &mut plaintext_len as *mut _, + &mut keylist as *mut *mut _, + std::ptr::null_mut(), // filename_ptr + ); + + // If this returns Error::MalformedMessage, it probably means + // that decompression is not enabled. + assert_eq!(rc, Error::DecryptedAndVerified.into()); + + let ptext = unsafe { check_slice!(plaintext, plaintext_len) }; + assert_eq!(ptext, MSG.as_bytes()); + + // Clean up. + unsafe { Box::from_raw(session) }; + + Ok(()) + } +}