Fluent builders with typesafe API for the JCA

Overview

Download Build Status

Security Builders

This library implements a set of "fluent" API builders for the java.security classes, and provides more typesafe, intuitive API to access trust stores, key stores and keys. The primary purpose of this library is to make small tasks easy, and provide better integration with the JSSE stack.

Installation

Maven

In your pom.xml:

<dependency>
    <groupId>com.tersesystems.securitybuilder</groupId>
    <artifactId>securitybuilder</artifactId>
    <version>1.0.0</version><!-- see badge for latest version -->
</dependency>

sbt

libraryDependencies += "com.tersesystems.securitybuilder" % "securitybuilder" % "1.0.0"

Usage

The primary use of this package is to set up test X.509 certificates, private keys and trust stores. The Java Cryptography Architecture lays out how to create and initialize certificates, keystores, and so on, but typically does so in frustrating ways.

The assumption is that you'll be working with Java 1.8 but with decent algorithms, so there are a number of preset defaults. The builders are thread-safe and only build when you pull the trigger, but assume immutable input, so don't pass in arrays or lists that you are still fiddling with.

All the classes are in com.tersesystems.securitybuilder package.

import com.tersesystems.securitybuilder.*;

In general, if you're just using the JCA, there are some based off Latacora's Cryptographic Right Answers:

  • Use RSA with 2048 bit key length and SHA-2 for public and private keys.
  • Use AES-GCM for encryption but SEE WARNING BELOW, and never reuse the IV. There is no provable difference between AES-128 and AES-256, so don't worry about it and use AES-256.
  • If you're going over the network, you generally want full on TLS, so use JSSE with debugjsse as the provider to see what's going on under the hood. Be aware that SSLEngine/SSLSocket does not know that you're using HTTPS, so you need to define hostname verification yourself by setting sslParameters.setEndpointIdentificationAlgorithm("HTTPS").
  • Use an HMAC with at least SHA256, and a secret key that has at least 96 bits of entropy -- EntropySource.salt() uses 256 bits.
  • Use a MessageDigest with at least SHA256.
  • Use PBKDF2 with a SHA-2 HMAC if you have to, but if you can use jBCrypt or scrypt go with that.
  • There's no real need to use your own SecureRandom, and you don't need to use useInstanceStrong, the entropy pool is the same and you may get blocking. Use EntropySource.

WARNING

Please be aware that some of the algorithms in the JCA are way, way out of date.

If you need a cryptography API, DON'T USE THE JCA! Even with these builders, building your own crypto using a low level library is like juggling chainsaws in the dark. In particular, low level libraries don't do key management and key rotation very well.

Use Google Tink instead, which has support for storing keysets, symmetric key encryption, digital signatures, envelope encryption and key rotation.

Google Tink doesn't do everything: in that case, I recommend looking for a fallback professional high-level library rather than rolling your own. This will typically involve an binding on top of a C library like lazysodium on top of libsodium, or a specialized crypto framework like Noise-Java implementing the Noise Protocol Framework.

JSSE (Java TLS Classes)

X509CertificateCreator

Creates an X509Certificate or a chain of X509Certificate.

Very useful for building up certificates if you use chain().

public class X509CertificateCreatorTest {
  @Test
  public void testFunctionalStyle() throws Exception {
    FinalStage<RSAKeyPair> keyPairCreator = KeyPairCreator.creator().withRSA().withKeySize(2048);
    RSAKeyPair rootKeyPair = keyPairCreator.create();
    RSAKeyPair intermediateKeyPair = keyPairCreator.create();
    RSAKeyPair eePair = keyPairCreator.create();

    IssuerStage<RSAPrivateKey> creator =
        X509CertificateCreator.creator().withSHA256withRSA().withDuration(Duration.ofDays(365));

    String issuer = "CN=letsencrypt.derp,O=Root CA";
    X509Certificate[] chain =
        creator
            .withRootCA(issuer, rootKeyPair, 2)
            .chain(
                rootKeyPair.getPrivate(),
                rootCreator ->
                    rootCreator
                        .withPublicKey(intermediateKeyPair.getPublic())
                        .withSubject("OU=intermediate CA")
                        .withCertificateAuthorityExtensions(0)
                        .chain(
                            intermediateKeyPair.getPrivate(),
                            intCreator ->
                                intCreator
                                    .withPublicKey(eePair.getPublic())
                                    .withSubject("CN=tersesystems.com")
                                    .withEndEntityExtensions()
                                    .chain()))
            .create();

    PrivateKeyStore privateKeyStore =
        PrivateKeyStore.create("tersesystems.com", eePair.getPrivate(), chain);
    TrustStore trustStore = TrustStore.create(singletonList(chain[2]), cert -> "letsencrypt.derp");

    try {
      final PKIXCertPathValidatorResult result = CertificateChainValidator.validator()
          .withAnchor(new TrustAnchor(issuer, rootKeyPair.getPublic(), null))
          .withCertificates(chain)
          .validate();
      final PublicKey subjectPublicKey = result.getPublicKey();
      assertThat(subjectPublicKey).isEqualTo(eePair.getPublic());
    } catch (final CertPathValidatorException cpve) {
      fail("Cannot test exception", cpve);
    }

    SSLContext sslContext =
        SSLContextBuilder.builder()
            .withTLS()
            .withKeyManager(
                KeyManagerBuilder.builder()
                    .withSunX509()
                    .withPrivateKeyStore(privateKeyStore)
                    .build())
            .withTrustManager(
                TrustManagerBuilder.builder()
                    .withDefaultAlgorithm()
                    .withTrustStore(trustStore)
                    .build())
            .build();
    assertThat(sslContext).isNotNull();
  }
}

