RSA BSAFE CRYPTO-J

Cryptographic Components for Java

JSAFE Javadoc JCE Javadoc Search

X9.31

This sample demonstrates the use of the X9.31 Crypto-J methods required for government compliance in terms of random number generation, strong key generation and rDSA signatures.

/* X931.java
 * Copyright (c) 1997-2005, RSA Security Inc.
 *
 * This file is used to demonstrate how to interface to an RSA
 * Security licensed development product.  You have a
 * royalty-free right to use, modify, reproduce and distribute this
 * demonstration file (including any modified version), provided that
 * you agree that RSA Security has no warranty, implied or
 * otherwise, or liability for this demonstration file or any modified
 * version.
 *
 *
 * X9.31 Random Number Generation, Strong Key Generation, and rDSA Signatures
 *
 * This program demonstrates the use of the X9.31 Crypto-J methods required
 * for government compliance in terms of random number generation, strong
 * key generation and rDSA signatures.
 *
 */

package com.rsa.cryptoj.samples.crypto;

// Import the Crypto-J classes.
import com.rsa.jsafe.CryptoJ;
import com.rsa.jsafe.JSAFE_SecureRandom;
import com.rsa.jsafe.JSAFE_KeyPair;
import com.rsa.jsafe.JSAFE_PrivateKey;
import com.rsa.jsafe.JSAFE_PublicKey;
import com.rsa.jsafe.JSAFE_Signature;

import java.util.Date;
import java.io.PrintStream;
import java.security.SecureRandom;

public class X931 extends AppApplet {

  private Thread thisThread = null;

  public void init () {
    super.init ();
    thisThread = new Thread (this);
    thisThread.start ();
  }

  public static void main(String argv[]) throws Exception {
    X931 x931Instance = new X931();
    x931Instance.go();
  }

