//============================================================================== // tribble/crypto/RSACipher.java //============================================================================== package tribble.crypto; // System imports import java.lang.String; import java.math.BigInteger; import java.security.InvalidKeyException; import java.security.spec.KeySpec; import java.security.spec.RSAPrivateKeySpec; import java.security.spec.RSAPublicKeySpec; /******************************************************************************* * RSA, an asymmetric (public key) cipher. * *
* RSA was invented in 1978 by Ron Rivest, Adi Shamir, and Leonard Adleman of * Public Key Partners (PKP). Two weeks before the patent for RSA was due to * expire in Sep 2000, PKP placed the algorithm into the public domain. * * * @version API 2, $Revision: 1.5 $ $Date: 2005/09/11 04:22:22 $ * @since 2003-03-17 * @author * David R. Tribble * (david@tribble.com). * *
* Copyright ©2003-2005 by David R. Tribble, all rights reserved. * *
* THIS CODE MAY BE SUBJECT TO U.S. EXPORT RESTRICTIONS, AND SHOULD NOT BE
* EXPORTED OUTSIDE THE BORDERS OF THE UNITED STATES OF AMERICA.
*
*
* Within the confines of the U.S., however, permission is granted to
* freely use and distribute this source code provided that the original
* copyright and authorship notices remain intact.
*/
public final class RSACipher
extends tribble.crypto.AsymmetricCipher
{
// Identification
/** Revision information. */
static final String REV =
"@(#)tribble/crypto/RSACipher.java $Revision: 1.5 $ $Date: 2005/09/11 04:22:22 $\n";
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Constants
/** Encryption modulus (n). */
private static final String ALGORITHM = "RSA";
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Variables
/** Encryption modulus (n). */
private BigInteger m_n;
/** Encryption exponent (e). */
private BigInteger m_e;
/** Modulus length (bytes). */
private int m_modSize;
/** Temporary helper array. */
private byte[] m_u1;
/** Temporary helper array. */
private byte[] m_u2;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Constructors
/***************************************************************************
* Constructor.
*
* @since 1.1, 2003-03-17
*/
public RSACipher()
{
// Initialize
super(ALGORITHM);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Methods
/***************************************************************************
* Retrieve the plaintext block size (in bytes) of this cipher.
*
*
* Due to the nature of the underlying arithmetic of the algorithm used, the * plaintext block size is always one byte shorter than the ciphertext block * size (which is the same size as the modulus). * * @return * The size, in bytes, of the plaintext blocks to use with this cipher. * * @since 1.2, 2003-03-22 * * @see #getCipherBlockSize */ public int getPlainBlockSize() /*const*/ //overriddes tribble.crypto.AsymmetricCipher { return (m_modSize-1); } /*************************************************************************** * Retrieve the ciphertext block size (in bytes) of this cipher. * *
* Due to the nature of the underlying arithmetic of the algorithm used, the * ciphertext block size is the same size as the modulus, and is always one * byte longer than the plaintext block size. * * @return * The size, in bytes, of the ciphertext blocks to use with this cipher. * * @since 1.2, 2003-03-22 * * @see #getPlainBlockSize */ public int getCipherBlockSize() /*const*/ //overriddes tribble.crypto.AsymmetricCipher { return (m_modSize); } /*************************************************************************** * Initialize this cipher. * * @param key * The encryption key for this cipher. * * @param decrypt * If true, this indicates that this cipher is to be initialized for * decrypting, otherwise it is to be initialized for encrypting. * * @see #initialize(KeySpec, boolean) initialize() * @see #clear clear() * * @since 1.5, 2005-07-05 */ protected void initialize(byte[] key, boolean decrypt) throws InvalidKeyException { /*+++INCOMPLETE ...decode key[] into a RSAPublicKeySpec or RSAPrivateKeySpec object; ...might also provide wrapKey() and unWrapKey() methods; ...; +++*/ throw new InvalidKeyException("INCOMPLETE"); } /*************************************************************************** * Initialize this cipher. * * @param key * The asymmetric (public or private) key for this cipher. * This is an RSA public or private key. * * @param decrypt * Specifies that this cipher is to be set up in decryption mode. * * @see #clear clear() * * @since 1.1, 2003-03-20 */ protected void initialize(/*const*/ KeySpec key, boolean decrypt) throws InvalidKeyException //overriddes tribble.crypto.AsymmetricCipher { // Check the key if (key == null) throw new InvalidKeyException("Null key"); // Set the mode m_decrypt = decrypt; // Get the key type if (key instanceof RSAPublicKeySpec) { RSAPublicKeySpec pub; pub = (RSAPublicKeySpec) key; m_n = pub.getModulus(); m_e = pub.getPublicExponent(); } else if (key instanceof RSAPrivateKeySpec) { RSAPrivateKeySpec pri; pri = (RSAPrivateKeySpec) key; m_n = pri.getModulus(); m_e = pri.getPrivateExponent(); } else throw new InvalidKeyException("Key is not PublicKey or PrivateKey"); // Get the size of the modulus, // and thus the plaintext and ciphertext block sizes m_modSize = (m_n.bitLength()+8-1)/8; m_u1 = new byte[m_modSize-1]; m_u2 = new byte[m_modSize]; } /*************************************************************************** * Reset this cipher, wiping all sensitive information. * *
* This method will be called after this cipher object is no longer needed. * It should overwrite any sensitive data contained within this object * (e.g., encryption key schedules). * This cipher object can no longer be used after this method has been * called. * * @see #initialize initialize() * * @since 1.5, 2005-07-07 */ protected void clear() //overrides tribble.crypto.AsymmetricCipher { // Wipe sensitive info for (int i = 0; i < m_u1.length; i++) m_u1[i] = 0x00; for (int i = 0; i < m_u2.length; i++) m_u2[i] = 0x00; m_n = null; m_e = null; } /*************************************************************************** * Encrypt a block of plaintext. * * @param in * A block of bytes to encrypt. * The number of plaintext bytes read from the block is the length returned * by {@link #getPlainBlockSize}. * * @param inOff * The index of the first byte of array in to encrypt. * * @param out * An array that will be filled with the encrypted bytes. * The number of ciphertext bytes written to the block is the length returned * by {@link #getCipherBlockSize}. * * @param outOff * The index of the first byte of array out to fill. * * @see #blockDecrypt blockDecrypt() * * @since 1.1, 2003-03-20 */ protected void blockEncrypt(byte[] in, int inOff, byte[] out, int outOff) //overriddes tribble.crypto.AsymmetricCipher { BigInteger x; byte[] v; // Prepare the plaintext block System.arraycopy(in, inOff, m_u1, 0, m_modSize-1); x = new BigInteger(+1, m_u1); // Encrypt the plaintext block (c = p**e mod n) x = x.modPow(m_e, m_n); // Extract the encrypted ciphertext block v = x.toByteArray(); if (v.length <= m_modSize) { for (int i = m_modSize - v.length - 1; i >= 0; i--) out[outOff+i] = (byte) 0x00; System.arraycopy(v, 0, out, outOff + m_modSize - v.length, v.length); } else System.arraycopy(v, v.length - m_modSize, out, outOff, m_modSize); // Wipe sensitive info for (int i = 0; i < v.length; i++) v[i] = 0x00; } /*************************************************************************** * Decrypt a block of ciphertext. * * @param in * A block of bytes to decrypt. * The number of ciphertext bytes read from the block is the length returned * by {@link #getCipherBlockSize}. * * @param inOff * The index of the first byte of array in to decrypt. * * @param out * An array that will be filled with the decrypted bytes. * The number of plaintext bytes written to the block is the length returned * by {@link #getPlainBlockSize}. * * @param outOff * The index of the first byte of array out to fill. * * @see #blockEncrypt blockEncrypt() * * @since 1.1, 2003-03-20 */ protected void blockDecrypt(byte[] in, int inOff, byte[] out, int outOff) //overriddes tribble.crypto.AsymmetricCipher { BigInteger x; byte[] v; // Prepare the ciphertext block System.arraycopy(in, inOff, m_u2, 0, m_modSize); x = new BigInteger(+1, m_u2); // Decrypt the ciphertext block (p = c**e mod n) x = x.modPow(m_e, m_n); // Extract the decrypted plaintext block v = x.toByteArray(); if (v.length <= m_modSize-1) { for (int i = m_modSize-1 - v.length - 1; i >= 0; i--) out[outOff+i] = (byte) 0x00; System.arraycopy(v, 0, out, outOff + m_modSize-1 - v.length, v.length); } else System.arraycopy(v, v.length - (m_modSize-1), out, outOff, m_modSize-1); // Wipe sensitive info for (int i = 0; i < v.length; i++) v[i] = 0x00; } } // End RSACipher.java