| RSA BSAFE CRYPTO-J |
Cryptographic Components for Java |
| JSAFE Javadoc | JCE Javadoc | Search |
/* 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.");
}
}