Cryptography for Java Developers
Hashes, MAC, Key Derivation, Encrypting Passwords, Symmetric Ciphers & AES, Digital Signatures & ECDSA
About the Speaker
What is Cryptography?
Cryptography in Java – APIs and Libraries
Hashes, MAC Codes and Key Derivation (KDF)
Encrypting Passwords: from Plaintext to Argon2
Symmetric Encryption: AES (KDF + Block Modes + IV + MAC)
Digital Signatures, Elliptic Curves, ECDSA, EdDSA
Live demos and code examples: https://github.com/nakov/Java-Cryptography-Examples
Video (in Bulgarian language): https://youtu.be/ZG3BLXWVwJM
Blog: https://nakov.com/blog/2019/01/26/cryptography-for-java-developers-nakov-at-jprofessionals-jan-2019/
P4C x ELT = P4ELT: Its Theoretical Background (Kanazawa, 2024 March).pdf
Cryptography for Java Developers: Nakov jProfessionals (Jan 2019)
1. Hashes, MAC, Key Derivation, Encrypting Passwords,
Symmetric Ciphers & AES, Digital Signatures & ECDSA
Cryptography for Java Developers
Dr. Svetlin Nakov
Co-Founder, Chief Training & Innovation
@ Software University (SoftUni)
https://nakov.com
Software University (SoftUni) – http://softuni.org
2. Table of Contents
1. About the Speaker
2. What is Cryptography?
3. Cryptography in Java – APIs and Libraries
4. Hashes, MAC Codes and Key Derivation (KDF)
5. Encrypting Passwords: from Plaintext to Argon2
6. Symmetric Encryption:
AES (KDF + Block Modes + IV + MAC)
7. Digital Signatures, Elliptic Curves, ECDSA, EdDSA 2
3. Software engineer, trainer, entrepreneur,
PhD, author of 15+ books, blockchain expert
3 successful tech educational initiatives (150,000+ students)
About Dr. Svetlin Nakov
3
4. Book "Practical Cryptography for Developers"
4
GitHub:
github.com/nakov/pra
ctical-cryptography-
for-developers-book
Book site:
https://cryptobook.
nakov.com
6. Cryptography provides security and protection of information
Storing and transmitting data in a secure way
Hashing data (message digest) and MAC codes
Encrypting and decrypting data
Symmetric and asymmetric schemes
Key derivation functions (KDF)
Key agreement schemes, digital certificates
Digital signatures (sign / verify)
What is Cryptography?
6
8. JDK defines security APIs based on
pluggable security providers
Build-in providers (come with JDK)
and 3rd party providers
Named algorithms, e.g.
MessageDigest: SHA-256, SHA3-
256, RipeMD160, Skein-1024
Cipher: AES, Blowfish, ECIES
Signature: SHA3-256withECDSA,
SHA512withRSA, SHA384withDSA
Java Security: Architecture
8
9. Cryptography in Java is based on the Java Cryptography
Architecture (JCA)
The built-in functionality is limited
Typical Java style: lot of boilerplate code
Bouncy Castle is a leading Java crypto library / API / provider
https://www.bouncycastle.org/java.html
Argon2 JVM – fast Argon2 native implementation for Java
https://github.com/phxql/argon2-jvm
Cryptography APIs in Java
9
10. Cava Crypto – excellent simple ECDSA library for secp256k1
https://github.com/ConsenSys/cava
https://github.com/ConsenSys/cava/tree/master/crypto
Web3j / Crypto – a simplified library for secp256k1 signatures
https://github.com/web3j
Ed25519-Java – simple EdDSA and Ed25519 implementation
https://github.com/str4d/ed25519-java
Cryptography APIs in Java
10
11. Use Maven / Gradle to install the Java crypto libraries
Installing the Bouncy Castle crypto provider / API
Installing the Libraries
11
pom.xml
<!-- Install the Bouncy Castle crypto provider for Java -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.60</version>
</dependency>
13. What is Cryptographic Hash Function?
13
One-way transformation, infeasible to invert
Extremely little chance to find a collision
Some text
Some text
Some text
Some text
Some text
Some text
Some text
20c9ad97c081d63397d
7b685a412227a40e23c
8bdc6688c6f37e97cfb
c22d2b4d1db1510d8f6
1e6a8866ad7f0e17c02
b14182d37ea7c3c8b9c
2683aeb6b733a1
Text Hash (digest)
Cryptographic
hash function
14. SHA-2 (SHA-256, SHA-384, SHA-512)
Secure crypto hash function, the most widely used today (RFC 4634)
Used in Bitcoin, IPFS, many others
SHA-3 (SHA3-256, SHA3-384, SHA3-512) / Keccak-256
Strong cryptographic hash function, more secure than SHA-2
Used in Ethereum and many modern apps
Modern Hashes: SHA-2, SHA3
14
SHA-256('hello') = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7
425e73043362938b9824
SHA3-256('hello') = 3338be694f50c5f338814986cdf0686453a888b84f4
24d792af4b9202398f392
15. BLAKE2 (BLAKE2s – 256-bit, BLAKE2b – 512-bit)
Secure crypto hash function, very fast
RIPEMD-160 (160-bit crypto hash)
Considered weak, just 160-bits, still unbroken
Broken hash algorithms: MD5, SHA-1, MD4, SHA-0, MD2
Git and GitHub still use SHA-1 and suffer of collision attacks
Modern Hashes: BLAKE2, RIPEMD-160
15
BLAKE2s('hello') = 19213bacc58dee6dbde3ceb9a47cbb330b3d86f8cca8
997eb00be456f140ca25
RIPEMD-160('hello') = 108f07b8382412612c048d07d13f814118445acd
16. Calculate SHA-256 hash using the built-in JCA provider:
SHA-256 in Java – Example
16
var digest = MessageDigest.getInstance("SHA-256");
digest.update("hello".getBytes());
byte[] hash = digest.digest();
System.out.println("SHA-256('hello') = " +
Hex.toHexString(hash));
import java.security.MessageDigest;
import org.bouncycastle.util.encoders.Hex;
SHA-256('hello') =
2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
17. Calculate RIPEMD-160 hash using the Bouncy Castle provider:
RIPEMD-160 in Java – Example
17
var digest = MessageDigest.getInstance("RIPEMD160");
digest.update("hello".getBytes());
byte[] hash = digest.digest();
System.out.println("RIPEMD-160('hello') = " +
Hex.toHexString(hash));
import java.security.*;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
// One-time registration of the "BouncyCastle" JCA provider
Security.addProvider(new BouncyCastleProvider());
108f07b8382412612c048d07d13f814118445acd
22. Scrypt (RFC 7914) is a strong cryptographic key-derivation function
Memory intensive, designed to prevent ASIC and FPGA attacks
key = Scrypt(password, salt, N, r, p, derived-key-len)
N – iterations count (affects memory and CPU usage), e.g. 16384
r – block size (affects memory and CPU usage), e.g. 8
p – parallelism factor (threads to run in parallel), usually 1
Memory used = 128 * N * r * p bytes, e.g. 128 * 16384 * 8 = 16 MB
Parameters for interactive login: N=16384, r=8, p=1 (RAM=16MB)
Parameters for file encryption: N=1048576, r=8, p=1 (RAM=1GB)
Key Derivation Functions: Scrypt
22
23. Scrypt in Java – Example
23
// One-time registration of the "BouncyCastle" JCA provider
Security.addProvider(new BouncyCastleProvider());
ScryptKeySpec spec = new ScryptKeySpec(
"password".toCharArray(), "salt".getBytes(),
16384, 8, 1, 128);
var keyFact = SecretKeyFactory.getInstance("Scrypt");
byte[] derivedKey = keyFact.generateSecret(spec).getEncoded();
System.out.println("Scrypt: " + Hex.toHexString(derivedKey));
Scrypt: 745731af4484f323968969eda289aeee
24. Argon2 is ASIC-resistant KDF, stronger than Scrypt and bcrypt
Recommended due to better ASIC-resistance
Key Derivation: Argon2
24
pom.xml
<!-- Install Argon2-JVM – fast native Argon2 library for Java -->
<dependency>
<groupId>de.mkammerer</groupId>
<artifactId>argon2-jvm</artifactId>
<version>2.5</version>
</dependency>
26. Clear-text passwords, e.g. store the password directly in the DB
Never do anti-pattern!
Simple password hash, e.g. store SHA256(password) in the DB
Highly insecure, still better than clear-text, dictionary attacks
Salted hashed passwords, e.g. store HMAC(pass, random_salt)
Almost secure, GPU / ASIC-crackable
ASIC-resistant KDF password hash, e.g. Argon2(password)
Recommended, secure (when the KDF settings are secure)
Password Encryption (Register / Login)
26
28. Symmetric Encryption
AES, Block Modes, Authenticated Encryption
encrypt
(secret key)
I am a non-
encrypted
message …
decrypt
(secret key)
I am a non-
encrypted
message …
29. Symmetric key ciphers
Use the same key
(or password) to encrypt
and decrypt data
Popular symmetric algorithms
AES, ChaCha20, Twofish, Serpent, RC5, RC6
Broken algorithms (don't use them!)
DES, 3DES, RC2, RC4
Symmetric Key Ciphers
29
30. Block ciphers
Split data on blocks (e.g. 128 bits), then encrypt each block
separately, change the internal state, encrypt the next block, …
Stream ciphers
Work on sequences of data (encrypts / decrypts byte by byte)
Block ciphers can be transformed to stream ciphers
Using block mode of operation (e.g. CBC, CTR, GCM, CFB, …)
https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
Symmetric Key Ciphers
30
31. AES – Advanced Encryption Standard (Rijndael)
Symmetric key block cipher (128-bit blocks)
Key lengths: 128, 160, 192, 224 and 256 bits
No significant practical attacks are known for AES
Modern CPU hardware implements AES instructions
This speeds-up AES and secure Internet communication
AES is used by most Internet Web sites for the https:// content
The "AES" Cipher
31
32. AES is a "block cipher" – encrypts block by block (e.g. 128 bits)
Supports several modes of operation (CBC, CTR, GCM, …)
Some modes of operation (like CBC / CTR) require initial vector (IV)
Non-secret random salt used to get different result each time
Recommended modes: CTR (Counter) or GCM (Galois/Counter)
CBC may use a padding algorithm (typically PKCS7) to help splitting
the input data into blocks of fixed block-size (e.g. 128 bits)
May use password to key derivation function, e.g. Argon2(passwd)
May use MAC to check the password validity, e.g. HMAC(text, key)
AES Cipher Settings
32
33. The AES Encryption Process
33
input msg random IV+
AES
key+ ciphertext
input msg
MAC
key+ MAC code
input msg key+
AES
ciphertext MAC+IV+
KDF
password key kdf-salt+
34. The AES Decryption Process
34
original msg
MAC
key+ MAC code
AES
ciphertext IV+
KDF
password key
original msg
decrypt
Decryption
MAC code
compare Encryption
MAC code
key+
kdf-salt+
35. AES-256-CTR-Argon2-HMAC – Encrypt
35
static Map<String, String> aes256CtrArgon2HMacEncrypt(
String plainText, String password) throws Exception {
// Derive a secret key from the encryption password
SecureRandom rand = new SecureRandom();
byte[] argon2salt = new byte[16];
rand.nextBytes(argon2salt); // Generate 128-bit salt
byte[] argon2hash = Argon2Factory.createAdvanced(
Argon2Factory.Argon2Types.ARGON2id).rawHash(16,
1 << 15, 2, password, argon2salt);
Key secretKey = new SecretKeySpec(argon2hash, "AES");
36. AES-256-CTR-Argon2-HMAC – Encrypt
36
// AES encryption: {plaintext + IV + secretKey} -> ciphertext
byte[] aesIV = new byte[16];
rand.nextBytes(aesIV); // Generate 128-bit IV (salt)
IvParameterSpec ivSpec = new IvParameterSpec(aesIV);
Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
byte[] plainTextBytes = plainText.getBytes("utf8");
byte[] cipherBytes = cipher.doFinal(plainTextBytes);
// Calculate the MAC of the plaintext with the argon2hash
Mac mac = Mac.getInstance("HmacSHA256");
Key macKey = new SecretKeySpec(argon2hash, "HmacSHA256");
mac.init(macKey);
byte[] hmac = mac.doFinal(plainText.getBytes("utf8"));
42. Digital signatures provide message signing / verification
Authentication (proof that known sender have signed the message)
Integrity (the message cannot be altered after signing)
Non-repudiation (signer cannot deny message signing)
Digital signatures are based on public key cryptography
Messages are signed by someone's private key
Signatures are verified by the corresponding public key
May use RSA, DSA, elliptic curves (ECC) like ECDSA / EdDSA
Digital Signatures – Concepts
42
43. Uses a pair of keys: public key + private key
Sign / decrypt by private key
Verify / encrypt by public key
Public Key Cryptography
43
44. Well-known public-key crypto-systems
RSA – based on discrete logarithms
ECC – based on elliptic curves
ECC cryptography is considered more secure
3072-bit RSA key ≈≈ 256-bit ECC key ~ 128-bit security level
Most blockchains (like Bitcoin, Ethereum and EOS) use ECC
But be warned: ECC is not quantum-safe!
Public Key Crypto Systems
44
45. Digital signatures in Java are painful use external libraries
Use the "Cava Crypto" library for secp256k1 ECDSA signatures
ECDSA in Java – Example
45
pom.xml
!-- Install Cava Crypto: simple secp256k1 ECDSA library -->
<dependency>
<groupId>net.consensys.cava</groupId>
<artifactId>cava-crypto</artifactId>
<version>0.5.0</version>
</dependency>
46. ECDSA in Java – Example
46
Registering the Bouncy Castle crypto provider
Generating public + private key pair:
Security.addProvider(new BouncyCastleProvider());
// Generate random key-pair
SECP256K1.KeyPair keyPair = SECP256K1.KeyPair.random();
// Load key-pair from existing private key
SECP256K1.KeyPair keyPair = SECP256K1.KeyPair.fromSecretKey(
SECP256K1.SecretKey.fromInteger(new BigInteger(
"207724f0eba0800350f579726c2a8bbd1ac6385f4168e493cfd91efe522959cf", 16)));
51. EdDSA is elliptic curve-based digital signature scheme
(based on Edwards curves)
Ed25519 is fast Edwards curve, used for EdDSA signatures
256-bit public key (252 + 5 fixed bits) and 256-bit private key
Supported by 3rd party libraries like
https://github.com/str4d/ed25519-java
EdDSA is preferred to ECDSA in most modern apps
Faster and easier to use
EdDSA + Ed25519 Signatures
51
52. EdDSA in Java – Example
52
Installing the required library Ed25519-Java using Maven
Registering the EdDSA-Java crypto provider
Security.addProvider(new EdDSASecurityProvider());
pom.xml
<dependency>
<groupId>net.i2p.crypto</groupId>
<artifactId>eddsa</artifactId>
<version>0.3.0</version>
</dependency>
53. EdDSA in Java – Example
53
Generating a random EdDSA public + private key pair
var keyGen = KeyPairGenerator.getInstance("EdDSA");
var keyPair = keyGen.generateKeyPair();
System.out.println("Private key: " +
Hex.toHexString(keyPair.getPrivate().getEncoded()));
System.out.println("Public key: " +
Hex.toHexString(keyPair.getPublic().getEncoded()));
Private key: 302e020100300506032b657004220420b57ea3f12b503be8e7c89
99dd9cb630ecb06cb68e10763fb40331e5131b2a1f0
Public key: 302a300506032b6570032100796295d26f7a69a2a573cf95f99bd5
becb906e757bb55424deb4ed00a99cc572
54. EdDSA in Java – Example
54
Signing a message with EdDSA
String msg = "Message for signing";
Signature signer = new EdDSAEngine(
MessageDigest.getInstance("SHA-512"));
signer.initSign(keyPair.getPrivate());
signer.update(msg.getBytes());
byte[] signature = signer.sign();
System.out.println("Signature: " + Hex.toHexString(signature));
Signature: 1256d92d27b5b4e633494b86f5f55dc18155ae4eed35d5f596f1dbb
894acef0df7e2b756ef5e5681260d2f46dd1c26e180591e1ec3f9997f213ddf0ca
55c6703