You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@shiro.apache.org by jhericks <ja...@jasonerickson.com> on 2012/06/28 07:10:00 UTC

Initialization Vector doesn't appear to be doing it's job for me

I am using the DefaultBlockCipherService with BouncyCastleProvider to do
password based encryption.  The encryption and decryption work great, but
for two unencrypted messages that are only slightly different, almost all of
the encrypted bytes are the same.  I thought that the initialization vector
was supposed to make this not happen, but clearly I am missing something. 
Am I using an algorithm that won't feedback on the initialization vector? Is
there some setting I need to add to the CipherService? BouncyCastleProvider
is not a must, but it's a provider I got to work with PBE and PBE is a
requirement for me.

Here is a class that demonstrates the issue:



--
View this message in context: http://shiro-user.582556.n2.nabble.com/Initialization-Vector-doesn-t-appear-to-be-doing-it-s-job-for-me-tp7577553.html
Sent from the Shiro User mailing list archive at Nabble.com.

Re: Initialization Vector doesn't appear to be doing it's job for me

Posted by jhericks <ja...@jasonerickson.com>.
Here is the sample code again, this time in plain text:


import java.security.Security;

import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;

import org.apache.shiro.crypto.CryptoException;
import org.apache.shiro.crypto.DefaultBlockCipherService;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class TooSimilarDemo {

    private static final String ALGORITHM =
"PBEWITHSHAAND2-KEYTRIPLEDES-CBC";
    private static DefaultBlockCipherService cipherService;
    private static final String SALT =
            "A long, but constant phrase that will be used each time as the
salt.";
    private static final int ITERATIONS = 2000;
    private static final int KEY_LENGTH = 8;
    private static final String PLAIN_LOREM_IPSUM =
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit\n"
                    + "Etiam in sem at dolor tempor volutpat\n"
                    + "Nullam molestie libero nisl, ac sodales turpis\n"
                    + "Maecenas porta nulla quis elit sodales id ultricies
metus vulputate\n"
                    + "Suspendisse ut mi in nisi tempus consectetur\n"
                    + "Etiam vel urna tellus, ut bibendum diam\n"
                    + "Suspendisse hendrerit ipsum vel lectus posuere
faucibus\n"
                    + "Praesent congue faucibus orci, ac suscipit nisi
tincidunt at";

    public static void main(String[] args) throws CryptoException, Exception
{
        Security.addProvider(new BouncyCastleProvider());
        cipherService = new DefaultBlockCipherService(ALGORITHM);
        cipherService.setInitializationVectorSize(64);
        String slightlyChanged =
                new StringBuilder(PLAIN_LOREM_IPSUM).replace(0, 5, "Ipsum")
                        .toString();
        final String passphrase = "secret";
        byte[] encryptedText =
                encryptWithService(passphrase,
PLAIN_LOREM_IPSUM.getBytes());
        byte[] encryptedSlightlyChanged =
                encryptWithService(passphrase, slightlyChanged.getBytes());

        String decryptedPlainText =
                new String(decryptWithService(passphrase, encryptedText));
        String decryptedSlightlyChanged =
                new String(decryptWithService(passphrase,
                        encryptedSlightlyChanged));
        if (!PLAIN_LOREM_IPSUM.equals(decryptedPlainText)) {
            System.err.println(PLAIN_LOREM_IPSUM + " must match "
                    + decryptedPlainText);
        } else if (!slightlyChanged.equals(decryptedSlightlyChanged)) {
            System.err.println(slightlyChanged + " must match "
                    + decryptedSlightlyChanged);
        } else {
            int byteMatchCount = 0;
            for (int i = 0; i < encryptedText.length
                    && i < encryptedSlightlyChanged.length; i++) {
                if (encryptedText[i] == encryptedSlightlyChanged[i]) {
                    byteMatchCount++;
                }
            }
            System.out.println("Everything worked but " + byteMatchCount
                    + " bytes out of " + encryptedText.length
                    + " were the same.  ("
                    + (100.0 * byteMatchCount / encryptedText.length)
                    + " percent)");
        }
    }

    private static byte[] encryptWithService(String passphrase, byte[]
plainText)
            throws CryptoException, Exception {
        return cipherService.encrypt(plainText,
                generateKey(passphrase).getEncoded()).getBytes();

    }

    private static byte[] decryptWithService(String passphrase,
            byte[] cipherText) throws CryptoException, Exception {
        return cipherService.decrypt(cipherText,
                generateKey(passphrase).getEncoded()).getBytes();
    }

    private static SecretKey generateKey(String passphrase) throws Exception
{
        PBEKeySpec keySpec =
                new PBEKeySpec(passphrase.toCharArray(), SALT.getBytes(),
                        ITERATIONS, KEY_LENGTH);
        SecretKeyFactory keyFactory =
SecretKeyFactory.getInstance(ALGORITHM);
        return keyFactory.generateSecret(keySpec);
    }
}