  public void go () throws Exception {

    JSAFE_SecureRandom random = null;
    JSAFE_KeyPair strongRSAKeyPair = null;
    JSAFE_PrivateKey privateKey = null;
    JSAFE_PublicKey publicKey = null;
    boolean compareOkay = true;
    byte[] signature = null;

    // These are the 8 bytes that we will eventually sign via
    // the X9.31 specification.
    byte[] signMe = {
      (byte)0x49, (byte) 0x20, (byte)0x61, (byte)0x6D,
      (byte)0x20, (byte) 0x6A, (byte)0x75, (byte)0x73 };

    println("Beginning X931 Example.");

    // When using a FIPS 140 compliant version of the toolkit,
    // check that the required power-up self-tests passed
    // before proceeding.
    if (CryptoJ.isFIPS140Compliant() && !CryptoJ.selfTestPassed()) {
      println("Crypto-J is disabled, power-up self-testing failed");
      return;
    }

    try {
      // Like most other Crypto-J objects, a new instance of
      // JSAFE_SecureRandom is obtained by calling the getInstance() method. The
      // first parameter, "X931Random-6", tells Crypto-J to create a
      // PRNG that generates random bits based on the X931
      // specification with 6 streams of randomness.
      random = (JSAFE_SecureRandom)
        JSAFE_SecureRandom.getInstance("X931Random-6", "Java");

      // Seeding is the most important aspect of dealing with a secure
      // random number generator. It is extremely important to seed
      // the PRNG with a value that contains sufficient entropy.
      // According to the X9.31 specification, it's necessary to have two independent
      // streams of seeding. There is a standard seed plus an optional
      // user-supplied seed. These are both required if wanting to maintain
      // compliance with the X9.31 specification. The input passed into
      // the extraSeed function must be 20 to 64 times longer than the number
      // of streams.
      // The standard seeding done below is a very insecure method of seeding.
      // Dates are deterministic and insecure for seeding random number
      // generator. It is offered here for example and testing purposed only
      // Note, also the use of the SecureRandom class to get extra seed.

      random.seed(new Date().toString().getBytes());  // standard seeding
      random.extraSeed(SecureRandom.getSeed(205));    // extra seeding

     } catch (Exception anyException) {
      println("Exception caught while seeding the PRNG.");
      println(anyException.toString());
      anyException.printStackTrace (new PrintStream (this.getOutputStream ()));
      throw anyException;
     }

     try {
      // If you want to generate some (pseudo) random bytes, use the
      // generateRandomBytes() methods. The following call returns a
      // byte array that contains 64 random bytes.
      byte [] randomBytes = random.generateRandomBytes(64);

      println("Here are some random bytes:");
      printBuffer(randomBytes);

      // The previous call returned an array of random bytes, it's also possible
      // to tell a JSAFE_SecureRandom object to fill in a portion of a byte
      // array. The following statement replaces some of the random bytes
      // generated with the last call to generateRandomBytes with some
      // newly generated pseudo random bytes.
      random.generateRandomBytes(randomBytes, 4, 10);

      println("Here are some more random bytes:");
      printBuffer(randomBytes);

      // Knowing the random bytes could aide an attacker in defeating the
      // security of the application. It's therefore good practice to
      // zero out the buffer that contains the aforementioned random bytes
      // before exiting.
      for (int i = 0; i < randomBytes.length; i++) {
        randomBytes[i] = (byte) 0x00;
      }

    } catch (Exception anyException) {
      println("Exception caught while generating random bytes.");
      println(anyException.toString());
      anyException.printStackTrace (new PrintStream (this.getOutputStream ()));
      throw anyException;
    }

    // Remember to clean up after yourself! Call clearSensitiveData()
    // after the PRNG is no longer needed. This clears out the state information
    // from the object. It's very difficult to peek inside a running application
    // to gather this type of information and compromise the security of a system,
    // but it is certainly possible. Never underestimate the resourcefulness of
    // your potential attackers!
    // Since the random number generator is used later on,
    // this code is commented out:
    // random.clearSensitiveData();

    println("Random Number Generation Successful.");

    // Continue by using the X931 Random Number Generator to
    // generate a strong RSA Key in accordance with the X931 specification.
    //
    // Create an instance of a JSAFE_KeyPair

    try {
      println("Instantiating a JSAFE KeyPair Object");
      strongRSAKeyPair = JSAFE_KeyPair.getInstance("RSA", "Java");
      println("Instantiation Successful!");

      // Notice that "RSA" and "Java" was chosen for the parameters. The "RSA" tells
      // Crypto-J to generate RSA keys and the "Java" tells Crypto-J not to use
      // any faster native implementation.

      // Continue by calling generateStrongInit() to actually generate the keys.
      // The minimum keysize for X931 Strong Random Number
      // generation is 1024 bits. This example uses 2048 bits, which is the
      // recommended minimum key size for RSA Keys.
      // Notice that the following passes in the X931 random class which was
      // previously instantiated.

      int [] keyPairGenParams = { 2048, 65537 };
      println("Generating Strong Keys");
      strongRSAKeyPair.generateStrongInit(null, keyPairGenParams, random);
      strongRSAKeyPair.generate();
      println("Strong Key Generation Complete!");
      println("Extracting Private Key for later use");
      privateKey = strongRSAKeyPair.getPrivateKey();
      publicKey = strongRSAKeyPair.getPublicKey();

    } catch (Exception anyException) {
      println(" Exception caught while generating an RSA KeyPair..");
      println(anyException.toString());
      anyException.printStackTrace (new PrintStream (this.getOutputStream ()));
      throw anyException;
    }

     try {
       // Create the JSAFE_Signature instance that actually does the signing.
       // Note that the following call is used in accordance with the
       // X9.31 specfication. According to X931, the only two valid choices
       // for the message digest are "SHA1" or "DEA." DEA is not currently
       // implemented in Crypto-J. The specification of X931Pad for padding
       // is what gives rise to X931 signing/verification as opposed to regular
       // signing with PKCSBlock01Pad.
       println("Beginning signature example");

       JSAFE_Signature signer =
         JSAFE_Signature.getInstance("SHA1/X931RSA/X931Pad", "Java");

       // Signing does not require the generation of random bytes. It is
       // therefore okay to pass a 'null' as the second parameter to signInit().
       signer.signInit(privateKey, null);
       signer.signUpdate(signMe, 0, signMe.length);
       signature = signer.signFinal();

       println("Signing Complete");
       println("Result:");
       printBuffer(signature);

       // There might be sensitive information still in the signer object,
       // so call clearSensitiveData() before it goes out of scope.
       signer.clearSensitiveData();
       println("X9.31 Signing Sucessfully Completed!");

    } catch (Exception anyException) {
      println("Exception caught while signing arbitrary data.");
      anyException.printStackTrace (new PrintStream (this.getOutputStream ()));
      throw anyException;
    }

    try {
      // This is the easy way to vertify something that was just signed.
      JSAFE_Signature verifier =
        JSAFE_Signature.getInstance("SHA1/X931RSA/X931Pad", "Java");

      verifier.verifyInit (publicKey, null);
      verifier.verifyUpdate (signMe, 0, signMe.length);
      compareOkay = verifier.verifyFinal (signature, 0, signature.length);

      // The verifier may also contain sensitive information, so
      // call clearSensitiveData() before it goes out of scope.
      verifier.clearSensitiveData();

     } catch(Exception anyException) {
       println("Exception encountered during verify.");
       anyException.printStackTrace (new PrintStream (this.getOutputStream ()));
       throw anyException;
     }

    try {

      if (compareOkay) {
        println("Success! The signature was verified."); }
      else {
        println("Failure! The signature was not verified!");
        throw new Exception("Failure! The signature was not verified!");
      }

    } catch(Exception anyException) {
      println("Exception encountered during verify.");
      anyException.printStackTrace (new PrintStream (this.getOutputStream ()));
      throw anyException;
    }

    // Make sure to also clear the keys to prevent attacks.
    publicKey.clearSensitiveData();
    privateKey.clearSensitiveData();
    strongRSAKeyPair.clearSensitiveData();

    println("Successful Ending.");
  }

}

Copyright (c) 1999-2005 RSA Security Inc. All rights reserved. 038-001001-3500-001-000 - 3.5