// RSA public key decryption test // // Login server which expects an RSA-encrypted array argument // containing: "username:password", 0, seed, 0 ... 0 // where seed is a 20-byte array used to initialize a SecureRandom // sequence generator. // // R. Perry, July 1998 import java.security.*; import java.io.*; import java.net.InetAddress; import java.rmi.*; import java.rmi.server.*; import java.rmi.registry.LocateRegistry; import java.security.Cipher; import cryptix.provider.rsa.*; import cryptix.util.core.Hex; import sequence.Sequence; public class LoginServer extends UnicastRemoteObject implements Login { private PrivateKey sk; // RSA private key, used to decrypt the login array private boolean authenticated = false; // set true after user is authenticated private Sequence seq = null; // SecureRandom sequence generator public LoginServer( PrivateKey sk) throws java.rmi.RemoteException { super(); this.sk = sk; } public boolean login( byte[] b_in) throws java.rmi.RemoteException, java.rmi.server.ServerNotActiveException, java.security.NoSuchAlgorithmException, java.security.KeyException, javax.crypto.NoSuchPaddingException, javax.crypto.IllegalBlockSizeException, javax.crypto.BadPaddingException, java.security.NoSuchProviderException { // ToDo: hosts.allow restrictions for ClientHost // System.out.println( "LoginServer: login(): called from " + this.getClientHost()); // can't allow more than one authentication for this process, // otherwise a snooper could replay someone elses login() call. // if( authenticated) { System.out.println( "LoginServer: login(): already authenticated"); return false; } // System.out.println( "LoginServer: this.toString = " + this.toString()); // System.out.println( "LoginServer: ref.toString = " + this.ref.toString()); // System.out.println( "LoginServer: ref.remoteToString = " + this.ref.remoteToString()); // setup for decryption // System.out.println( "LoginServer: calling Cipher.getInstance"); Cipher c = Cipher.getInstance( "RSA"); c.initDecrypt( sk); // c.init( Cipher.DECRYPT, sk); if( b_in == null) { System.out.println( "LoginServer: input array is null"); return false; } if( b_in.length != c.getCiphertextBlockSize()) { System.out.println( "LoginServer: input array size (" + b_in.length + ") != ciphertext block size (" + c.getCiphertextBlockSize() + ")"); return false; } // perform decryption // byte[] b_out = c.crypt( b_in); // byte[] b_out = c.doFinal( b_in); System.out.print( "LoginServer: decrypted message: "); int i_seed = -1; // start index of seed array in b_out byte[] seed = new byte[20]; // SecureRandom seed for( int i = 0; i < b_out.length; ++i) if( b_out[i] == 0) { i_seed = i + 1; break; } else // print the decrypted message for testing/debugging only. // This should be the client username:password and should NOT // be printed/logged in a production version of this code. // System.out.print( (char) b_out[i]); System.out.println(); // System.out.println( "LoginServer: message in hex: " + Hex.toString( b_out)); if( i_seed < 0 || i_seed + 20 > b_out.length) { System.out.println( "LoginServer: bad i_seed = " + i_seed); return false; } // setup sequence seed // for( int i = 0; i < 20; ++i) seed[i] = b_out[i_seed++]; seq = new Sequence( seed); authenticated = true; // really need to do password lookup here... return authenticated; } /* * verify: returns true if authenticated is true and seqnum matches the * expected next SecureRandom sequence number; otherwise returns false. */ public boolean verify( long seqnum) { if( seq == null) { System.out.println( "LoginServer: verify(): seq is null"); return false; } boolean c = seq.compare( seqnum); System.out.println( "LoginServer: seq.compare() = " + c + ", authenticated = " + authenticated); if( authenticated && c) return true; else return false; } }