org.logi.crypto.keys
Class RSAKey

java.lang.Object
  |
  +--org.logi.crypto.Crypto
        |
        +--org.logi.crypto.keys.K
              |
              +--org.logi.crypto.keys.RSAKey
All Implemented Interfaces:
BlindSignatureKey, CipherKey, Key, PrettyPrintable, SignatureKey

public class RSAKey
extends K
implements CipherKey, SignatureKey, BlindSignatureKey

An instance of this class handles a single RSA key.

The RSA algorithm is probably the best known and most widely used public key algorithm. Breaking one RSA key is believed to be as difficult as factoring the modulus (n) of the group in which calculations are done. When speaking of the size of an RSA key, it is understood to be the size of this modulus.

The first 512 bit number is expected to be factored by the end of 1999. 1024 bits should be more than enough in most cases, but the clinically paranoid may want to use up to 4096 bit keys.

Each RSA key is a pair (d,n) of integers and matches another key (e,n). If P is a block of plain data represented as an integer smaller than n, then it can be encrypted with the transformation:

E = (P^e) mod n
which has the inverse transformation:
P = (E^d) mod n

The keys' owner will keep (d,n) secret and publish (e,n) as widely as possible. This allows anyone who gets hold of the public key to encrypt data which can only be decrypted with the corresponding private key. All public keys generated with this package will use the exponent 65537.

Data that is encrypted with a private key can similarly only be decrypted with the corresponding public key. This is useful for digital signatures.

When P is created from an array of bytes, it will correspond to as many bytes of plain data as the bytes needed to store n, less one. When encrypting less than a full block of data, the data should be put in the most significant bytes of the plaintext-block and appended with random data. This is done by all relevant classes in the logi.crypto library. The plaintext block is encrypted to form a ciphertext block with as many bytes as are needed to store the modulus.

Note that since signing is the same operation as decryption, you should not sign data from an unknown source with a key also used for decrypting information without hashing it first. I.e. when implementing a system always perform the hashing in a process trusted by the owner of the key, or in speciali circumstances where you wish to sign unknown data, create a separate RSA key-pair for this. This implementation was originally done from a description given in Gallian's Contemporary Abstract Algebra, but various changes from various sources have been incorporated.

When a key-pair is created, the private key will actually be an instance of the RSAKeyChin class, which uses the Chinese Remainder Theorem to speed up exponentiation.

The CDS for the RSAKey class is RSAKey(r,n,pub) for a public key, RSAKey(r,n,pri) for a private key or RSAKey(r,n,p) for a private key where we know one factor of n. In all cases r, n and p are hexadecimal numbers.

Author:
Logi Ragnarsson (logir@logi.org)
See Also:
Crypto.fromString(String)

Fields inherited from class org.logi.crypto.Crypto
BIT, cdsPath, EMPTY_ARRAY, FOUR, keySource, NIBBLE, ONE, primeCertainty, random, TWO, ZERO
 
Constructor Summary
RSAKey(java.math.BigInteger r, java.math.BigInteger n, boolean pri)
          Create a new RSA key (r,n).
 
Method Summary
 BlindFingerprint blind(Fingerprint fp, BlindingFactor bf)
          Blind a fingerprint with a public key and the given blinding factor in preparation for blindly signing the fingerprint with the private key.
 int cipherBlockSize()
          Returns the size of the blocks that can be decrypted in one call to decrypt().
 BlindingFactor createBlindingFactor()
          Create a new blinding factor suitable for blinding a fingerprint before being signed with the private key in the pair.
static KeyPair createKeys(java.math.BigInteger r, java.math.BigInteger s, java.math.BigInteger n)
          Create a KeyPair object holding objects for the public RSA key (r,n) and the private RSA key (s,n).
static KeyPair createKeys(int bitLength)
          Create a pair of public/private keys.
static KeyPair createKeys(java.lang.String username, java.lang.String password, java.lang.String hashFunction, int bitLength)
          Create a pair of public/private keys from a username/password pair.
 void decrypt(byte[] source, int i, byte[] dest, int j)
          Decrypt one block of data.
 void encrypt(byte[] source, int i, byte[] dest, int j)
          Encrypt one block of data.
 boolean equals(java.lang.Object o)
          Return true iff the two keys are equivalent.
static java.math.BigInteger findPrime(java.math.BigInteger start)
          Returns the largest prime p <= start
 java.lang.String getAlgorithm()
          The name of the algorithm is "RSA".
 java.math.BigInteger getExponent()
          Return the RSA exponent.
 java.math.BigInteger getModulus()
          Return the RSA modulus.
 int getSize()
          Return the size of the key modulo in bits.
 boolean isPrivate()
          Return true iff this is a private key.
 boolean matches(Key key)
          Check if a key mathces this.
