/*
Wireless Java 2nd edition
Jonathan Knudsen
Publisher: Apress
ISBN: 1590590775
*/
import javax.servlet.http.*;
import javax.servlet.*;
import java.io.*;
import java.util.*;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SHA1Digest;
public class PasswordServlet extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
System.out.println("user = " + request.getParameter("user"));
System.out.println("timestamp = " + request.getParameter("timestamp"));
System.out.println("random = " + request.getParameter("random"));
System.out.println("digest = " + request.getParameter("digest"));
// Retrieve the user name.
String user = request.getParameter("user");
// Look up the password for this user.
String password = lookupPassword(user);
// Pull the timestamp and random number (hex encoded) out
// of the request.
String timestamp = request.getParameter("timestamp");
String randomNumber = request.getParameter("random");
// Compare the timestamp with the last saved
// timestamp for this user. Accept only timestamps
// that are greater than the last saved timestamp for this user.
// [not implemented]
// Gather values for the message digest.
byte[] userBytes = user.getBytes();
byte[] timestampBytes = HexCodec.hexToBytes(timestamp);
byte[] randomBytes = HexCodec.hexToBytes(randomNumber);
byte[] passwordBytes = password.getBytes();
// Create the message digest.
Digest digest = new SHA1Digest();
// Calculate the digest value.
digest.update(userBytes, 0, userBytes.length);
digest.update(timestampBytes, 0, timestampBytes.length);
digest.update(randomBytes, 0, randomBytes.length);
digest.update(passwordBytes, 0, passwordBytes.length);
byte[] digestValue = new byte[digest.getDigestSize()];
digest.doFinal(digestValue, 0);
// Now compare the digest values.
String message = "";
String clientDigest = request.getParameter("digest");
if (isEqual(digestValue, HexCodec.hexToBytes(clientDigest)))
message = "User " + user + " logged in.";
else
message = "Login was unsuccessful.";
// Send a response to the client.
response.setContentType("text/plain");
response.setContentLength(message.length());
PrintWriter out = response.getWriter();
out.println(message);
}
private String lookupPassword(String user) {
// Here you could do a real lookup based on the user name.
// You might look in a text file or a database. Here, I
// just use a hardcoded value.
return "happy8";
}
private boolean isEqual(byte[] one, byte[] two) {
if (one.length != two.length) return false;
for (int i = 0; i < one.length; i++)
if (one[i] != two[i]) return false;
return true;
}
}
class HexCodec {
private static final char[] kDigits = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f'
};
public static char[] bytesToHex(byte[] raw) {
int length = raw.length;
char[] hex = new char[length * 2];
for (int i = 0; i < length; i++) {
int value = (raw[i] + 256) % 256;
int highIndex = value >> 4;
int lowIndex = value & 0x0f;
hex[i * 2 + 0] = kDigits[highIndex];
hex[i * 2 + 1] = kDigits[lowIndex];
}
return hex;
}
public static byte[] hexToBytes(char[] hex) {
int length = hex.length / 2;
byte[] raw = new byte[length];
for (int i = 0; i < length; i++) {
int high = Character.digit(hex[i * 2], 16);
int low = Character.digit(hex[i * 2 + 1], 16);
int value = (high << 4) | low;
if (value > 127) value -= 256;
raw[i] = (byte)value;
}
return raw;
}
public static byte[] hexToBytes(String hex) {
return hexToBytes(hex.toCharArray());
}
}