How to determine appropriate key sizes.

Issue #177 duplicate
corey created an issue

I'm very naive when it comes to crypto so much of the terminology is over my head but I'm trying to follow the "JWE with Shared Key" example (http://connect2id.com/products/nimbus-jose-jwt/examples/jwe-with-shared-key) and am testing the other available EncryptionMethod(s) to see what works with JDK7+Unlimited Security.

In my testing I'm getting some failures with the error "Couldn't create AES/GCM/NoPadding cipher: Illegal key size". I was using the EncryptionMethod.cekBitLength() to determine the correct key length. This works for some of the EncryptionMethods but not others.

For example:

Attempting to use: A192CBC-HS384
Key: 384 bits, 48 bytes.
Failed to encrypt using A192CBC-HS384
com.nimbusds.jose.JOSEException: Illegal key size
    at com.nimbusds.jose.crypto.AESCBC.createAESCBCCipher(AESCBC.java:101)
    at com.nimbusds.jose.crypto.AESCBC.encrypt(AESCBC.java:128)
    at com.nimbusds.jose.crypto.AESCBC.encryptAuthenticated(AESCBC.java:176)
    at com.nimbusds.jose.crypto.ContentCryptoProvider.encrypt(ContentCryptoProvider.java:158)
    at com.nimbusds.jose.crypto.DirectEncrypter.encrypt(DirectEncrypter.java:118)
    at com.nimbusds.jose.JWEObject.encrypt(JWEObject.java:353)
    at com.katalystdm.encweb.Encryptor.encrypt(Encryptor.java:75)
    at com.katalystdm.encweb.Encryptor.main(Encryptor.java:95)
Caused by: java.security.InvalidKeyException: Illegal key size
    at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1034)
    at javax.crypto.Cipher.implInit(Cipher.java:800)
    at javax.crypto.Cipher.chooseProvider(Cipher.java:859)
    at javax.crypto.Cipher.init(Cipher.java:1370)
    at javax.crypto.Cipher.init(Cipher.java:1301)
    at com.nimbusds.jose.crypto.AESCBC.createAESCBCCipher(AESCBC.java:92)
    ... 7 more

How do I programmatically determine the appropriate length for the input key for a particular algorithm?

Here's the code I'm using to test:

import static java.lang.System.err;
import static java.lang.System.out;

import java.security.Provider;
import java.security.SecureRandom;
import java.security.Security;
import java.util.List;

import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.nimbusds.jose.EncryptionMethod;
import com.nimbusds.jose.JWEAlgorithm;
import com.nimbusds.jose.JWEHeader;
import com.nimbusds.jose.JWEObject;
import com.nimbusds.jose.Payload;
import com.nimbusds.jose.crypto.DirectEncrypter;
import com.nimbusds.jose.crypto.bc.BouncyCastleProviderSingleton;

public class Encryptor {

  private byte[] key(int length) {
    byte[] keymaterial = new byte[length/8];
    new SecureRandom().nextBytes(keymaterial);
    out.printf("Key: %d bits, %d bytes.\n", length, keymaterial.length);
    return keymaterial;
  }

  public String encrypt(final String input) {
    // initialize bouncy castle as well...
    Provider bc = BouncyCastleProviderSingleton.getInstance();
    Security.addProvider(bc);

    List<EncryptionMethod> methodsToTry = Lists.newArrayList(
        EncryptionMethod.A128CBC_HS256,
        EncryptionMethod.A128GCM,
        EncryptionMethod.A192CBC_HS384,
        EncryptionMethod.A192GCM,
        EncryptionMethod.A256CBC_HS512,
        EncryptionMethod.A256GCM
    );

    out.printf("Security providers: %s\n", Joiner.on(',').join(Security.getProviders()));

    String encryptedOutput = null;
    for (EncryptionMethod em : methodsToTry) {
      try {
        out.println("Attempting to use: " + em);

        // Set the plain text
        Payload payload = new Payload(input);

        // Create the header
        JWEHeader header = new JWEHeader(JWEAlgorithm.DIR, em);

        // Create the JWE object and encrypt it
        JWEObject jweObject = new JWEObject(header, payload);

        // This doesn't appear to give the correct result!?
        byte[] key = key(em.cekBitLength());
        jweObject.encrypt(new DirectEncrypter(key));

        // Serialise to compact JOSE form...
        encryptedOutput = jweObject.serialize();

        out.printf("Successfully encrypted using %s giving: %s\n", em, encryptedOutput);
      }
      catch (Exception e) {
        err.printf("Failed to encrypt using %s.\n", em);
        e.printStackTrace(err);
      }

    }
    return encryptedOutput;
  }

  public static void main(String[] args) {
    new Encryptor().encrypt("Hello World!");
  }
}

Comments (3)

  1. Log in to comment