static RSAKey parseCDS(java.lang.String[] param)
          Used by Crypto.fromString when parsing a CDS.
 int plainBlockSize()
          Returns the size of the blocks that can be encrypted in one call to encrypt().
 void prettyPrint(java.io.PrintWriter out, int ind, int rec)
          Print this object to out, indented with ind tabs, going down at most rec levels of recursion.
 BlindSignature sign(BlindFingerprint fp)
          Create a signature for a blinded fingerprint with a private key.
 Signature sign(Fingerprint fp)
          Create a signature for a Fingerprint with a private key.
 int signatureSize()
          Returns the length of the signature in bytes.
 int signBlockSize()
          Returns the maximum size in bytes of the fingerprint that can be signed.
 java.lang.String toString()
          Return a CDS for this key.
 Signature unBlind(BlindSignature bs, BlindingFactor bf)
          Unblind a blind signature using the same blinding factor that was used to blind the original fingerprint.
 boolean verify(Signature s, Fingerprint fp)
          Verify a Signature on a Fingerprint with a public key.
 
Methods inherited from class org.logi.crypto.keys.K
getFingerprint, getFingerprint, hashCode, matchFingerprint, matchFingerprint
 
Methods inherited from class org.logi.crypto.Crypto
binString, binString, ensureArrayLength, ensureArrayLength, equal, equalRelaxed, equalSub, fromHexNibble, fromHexString, fromString, fromString, hexString, hexString, hexString, hexString, hexString, initRandom, initRandom, makeClass, makeInt, makeLong, makeSessionKey, pastSpace, pickBits, pickBits, prettyPrint, readBlock, readInt, trimArrayLength, trimArrayLength, trimLeadingZeroes, writeBytes, writeBytes, writeInt
 
Methods inherited from class java.lang.Object
getClass, notify, notifyAll, wait, wait, wait
 
Methods inherited from interface org.logi.crypto.keys.Key
getFingerprint, getFingerprint, hashCode, matchFingerprint, matchFingerprint
 
Methods inherited from interface org.logi.crypto.PrettyPrintable
prettyPrint
 

Constructor Detail

RSAKey

public RSAKey(java.math.BigInteger r,
              java.math.BigInteger n,
              boolean pri)
Create a new RSA key (r,n). It is a private key if pri is true.
Method Detail

parseCDS

public static RSAKey parseCDS(java.lang.String[] param)
                       throws InvalidCDSException
Used by Crypto.fromString when parsing a CDS.

A valid CDS can be created by calling the toString() method.

Throws:
InvalidCDSException - if the CDS is malformed.
See Also:
Crypto.fromString(String)

findPrime

public static java.math.BigInteger findPrime(java.math.BigInteger start)
Returns the largest prime p <= start

createKeys

public static KeyPair createKeys(int bitLength)
Create a pair of public/private keys. The key modulo will be bitLength or bitLength-1 bits.

createKeys

public static KeyPair createKeys(java.lang.String username,
                                 java.lang.String password,
                                 java.lang.String hashFunction,
                                 int bitLength)
                          throws InvalidCDSException
Create a pair of public/private keys from a username/password pair. The public exponent will be 65536 and the private exponent will have bitLength or bitLength-1 bits.

The keys are created by hashing the password, appending with 0's until it is bitLength bits long and searching for a prime pby counting down from there. Another prime q is found in the same way, but the username is prepended to the password before hashing. Key-generation proceeds as normally from there.

The hashFunction parameters directs which hash function to use. It must be the name of a supported hash function, such as MD5 or SHA1.

The username does not need to be secret and can in fact be a fixed string. It plays a similar role as SALT in unix password systems in protecting against dictionary attacks.

Throws:
InvalidCDSException - if the specified hash function is not available.

createKeys

public static KeyPair createKeys(java.math.BigInteger r,
                                 java.math.BigInteger s,
                                 java.math.BigInteger n)
                          throws KeyException
Create a KeyPair object holding objects for the public RSA key (r,n) and the private RSA key (s,n).
Throws:
KeyException - if (r,n) and (s,n) does not describe a valid pair of RSA keys.

getSize

public int getSize()
Return the size of the key modulo in bits.
Specified by:
getSize in interface Key

getAlgorithm

