Code with Finding: |
class PublicKeyCryptoClient {
/**
* Implements the authentication protocol on the client side
* is and os are the inputstream and output stream of the Socket
* used to connect to the server
*/
public static KeyNonceBundle clientSideAuth(InputStream is, OutputStream os, PublicKey serverPubK) {
/*Generate a symmetric session key.
* For Blowfish, the default is 128 bit length*/
KeyGenerator kg = null;
try {
kg = KeyGenerator.getInstance("Blowfish");
}
catch (Exception e) {/*algorithm is valid*/}
kg.init(BLOWFISH_KEY_LENGTH);
SecretKey key = kg.generateKey();
byte[] sendkey = key.getEncoded();
if (DEBUG) {
try {
System.out.println("Encoded Key: " + new String(sendkey, "UTF8"));
}
catch (Exception e) {
//cannot happen, correct enc.
}
}
/*Prepare to encrypt a message for the server
* using the server's public key */
Cipher c = null;
try {
c = Cipher.getInstance("RSA");
c.init(Cipher.ENCRYPT_MODE, serverPubK);
}
catch (Exception e) {
System.out.println("Server's Public Key fed is incorrect");
return null;
}
/*Initialize a nonce.
*The sec random num gen. will also be used for ivp*/
SecureRandom sr = null;
try {
sr= SecureRandom.getInstance("SHA1PRNG");
}
catch (Exception e) {/*Valid algorithm*/}
byte[] nonce = new byte[NONCE_LENGTH];
sr.nextBytes(nonce);
if (DEBUG) {
System.out.println("First Nonce created on client side: " + new BigInteger(nonce));
}
/*Construct the first message*/
byte[] firstmsg = new byte[NONCE_LENGTH + BLOWFISH_KEY_LENGTH_BYTES];
System.arraycopy(nonce, 0, firstmsg, 0, NONCE_LENGTH);
System.arraycopy(sendkey, 0, firstmsg, NONCE_LENGTH, BLOWFISH_KEY_LENGTH_BYTES);
byte[] encfirstmsg = null;
/*Encrypt */
try {
encfirstmsg = c.doFinal(firstmsg);
BufferedOutputStream bos = new BufferedOutputStream(os);
bos.write(encfirstmsg);
bos.flush();
}
catch (Exception e) {
System.out.println("Error sending the first message");
return null;
}
if (DEBUG) {
try {
System.out.println("First Message: " + new String(encfirstmsg, "UTF8"));//firstmsgbase64);
}
catch (Exception e) {/*valid enc*/}
}
//Zero out arrays that contained RAW keys
Arrays.fill(sendkey, (byte) 0x00);
Arrays.fill(firstmsg, (byte) 0x00);
/*Receive the second message*/
try {
c = Cipher.getInstance("Blowfish/CFB8/PKCS5Padding");
}
catch (Exception e) {/*Everything is valid*/}
//get ivp from prepend of second msg.
byte[] iv = new byte[8];
try {
int bytesRead = is.read(iv);
while (bytesRead != 8) {
bytesRead += is.read(iv, bytesRead, 8 - bytesRead);
}
}
catch (Exception e) {
System.out.println("Error/Timeout while receiving the second message.");
return null;
}
IvParameterSpec ivp = new IvParameterSpec(iv);
//fetch the actual second message
byte[] secondmsg = new byte[NONCE_LENGTH + NONCE_LENGTH];
try {
c.init(Cipher.DECRYPT_MODE, key, ivp);
CipherInputStream cis = new CipherInputStream(is, c);
int bytesRead = cis.read(secondmsg);
while (bytesRead != NONCE_LENGTH + NONCE_LENGTH) {
System.out.println(bytesRead);
bytesRead += cis.read(secondmsg, bytesRead, NONCE_LENGTH + NONCE_LENGTH - bytesRead);
}
}
catch (Exception e) {
System.out.println("Error/Timeout while receiving the second message.");
return null;
}
if (DEBUG) {
try {
System.out.println("Second msg received: " + new String(secondmsg, "UTF8"));
}
catch (Exception e) {/*Valid enc*/}
}
/*Verify that the first nonce is nonce + 1*/
byte[] recvnonce = new byte[NONCE_LENGTH];
System.arraycopy(secondmsg, 0, recvnonce, 0, NONCE_LENGTH);
BigInteger firstNonceNum = new BigInteger(nonce);
byte[] firstNonceNumPlusOne = firstNonceNum.add(BigInteger.ONE).toByteArray();
byte[] firstNonceNumPlusOneCorrectLen = new byte[NONCE_LENGTH];
System.arraycopy(firstNonceNumPlusOne, 0, firstNonceNumPlusOneCorrectLen, 0, NONCE_LENGTH);
if (!Arrays.equals(recvnonce, firstNonceNumPlusOneCorrectLen)) {
if (DEBUG) {
System.out.println("Failure");
}
return null;
}
else {
/*Calculate second nonce * 2*/
byte[] secondNonce = new byte[NONCE_LENGTH];
System.arraycopy(secondmsg, NONCE_LENGTH, secondNonce, 0, NONCE_LENGTH);
BigInteger secondNonceNum = new BigInteger(secondNonce);
if (DEBUG) {
System.out.println("Second nonce received: " + secondNonceNum);
}
byte[] secondNonceTimesTwo = secondNonceNum.shiftLeft(1).toByteArray();
if (DEBUG) {
System.out.println("Second nonce * 2: " + secondNonceTimesTwo);
}
byte[] secondNonceTimesTwoCorrectLen = new byte[NONCE_LENGTH];
System.arraycopy(secondNonceTimesTwo, 0, secondNonceTimesTwoCorrectLen, 0, NONCE_LENGTH);
byte[] thirdmsg = new byte[NONCE_LENGTH];
System.arraycopy(secondNonceTimesTwoCorrectLen, 0, thirdmsg, 0, NONCE_LENGTH);
//Create a new ivp for this new msg
iv = new byte[8];
sr.nextBytes(iv);
ivp = new IvParameterSpec(iv);
//prepend iv to the msg
try {
os.write(iv);
c.init(Cipher.ENCRYPT_MODE, key, ivp);
CipherOutputStream cos = new CipherOutputStream(new NonClosingCipherOutputStream(os), c);
cos.write(thirdmsg);
cos.flush();
cos.close();
}
catch (Exception e) {
System.out.println("Error/Timeout while sending the third message");
return null;
}
if (DEBUG) {
System.out.println("Success");
}
return new KeyNonceBundle(key, firstNonceNum, secondNonceNum);
}
}
}
|