Wednesday, February 24, 2010
Sunday, February 14, 2010
The RichRSACipher class: An RSA cipher implementation
The RichRSACipher class: An RSA cipher implementation
package com.richware.chap12;
import java.io.*;
import java.math.BigInteger;
import java.security.*;
import java.security.interfaces.*;
import java.security.spec.*;
import javax.crypto.*;
import sun.misc.*;
/**
* Class RichRSACipher
* Description: This is an example of a
* simple RSA Encryption
* RSA information is from PKCS#1v2.0
* a publication from RSA Security
*
* Copyright: Copyright (c) 2002 Wiley Publishing, Inc.
* @author Rich Helton
* @version 1.0
* DISCLAIMER: Please refer to the disclaimer at the beginning of this book.
*/
public final class RichRSACipher extends CipherSpi
{
private RSAKeyGenParameterSpec params_;
private SecureRandom random_;
private final static boolean DEBUG = true;
private int opmode_;
private Key key_;
private byte[] internal_buffer_;
/**
* Constructor RichRSACipher
*/
public RichRSACipher() {}
/**
* Method engineDoFinal
* Description: See CipherSpi
*/
protected byte[] engineDoFinal(
byte[] input, int inputOffset, int inputLen)
throws IllegalBlockSizeException,
BadPaddingException
{
byte[] output = engineUpdate(input, inputOffset, inputLen);
internal_buffer_ = null;
return output;
}
/**
* Method engineDoFinal
* Description: See CipherSpi
*/
protected int engineDoFinal(
byte[] input, int inputOffset, int inputLen, byte[] output,
int outputOffset)
throws ShortBufferException,
IllegalBlockSizeException,
BadPaddingException
{
byte[] buffer;
buffer = engineDoFinal(input, inputOffset, inputLen);
if (output.length - outputOffset < buffer.length)
{
throw new ShortBufferException(
"Output longer than buffer");
}
System.arraycopy(buffer, 0, output, outputOffset,
buffer.length);
return buffer.length;
}
/**
* Method engineGetBlockSize
* Description: See CipherSpi
*/
protected int engineGetBlockSize()
{
if ((opmode_ == Cipher.ENCRYPT_MODE)
|| (opmode_ == Cipher.WRAP_MODE))
{
return params_.getKeysize();
}
else
{
return params_.getKeysize() - 1;
}
}
/**
* Method engineGetIV
* Description: See CipherSpi
*/
protected byte[] engineGetIV()
{
return null; // If not supported
}
/**
* Method engineGetKeySize
* Description: See CipherSpi
*/
protected int engineGetKeySize(Key key)
throws InvalidKeyException
{
/*
* Get the key size based on bit length
*/
if (key instanceof RSAPrivateKey)
{
RSAPrivateKey k = (RSAPrivateKey) key;
return k.getModulus().bitLength();
}
else if (key instanceof RSAPublicKey)
{
RSAPublicKey k = (RSAPublicKey) key;
return k.getModulus().bitLength();
}
throw new InvalidKeyException("Unsupported RSA key!");
}
/**
* Method engineGetOutputSize
* Description: See CipherSpi
*/
protected int engineGetOutputSize(int inputLen)
{
if ((opmode_ == Cipher.ENCRYPT_MODE)
|| (opmode_ == Cipher.WRAP_MODE))
{
return params_.getKeysize();
}
else
{
return params_.getKeysize() - 1;
}
}
/**
* Method engineGetParameters
* Description: See CipherSpi
*/
protected AlgorithmParameters engineGetParameters()
{
return null;
}
/**
* Method engineInit
* Description: See CipherSpi
*/
protected void engineInit(
int opmode, Key _key, AlgorithmParameterSpec params, SecureRandom
_random)
throws InvalidKeyException,
InvalidAlgorithmParameterException
{
// Check for valid key
if ((!(_key instanceof RSAPublicKey))
&& (!(_key instanceof RSAPrivateKey)))
{
throw new InvalidKeyException("Unsupported RSA Key!");
}
// Check for valid Parameter Spec
if ((params != null)
&& (!(params instanceof RSAKeyGenParameterSpec)))
{
throw new InvalidAlgorithmParameterException(
"Unsupported RSA AlgorithmParameterSpec!");
}
// Initialize the params
if (params != null)
{
params_ = (RSAKeyGenParameterSpec) params;
}
else
{
int keysize = 0;
BigInteger publicExp = null;
if (_key instanceof RSAPublicKey)
{
publicExp = ((RSAPublicKey) _key).getPublicExponent();
int modulusLength =
((RSAPublicKey) _key).getModulus().bitLength();
keysize = (modulusLength + 7) / 8;
}
else if (_key instanceof RSAPrivateKey)
{
int modulusLength =
((RSAPrivateKey) _key).getModulus().bitLength();
keysize = (modulusLength + 7) / 8;
}
if(DEBUG){
System.out.println("RichRSACipher:engineInit:keysize:" + keysize);
}
params_ = new RSAKeyGenParameterSpec(keysize, publicExp);
}
random_ = _random;
// Check for valid types of opmode
if ((opmode == Cipher.DECRYPT_MODE)
|| (opmode == Cipher.ENCRYPT_MODE)
|| (opmode == Cipher.UNWRAP_MODE)
|| (opmode == Cipher.WRAP_MODE))
{
if (((opmode == Cipher.DECRYPT_MODE) || (opmode == Cipher
.UNWRAP_MODE)) && (_key instanceof RSAPublicKey))
{
throw new InvalidKeyException(
"Unsupported: Decrypt/UnWrap mode must use RSAPrivateKey");
}
if (((opmode == Cipher.ENCRYPT_MODE) || (opmode == Cipher
.WRAP_MODE)) && (_key instanceof RSAPrivateKey))
{
throw new InvalidKeyException(
"Unsupported: Encrypt/Wrap mode must use RSAPublicKey");
}
if(DEBUG){
if ((opmode == Cipher.DECRYPT_MODE) || (opmode == Cipher.UNWRAP_MODE)){
System.out.println("RichRSACipher:engineInit:DECRYPT_MODE");
}else{
System.out.println("RichRSACipher:engineInit:ENCRYPT_MODE");
}
}
}
else
{
throw new InvalidKeyException("Unsupported opmode!");
}
opmode_ = opmode;
key_ = _key;
}
/**
* Method engineInit
* Description: See CipherSpi
*/
protected void engineInit(
int opmode, Key _key, AlgorithmParameters params, SecureRandom _random)
throws InvalidKeyException,
InvalidAlgorithmParameterException
{
/*
* Note _key is used instead of Key, because Key is a class.
* Random is also a class.
*/
engineInit(opmode, _key, (AlgorithmParameterSpec) null,
_random);
}
/**
* Method engineInit
* Description: See CipherSpi
*/
protected void engineInit(
int opmode, Key _key, SecureRandom _random)
throws InvalidKeyException
{
try
{
engineInit(opmode, _key, (AlgorithmParameterSpec) null,
_random);
}
catch (InvalidAlgorithmParameterException ex)
{
throw new InvalidKeyException(ex.getMessage());
}
}
/**
* Method engineSetMode
* Description: See CipherSpi
*/
protected void engineSetMode(String mode)
throws NoSuchAlgorithmException
{
if (!mode.equalsIgnoreCase("ECB"))
{
throw new NoSuchAlgorithmException(
"RSA supports only ECB mode");
}
}
/**
* Method engineSetPadding
* Description: See CipherSpi
*/
protected void engineSetPadding(String s)
throws NoSuchPaddingException
{
// Only accepts avaliable padding
if (!s.equalsIgnoreCase("PKCS1_V1_5"))
{
throw new NoSuchPaddingException("Unknown padding: "
+ s);
}
}
/**
* Method engineUpdate
* Description: See CipherSpi
*/
protected byte[] engineUpdate(byte[] input, int inputOffset,
int inputLen)
{
try
{
if (inputOffset > 0)
{
int outputSize = inputOffset + inputLen;
byte[] tmp = new byte[outputSize];
System.arraycopy(input, inputOffset, internal_buffer_,
internal_buffer_.length, inputLen);
if ((opmode_ == Cipher.ENCRYPT_MODE)
|| (opmode_ == Cipher.WRAP_MODE))
{
return (encrypt(internal_buffer_));
}
else
{
return (decrypt(internal_buffer_));
}
}
else
{
internal_buffer_ = new byte[inputLen];
System.arraycopy(input, 0, internal_buffer_,0, inputLen);
if ((opmode_ == Cipher.ENCRYPT_MODE)
|| (opmode_ == Cipher.WRAP_MODE))
{
if(DEBUG){
System.out.println("RichRSACipher:engineUpdate:encrypting");
}
return (encrypt(internal_buffer_));
}
else
{
if(DEBUG){
System.out.println("RichRSACipher:engineUpdate:decrypting");
}
return (decrypt(internal_buffer_));
}
}
}
/*
* Catches
*/
catch (Exception ex)
{
ex.printStackTrace();
}
return null;
}
/**
* Method engineUpdate
* Description: See CipherSpi
*/
protected int engineUpdate(
byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)
throws ShortBufferException
{
byte[] buffer;
buffer = engineUpdate(input, inputOffset, inputLen);
if (output.length - outputOffset < buffer.length)
{
throw new ShortBufferException(
"Output longer than buffer");
}
System.arraycopy(buffer, 0, output, outputOffset,
buffer.length);
return buffer.length;
}
/**
* Method I2OSP
* Description: Integer to Octet String Primitive
* See PKCS#1
*/
private byte[] I2OSP(BigInteger x, int l)
throws IllegalBlockSizeException
{
/*
* Section 4.1 of PKCS#1v2.0
* I2OSP converts a nonnegative integer to an octet string
* of a specified length. I2OSP (x, l)
* Input: x nonnegative integer to be converted
* l intended length of the resulting octet string
* Output: X corresponding octet string of length l; or
* integer too large
* Steps:
*/
/*
* 1. If x = 256l, output "integer too large " and stop.
*/
int j = (x.bitLength() + 7) / 8;
if (l == -1)
{
l = j;
}
if ((j > l) || (x.signum() == -1))
{
throw new IllegalBlockSizeException("Block too large");
}
/*
* 2. Write the integer x in its unique l-digit representation
* base 256: x = xl- 1 256^ (l- 1) + xl -2 256 256^(l -2) + ...& +
x1 256 + x0
* where 0 = xi < 256 (note that one or more leading digits
* will be zero if x < 256^ (l- 1)).
*/
byte[] C = x.toByteArray();
/*
* remove the leading zeros
*/
int index = 0;
for (; (index < C.length) && (C[index] == 0); index++);
if (index > 0)
{
byte[] temp = new byte[C.length - index];
System.arraycopy(C, index, temp, 0, temp.length);
C = temp;
}
else if (C.length > l)
{
throw new IllegalBlockSizeException("Block too large");
}
/*
* 3. Let the octet Xi have the value xl -i for 1 = i = l.
* Output the octet string X = X1 X2 & ... Xl.
*/
if (C.length == l)
{
return C;
}
/*
* C is not long enough
*/
byte[] result = new byte[l];
System.arraycopy(C, 0, result, l - C.length, C.length);
return result;
}
/**
* Method encrypt
* Description: Encrypt with pad
* See PKCS#1
* @param M the plaintext message
*/
private byte[] encrypt(byte[] M)
throws IllegalBlockSizeException
{
/*
* RSA Steps according to PKCS #1 v 2.0 pg 15 for encryption:
* 1. Apply the EME-PKCS1-v1_5 encoding operation (Section 9.1.2.1)
* to the message M to produce an encoded message EM of length k-1
* octets: EM = EME-PKCS1-V1_5-ENCODE (M, k-1)
* If the encoding operation outputs "message too long, ," then
output
* message too long and stop.
*/
int k = params_.getKeysize();
byte[] EM = EME_PKCS1_V1_5_ENCODE(M, k - 1);
/*
* 2. Convert the encoded message EM to an integer message
* representative m: m = OS2IP (EM)
*/
BigInteger m = new BigInteger(1, EM);
/*
* 3. Apply the RSAEP encryption primitive (Section 5.1.1) to the
* public key (n, e) and the message representative m to produce
* an integer ciphertext representative c: c = RSAEP ((n, e), m)
*/
BigInteger c = RSAEP((RSAPublicKey) key_, m);
/*
* 4. Convert the ciphertext representative c to a ciphertext C of
* length k octets: C = I2OSP (c, k)
*/
byte[] C = I2OSP(c, k);
/*
* 5. Output the ciphertext C.
*/
return C;
}
/**
* Method decrypt
* Description: Decrypt with pad
* See PKCS#1
* @param M the ciphertext message
*/
private byte[] decrypt(byte[] C)
throws BadPaddingException, IllegalBlockSizeException
{
/*
* RSA Steps according to PKCS #1 v 2.0 pg 16 for decryption:
* 1. If the length of the ciphertext C is not k octets, output
* decryption error and stop.
*/
int k = params_.getKeysize();
if (k != C.length)
{
throw new IllegalBlockSizeException("decryption error");
}
/*
* 2. Convert the ciphertext C to an integer ciphertext
* representative c: c = OS2IP (C)
*/
BigInteger c = new BigInteger(1, C);
/*
* 3. Apply the RSADP decryption primitive to the private
* key (n, d) and the ciphertext representative c to produce
* an integer message representative m: m = RSADP ((n, d), c)
* If RSADP outputs ciphertext out of range, then output
* decryption error and stop.
*/
BigInteger m = RSADP((RSAPrivateKey) key_, c);
/*
* 4. Convert the message representative m to an encoded message
* EM of length k-1 octets: EM = I2OSP (m, k-1)
* If I2OSP outputs integer too large, then output decryption
* error and stop.
*/
byte[] EM = I2OSP(m, k - 1);
/*
* 5. Apply the EME-PKCS1-v1_5 decoding operation to the encoded
* message EM to recover a message M: M = EME-PKCS1-V1_5-DECODE(EM)
* If the decoding operation outputs decoding error, then output
* decryption error and stop.
*/
byte[] M = EME_PKCS1_V1_5_DECODE(EM);
/*
* 6. Output the message M.
*/
return M;
}
/**
* Method EME_PKCS1_V1_5_ENCODE
* Description: Pad encoding
*
* @param M the ciphertext message
* @param emLen the length of encr message
*
* @return encoded pad
*
* @throws IllegalBlockSizeException
*
*/
private byte[] EME_PKCS1_V1_5_ENCODE(byte[] M, int emLen)
throws IllegalBlockSizeException
{
/*
* Section 9.1.2.1 of PKCS#1v2.0
* 1. If the length of the message M is greater than emLen 10
* octets, output message too long and stop.
*/
if (M.length > emLen - 10)
{
throw new IllegalBlockSizeException("message too long");
}
/*
* 2. Generate an octet string PS of length emLen-||M||-2
* consisting of pseudorandomly generated nonzero octets.
* The length of PS will be at least 8 octets.
*/
byte[] PS =
new byte[(emLen - M.length - 2)];
// Fill the padding string with random non-zero bytes
for (int i = 0; i < PS.length; i++)
{
PS[i] = (byte) (random_.nextInt(255) + 1);
}
/*
* 3. Concatenate PS, the message M, and other padding to
* form the encoded message EM as EM = 02 || PS || 00 || M
*/
byte[] EM = new byte[emLen];
int index = 0;
EM[index++] = (byte) 0x02;
for (int i = 0; i < PS.length; i++)
{
EM[index++] = PS[i];
}
EM[index++] = (byte) 0x00;
for (int i = 0; i < M.length; i++)
{
EM[index++] = M[i];
}
/*
* 4. Output EM.
*/
return EM;
}
/**
* Method EME_PKCS1_V1_5_DECODE
* Description: Pad decoding
*
* @param EM the encrypted message
*
* @return pad
*
* @throws BadPaddingException
*
*/
private byte[] EME_PKCS1_V1_5_DECODE(byte[] EM)
throws BadPaddingException
{
/*
* Section 9.1.2.2 of PKCS#1v2.0
* 1. If the length of the encoded
* message EM is less than 10, output decoding error
* and stop.
*/
if (EM.length < 10)
{
throw new BadPaddingException("message too short");
}
/*
* 2. Separate the encoded message EM into an octet string PS
* consisting of nonzero octets and a message M as
* EM = 02 || PS || 00 || M. If the first octet of EM is not 02,
* or if there is no 00 octet to separate PS from M,
* output decoding error and stop.
*/
if (EM[0] != (byte) 0x02)
{
throw new BadPaddingException(
"message not formatted properly");
}
// Need to start by looking for the first non-zero byte
int start = 0;
while (EM[start] != (byte) 0x00)
{
start++;
if (start >= EM.length)
{
throw new BadPaddingException("bad padding");
}
}
start++; // Ignore the first 00
/*
* 3. If the length of PS is less than 8 octets,
* output decoding error and stop.
*/
if (start < 10)
{
throw new BadPaddingException("bad padding");
}
byte[] M = new byte[EM.length - start];
System.arraycopy(EM, start, M, 0, M.length);
/*
* 4. Output M.
*/
return M;
}
/**
* Method RSEAP
* Description: Performs the encryyrption
*
* @param publicKey the RSA public key
* @param m the plaintext integer
*
* @return the ciphertext integer
*
* @throws IllegalBlockSizeException
*
*/
private BigInteger RSAEP(RSAPublicKey publicKey, BigInteger m)
throws IllegalBlockSizeException
{
/*
* RSAEP ((n, e), m)
* Input: (n, e) RSA public key
* m message representative, an integer between 0 and n-1
* Output: c ciphertext representative, an integer between 0 and
* n-1; or message representative out of range
* Assumptions: public key (n, e) is valid
*/
BigInteger e = publicKey.getPublicExponent();
BigInteger n = publicKey.getModulus();
/*
* 1. If the message representative m is not between 0 and n-1,
* output message representative out of range and stop.
*/
BigInteger nMinusOne = n.subtract(BigInteger.ONE);
/*
* m > 0 and m < n-1
*/
if (m.compareTo(BigInteger.ZERO) < 0)
{
throw new IllegalBlockSizeException(
"Ciphertext too small");
}
if (m.compareTo(nMinusOne) > 0)
{
throw new IllegalBlockSizeException(
"Ciphertext too large");
}
/*
* 2. Let c = me mod n.
*/
BigInteger c = m.modPow(e, n);
/*
* 3. Output c.
*/
return c;
}
/**
* Method RSADP
* Description: Performs the decryption
*
* @param K the RSA Private Key
* @param c an integer representing
* the cipher
*
* @return the plaintext integer
*
*/
private BigInteger RSADP(RSAPrivateKey K,
BigInteger c)
{
/*
* RSADP (K, c)
* Input: K RSA private key, where K has one of the following
* forms: a pair (n, d)
* a quintuple (p, q, dP, dQ, qInv)
* c ciphertext representative, an integer between 0 and n-1
* Output: m message representative, an integer between 0 and n-1;
or
* ciphertext representative out of range
* Assumptions: private key K is valid
* Steps:
* 1. If the ciphertext representative c is not between 0 and n-1,
* output ciphertext representative out of range and stop.
*/
/*
* 2.1 Let m = cd mod n.
* PKCS #1 V2.0: RSA CRYPTOGRAPHY STANDARD 9
* Else, if the second form (p, q, dP, dQ, qInv) of K is used:
*/
if (!(K instanceof RSAPrivateCrtKey))
{
BigInteger d = K.getPrivateExponent();
BigInteger n = K.getModulus();
BigInteger m = c.modPow(d, n);
return m;
}
/*
* 2. If the first form (n, d) of K is used:
*/
RSAPrivateCrtKey privateCrtKey =
(RSAPrivateCrtKey) K;
BigInteger p = privateCrtKey.getPrimeP();
BigInteger q = privateCrtKey.getPrimeQ();
BigInteger dP =
privateCrtKey.getPrimeExponentP();
BigInteger dQ =
privateCrtKey.getPrimeExponentQ();
BigInteger qInv =
privateCrtKey.getCrtCoefficient();
/*
* 2.2 Let m1 = cdP mod p.
*/
BigInteger m1 = c.modPow(dP, p);
/*
* 2.3 Let m2 = cdQ mod q.
*/
BigInteger m2 = c.modPow(dQ, q);
/*
* 2.4 Let h = qInv ( m1 m2 ) mod p.
*/
BigInteger h = m1.subtract(m2);
h = h.multiply(qInv);
h = h.mod(p);
/*
* 2.5 Let m = m2 + h q.
*/
BigInteger m = h.multiply(q);
m = m.add(m2);
/*
* 3. Output m.
*/
return m;
}
}
package com.richware.chap12;
import java.io.*;
import java.math.BigInteger;
import java.security.*;
import java.security.interfaces.*;
import java.security.spec.*;
import javax.crypto.*;
import sun.misc.*;
/**
* Class RichRSACipher
* Description: This is an example of a
* simple RSA Encryption
* RSA information is from PKCS#1v2.0
* a publication from RSA Security
*
* Copyright: Copyright (c) 2002 Wiley Publishing, Inc.
* @author Rich Helton
* @version 1.0
* DISCLAIMER: Please refer to the disclaimer at the beginning of this book.
*/
public final class RichRSACipher extends CipherSpi
{
private RSAKeyGenParameterSpec params_;
private SecureRandom random_;
private final static boolean DEBUG = true;
private int opmode_;
private Key key_;
private byte[] internal_buffer_;
/**
* Constructor RichRSACipher
*/
public RichRSACipher() {}
/**
* Method engineDoFinal
* Description: See CipherSpi
*/
protected byte[] engineDoFinal(
byte[] input, int inputOffset, int inputLen)
throws IllegalBlockSizeException,
BadPaddingException
{
byte[] output = engineUpdate(input, inputOffset, inputLen);
internal_buffer_ = null;
return output;
}
/**
* Method engineDoFinal
* Description: See CipherSpi
*/
protected int engineDoFinal(
byte[] input, int inputOffset, int inputLen, byte[] output,
int outputOffset)
throws ShortBufferException,
IllegalBlockSizeException,
BadPaddingException
{
byte[] buffer;
buffer = engineDoFinal(input, inputOffset, inputLen);
if (output.length - outputOffset < buffer.length)
{
throw new ShortBufferException(
"Output longer than buffer");
}
System.arraycopy(buffer, 0, output, outputOffset,
buffer.length);
return buffer.length;
}
/**
* Method engineGetBlockSize
* Description: See CipherSpi
*/
protected int engineGetBlockSize()
{
if ((opmode_ == Cipher.ENCRYPT_MODE)
|| (opmode_ == Cipher.WRAP_MODE))
{
return params_.getKeysize();
}
else
{
return params_.getKeysize() - 1;
}
}
/**
* Method engineGetIV
* Description: See CipherSpi
*/
protected byte[] engineGetIV()
{
return null; // If not supported
}
/**
* Method engineGetKeySize
* Description: See CipherSpi
*/
protected int engineGetKeySize(Key key)
throws InvalidKeyException
{
/*
* Get the key size based on bit length
*/
if (key instanceof RSAPrivateKey)
{
RSAPrivateKey k = (RSAPrivateKey) key;
return k.getModulus().bitLength();
}
else if (key instanceof RSAPublicKey)
{
RSAPublicKey k = (RSAPublicKey) key;
return k.getModulus().bitLength();
}
throw new InvalidKeyException("Unsupported RSA key!");
}
/**
* Method engineGetOutputSize
* Description: See CipherSpi
*/
protected int engineGetOutputSize(int inputLen)
{
if ((opmode_ == Cipher.ENCRYPT_MODE)
|| (opmode_ == Cipher.WRAP_MODE))
{
return params_.getKeysize();
}
else
{
return params_.getKeysize() - 1;
}
}
/**
* Method engineGetParameters
* Description: See CipherSpi
*/
protected AlgorithmParameters engineGetParameters()
{
return null;
}
/**
* Method engineInit
* Description: See CipherSpi
*/
protected void engineInit(
int opmode, Key _key, AlgorithmParameterSpec params, SecureRandom
_random)
throws InvalidKeyException,
InvalidAlgorithmParameterException
{
// Check for valid key
if ((!(_key instanceof RSAPublicKey))
&& (!(_key instanceof RSAPrivateKey)))
{
throw new InvalidKeyException("Unsupported RSA Key!");
}
// Check for valid Parameter Spec
if ((params != null)
&& (!(params instanceof RSAKeyGenParameterSpec)))
{
throw new InvalidAlgorithmParameterException(
"Unsupported RSA AlgorithmParameterSpec!");
}
// Initialize the params
if (params != null)
{
params_ = (RSAKeyGenParameterSpec) params;
}
else
{
int keysize = 0;
BigInteger publicExp = null;
if (_key instanceof RSAPublicKey)
{
publicExp = ((RSAPublicKey) _key).getPublicExponent();
int modulusLength =
((RSAPublicKey) _key).getModulus().bitLength();
keysize = (modulusLength + 7) / 8;
}
else if (_key instanceof RSAPrivateKey)
{
int modulusLength =
((RSAPrivateKey) _key).getModulus().bitLength();
keysize = (modulusLength + 7) / 8;
}
if(DEBUG){
System.out.println("RichRSACipher:engineInit:keysize:" + keysize);
}
params_ = new RSAKeyGenParameterSpec(keysize, publicExp);
}
random_ = _random;
// Check for valid types of opmode
if ((opmode == Cipher.DECRYPT_MODE)
|| (opmode == Cipher.ENCRYPT_MODE)
|| (opmode == Cipher.UNWRAP_MODE)
|| (opmode == Cipher.WRAP_MODE))
{
if (((opmode == Cipher.DECRYPT_MODE) || (opmode == Cipher
.UNWRAP_MODE)) && (_key instanceof RSAPublicKey))
{
throw new InvalidKeyException(
"Unsupported: Decrypt/UnWrap mode must use RSAPrivateKey");
}
if (((opmode == Cipher.ENCRYPT_MODE) || (opmode == Cipher
.WRAP_MODE)) && (_key instanceof RSAPrivateKey))
{
throw new InvalidKeyException(
"Unsupported: Encrypt/Wrap mode must use RSAPublicKey");
}
if(DEBUG){
if ((opmode == Cipher.DECRYPT_MODE) || (opmode == Cipher.UNWRAP_MODE)){
System.out.println("RichRSACipher:engineInit:DECRYPT_MODE");
}else{
System.out.println("RichRSACipher:engineInit:ENCRYPT_MODE");
}
}
}
else
{
throw new InvalidKeyException("Unsupported opmode!");
}
opmode_ = opmode;
key_ = _key;
}
/**
* Method engineInit
* Description: See CipherSpi
*/
protected void engineInit(
int opmode, Key _key, AlgorithmParameters params, SecureRandom _random)
throws InvalidKeyException,
InvalidAlgorithmParameterException
{
/*
* Note _key is used instead of Key, because Key is a class.
* Random is also a class.
*/
engineInit(opmode, _key, (AlgorithmParameterSpec) null,
_random);
}
/**
* Method engineInit
* Description: See CipherSpi
*/
protected void engineInit(
int opmode, Key _key, SecureRandom _random)
throws InvalidKeyException
{
try
{
engineInit(opmode, _key, (AlgorithmParameterSpec) null,
_random);
}
catch (InvalidAlgorithmParameterException ex)
{
throw new InvalidKeyException(ex.getMessage());
}
}
/**
* Method engineSetMode
* Description: See CipherSpi
*/
protected void engineSetMode(String mode)
throws NoSuchAlgorithmException
{
if (!mode.equalsIgnoreCase("ECB"))
{
throw new NoSuchAlgorithmException(
"RSA supports only ECB mode");
}
}
/**
* Method engineSetPadding
* Description: See CipherSpi
*/
protected void engineSetPadding(String s)
throws NoSuchPaddingException
{
// Only accepts avaliable padding
if (!s.equalsIgnoreCase("PKCS1_V1_5"))
{
throw new NoSuchPaddingException("Unknown padding: "
+ s);
}
}
/**
* Method engineUpdate
* Description: See CipherSpi
*/
protected byte[] engineUpdate(byte[] input, int inputOffset,
int inputLen)
{
try
{
if (inputOffset > 0)
{
int outputSize = inputOffset + inputLen;
byte[] tmp = new byte[outputSize];
System.arraycopy(input, inputOffset, internal_buffer_,
internal_buffer_.length, inputLen);
if ((opmode_ == Cipher.ENCRYPT_MODE)
|| (opmode_ == Cipher.WRAP_MODE))
{
return (encrypt(internal_buffer_));
}
else
{
return (decrypt(internal_buffer_));
}
}
else
{
internal_buffer_ = new byte[inputLen];
System.arraycopy(input, 0, internal_buffer_,0, inputLen);
if ((opmode_ == Cipher.ENCRYPT_MODE)
|| (opmode_ == Cipher.WRAP_MODE))
{
if(DEBUG){
System.out.println("RichRSACipher:engineUpdate:encrypting");
}
return (encrypt(internal_buffer_));
}
else
{
if(DEBUG){
System.out.println("RichRSACipher:engineUpdate:decrypting");
}
return (decrypt(internal_buffer_));
}
}
}
/*
* Catches
*/
catch (Exception ex)
{
ex.printStackTrace();
}
return null;
}
/**
* Method engineUpdate
* Description: See CipherSpi
*/
protected int engineUpdate(
byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset)
throws ShortBufferException
{
byte[] buffer;
buffer = engineUpdate(input, inputOffset, inputLen);
if (output.length - outputOffset < buffer.length)
{
throw new ShortBufferException(
"Output longer than buffer");
}
System.arraycopy(buffer, 0, output, outputOffset,
buffer.length);
return buffer.length;
}
/**
* Method I2OSP
* Description: Integer to Octet String Primitive
* See PKCS#1
*/
private byte[] I2OSP(BigInteger x, int l)
throws IllegalBlockSizeException
{
/*
* Section 4.1 of PKCS#1v2.0
* I2OSP converts a nonnegative integer to an octet string
* of a specified length. I2OSP (x, l)
* Input: x nonnegative integer to be converted
* l intended length of the resulting octet string
* Output: X corresponding octet string of length l; or
* integer too large
* Steps:
*/
/*
* 1. If x = 256l, output "integer too large " and stop.
*/
int j = (x.bitLength() + 7) / 8;
if (l == -1)
{
l = j;
}
if ((j > l) || (x.signum() == -1))
{
throw new IllegalBlockSizeException("Block too large");
}
/*
* 2. Write the integer x in its unique l-digit representation
* base 256: x = xl- 1 256^ (l- 1) + xl -2 256 256^(l -2) + ...& +
x1 256 + x0
* where 0 = xi < 256 (note that one or more leading digits
* will be zero if x < 256^ (l- 1)).
*/
byte[] C = x.toByteArray();
/*
* remove the leading zeros
*/
int index = 0;
for (; (index < C.length) && (C[index] == 0); index++);
if (index > 0)
{
byte[] temp = new byte[C.length - index];
System.arraycopy(C, index, temp, 0, temp.length);
C = temp;
}
else if (C.length > l)
{
throw new IllegalBlockSizeException("Block too large");
}
/*
* 3. Let the octet Xi have the value xl -i for 1 = i = l.
* Output the octet string X = X1 X2 & ... Xl.
*/
if (C.length == l)
{
return C;
}
/*
* C is not long enough
*/
byte[] result = new byte[l];
System.arraycopy(C, 0, result, l - C.length, C.length);
return result;
}
/**
* Method encrypt
* Description: Encrypt with pad
* See PKCS#1
* @param M the plaintext message
*/
private byte[] encrypt(byte[] M)
throws IllegalBlockSizeException
{
/*
* RSA Steps according to PKCS #1 v 2.0 pg 15 for encryption:
* 1. Apply the EME-PKCS1-v1_5 encoding operation (Section 9.1.2.1)
* to the message M to produce an encoded message EM of length k-1
* octets: EM = EME-PKCS1-V1_5-ENCODE (M, k-1)
* If the encoding operation outputs "message too long, ," then
output
* message too long and stop.
*/
int k = params_.getKeysize();
byte[] EM = EME_PKCS1_V1_5_ENCODE(M, k - 1);
/*
* 2. Convert the encoded message EM to an integer message
* representative m: m = OS2IP (EM)
*/
BigInteger m = new BigInteger(1, EM);
/*
* 3. Apply the RSAEP encryption primitive (Section 5.1.1) to the
* public key (n, e) and the message representative m to produce
* an integer ciphertext representative c: c = RSAEP ((n, e), m)
*/
BigInteger c = RSAEP((RSAPublicKey) key_, m);
/*
* 4. Convert the ciphertext representative c to a ciphertext C of
* length k octets: C = I2OSP (c, k)
*/
byte[] C = I2OSP(c, k);
/*
* 5. Output the ciphertext C.
*/
return C;
}
/**
* Method decrypt
* Description: Decrypt with pad
* See PKCS#1
* @param M the ciphertext message
*/
private byte[] decrypt(byte[] C)
throws BadPaddingException, IllegalBlockSizeException
{
/*
* RSA Steps according to PKCS #1 v 2.0 pg 16 for decryption:
* 1. If the length of the ciphertext C is not k octets, output
* decryption error and stop.
*/
int k = params_.getKeysize();
if (k != C.length)
{
throw new IllegalBlockSizeException("decryption error");
}
/*
* 2. Convert the ciphertext C to an integer ciphertext
* representative c: c = OS2IP (C)
*/
BigInteger c = new BigInteger(1, C);
/*
* 3. Apply the RSADP decryption primitive to the private
* key (n, d) and the ciphertext representative c to produce
* an integer message representative m: m = RSADP ((n, d), c)
* If RSADP outputs ciphertext out of range, then output
* decryption error and stop.
*/
BigInteger m = RSADP((RSAPrivateKey) key_, c);
/*
* 4. Convert the message representative m to an encoded message
* EM of length k-1 octets: EM = I2OSP (m, k-1)
* If I2OSP outputs integer too large, then output decryption
* error and stop.
*/
byte[] EM = I2OSP(m, k - 1);
/*
* 5. Apply the EME-PKCS1-v1_5 decoding operation to the encoded
* message EM to recover a message M: M = EME-PKCS1-V1_5-DECODE(EM)
* If the decoding operation outputs decoding error, then output
* decryption error and stop.
*/
byte[] M = EME_PKCS1_V1_5_DECODE(EM);
/*
* 6. Output the message M.
*/
return M;
}
/**
* Method EME_PKCS1_V1_5_ENCODE
* Description: Pad encoding
*
* @param M the ciphertext message
* @param emLen the length of encr message
*
* @return encoded pad
*
* @throws IllegalBlockSizeException
*
*/
private byte[] EME_PKCS1_V1_5_ENCODE(byte[] M, int emLen)
throws IllegalBlockSizeException
{
/*
* Section 9.1.2.1 of PKCS#1v2.0
* 1. If the length of the message M is greater than emLen 10
* octets, output message too long and stop.
*/
if (M.length > emLen - 10)
{
throw new IllegalBlockSizeException("message too long");
}
/*
* 2. Generate an octet string PS of length emLen-||M||-2
* consisting of pseudorandomly generated nonzero octets.
* The length of PS will be at least 8 octets.
*/
byte[] PS =
new byte[(emLen - M.length - 2)];
// Fill the padding string with random non-zero bytes
for (int i = 0; i < PS.length; i++)
{
PS[i] = (byte) (random_.nextInt(255) + 1);
}
/*
* 3. Concatenate PS, the message M, and other padding to
* form the encoded message EM as EM = 02 || PS || 00 || M
*/
byte[] EM = new byte[emLen];
int index = 0;
EM[index++] = (byte) 0x02;
for (int i = 0; i < PS.length; i++)
{
EM[index++] = PS[i];
}
EM[index++] = (byte) 0x00;
for (int i = 0; i < M.length; i++)
{
EM[index++] = M[i];
}
/*
* 4. Output EM.
*/
return EM;
}
/**
* Method EME_PKCS1_V1_5_DECODE
* Description: Pad decoding
*
* @param EM the encrypted message
*
* @return pad
*
* @throws BadPaddingException
*
*/
private byte[] EME_PKCS1_V1_5_DECODE(byte[] EM)
throws BadPaddingException
{
/*
* Section 9.1.2.2 of PKCS#1v2.0
* 1. If the length of the encoded
* message EM is less than 10, output decoding error
* and stop.
*/
if (EM.length < 10)
{
throw new BadPaddingException("message too short");
}
/*
* 2. Separate the encoded message EM into an octet string PS
* consisting of nonzero octets and a message M as
* EM = 02 || PS || 00 || M. If the first octet of EM is not 02,
* or if there is no 00 octet to separate PS from M,
* output decoding error and stop.
*/
if (EM[0] != (byte) 0x02)
{
throw new BadPaddingException(
"message not formatted properly");
}
// Need to start by looking for the first non-zero byte
int start = 0;
while (EM[start] != (byte) 0x00)
{
start++;
if (start >= EM.length)
{
throw new BadPaddingException("bad padding");
}
}
start++; // Ignore the first 00
/*
* 3. If the length of PS is less than 8 octets,
* output decoding error and stop.
*/
if (start < 10)
{
throw new BadPaddingException("bad padding");
}
byte[] M = new byte[EM.length - start];
System.arraycopy(EM, start, M, 0, M.length);
/*
* 4. Output M.
*/
return M;
}
/**
* Method RSEAP
* Description: Performs the encryyrption
*
* @param publicKey the RSA public key
* @param m the plaintext integer
*
* @return the ciphertext integer
*
* @throws IllegalBlockSizeException
*
*/
private BigInteger RSAEP(RSAPublicKey publicKey, BigInteger m)
throws IllegalBlockSizeException
{
/*
* RSAEP ((n, e), m)
* Input: (n, e) RSA public key
* m message representative, an integer between 0 and n-1
* Output: c ciphertext representative, an integer between 0 and
* n-1; or message representative out of range
* Assumptions: public key (n, e) is valid
*/
BigInteger e = publicKey.getPublicExponent();
BigInteger n = publicKey.getModulus();
/*
* 1. If the message representative m is not between 0 and n-1,
* output message representative out of range and stop.
*/
BigInteger nMinusOne = n.subtract(BigInteger.ONE);
/*
* m > 0 and m < n-1
*/
if (m.compareTo(BigInteger.ZERO) < 0)
{
throw new IllegalBlockSizeException(
"Ciphertext too small");
}
if (m.compareTo(nMinusOne) > 0)
{
throw new IllegalBlockSizeException(
"Ciphertext too large");
}
/*
* 2. Let c = me mod n.
*/
BigInteger c = m.modPow(e, n);
/*
* 3. Output c.
*/
return c;
}
/**
* Method RSADP
* Description: Performs the decryption
*
* @param K the RSA Private Key
* @param c an integer representing
* the cipher
*
* @return the plaintext integer
*
*/
private BigInteger RSADP(RSAPrivateKey K,
BigInteger c)
{
/*
* RSADP (K, c)
* Input: K RSA private key, where K has one of the following
* forms: a pair (n, d)
* a quintuple (p, q, dP, dQ, qInv)
* c ciphertext representative, an integer between 0 and n-1
* Output: m message representative, an integer between 0 and n-1;
or
* ciphertext representative out of range
* Assumptions: private key K is valid
* Steps:
* 1. If the ciphertext representative c is not between 0 and n-1,
* output ciphertext representative out of range and stop.
*/
/*
* 2.1 Let m = cd mod n.
* PKCS #1 V2.0: RSA CRYPTOGRAPHY STANDARD 9
* Else, if the second form (p, q, dP, dQ, qInv) of K is used:
*/
if (!(K instanceof RSAPrivateCrtKey))
{
BigInteger d = K.getPrivateExponent();
BigInteger n = K.getModulus();
BigInteger m = c.modPow(d, n);
return m;
}
/*
* 2. If the first form (n, d) of K is used:
*/
RSAPrivateCrtKey privateCrtKey =
(RSAPrivateCrtKey) K;
BigInteger p = privateCrtKey.getPrimeP();
BigInteger q = privateCrtKey.getPrimeQ();
BigInteger dP =
privateCrtKey.getPrimeExponentP();
BigInteger dQ =
privateCrtKey.getPrimeExponentQ();
BigInteger qInv =
privateCrtKey.getCrtCoefficient();
/*
* 2.2 Let m1 = cdP mod p.
*/
BigInteger m1 = c.modPow(dP, p);
/*
* 2.3 Let m2 = cdQ mod q.
*/
BigInteger m2 = c.modPow(dQ, q);
/*
* 2.4 Let h = qInv ( m1 m2 ) mod p.
*/
BigInteger h = m1.subtract(m2);
h = h.multiply(qInv);
h = h.mod(p);
/*
* 2.5 Let m = m2 + h q.
*/
BigInteger m = h.multiply(q);
m = m.add(m2);
/*
* 3. Output m.
*/
return m;
}
}
Thursday, February 4, 2010
Listing
Listing 1: The RichDSA class: The DSA Signature sample application
package com.richware.chap11;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import javax.crypto.interfaces.*;
import java.security.spec.*;
import java.math.BigInteger;
import java.io.*;
/**
* Class RichDSA
* Description: This is an example
* implementation of the DSA
* algorithm.
*
* Copyright: Copyright (c) 2002 Wiley Publishing, Inc.
* @author Rich Helton
* @version 1.0
* DISCLAIMER: Please refer to the disclaimer at the beginning of this book.
*/
public class RichDSA
{
/* the key length */
private int l_ = 1024;
/* the private key */
private BigInteger x_;
/* the public key */
private BigInteger y_;
/* the DSA parameters, see spec */
/* h is used to generate g */
private BigInteger h_;
private BigInteger p_;
private BigInteger q_;
private BigInteger g_;
/* q bit length */
int qBitLength_ = 160;
/* the SHA1 message digest */
private MessageDigest md_;
/* To debug or not to debug */
private final boolean DEBUG = false;
/* The certainty, that the generated numbers are prime. */
private final int CERTAINTY = 80;
/* The secure random generator */
private SecureRandom secureRandom_;
/* BigInteger Constants */
private static final BigInteger ZERO =
BigInteger.valueOf(0L);
private static final BigInteger ONE =
BigInteger.valueOf(1L);
private static final BigInteger TWO =
BigInteger.valueOf(2L);
/**
* Constructor RichDSA
*
*
*/
public RichDSA()
{
initKeys();
}
/**
* Method initKeys
*/
public void initKeys()
{
BigInteger x, c, qMultTwo;
try
{
md_ = MessageDigest.getInstance("SHA1");
if (secureRandom_ == null)
{
secureRandom_ = new SecureRandom();
}
int counter = 0;
boolean primesFound = false;
while (!primesFound)
{
counter = 0;
/*
* Calculate Q
*/
q_ = new BigInteger(qBitLength_, CERTAINTY,
secureRandom_);
while ((counter <>
{
/*
* q must be a divisor of p
* h ^ ((p-1) / q) mod p
* and p being prime are a
* must. X will be shifted to try
* another random and tested for prime.
* See DSA Spec.
* Appendix 2 and 3.
*/
x = reseedX();
qMultTwo = q_.multiply(TWO);
c = x.mod(qMultTwo);
/*
* Calculate P
*/
p_ = x.subtract(c.subtract(ONE));
/*
* If P is long enough and is prime,
* use it
*/
if (p_.bitLength() >= (l_))
{
if (DEBUG)
{
System.out.println("Counter :" + counter);
}
/*
* P must be prime to quit
*/
if (p_.isProbablePrime(CERTAINTY))
{
primesFound = true;
}
}
counter++;
}
}
/*
* Calculate H
*/
boolean hFound = false;
while (!hFound)
{
h_ = new BigInteger(l_, secureRandom_);
if ((h_.compareTo(ONE) > 0)
|| (h_.compareTo(p_.subtract(ONE)) <>
{
hFound = true;
}
}
/*
* Generate G, the generator
*/
BigInteger pMinusOneOverQ = p_.subtract(ONE).divide(q_);
boolean gFound = false;
while (!gFound)
{
g_ = h_.modPow(pMinusOneOverQ, p_);
if (g_.compareTo(ONE) > 0)
{
gFound = true;
}
}
/*
* Generate X, the private key
*/
x_ = new BigInteger(qBitLength_ - 1, secureRandom_);
while ((x_.compareTo(BigInteger.ZERO)) == 0)
{
x_ = new BigInteger(qBitLength_ - 1, secureRandom_);
}
/*
* Generate Y, the public key
*/
y_ = g_.modPow(x_, p_);
/*
* If DEBUG, print the results
*/
if (DEBUG)
{
System.out.println();
System.out.println("p_ :" + p_);
System.out.println();
System.out.println("q_ :" + q_);
System.out.println();
System.out.println("x_ :" + x_);
System.out.println();
System.out.println("y_ :" + y_);
System.out.println();
System.out.println("g_ :" + g_);
System.out.println();
System.out.println("h_ :" + h_);
}
}
/*
* Catches
*/
catch (Exception ex)
{
ex.printStackTrace();
}
}
/**
* Method reseedX
* Description reseed X by shifting
*
* @return a new random X
*
*/
private BigInteger reseedX()
{
byte[] shiftBytes = new byte[(l_ / 8)];
secureRandom_.nextBytes(shiftBytes);
shiftBytes[0] = (byte) (shiftBytes[0] | 128);
return (new BigInteger(1, shiftBytes));
}
/**
* Method sign
* Description: return the
* signature
* @return mostly r and s
*
*/
public byte[] sign()
{
try
{
/*
* Calculate the digest, number
*/
byte[] digest = md_.digest();
BigInteger m = new BigInteger(1, digest);
/*
* Generate k, a random number
* 0 <>
*/
BigInteger k = new BigInteger(qBitLength_ - 1,
secureRandom_);
while (k.compareTo(q_) >= 0)
{
k = new BigInteger(qBitLength_ - 1, secureRandom_);
}
/*
* Inverse of K
*/
BigInteger kInv = k.modInverse(q_);
/*
* r = (g ^ k mod p) mod q
*/
BigInteger r = (g_.modPow(k, p_)).mod(q_);
/*
* s = (k ^ -1(SHA(M) +xr)) mod q
*/
BigInteger s =
kInv.multiply((m.add(x_.multiply(r)))).mod(q_);
/*
* If DEBUG, print the results
*/
if (DEBUG)
{
System.out.println();
System.out.println("sign:r :" + r);
System.out.println();
System.out.println("sign:s :" + s);
System.out.println();
System.out.println("sign:m :" + m);
}
/*
* Put r and s in a buffer
* with some magic numbers
* to check for corruption
*/
byte[] rdata = r.toByteArray();
byte[] sdata = s.toByteArray();
byte[] data = new byte[6 + rdata.length + sdata.length];
int i = 0;
/*
* Put first magic number
*/
data[i++] = 0x40;
/*
* Put in length
*/
data[i++] = (byte) (data.length - 2);
/*
* Put in Separator
*/
data[i++] = 0x02;
/*
* Put in r length
*/
data[i++] = (byte) (rdata.length);
/*
* Put r in buffer
*/
for (int j = 0; j <>
{
data[i++] = rdata[j];
}
/*
* Put in sepaerator
*/
data[i++] = 0x02;
/*
* Put in s length
*/
data[i++] = (byte) (sdata.length);
/*
* Put s in buffer
*/
for (int j = 0; j <>
{
data[i++] = sdata[j];
}
return data;
}
/*
* Catches
*/
catch (Exception ex)
{
ex.printStackTrace();
}
return null;
}
/**
* Method update
* Description : uppdate the hash
*
* @param b the bytes
* @param offset the offset
* @param len the length
*
* @throws SignatureException
*
*/
public void update(byte[] b, int offset, int len)
throws SignatureException
{
md_.update(b, offset, len);
if (DEBUG)
{
System.out.println();
System.out.println("update:Length:" + len);
}
}
/**
* Method verify
* @param data
*
* @return
*
*/
public boolean verify(byte[] data)
{
try
{
int i = 0;
/*
* Check for the first
* magic number,
* the length
* and separator
*/
if ((data[i++] != 0x40)
|| (data[i++] != data.length - 2)
|| (data[i++] != 0x02))
{
throw new SignatureException(
"Corrupted signature data");
}
/*
* Check r length
*/
byte len = data[i++];
if (len > 21)
{
throw new SignatureException(
"Corrupted signature data");
}
/*
* Get the r buffer
*/
byte[] rdata = new byte[len];
for (int j = 0; j <>
{
rdata[j] = data[i++];
}
/*
* Check separator
*/
if (data[i++] != 0x02)
{
throw new SignatureException(
"Corrupted signature data");
}
/*
* Check s length
*/
len = data[i++];
if (len > 21)
{
throw new SignatureException(
"Corrupted signature data");
}
/*
* Get the s buffer
*/
byte[] sdata = new byte[len];
for (int j = 0; j <>
{
sdata[j] = data[i++];
}
/*
* Get r and s from Buffer
*/
BigInteger r = new BigInteger(rdata);
BigInteger s = new BigInteger(sdata);
/*
* reject the signature, if r or s >= q
*/
if ((r.compareTo(q_) >= 0) || (s.compareTo(q_) >= 0))
{
return false;
}
/*
* Get the hash value,number
*/
byte[] digest = md_.digest();
BigInteger m = new BigInteger(1, digest);
/*
* w = (S^-1) mod q
*/
BigInteger w = s.modInverse(q_);
/*
* u1 = ((SHA(M)w) mod q
*/
BigInteger u1 = m.multiply(w).mod(q_);
/*
* u2 = ((r)w) mod q
*/
BigInteger u2 = r.multiply(w).mod(q_);
if (DEBUG)
{
System.out.println();
System.out.println("verify:r :" + r);
System.out.println();
System.out.println("verify:s :" + s);
System.out.println();
System.out.println("verify:m :" + m);
System.out.println();
System.out.println("verify:w :" + w);
System.out.println();
System.out.println("verify:u1 :" + u1);
System.out.println();
System.out.println("verify:u2 :" + u2);
System.out.println();
System.out.println("verify:g :" + g_);
System.out.println();
System.out.println("verify:p :" + p_);
System.out.println();
System.out.println("verify:q :" + q_);
System.out.println();
System.out.println("verify:y :" + y_);
}
BigInteger gu1 = g_.modPow(u1, p_);
BigInteger yu2 = y_.modPow(u2, p_);
/*
* v = (((g)^ul (y) ^u2 ) mod p) mod q
*/
BigInteger v = gu1.multiply(yu2).mod(p_).mod(q_);
return v.equals(r);
}
/*
* Catches
*/
catch (Exception ex)
{
ex.printStackTrace();
}
return false;
}
/**
* Method main
* Description: This is a test driver
*
*
* @param args none
*
*/
public static void main(String[] args)
{
try
{
String localDirectory = System.getProperty("user.dir");
System.out.println("Changing directory to Chapter 11");
System.setProperty("user.dir",localDirectory +
"\\com\\richware\\chap11\\");
localDirectory = System.getProperty("user.dir");
String localFile = localDirectory + args[0];
System.out.println("Openining Chapter 11 plus the file as an
argument: " + localFile);
System.out.println("Initializing Keys... This could take several
minutes....");
/*
* Start the homegrown signer
* it automatically
* generates the keys
*/
RichDSA dsa = new RichDSA();
/*
* Start the JDK version
*/
/*
* Generate the Keypair
* get the private Key
* get the public Key
*/
KeyPairGenerator kpg =
KeyPairGenerator.getInstance("DSA");
SecureRandom r = new SecureRandom();
kpg.initialize(1024, r);
KeyPair kp = kpg.genKeyPair();
PrivateKey privKey = kp.getPrivate();
PublicKey pubKey = kp.getPublic();
/*
* Construct a sign
* and verify Signature
* If the same Signature
* class is used for both
* sign and verify in the same context
* might cause some problems
*/
Signature dsaSign =
Signature.getInstance("SHA1withDSA", "SUN");
Signature dsaVerify =
Signature.getInstance("SHA1withDSA", "SUN");
/*
* Init a sign
* with private Key
* and verify with
* a public Key
*/
dsaSign.initSign(privKey);
dsaVerify.initVerify(pubKey);
/*
* Open a File
* and read the text
*/
File inputTextFile =
new File(localFile);
FileInputStream fis =
new FileInputStream(inputTextFile);
BufferedInputStream bis =
new BufferedInputStream(fis);
byte[] buff =
new byte[(int) inputTextFile.length()];
int len;
/*
* Loop through the File
* pass the date through
* update method for
* hashing
*/
while (bis.available() != 0)
{
len = bis.read(buff);
dsa.update(buff, 0, len);
dsaSign.update(buff, 0, len);
}
/*
* Close the file
*/
bis.close();
fis.close();
/*
* Get the signatures
* the signature and public Key bytes
* are normally written to file
*/
byte[] text_signature = dsa.sign();
byte[] jdk_signature = dsaSign.sign();
/*
* Open a File
* and read the text
*/
inputTextFile = new File(localFile);
fis = new FileInputStream(inputTextFile);
bis = new BufferedInputStream(fis);
buff = new byte[(int) inputTextFile.length()];
/*
* Loop through the File
* pass the date through
* update method for
* hashing
*/
while (bis.available() != 0)
{
len = bis.read(buff);
dsa.update(buff, 0, len);
dsaVerify.update(buff, 0, len);
}
/*
* Verify with hash
* public key and
* signatures
*/
boolean verifies = dsa.verify(text_signature);
boolean jdk_verifies = dsaVerify.verify(jdk_signature);
System.out.println("RichDSA Verify : " + verifies);
System.out.println("JDK Verify : " + jdk_verifies);
/*
* Close the file
*/
bis.close();
fis.close();
}
/*
* Catches
*/
catch (Exception ex)
{
ex.printStackTrace();
}
}
}
Subscribe to:
Posts (Atom)
Search This Blog
Followers
Blog Archive
About Me
- Lohit Seth
- Hello Friends Lohit here. if u wanna know me then go to my orkut page and add me http://www.orkut.co.in/Main#Profile?rl=ls&uid=15846901972849568761