class cookie extends ActiveCacheInterface {
private static BigInteger mval;
private static BigInteger eval;
// the main function of the applet
public static int FromCache(String User_HTTP_Request,
String Client_IP_Address,
String Client_Name,
int Cache_File,
int New_File)
{
int status, result;
// is the public
key of the server in ActiveCache or not
boolean keyInCache = is_in_cache("pubkey");
if (!keyInCache) {
// not
in ActiveCache, get it from server, and save it in cache
result = getPubKeyObj();
// get
public key failed, let proxy contact server
if (result == -1) return -1;
}
// read the public
key from object in cache
if (readPubKey() == -1) return -1;
// check the client
request for cookie header and verify signature
status = checkCookie(User_HTTP_Request);
if (status == 1) {
// client
request has cookie header and passed verification
// access
to the cached document granted
return 0;
}
else {
// no
cookie header or signature not correct, access not granted
return -1;
}
}
// get the public key from server and
save to an object in ActiveCache
private static int getPubKeyObj()
{
// send request
to server to get public key
int fd = sendGetReq();
if (fd == -1) return -1;
// save the public
key into an object in ActiveCache
int result = saveGetResult(fd);
return result;
}
// send GET request to server to get
the public key file
// return the file descriptor that
save the response from server
private static int sendGetReq()
{
StringBuffer reqStr = new StringBuffer();
String curDoc, docName;
int fd, pos;
// construct the
url of public key, which is the url of
// the cached document
appended by ".pubkey"
curDoc = curdocurl();
pos = curDoc.indexOf("http://");
if (pos == -1) return -1;
pos = curDoc.indexOf('/', pos+8);
if (pos == -1) return -1;
docName = curDoc.substring(pos);
// reqStr is the
HTTP request to be sent to server
// should be like
GET cached_doc.html.pubkey HTTP/1.0
reqStr.append("GET ").append(docName)
.append(".pubkey").append(" HTTP/1.0\n\n");
// send request
to server getting the object,
// response is saved
in a file, whose file descriptor is fd
fd = send_request_to_server(new String(reqStr));
return fd;
}
// parse the response from server when
proxy get
// the public key file from server,
then save the
// public key contained in the response
into an
// object in ActiveCache. fd is the
file
// which contains the response from
server
private static int saveGetResult(int fd)
{
int num, pos1, pos2, start;
int newfd;
byte buf[];
String line;
// check the response
status, the first line
// of the response
should be HTTP/1.x 200 OK
{
// we
assume the response header from server
// is
no longer than 2048 bytes, read the whole
// response
header into the buffer at once
buf = new byte[2048];
num = read(fd, buf, 2048);
line = new String(buf, 0);
pos1 = line.indexOf(' ');
if (pos1 == -1) {
close(fd);
return -1;
} else {
String status = line.substring(pos1+1,
pos1+4);
if (!status.equals("200"))
return
-1;
}
}
// filter the header
of the response, the header
// ends with \n\n
or \r\n\r\n
{
pos2 = line.indexOf("\n\n", pos1);
if (pos2 != -1) start = pos2
+ 2;
else {
pos2 = line.indexOf("\n\r\n",
pos1);
if (pos2 != -1) start
= pos2 + 3;
else start = -1;
}
}
// if the end of
header not found, there are
// some error in
the response from server, quit
if (start == -1) {
close(fd);
return -1;
}
// now going to
copy the content of the response,
// which is the
public key into an object "pubkey"
newfd = create("pubkey", 00700);
if (newfd == -1) {
close(fd);
return -1;
}
byte[] writebuf = new byte[num-start];
// we need to copy
the bytes into another buffer
// because write
can only write the whole buffer
// into an object
at this moment
byteCopy(buf, start, num-start, writebuf);
// write the part
in the buffer after header into object
write(newfd, writebuf, num-start);
// copy other parts
in the response into object
while ((num = read(fd, buf, 2048)) > 0) {
write(newfd, buf, num);
}
close(fd);
close(newfd);
return 0;
}
// read the public key from the object
in ActiveCache.
// the public key is RSA key. here
we uses two biginteger
// to represent the key. format of
the object is like:
// byte#_of_int1 int1 byte#_of_int2
int2
private static int readPubKey()
{
int num, len1, len2;
int fd = open("pubkey", 0);
if (fd == -1) return -1;
// we currently
assume the size of object is less than 1024
byte[] lbuf = new byte[1024];
num = read(fd, lbuf, 1024);
// the first two
bytes contains the value of length of mval
// now len1 is the
length of mval
len1 = (((lbuf[0]+256)%256) << 8) +
((lbuf[1]+256)%256);
// read mval # of
bytes and create a biginteger from it
byte[] mbuf = new byte[len1];
if (byteCopy(lbuf, 2, len1, mbuf) != len1)
{
close(fd);
return -1;
}
// now mval contains
the value of the first biginteger
mval = new BigInteger(mbuf);
// read the length
of eval
len2 = (((lbuf[len1+2]+256)%256) <<
8) + ((lbuf[len1+3]+256)%256);
// read the value
of eval
byte[] ebuf = new byte[len2];
if (byteCopy(lbuf, len1+4, len2, ebuf) !=
len2) {
close(fd);
return -1;
}
// now eval contains
the value of the second biginteger
eval = new BigInteger(ebuf);
return 0;
}
// parse the cookie header from the
client request, get
// the ID and SIGNATURE, then verify
the signature
public static int checkCookie(String User_HTTP_Request)
{
int pos1, pos2, pos3;
String cookieStr;
String content, signature;
// test whether
cookie string is in the request header
// and extract the
string if exists
pos1 = User_HTTP_Request.indexOf("Cookie:");
if (pos1 == -1) return -1;
// find the end
of line of this cookie header
pos2 = User_HTTP_Request.indexOf("\n", pos1);
pos3 = User_HTTP_Request.indexOf("\r", pos1);
if ((pos3!=-1) && (pos3<pos2))
pos2 = pos3;
if (pos2 == -1) return -1;
// copy this line
of cookie header into cookieStr
cookieStr = User_HTTP_Request.substring(pos1,
pos2);
// check whether
the cookie string contains "ID"
// and extract the
content if exists
pos1 = cookieStr.indexOf("ID=");
if (pos1 == -1) return -1;
// should end with
a "; "
pos2 = cookieStr.indexOf("; ", pos1);
if (pos2 == -1) content = cookieStr.substring(pos1+3);
else content = cookieStr.substring(pos1+3,
pos2);
// check whether
the cookie string contains "signature"
// and extract the
signature if exists
pos1 = cookieStr.indexOf("SIGNATURE=");
if (pos1 == -1) return -1;
// should end with
a "; "
pos2 = cookieStr.indexOf("; ", pos1);
if (pos2 == -1) signature = cookieStr.substring(pos1+10);
else signature = cookieStr.substring(pos1+10,
pos2);
// copy the value
of id to byte array cont
byte[] cont = Convert(content);
// copy the value
of signature to byte array codedsign
byte[] codedsign = Convert(signature);
// since the original
signature may contain bytes > 128
// we encoded the
original signature with uuencode and then
// send it as a
cookie, so the signature we have in cookie
// header is encoded
in uuencode, we now decode it with
// uudecode to the
original signature
byte[] sign = uudecode(codedsign);
// verify the signature
return verifySign(cont, sign);
}
// verify the signature, return 1 if
correct
private static int verifySign(byte[] content, byte[] signature)
{
try {
SHA1_RSA_PKCS1Signature rsa =
new SHA1_RSA_PKCS1Signature();
// now
construct a RSA public key with the public key
// we
get from the server
RawRSAPublicKey rawkey = new
RawRSAPublicKey(mval, eval);
rsa.initVerify(rawkey);
// verify
whether signature is the signature of content
// with
the public key
rsa.update(content);
boolean verifies = rsa.verify(signature);
if (verifies) {
// yes, passed verification
return 1;
}
else {
System.out.println("signature
verified false");
return -1;
}
} catch (InvalidKeyException ike) {
System.out.println("Invalid key
exception");
} catch (InvalidKeyException ike) {
System.out.println("Invalid key
exception");
return -1;
} catch (SignatureException se) {
System.out.println("signature
exception");
return -1;
}
}
// uudecode to decode the encoded signature,
check the
// algorithm of uudecode if you are
more interested in this
private static byte[] uudecode(byte[] d)
{
int i, j;
int len = (d.length/4)*3;
if (d.length%4 == 1) {
System.out.println("error format
of encoded byte array");
return null;
}
if (d.length%4 != 0)
len += (d.length%4 - 1);
byte[] src = new byte[len];
len += (d.length%4 - 1);
byte[] src = new byte[len];
for (i=0, j=0; i+4<=d.length; i+=4, j+=3)
{
src[j] = (byte)((DEC(d[i])<<2)
| (DEC(d[i+1])>>4));
src[j+1] = (byte)((DEC(d[i+1])<<4)
| (DEC(d[i+2])>>2));
src[j+2] = (byte) ((DEC(d[i+2])<<6)
| DEC(d[i+3]));
}
if (d.length-i == 2) {
src[j] = (byte)((DEC(d[i])<<2)
| (DEC(d[i+1])>>4));
} else if (d.length-i == 3) {
src[j] = (byte)((DEC(d[i])<<2)
| (DEC(d[i+1])>>4));
src[j+1] = (byte)((DEC(d[i+1])<<4)
| (DEC(d[i+2])>>2));
}
return src;
}
private static byte DEC(byte c)
{
return (byte)(((c) - ' ') & 077);
}
// copy bytes from b1 starting from
off, length len to a new byte arrary b2
private static int byteCopy(byte[] b1, int off, int len, byte[]
b2)
{
int i, realLen;
if ((off < 0) || (len <= 0)) return
-1;
if (b1.length < off) return -1;
if (b1.length < off+len)
realLen = b1.length - off;
else
realLen = len;
for (i = 0; i < realLen; i++) {
b2[i] = b1[off+i];
}
return realLen;
}
// convert a String to a byte array
private static byte[] Convert(String str)
{
int i;
byte buf[] = new byte[str.length()];
// str.getBytes(0, str.length(), buf, 0);
for (i=0; i<str.length(); i++) {
buf[i] = (byte)(str.charAt(i));
}
return buf;
}
}