Admittedly this doesn't look very simple, but you should see the code it replaces.

CertificateBuilder

Builds a java.security.Certificate from a source.

If you use withX509(), it will give you an X509Certificate.

public class CertificateBuilderTest {
  @Test
  public void testX509Certificate() {
    final InputStream inputStream = getClass().getResourceAsStream("/playframework.pem");
    try {
      final X509Certificate x509Certificate =
          CertificateBuilder.builder()
            .withX509()
            .withInputStream(inputStream)
            .build();
      assertThat(x509Certificate.getSigAlgName()).isEqualTo("SHA256withECDSA");
    } catch (final CertificateException e) {
      fail(e.getMessage(), e);
    }
  }
}

KeyManagerBuilder

Builds a KeyManager from input. If you use withNewSunX509(), then you get a X509ExtendedKeyManager that can differentiate between RSA / DSA keys, pick out unexpired keys, and use password specific entries out of the store (if you use the keystore builder defined below). See Key Managers and Key Stores for the gory details.

Recommend using with debugjsse provider.

public class KeyManagerBuilderTest {

  @Test
  public void testKeyManagerWithKeyStore() {
    try {
      final KeyStore keyStore = KeyStoreBuilder.empty();
      final X509ExtendedKeyManager keyManager =
          KeyManagerBuilder.builder()
              .withNewSunX509()
              .withKeyStore(keyStore, "".toCharArray())
              .build();
      assertThat(keyManager.getPrivateKey("derp")).isNull();
    } catch (final GeneralSecurityException e) {
      fail(e.getMessage(), e);
    }
  }
}

TrustManagerBuilder

Builds a TrustManager from input.

Recommend using with debugjsse provider.

public class TrustManagerBuilderTest {
  @Test
  void builderWithKeyStore() throws Exception {
    final KeyStore keyStore = KeyStoreBuilder.empty();
    final X509ExtendedTrustManager trustManager =
        TrustManagerBuilder.builder().withDefaultAlgorithm().withKeyStore(keyStore).build();
    assertThat(trustManager.getAcceptedIssuers()).isEmpty();
  }
}

SSLContextBuilder

Build a SSLContext.

You will typically want to combine this with TrustManagerBuilder and KeyManagerBuilder.

Recommend using with debugjsse provider.

public class SSLContextBuilderTest {

  @Test
  public void testSSLContextBuilderWithTLS() {
    try {
      final SSLContext sslContext = SSLContextBuilder.builder().withTLS().build();
      sslContext.createSSLEngine();
    } catch (final GeneralSecurityException e) {
      fail(e.getMessage(), e);
    }
  }

  @Test
  public void testSSLContextBuilderWithTLSAndKeyManager() {
    try {
      final X509ExtendedKeyManager km =
          KeyManagerBuilder.builder().withNewSunX509().withDefaultKeyStoreAndPassword().build();

      final SSLContext sslContext =
          SSLContextBuilder.builder().withTLS().withKeyManager(km).build();
      sslContext.createSSLEngine();
    } catch (final GeneralSecurityException e) {
      fail(e.getMessage(), e);
    }
  }
}

CertificateChainValidator

Validates a certificate chain using a PKIX CertPathValidator. See Java PKI Programmer's Guide for details, but you can safely ignore most if not all of it.

public class CertificateChainValidatorTest {
  public void testCertificate(Certificate[] chain, X509Certificate rootCertificate) {
    try {
      final PKIXCertPathValidatorResult result = CertificateChainValidator.validator()
          .withTrustedCertificates(rootCertificate)
          .withCertificates(chain)
          .validate();
      final PublicKey subjectPublicKey = result.getPublicKey();
      assertThat(subjectPublicKey).isEqualTo(eePair.getPublic());
    } catch (final CertPathValidatorException cpve) {
      fail("Cannot test exception", cpve);
    }
  }
}

