Q&A: How to generate and protect keys in Java Card?

Cryptographic keys are often at the heart of Java Card applications, which often rely on cryptography to protect their data in storage and/or communication. Keys therefore become the most sensitive pieces of data in such applications. All evaluators know that, as getting the values of secret/private keys is the ultimate goal of a security evaluation.

Let’s start by secret keys, used in symmetric algorithms like AES and DES. Such keys are just random values of a given length, without any strong mathematical property((Keys must verify some properties, though, as some values will not provide an adequate protection; however, the probability to get one of these keys is quite low, and no test is usually performed on the keys that are generated on a smart card.

A secret key therefore starts its life as a byte array filled with random data. For a triple DES key, we need 16 bytes of data. Two origins are possible for this data: it may be imported from the outside through a personalization command, or it may be generated on the card using a random number generator. Here is an example using a RNG:

  byte[] keyBytes = JCSystem.getTransientByteArray(COD,16);
  RandomData rng = RandomData.getInstance(ALG_SECURE_RANDOM);

  rng.generateData(keyBytes,0,16);

The next step consists in creating the key object and assigning the random data to the key object:

  DESKey key = KeyBuilder.buildKey(ALG_DES, LENGTH_3DES_2KEY);
  key.setKey(keyBytes);

When that is done, the essential is done. At this point, applet developers are not responsible any more for the protection of the key. The Java Card platform is in charge of implementing the key container classes in a way that protects keys from disclosure at all times (when they are stored and when they are used). In most cases, this means that the key values will be encrypted using another key, managed by the platform.

Applet developers should refrain from any attempt to protect cryptographic keys when they are stored in Key objects. However, the values of keys still need to be protected, whenever they are not stored in the proper containers. For instance, the raw data used to initialize the key should be cleared after the initialization. The initialization code therefore is as follows:

  try {
    rng.generateData(keyBytes,0,16);
    key.setKey(keyBytes);
  } finally {
    Util.arrayFillNonAtomic(keyBytes,0);
  }

With private keys (used in assymetric algorithms like RSA), things are even simpler, since there is a dedicated class to generate key pairs (a public key and a private key). This means that the actual key values are kept during the entire process under the protection of the platform.

Basically, the two rules about keys are:

  • Keys stored in Key container are protected by the platform, and only by the platform.
  • Plaintext key values should not be stored in byte arrays, expect for very short periods of time when absolutely needed, and the values should be cleared when then are not used any more.

Following them is a good start in the proper protection of cryptographic keys.

One Comment

Leave a Reply

Your email is never shared.Required fields are marked *