Revision: 684
http://stripes.svn.sourceforge.net/stripes/?rev=684&view=rev
Author: bengunter
Date: 2007-12-13 10:51:44 -0800 (Thu, 13 Dec 2007)
Log Message:
-----------
Fixed STS-459: CryptoUtil should validate its input. A magic number is prefixed
to the result before encryption and checked for upon decryption. In testing
this, I also found that most of the time when a bogus value is fed in to
decrypt it results in a BadPaddingException so I added a try/catch to catch
that and IllegalBlockSizeException. Those cases plus the case of a bogus input
that happens to decrypt properly are logged as a warning and null is returned.
Modified Paths:
--------------
trunk/stripes/src/net/sourceforge/stripes/util/CryptoUtil.java
trunk/tests/src/net/sourceforge/stripes/util/CryptoUtilTest.java
Modified: trunk/stripes/src/net/sourceforge/stripes/util/CryptoUtil.java
===================================================================
--- trunk/stripes/src/net/sourceforge/stripes/util/CryptoUtil.java
2007-12-13 15:45:18 UTC (rev 683)
+++ trunk/stripes/src/net/sourceforge/stripes/util/CryptoUtil.java
2007-12-13 18:51:44 UTC (rev 684)
@@ -16,7 +16,9 @@
import net.sourceforge.stripes.exception.StripesRuntimeException;
+import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.servlet.http.HttpServletRequest;
@@ -38,6 +40,8 @@
* @since Stripes 1.2
*/
public class CryptoUtil {
+ private static final Log log = Log.getInstance(CryptoUtil.class);
+
/** The algorithm that is used to encrypt values. */
public static String ALGORITHM = "AES";
@@ -45,9 +49,16 @@
public static String SESSION_ATTR_SECRET_KEY = "__stripes_secret_key";
/**
+ * Magic number to be prefixed to data before encryption. When a value is
decrypted, the
+ * resulting byte array must begin with the magic number to ensure that it
was encrypted with
+ * the current session key. (The "||" part is because they look like
Stripes.)
+ */
+ public static byte[] MAGIC_NUMBER = new byte[] { Byte.MIN_VALUE,
Byte.MAX_VALUE, '|', '|' };
+
+ /**
* Takes in a String, encrypts it and then base64 encodes the resulting
byte[] so that
* it can be transmitted and stored as a String. Can be decrypted by a
subsequent call
- * to decrypt(String,Request) in the same session.
+ * to [EMAIL PROTECTED] #decrypt(String, HttpServletRequest)} in the same
session.
*
* @param input the String to encrypt and encode
* @param request the current request
@@ -59,7 +70,11 @@
try {
// First encrypt the String with a Cipher
Cipher cipher = getCipher(request, Cipher.ENCRYPT_MODE);
- byte[] output = cipher.doFinal(input.getBytes());
+ byte[] inbytes = input.getBytes();
+ int size = cipher.getOutputSize(MAGIC_NUMBER.length +
inbytes.length);
+ byte[] output = new byte[size];
+ int index = cipher.update(MAGIC_NUMBER, 0, MAGIC_NUMBER.length,
output, 0);
+ cipher.doFinal(inbytes, 0, inbytes.length, output, index);
// Then base64 encode the bytes
return Base64.encodeBytes(output, Base64.URL_SAFE |
Base64.DONT_BREAK_LINES);
@@ -71,7 +86,7 @@
/**
* Takes in a base64 encoded and encrypted String that was generated by a
call
- * to encrypt(String,Request) and decrypts it.
+ * to [EMAIL PROTECTED] #encrypt(String, HttpServletRequest)} and decrypts
it.
*
* @param input the base64 String to decode and decrypt
* @param request the current request
@@ -89,9 +104,28 @@
// Then fetch a cipher and decrypt the bytes
Cipher cipher = getCipher(request, Cipher.DECRYPT_MODE);
- byte[] output = cipher.doFinal(bytes);
+ byte[] output;
+ try {
+ output = cipher.doFinal(bytes);
+ }
+ catch (IllegalBlockSizeException e) {
+ log.warn("Input was not encrypted with the current session key: ",
input);
+ return null;
+ }
+ catch (BadPaddingException e) {
+ log.warn("Input was not encrypted with the current session key: ",
input);
+ return null;
+ }
- return new String(output);
+ // Check for the magic number so we don't eat garbage
+ for (int i = 0; i < MAGIC_NUMBER.length; i++) {
+ if (MAGIC_NUMBER[i] != output[i]) {
+ log.warn("Input was not encrypted with the current session
key: ", input);
+ return null;
+ }
+ }
+
+ return new String(output, MAGIC_NUMBER.length, output.length -
MAGIC_NUMBER.length);
}
/**
Modified: trunk/tests/src/net/sourceforge/stripes/util/CryptoUtilTest.java
===================================================================
--- trunk/tests/src/net/sourceforge/stripes/util/CryptoUtilTest.java
2007-12-13 15:45:18 UTC (rev 683)
+++ trunk/tests/src/net/sourceforge/stripes/util/CryptoUtilTest.java
2007-12-13 18:51:44 UTC (rev 684)
@@ -65,4 +65,11 @@
Assert.assertNull(decrypted, "Decrypting null should give back null.");
}
+
+ @Test(groups = "fast")
+ public void decryptBogusInputTest() throws Exception {
+ String input = CryptoUtil.encrypt("This is bogus!", getRequest());
+ String decrypted = CryptoUtil.decrypt(input, getRequest());
+ Assert.assertNull(decrypted, "Decrypting a bogus input should give
back null.");
+ }
}
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
-------------------------------------------------------------------------
SF.Net email is sponsored by:
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services
for just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
_______________________________________________
Stripes-development mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/stripes-development