--
View this message in context: http://shiro-user.582556.n2.nabble.com/Initialization-Vector-doesn-t-appear-to-be-doing-it-s-job-for-me-tp7577553p7577594.html
Sent from the Shiro User mailing list archive at Nabble.com.

Re: Initialization Vector doesn't appear to be doing it's job for me

Posted by jhericks <ja...@jasonerickson.com>.
My algorithm is PBEWITHSHAAND2-KEYTRIPLEDES-CBC.  I thought that set the mode
to Cipher-Block-Chaining.  I'm pretty sure I tried setting the mode
explicitly to CBC as well, but it made no difference.

I stepped through the Shiro code and could see it doing exactly as you
describe with regards to putting IV on the front of the byte array and
stripping it off for decryption.  However, it didn't seem to do the job. 
It's pretty easy to reproduce with the sample code provided.  (Sorry about
the formatting.)

--
View this message in context: http://shiro-user.582556.n2.nabble.com/Initialization-Vector-doesn-t-appear-to-be-doing-it-s-job-for-me-tp7577553p7577592.html
Sent from the Shiro User mailing list archive at Nabble.com.

Re: Initialization Vector doesn't appear to be doing it's job for me

Posted by Les Hazlewood <lh...@apache.org>.
P.S.  Sorry, I didn't see your included example code - the ASF list
stripped it off (and it is only visible in Nabble).

Unfortunately, ASF lists don't do too well with formatted messages.
Plaintext/unformatted is usually safest.

--
Les Hazlewood | @lhazlewood
CTO, Stormpath | http://stormpath.com | @goStormpath | 888.391.5282
Stormpath wins GigaOM Structure Launchpad Award! http://bit.ly/MvZkMk


