Skip to content

Java Password encryption example

The example below uses the BouncyCastle library.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
package com.onegini.example;

import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.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.Base64;
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 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 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() {
    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(Base64.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, Cipher.ENCRYPT_MODE);
    final byte[] ciphertextBytes = cipher.doFinal(plaintextBytes);
    return new String(Base64.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 = Base64.getDecoder().decode(ciphertext);
    final Cipher cipher = createCipher(key, iv, Cipher.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(Base64.getDecoder().decode(iv));
    final Cipher cipher = Cipher.getInstance(CIPHER, PROVIDER);
    cipher.init(encryptMode, keySpec, ivSpec, secureRandom);
    return cipher;
  }
}