RSA keys and operations

Keys

The hardware JCE implementation (IBMJCECCA) extends the RSA keys that are available in the software JCE implementation. In the software JCE implementation, the actual RSA key material is stored in the key object. The IBMJCECCA implementation extends this by adding the following alternative representations:

  • An RSA key pair that was previously stored in the CCA key storage area. The key objects contain the CCA key storage area label for the keys.

    The following example illustrates creating RSA key objects for a key pair that is already stored in the CCA key storage area with the label "MYRSA.KEYPAIR", then deleting the CCA key storage area entry.
    // create key objects for an existing CCA key storage area entry
    // (No checking is done to verify that the entry exists.)
    //
    KeyFactory rsaKeyFactory = KeyFactory.getInstance("RSA", "IBMJCECCA");
    
    KeyLabelKeySpec spec = new KeyLabelKeySpec("MYRSA.KEYPAIR");
    PublicKey pubKey = rsaKeyFactory.generatePublic(spec);
    PrivateKey privKey = rsaKeyFactory.generatePrivate(spec);
    
    // delete the entry from the CCA key storage area
    // (An exception is thrown if the CCA key storage area entry does not exist.)
    //
    ((RSAPrivateHWKey)privKey).deletePKDSEntry();
    
    //
    // Note that, in this example, the Java key objects still
    // exist, but the CCA key storage area entry they represent has been deleted.
    // Any attempt to use the objects "pubKey" or "privKey" will 
    // cause an exception containing a hardware return code and 
    // reason code.
    //
  • An RSA key pair that is generated by an IBMJCECCA call to the underlying hardware, then stored in the CCA key storage area. The key objects contain the CCA key storage area label for the keys.

    The following example illustrates generating an RSA key pair that is stored in the CCA key storage area with an automatically generated label and creating key objects that contains the label for the CCA key storage area entry.
    // create a new CCA key storage area entry and key objects to represent it. 
    //
    AlgorithmParameterSpec spec = new RSAKeyParameterSpec(1024, 
                                                          KeyHWAttributeValues.PKDS, 
                                                          KeyHWAttributeValues.KEYMANAGEMENT);
    KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "IBMJCECCA");
    generator.initialize(spec);
    
    KeyPair keyPair = generator.generateKeyPair();
    PublicKey pubKey = keyPair.getPublic();
    PrivateKey privKey = keyPair.getPrivate();
    
    // delete the entry from the CCA key storage area
    // (An exception is thrown if the CCA key storage area entry does not exist.)
    //
    ((RSAPrivateHWKey)privKey).deletePKDSEntry();
    
    //
    // Note that, in this example, the Java key objects still
    // exist, but the CCA key storage area entry they represent has been deleted.
    // Any attempt to use the objects "pubKey" or "privKey" will 
    // cause an exception containing a hardware return code and 
    // reason code.
    //
    The following example illustrates generating an RSA key pair that is stored in the CCA key storage area with the label "ANRSA.KEYPAIR" and creating key objects that contain the label for the CCA key storage area entry.
    // create a new CCA key storage area entry and key objects to represent it
    //
    AlgorithmParameterSpec spec = new RSAKeyParameterSpec(1024, 
                                                          KeyHWAttributeValues.PKDS, 
                                                          KeyHWAttributeValues.KEYMANAGEMENT,
                                                          "ANRSA.KEYPAIR");
    
    KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "IBMJCECCA");
    generator.initialize(spec);
    
    KeyPair keyPair = generator.generateKeyPair();
    PublicKey pubKey = keyPair.getPublic();
    PrivateKey privKey = keyPair.getPrivate();
    
    // delete the entry from the CCA key storage area
    // (An exception is thrown if the CCA key storage area entry does not exist.)
    //
    ((RSAPrivateHWKey)privKey).deletePKDSEntry();
    
    //
    // Note that, in this example, the Java key objects still
    // exist, but the CCA key storage area entry they represent has been deleted.
    // Any attempt to use the objects "pubKey" or "privKey" will 
    // cause an exception containing a hardware return code and 
    // reason code.
    //

Operations

Both RSA encryption and decryption are available in the IBMJCECCA provider by using hardware cryptography. Because the RSA algorithm is quite compute intensive, using hardware cryptography provides significant performance improvements over software cryptography. Using hardware to perform the RSA encryption and decryption also allows use of the more secure method of storing key pairs in CCA key storage. With a key pair that is stored in the CCA key storage, the sensitive private key is never made available in the clear.

In software implementations of JCE providers (such as OpenJCEPlus), RSA encryption and decryption are implemented with PKCS 1 type 2 padding. RSA encryption and decryption with PKCS 1 type 2 padding is also implemented in hardware cryptography and is available with the IBMJCECCA provider.