On Mon, Jul 9, 2012 at 5:02 PM, Les Hazlewood <lh...@apache.org> wrote:
> Hi Jason,
>
> Assuming you're using a block cipher, your encryption output would
> depend on the Cipher Mode of Operation used for encryption (assuming
> you're using a block algorithm like AES or Blowfish).  The Operation
> Mode determines how to utilize the Initialization Vector (IV) when
> starting encryption.  When using an IV, the output *should* be
> significantly different across encryption operations even when
> encrypting the same exact plaintext [1] multiple times.
>
> Shiro generates an IV using a Secure Random generator (by default),
> and that IV size must be compatible with the cipher algorithm (i.e.
> the block size of the cipher).  Shiro prepends the IV to the encrypted
> output byte array automatically (this is conventional practice and
> 'safe' to do).  I'm unsure as to why you needed to do this yourself.
>
> It sounds like you're doing the exact same thing that Shiro is doing
> by default - how might your logic differ?
>
> What cipher algorithm are you using?  What Cipher Mode of Operation?
> Shiro block ciphers default to OperationMode.CBC.
>
> [1] http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Initialization_vector_.28IV.29
>
> HTH,
>
> --
> Les Hazlewood | @lhazlewood
> CTO, Stormpath | http://stormpath.com | @goStormpath | 888.391.5282
> Stormpath wins GigaOM Structure Launchpad Award! http://bit.ly/MvZkMk
>
> On Mon, Jul 9, 2012 at 11:19 AM, jhericks <ja...@jasonerickson.com> wrote:
>> I never got any response on this, but it seems that the problem was nothing
>> special with Shiro as I was able to reproduce it with just the bare Cipher
>> using the BouncyCastle provider.
>>
>> What I wound up doing was something similar but not identical to
>> initialization vector, which is that I generate the salt at random and put
>> the salt at the front of the encrypted byte array.  Then to decrypt, I pull
>> the salt off the front and use it to decrypt the rest of the array.
>>
>> I'm not a security expert, so I don't know if I'm giving up a lot by using
>> this workaround.
>>
>> --
>> View this message in context: http://shiro-user.582556.n2.nabble.com/Initialization-Vector-doesn-t-appear-to-be-doing-it-s-job-for-me-tp7577553p7577587.html
>> Sent from the Shiro User mailing list archive at Nabble.com.

Re: Initialization Vector doesn't appear to be doing it's job for me

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

Assuming you're using a block cipher, your encryption output would
depend on the Cipher Mode of Operation used for encryption (assuming
you're using a block algorithm like AES or Blowfish).  The Operation
Mode determines how to utilize the Initialization Vector (IV) when
starting encryption.  When using an IV, the output *should* be
significantly different across encryption operations even when
encrypting the same exact plaintext [1] multiple times.

Shiro generates an IV using a Secure Random generator (by default),
and that IV size must be compatible with the cipher algorithm (i.e.
the block size of the cipher).  Shiro prepends the IV to the encrypted
output byte array automatically (this is conventional practice and
'safe' to do).  I'm unsure as to why you needed to do this yourself.

It sounds like you're doing the exact same thing that Shiro is doing
by default - how might your logic differ?

What cipher algorithm are you using?  What Cipher Mode of Operation?
Shiro block ciphers default to OperationMode.CBC.

[1] http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Initialization_vector_.28IV.29

HTH,

--
Les Hazlewood | @lhazlewood
CTO, Stormpath | http://stormpath.com | @goStormpath | 888.391.5282
Stormpath wins GigaOM Structure Launchpad Award! http://bit.ly/MvZkMk

On Mon, Jul 9, 2012 at 11:19 AM, jhericks <ja...@jasonerickson.com> wrote:
> I never got any response on this, but it seems that the problem was nothing
> special with Shiro as I was able to reproduce it with just the bare Cipher
> using the BouncyCastle provider.
>
> What I wound up doing was something similar but not identical to
> initialization vector, which is that I generate the salt at random and put
> the salt at the front of the encrypted byte array.  Then to decrypt, I pull
> the salt off the front and use it to decrypt the rest of the array.
>
> I'm not a security expert, so I don't know if I'm giving up a lot by using
> this workaround.
>
> --
> View this message in context: http://shiro-user.582556.n2.nabble.com/Initialization-Vector-doesn-t-appear-to-be-doing-it-s-job-for-me-tp7577553p7577587.html
> Sent from the Shiro User mailing list archive at Nabble.com.

Re: Initialization Vector doesn't appear to be doing it's job for me

Posted by jhericks <ja...@jasonerickson.com>.
I never got any response on this, but it seems that the problem was nothing
special with Shiro as I was able to reproduce it with just the bare Cipher
using the BouncyCastle provider.

What I wound up doing was something similar but not identical to
initialization vector, which is that I generate the salt at random and put
the salt at the front of the encrypted byte array.  Then to decrypt, I pull
the salt off the front and use it to decrypt the rest of the array.

I'm not a security expert, so I don't know if I'm giving up a lot by using
this workaround.  

--
View this message in context: http://shiro-user.582556.n2.nabble.com/Initialization-Vector-doesn-t-appear-to-be-doing-it-s-job-for-me-tp7577553p7577587.html
Sent from the Shiro User mailing list archive at Nabble.com.