Ah.  I think I found it.

The following lines are incorrect:

// Setup
byte[] bytes = Base64.decode(appkey.getBytes());
...
// Decrypt result
byte[] decoded = Base64.decode(result1.getBytes())

appkey and result1 are UTF-8-encoded Strings of base64-encoded byte
arrays: i.e. there are two levels of encoding going on here - one for
base64 and another encoding for the String itself.  When you call
String#getBytes(), the JDK will return the bytes of that string using
the platform's default encoding character set.  Shiro instead
explicitly uses UTF-8 for guaranteed behavior.

The Base64 class will use the UTF-8 charset as required.  So you just
need to instead call Base64.decode(appkey) and Base64.decode(result1).

HTH!

Cheers,

-- 
Les Hazlewood
Founder, Katasoft, Inc.
Application Security Products & Professional Apache Shiro Support and Training:
http://www.katasoft.com

On Tue, Apr 5, 2011 at 6:04 PM, Tauren Mills <[email protected]> wrote:
> Sorry to bring this up again, but unfortunately my solution only works for
> strings that are exactly 16 characters long. I'm not sure what I'm doing
> wrong. This seems like it should be so simple...
> public class CryptoTest {
> private static final String appkey = "sA1FGmFsXUHwPXrJOyWYfA==";
> private static final String value16 = "ABCDEFGHIJKLMNOP";
> private static final String value8 = "ABCDEFGH";
> private static final String value13a = "4007000000027";
> private static final String value13b = "4007000000027   ";
> private static final String value13c = "4007000000027...";
> private static final String value13d = "4007000000027XXX";
> public static void main(String[] args) {
> doIt(value8);
> doIt(value16);
> doIt(value13a);
> doIt(value13b);
> doIt(value13c);
> doIt(value13d);
> }
> private static void doIt(String value) {
> System.out.println("-----------");
> System.out.println("Original Value: "+value);
> System.out.println("Original Value length: "+value.length());
> // Setup
> AesCipherService cipherService = new AesCipherService();
> byte[] bytes = Base64.decode(appkey.getBytes());
> try {
> // Encrypt value
> ByteSource encrypted = cipherService.encrypt(value.getBytes(), bytes);
> String result1 = encrypted.toBase64();
> System.out.println("Encrypted: "+result1);
> System.out.println("Encrypted length: "+result1.length());
> // Decrypt result
> byte[] decoded = Base64.decode(result1.getBytes());
> System.out.println("Decoded length: "+decoded.length);
> System.out.println("Decoded: "+new SimpleByteSource(decoded).toString());
> ByteSource decrypted = cipherService.decrypt(decoded, bytes);
> System.out.println("Decrypted: "+new
> SimpleByteSource(Base64.decode(decrypted.getBytes())).toString());
>  } catch (CryptoException e) {
> e.printStackTrace();
> }
> }
> }
> This produces the following output:
> -----------
> Original Value: ABCDEFGH
> Original Value length: 8
> Encrypted: DARMjklfVRyLoD1irf0apGStAymsKOEHR1/muvhwbag=
> Encrypted length: 44
> Decoded length: 32
> Decoded: DARMjklfVRyLoD1irf0apGStAymsKOEHR1/muvhwbag=
> Decrypted: ABCDEFGH
> -----------
> Original Value: ABCDEFGHIJKLMNOP
> Original Value length: 16
> Encrypted: 9ODpJ68Krm7PcjlvD7MVjmBefjijw6BTV1DWtt2mfqJxn6wccIRrs6hvV1/CWycr
> Encrypted length: 64
> Decoded length: 48
> Decoded: 9ODpJ68Krm7PcjlvD7MVjmBefjijw6BTV1DWtt2mfqJxn6wccIRrs6hvV1/CWycr
> Decrypted: ABCDEFGHIJKLMNOP
> -----------
> Original Value: 4007000000027
> Original Value length: 13
> Encrypted: g5KGBx/79z6e/CapGmVhAbApmxpZ+v2+xcChw+bQrrE=
> Encrypted length: 44
> Decoded length: 32
> Decoded: g5KGBx/79z6e/CapGmVhAbApmxpZ+v2+xcChw+bQrrE=
> Decrypted: 400700000002AA==
> -----------
> Original Value: 4007000000027
> Original Value length: 16
> Encrypted: qtX3ct7uVg11kZqwGiPK0JB5wi5E40+I3kHpk3bOcHu3n/cxPd/b5q8dE0CRM7aX
> Encrypted length: 64
> Decoded length: 48
> Decoded: qtX3ct7uVg11kZqwGiPK0JB5wi5E40+I3kHpk3bOcHu3n/cxPd/b5q8dE0CRM7aX
> Decrypted: 400700000002AA==
> -----------
> Original Value: 4007000000027...
> Original Value length: 16
> Encrypted: 6RdBKnJDxOMVjvQoMu6UHfZ/ZOLoEVB+lBfoBySKSax+Ivv49fA3zUhIos4LWsXG
> Encrypted length: 64
> Decoded length: 48
> Decoded: 6RdBKnJDxOMVjvQoMu6UHfZ/ZOLoEVB+lBfoBySKSax+Ivv49fA3zUhIos4LWsXG
> Decrypted: 400700000002AA==
> -----------
> Original Value: 4007000000027XXX
> Original Value length: 16
> Encrypted: heR4cKiGBuXOUWqzsTS+oy3X0ygVcc8z2iqUv+rSf79sozT00csoepRDklSXx36+
> Encrypted length: 64
> Decoded length: 48
> Decoded: heR4cKiGBuXOUWqzsTS+oy3X0ygVcc8z2iqUv+rSf79sozT00csoepRDklSXx36+
> Decrypted: 4007000000027XXX
> The weird thing is that strings of numbers or letters that are 8 or 16
> characters long work. But if the string is 13 characters long and padded
> with spaces or periods to make it 16 long, it still doesn't work right.
> What's going on? I'm feeling quite stupid right now, hopefully someone can
> clear it all up for me.
>
> Thanks!
> Tauren
>
> On Tue, Apr 5, 2011 at 5:41 AM, Tauren Mills <[email protected]> wrote:
>>
>> Never mind, and sorry for the noise. I should stop working all night and
>> get some sleep.
>> I had forgotten to do a Base64.decode() before decrypting. Once I added
>> that, it works a whole lot better!
>> Tauren
>>
>> On Tue, Apr 5, 2011 at 4:53 AM, Tauren Mills <[email protected]> wrote:
>>>
>>> I finally got around to testing out some crypto code and am having
>>> CryptoExceptions thrown when decrypting. The problem seems to be with
>>> padding. I was under the assumption that Shiro took care of all that for me.
>>> If not, how do I solve this?
>>> import org.apache.shiro.codec.Base64;
>>> import org.apache.shiro.crypto.AesCipherService;
>>> import org.apache.shiro.crypto.CryptoException;
>>> import org.apache.shiro.util.ByteSource;
>>> public class CryptoTest {
>>> private static final String appkey = "sA1FGmFsXUHwPXrJOyWYfA==";
>>> private static final String value16 = "ABCDEFGHIJKLMNOP";
>>> private static final String value8 = "ABCDEFGH";
>>> public static void main(String[] args) {
>>> try {
>>> doIt(value8);
>>> } catch (CryptoException e) {
>>> e.printStackTrace();
>>> }
>>> System.out.println("-----------");
>>> try {
>>> doIt(value16);
>>> } catch (CryptoException e) {
>>> e.printStackTrace();
>>> }
>>> }
>>> private static void doIt(String value) throws CryptoException {
>>> System.out.println("Value: "+value);
>>> System.out.println("Value length: "+value.length());
>>> // Setup
>>> AesCipherService cipherService = new AesCipherService();
>>> byte[] bytes = Base64.decode(appkey.getBytes());
>>> // Encrypt value
>>> ByteSource encrypted = cipherService.encrypt(value.getBytes(), bytes);
>>> String result1 = encrypted.toBase64();
>>> System.out.println("Encrypted: "+result1);
>>> System.out.println("Encrypted length: "+result1.length());
>>> // Decrypt result
>>> ByteSource decrypted = cipherService.decrypt(result1.getBytes(), bytes);
>>> String result2 = decrypted.toString();
>>> System.out.println("Decrypted: "+result2);
>>> System.out.println("Decrypted length: "+result2.length());
>>> }
>>> }
>>> This produces the following output:
>>> Value: ABCDEFGH
>>> Value length: 8
>>> Encrypted: +LZxy50cDjd8UFanLoNLa8yvw6ctNLRGJsY4BzDIM8s=
>>> Encrypted length: 44
>>> -----------
>>> Value: ABCDEFGHIJKLMNOP
>>> Value length: 16
>>> Encrypted:
>>> fgc/8DUeyt7wQkO/TS3SNwaTOVU3swTMaMHMm3mQ05jge77vrXlrxQYNoqPey1wg
>>> Encrypted length: 64
>>> org.apache.shiro.crypto.CryptoException: Unable to execute 'doFinal' with
>>> cipher instance [javax.crypto.Cipher@17386918].
>>> at
>>> org.apache.shiro.crypto.JcaCipherService.crypt(JcaCipherService.java:464)
>>> at
>>> org.apache.shiro.crypto.JcaCipherService.crypt(JcaCipherService.java:447)
>>> at
>>> org.apache.shiro.crypto.JcaCipherService.decrypt(JcaCipherService.java:392)
>>> at
>>> org.apache.shiro.crypto.JcaCipherService.decrypt(JcaCipherService.java:384)
>>> at com.sprtz.test.CryptoTest.doIt(CryptoTest.java:61)
>>> at com.sprtz.test.CryptoTest.main(CryptoTest.java:17)
>>> Caused by: javax.crypto.IllegalBlockSizeException: Input length must be
>>> multiple of 16 when decrypting with padded cipher
>>> at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
>>> at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
>>> at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..)
>>> at javax.crypto.Cipher.doFinal(DashoA13*..)
>>> at
>>> org.apache.shiro.crypto.JcaCipherService.crypt(JcaCipherService.java:461)
>>> ... 5 more
>>> org.apache.shiro.crypto.CryptoException: Unable to execute 'doFinal' with
>>> cipher instance [javax.crypto.Cipher@787bb290].
>>> at
>>> org.apache.shiro.crypto.JcaCipherService.crypt(JcaCipherService.java:464)
>>> at
>>> org.apache.shiro.crypto.JcaCipherService.crypt(JcaCipherService.java:447)
>>> at
>>> org.apache.shiro.crypto.JcaCipherService.decrypt(JcaCipherService.java:392)
>>> at
>>> org.apache.shiro.crypto.JcaCipherService.decrypt(JcaCipherService.java:384)
>>> at com.sprtz.test.CryptoTest.doIt(CryptoTest.java:61)
>>> at com.sprtz.test.CryptoTest.main(CryptoTest.java:25)
>>> Caused by: javax.crypto.BadPaddingException: Given final block not
>>> properly padded
>>> at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
>>> at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
>>> at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..)
>>> at javax.crypto.Cipher.doFinal(DashoA13*..)
>>> at
>>> org.apache.shiro.crypto.JcaCipherService.crypt(JcaCipherService.java:461)
>>> ... 5 more
>>> The code seems fairly straight forward. Notice the exceptions are
>>> different based on the length of the value to encrypt/decrypt.
>>> I'm using 128bit AES since I don't have the extras installed. Any
>>> thoughts on what I am doing wrong?
>>> Thanks,
>>> Tauren

Reply via email to