Skip to content

Commit

Permalink
Merge branch 'develop' into redwood-check-secret
Browse files Browse the repository at this point in the history
  • Loading branch information
zenmonkeykstop committed Oct 27, 2023
2 parents 1093631 + c802f74 commit 598c774
Show file tree
Hide file tree
Showing 9 changed files with 46 additions and 42 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ See the [introduction for contributors](https://developers.securedrop.org/en/lat
If you're just starting, we have labeled some issues as a [*good first issue*](https://github.com/freedomofpress/securedrop/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22). If no one else has
indicated they're working on it, please leave a comment saying you're interested, and feel free to get started right away!

Check out our [Development Roadmap](https://github.com/freedomofpress/securedrop/wiki-Roadmap) to see our plans and priorities for upcoming releases.
Check out our [Development Roadmap](https://github.com/freedomofpress/securedrop/wiki/Development-Roadmap) to see our plans and priorities for upcoming releases.

For translators, see the [Translator Guide](https://developers.securedrop.org/en/latest/translations.html) to learn how to get started with SecureDrop translations
in our [translation portal](https://weblate.securedrop.org/).
Expand Down
3 changes: 0 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ GCLOUD_VERSION := 222.0.0-1
SDROOT := $(shell git rev-parse --show-toplevel)
TAG ?= $(shell git rev-parse HEAD)
STABLE_VER := $(shell cat molecule/shared/stable.ver)
VERSION=$(shell python -c "import securedrop.version; print(securedrop.version.__version__)")

SDBIN := $(SDROOT)/securedrop/bin
DEVSHELL := $(SDBIN)/dev-shell
Expand Down Expand Up @@ -364,7 +363,6 @@ $(POT): securedrop
--charset=utf-8 \
--output=${POT} \
--project="SecureDrop" \
--version=${VERSION} \
--msgid-bugs-address=securedrop@freedom.press \
--copyright-holder="Freedom of the Press Foundation" \
--add-comments="Translators:" \
Expand Down Expand Up @@ -393,7 +391,6 @@ $(DESKTOP_POT): ${DESKTOP_BASE}/*.in
-F securedrop/babel.cfg \
--output=${DESKTOP_POT} \
--project=SecureDrop \
--version=${VERSION} \
--msgid-bugs-address=securedrop@freedom.press \
--copyright-holder="Freedom of the Press Foundation" \
--add-location=never \
Expand Down
2 changes: 2 additions & 0 deletions builder/build-debs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

set -euxo pipefail

git --no-pager log -1 --oneline --show-signature --no-color

OCI_RUN_ARGUMENTS="--user=root -v $(pwd):/src:Z"

# Default to podman if available
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: SecureDrop 2.7.0~rc1\n"
"Project-Id-Version: SecureDrop VERSION\n"
"Report-Msgid-Bugs-To: securedrop@freedom.press\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
Expand Down
4 changes: 3 additions & 1 deletion redwood/redwood/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ from typing import BinaryIO
def generate_source_key_pair(passphrase: str, email: str) -> tuple[str, str, str]: ...
def is_valid_public_key(input: str) -> str: ...
def is_valid_secret_key(input: str, passphrase: str) -> str: ...
def encrypt_message(recipients: list[str], plaintext: str, destination: Path) -> None: ...
def encrypt_message(
recipients: list[str], plaintext: str, destination: Path, *, armor: bool = False
) -> None: ...
def encrypt_stream(recipients: list[str], plaintext: BinaryIO, destination: Path) -> None: ...
def decrypt(ciphertext: bytes, secret_key: str, passphrase: str) -> bytes: ...

Expand Down
45 changes: 21 additions & 24 deletions redwood/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,10 @@ pub fn encrypt_message(
recipients: Vec<String>,
plaintext: String,
destination: PathBuf,
armor: Option<bool>,
) -> Result<()> {
let plaintext = plaintext.as_bytes();
encrypt(&recipients, plaintext, &destination)
encrypt(&recipients, plaintext, &destination, armor)
}

/// Encrypt a Python stream (`typing.BinaryIO`) for the specified recipients.
Expand All @@ -144,7 +145,7 @@ pub fn encrypt_stream(
destination: PathBuf,
) -> Result<()> {
let stream = stream::Stream { reader: plaintext };
encrypt(&recipients, stream, &destination)
encrypt(&recipients, stream, &destination, None)
}

/// Helper function to encrypt readable things.
Expand All @@ -154,6 +155,7 @@ fn encrypt(
recipients: &[String],
mut plaintext: impl Read,
destination: &Path,
armor: Option<bool>,
) -> Result<()> {
let mut certs = vec![];
let mut recipient_keys = vec![];
Expand All @@ -175,7 +177,11 @@ fn encrypt(
.open(destination)?;
let mut writer = BufWriter::new(sink);
let message = Message::new(&mut writer);
let message = Armorer::new(message).build()?;
let message = if armor.unwrap_or(false) {
Armorer::new(message).build()?
} else {
message
};
let message = Encryptor::for_recipients(message, recipient_keys).build()?;
let mut message = LiteralWriter::new(message).build()?;

Expand Down Expand Up @@ -313,6 +319,7 @@ mod tests {
vec![good_key, BAD_KEY.to_string()],
SECRET_MESSAGE.to_string(),
tmp_dir.path().join("message.asc"),
None,
)
.unwrap_err();
assert_eq!(err.to_string(), expected_err_msg);
Expand Down Expand Up @@ -360,42 +367,31 @@ mod tests {
vec![public_key1, public_key2],
SECRET_MESSAGE.to_string(),
tmp.clone(),
None,
)
.unwrap();
let ciphertext = std::fs::read_to_string(tmp).unwrap();
// Verify ciphertext looks like an encrypted message
assert!(ciphertext.starts_with("-----BEGIN PGP MESSAGE-----\n"));
let ciphertext = std::fs::read(tmp).unwrap();
// Decrypt as key 1
let plaintext = decrypt(
ciphertext.clone().into_bytes(),
secret_key1,
PASSPHRASE.to_string(),
)
.unwrap();
let plaintext =
decrypt(ciphertext.clone(), secret_key1, PASSPHRASE.to_string())
.unwrap();
// Verify message is what we put in originally
assert_eq!(
SECRET_MESSAGE,
String::from_utf8(plaintext.to_vec()).unwrap()
);
// Decrypt as key 2
let plaintext = decrypt(
ciphertext.clone().into_bytes(),
secret_key2,
PASSPHRASE.to_string(),
)
.unwrap();
let plaintext =
decrypt(ciphertext.clone(), secret_key2, PASSPHRASE.to_string())
.unwrap();
// Verify message is what we put in originally
assert_eq!(
SECRET_MESSAGE,
String::from_utf8(plaintext.to_vec()).unwrap()
);
// Try to decrypt as key 3, expect an error
let err = decrypt(
ciphertext.into_bytes(),
secret_key3,
PASSPHRASE.to_string(),
)
.unwrap_err();
let err = decrypt(ciphertext, secret_key3, PASSPHRASE.to_string())
.unwrap_err();
assert_eq!(
err.to_string(),
"OpenPGP error: no matching pkesk, wrong secret key provided?"
Expand Down Expand Up @@ -426,6 +422,7 @@ mod tests {
key, // missing or malformed recipient key
"Look ma, no key".to_string(),
tmp_dir.path().join("message.asc"),
None,
)
.unwrap_err();
assert_eq!(err.to_string(), error);
Expand Down
16 changes: 8 additions & 8 deletions securedrop/tests/test_encryption.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,9 @@ def test_encrypt_source_message(self, config, tmp_path):
message_in=message, encrypted_message_path_out=encrypted_message_path
)

# And the output file contains the encrypted data
# And the output file doesn't contain the message plaintext
encrypted_message = encrypted_message_path.read_bytes()
assert encrypted_message.startswith(b"-----BEGIN PGP MESSAGE-----")
assert message.encode() not in encrypted_message

# And the journalist is able to decrypt the message
decrypted_message = utils.decrypt_as_journalist(encrypted_message).decode()
Expand All @@ -139,9 +139,9 @@ def test_encrypt_source_file(self, config, tmp_path):
encrypted_file_path_out=encrypted_file_path,
)

# And the output file contains the encrypted data
# And the output file doesn't contain the file plaintext
encrypted_file = encrypted_file_path.read_bytes()
assert encrypted_file.startswith(b"-----BEGIN PGP MESSAGE-----")
assert file_to_encrypt_path.read_bytes() not in encrypted_file

# And the journalist is able to decrypt the file
decrypted_file = utils.decrypt_as_journalist(encrypted_file)
Expand Down Expand Up @@ -174,9 +174,9 @@ def test_encrypt_and_decrypt_journalist_reply(
encrypted_reply_path_out=encrypted_reply_path,
)

# And the output file contains the encrypted data
# And the output file doesn't contain the reply plaintext
encrypted_reply = encrypted_reply_path.read_bytes()
assert encrypted_reply.startswith(b"-----BEGIN PGP MESSAGE-----")
assert journalist_reply.encode() not in encrypted_reply

# And source1 is able to decrypt the reply
decrypted_reply = encryption_mgr.decrypt_journalist_reply(
Expand Down Expand Up @@ -225,9 +225,9 @@ def test_gpg_encrypt_and_decrypt_journalist_reply(
encrypted_reply_path_out=encrypted_reply_path,
)

# And the output file contains the encrypted data
# And the output file doesn't contain the reply plaintext
encrypted_reply = encrypted_reply_path.read_bytes()
assert encrypted_reply.startswith(b"-----BEGIN PGP MESSAGE-----")
assert journalist_reply.encode() not in encrypted_reply

# And source1 is able to decrypt the reply
decrypted_reply = encryption_mgr.decrypt_journalist_reply(
Expand Down
12 changes: 9 additions & 3 deletions securedrop/tests/test_journalist_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -777,10 +777,16 @@ def test_authorized_user_can_add_reply(

# First we must encrypt the reply, or it will get rejected
# by the server.
encryption_mgr = EncryptionManager.get_default()
reply_path = tmp_path / "message.gpg"
encryption_mgr.encrypt_journalist_reply(
test_source["source"], "This is a plaintext reply", reply_path
# Use redwood directly, so we can generate an armored message.
redwood.encrypt_message(
recipients=[
test_source["source"].public_key,
EncryptionManager.get_default().get_journalist_public_key(),
],
plaintext="This is an encrypted reply",
destination=reply_path,
armor=True,
)
reply_content = reply_path.read_text()

Expand Down
2 changes: 1 addition & 1 deletion securedrop/translations/messages.pot
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: SecureDrop 2.7.0~rc1\n"
"Project-Id-Version: SecureDrop VERSION\n"
"Report-Msgid-Bugs-To: securedrop@freedom.press\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
Expand Down

0 comments on commit 598c774

Please sign in to comment.