Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / Security / February 2004

Tip: Looking for answers? Try searching our database.

JCE decryption issue, possibly String.getBytes() issue

Thread view: 
Dan Anderson - 25 Feb 2004 20:09 GMT
I have code that has been working fine for some time, or so we
thought. We recently discovered that at times the decryption is
failing. I should say that are using Sun JCE1.2.2.

Below is an example of a clear text string that will fail
consistently:
String clearText = "ss=078388601&ts=20040210195639";

Ok, Here is my test class that I run. It executes the CipherTest
class, enclosed further down:
public class JCEDebug {
/**
* Constructor for JCEDebug.
*/
public JCEDebug() {
    super();
}

public static void main(String[] args)
{
    String clearText = "ss=078388601&ts=20040210195639";
         
    try
    {
        CipherTest cipher1 = new CipherTest();
        System.out.println("Start value = " + clearText);
        cipherText = cipher1.encrypt(clearText);
        System.out.println("Encrypted value = " + cipherText);
           
        CipherTest cipher2 = new CipherTest();
        clearText = cipher2.decrypt(cipherText);
        System.out.println("Decrypted value = " + clearText);
    }
    catch(Exception e)
    {
        System.out.println("Caught Exception msg = " + e.getMessage());
    }
}
}

Here is the source for CipherTest:

import java.security.*;
import java.security.spec.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.io.IOException;

public class CipherTest
{
   final private static String CRYPTO_ALGORITHM = "DESede";
   final private static String CRYPTO_BLOCK_MODE = "CBC";
   final private static String CRYPTO_PADDING = "PKCS5Padding";

   private static String keyData1 = "qTqE0Fgy";
   private static String keyData2 = "G5h2NERs";
   private static String keyData3 = "NiFNj4Vg";
   private static String initVector = "h8sNq4lJ";
   private static String keyData = null;
   private static byte[] desedeKeyData = null;
   private static IvParameterSpec ivParamSpec = null;
   private static DESedeKeySpec secretKeySpec = null;
   private static SecretKeyFactory keyFactory = null;
   private static SecretKey secretKey = null;
   private boolean initialized=false;

/**
* CipherTest constructor comment.
*/
public CipherTest() {
   super();
   try{
       initData();
   }
   catch(NoSuchAlgorithmException nsae){
   }
   catch(InvalidKeyException ike){
   }
   catch(InvalidKeySpecException ikse){
   }
   catch(java.io.UnsupportedEncodingException uee){
   }
}

/**
* Insert the method's description here.
* Creation date: (1/16/2003 4:29:47 PM)
* @return java.lang.String
* @param passedString java.lang.String
* @param cipherMode int
*/
protected String cipher(String passedString, int cipherMode)
   throws InvalidKeyException, NoSuchAlgorithmException,
       ExceptionInInitializerError, InvalidKeySpecException,
       NoSuchPaddingException, InvalidAlgorithmParameterException,
       IllegalStateException, IllegalBlockSizeException,
       BadPaddingException, NoClassDefFoundError
{
   if (!isInitialized()){
       throw new java.lang.IllegalStateException();
   }
   
   // Create the encryption cipher
   Cipher desCipher = null;
   desCipher = Cipher.getInstance(CRYPTO_ALGORITHM+"/"+CRYPTO_BLOCK_MODE+"/"+CRYPTO_PADDING);

   // Initialize the cipher for encryption
   desCipher.init(cipherMode, secretKey, ivParamSpec);

   byte[] passedBytes = passedString.getBytes();

   // Cipher the data
   byte[] resultBytes = null;
   resultBytes = desCipher.doFinal(passedBytes);

   if( resultBytes != null )
   {
       return new String(resultBytes);
   }
   else
   {
       return null;
   }
}

/**
* Insert the method's description here.
* Creation date: (1/16/2003 4:29:47 PM)
* @return java.lang.String
* @param clearText java.lang.String
*/
public  String decrypt(String cipherText)
   throws InvalidKeyException, NoSuchAlgorithmException,
       ExceptionInInitializerError, InvalidKeySpecException,
       NoSuchPaddingException, InvalidAlgorithmParameterException,
       IllegalStateException, IllegalBlockSizeException,
       BadPaddingException, NoClassDefFoundError
{
   // Pass the string and the correct mode
   return cipher(cipherText, Cipher.DECRYPT_MODE);
}

/**
* Insert the method's description here.
* Creation date: (1/16/2003 4:29:47 PM)
* @return java.lang.String
* @param clearText java.lang.String
*/
public  String encrypt(String clearText)
   throws InvalidKeyException, NoSuchAlgorithmException,
       ExceptionInInitializerError, InvalidKeySpecException,
       NoSuchPaddingException, InvalidAlgorithmParameterException,
       IllegalStateException, IllegalBlockSizeException,
       BadPaddingException, NoClassDefFoundError
{
   // Pass the string and the correct mode
   return cipher(clearText, Cipher.ENCRYPT_MODE);
}

/**
* Insert the method's description here.
* Creation date: (1/16/2003 4:08:42 PM)
*/
public void initData()
   throws InvalidKeyException, NoSuchAlgorithmException,
ExceptionInInitializerError,
   InvalidKeySpecException, NoClassDefFoundError
{
   Security.insertProviderAt( new com.sun.crypto.provider.SunJCE(),
2);
   System.setProperty("java.protocol.handler.pkgs",
"sun.net.www.protocol");
   
   keyData = keyData1 + keyData2 + keyData3;
   desedeKeyData = keyData.getBytes();

   // Create the initialization vector paramater spec      
   ivParamSpec = new IvParameterSpec(initVector.getBytes());

   // Create the key spec
   secretKeySpec = new DESedeKeySpec(desedeKeyData);

   // Create the key factory
   keyFactory = SecretKeyFactory.getInstance(CRYPTO_ALGORITHM);

   // Generate the encryption key
   secretKey = keyFactory.generateSecret(secretKeySpec);

   // Mark it as initialized
   initialized = true;
}

/**
* Insert the method's description here.
* Creation date: (5/6/2003 1:53:22 PM)
* @return boolean
*/
public boolean isInitialized() {
   return initialized;
}

public void setInitialized(boolean newInitialized) {
   initialized = newInitialized;
}
}

