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;
  }
}