This is a toy project to demonstrate how cryptographic fingerprinting of classified documents can be used to balance accountability and security concerns. (It's also an opportunity to practice developing a Flask app.)
The issuing of secret warrants for national security-related surveillance by the Foreign Intelligence Surveillance Court (FISC) in the USA remains controversial. Under the 1978 Foreign Intelligence Surveillance Act (FISA) and later amendments - particularly the 2008 FISA Amendments Act, domestic and foreign intelligence agencies in the United States have significant statutory permission for both warrantless and classified warrant-authorized surveillance of United States citizens. The core dilemma is that the secrecy of these court orders can be justifiable (a suspect should not be tipped off to the details - or existence - of an ongoing investigation!), but it inherently poses a profound risk to Constitutional (especially Fourth Amendment) rights and allows for serious abuses of power.
The thesis of this project is that cryptographic fingerprinting of classified documents provides a way to hold secret courts accountable while protecting sensitive details of these court orders:
- When a secret court order ("warrant") is issued, its fingerprint should be published, accessible to the public.
- The contents of the warrant are sensitive and cannot be extracted from the fingerprint. Importantly, even finding a hash collision isn't useful if the content generating the same hash is gibberish i.e. not a readable court order! This protects the ability of national security agencies, law enforcement, etc. to use secret court orders insofar as they have any value to society. However:
- Publishing the fingerprint acts as "pre-registration" for evidence collection if and when the target is eventually prosecuted. If the state cannot produce the court order text that generated the hash when entering evidence, it is prima facie inadmissable.
- Fingerprints are published with timestamps, which can be compared to statutory declassification timelines. Legal consequences ought to apply if an issuing court cannot produce the text that generated a fingerprint which reaches a declassification deadline (or produce an appropriate order extending the classification).
- The algorithm generating the fingerprints should also incorporate the fingerprint of the previous issued warrant, so as to prevent tampering with history.
- Clone this repo.
- Create a Conda virtual environment from
environment.yml. - Set up a deployment config file at
./instance/config.py. This should define, at a minimum, the following Python string variables:SECRET_KEY: Used for secure signing.JWT_SECRET_KEY: Similar, for JSON web token authentication.INIT_ADMIN_PASSWORD: Password for the app's admin user, username "Admin". Only this user may create other users with the ability to post new warrants.
- For testing purposes,
flask --app habeas runis sufficient. - Alternatively, follow the official Flask user guide for other deployment options.
A Postman collection is provided for convenience, as habeas.postman_collection.json.
- Use the
/auth/get_tokenPOST endpoint to obtain a JWT authentication token. - With the Admin user's JWT in the header, use the
/auth/new_userPOST endpoint to create a new user capable of publishing a warrant. (This would represent, say, a judge or court reporter.) - With any user's JWT in the header, use the
/warrant/newPOST endpoint to publish a new warrant. This can be done by including the warrant's JSON contents as the raw payload, or uploading a text file in the request (supported file extensions are.txt,.md, and.json.) - No JWT in the header is necessary to use the
/warrant/queryGET endpoint to retrieve document fingerprints. Optional parameters are:start: String ISO-8601 formatted timestamp with the earliest document date to retrieve.next_id: Integer document ID to start the next page of results at, for pagination purposes. (Page size is controlled by the app config variableRESULTS_PER_PAGE.) When the number of records returned in a query exceeds this, the appropriatenext_idis included in the response JSON.
See conda environment.yml file for full details. Key dependencies are:
- Python 3.13
- Flask 3.1.0
- Flask-JWT-Extended 4.7.1
- Pandas 2.2.3