What I see for results are:
Start value = ss=078388601&ts=20040210195639
Encrypted value = ¦Í?+s²þy8{d
gƒ?çè‚P½:Õ]/Á?½ö"î
Decrypted value = ¼"™Hu¼^
^#ëvÅt200402?0195639

This type of behavior doesn't occur all of the time, only when certain
results are produced by the encryption. So, that along with other
posts, is why I suspect it may be related to the string to byte[] and
byte[] to string conversions. But, I have attempted to perform these
conversions using string.getBytes("ASCII"), as well as
string.getBytes("UTF-8"). Furthermore, I have attempted to serialize
the string prior to encryption, then deserialize it after encryption
using the ByteArrayOutputStream, all to no avail.

Any help that you all can provide with solving this riddle would be
greatly appreciated.   Thank you!
G Gainey - 26 Feb 2004 13:58 GMT
>     // Cipher the data
>     byte[] resultBytes = null;
[quoted text clipped - 8 lines]
>         return null;
>     }

I'm surprised you're not failing much more frequently.

ciphertext -cannot- be reliably turned into a String.  Strings have
internal structure; ciphertext is (or at least it ought to be!) an
apparently-random bitstream.  The String(byte[]) constructor is going to
mash your bitstream into String format, and generally mangle it along
the way.  Once String has "improved" your ciphertext, it isn't
ciphertext anymore - it's junk.

If you want your ciphertext to be a String, use Base64 to encode it -
that's what Base64 is for.  Base64.decode() before decrypting.

> This type of behavior doesn't occur all of the time, only when certain
> results are produced by the encryption. So, that along with other
> posts, is why I suspect it may be related to the string to byte[] and
> byte[] to string conversions. But, I have attempted to perform these
> conversions using string.getBytes("ASCII"), as well as
> string.getBytes("UTF-8").

I don't think these are your problem - but it's a good idea to do this
anyway.  If you're moving data from one machine to another, you'll get
bitten when the default encoding is different.

> Furthermore, I have attempted to serialize
> the string prior to encryption, then deserialize it after encryption
> using the ByteArrayOutputStream, all to no avail.

If you've already turned it into a String, it's too late - the damage is
already done.

Grant

Signature

In theory, there is no difference between Theory and Practice.
In practice, there is no relationship between Theory and Practice.

Michael Amling - 27 Feb 2004 17:35 GMT
> I have code that has been working fine for some time, or so we
> thought. We recently discovered that at times the decryption is
> failing. I should say that are using Sun JCE1.2.2.

> /**
>  * Insert the method's description here.
[quoted text clipped - 22 lines]
>
>     byte[] passedBytes = passedString.getBytes();

  Your passedBytes will always be a sequence of bytes that is a valid
character encoding. If the ciphertext is not a sequences of bytes that
is a valid character encoding, there is no String for which getBytes()
will return the ciphertext.

>     // Cipher the data
>     byte[] resultBytes = null;
[quoted text clipped - 3 lines]
>     {
>         return new String(resultBytes);

  Someone did not read
http://java.sun.com/j2se/1.4.2/docs/api/java/lang/String.html, which
says in the description of the String(byte[]) constructor, "The behavior
of this constructor when the given bytes are not valid in the default
charset is unspecified."
  Leaving the ciphertext as a byte array is the easiest thing to do. A
byte array is the easiest thing to write to a file or send to a Socket's
output stream.
  If you insist on converting the ciphertext to characters, use a
method that works for any sequence of bytes, such as hexadecimal or base 64.

>     }
>     else
>     {
>         return null;
>     }
> }

--Mike Amling


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.