KeyStores

Key stores are used for key management. The java.security.KeyStore has three wrappers, depending on purpose: PrivateKeyStore, TrustStore, and SecretKeyStore. They all extend AbstractKeyStore, and are written to be a drop in for java.util.Map. See blog post for gory details.

PrivateKeyStore

Sets up a private keystore that is set up the way that the default SunX509 keymanager expects -- that is, all the private keys have the same password. You work with PrivateKeyEntry and never have to provide the password as a parameter.

public class PrivateKeyStoreTest {
  
  @Test
  public void testAdd() {
    try {
      final char[] password = "".toCharArray();
      final KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
      keyStore.load(null);
      final PrivateKeyStore privateKeyStore = PrivateKeyStore.create(keyStore, password);
      final RSAKeyPair rsaKeyPair = KeyPairCreator.creator().withRSA().withKeySize(2048).build();

      final X509Certificate rsaCertificate =
          X509CertificateCreator.builder()
              .withSHA256withRSA()
              .withNotBeforeNow()
              .withDuration(Duration.ofDays(365))
              .withRootCA("CN=example.com", rsaKeyPair, 2)
              .build();
      final PrivateKeyEntry entry =
          new PrivateKeyEntry(rsaKeyPair.getPrivate(), new Certificate[] {rsaCertificate});
      privateKeyStore.put("alias1", entry);

      // PrivateKey doesn't override equals!
      assertThat(Arrays.equals(privateKeyStore.get("alias1").getPrivateKey().getEncoded(), (entry.getPrivateKey().getEncoded()))).isTrue();
    } catch (final Exception e) {
      fail(e.getMessage());
    }
  }
}

TrustStore

TrustStore is a wrapper around KeyStore for TrustedCertificateEntry.

public class TrustStoreTest {
  @Test
  void testSize() {
    try {
      final KeyStore keyStore = generateStore();
      final TrustStore trustStore = TrustStore.create(keyStore);

      final RSAKeyPair rsaKeyPair = KeyPairCreator.creator().withRSA().withKeySize(2048).build();
      final DSAKeyPair dsaKeyPair = KeyPairCreator.creator().withDSA().withKeySize(1024).build();

      final X509Certificate rsaCertificate =
          X509CertificateCreator.builder()
              .withSHA256withRSA()
              .withDuration(Duration.ofDays(365))
              .withRootCA("CN=example.com", rsaKeyPair, 2)
              .create();

      final X509Certificate dsaCertificate =
          X509CertificateCreator.builder()
              .withSignatureAlgorithm("SHA256withDSA")
              .withDuration(Duration.ofDays(365))
              .withRootCA("CN=example.com", dsaKeyPair.getKeyPair(), 2)
              .create();

      trustStore.put("rsaentry", new TrustedCertificateEntry(rsaCertificate));
      trustStore.put("dsaentry", new TrustedCertificateEntry(dsaCertificate));

      assertThat(trustStore.size()).isEqualTo(2);
    } catch (final Exception e) {
      fail(e.getMessage());
    }
  }
}

SecretKeyStore

A KeyStore that contains only SecretKeyEntry.

Use this with a KeyStore format of type PKCS12.

public class SecretKeyStoreTest {
  @Test
  void testSize() {
    try {
      String password = "hello world".toCharArray();
      byte[] salt = EntropySource.salt();

      final Map<String, ProtectionParameter> passwordMap =
          Collections.singletonMap("username", new PasswordProtection(password));
      final SecretKeyStore secretKeyStore = generateSecretKeyStore(passwordMap);
  
      PBEKey secretKey = PasswordBuilder.builder()
        .withPBKDF2WithHmacSHA512()
        .withPassword(password)
        .withIterations(10000)
        .withSalt(salt)
        .withKeyLength(64 * 8)
        .build();
    
      secretKeyStore.put("username", new SecretKeyEntry(secretKey));
      assertThat(secretKeyStore.size()).isEqualTo(1);
    } catch (final KeyStoreException
        | IOException
        | NoSuchAlgorithmException
        | CertificateException
        | InvalidKeySpecException e) {
      fail(e);
    }
  }
}

KeyStoreBuilder

Builds a KeyStore.

public class KeyStoreBuilderTest {

  @Test
  public void testKeyStoreBuilderWithPathAndNoPassword() {
    try {
      final Path tempPath = Files.createTempFile(null, null);
      final KeyStore keyStore = KeyStoreBuilder.empty();
      try (OutputStream outputStream = Files.newOutputStream(tempPath)) {
        keyStore.store(outputStream, "".toCharArray());
      }

      final KeyStore keyStoreFromPath =
          KeyStoreBuilder.builder().withDefaultType().withPath(tempPath).withNoPassword().build();
      assertThat(keyStoreFromPath.getType()).isEqualTo(KeyStore.getDefaultType());
    } catch (final Exception e) {
      fail(e.getMessage(), e);
    }
  }
}

