Someone asked for a compilable example, so here's the entire thing
(and I'm in North America. Can't you tell from my accent) :
~~~~~~~~~~~~~~~~~~
IQueryString.java
~~~~~~~~~~~~~~~~~~
public interface IQueryString {
int Count ();
String QueryString ();
void Append(String Tag, String Value);
String Item(String Tag);
Boolean Load(String QueryString);
void Reset();
void Update(String Tag, String Value);
}
~~~~~~~~~~~~~~~~
QueryString.java
~~~~~~~~~~~~~~~~
import java.io.*;
import java.util.*;
import java.lang.StringBuilder;
import java.security.*;
import java.net.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import
com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException;
import com.sun.org.apache.xml.internal.security.utils.Base64;
public class QueryString implements IQueryString {
QueryString () throws Exception{
m_objState = new Hashtable<String, String>();
try {
m_objCrypt = Cipher.getInstance("AES/CBC/PKCS5Padding");
m_objDecrypt = Cipher.getInstance("AES/CBC/PKCS5Padding");
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
MessageDigest sha256 = null;
try {
sha256 = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
byte[] theTextToDigestAsBytes =ComputeHash("A Random
String".toLowerCase()).getBytes();
sha256.update(theTextToDigestAsBytes);
byte[] aesKey = sha256.digest();
//printhash(aesKey);
System.out.println("Digest is " + aesKey.length + " bytes long");
// Sets up a 128 bit (16 byte) IV for CBC mode
final int BLOCK_BYTES = 16;
sha256.reset();
byte[] fullSHA = sha256.digest(ComputeHash("3rfdfh6y-34rt-3rkl-9ijh-
mg94kgjdhsg3".toLowerCase()).getBytes());
//printhash(fullSHA);
byte[] aesIV = new byte[BLOCK_BYTES];
System.arraycopy(fullSHA, 0, aesIV, 0, BLOCK_BYTES);
// Set up the IV and two cipher objects, one to encrypt
and
// one to decrypt:
IvParameterSpec aesParameterSpec = new IvParameterSpec
(aesIV);
AlgorithmParameters aesParameters =
AlgorithmParameters.getInstance("AES");
aesParameters.init(aesParameterSpec);
SecretKeySpec aesKeySpec = new SecretKeySpec(aesKey,
0,aesKey.length,"AES");
System.out.println("before the init");
try
{
m_objCrypt.init(Cipher.ENCRYPT_MODE, aesKeySpec, aesParameters);
m_objDecrypt.init(Cipher.DECRYPT_MODE, aesKeySpec, aesParameters);
}
catch (Exception e) {
System.out.println(e.getMessage());
}
}
public int Count() {
return m_objState.size();
}
public String QueryString() {
StringBuilder stbRetval = new StringBuilder();
stbRetval.append(URL_START);
stbRetval.append(HASH_IDENTIFIER);
String strState = StateToLineFormat();
stbRetval.append(ComputeHash(strState));
stbRetval.append(VALUE_IDENTIFIER);
stbRetval.append(EncryptValue(strState));
if (stbRetval.length() >= MAX_QUERY_LENGTH)
{
try {
throw new Exception();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return stbRetval.toString();
}
public void Append(String Tag, String Value) {
if (null == Tag)
{
try {
throw new Exception();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (null == Value)
{
try {
throw new Exception();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
m_objState.put(Tag, Value);
}
public String Item(String Tag) {
String strValue = null;
if (m_objState.containsKey(Tag))
{
strValue = m_objState.get(Tag);
}
else
{
System.out.println("Can't find it");
}
return strValue;
}
public Boolean Load(String QueryString) {
Boolean bolRetval = true;
if (QueryString.length() >= MAX_QUERY_LENGTH)
{
try {
throw new Exception();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (QueryString.contains("&T="))
{
try {
throw new Exception();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try
{
if (false == QueryString.contains(VALUE_IDENTIFIER))
{
try {
throw new Exception();
} catch (Exception e) {
e.printStackTrace();
}
}
if (HASH_IDENTIFIER != QueryString.substring
(0,HASH_IDENTIFIER.length()))
{
try {
throw new Exception();
} catch (Exception e) {
e.printStackTrace();
}
}
String strClientHash = QueryString.substring(HASH_IDENTIFIER.length
(), HASH_LENGTH);
String strClientValue = QueryString.substring(
(HASH_IDENTIFIER.length() + HASH_LENGTH + VALUE_IDENTIFIER.length
())
);
String strDecState = this.DecryptValue( URLDecoder.decode
(strClientValue,"UTF-8"));
String strCompatHash = this.ComputeHash(strDecState);
if (false == strCompatHash.equals(strClientHash))
{
throw new Exception();
}
String [] astrValues = strDecState.split( ";");
for (String strRawValue : astrValues)
{
if (strRawValue.length() > 0)
{
String[] astrReal = strRawValue.split("=");
m_objState.put(astrReal[0], this.LineDecode(astrReal[1]));
}
}
}
catch (Exception ignoreTillWeGetLogLog)
{
bolRetval = false;
}
return bolRetval;
}
public void Reset() {
m_objState.clear();
}
public void Update(String Tag, String Value) {
if (null == Tag)
{
try {
throw new Exception();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
m_objState.remove(Tag);
this.Append(Tag, Value);
}
public String ComputeHash(String ValueStream) {
if (null == ValueStream)
{
try {
throw new Exception();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
MessageDigest sha256 = null;
try {
sha256 = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
byte[] SHA256HASH = sha256.digest(ValueStream.getBytes());
return stringhash(SHA256HASH);
}
public String EncryptValue(String Value) {
String returnValue = null;
if (Value.length() >= MAX_QUERY_LENGTH)
{
try {
throw new Exception();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
byte[] byaRawText = null;
try {
byaRawText = Value.getBytes("US-ASCII");
} catch (UnsupportedEncodingException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
byte[] byaCipherText = null;
try {
byaCipherText = m_objCrypt.doFinal(byaRawText, 0,
byaRawText.length);
} catch (IllegalBlockSizeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BadPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
returnValue = b64encode(byaCipherText);
return returnValue;
}
public String DecryptValue(String EncryptedValue) {
if (EncryptedValue.length() >= MAX_QUERY_LENGTH) {
try {
throw new Exception();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
byte[] abyDecText = null;
try
{
System.out.println("before the decode");
byte[]abyFromBase64=b64decode(EncryptedValue);
System.out.println("before the buffer");
abyDecText = m_objDecrypt.doFinal
(abyFromBase64,0,abyFromBase64.length);
System.out.println("before the queryString");
}
catch (Exception e)
{
System.out.println(e.getMessage());
}
String returnValue = null;
try {
returnValue = new String(abyDecText,"US-ASCII");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return returnValue;
}
/*
public static String b64encodeold(byte[] b) throws
MessagingException,
IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
OutputStream b64os = MimeUtility.encode(baos, "base64");
b64os.write(b);
b64os.close();
System.out.println (new String(baos.toByteArray()));
return new String(baos.toByteArray());
}
*/
public static String b64encode(byte[] bIn)
{
String base64Encoded = new String(Base64.encode(bIn));
return base64Encoded;
}
/*
public static byte[] b64decodeold(String s) throws
MessagingException, IOException {
ByteArrayInputStream bais = new ByteArrayInputStream
(s.getBytes());
InputStream b64is = MimeUtility.decode(bais, "Base64");
byte[] tmp = new byte[s.length()];
int n = b64is.read(tmp);
byte[] res = new byte[n];
System.arraycopy(tmp, 0, res, 0, n);
System.out.println("decode length:"+res.length);
System.out.println("decode:"+byteToString(res));
return res;
}
*/
public static byte[] b64decode(String s) {
byte[] base64decoded = null;
try {
base64decoded = Base64.decode(s);
} catch (Base64DecodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return base64decoded;
}
protected static String byteToString(byte[] myBA){
String btoString = new String(myBA);
return btoString;
}
protected static void listProviders ()
{
Provider[] provider = Security.getProviders();
for (int i = 0; i< provider.length; i++) {
System.out.println("Name : " + provider
.getName());
System.out.println(" Info : " + provider.getServices());
System.out.println
("---------------------------------------------------------------------------");
}
}
protected static void printhash (byte hashdigest[])
{
StringBuffer hexString = new StringBuffer();
for (int i=0;i<hashdigest.length;i++) {
String hex = Integer.toHexString(0xFF & hashdigest);
if(hex.length()==1) hexString.append('0');
hexString.append(hex);
}
System.out.println("HASH: " +hexString.toString());
}
protected String stringhash (byte hashdigest[])
{
StringBuffer hexString = new StringBuffer();
for (int i=0;i<hashdigest.length;i++) {
String hex = Integer.toHexString(0xFF & hashdigest);
if(hex.length()==1) hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
}
protected String LineDecode(String Value)
{
String strRetval = Value;
strRetval = strRetval.replace("%3D", "=");
strRetval = strRetval.replace("%3B", ";");
strRetval = strRetval.replace("%25", "%");
return strRetval;
}
protected String LineEncode(String Value)
{
String strRetval = Value;
strRetval = strRetval.replace("%", "%25");
strRetval = strRetval.replace(";", "%3B");
strRetval = strRetval.replace("=", "%3D");
return strRetval;
}
private String StateToLineFormat() {
String strReturn = "";
Enumeration<String> keys = m_objState.keys();
while ( keys.hasMoreElements() )
{
String key = (String)keys.nextElement();
strReturn += key + "=" + this.LineEncode(m_objState.get(key)) +
";";
}
return strReturn;
}
protected static Cipher m_objCrypt;
protected static Cipher m_objDecrypt;
protected Hashtable<String,String> m_objState;
protected static int MAX_QUERY_LENGTH = 2048;
protected String HASH_IDENTIFIER = "I=";
protected int HASH_LENGTH = 64;
protected String VALUE_IDENTIFIER = "&V=";
protected String URL_START = "?";
}
~~~~~~~~~~~~~~~~~~~~~
QueryStringTest.java
~~~~~~~~~~~~~~~~~~~~~
import java.io.UnsupportedEncodingException;
import junit.framework.Assert;
import org.junit.Before;
import org.junit.Test;
public class QueryStringTest {
public QueryString m_queryString;
@Before
public void setUp(){
try {
m_queryString = new QueryString();
} catch (Exception e) {
System.out.println(e.getMessage()); }
}
@test
public void TestBlankValueComputeHashEqualsDefaultSha256()
{
try {
Assert.assertEquals
("E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
m_queryString.ComputeHash("").toUpperCase());
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
@test
public void TestAppendValue() {
try {
m_queryString.Append("Tag123","123");
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
@test
public void testCount() {
m_queryString.Reset();
m_queryString.Append("Tag123","123");
Assert.assertEquals(1, m_queryString.Count());
}
@test
public void testAppend() {
m_queryString.Reset();
m_queryString.Append("Tag123","123");
Assert.assertEquals(1,m_queryString.Count());
}
@test
public void testItem() {
m_queryString.Reset();
m_queryString.Append("Tag123","123");
Assert.assertEquals("123",m_queryString.Item("Tag123"));
}
@test
public void testReset() {
m_queryString.Reset();
m_queryString.Append("Tag123","123");
Assert.assertEquals(1, m_queryString.Count());
m_queryString.Reset();
Assert.assertEquals(0, m_queryString.Count());
}
@test
public void testUpdate() {
m_queryString.Update("Tag123","123");
m_queryString.Update("Tag123","456");
Assert.assertEquals("456",m_queryString.Item("Tag123"));
}
@test
public void testComputeHash() {
Assert.assertEquals
("fa3444fa161e2610e4c1273ccbc572f5091de6550b53581d5044ec80b1ff4064",m_queryString.ComputeHash
("A Random String"));
}
@test
public void testEncryptValue() {
Assert.assertEquals("jU5JuAVxi3isKWf6SJ9CJA==",
m_queryString.EncryptValue("Secret"));
}
@test
public void testDecryptValue() {
Assert.assertEquals("Secret", m_queryString.DecryptValue
("jU5JuAVxi3isKWf6SJ9CJA=="));
}
@test
public void testBase64Encode() throws UnsupportedEncodingException {
byte[] btoEncode = "EncodeMe".getBytes("US-ASCII");
Assert.assertEquals("RW5jb2RlTWU=", m_queryString.b64encode
(btoEncode));
}
@test
public void testBase64Decode() {
Assert.assertEquals("EncodeMe", new String(m_queryString.b64decode
("RW5jb2RlTWU=")));
}
}