However, there are two restrictions that are imposed by the hardware:

  • The type of key pair that is needed. The hardware implementation of RSA requires that the keys that are used to encrypt and decrypt data are generated to have a key usage of KEYMANAGEMENT. This restriction means that when the RSA key pair is generated, the key usage must be set to KEYMANAGEMENT.
  • The maximum length of the data that can be encrypted or decrypted. The hardware implementation of RSA limits the amount of data to be encrypted or decrypted to either 245 bytes or 11 bytes smaller than the modulus size of the key (in bytes), whichever is smaller.

The IBMJCECCA provider also implements RSA encryption and decryption with zero padding. This padding scheme is not supported by all JCE providers. The default padding scheme is PKCS 1 type 2 padding for the IBMJCECCA provider.

The following example illustrates creating an instance of an RSA Cipher with zero padding:
Cipher myCipher = Cipher.getInstance("RSA/ /ZeroPadding", "IBMJCECCA");
The following example illustrates creating an instance of an RSA Cipher with PKCS 1 type 2 padding:
Cipher myCipher = Cipher.getInstance("RSA/ /PKCS1Padding", "IBMJCECCA");
The following example shows an alternative method:
Cipher myCipher = Cipher.getInstance("RSA", "IBMJCECCA"); // accept the default padding
The IBMJCECCA provider supports RSA wrapping of a symmetric key for export to another host. The following keys are supported for RSA wrapping:
  • A key object that contains a clear AES, DES, or triple DES key
  • A key object that contains a CCA key storage area label for an encrypted AES, DES DATA, or triple DES DATA key
  • A key object that contains a hardware token with an encrypted AES, DES DATA, or triple DES DATA key

The IBMJCECCA provider supports RSA unwrapping of a symmetric key for import from another host. By default, the resulting (unwrapped) key object contains a clear key.

If a CCAAlgorithmParameterSpec object is created with no type specified, or with type CCAAlgorithmParameterSpec.SECURE_INTERNAL_TOKEN specified, and the RSA Cipher is initialized with this CCAAlgorithmParameterSpec object, the resulting (unwrapped) key object contains a hardware token. This token contains the key that is encrypted with the host primary key. If a CCAAlgorithmParameterSpec object is created with type CAAlgorithmParameterSpec.CKDS, and the RSA Cipher is initialized with this CCAAlgorithmParameterSpec object, the resulting (unwrapped) key object contains the label for a CCA key storage area entry that contains a hardware token. This token contains the key that is encrypted with the host primary key.

The following example illustrates generating a triple DES key object that contains a clear key, wrapping it, then unwrapping it to a triple DES key object that contains a clear key.
// Generate a clear triple DES key
//
KeyGenerator keyGen =
        KeyGenerator.getInstance("DESede", "IBMJCECCA");
Key tdesKey = keyGen.generateKey();

// Generate an RSA key pair
//
KeyPairGenerator rsaKeyPairGen =
        KeyPairGenerator.getInstance("RSA","IBMJCECCA");
rsaKeyPairGen.initialize(1024);
KeyPair rsaKeyPair = rsaKeyPairGen.generateKeyPair();
PublicKey rsaPub = rsaKeyPair.getPublic();
PrivateKey rsaPriv = rsaKeyPair.getPrivate();

// Wrap the triple DES key as for export
//
Cipher rsaCipher = Cipher.getInstance("RSA","IBMJCECCA");
rsaCipher.init(Cipher.WRAP_MODE, rsaPub,
               (AlgorithmParameters)null, null);
byte[] wrappedKey = rsaCipher.wrap(tdesKey);

// Unwrap the triple DES key as for import
// Unwrap to a clear key
//
Key unwrappedDesKey =
        rsaCipher.unwrap(wrappedKey, "DESede", Cipher.SECRET_KEY);
The following example illustrates generating a triple DES key object that contains a hardware key token, wrapping it, then unwrapping it to a triple DES key object that contains a hardware key token.
// Generate a secure triple DES hardware key
//
CCAAlgorithmParameterSpec ccaAlgParmSpec =
        new CCAAlgorithmParameterSpec();
KeyGenerator keyGen =
        KeyGenerator.getInstance("DESede", "IBMJCECCA");
keyGen.init(ccaAlgParmSpec, null);
Key tdesKey = keyGen.generateKey();

// Generate an RSA key pair
//
KeyPairGenerator rsaKeyPairGen =
        KeyPairGenerator.getInstance("RSA","IBMJCECCA");
rsaKeyPairGen.initialize(1024);
KeyPair rsaKeyPair = rsaKeyPairGen.generateKeyPair();
PublicKey rsaPub = rsaKeyPair.getPublic();
PrivateKey rsaPriv = rsaKeyPair.getPrivate();

// Wrap the triple DES hardware key as for export
//
Cipher rsaCipher = Cipher.getInstance("RSA","IBMJCECCA");
rsaCipher.init(Cipher.WRAP_MODE, rsaPub,
               (AlgorithmParameters)null, null);
