Skip to content
This repository has been archived by the owner on Jan 5, 2024. It is now read-only.

Support VeraCrypt export devices #126

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ check-black: ## Check Python source code formatting with black
TESTS ?= tests
.PHONY: test
test: ## Run tests
poetry run pytest -v --cov-report html --cov-report term-missing --cov=securedrop_export $$TESTS
poetry run pytest -v --cov-report html --cov-report term-missing \
--cov=securedrop_export --log-disable=securedrop_export.main $$TESTS

.PHONY: lint
lint: ## Run linter
Expand Down
37 changes: 17 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,6 @@ Metadata contains three possible keys which may contain several possible values:
`device`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to change the line above that says "We do not yet support drives that use full-disk encryption with VeraCrypt." ;-)

: specifies the method used for export, and can be either a device or a preflight check. See the Devices section below for possible values. It is a required key.

`encryption_method`
: used exclusively when exporting to USB storage. It is an optional key. Possible values are:
luks

`encryption_passphrase`
: used exclusively when exporting to USB storage. It is an optional key. It contains an arbitrary string that contains the disk encryption passphrase of the device.
Expand All @@ -76,7 +73,6 @@ Example archive metadata (`metadata.json`):
```
{
"device": "disk"
"encryption-method": "luks"
"encryption-key": "Your encryption passphrase goes here"
}
```
Expand All @@ -94,34 +90,34 @@ For all device types (described in detail below), the following standard error t

The supported device types for export are as follows, including the possible errors specific to that device type:

1. `usb-test` : Preflight check that probes for USB connected devices, that returns:
- `USB_CONNECTED` if a USB device is attached to the dedicated slot
- `USB_NOT_CONNECTED` if no USB is attached
- `USB_CHECK_ERROR` if an error occurred during pre-flight
1. `disk-test` : Preflight check that probes for USB connected devices, that returns:
- `DEVICE_WRITABLE` if a supported USB device is attached and unlocked
- `DEVICE_LOCKED` if a supported drive is inserted but locked (a LUKS drive, since locked Veracrypt detection is not supported)
- `NO_DEVICE_DETECTED`, `MULTI_DEVICE_DETECTED`: wrong number of inserted USB drives
- `INVALID_DEVICE_DETECTED`: Wrong number of partitions, unsupported encryption scheme, etc
- `UNKNOWN_DEVICE_DETECTED`: (Future use) this is what a locked drive that could be Veracrypt would return
- `DEVICE_ERROR`: A problem was encountered and device state cannot be reported.

2. `disk-test`: Preflight check that checks for LUKS-encrypted volume that returns:
- `USB_ENCRYPTED` if a LUKS volume is attached to sd-devices
- `USB_ENCRYPTION_NOT_SUPPORTED` if a LUKS volume is not attached or there was any other error
- `USB_DISK_ERROR`

3. `printer-test`: prints a test page that returns:
2. `printer-test`: prints a test page that returns:
- `ERROR_PRINTER_NOT_FOUND` if no printer is connected
- `ERROR_PRINTER_NOT_SUPPORTED` if the printer is not currently supported by the export script
- `ERROR_PRINTER_DRIVER_UNAVAILABLE` if the printer driver is not available
- `ERROR_PRINTER_INSTALL` If there is an error installing the printer
- `ERROR_PRINT` if there is an error printing

4. `printer`: sends files to printer that returns:
3. `printer`: sends files to printer that returns:
- `ERROR_PRINTER_NOT_FOUND` if no printer is connected
- `ERROR_PRINTER_NOT_SUPPORTED` if the printer is not currently supported by the export script
- `ERROR_PRINTER_DRIVER_UNAVAILABLE` if the printer driver is not available
- `ERROR_PRINTER_INSTALL` If there is an error installing the printer
- `ERROR_PRINT` if there is an error printing

5. `disk`: sends files to disk that returns:
- `USB_BAD_PASSPHRASE` if the luks decryption failed (likely due to bad passphrase)
- `ERROR_USB_MOUNT` if there was an error mounting the volume (after unlocking the luks volume)
- `ERROR_USB_WRITE` if there was an error writing to disk (e.g., no space left on device)
4. `disk`: sends files to disk that returns:
- `SUCCESS_EXPORT`: Successful
- `ERROR_CLEANUP`: Export was successful but files could not be cleaned up or drive was not properly unmounted
- `ERROR_UNLOCK_LUKS` if the luks decryption failed (likely due to bad passphrase)
- `ERROR_MOUNT` if there was an error mounting the volume (after unlocking the luks volume)
- `ERROR_WRITE` if there was an error writing to disk (e.g., no space left on device)

### Export Folder Structure

Expand All @@ -132,7 +128,8 @@ When exporting to a USB drive, the files will be placed on the drive as follows:

└── sd-export-20200116-003153
└── export_data
└── secret_memo.pdf
└── transcript.txt
└── secret_memo.pdf
```

To support multiple files, in the long term, we are planning to use a folder structure similar to the following, where the journalist designation for a source is used for folder names and message/reply file names.
Expand Down
16 changes: 1 addition & 15 deletions securedrop_export/archive.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ class Metadata(object):
"""

METADATA_FILE = "metadata.json"
SUPPORTED_ENCRYPTION_METHODS = ["luks"]
cfm marked this conversation as resolved.
Show resolved Hide resolved

def __init__(self, archive_path: str):
self.metadata_path = os.path.join(archive_path, self.METADATA_FILE)
Expand All @@ -38,13 +37,8 @@ def validate(self) -> "Metadata":
logger.info("Parsing archive metadata")
json_config = json.loads(f.read())
self.export_method = json_config.get("device", None)
self.encryption_method = json_config.get("encryption_method", None)
self.encryption_key = json_config.get("encryption_key", None)
logger.info(
"Target: {}, encryption_method {}".format(
self.export_method, self.encryption_method
)
)
logger.info("Command: {}".format(self.export_method))

except Exception as ex:
logger.error("Metadata parsing failure")
Expand All @@ -54,12 +48,6 @@ def validate(self) -> "Metadata":
try:
logger.debug("Validate export action")
self.command = Command(self.export_method)
if (
self.command is Command.EXPORT
and self.encryption_method not in self.SUPPORTED_ENCRYPTION_METHODS
):
logger.error("Unsupported encryption method")
raise ExportException(sdstatus=Status.ERROR_ARCHIVE_METADATA)
except ValueError as v:
raise ExportException(sdstatus=Status.ERROR_ARCHIVE_METADATA) from v

Expand Down Expand Up @@ -95,7 +83,5 @@ def set_metadata(self, metadata: Metadata) -> "Archive":
"""
self.command = metadata.command
if self.command is Command.EXPORT:
# When we support multiple encryption types, we will also want to add the
# encryption_method here
self.encryption_key = metadata.encryption_key
return self
4 changes: 2 additions & 2 deletions securedrop_export/disk/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
from .legacy_service import Service as LegacyService # noqa: F401
from .legacy_status import Status as LegacyStatus # noqa: F401
from .service import Service # noqa: F401
from .status import Status # noqa: F401
Loading