You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@shiro.apache.org by Tauren Mills <ta...@groovee.com> on 2011/04/05 13:53:02 UTC

Padding problems with Crypto

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

Re: Padding problems with Crypto

Posted by Tauren Mills <ta...@groovee.com>.
Les,


> Glad to help!
>
> And the idea about using this to seed a crypto chapter is a great
> idea.  I would have liked to have gotten to this earlier, but there
> are only 24 hours in a day :/  (Just a side note for anyone reading
> this, anyone can contribute to documentation by logging in to the ASF
> Confluence wiki and contributing pages or attaching text to a Jira
> issue).
>

I totally understand! I'm working night and day to meet a deadline and wish
there were more hours in the day. If things slow down, I'll see if I can
help out on the wiki. But don't hold your breath, as running a startup
pretty much takes everything I've got. I really do want to figure out a way
to give back to all the great open source projects that I use (including
Shiro), but time is the one asset that is most difficult to find.


> Also, our discussion has given me some ideas.  For example,
> SimpleByteSource(String foo) only does one thing - it converts the
> input (non-encoded) string into bytes (i.e.
> CodecSupport.toBytes(unencodedString)).
>
> Maybe we can add some heuristics to it where we check the argument,
> and if Base64.isBase64(rawStringBytes)  or Hex.isHex(stringRawBytes)
> we can decode the string first.  Otherwise, we use the String as
> supplied.  That might eliminate many decoding confusion issues.
>
> I also thought of a ByteSource.Builder inner class to build ByteSource
> instances instead of forcing an implementation class
> (SimpleByteSource) on end-users.
>

These sound like great ideas. I had hinted previously that the crypto
classes could be enhanced to accept strings and deal with the encoding
internally, but your ideas are even better. It keeps the separation, but
still will make it very easy to use.

My intent was that it would be simple for a user like myself who's only
working with strings to use Shiro's crypto features. Obviously it's better
to fully understand what's going on inside that black box, but sometimes I
just want to trust that the box does what it claims and use it without a
full understanding of encoding and crypto.

I'm thankful for your explanations, as I now understand the internals
better. I think that the documentation should certainly include these
explanations.

Thanks,
Tauren



> This has been helpful for me too! ;)
>
> Thanks,
>
> Les
>
> On Fri, Apr 8, 2011 at 12:26 AM, Tauren Mills <ta...@groovee.com> wrote:
> > Les,
> > I wanted to thank you for your help with all this. I'm now successfully
> > encrypting and decrypting values that I can get and set to my persistence
> > system as string values. Your assistance was invaluable, and the
> information
> > in this thread might be a nice start to the Shiro crypto user manual.
> > Thanks again,
> > Tauren
> >
> > On Tue, Apr 5, 2011 at 11:59 PM, Les Hazlewood <lh...@apache.org>
> > wrote:
> >>
> >> Finally, I think a lot of your frustration can be cleared up by 2
> >> simple guidelines:
> >>
> >> 1.  You shouldn't ever really need to call aString.getBytes() or
> >> aByteSource.getBytes().
> >>
> >> 2.  If you need bytes-->string or string-->bytes behavior (reading
> >> from files or the database and vice versa), you can do that simply:
> >>
> >> a.  bytes --> string:  aByteSource.toBase64();
> >> b.  string --> bytes:  Base64.decode(base64EncodedString);
> >>
> >> Those two things should probably get you all you need.  Anything else
> >> will probably just cause confusion.
> >>
> >> HTH,
> >>
> >> Les
>

Re: Padding problems with Crypto

Posted by Les Hazlewood <lh...@apache.org>.
Hi Tauren,

Glad to help!

And the idea about using this to seed a crypto chapter is a great
idea.  I would have liked to have gotten to this earlier, but there
are only 24 hours in a day :/  (Just a side note for anyone reading
this, anyone can contribute to documentation by logging in to the ASF
Confluence wiki and contributing pages or attaching text to a Jira
issue).

Also, our discussion has given me some ideas.  For example,
SimpleByteSource(String foo) only does one thing - it converts the
input (non-encoded) string into bytes (i.e.
CodecSupport.toBytes(unencodedString)).

Maybe we can add some heuristics to it where we check the argument,
and if Base64.isBase64(rawStringBytes)  or Hex.isHex(stringRawBytes)
we can decode the string first.  Otherwise, we use the String as
supplied.  That might eliminate many decoding confusion issues.

I also thought of a ByteSource.Builder inner class to build ByteSource
instances instead of forcing an implementation class
(SimpleByteSource) on end-users.

This has been helpful for me too! ;)

Thanks,

Les