KeyStoreDefaults

Allows access to the default KeyStore used for CA certificates and for the private key store location.

KeyManagerKeyStoreBuilder

Builds a KeyStore.Builder, using a keystore builder that is able to send different passwords to the "NewSunX509" keymanager.

The out of the box KeyStore.Builder API does not do this! See blog post for details.

public class DifferentPasswordsTest {

  @Test
  public void testWithBuilder() throws GeneralSecurityException, IOException {
    final char[] password1 = "password1".toCharArray();
    final char[] password2 = "password2".toCharArray();
    final Map<String, ProtectionParameter> passwordsMap = new HashMap<>();
    passwordsMap.put("rsaentry", new PasswordProtection(password1));
    passwordsMap.put("dsaentry", new PasswordProtection(password2));

    final KeyStore keyStore = generateStore();
    final KeyStore.Builder builder =
        KeyManagerKeyStoreBuilder.newInstance(keyStore, passwordsMap::get);

    final KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
    kmf.init(new KeyStoreBuilderParameters(builder));
    final X509ExtendedKeyManager keyManager = (X509ExtendedKeyManager) kmf.getKeyManagers()[0];

    final String rsaAlias = keyManager.chooseServerAlias("RSA", null, null);
    assertThat(rsaAlias).contains("rsaentry");
    final PrivateKey rsaPrivateKey = keyManager.getPrivateKey(rsaAlias);
    assertThat(rsaPrivateKey).isNotNull(); // can get password

    final String dsaAlias = keyManager.chooseServerAlias("DSA", null, null);
    assertThat(dsaAlias).contains("dsaentry");
    final PrivateKey dsaPrivateKey = keyManager.getPrivateKey(dsaAlias);
    assertThat(dsaPrivateKey).isNotNull(); // can get password
  }
}

Key Builders and Creators

KeyPairCreator

Creates a new KeyPair containing PublicKey and PrivateKey using a KeyPairGenerator.

If you use withRSA, withDSA or withEC then you get back RSAKeyPair etc.

class KeyPairCreatorTest {
  @Test
  void testWithAlgorithm() throws GeneralSecurityException {
    final KeyPair keyPair = KeyPairCreator.creator().withAlgorithm("RSA").withKeySize(2048).create();
    Assertions.assertThat(keyPair.getPublic().getAlgorithm()).isEqualTo("RSA");
  }

  @Test
  void testWithRSA() throws GeneralSecurityException {
    final RSAKeyPair keyPair = KeyPairCreator.creator().withRSA().withKeySize(2048).create();
    Assertions.assertThat(keyPair.getPublic().getAlgorithm()).isEqualTo("RSA");
  }

  @Test
  void testWithDSA() throws GeneralSecurityException {
    final DSAKeyPair keyPair = KeyPairCreator.creator().withDSA().withKeySize(1024).create();
    Assertions.assertThat(keyPair.getPublic().getAlgorithm()).isEqualTo("DSA");
  }

  @Test
  void testWithDH() throws GeneralSecurityException {
    final DHKeyPair keyPair = KeyPairCreator.creator().withDH().withKeySize(1024).create();
    Assertions.assertThat(keyPair.getPublic().getAlgorithm()).isEqualTo("DH");
  }

  @Test
  void testWithEC() throws GeneralSecurityException {
    final ECKeyPair keyPair = KeyPairCreator.creator().withEC().withKeySize(224).create();
    Assertions.assertThat(keyPair.getPublic().getAlgorithm()).isEqualTo("EC");
  }
}

EncodedKeySpecBuilder

Builds a EncodedKeySpec from existing source material.

You can use either PKCS8EncodedKeySpec, commonly used for PEM encoded private keys, or X509EncodedKeySpec, used for PEM encoded X.509 certificates.

class PKCS8EncodedKeySpecBuilderTest {
  @Test
  public void testGeneration() throws Exception {
    // Read a private key
    final Reader reader = new InputStreamReader(getClass().getResourceAsStream("/private-key.pem"));
    final PKCS8EncodedKeySpec keySpec =
        PKCS8EncodedKeySpecBuilder.builder().withReader(reader).withNoPassword().build();
    assertThat(keySpec.getFormat()).isEqualTo("PKCS#8");
  }
}

PublicKeyBuilder

Builds a PublicKey.

Will provide public key of the appropriate type using withRSA, withDSA, or withEC methods.

public class PublicKeyBuilderTest {

