Bringin math to social problems
Practical Primitives
encryption and hashing
At the bottom (or as deep as I am willing to go right now) we have encryption and hashing. Both of these patterns use cryptography to provide some guarantees which are simple to understand, even if how they are being guaranteed is a little on the mind-bending side. These guarantees might seem just neat at first, but when combined together, create tools which are used everywhere today and have endless potential.
Encryption is a mapping of any piece of data and a key to another piece of data: data + key => other_data
. But encryption provides some interesting guarantees (backed by the mind-bending maths) about this relationship.
+-------------+ +---------------+
| | | |
| data1+key---+---+-->other_data1 |
| | | |
| | | |
| data2+key--+---+-->other_data2 |
| | | |
| | | |
| data3+key---+---+-->other_data3 |
| | | |
| | | |
| data4+key--+---+-->other_data4 |
| | | |
+-------------+ +---------------+
encryption is a one-to-one relationship
- It is impossible to calculate the original
data
fromother_data
without thekey
- It is impractical to even try guessing (would take mind-bending amounts of time)
- Changing the input data or key just a little results in a completely different output
So encryption is a practical way to scramble data.
Hashing is a mapping of any piece of data to a much smaller (fixed sized, really tiny) piece of data: data => small_data
. Hashing has similar guarantees to encryption, with a twist of its own.
+----------+ +----------------+
| | | |
| data1---+--+--+-->small_data1 |
| | | | |
| | | | |
| data2---+--+ | |
| | | |
| | | |
| data3--+-----+-->small_data2 |
| | | |
| | | |
| data4----+-----+--->small_data3 |
| | | |
+----------+ +----------------+
hashing is a many-to-one relationship
- Like encryption, it’s impossible to calculate
data
fromsmall_data
- Also impractical to even try guessing
- Changing the input data just a little also results in a completely different output
What is the twist? That many-to-one relation implies that different input data maps to same output. A collision! But, and we have to trust the mind-bending maths again here, the chances of a collision are just so, so, so, SO small…we just don’t worry about it.
So hashing is a practical way to identify data.
symmetric and asymmetric
Encryption comes in two forms: symmetric and asymmetric. These have to do with the type of key used in the mapping.
Symmetric is when the same key
is used to encrypt and decrypt the data. This is straightforward to understand, but limits the use cases. One of the obvious use cases of encryption is to transfer date without others being able to read it. The data is safe to transfer since its scrambled, but how do you transfer the key?
Enter asymmetric encryption. Asymmetric encryption uses more of that mind-bending maths to create two keys which have a nifty relationship: encryption with one can only be decrypted with the other. The “how do you transfer the key?” question can now be answered:
- the data recipient (let’s call her Alice) sends her first key (let’s call it her public key) to the data sender (let’s call him Bob)
- Bob encrypts the data with Alice’s public key and sends her the encrypted data
- Alice decrypts the data using the second key in her key pair (let’s call that her private key)
signatures
Digital signatures compose hashing and encryption. What is the use case? Data shooting across the internet goes through a lot of intermediate servers and routers which are not controlled by the data sender or data receiver. It is possible that the intermediate servers could tamper with some data or pretend to be a sender. A data receiver wants to verify who sent data and what data did they send? The data needs a signature.
The signature pattern begins with a small chunk of data sent along side the original data. A message authentication code (MAC). How does this chunk of data allow a receiver to verify who and what?
- The data sender uses hashing to create a small identifier for the data being sent
- The data sender encrypts the small identifier (this is a Hashed MAC or HMAC)
- The data sender sends the HMAC along with the data to the data receiver
- The data receiver decrypts the HMAC and hashes the data
- If the two values match they know who sent the data and that it hasn’t been tampered with
If the sender and receiver are the same person (e.g. maybe sending a data to a different storage) symmetric encryption can be used since the key never needs to be sent. Asymmetric encryption is used if the sender and receiver are different people.
+------+
| Data |
+--+---+
|
| Hash
|
v
+----+ +---------+
| ID +--------->|Signature|
+----+ +---------+
Encrypt
generate HMAC signature
+------+ +---------+
| Data | |Signature|
+--+---+ +----+----+
| |
| Hash | Decrypt
| |
v v
+----+ +----+
| ID | == | ID |
+----+ +----+
validate data with signature
Tools of the Trade
X.590
- Everything you should know about certificates and PKI but are too afraid to ask
crt
is public,key
is private- chain of trust
certificate authority
- using smallstep tooling
- The root cert (public) is shared, but the key should be very secret. Maybe even tossed after making an intermediate pair.
- Bumped the max TLS cert lifetime from 24h to a year (8760h) with
maxTLSCertDuration
setting step-ca
is the CA daemon
create root and intermediate CA certificates and keys
- CA config (password and intermediate are store under
/home/authority/.step
) - Root cert is under
/etc/step-ca/roo_ca.crt
step-cli ca init --name="Gemini" \
--dns="ca.yonson.dev" --address=":443" \
--provisioner="nick@yonson.dev"
- getting started
- smallstep docs for homelab…a little complex these days
sudo step-cli ca bootstrap --ca-url gemini2.lan:8444 --fingerprint ff13c382c168821f7e13fb362678974c04d5547dc3f106aad4c99615b8b4f877
copies cert and settings for step-cli
sudo trust anchor --store /root/.step/certs/root_ca.crt
Setup /etc/ca-certificates/extracted/cadir/Gemini_Root_CA.pem
create service certificate and private key (nginx example)
# step-cli ca certificate "*.yonson.dev" /etc/nginx/server.crt /etc/nginx/server.key
- the CA url needs to be gemini.lan since that is connected to the root/intermediate somehow…
*
allows all subdomains to use same server cert
# step-cli ca renew --ca-url=gemini2.lan:8444 --root=/home/authority/.step/certs/root_ca.crt /etc/nginx/server.crt /etc/nginx/server.key
step ca renew command renews the given certificate (with a request to the certificate authority) and writes the new certificate to disk
server {
listen 444 ssl;
server_name labs.yonson.dev;
ssl_certificate server.crt;
ssl_certificate_key server.key;
location /public.key { alias /srv/public.key; }
location /private.key { alias /srv/private.key; }
}
nginx configs for simple https server to serve over LAN
mTLS clients
- cert and key together make
pkcs12
format (p12)- p12 is the standard way to load client certs into apps like Firefox
- smallstep added some support for p12
nss
is the standard tool suite in linux to try and make OS handle certs- client cert chain
- PEM is multple certs format
- In order to provide multiple certificates for the client chain, the “PEM” format is required as the “DER” format can only provide a single certificate (or key).
step crypto key format
to switch formats, but PEM format is default for step- maybe the
--bundle
flag/command can be used when full chain is needed
-
Get root cert if you don’t already using step-cli
-
generate cert/key on where CA is reachable
$ step-cli ca certificate --ca-url="gemini2.lan:8444" --root="/etc/ca-certificates/extracted/cadir/Gemini_Root_CA.pem" --not-after="8760h" "mercury4" client.crt client.key
should be good for a year
- package in p12
$ step-cli certificate p12 mercury4.p12 client.crt client.key
- load into nss for OS
certutil -d sql:$HOME/.pki/nssdb -L
list certs
$ pk12util -d sql:$HOME/.pki/nssdb -i mercury4.p12
using standard db nssdb
- Chromium and Evolution use the “shared” database at -d “sql:$HOME/.pki/nssdb”. For Firefox, Thunderbird, and SeaMonkey, specify the browser’s own profile directory (e.g. -d ~/.mozilla/firefox/ov6jazas.default).
- Loaded the p12 through firefox UI, nss works for chromium though
- chromium docs
git
- client
http.sslCert
- looks like it prefers
pem
format - doc
- need a user account over https? a
system
user account…- having to store user credentials client side seems worse than forwarding port 22
- looks like it prefers
- server
- ssh setup is really easy, just need to the server exposed and use keys
- how to pass request from nginx to system to push/pull?
- can use CGI built in to nginx or forward requests to git http-backend…appears most use CGI
- Common Gateway Interface (CGI) is an interface specification that enables web servers to execute an external program, typically to process user requests
- cgit
- web interface, but maybe allows https configuration?
- arch docs
iOS
- certs at
Settings > General > VPN & Device Management
- add the root cert, then have to “activate” in General settings
- tried chaining in both directions and adding to p12 package, no luck
Android
- add trusted credential to OS
- “VPN & app user certificate” for client
Not sure why no prompt when visiting labs.yonson.dev/ums
$ openssl s_client -crlf -connect labs.yonson.dev:443
...
Acceptable client certificate CA names
O = Gemini, CN = Gemini Root CA
$ step-cli certificate inspect client.crt
...
Issuer: O=Gemini,CN=Gemini Intermediate CA
Looks like the intermediate is maybe the issue?
cat sub.crt rootca.crt > chain.crt
openssl pkcs12 -export -in client01.crt -inkey client01.key -certfile chain.crt -out client01-combined.p12
- that worked! So I think solutions are:
- combine root and intermediate crts when packaging client cert (smallstep tooling doesn’t do this cause it shouldn’t have to?)
- recreate the intermediate crt to match root name?
- have nginx point to the intermediate instead of the root (seems bad)
PGP
gpg --armor --export you@example.com > mykey.asc
export public key
gpg --export-secret-key -a nickj21@gmail.com | qrencode -o key.png
qr code