Skip to content

Instantly share code, notes, and snippets.

@rstiller
Created July 26, 2012 13:39
Show Gist options
  • Select an option

  • Save rstiller/3182073 to your computer and use it in GitHub Desktop.

Select an option

Save rstiller/3182073 to your computer and use it in GitHub Desktop.

Revisions

  1. rstiller created this gist Jul 26, 2012.
    99 changes: 99 additions & 0 deletions gistfile1.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,99 @@
    package cooky;

    import java.io.ByteArrayOutputStream;
    import java.util.Arrays;

    import javax.crypto.Mac;
    import javax.crypto.SecretKey;
    import javax.crypto.spec.SecretKeySpec;

    /**
    * HMAC (Key-Hashed Message Authentication Code) http://www.ietf.org/rfc/rfc2104.txt
    * http://www.cse.msu.edu/~alexliu/publications/Cookie/cookie.pdf
    */
    public class CookieEncryption {

    private static final SecretKey SERVER_KEY = new SecretKeySpec("MyServerPassword".getBytes(), "HmacMD5");
    private static final byte SEPARATOR = (byte) ';';

    protected Mac mac;
    protected ByteArrayOutputStream output = new ByteArrayOutputStream();

    public CookieEncryption() throws Exception {
    mac = Mac.getInstance("HmacMD5");
    }

    protected byte[] hmac(final SecretKey key, final byte[]... arrays) throws Exception {
    mac.init(key);
    for (byte[] array : arrays) {
    mac.update(array);
    }
    return mac.doFinal();
    }

    public byte[] generateCookieValue(final byte[] username, final byte[] expiresOn, final byte[] data,
    final byte[] sessionKey) throws Exception {
    SecretKey k = new SecretKeySpec(hmac(SERVER_KEY, username, expiresOn), "HmacMD5");
    byte[] encryptedData = encrypt(data, k);
    byte[] hash = hmac(k, username, expiresOn, data, sessionKey);

    output.reset();
    output.write(username);
    output.write(SEPARATOR);
    output.write(expiresOn);
    output.write(SEPARATOR);
    output.write(encryptedData);
    output.write(SEPARATOR);
    output.write(hash);

    return output.toByteArray();
    }

    private byte[] encrypt(final byte[] data, final SecretKey k) {
    // TODO: do real encryption
    return data;
    }

    private byte[] decrypt(final byte[] data, final SecretKey k) {
    // TODO: do real decryption
    return data;
    }

    public boolean authenticateCookieValue(final byte[] cookieValue, final byte[] sessionKey) throws Exception {
    int[] separators = new int[] {
    -1, -1, -1
    };
    SecretKey k;
    byte[] username;
    byte[] expiresOn;
    byte[] encryptedData;
    byte[] decryptedData;
    byte[] hash;
    byte[] cookieHash;

    for (int i = 0, j = 0; i < cookieValue.length; i++) {
    if (cookieValue[i] == SEPARATOR) {
    separators[j++] = i;
    }
    }

    username = new byte[separators[0]];
    System.arraycopy(cookieValue, 0, username, 0, username.length);

    expiresOn = new byte[separators[1] - separators[0] - 1];
    System.arraycopy(cookieValue, separators[0] + 1, expiresOn, 0, expiresOn.length);

    encryptedData = new byte[separators[2] - separators[1] - 1];
    System.arraycopy(cookieValue, separators[1] + 1, encryptedData, 0, encryptedData.length);

    cookieHash = new byte[cookieValue.length - separators[2] - 1];
    System.arraycopy(cookieValue, separators[2] + 1, cookieHash, 0, cookieHash.length);

    k = new SecretKeySpec(hmac(SERVER_KEY, username, expiresOn), "HmacMD5");
    decryptedData = decrypt(encryptedData, k);
    hash = hmac(k, username, expiresOn, decryptedData, sessionKey);

    return Arrays.equals(hash, cookieHash);
    }

    }