Build a Voter Registration System with SSH Keys (the lazy way)
Did you know you can digitally sign and validate messages with your ssh keys?
Let’s face it, ssh keys can be a dry topic. Let’s spruce up the conversation with a fun scenario!
You are a Cyber Security Pro for the United States of Utopia. You are tasked with ensuring the integrity of their up comming National Election.
After scratching your chin for a full minute on how you might emabark on this quest you remember a security talk that happened on the Lazy Dev School blog titled “How to Generate an ed25519 SSH Key Pair”.
Sitting next to you, a collegue is slurping up a nitro cold brew through that sippy cup lid.
You blert out loud “Could voter fraud be prevented with ssh keys?”
Your collegue turns their head towards you and give you a look that says “Please don’t wear your tin foil hat to work”.
Unwaivering in your idea, you head back to your cave, throw on some lazy pants and start flying away on your keyboard.
Prerequisites
- Terminal or Terminal Emulator with an open ssh client
If for some reason you landed here without knowing what an SSH key is, check out the Official Lazy Dev School article on “How to Generate an ed25519 SSH Key Pair”.
Overview
In order to create a voter registration system we need to talk about architecture
- Central Voting Authority (CVA)
- Registration Offices across the land
- A mechanism to certify the registration offices so only authorized facilities can register voters
- Voter Registration VerificationProcess
- Election Day Process
Establish a Central Voting Authority
The voting authority is the most trusted entity in the system. Their job is to certify voter registration offices. If we don’t do this step, some yahoo could open a fake voter registration office without your approval.
For our purposes we will call the Central Voting Authortity the CVA.
In this step we will generate the cva key pair. The private key is the agenciey’s secret stamp. The public key is the agency’s official seal that everyone can recognize.
The CVA private key is the most important thing in this whole system. If this key is compromised, the whole system is breaks.
# Generate a new Voting Authority key
ssh-keygen -f cva_key -C "Central Voting Authority" -N ""
-f cva_key
: specifies the filename for the key. In this case, it will create files namedcva_key
(private key) andcva_key.pub
(public key).-C "Central Voting Authority"
: This flag adds a comment to the key. The comment “Central Voting Authority” is being attached to this key for identification purposes.-N ""
: This flag sets an empty passphrase for the key. The double quotes indicate no passphrase will be used.ey
Create a Voter Registration Offices
Now we can create official voter registration offices authorized by the CVA. These offices will be responsible for registering voters and issuing digital signatures that can be used to verify their vote.
# Create a key for a local registration office
ssh-keygen -f reg_office_01 -C "Registration Office 1" -N ""
ssh-keygen -f reg_office_02 -C "Registration Office 2" -N ""
-f reg_office_01
: specifies the filename for the key. In this case, it will create files namedreg_office_01
(private key) andreg_office_01.pub
(public key).-C "Registration Office 1"
: This flag adds a comment to the key. The comment “Central Voting Authority” is being attached to this key for identification purposes.-N ""
: This flag sets an empty passphrase for the key. The double quotes indicate no passphrase will be used.ey
# The CVA certifies the registration office's public key
ssh-keygen -s cva_key -I reg_office_01@digitopia -n voter_registration -V +52w reg_office_01.pub
ssh-keygen -s cva_key -I reg_office_02@digitopia -n voter_registration -V +52w reg_office_02.pub
When a voter registers, the registration is signed by the office’s private key along with it’s certificate. The certificate is only used durring the signing or verification process. We will see those steps at the end of this tutorial.
-s cva_key
: This flag specifies the private key to be used for signing. It’s using thecva_key
we generated in the previous command.-I reg_office_01@digitopia
: The-I
false is for identification and helps track which certificate belongs to which office.-n voter_registration
: Specifies the principals authorized for this certificate. In this case it ensures it can only be used for voter registration purposes. You will not be able to see this text anywhere, it becomes part of the certificate.-V +52w
: This sets the validity period for the certificate. In this case, it’s valid for 52 weeks (approximately one year) from the current date.reg_office_01.pub
: This is the public key file being certified.
The -V +52w
flag is used to specify the validity period for the key. This implies there is some kind of key rotation process in place. It’s alwas a good move to have a defined key rotation process for high stakes systems.
Publish the official Polling Locations (Authorized Signers File)
The allowed signers file lists all the official voter registration offices. If you skip this step voters would not know which voter registration locaions are legitament.
- The central authroity maintains the official list of authorized signers (Voter Registration Offices)
- File is securely distributed to the offices prior to election day
- Enables citizen to execute a vote from anywhere as long as they validate their registration
The allowed signers file is similar to the authorizied_keys
file on a server.
The authorizied_keys
file lists out all the public keys authorized to login to a given server.
In the context of this example, the Authorized Signers file lists out all the voter registration offices authorized to register voters.
AND
This file establishes the CVA as the “root of trust”
# add CVA as root of trust
echo "cva@digitopia cert-authority $(cat cva_key.pub)" > allowed_signers
# add registration offices as an authorized signer
echo "reg_office_01@digitopia $(cat reg_office_01.pub)" >> allowed_signers
echo "reg_office_02@digitopia $(cat reg_office_02.pub)" >> allowed_signers
echo
is a command that outputs the string to the terminal$(cat cva_key.pub)
is a command that outputs the contents ofcva_key.pub
to the terminal- the text of the echo and the output from the $(cat cva_key.pub) are concatenated together and written to a file called
allowed_signers
Voter Registration
Congratulations! You have successfully created the infrastructure required to register voters.
Each voter will go through a vetting process. This could be as simple as verify their criminal record, valid id, prior year taxes, etc.
If they pass the vetting process their registration will be completed. The way we can prove their registration is complete is by signing their registration data with the office’s private key and associated namespace.
The action of signing results in an artifact called a signature file.
The signature file will not be given to the voter. Instead, the signature file will be stored on CVA servers and a confirmation will be given to the voter in the form of a hashed version of the signature file.
# Create Alice's voter registration form
echo "Name: Alice Citizen
ID: AC12345
Address: 123 Democracy St
DOB: 1990-01-01" > alice_registration.txt
# Create Shawn's voter registration form
echo "Name: Shawn Citizen
ID: AC45456
Address: 123 Lazy Dev St
DOB: 1998-05-01" > shawn_registration.txt
echo
is a command that outputs the string to the terminal>
is the redirection operator. It takes the output of theecho
command and redirects it to a file path
# The registration offices sign the voter registration forms for Alice and Shawn
cat alice_registration.txt | ssh-keygen -Y sign -n voter_registration -f reg_office_02 > alice_registration.sig
cat shawn_registration.txt | ssh-keygen -Y sign -n voter_registration -f reg_office_01 > shawn_registration.sig
cat
: passes the contents of*.txt
to terminal|
is the pipe operator. It takes the output of thecat
command and passes it to thessh-keygen
command-Y sign
tellsssh-keygen
to sign the data passed to it from the pipe command-n voter_registration
tellsssh-keygen
to sign the data using thevoter_registration
namespace. When it comes time to validate the signature the same namespace baked into certificate needs to match the namespace used durring signing.-f reg_office_0*
tellsssh-keygen
to sign the data with the private key inreg_office_01
orreg_office_02
The signature generated is sensative and is going nowhere but to the CVA servers. But how can Alice prove she has completed registration? The registration offce can give Alice a hash of the signature file.
# reset the voter database
echo "" > voter_database.txt
# Provide Alice with a confirmation (not the actual signature)
hashed_signature=$(shasum -a 256 alice_registration.sig | cut -d' ' -f1)
principal="reg_office_02@digitopia"
echo "Voter Registration Confirmation
Name: Alice Citizen
ID: AC12345
Registration Office: Office 02
Registration ID: $hashed_signature" > alice_confirmation.txt
echo "Registration ID: $hashed_signature, Principal: $principal, Timestamp: $(date)" >> voter_database.txt
echo "Alice has been provided with their voter registration confirmation."
#####
# Provide Shawn with a confirmation (not the actual signature)
hashed_signature=$(shasum -a 256 shawn_registration.sig | cut -d' ' -f1)
principal="reg_office_01@digitopia"
echo "Voter Registration Confirmation
Name: Sean Citizen
ID: AC45456
Registration Office: Office 01
Registration ID: $hashed_signature" > shawn_confirmation.txt
echo "Registration ID: $hashed_signature, Principal: $principal, Timestamp: $(date)" >> voter_database.txt
echo "Shawn has been provided with their voter registration confirmation."
shasum -a 256
command that gernerates a hash using the sha256 algorithmcut -d' ' -f1
command that extracts the first field from the output of thesha256sum
command; fields are delimited by spaces-d' '
Lets dig a little deeper into the hash.
The confirmation for registration is provided to Alice in the form of a hash of the signature file. This is the only secure way to prove she completed the process.
It is secure because there is no way to recover the signature file from the hash. This is a one way cryptographic function.
What purpose is the hash serving?
Proof of Registration: The hash is a unique ID for Alice’s registration that can easily be found in the CVA database.
# Function to check if a registration exists
check_registration() {
reg_id=$1
if grep -q "$reg_id" voter_database.txt; then
echo "Registration found for ID: $reg_id"
return 0
else
echo "No registration found for ID: $reg_id"
return 1
fi
}
# Usage
registration_id=$(grep "Registration ID:" alice_confirmation.txt | cut -d' ' -f3)
check_registration "$registration_id"
registration_id=$(grep "Registration ID:" shawn_confirmation.txt | cut -d' ' -f3)
check_registration "$registration_id"
grep -q
: Quietly searches for the pattern. In this case the hashed signature (Alice’s confirmation) registration confirmationcut -d' ' -f3
: Extracts the registration ID from Alice’s confirmation- The function returns 0 if found, 1 if not found
Verification: Officials can quickly verify a citizens voter registration status.
#!/bin/bash
verify_registration() {
reg_file=$1
sig_file=$2
allowed_signers_file="allowed_signers"
voter_database="voter_database.txt"
echo "Verifying registration file: $reg_file"
echo "Using signature file: $sig_file"
echo "Using allowed_signers file: $allowed_signers_file"
# Calculate the hash of the signature file
sig_hash=$(shasum -a 256 "$sig_file" | cut -d' ' -f1)
# Look up the principal in the voter database
db_entry=$(grep "$sig_hash" "$voter_database")
if [ -z "$db_entry" ]; then
echo "No matching registration found in the database"
return 1
fi
# Extract the principal from the database entry
principal=$(echo "$db_entry" | awk -F', ' '{print $2}' | awk -F': ' '{print $2}')
# Verify the signature using ssh-keygen
cat "$reg_file" | ssh-keygen -Y verify -n voter_registration -f "$allowed_signers_file" -I "$principal" -s "$sig_file"
if [ $? -eq 0 ]; then
echo "Registration verification succeeded"
return 0
else
echo "Registration verification failed"
return 1
fi
}
reg_file="alice_registration.txt"
sig_file="alice_registration.sig"
verify_registration "$reg_file" "$sig_file"
reg_file="shawn_registration.txt"
sig_file="shawn_registration.sig"
verify_registration "$reg_file" "$sig_file"
- Checks if registration and signature files exist
- Uses ssh-keygen -Y verify to verify the signature
- Returns the result of the verification (0 for success, non-zero for failure)
Conclusion
In this tutorial, we’ve explored how SSH key signing can be applied to create a secure, efficient (lazy), and transparent voter registration system. By leveraging the power of public-key cryptography, we’ve demonstrated how to:
- Brag to our friends about our new bash scripting skills
- Establish a trusted Central Voting Authority
- Create and certify legitimate voter registration offices
- Securely register voters and protect their information
- Verify voter registrations completed
- Detect and prevent schenanigans with voter registration
Attribution
- This post was inspired by the Is it possible to sign a file using an ssh key? TL;DR