The Java Cryptography API enables you to encrypt and decrypt data in Java, as well as manage keys, sign and authenticate messages, calculate cryptographic hashes and much more. The term cryptography is often abbreviated to crypto, so sometimes you will see references to Java crypto instead of Java Cryptography. The two terms refer to the same topic though.
The Java Mac
class is used to create a MAC from a message. The term MAC is short for Message Authentication Code. A MAC is similar to a message digest, but uses an additional key to encrypt the message digest. Only by having both the original data and the key can you verify the MAC. Thus, a MAC is a more secure way to guard a block of data from modification than a message digest. The Mac
class is described in more detail in the Java Mac tutorial, but below is a short introduction.
You create a Java Mac
instance by calling the Mac.getInstance()
method, passing as parameter the name of the algorithm to use. Here is how that looks:
import javax.crypto.Cipher; import javax.crypto.Mac; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.net.URLDecoder; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; import java.util.Arrays; import java.util.Base64; public class EncryptionService { private static final String cipher_type = "AES/CBC/PKCS5Padding";// same as PKCS7 padding mode private static int IV_SIZE = 16; // 128 bit private final byte[] encryption_key; private final byte[] auth_key; /** * * @param encryption_key * must be 44 bytes and Base64 encoded<br> * @param auth_key * must be 44 bytes and Base64 encoded<br> */ public EncryptionService(String encryption_key, String auth_key) throws Exception { this.encryption_key = Base64.getDecoder().decode(encryption_key); this.auth_key = Base64.getDecoder().decode((auth_key)); } public String encrypt(String inputStr) throws Exception { byte[] input = inputStr.getBytes("UTF-8"); byte[] iv = generateIV(); byte[] ciphertext = encrypt(encryption_key, iv, input); byte[] ivcipher = concat(iv, ciphertext); byte[] hmac = generateHMAC(auth_key, ivcipher); return Base64.getEncoder().encodeToString(concat(ivcipher, hmac)); } public String encryptAndUrlEncode(String input) throws Exception { String encryptedInput = encrypt(input); return URLEncoder.encode(encryptedInput, StandardCharsets.UTF_8.toString()); } public String decrypt(String base64_payload) throws Exception { byte[] encrypted_payload = Base64.getDecoder().decode(base64_payload); byte[] iv = Arrays.copyOf(encrypted_payload, IV_SIZE); int macLenght = hmacLength(auth_key); byte[] hmac1 = Arrays.copyOfRange(encrypted_payload, encrypted_payload.length - macLenght, encrypted_payload.length); byte[] ciphertext = Arrays.copyOfRange(encrypted_payload, IV_SIZE, encrypted_payload.length - macLenght); byte[] data = concat(iv, ciphertext); byte[] hmac2 = generateHMAC(auth_key, data); if (Arrays.equals(hmac1, hmac2)) { byte[] decrypt = decrypt(encryption_key, iv, ciphertext); return new String(decrypt, "UTF-8"); } else { throw new RuntimeException("Incorrect HMAC"); } } public String decryptUrlEncodedPayload(String urlEncodedPayload) throws Exception { String decodedPayload = URLDecoder.decode(urlEncodedPayload, StandardCharsets.UTF_8.toString()); return this.decrypt(decodedPayload); } private byte[] generateIV() throws Exception { byte[] iv = new byte[IV_SIZE]; SecureRandom randomSecureRandom = SecureRandom.getInstance("SHA1PRNG"); randomSecureRandom.nextBytes(iv); return iv; } private byte[] encrypt(byte[] skey, byte[] iv, byte[] data) throws Exception { SecretKeySpec key = new SecretKeySpec(skey, "AES"); Cipher cipher = Cipher.getInstance(cipher_type); AlgorithmParameterSpec param = new IvParameterSpec(iv); cipher.init(Cipher.ENCRYPT_MODE, key, param); return cipher.doFinal(data); } private byte[] decrypt(byte[] skey, byte[] iv, byte[] data) throws Exception { SecretKeySpec key = new SecretKeySpec(skey, "AES"); AlgorithmParameterSpec param = new IvParameterSpec(iv); Cipher cipher = Cipher.getInstance(cipher_type); cipher.init(Cipher.DECRYPT_MODE, key, param); return cipher.doFinal(data); } /* * Generate Hashed Message Authentication Code (HMAC) */ private byte[] generateHMAC(byte[] skey, byte[] data) throws Exception { SecretKeySpec key = new SecretKeySpec(skey, "HmacSHA256"); Mac sha256_HMAC = Mac.getInstance("HmacSHA256"); sha256_HMAC.init(key); return sha256_HMAC.doFinal(data); } private int hmacLength(byte[] skey) throws Exception { SecretKeySpec key = new SecretKeySpec(skey, "HmacSHA256"); Mac sha256_HMAC = Mac.getInstance("HmacSHA256"); sha256_HMAC.init(key); return sha256_HMAC.getMacLength(); } private byte[] concat(byte[] first, byte[] second) { byte[] result = Arrays.copyOf(first, first.length + second.length); System.arraycopy(second, 0, result, first.length, second.length); return result; } }
@Test public void test_encryption() throws Exception { // // must be 44 bytes or more // String encryptionKey = "/I+CI2+sX6Z1aAr/6U6B1NuXjogJXbY0LATv6Ew1L6M="; // // // must be 44 bytes or more // String authKey = "bpyp6QiIHE/h8Uh0OTvghrNd+x7ez+vEtX+GQ8tpwVk="; String encryptionKey = new String(Base64.getEncoder().encode("testtesttesttesttesttesttesttest".getBytes())); String authKey = new String(Base64.getEncoder().encode("testtesttesttesttesttesttesttest".getBytes())); System.out.println(new String(Base64.getDecoder().decode(encryptionKey))); System.out.println(new String(Base64.getDecoder().decode(authKey))); EncryptionService encryptionService = new EncryptionService(encryptionKey, authKey); String inputStr = "hello"; System.out.println("inputStr: " + inputStr); String encryptedStr = encryptionService.encrypt(inputStr); System.out.println("encryptedStr: " + encryptedStr); String decryptedStr = encryptionService.decrypt(encryptedStr); System.out.println("decryptedStr: " + decryptedStr); }
testtesttesttesttesttesttesttest testtesttesttesttesttesttesttest inputStr: hello encryptedStr: XdNGUYxx/eiTR4s2r1OSDuytHAd4vFAtbVZZUFESWM7QV4ftQpwVQEt22i77Xq6fFSCGEWDLyKps7KxKgB+7Qg== decryptedStr: hello