Password encryption
If a password of a user is sent in an API or login request, it must be encrypted. This chapter shows an sample implementation to encrypt the password of a user.
Sample implementation
package com.onegini.example;
import static java.lang.String.format;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Base64.getDecoder;
import static java.util.Base64.getEncoder;
import static javax.crypto.Cipher.DECRYPT_MODE;
import static javax.crypto.Cipher.ENCRYPT_MODE;
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Arrays;
import java.util.Collection;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
public class JceAesGcmEncryptionTest {
/**
* Example results:
*
* Key: cf0138d58946c6849a5d972c50830f76, initialization vector: BVLdWx//evkFUt1bH/96+Q==, plaintext: P@ssword1, ciphertext: o/MCR6uS/RAmOse1+3ngU6gjf/+r8h4xWw==
* Key: cf0138d58946c6849a5d972c50830f76, initialization vector: BVLdWx//evkFUt1bH/96+Q==, plaintext: P@ssword1P@ssword1P@ssword1P@ssword1, ciphertext: o/MCR6uS/RAm3AXKVisVZoxuGFgqpBMm6uGxBaZK1Pk/oIIfg+Yf0BkINfadXkSQBklXbQ==
* Key: 4592d93c50f4fc7b57e6e67d4ddd0226, initialization vector: BVLdWx//evkFUt1bH/96+Q==, plaintext: P@ssword1, ciphertext: DJCDlVHLTEmv9+bckUGxSYMVRuesD3Imzw==
* Key: 4592d93c50f4fc7b57e6e67d4ddd0226, initialization vector: BVLdWx//evkFUt1bH/96+Q==, plaintext: P@ssword1P@ssword1P@ssword1P@ssword1, ciphertext: DJCDlVHLTEmvl2XNByIvh5fF2t2oClfyT4/4k01vFgTJTT9Gf75K8TIKn3gSdLFYngjNRA==
* Key: cf0138d58946c6849a5d972c50830f76, initialization vector: IvRBeADfn3+z6Yp8F0cAlw==, plaintext: P@ssword1, ciphertext: 4VxXjErxQ2+jMlCbKgXuiBRstBg6O9P6FA==
* Key: 4592d93c50f4fc7b57e6e67d4ddd0226, initialization vector: IvRBeADfn3+z6Yp8F0cAlw==, plaintext: P@ssword1, ciphertext: sj0QVsoqkhk5YLWWvMIpdwiITRmq0unYiA==
* Key: cf0138d58946c6849a5d972c50830f76, initialization vector: IvRBeADfn3+z6Yp8F0cAlw==, plaintext: P@ssword1P@ssword1P@ssword1P@ssword1, ciphertext: 4VxXjErxQ2+j+G5GgLzmfOidCYjxeKztyA1kx3iNJgZJImbrKqsWa5znwxTUQSK1XlGw8g==
* Key: 4592d93c50f4fc7b57e6e67d4ddd0226, initialization vector: IvRBeADfn3+z6Yp8F0cAlw==, plaintext: P@ssword1P@ssword1P@ssword1P@ssword1, ciphertext: sj0QVsoqkhk5VbMf5H2gB+ywJPRLQfibgAyaDlAgQD/Ia81LLLQ64stXoz47IZVj2soRLg==
*/
private static final String ALGORITHM = "AES";
private static final String CIPHER = "AES/GCM/NoPadding";
private static final String PROVIDER = "BC";
private final SecureRandom secureRandom;
private final String key;
private final String password;
public JceAesGcmEncryptionTest(final String key, final String password) throws NoSuchProviderException, NoSuchAlgorithmException {
this.key = key;
this.password = password;
this.secureRandom = SecureRandom.getInstance("SHA1PRNG", "SUN");
}
@Parameterized.Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{
{ "cf0138d58946c6849a5d972c50830f76", "P@ssword1"},
{ "cf0138d58946c6849a5d972c50830f76", "P@ssword1P@ssword1P@ssword1P@ssword1"},
{ "4592d93c50f4fc7b57e6e67d4ddd0226", "P@ssword1"},
{ "4592d93c50f4fc7b57e6e67d4ddd0226", "P@ssword1P@ssword1P@ssword1P@ssword1"}
});
}
@BeforeClass
public static void setUpClass()
throws Exception {
if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
Security.addProvider(new BouncyCastleProvider());
}
}
@Test
public void how_to_encrypt_password_with_random_initialization_vector() throws Exception {
final byte[] randomInitializationVector = new byte[16];
secureRandom.nextBytes(randomInitializationVector);
final String randomInitializationVectorBase64 = new String(getEncoder().encode(randomInitializationVector), UTF_8);
final String passwordEncrypted = encrypt(password, key, randomInitializationVectorBase64);
final String passwordDecrypted = decrypt(passwordEncrypted, key, randomInitializationVectorBase64);
System.out.println(format("Key: %s, random initialization vector: %s, password: %s, passwordEncrypted: %s", key, randomInitializationVectorBase64, password, passwordEncrypted));
assertEquals(passwordDecrypted, password);
assertNotEquals(passwordEncrypted, password);
}
public String encrypt(final String plaintext, final String key, final String iv) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, InvalidAlgorithmParameterException, BadPaddingException, IllegalBlockSizeException {
final byte[] plaintextBytes = plaintext.getBytes();
final Cipher cipher = createCipher(key, iv, ENCRYPT_MODE);
final byte[] ciphertextBytes = cipher.doFinal(plaintextBytes);
return new String(getEncoder().encode(ciphertextBytes), UTF_8);
}
public String decrypt(final String ciphertext, final String key, final String iv) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, InvalidAlgorithmParameterException, BadPaddingException, IllegalBlockSizeException {
final byte[] ciphertextBytes = getDecoder().decode(ciphertext);
final Cipher cipher = createCipher(key, iv, DECRYPT_MODE);
final byte[] plaintextBytes = cipher.doFinal(ciphertextBytes);
return new String(plaintextBytes, UTF_8);
}
private Cipher createCipher(final String key, final String iv, final int encryptMode) throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
final SecretKey keySpec = new SecretKeySpec(key.getBytes(), ALGORITHM);
final IvParameterSpec ivSpec = new IvParameterSpec(getDecoder().decode(iv));
final Cipher cipher = Cipher.getInstance(CIPHER, PROVIDER);
cipher.init(encryptMode, keySpec, ivSpec, secureRandom);
return cipher;
}
}