byte[] wrappedKey = rsaCipher.wrap(tdesKey);

// Unwrap the triple DES key as for import
// Unwrap to a secure hardware key
//
CCAAlgorithmParameterSpec ccaAlgParmSpec_forUnwrap =
        new CCAAlgorithmParameterSpec();
rsaCipher.init(Cipher.UNWRAP_MODE, rsaPriv,
               ccaAlgParmSpec_forUnwrap, null);
Key unwrappedDesKey =
        rsaCipher.unwrap(wrappedKey, "DESede", Cipher.SECRET_KEY);
      
The following example illustrates deleting an RSA hardware key object for a key that is stored in the CCA key storage area, with the label "MYRSAKEY".
// Get the key store instance, open an input stream to the
// keystore file and load the key store.
//
KeyStore jceccaks = KeyStore.getInstance("JCECCAKS", "IBMJCECCA");
InputStream istream = new FileInputStream("keyStore.cca");
jceccaks.load(istream, "keystorePW".toCharArray());

// Given the alias for the CCA key storage area key entry, retrieve the private
// hardware key from the key store.
//
PrivateKey privateKey = (PrivateKey) jceccaks.getKey("MYRSAKEY", "myrsakeyPW".toCharArray());

// Delete the RSA hardware CCA key storage area key entry.
//
((RSAPrivateHWKey)privateKey).deletePKDSEntry();

// Delete the RSA key store object.
//
jceccaks.deleteEntry("MYRSAKEY");

// Write the modified key store contents to the key store file.
//
OutputStream ostream = new FileOutputStream("keyStore.cca");
jceccaks.store(ostream, "keystorePW".toCharArray());
      
Note: The DSAPrivateHWKey class also has a deletePKDSEntry method. You can follow the previous code example to delete DSA private hardware CCA key storage area key entries by substituting the DSAPrivateHWKey class for the RSAPrivateHWKey class.

Like OpenJCEPlus, the IBMJCECCA provider implements RSA wrapping and unwrapping with OAEP (Optimal Asymmetric Encryption Padding). The IBMJCECCA support differs from the software JCE implementation support in the following ways:

  • Start of changes for 17.0.9.0IBMJCECCA RSA wrapping with OAEP supports SHA-1, SHA-224, SHA-256, SHA-384, and SHA-512 padding algorithms.End of changes for 17.0.9.0
  • Start of changes for 17.0.9.0OAEP with SHA-512 padding requires an RSA key size of 2048.End of changes for 17.0.9.0
  • IBMJCECCA RSA wrapping with OAEP can be used only to wrap SECURE_INTERNAL_TOKEN keys and encrypted keys in the CCA key storage area.
The following examples illustrate creating an instance of an RSA Cipher with the OAEP SHA-1 and the OAEP SHA-256 padding algorithm:
Cipher rsaCipher = Cipher.getInstance("RSA/ /OAEPPADDINGSHA-1", "IBMJCECCA");
Cipher rsaCipher = Cipher.getInstance("RSA/ /OAEPPADDINGSHA-256", "IBMJCECCA");
The following example illustrates wrapping a DES key token using RSA with OAEP and SHA-256 padding:
OAEPParameterSpec oaepSpec = new OAEPParameterSpec(
       "SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT);
CCAAlgorithmParameterSpec ccaSpec = new CCAAlgorithmParameterSpec(CCAAlgorithmParameterSpec.SECURE_INTERNAL_TOKEN);
ccaSpec.setOAEPParameterSpec(oaepSpec);
rsaCipher.init(Cipher.WRAP_MODE, rsaPub,ccaSpec, null);
byte[] wrappedKey = rsaCipher.wrap(desKey); 
The following example illustrates unwrapping a DES key to an encrypted key stored in the CCA key storage area, when the key was wrapped by using RSA with OAEP and SHA-256 padding:
OAEPParameterSpec oaepSpec = new OAEPParameterSpec(
       "SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT); 
CCAAlgorithmParameterSpec ccaSpec = new CCAAlgorithmParameterSpec(CCAAlgorithmParameterSpec.CKDS);
ccaSpec.setOAEPParameterSpec(oaepSpec);
rsaCipher.init(Cipher.UNWRAP_MODE, rsaPriv, ccaSpec, null);
Key unwrappedKey = rsaCipher.unwrap(wrappedKey, "DES" Cipher.SECRET_KEY);

The RSA cipher in the IBMJCECCA provider supports wrapping and unwrapping of AES transport keys, such as AES EXPORTER and AES IMPORTER keys, using RSA with OAEP. Note that IBMJCECCA transport key objects contain transient fields that might not persist through wrap and unwrap operations. For more information, see Symmetric transport keys (key encrypting keys).

The RSA cipher in the IBMJCECCA provider supports wrapping and unwrapping of DES and Triple DES keys, but only if they are DATA keys.