public java.lang.String getAlgorithm()
The name of the algorithm is "RSA".
Specified by:
getAlgorithm in interface Key

getExponent

public java.math.BigInteger getExponent()
Return the RSA exponent.

getModulus

public java.math.BigInteger getModulus()
Return the RSA modulus.

isPrivate

public boolean isPrivate()
Return true iff this is a private key.
Specified by:
isPrivate in interface Key

toString

public java.lang.String toString()
Return a CDS for this key.
Overrides:
toString in class java.lang.Object
See Also:
Crypto.fromString(java.io.Reader)

prettyPrint

public void prettyPrint(java.io.PrintWriter out,
                        int ind,
                        int rec)
                 throws java.io.IOException
Print this object to out, indented with ind tabs, going down at most rec levels of recursion.
Specified by:
prettyPrint in interface PrettyPrintable
Overrides:
prettyPrint in class Crypto

equals

public boolean equals(java.lang.Object o)
Return true iff the two keys are equivalent.
Overrides:
equals in class java.lang.Object

matches

public final boolean matches(Key key)
Check if a key mathces this. This is true if this and key are a matched pair of public/private keys.
Specified by:
matches in interface Key

plainBlockSize

public int plainBlockSize()
Returns the size of the blocks that can be encrypted in one call to encrypt(). For RSA keys this depends on the size of the key.
Specified by:
plainBlockSize in interface CipherKey

cipherBlockSize

public int cipherBlockSize()
Returns the size of the blocks that can be decrypted in one call to decrypt(). For RSA keys this depends on the size of the key.
Specified by:
cipherBlockSize in interface CipherKey

encrypt

public void encrypt(byte[] source,
                    int i,
                    byte[] dest,
                    int j)
Encrypt one block of data. The plaintext is taken from source starting at offset i and ciphertext is written to dest, starting at offset j.

The amount of data read and written will match the values returned by plainBlockSize() and cipherBlockSize().

Specified by:
encrypt in interface CipherKey

decrypt

public void decrypt(byte[] source,
                    int i,
                    byte[] dest,
                    int j)
Decrypt one block of data. The ciphertext is taken from source starting at offset i and plaintext is written to dest, starting at offset j.

The amount of data read and written will match the values returned by cipherBlockSize() and plainBlockSize().

Specified by:
decrypt in interface CipherKey

signBlockSize

public int signBlockSize()
Returns the maximum size in bytes of the fingerprint that can be signed.
Specified by:
signBlockSize in interface SignatureKey

signatureSize

public int signatureSize()
Returns the length of the signature in bytes.
Specified by:
signatureSize in interface SignatureKey

sign

public Signature sign(Fingerprint fp)
               throws KeyException
Create a signature for a Fingerprint with a private key. If fp is a BlindFingerprint, then a BlindSignature will be returned, so in this case the return value can be safely typecast to BlindSignature.
Specified by:
sign in interface SignatureKey
Throws:
KeyException - if the key modulus is shorter than the signature.
KeyException - if this is not a private key

verify

public boolean verify(Signature s,
                      Fingerprint fp)
               throws KeyException
Verify a Signature on a Fingerprint with a public key.

The method returns true iff s is a signature for fp created with the mathcing private key.

Specified by:
verify in interface SignatureKey
Throws:
KeyException - if this is not a public key

createBlindingFactor

public BlindingFactor createBlindingFactor()
Create a new blinding factor suitable for blinding a fingerprint before being signed with the private key in the pair.
Specified by:
createBlindingFactor in interface BlindSignatureKey

blind

public BlindFingerprint blind(Fingerprint fp,
                              BlindingFactor bf)
                       throws KeyException
Blind a fingerprint with a public key and the given blinding factor in preparation for blindly signing the fingerprint with the private key.
Specified by:
blind in interface BlindSignatureKey
Throws:
KeyException - if you try to blind with a private key
KeyException - if the BlindingFactor is not an RSABlindingFactor

sign

public BlindSignature sign(BlindFingerprint fp)
                    throws KeyException
Create a signature for a blinded fingerprint with a private key.
Specified by:
sign in interface BlindSignatureKey
Throws:
KeyException - if there are problems, depending on the implementing class.

unBlind

public Signature unBlind(BlindSignature bs,
                         BlindingFactor bf)
                  throws KeyException
Unblind a blind signature using the same blinding factor that was used to blind the original fingerprint.
Specified by:
unBlind in interface BlindSignatureKey
Throws:
KeyException - if there are problems, depending on the implementing class.


Copyright 1997-2000 Logi Ragnarsson