  @Test
  public void testRSAPublicKey() throws GeneralSecurityException {
    final BigInteger modulus =
        new BigInteger(
            "b4a7e46170574f16a97082b22be58b6a2a629798419"
                + "be12872a4bdba626cfae9900f76abfb12139dce5de5"
                + "6564fab2b6543165a040c606887420e33d91ed7ed7",
            16);
    final BigInteger exp = new BigInteger("11", 16);
    final RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(modulus, exp);
    RSAPublicKey rsaPublicKey =
        PublicKeyBuilder.builder().withRSA().withKeySpec(rsaPublicKeySpec).build();
    assertThat(rsaPublicKey).isNotNull();
  }
}

PrivateKeyBuilder

Builds a PrivateKey.

Will provide private key of the appropriate type using withRSA, withDSA, or withEC methods.

class PrivateKeyBuilderTest {

  @Test
  void builderWithRSA() throws GeneralSecurityException {
    final RSAPrivateKey exampleKey =
        (RSAPrivateKey)
            KeyPairCreator.creator().withAlgorithm("RSA").withKeySize(2048).build().getPrivate();
    final RSAPrivateKeySpec rsaPrivateKeySpec =
        new RSAPrivateKeySpec(exampleKey.getModulus(), exampleKey.getPrivateExponent());
    final RSAPrivateKey privateKey =
        PrivateKeyBuilder.builder().withRSA().withKeySpec(rsaPrivateKeySpec).build();

    assertThat(privateKey).isNotNull();
  }
}

SecretKeyBuilder

Builds a SecretKey.

The algorithms are in The SunJCE Provider.

public class SecretKeyBuilderTest {
  @Test
  public void testSecretKeySpec() throws Exception {
    byte[] aesKeyData = "abc123".getBytes();

    SecretKey secretKey = SecretKeyBuilder.builder()
        .withSecretKeySpec("AES")
        .withData(aesKeyData)
        .build();

    assertThat(secretKey.getAlgorithm()).isEqualTo("AES");
  }
}

MACs, Signatures, Passwords

MacBuilder

Builds an Message Authentication Code based on cryptographic hashing, aka Mac.

public class MacBuilderTest {
  @Test
  void testMacBuild() throws GeneralSecurityException {
    SecretKey key = new SecretKeySpec("privatekey".getBytes(), "HmacSHA256");

    Mac sha256Mac = MacBuilder.builder().withAlgorithm("HmacSHA256").withKey(key).build();
    String output = byteArrayToHex(sha256Mac.doFinal("test".getBytes()));

    assertThat(sha256Mac.getAlgorithm()).isEqualTo("HmacSHA256");
    assertThat(output).isEqualTo("27f0d5331806fb9f21247b19bee883a7cfe54c069d6e28edccc2cff8e78c4a74");
  }

  @Test
  void testSecretKeySpec() throws GeneralSecurityException {
    Mac sha256Mac = MacBuilder.builder().withSecretKeySpec("HmacSHA256").withString("privatekey").build();
    String output = byteArrayToHex(sha256Mac.doFinal("test".getBytes()));

    assertThat(sha256Mac.getAlgorithm()).isEqualTo("HmacSHA256");
    assertThat(output).isEqualTo("27f0d5331806fb9f21247b19bee883a7cfe54c069d6e28edccc2cff8e78c4a74");
  }

  @Test
  void testHmac() throws GeneralSecurityException {
    Mac sha256Mac = MacBuilder.builder().withHmacSHA256().withString("privatekey").build();
    String output = byteArrayToHex(sha256Mac.doFinal("test".getBytes()));

    assertThat(sha256Mac.getAlgorithm()).isEqualTo("HmacSHA256");
    assertThat(output).isEqualTo("27f0d5331806fb9f21247b19bee883a7cfe54c069d6e28edccc2cff8e78c4a74");
  }
}

MessageDigestBuilder

Builds a MessageDigest.

These are intentionally curtailed so you don't pick out weak MessageDigest algorithms.

public class MessageDigestBuilderTest {
  @Test
  public void testSha512() throws NoSuchAlgorithmException {
    assertThat(MessageDigestBuilder.sha512().getAlgorithm()).isEqualTo("SHA-512");
  }
}

SignatureBuilder

Builds a Signature. for either signing or verifying.

public class SignatureBuilderTest {

  @Test
  public void testSignature() {
    try {
      final KeyPair<?, ?> keyPair =
          KeyPairCreator.creator().withAlgorithm("RSA").withKeySize(2048).build();
      final PrivateKey privateKey = keyPair.getPrivate();
      final PublicKey publicKey = keyPair.getPublic();

      final Signature signingSignature =
          SignatureBuilder.builder().withAlgorithm("SHA256withRSA").signing(privateKey).build();
      final byte[] digest = signingSignature.sign();

      final Signature verifySignature =
          SignatureBuilder.builder().withAlgorithm("SHA256withRSA").verifying(publicKey).build();
      assertThat(verifySignature.verify(digest)).isEqualTo(true);
    } catch (final Exception e) {
      Fail.fail(e.getMessage(), e);
    }
  }
}

