final project
Project Hints Double Password Authentication
Few things to keep in mind in this exercise (mainly with regards to DataInputStream/DataOutputStream class:
You can use writeUTF to write Strings (readUTF to read) [e.g., out.writeUTF(x)] You can use writeInt, writeDouble, etc. to write Integers and Doubles (readInt,
readDouble) Another way to do is to convert everything to byte arrays and use write. Here you will
need to worry about passing the length information for each value you pass - it may be tedious
As the digest value is a byte array, you may simply want to use write. When you use write to pass a byte array, reading the same array at the server requires you to also know the size of the byte array. So before you pass the digest value, you could pass the length of the byte array that stores the digest value (using writeInt) and then the digest itself. At the other end you can read the length value (using readInt) and then use that to create the byte array that can be used to store the appropriate size of bytes read from the input stream. Here is a sample you could do for the digest value passed.
Client Server
out.writeInt(digestValue.length); out.write(digestValue); out.flush();
//digestValue is of type byte[]
int length = in.readInt(); byte[] protected = new byte[length]; in.readFully(protected);
//reads the number of bytes equal to length of protected
Note that you need to pass the original values (username, time value, etc.) and the digest. At the server you have to re-compute the digest the same way you computed the at the client side using the original values. Then, you need to compare the digest value received from the client with the newly computed digest. Here is one way you can check if the two digests are equal:
MessageDigest.isEqual(recomputedDigest, receivedDigest);
ElGamal Signature
Keys
Create a random prime number p Choose g and d - both less than p Calculate y = g^d mod p Private key is d, public key is (y, g, p)
Signing message m
Choose k that is relatively prime to (p-1) Compute a = g^k mod p Compute b = ((m-da)*k-1) mod (p-1)
Where k-1 is computed as follows: k-1 =k.modInverse(p-1).
Verifying the signature
Check if the following equality holds
(y^a).(a^b) mod p = g^m mod p
Note "(y^a).(a^b) mod p" is equivalent to "[(y^a) mod p] [(a^b) mod p] mod p"
Some issues
Since you are working with BigInteger class - be careful. For instance, to calculate (p-1) (call it pMinusOne), you could do the following
BigInteger pOne = BigInteger.valueOf(1);
BigInteger pMinusOne = p.substract(pOne) // where p is the random number
Note that k should be relatively prime to (p-1)
loop {
BigInteger k = new BigInterger (???); // check existing code of this type
} until k is relatively prime to (p-1)
To check "BigInteger k is relatively prime to BigInteger p" you can do the following:
k.gcd(pMinusOne).equals(pOne) == true;
Cipher
Three things to do here.
1. Generating DES Key
The link provided in the question sheet has information and examples regarding how to create one. Some Classes that you need to understand are
Key and KeyGenerator
check out getInstance(??), init(new SecureRandom()) and generateKey() functions of class KeyGenerator.
2. Storing keys in a file
You could do it a number of ways. Here is one:
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("KeyFile.xx"));
That is, you create an object output stream to an output file name KeyFile.xx.
Since it is an object output stream you can now write the Key object that has your key. Assuming you have
Key k = .... // creates the key using the KeyGenerator object that is using some instance of encryption algorithm, DES here.
out.writeObject(k); // will store your key object in the file.
At the server, you can now do:
Key k = (Key) in.readObject(); // to read from object in which is an ObjectInputStream
You can use an ObjectOutputStream object to also communicate to the server. However, instead of a file (through FileOutputStream), you now need to associate the socket ( it is given) with the ObjectOutputStream object. If s is the Socket object you have created then you can do the following:
ObjectOutputStream outSocket = new ObjectOutputStream(s.getOutputStream());
Note that Socket objects are used to form a communication channel to another machine by associating with it a port and the host address.
2. Cipher - Encrypting and Decrypting and then outputting the digest
To encrypt a message using Cipher class using a DES algorithm you can do the following.
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, k);
This sets the cipher object to Encrypt mode with the specified key k (a Key object). You can do the same two statements in the server to initialize a cipher object to Cipher.DECRYPT_MODE
You can now use the CipherOutputStream (CipherInputStream in server)
Note that in the documentation at the URL provided to you sey the following about the CipherOutputStream class:
A CipherOutputStream is composed of an OutputStream and a Cipher so that write() methods first process the data before writing them out to the underlying OutputStream. The cipher must be fully initialized before being used by a CipherOutputStream.
For example, if the cipher is initialized for encryption, the CipherOutputStream will attempt to encrypt data before writing out the encrypted data.
Hence, you can create a CipherOutputStream object to pass the encrypted value to the server. You can now easily create an CipherOutputStream object:
CipherOutputStream cipherOut = new CipherOutputStream(sSocket, cipher);
Now you can use cipherOut.write(byte []) to send the message encrypted using DES to the server - as cipherOut is now associated with sSocket object. Note that the input to the write function is a byte stream so if you have a String message you need to get the bytes.
On the Server side, you can use "CipherInputStream cipherIn = .." (similar to CipherInputStream) and then use cipherIn.read() to read the message bytes.