On Fri, Apr 8, 2011 at 12:26 AM, Tauren Mills <ta...@groovee.com> wrote:
> Les,
> I wanted to thank you for your help with all this. I'm now successfully
> encrypting and decrypting values that I can get and set to my persistence
> system as string values. Your assistance was invaluable, and the information
> in this thread might be a nice start to the Shiro crypto user manual.
> Thanks again,
> Tauren
>
> On Tue, Apr 5, 2011 at 11:59 PM, Les Hazlewood <lh...@apache.org>
> wrote:
>>
>> Finally, I think a lot of your frustration can be cleared up by 2
>> simple guidelines:
>>
>> 1.  You shouldn't ever really need to call aString.getBytes() or
>> aByteSource.getBytes().
>>
>> 2.  If you need bytes-->string or string-->bytes behavior (reading
>> from files or the database and vice versa), you can do that simply:
>>
>> a.  bytes --> string:  aByteSource.toBase64();
>> b.  string --> bytes:  Base64.decode(base64EncodedString);
>>
>> Those two things should probably get you all you need.  Anything else
>> will probably just cause confusion.
>>
>> HTH,
>>
>> Les

Re: Padding problems with Crypto

Posted by Tauren Mills <ta...@groovee.com>.
Les,

I wanted to thank you for your help with all this. I'm now successfully
encrypting and decrypting values that I can get and set to my persistence
system as string values. Your assistance was invaluable, and the information
in this thread might be a nice start to the Shiro crypto user manual.

Thanks again,
Tauren


On Tue, Apr 5, 2011 at 11:59 PM, Les Hazlewood <lh...@apache.org>wrote:

> Finally, I think a lot of your frustration can be cleared up by 2
> simple guidelines:
>
> 1.  You shouldn't ever really need to call aString.getBytes() or
> aByteSource.getBytes().
>
> 2.  If you need bytes-->string or string-->bytes behavior (reading
> from files or the database and vice versa), you can do that simply:
>
> a.  bytes --> string:  aByteSource.toBase64();
> b.  string --> bytes:  Base64.decode(base64EncodedString);
>
> Those two things should probably get you all you need.  Anything else
> will probably just cause confusion.
>
> HTH,
>
> Les
>

Re: Padding problems with Crypto

Posted by Les Hazlewood <lh...@apache.org>.
Finally, I think a lot of your frustration can be cleared up by 2
simple guidelines:

1.  You shouldn't ever really need to call aString.getBytes() or
aByteSource.getBytes().

2.  If you need bytes-->string or string-->bytes behavior (reading
from files or the database and vice versa), you can do that simply:

a.  bytes --> string:  aByteSource.toBase64();
b.  string --> bytes:  Base64.decode(base64EncodedString);

Those two things should probably get you all you need.  Anything else
will probably just cause confusion.

HTH,

Les

Re: Padding problems with Crypto

Posted by Les Hazlewood <lh...@apache.org>.
> System.out.println(new
> SimpleByteSource(Base64.decode(decrypted.getBytes())).toString());

I think you're getting encryption/decryption mixed with
encoding/decoding - they are different operations.

For example, the 'decrypted' variable above represents decrypted
bytes.  Decrypted bytes are not encoded bytes.  So calling
Base64.decode(decryptedBytes) will fail - you're trying to decode
('un' encode) something that is not encoded.

There are 3 things at play here, and I think you're mixing them
together, and it is causing erroneous results and frustration (don't
worry, this confuses a lot of people, so you're definitely not alone
here).  Here are the 3 things:

1.  Encryption/Decryption operations have no 'knowledge' of of
encoding/decoding (like Base64 or Hex).  They take in byte arrays (or
byte streams) and spit out byte arrays (or byte streams).

2.  Once a CipherService spits out a byte array, those bytes can be
_anything_ - literally a mix of 1s and 0s that make no sense at all
(which is good crypto).   But because totally seemingly random bytes
can't necessarily be printed to strings so people can see them,
something needs to ensure all those 1s and 0s can be converted into a
byte array that can be printed into strings.  Base64 is one way of
transforming random-seeming bytes into a character-friendly byte set
(Hex is another way).

3.  Once you have character-friendly bytes, the JDK needs to know how
you want those bytes transferred into Unicode characters.  By default
Shiro specifies UTF-8 to guarantee portability.  If you used, say,
someString.getBytes() (instead of someString.getBytes("UTF-8")), you
let Java default to the platform-specific character set.  This will
cause problems for Shiro since it expects UTF-8 always.

Steps 2 and 3 (and their reverse) are hidden for Shiro end users if
you use the Base64.encode(unencodedBytes) and
Base64.decode(base64EncodedString) methods respectively.

Users should never have to worry about the CodecSupport helper methods
if they're using the API this way.

Does this help at all?

Cheers,

Les

P.S.  I know this stuff can be confusing.  Take a breather, relax and
maybe take a mental break.  If you keep slamming your head against the
monitor, maybe it's time to grab a cup of coffee or something :)