EntropySource

Pulls from SecureRandom /dev/urandom, using the recommended number of random bits. See blog post for details.

public class EntropySource {
  /**
   * Provides an initialization vector for GCM.
   */
  public static byte[] gcmIV() {
    return nextBytes(DEFAULT_GCM_IV_LENGTH);
  }

  /**
   * Provides a salt, which must be unique but is not private.
   */
  public static byte[] salt() {
    return nextBytes(DEFAULT_SALT_LENGTH);
  }
}

Odds and Ends

Finally, there's some code which is useful in a pinch but which doesn't really go anywhere else.

AuthenticatedEncryptionBuilder

Makes generating an AES-GCM cipher a bit easier. You always want to use an authenticated encryption mode.

Again, you're better off using Google Tink's symmetric encryption if you're doing encryption -- and if you're going over the network, you generally want full on TLS. See the usage and warnings up top.

public class AuthenticatedEncryptionBuilderTest {
  @Test
  public void testCipher() throws GeneralSecurityException {
    final SecretKey aesSecretKey = SecretKeyGenerator.generate().withAES().withKeySize(128).build();
    final SecretKeySpec secretKeySpec = new SecretKeySpec(aesSecretKey.getEncoded(), aesSecretKey.getAlgorithm());
    final IvStage builder = AuthenticatedEncryptionBuilder.builder().withSecretKey(secretKeySpec);

    byte[] gcmIV = EntropySource.gcmIV();
    byte[] inputData = "input text".getBytes(UTF_8);

    byte[] encryptedData = builder.withIv(gcmIV).encrypt().doFinal(inputData);
    byte[] decryptedData = builder.withIv(gcmIV).decrypt().doFinal(encryptedData);

    String decryptString = new String(decryptedData, UTF_8);
    assertThat(decryptString).isEqualTo("input text");
  }
}

PasswordBuilder

A specialized secret key builder for encrypting passwords.

Use PBKDF2 with a SHA-2 HMAC if you have to, but if you can use jBCrypt or scrypt, go with that.

public class PasswordBuilderTest {

  @Test
  public void testPasswordSpec() throws Exception {
    byte[] salt = EntropySource.salt();

    PBEKey passwordBasedEncryptionKey = PasswordBuilder.builder()
        .withPBKDF2WithHmacSHA512()
        .withPassword("hello world".toCharArray())
        .withIterations(1000)
        .withSalt(salt)
        .withKeyLength(64 * 8)
        .build();

    byte[] encryptedPassword = passwordBasedEncryptionKey.getEncoded();
    assertThat(passwordBasedEncryptionKey.getAlgorithm()).isEqualTo("PBKDF2WithHmacSHA512");
  }
}

KeyAgreementBuilder

Creates a KeyAgreement instance.

This is typically used with Diffie-Hellman, most commonly found in SSH. Use jsch if you want SSH, otherwise you're better off using a high level crypto library like those described in the WARNING section up top.

The canonical DH key exchange:

