We have summarized how to handle the following cryptographic techniques in the Java standard library. We will briefly explain each cryptographic technology and introduce an implementation example.
--Symmetric encryption (AES) --Public Key Cryptography (RSA) --One-way hash function (SHA-256) --Message authentication code (HMAC) --Digital signature (RSA + SHA-256) --Diffie-Hellman Key Exchange
The algorithm used in the implementation example is shown in parentheses.
Symmetric encryption is a technology that protects the confidentiality of messages. It has the following features.
--The encryption and decryption keys are the same --Processing speed is faster than public key cryptography
This is a method for generating a symmetric key (common key).
public SecretKey generateKey() throws NoSuchAlgorithmException {
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(128);
return keyGen.generateKey();
}
How to generate an initialization vector. The initialization vector is a random bit string that is intended to be used so that different ciphertexts can be obtained each time even if encrypted using the same key.
public IvParameterSpec generateIV() {
SecureRandom random = new SecureRandom();
byte[] iv = new byte[16];
random.nextBytes(iv);
return new IvParameterSpec(iv);
}
How to encrypt a message.
Specify the algorithm, block mode, and padding method when acquiring the Cipher
instance.
See the JavaDoc for the Cipher
class for a combination of algorithms, block modes, and padding methods.
public byte[] encrypto(String plainText, SecretKey key, IvParameterSpec iv) throws GeneralSecurityException {
//Format:"algorithm/Block mode/Padding method"
Cipher encrypter = Cipher.getInstance("AES/CBC/PKCS5Padding");
encrypter.init(Cipher.ENCRYPT_MODE, key, iv);
return encrypter.doFinal(plainText.getBytes());
}
This is the method of decrypting the ciphertext. Specify the algorithm, block mode, and padding method as you did for encryption.
public String decrypto(byte[] cryptoText, SecretKey key, IvParameterSpec iv) throws GeneralSecurityException {
//Format:"algorithm/Block mode/Padding method"
Cipher decrypter = Cipher.getInstance("AES/CBC/PKCS5Padding");
decrypter.init(Cipher.DECRYPT_MODE, key, iv);
return new String(decrypter.doFinal(cryptoText));
}
Public key cryptography is a technology for protecting the confidentiality of messages. It has the following features.
--The encryption and decryption keys are different --Slow processing speed compared to symmetric encryption
This is a method for generating a public key cryptographic key pair (public key / private key pair).
public KeyPair generateKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2024);
return keyGen.generateKeyPair();
}
Obtain the public / private key from the key pair.
KeyPair keyPair = generateKeyPair();
PublicKey publickey = keyPair.getPublic();
PrivateKey privatekey = keyPair.getPrivate();
How to encrypt a message. Encrypt using ** public key **.
Specify the algorithm, block mode, and padding method when acquiring the Cipher
instance.
See the JavaDoc for the Cipher
class for a combination of algorithms, block modes, and padding methods.
public byte[] encrypto(String plainText, PublicKey publickey) throws GeneralSecurityException {
//Format:"algorithm/Block mode/Padding method"
Cipher encrypter = Cipher.getInstance("RSA/ECB/PKCS1Padding");
encrypter.init(Cipher.ENCRYPT_MODE, publickey);
return encrypter.doFinal(plainText.getBytes());
}
This is the method of decrypting the ciphertext. Decrypt using the ** private key **. Specify the algorithm, block mode, and padding method as you did for encryption.
public String decrypto(byte[] cryptoText, PrivateKey privatekey) throws GeneralSecurityException {
Cipher decrypter = Cipher.getInstance("RSA/ECB/PKCS1Padding");
decrypter.init(Cipher.DECRYPT_MODE, privatekey);
return new String(decrypter.doFinal(cryptoText));
}
The one-way hash function is a technology for detecting message tampering. It has the following features.
--A fixed-length hash value can be obtained from a message of any length. --It is practically impossible to obtain the original message from the hash value (it takes a very long time)
How to hash a message. In Java, the one-way hash function is called "message digest".
private byte[] hash(String plainText) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA-256");
return md.digest(plainText.getBytes());
}
This is a method for detecting tampering. All you have to do is get the hash value again and compare.
private boolean verify(String plainText, byte[] givenHash) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] newHash = md.digest(plainText.getBytes());
return Arrays.equals(givenHash, newHash);
}
Message authentication code (MAC) is a technology for detecting message tampering and "spoofing". It has the following features.
--Get the MAC value of a message using a common key for the sender and recipient of the message --Fixed length MAC value can be obtained from messages of arbitrary length --It is practically impossible to obtain the original message from the MAC value (it takes a very long time) --Recipient can detect sender "spoofing" --Third parties cannot detect the sender's "spoofing" (the recipient may be "spoofing" to the sender)
This is the method for generating the key (common key) for the message authentication code.
public SecretKey generateKey() throws NoSuchAlgorithmException {
KeyGenerator keyGen = KeyGenerator.getInstance("HmacSHA256");
return keyGen.generateKey();
}
How to get the MAC value of a message.
private byte[] mac(String plainText, SecretKey key) throws GeneralSecurityException {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(key);
return mac.doFinal(plainText.getBytes());
}
This is a method for detecting tampering. All you have to do is get the MAC value again and compare.
private boolean verify(String plainText, SecretKey key, byte[] givenMac) throws GeneralSecurityException {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(key);
byte[] newMac = mac.doFinal(plainText.getBytes());
return Arrays.equals(givenMac, newMac);
}
Digital signatures are a technology for detecting message tampering and "spoofing". It has the following features.
--Use different keys for message sender and recipient --Recipient can detect sender "spoofing" --Third parties can detect "spoofing" of the sender --The public / private key of public key cryptography is used in reverse.
How to generate a digitally signed key pair (public key / private key pair).
public KeyPair generateKey() throws NoSuchAlgorithmException {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2024);
return keyGen.generateKeyPair();
}
Obtain the public / private key from the key pair.
KeyPair keyPair = generateKey();
PublicKey publickey = keyPair.getPublic();
PrivateKey privatekey = keyPair.getPrivate();
How to sign a message. Sign using the ** private key **.
public byte[] sign(String plainText, PrivateKey privatekey) throws GeneralSecurityException {
Signature sign = Signature.getInstance("SHA256withRSA");
sign.initSign(privatekey);
sign.update(plainText.getBytes());
return sign.sign();
}
How to verify your signature. Validate using ** public key **.
public boolean verify(String plainText, byte[] sign, PublicKey publicKey) throws GeneralSecurityException {
Signature verify = Signature.getInstance("SHA256withRSA");
verify.initVerify(publicKey);
verify.update(plainText.getBytes());
return verify.verify(sign);
}
Diffie-Hellman key exchange is a technology for securely sharing a common key between the sender and recipient of a message. It has the following features.
--The sender and receiver of the message exchange information and generate a common key based on that information. --Even if a third party eavesdrops on the exchanged information, the third party cannot generate a common key.
The procedure for Diffie-Hellman key exchange is complicated, so let's organize the procedure before explaining how to use it in detail. Invite Alice (sender) and Bob (receiver) to appear to explain the procedure.
When Alice and Bob exchange keys, follow the steps below to generate a common key.
We will explain how to exchange keys according to the procedure explained above.
First, generate a key pair and get P and G from the key pair.
//Key pair generation
public KeyPair generateKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DiffieHellman");
keyGen.initialize(2048);
return keyGen.generateKeyPair();
}
//Get P and G
KeyPair keyPair = generateKeyPair();
DHPublicKey publicKey = (DHPublicKey) keyPair.getPublic();
DHParameterSpec paramSpec = publicKey.getParams();
BigInteger p = paramSpec.getP();
BigInteger g = paramSpec.getG();
In Java, the values of P and G are fixed. See the Java Cryptography Architecture Standard Algorithm Name Documentation for P and G values.
https://docs.oracle.com/javase/jp/8/docs/technotes/guides/security/StandardNames.html#algspec Algorithm specifications → DSA key pair generation algorithm → Default values of parameters
Send P and G from Alice to Bob. At this time, the values of P and G may be seen by a third party. Bob will generate a key pair based on the received P and G.
public KeyPair generateKeyPair(BigInteger p, BigInteger g) throws GeneralSecurityException {
DHParameterSpec paramSpec = new DHParameterSpec(p, g);
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DiffieHellman");
keyGen.initialize(paramSpec);
return keyGen.generateKeyPair();
}
Alice gets the secret value X and the public value Y.
//Get secret value X
DHPrivateKey privateKey = (DHPrivateKey) keyPair.getPrivate();
BigInteger x = privateKey.getX();
//Get public value Y
DHPublicKey publicKey = (DHPublicKey) keyPair.getPublic();
BigInteger y = publicKey.getY();
Bob gets the secret value X and the public value Y. The acquisition method is the same as Alice.
Alice and Bob exchange the published value Y. At this time, the value of Y may be seen by a third party.
Alice generates a common key.
To generate the common key, use the values of P and G, the public value Y of the other party (Bob), and the private key (DHPrivateKey
) of yourself (Alice).
public SecretKey generateKey(BigInteger p, BigInteger g, BigInteger othersY, DHPrivateKey myPrivateKey)
throws GeneralSecurityException {
//Generate the public key of the other party (Bob)
DHPublicKeySpec publicKeySpec = new DHPublicKeySpec(othersY, p, g);
KeyFactory keyFactory = KeyFactory.getInstance("DiffieHellman");
DHPublicKey othersPublicKey = (DHPublicKey) keyFactory.generatePublic(publicKeySpec);
//Generate a common key using the public key of the other party (Bob) and the private key of yourself (Alice)
KeyAgreement keyAgreement = KeyAgreement.getInstance("DiffieHellman");
keyAgreement.init(myPrivateKey);
keyAgreement.doPhase(othersPublicKey, true);
SecretKey key = keyAgreement.generateSecret("AES");
return key;
}
Bob generates a common key.
It is generated in the same way as Alice, but uses Alice's public value Y and Bob's private key (DHPrivateKey
).
PBE -Password Based Encryption-
PBE is a technology for protecting confidentiality using passwords. It has the following features.
--The encryption and decryption keys are the same --Generate key from password
Prepare the salt before generating the key. Salt is a random byte array. Salt is used to prevent passwords from being cracked by dictionary attacks.
public byte[] generateSalt() {
SecureRandom random = new SecureRandom();
byte[] salt = new byte[8];
random.nextBytes(salt);
return salt;
}
This is the method for generating the PBE key (common key). Specify the password, salt, and the number of hashes. By increasing the number of hashes, you can increase the processing time required for brute force attacks.
public SecretKey generateKey(String password, byte[] salt, int hashCount) throws GeneralSecurityException {
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, hashCount);
SecretKeyFactory keyFac = SecretKeyFactory.getInstance("PBEWithHmacSHA256AndAES_128");
SecretKey key = keyFac.generateSecret(keySpec);
keySpec.clearPassword();
return key;
}
Get the algorithm parameters as a byte array and save. Values such as initialization vector are stored in the algorithm parameters.
private byte[] getAlgorithmParameters(SecretKey key) throws GeneralSecurityException, IOException {
Cipher encrypter = Cipher.getInstance("PBEWithHmacSHA256AndAES_128");
encrypter.init(Cipher.ENCRYPT_MODE, key);
AlgorithmParameters params = encrypter.getParameters();
return params.getEncoded();
}
How to encrypt a message. Specify the common key and algorithm parameters.
public byte[] encrypto(String plainText, SecretKey key, byte[] algParam)
throws GeneralSecurityException, IOException {
AlgorithmParameters params = AlgorithmParameters.getInstance("PBEWithHmacSHA256AndAES_128");
params.init(algParam);
Cipher encrypter = Cipher.getInstance("PBEWithHmacSHA256AndAES_128");
encrypter.init(Cipher.ENCRYPT_MODE, key, params);
return encrypter.doFinal(plainText.getBytes());
}
This is the method of decrypting the ciphertext. Specify the common key and algorithm parameters.
public String decrypto(byte[] cryptoText, SecretKey key, byte[] algParam)
throws GeneralSecurityException, IOException {
AlgorithmParameters params = AlgorithmParameters.getInstance("PBEWithHmacSHA256AndAES_128");
params.init(algParam);
Cipher decrypter = Cipher.getInstance("PBEWithHmacSHA256AndAES_128");
decrypter.init(Cipher.DECRYPT_MODE, key, params);
return new String(decrypter.doFinal(cryptoText));
}
Here is a summary of what I learned about cryptography, which is gaining more and more attention due to the rise of blockchain. You can see that Java covers various cryptographic techniques.
Recommended Posts