Re: Padding problems with Crypto

Posted by Tauren Mills <ta...@groovee.com>.
By the way, I figured out how to convert to a string. Thanks for all your
help. I think I'm finally set! I wasn't aware of CodecSupport, which is very
handy!

CodecSupport.toString(decrypted.getBytes());

Tauren


On Tue, Apr 5, 2011 at 7:44 PM, Tauren Mills <ta...@groovee.com> wrote:

> Would it make sense to enhance Shiro's encrypt and decrypt to handle all of
> these conversions internally? Basically, have a version of encrypt and
> decrypt that can accept and output normal Strings, base64 strings, byte
> arrays, etc.?
>
> Having not needed to do much in the past with encoding or encrypting,
> dealing with this is not my strong point. I'm sure this is the case for lots
> of people out there. It would be nice if Shiro handled most of the work and
> made it even simpler to use the API.
>
> I would think that many people would have similar use cases to mine:
>
> * My key is pulled from persistence somewhere as a string
> * My user enters a credit card into a UI and I get it as a string
> * I encrypt the value with my key and want to store it as a string in the
> DB
> * I pull the string from the DB to decrypt it
> * I send a string of the card value to the card processor
>
>  Thanks again,
> Tauren
>
>
> On Tue, Apr 5, 2011 at 7:34 PM, Tauren Mills <ta...@groovee.com> wrote:
>
>> Les,
>>
>> Ok, it's making a little more sense now. Thanks.
>>
>> Just to be crystal clear, what is the *right* way to get a String from the
>> value of decrypted in testBlockOperations? The unit test compares the byte
>> arrays to assert true, but never converts the decrypted value back to a
>> string:
>>
>>         assertTrue(Arrays.equals(plaintext, decrypted.getBytes()));
>>
>> The following almost works, but strips all spaces and leaves garbage at
>> the end:
>>
>>     System.out.println(new
>> SimpleByteSource(Base64.decode(decrypted.getBytes())).toString());
>>
>> Thanks,
>> Tauren
>>
>>
>> On Tue, Apr 5, 2011 at 7:20 PM, Les Hazlewood <lh...@apache.org>wrote:
>>
>>> > 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.
>>>
>>> To clarify this a bit more, think of it this way:
>>>
>>> Base64 really encodes (converts) byte arrays of any type into byte
>>> arrays with a limited byte alphabet.  It is really a byte array ->
>>> byte array mechanism.  That's encoding level 1.
>>>
>>> Once an encoding has been done, the resulting byte array output is
>>> guaranteed to representable in a simple character set.  But Java needs
>>> to know the character set to use.  So this is the byte array -->
>>> String mechanism.  That's encoding level 2.
>>>
>>> Shiro uses UTF-8 for this 2nd level to guarantee the same behavior no
>>> matter what JVM it is deployed in.  If you call aString.getBytes(),
>>> you bypass Shiro's mechanism and use whatever the platform's default
>>> character set is, which is likely to be incorrect.
>>>
>>> I hope that makes more sense!
>>>
>>> --
>>> Les Hazlewood
>>> Founder, Katasoft, Inc.
>>> Application Security Products & Professional Apache Shiro Support and
>>> Training:
>>> http://www.katasoft.com
>>>
>>
>>
>

Re: Padding problems with Crypto

Posted by Tauren Mills <ta...@groovee.com>.
Would it make sense to enhance Shiro's encrypt and decrypt to handle all of
these conversions internally? Basically, have a version of encrypt and
decrypt that can accept and output normal Strings, base64 strings, byte
arrays, etc.?

Having not needed to do much in the past with encoding or encrypting,
dealing with this is not my strong point. I'm sure this is the case for lots
of people out there. It would be nice if Shiro handled most of the work and
made it even simpler to use the API.

I would think that many people would have similar use cases to mine:

* My key is pulled from persistence somewhere as a string
* My user enters a credit card into a UI and I get it as a string
* I encrypt the value with my key and want to store it as a string in the DB
* I pull the string from the DB to decrypt it
* I send a string of the card value to the card processor

Thanks again,
Tauren


On Tue, Apr 5, 2011 at 7:34 PM, Tauren Mills <ta...@groovee.com> wrote:

> Les,
>
> Ok, it's making a little more sense now. Thanks.
>
> Just to be crystal clear, what is the *right* way to get a String from the
> value of decrypted in testBlockOperations? The unit test compares the byte
> arrays to assert true, but never converts the decrypted value back to a
> string:
>
>         assertTrue(Arrays.equals(plaintext, decrypted.getBytes()));
>
> The following almost works, but strips all spaces and leaves garbage at the
> end:
>
>     System.out.println(new
> SimpleByteSource(Base64.decode(decrypted.getBytes())).toString());
>
> Thanks,
> Tauren
>
>
> On Tue, Apr 5, 2011 at 7:20 PM, Les Hazlewood <lh...@apache.org>wrote:
>
>> > 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.
>>
>> To clarify this a bit more, think of it this way:
>>
>> Base64 really encodes (converts) byte arrays of any type into byte
>> arrays with a limited byte alphabet.  It is really a byte array ->
>> byte array mechanism.  That's encoding level 1.
>>
>> Once an encoding has been done, the resulting byte array output is
>> guaranteed to representable in a simple character set.  But Java needs
>> to know the character set to use.  So this is the byte array -->
>> String mechanism.  That's encoding level 2.
>>
>> Shiro uses UTF-8 for this 2nd level to guarantee the same behavior no
>> matter what JVM it is deployed in.  If you call aString.getBytes(),
>> you bypass Shiro's mechanism and use whatever the platform's default
>> character set is, which is likely to be incorrect.
>>
>> I hope that makes more sense!
>>
>> --
>> Les Hazlewood
>> Founder, Katasoft, Inc.
>> Application Security Products & Professional Apache Shiro Support and
>> Training:
>> http://www.katasoft.com
>>
>
>

Re: Padding problems with Crypto

Posted by Tauren Mills <ta...@groovee.com>.
Les,

Ok, it's making a little more sense now. Thanks.

Just to be crystal clear, what is the *right* way to get a String from the
value of decrypted in testBlockOperations? The unit test compares the byte
arrays to assert true, but never converts the decrypted value back to a
string:

        assertTrue(Arrays.equals(plaintext, decrypted.getBytes()));

The following almost works, but strips all spaces and leaves garbage at the
end:

    System.out.println(new
SimpleByteSource(Base64.decode(decrypted.getBytes())).toString());

Thanks,
Tauren


On Tue, Apr 5, 2011 at 7:20 PM, Les Hazlewood <lh...@apache.org> wrote:

> > 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.
>
> To clarify this a bit more, think of it this way:
>
> Base64 really encodes (converts) byte arrays of any type into byte
> arrays with a limited byte alphabet.  It is really a byte array ->
> byte array mechanism.  That's encoding level 1.
>
> Once an encoding has been done, the resulting byte array output is
> guaranteed to representable in a simple character set.  But Java needs
> to know the character set to use.  So this is the byte array -->
> String mechanism.  That's encoding level 2.
>
> Shiro uses UTF-8 for this 2nd level to guarantee the same behavior no
> matter what JVM it is deployed in.  If you call aString.getBytes(),
> you bypass Shiro's mechanism and use whatever the platform's default
> character set is, which is likely to be incorrect.
>
> I hope that makes more sense!
>
> --
> Les Hazlewood
> Founder, Katasoft, Inc.
> Application Security Products & Professional Apache Shiro Support and
> Training:
> http://www.katasoft.com
>

Re: Padding problems with Crypto

Posted by Les Hazlewood <lh...@apache.org>.
> 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.

To clarify this a bit more, think of it this way:

Base64 really encodes (converts) byte arrays of any type into byte
arrays with a limited byte alphabet.  It is really a byte array ->
byte array mechanism.  That's encoding level 1.

Once an encoding has been done, the resulting byte array output is
guaranteed to representable in a simple character set.  But Java needs
to know the character set to use.  So this is the byte array -->
String mechanism.  That's encoding level 2.

Shiro uses UTF-8 for this 2nd level to guarantee the same behavior no
matter what JVM it is deployed in.  If you call aString.getBytes(),
you bypass Shiro's mechanism and use whatever the platform's default
character set is, which is likely to be incorrect.

I hope that makes more sense!

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

Re: Padding problems with Crypto

Posted by Les Hazlewood <lh...@apache.org>.
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 <ta...@groovee.com> 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 <ta...@groovee.com> 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 <ta...@groovee.com> 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

Re: Padding problems with Crypto

Posted by Les Hazlewood <lh...@apache.org>.
Hi Tauren,

Check out Shiro's AesCipherServiceTest:

https://svn.apache.org/repos/asf/shiro/trunk/core/src/test/java/org/apache/shiro/crypto/AesCipherServiceTest.java

How does this differ from your test?

In the meantime, I'll see what happens when I add your test strings to
the string array in the test class.

Cheers,

Les

On Tue, Apr 5, 2011 at 6:04 PM, Tauren Mills <ta...@groovee.com> 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 <ta...@groovee.com> 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 <ta...@groovee.com> 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

Re: Padding problems with Crypto

Posted by Tauren Mills <ta...@groovee.com>.
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 <ta...@groovee.com> 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 <ta...@groovee.com> 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
>>
>>
>>
>

Re: Padding problems with Crypto

Posted by Tauren Mills <ta...@groovee.com>.
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 <ta...@groovee.com> 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
>
>
>