public class KeyAgreementBuilderTest {
  @Test
  public void testKeyAgreementParams() throws GeneralSecurityException, IOException {
    // Alice creates her own DH key pair with 2048-bit key size
    DHKeyPair aliceKpair = KeyPairCreator.creator().withDH().withKeySize(2048).create();

    // Alice creates and initializes her DH KeyAgreement object
    KeyAgreement aliceKeyAgree = KeyAgreementBuilder.builder()
        .withDH()
        .withKey(aliceKpair.getPrivate())
        .build();

    // Alice encodes her public key, and sends it over to Bob.
    byte[] alicePubKeyEnc = aliceKpair.getPublic().getEncoded();

    //* Let's turn over to Bob. Bob has received Alice's public key
    //* in encoded format.
    //* He instantiates a DH public key from the encoded key material.
    DHPublicKey alicePubKey = PublicKeyBuilder.builder().withDH()
        .withKeySpec(new X509EncodedKeySpec(alicePubKeyEnc)).build();

    //* Bob gets the DH parameters associated with Alice's public key.
    //* He must use the same parameters when he generates his own key
    //* pair.
    DHParameterSpec dhParamFromAlicePubKey = alicePubKey.getParams();

    // Bob creates his own DH key pair
    DHKeyPair bobKpair = KeyPairCreator.creator().withDH().withKeySpec(dhParamFromAlicePubKey)
        .create();

    // Bob creates and initializes his DH KeyAgreement object
    KeyAgreement bobKeyAgree = KeyAgreementBuilder.builder().withDH().withKey(bobKpair.getPrivate())
        .build();

    // Bob encodes his public key, and sends it over to Alice.
    byte[] bobPubKeyEnc = bobKpair.getPublic().getEncoded();

    //* Alice uses Bob's public key for the first (and only) phase
    //* of her version of the DH protocol.
    //* Before she can do so, she has to instantiate a DH public key
    //* from Bob's encoded key material.
    DHPublicKey bobPubKey = PublicKeyBuilder.builder().withDH()
        .withKeySpec(new X509EncodedKeySpec(bobPubKeyEnc)).build();
    aliceKeyAgree.doPhase(bobPubKey, true);

    //* Bob uses Alice's public key for the first (and only) phase
    //* of his version of the DH protocol.
    bobKeyAgree.doPhase(alicePubKey, true);

    // At this stage, both Alice and Bob have completed the DH key
    // agreement protocol. Both generate the (same) shared secret.
    byte[] aliceSharedSecret = aliceKeyAgree.generateSecret();
    byte[] bobSharedSecret = new byte[aliceSharedSecret.length];
    bobKeyAgree.generateSecret(bobSharedSecret, 0);
    assertThat(Arrays.equals(aliceSharedSecret, bobSharedSecret)).isTrue();

    // Now let's create a SecretKey object using the shared secret
    // and use it for encryption.
    SecretKeySpec bobAesKey = new SecretKeySpec(bobSharedSecret, 0, 16, "AES");
    SecretKeySpec aliceAesKey = new SecretKeySpec(aliceSharedSecret, 0, 16, "AES");

    // Bob encrypts, using AES in GCM mode
    final byte[] iv = EntropySource.gcmIV();
    Cipher bobCipher = AuthenticatedEncryptionBuilder.builder().withSecretKey(bobAesKey).withIv(iv)
        .encrypt();
    byte[] cleartext = "This is just an example".getBytes();
    byte[] ciphertext = bobCipher.doFinal(cleartext);

    // Alice decrypts, using AES in GCM mode
    Cipher aliceCipher = AuthenticatedEncryptionBuilder.builder().withSecretKey(aliceAesKey).withIv(iv).decrypt();
    byte[] recovered = aliceCipher.doFinal(ciphertext);
    assertThat(Arrays.equals(cleartext, recovered)).isTrue();
  }
}
You might also like...

Eclipse Collections is a collections framework for Java with optimized data structures and a rich, functional and fluent API.

Eclipse Collections is a collections framework for Java with optimized data structures and a rich, functional and fluent API.

English | 中文 | Deutsch | Español | Ελληνικά | Français | 日本語 | Norsk (bokmål) | Português-Brasil | Русский | हिंदी Eclipse Collections is a comprehens

Jan 5, 2023

Eclipse Collections is a collections framework for Java with optimized data structures and a rich, functional and fluent API.

Eclipse Collections is a collections framework for Java with optimized data structures and a rich, functional and fluent API.

English | 中文 | Deutsch | Español | Ελληνικά | Français | 日本語 | Norsk (bokmål) | Português-Brasil | Русский | हिंदी Eclipse Collections is a comprehens

Dec 29, 2022

dOOv (Domain Object Oriented Validation) a fluent API for type-safe bean validation and mapping

dOOv (Domain Object Oriented Validation) dOOv is a fluent API for typesafe domain model validation and mapping. It uses annotations, code generation a

Nov 20, 2022

Standalone Play WS, an async HTTP client with fluent API

Play WS Standalone Play WS is a powerful HTTP Client library, originally developed by the Play team for use with Play Framework. It uses AsyncHttpClie

Dec 15, 2022

JSON Web Token implementation for Java according to RFC 7519. Easily create, parse and validate JSON Web Tokens using a fluent API.

JWT-Java JSON Web Token library for Java according to RFC 7519. Table of Contents What are JSON Web Tokens? Header Payload Signature Features Supporte

Jul 10, 2022

"I am fluent in over 6 million forms of communication!"

K3PO K3PO is a network driver and language agnostic testing tool. It is designed to be able to create arbitrary network traffic and behavior, and to c

Dec 1, 2022

Fluent assertions for Java and Android

What is Truth? Truth makes your test assertions and failure messages more readable. Similar to AssertJ, it natively supports many JDK and Guava types,

Jan 5, 2023

Fluent assertions library for Java

Deep Dive Assertions Deep Dive is an assertion library for Java. It offers a fluent API which allows you to dive deep, i.e. going back and forth betwe

Jan 24, 2022

Examples and server integrations for generating the Swagger API Specification, which enables easy access to your REST API

Examples and server integrations for generating the Swagger API Specification, which enables easy access to your REST API

Swagger Core NOTE: If you're looking for Swagger Core 1.5.X and OpenAPI 2.0, please refer to 1.5 branch. NOTE: Since version 2.1.7 Swagger Core suppor

