Password encryption
If a password of a user is sent in an API or login request, it must be encrypted. API accepts hexadecimal representation of 128, 192 and 256 bit keys with hex:
prefix. Key can be generated by using openssl, example:
$ openssl aes-256-cbc -k secret -P -md sha1
salt=B6DDBE4EEAAEA8E4
key=C4B6150B28D655A64BFD2B01A0795770F495B1D07545CE82145CF7CEC0285986
iv =E7A4713DFBBE38CADA40170F0D34BCEC
This chapter shows an sample implementation to encrypt the password of a user.
Sample implementation
package com.onegini.example;
import ...
@RunWith(Parameterized.class)
public class JceAesGcmEncryptionTest {
/**
* Example results:
*
* Key 128 bit: 64504E14F8C3E18885C67DC57CB4EA4B, initialization vector: TOZvZFEdjaiK3BRYW1+63g==, plaintext: P@ssword1, ciphertext: yiuV8JnT0EERnL0gECFStaO+XZkcTHU2Rw==
* Key 192 bit: 2EAA9BE43F203B52C028A0EE32D8842542C9FF0A3D377FEF, initialization vector: HxSwolleur3ycGzp2Su0qw==, plaintext: P@ssword1P@ssword1P@ssword1P@ssword1, ciphertext: dSYVmPY+xIukujosaTx4HrWCmj8TXhgykKNe2F3bijdBUNhjr26a3S1eXFTsAo/AsU6rcw==
* Key 256 bit: 355D9E1F85FFF43161BDBAFAA7B3994F548767F0C1FB36D5FA36D63C1C3DF413, initialization vector: vuL6aXzYgo4KoiSPg9wFvw==, plaintext: P@ssword1, ciphertext: fwQ9BaJ4gZ49IBbuyzbJDSf4cjngbDKq3g==
*/
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[][]{
{ "hex:64504E14F8C3E18885C67DC57CB4EA4B", "P@ssword1"}, // 128 bit hex
{ "Hex:2EAA9BE43F203B52C028A0EE32D8842542C9FF0A3D377FEF", "P@ssword1P@ssword1P@ssword1P@ssword1"}, // 192 bit hex key
{ "HEX:355D9E1F85FFF43161BDBAFAA7B3994F548767F0C1FB36D5FA36D63C1C3DF413", "P@ssword1"}, // 256 bit key hex
});
}
@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(String.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 = SecretKeySpecFactory.of(key, ALGORITHM);
final IvParameterSpec ivSpec = new IvParameterSpec(getDecoder().decode(iv));
final Cipher cipher = Cipher.getInstance(CIPHER, PROVIDER);
cipher.init(encryptMode, keySpec, ivSpec, secureRandom);
return cipher;
}
}