Skip to content

Commit

Permalink
Make signer optional for encrypt
Browse files Browse the repository at this point in the history
Signed-off-by: Wiktor Kwapisiewicz <[email protected]>
  • Loading branch information
wiktor-k committed Mar 18, 2024
1 parent d485973 commit 113369c
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 7 deletions.
6 changes: 5 additions & 1 deletion NEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@
v0.1.23

New:
- `decrypt` accepts a function for supplying certificates for signature verification ([#22])
- the result of `decrypt` and `verify` exposes `valid_sigs` for retrieving a list of valid signatures ([#22])

Changed:
- `verify` now accepts a callback for supplying signing certificates ([#20])
- `verify` accepts a callback for supplying signing certificates ([#20])
- `encrypt` does not require the `signer` argument ([#22])

Removed:
- `Store` and the Cert-D has been removed ([#20]) due to confusing semantics

[#20]: https://github.com/wiktor-k/pysequoia/pull/20
[#22]: https://github.com/wiktor-k/pysequoia/pull/22
### git tag --edit -s -F NEXT.md v...
33 changes: 31 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ signing_key = Cert.from_file("signing-key.asc")
signed = sign(s.secrets.signer(), "data to be signed".encode("utf8"))

def get_certs(key_ids):
# key_ids is an array of required signing keys
print(f"For verification, we need these keys: {key_ids}")
return [signing_key]

Expand All @@ -114,6 +115,10 @@ assert result.valid_sigs[0].certificate == "afcf5405e8f49dbcd5dc548a86375b854b86
assert result.valid_sigs[0].signing_key == "afcf5405e8f49dbcd5dc548a86375b854b86acf9"
```

The function that returns certificates (here `get_certs`) may return more certificates than necessary.

`verify` succeeds if *at least one* correct signature has been made by any of the certificates supplied. If you need more advanced policies they can be implemented by inspecting the `valid_sigs` property.

### encrypt

Signs and encrypts a string to one or more recipients:
Expand All @@ -128,9 +133,31 @@ encrypted = encrypt(signer = s.secrets.signer("hunter22"), recipients = [r], byt
print(f"Encrypted data: {encrypted}")
```

The `signer` argument is optional and when omitted the function will return an unsigned (but encrypted) message.

### decrypt

Decrypts data:
Decrypts plain data:

```python
from pysequoia import decrypt

sender = Cert.from_file("no-passwd.pgp")
receiver = Cert.from_file("passwd.pgp")

content = "Red Green Blue"

encrypted = encrypt(recipients = [receiver], bytes = content.encode("utf8"))

decrypted = decrypt(decryptor = receiver.secrets.decryptor("hunter22"), bytes = encrypted)

assert content == decrypted.bytes.decode("utf8");

# this message did not contain any valid signatures
assert len(decrypted.valid_sigs) == 0
```

Decrypt can also verify signatures while decrypting:

```python
from pysequoia import decrypt
Expand All @@ -149,12 +176,14 @@ def get_certs(key_ids):
decrypted = decrypt(decryptor = receiver.secrets.decryptor("hunter22"), bytes = encrypted, store = get_certs)

assert content == decrypted.bytes.decode("utf8");
print(decrypted.valid_sigs)

# let's check the valid signature's certificate and signing subkey fingerprints
assert decrypted.valid_sigs[0].certificate == sender.fingerprint
assert decrypted.valid_sigs[0].signing_key == sender.fingerprint
```

Here, the same remarks as to [`verify`](#verify) also apply.

## Certificates

The `Cert` class represents one OpenPGP certificate (commonly called a
Expand Down
9 changes: 5 additions & 4 deletions src/encrypt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ use crate::signer::PySigner;

#[pyfunction]
pub fn encrypt(
signer: PySigner,
recipients: Vec<PyRef<Cert>>,
bytes: &[u8],
signer: Option<PySigner>,
) -> PyResult<Cow<'static, [u8]>> {
let mode = KeyFlags::empty()
.set_storage_encryption()
Expand Down Expand Up @@ -66,7 +66,7 @@ pub fn encrypt(

let message = Armorer::new(message).build()?;

let message = Encryptor::for_recipients(
let mut message = Encryptor::for_recipients(
message,
recipient_keys
.iter()
Expand All @@ -75,8 +75,9 @@ pub fn encrypt(
.build()
.context("Failed to create encryptor")?;

let message = Signer::new(message, signer).build()?;

if let Some(signer) = signer {
message = Signer::new(message, signer).build()?;
}
let mut message = LiteralWriter::new(message)
.build()
.context("Failed to create literal writer")?;
Expand Down

0 comments on commit 113369c

Please sign in to comment.