Jan 5, 2023

A Java API wrapper for the pastemyst api

Pastemyst.java What is pastemyst.java? pastemyst.java is a pastemyst API Wrapper, written in Java. The library is in early development, and all contri

Sep 28, 2022

Telegram API Client and Telegram BOT API Library and Framework in Pure java.

Javagram Telegram API Client and Telegram Bot API library and framework in pure Java. Hello Telegram You can use Javagram for both Telegram API Client

Oct 17, 2021

Dio-api-1 - Repositório com os artefatos da mentoria de API

dio-api-1 Repositório com os artefatos da mentoria de API Reference Documentation For further reference, please consider the following sections: Offic

Feb 25, 2022

Produtos-api-client - Biblioteca de consumo de uma API Rest básica de produtos disponibilizada em outro repositório.

produtos-api-client Biblioteca de consumo de uma API Rest básica de produtos disponibilizada no repositório: clique aqui para acessar Com essa bibliot

Jan 4, 2022

COMMA Config API is an API allowing you to easily create complex and stylish config menu screens for Minecraft Fabric mods

COMMA Config API is an API allowing you to easily create complex and stylish config menu screens for Minecraft Fabric mods. COMMA stands for Configurable Options Menu Modding API

Jan 13, 2022

An API wrapper for BotiCord API written in Java

An API wrapper for BotiCord API written in Java

An API wrapper for BotiCord API written in Java

Nov 8, 2022

API Gestor é uma API que permite a comunicação com um Banco de Dados educacionais sobre a educação brasileira.

API Gestor O projeto API Gestor é uma API que permite a comunicação de outras aplicações com os dados educacionais armazenados em um banco de dados, c

Apr 13, 2022

Jakarta money is a helpful library for a better developer experience when combining Money-API with Jakarta and MicroProfile API.

jakarta-money Jakarta money is a helpful library for a better developer experience when combining Money-API with Jakarta and MicroProfile API. The dep

Aug 12, 2022
Comments
  • SecretKeyGenerator

    SecretKeyGenerator

    https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html#KeyGenerator

    
        public void init(SecureRandom random);
    
        public void init(int keysize);
    
        public void init(int keysize, SecureRandom random);
    
    opened by wsargent 0
Releases(1.0.1)
Owner
Terse Systems
Terse Systems
Amazon Selling Partner JAVA SDK SP API

amazon-sp-api amazon sp api java sdk 背景: 亚马逊(amazon)在2020年10月推出了新的替代mws的api方案,称为Selling Partner API(SP-API)。sp-api在修改原mws的接口方式的基础上引入了aws的IAM权限管理,增加了开发

penghp 93 Nov 20, 2022
A library for bypassing all of Java's security mechanisms, visibility checks, and encapsulation measures via the JNI API

Narcissus: thwart strong encapsulation in JDK 16+ Narcissus is a JNI native code library that provides a small subset of the Java reflection API, whil

ToolFactory 29 Nov 3, 2022
Toloka has a powerful open API, it allows you to integrate an on-demand workforce directly into your processes, and to build scalable and fully automated human-in-the-loop ML pipelines.

Toloka Java SDK Documentation Website | API Documentation | Platform Designed by engineers for engineers, Toloka lets you integrate an on-demand workf

Toloka 10 Apr 27, 2022
Library to easily configure API Key authentication in (parts of) your Spring Boot Application

42 API Key Authentication A library to easily configure API Key authentication in (parts of) your Spring Boot Application. Features Easily configure A

null 2 Dec 8, 2021
A Twitter-API library JAVA

Tweety A Twitter-API library for JAVA. Code for Authorization (Oauth 1) can be found here :Authorization This api conta

Rohit Kumar 2 Apr 26, 2022
Simple API for using Java Reflection

Reflector По поводу багов или идей для данного репозитория можно писать в Discord или ВК(обратная связь) Обратная связь Discord: UnLegit#6190 ВКонтакт

null 1 Jan 25, 2022
Annotation processor to create immutable objects and builders. Feels like Guava's immutable collections but for regular value objects. JSON, Jackson, Gson, JAX-RS integrations included

Read full documentation at http://immutables.org // Define abstract value type using interface, abstract class or annotation @Value.Immutable public i

Immutables 3.2k Dec 31, 2022
Nano-library which provides the ability to define typesafe (!) configuration templates for applications.

Configur8 Nano-library which provides the ability to define typesafe (!) Configuration templates for applications. Concept: A Configuration is a set o

David Denton 11 Oct 3, 2022
dOOv (Domain Object Oriented Validation) a fluent API for type-safe bean validation and mapping

dOOv (Domain Object Oriented Validation) dOOv is a fluent API for typesafe domain model validation and mapping. It uses annotations, code generation a

dOOv 77 Nov 20, 2022