April, 2019
"cryptography is a solved problem ... the remaining problems ... are primarily political"
- Cryptography textbooks
" cryptography is in fact the strongest link in the chain"
- Security researchers
"Secure your router in two easy steps: enable secret and service password-encryption"
- Every CCNA curriculum ever
A security system that utilizes cryptography to enable or augment functionality
Cross-disciplinary
- Cryptography
- Mathematics
- Hardware / Software Engineering
- User Interfaces / APIs
- etc.
Many distinct ways to get cryptographic systems wrong
1. Theory
2. Primitives
3. Protocols
4. Implementation
5. Usage
Are our cryptographic systems constructed on the basis of valid assumptions?
- Open question...
Compromise assumed as hard as underlying problem
- RSA and integer factorization
- Diffie-Hellman and discrete logarithm
Hard problems assumed to be hard
One-way functions assumed to be feasible
- P != NP ?
The building blocks of cryptographic systems
In general, a primitive is an algorithm
- Ciphers, MACs, Signatures, Hash Functions, etc.
How do primitives break?
- The primitive itself is flawed
- The right primitive becomes the wrong primitive
History is littered with broken primitives...
Symmetric block cipher
- Block size: 64 bits
- Key size: 64 bits*
What's the issue?
- Key size is too small
Chronology
- 1998 EFF's Deep Crack breaks in 56 hours
- 1999 EFF's Deep Crack breaks in 22 hours
- 2006 COPACOBANA cracks in 9 days, for $10,000
- 2016 hashcat + GPU cracks in 15 days
Added to GSM standard to encrypt mobile traffic between device and cell tower
Stream cipher, comes in multiple flavors
- A5/0: no encryption
- A5/1: based on LFSRs
- A5/2: weaker version of A5/1
- A5/3 (KASUMI)
What's the issue?
- Deliberately weak algorithms (laptop-crackable)
- Vulnerable to downgrade attacks
Cryptographic hash functions
- MD5 digest width = 128 bits
- SHA-1 digest width = 160 bits
What's the problem?
- Digest width is too small
Chronology
- 2005 first full MD5 collision
- 2017 CWI Amsterdam and Google SHA-1 collision
History's most (in)famous stream cipher
What's the issue?
- Keystream bias(es)
Practical applications
- Cracking WEP communications
- Cracking SSL/TLS sessions (RFC 7465, 2015)
i := 0
j := 0
while GeneratingOutput:
i := (i + 1) mod 256
j := (j + S[i]) mod 256
swap values of S[i] and S[j]
K := S[(S[i] + S[j]) mod 256]
output K
endwhile
Primitives with security guarantees based on the computational difficulty of hard problems
A few problems we are entirely reliant upon
- Integer factorization (RSA)
- Discrete logarithm in finite fields (DSA)
- Discrete logarithm on elliptic curves (ECDSA)
Quantum computation may change the game...
Open question: will this be another case where the right primitives become the wrong primitives?
Cryptographic schemes for which quantum computation does not provide an exponential speedup
The search for post-quantum algorithms: NIST
- February 2016: Initial call for submissions
- December 2017: Round 1 candidates announced (69)
- January 2019: Round 2 candidates announced (17)
A note on practicality
- Key size (MBs, GBs??)
- Bandwidth (DoS made easy)
- Encrypt / decrypt / sign / validate times
A set of rules and conventions by which we perform cryptographic operations
Cryptographic protocols are everywhere
- Mobile phones
- Wireless access points (WEP, WPA*)
- Automobiles (vehicle immobilizers)
- Internet traffic (SSL/TLS)
When we design cryptographic protocols, we introduce complexity and thereby enlarge our attack surface
Introduced* the idea of asymmetric cryptography - New Directions in Cryptography (1976)
Establishment of shared secret between two parties over an insecure channel
"Textbook" (or "anonymous") DH protocol insecure against active adversary: man in the middle attacks
The protocol
Alice
Bob
Public
g, p
Choose a in {1,...,p-1}
Compute A = g^a mod p
Choose b in {1,...,p-1}
Compute B = g^b mod p
Compute S = B^a
= (g^b)^a
= g^ab
Compute S = A^b
= (g^a)^b
= g^ab
Send A
Send B
Fixing the protocol: DH-MQV
Alice
Bob
Public
g, p
Send A
Send B
(x, Y = g^y)
(y, X = g^x)
Pick random a
Compute A = g^a
Pick random b
Compute B = g^b
Compute (B x Y^B)^(a+xA)
Compute (A x X^A)^(b+yB)
Alice computes
Bob computes
The single most important cryptographic protocol in use today
Long history of attacks on SSL/TLS
- BEAST, CRIME, DROWN, TERROR, etc...
Vulnerable to ciphersuite downgrade attacks
Client
Server
Client Hello
Server Hello
I support algorithms X, Y, and Z
Let's use algorithm Y
RSA PKCS #1 v1.5 - a padding scheme for messages encrypted with RSA
When PKCS #1 v1.5 used within the SSL/TLS protocol, it is vulnerable to padding oracle attacks
RSA PKCS #1 v1.5 Padding scheme
0x00
0x02
0x00
Random, Nonzero Bytes
Original Message
SSL/TLS Protocol
Client
Server
Client Hello
Server Hello
Client Key Exchange
...
Stuff
Stuff
PMS
Active attack on the SSL/TLS (<1.3) protocol, using SSL/TLS server as a padding oracle
Relies on homomorphism of RSA encryption
Fixing the protocol
- Do not inform client of bad padding
Fixing the padding scheme
- Weakness of PKCS #1 v1.5 = low redundancy
- More advanced padding schemes e.g. OAEP
How do we actually realize cryptographic systems in the real world?
- Hardware
- Software
Why does this matter?
- Cryptographic systems vulnerable to the same flaws as all hardware / software systems
When we perform some cryptographic operation, we are faced with two choices
1. Roll it ourselves
2. Use a library
Many arguments against "rolling your own crypto"
Vast majority of people / organizations meet cryptography needs via software libraries
- Many exist
- But OpenSSL dominates
Academic Cryptographers,
Mathematicians,
Complexity Theorists
Crypto Implementors
Application Software Developers
End Users (e.g. you, me)
RSA-Encrypted Premaster Secret Message
...
1. Generate a string R of 46 random bytes
2. Decrypt the message to recover the plaintext M
3. If the PKCS#1 padding is not correct,
or the length of message M is not exactly 48 bytes:
pre_master_secret = ClientHello.client_version || R
else If ClientHello.client_version <= TLS 1.0,
and version number check is explicitly disabled:
pre_master_secret = M
else:
pre_master_secret = ClientHello.client_version || M[2..47]
RFC 5246: TLS version 1.2
(3)
(2)
(1)
i=RSA_private_decrypt((int)n,p,p,rsa,RSA_PKCS1_PADDING);
al = -1;
...
if (al != -1)
{
/* Some decryption failure -- use random value instead as countermeasure
* against Bleichenbacher's attack on PKCS1 v1.5 RSA padding
* (see RFC 2246, section 7.4.7.1). */
ERR_clear_error();
i = SSL_MAX_MASTER_KEY_LENGTH;
p[0] = s->client_version >> 8;
p[1] = s->client_version & 0xff;
if (RAND_pseudo_bytes(p+2, i-2) <= 0)
goto err;
}
s->session->master_key_length=
s->method->ssl3_enc->generate_master_secret(s,
s->session->master_key,
p,i);
OpenSSL 1.0.1c
(3)
(2)
(1)
// set up the context
EVP_CIPHER_CTX *ctx;
if (!(ctx = EVP_CIPHER_CTX_new()))
handle_errors();
// openssl wants unsigned character buffers
unsigned char *key_buf = ...
unsigned char *ct_buf = ...
unsigned char *pt_buf = ...
// initialize the encryption operation
if (EVP_EncryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, key_buf, NULL) != 1)
handle_errors();
// provide plaintext bytes to be encrypted
int len;
if (EVP_EncryptUpdate(ctx, ct_buf, &len, pt_buf, pt_len) != 1)
handle_errors();
ct_len += len;
// finalize encryption operation
if (EVP_EncryptFinal_ex(ctx, ct_buf+len, &len) != 1)
handle_errors();
ct_len += len;
// cleanup
EVP_CIPHER_CTX_free(ctx);
AES encryption: OpenSSL
// initialize some buffers
unsigned char *key = ...
unsigned char *pt = ...
unsigned char *ct = ...
// aes encryption: so easy a caveman could do it
aes_128_encrypt(ct, pt, key);
// do stuff with your encrypted buffer
Why is this better?
- Simpler, more intuitive API
- Fewer opportunities to make mistakes
Why is it dangerous?
- Gives user too much latitude to do something bad
AES encryption: proprietary*
#include "crypto_secretbox.h"
unsigned char key = ...
unsigned char nonce = ...
unsigned long long plen;
unsigned char pt = ...
unsigned long long clen;
unsigned char ct = ...
// do everything
crypto_secretbox(ct, pt, plen, nonce, key);
// do stuff with your encrypted buffer
// AND rest assured that message is authenticated
Why is this better?
- Equally simple / intuitive API
- Hides lower level details from users
AES encryption: NaCL
Survey of security-critical applications and libraries (2012)
Broken certificate verification in
- Amazon's EC2 library and cloud clients
- Paypal merchant SDKs
- Mobile banking applications
- Web server middlewares e.g. Apache Axis, Pusher
"The root causes of these vulnerabilities are badly designed APIs of SSL implementations ..."
During operation, cryptographic system leaks information regarding some secret value
Many attack vectors
- Timing
- Audio
- Power Usage (SPA, DPA)
- Electromagnetic Radiation
The time taken to perform some cryptographic operation leaks information about internal, secret value
// typical comparison operation
for (int i = 0; i < len; i++)
if (x[i] != y[i]) return false;
return true;
// constant time comparison
int diff = 0
for (int i = 0; i < len; i++)
diff |= x[i] ^ y[i];
return diff == 0
Leaky
Less so
Can cryptographic systems break despite careful design and correct implementation?
- Yes. Catastrophically.
Where do users screw up?
- Poor key management
- Misapplication of cryptographic tools
- Misuse of cryptographic tools
/*
* super_important_program.c
*
* A program that performs SUPER IMPORTANT computations,
* with the help of some crypto.
*/
static const char *SECRET_KEY = "YELLOWSUBMARINE";
// encrypt and decrypt all the things!
How do users / organizations store, distribute, update, and revoke encryption keys?
Hardcoded values
Sharing of asymmetric key parameters
- Common RSA modulus N
Most users don't know better; leads to using the wrong tool for the job
Non-cryptographic PRNGs in "secure" applications
- rand() in C, random in Python
Non-authenticated encryption where we should require authentication
- "Vanilla" AES
Mistaking algorithms for encryption schemes
- "Textbook" RSA
Despite choosing the correct tool, many users still neglect to read the manual
Common example: nonce reuse
- The name is literally the manual here
Use of a unique nonce is fundamental to the security guarantees of many symmetric algorithms
- Block ciphers in CTR mode
Exploiting nonce reuse
- KRACK attack on WPA2
How can we design cryptographic systems that remain secure despite misuse?
Active area of research e.g. RFC 8452
Cryptography is hard; designing and implementing secure cryptographic systems is really hard
Many distinct ways in which cryptographic systems break
- Theory, Primitives, Protocols, Implementation, Usage
What can we do?
- Panic
- Recognize limitations
- ???
- Practical Cryptographic Systems by Matthew Green
- Should We Deploy TLS? by Matthew Green
- Chosen Ciphertext Attacks Against Protocols Based on the RSA Encryption Standard PKCS#1 by Daniel Bleichenbacher
- 20 Years of Attacks on the RSA Cryptosystem by Dan Boneh
- The Most Dangerous Code in the World: Validating SSL Certificates in Non-Browser Software by Georgiev et al.
- Post-Quantum Cryptography by Daniel J. Bernstein
- Serious Cryptography by Jean-Philipoe Aumasson
- Cryptography Engineering by Ferguson, Schneier, Kohno
- RFC 2313 PKCS #1: RSA Encyption, Version 1.5
- RFC 8452 AES-GCM-SIV: Nonce Misuse-Resistant Authenticated Encryption
- RFC 7457 Summarizing Known Attacks on Transport Layer Security (TLS) and Datagram TLS (DTLS)
- RFC 5246 The Transport Layer Security (TLS) Protocol, Version 1.2