Blowfish Encryption / Decryption and String Corruption

Hey experts,

I have a program that is encrypting and decrypting Strings using blowfish encryption (uses JCE class) and sometimes my string will get messed up.  I setup a test where I encrypt and decrypt right away and half the time nothing happens, the other half this happens:


Before:  N-E-E-N-H-O-U-S-E
After: N-E-E-OYnƒ¦™ìS-E

Is there some way I can clean or ready my strings before they encrypted / decrypted?  Also, I was serializing string arrays and trying to do encryption / decryption, but crazy errors were occruing... probably b/c of this same issue.  

-Chris
LVL 1
DiscomonkeyAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

OBCTCommented:
Can you please post your code?
DiscomonkeyAuthor Commented:
Hasher is the object with the hashing and encryption methods in it....


// Encryption
String query_array = "N-E-E-N-H-O-U-S-E";
r1 = Hasher.random_nbit(16);      
byte[] key = Hasher.HMAC(r1, query_array);
d_enc = Hasher.encrypt(key, data_array);            

// Decryption
byte[] temp = Hasher.decrypt(key, db_encrypted[g][1].getBytes());                      
String temp = new String(temp);                      
System.out.println(temp);

///////////////////////////////////////////////////////////////////////
  /* ENCRYPT METHOD */
  ///////////////////////////////////////////////////////////////////////
  public static byte[] encrypt(byte[] key, String data){
        
        
      byte[] encrypted = null;        
        SecretKeySpec spec = new SecretKeySpec(key, "Blowfish");       
        Cipher c = null;
        
      try{      

      c = Cipher.getInstance("Blowfish");            
      c.init(Cipher.ENCRYPT_MODE, spec);                                 
         encrypted = c.doFinal(data.getBytes());            
                                 
      }catch(IllegalBlockSizeException d){System.out.println(d);}                                       
      catch(BadPaddingException e){System.out.println(e);}                                    
      catch(InvalidKeyException g){System.out.println(g);}                                     
      catch(NoSuchPaddingException d){System.out.println(d);}
      catch(NoSuchAlgorithmException e){System.out.println(e);}            
      
             
        return encrypted;
  }
  ////////////////////
  /* DECRYPT METHOD */
  ////////////////////
 
  public static byte[] decrypt(byte[] key, byte[] encrypted_data){
        
        
        byte[] decrypted = null;                 
        try{              
              SecretKeySpec spec = new SecretKeySpec(key, "Blowfish");            
            Cipher c = Cipher.getInstance("Blowfish");
            c.init(Cipher.DECRYPT_MODE, spec);                        
            decrypted = c.doFinal(encrypted_data);
        }
        catch(IllegalBlockSizeException d){System.out.println("Something happened");}
      catch(BadPaddingException e){System.out.println("Something happened");}                        
      catch(InvalidKeyException e){System.out.println("Something happened");}                   
      catch(NoSuchPaddingException d){System.out.println("Something happened");}
      catch(NoSuchAlgorithmException e){System.out.println("Something happened");}      
        
      
        
        return decrypted;
  }      
OBCTCommented:
The code so far looks fine...
Can you please post the random_nbit() and HMAC() methods?
CompTIA Cloud+

The CompTIA Cloud+ Basic training course will teach you about cloud concepts and models, data storage, networking, and network infrastructure.

DiscomonkeyAuthor Commented:
public static String random_nbit (int number ){
        
        Random generator = new Random();
        String random_nbit = new String();
        for(int i = 0; i < number; i++){
              int temp = generator.nextInt(2);
              random_nbit = random_nbit + random_nbit.valueOf(temp);              
        }
        
        return random_nbit;
  }



public static byte[] HMAC(String secret, String data){
        
        byte[] result = null;
      SecretKeySpec key = null;
      Mac mac = null;
            
      // Generate secret key for HMAC-MD5
      try{            
            key = new SecretKeySpec(secret.getBytes(), "HmacMD5");
            mac = Mac.getInstance("HmacMD5");
                  try{                  
                        mac.init(key);
                      try{                                   
                              result = mac.doFinal(data.getBytes());            
                      }catch(IllegalArgumentException a){}
                  }catch(InvalidKeyException i){}                                 
      }catch(NoSuchAlgorithmException e){}      
      
      return result;

  }


public static String md5( String source )
  {
    try
    {
     MessageDigest md = MessageDigest.getInstance( "MD5" );
     byte[] bytes = md.digest( source.getBytes() );
     return getString( bytes );
    }
    catch( Exception e )
    {
     e.printStackTrace();
     return null;
    }
  }
private static byte[] getBytes( String str )
  {
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    StringTokenizer st = new StringTokenizer( str, "-", false );
    while( st.hasMoreTokens() )
    {
      int i = Integer.parseInt( st.nextToken() );
      bos.write( ( byte )i );
    }
    return bos.toByteArray();
  }



Interesting that last method.... I used someone else md5 and this whole time I thought getBytes() was a standard method.....I guess its not !  Still, I dont know whats going on

DiscomonkeyAuthor Commented:
sometimes this fires off:


javax.crypto.BadPaddingException: Given final block not properly padded
DiscomonkeyAuthor Commented:
I took out the hyphens, didn't help at all, and the bad padding exception I think has nothing to do with the real problem.... which since its occuring randomly it has something to do with the hash and how its going into the encryption algorithm as the key....
DiscomonkeyAuthor Commented:
I need to clean the output of my hash funciton somehow I think.... I can use the same cleaning function when I decrypt so I won't lose its true value....
OBCTCommented:
After a bit of code sorting, I managed to get it running fine with a few minor changes.
Most of the changes were due to not having certain variables defined.
Here is the complete code I used.

import java.io.*;

import java.security.*;

import java.util.*;

import javax.crypto.*;
import javax.crypto.spec.*;

public class Test
{
    public static void main(String[] args) throws Exception
    {
        // Encryption
        String query_array = "N-E-E-N-H-O-U-S-E";
        String r1 = random_nbit(16);
        byte[] key = HMAC(r1, query_array);
        byte[] d_enc = encrypt(key, query_array);
       
        // Decryption
        byte[] temp = decrypt(key, d_enc);
        String str  = new String(temp);
        System.out.println(str);
    }

    public static byte[] encrypt(byte[] key, String data)
    {
        byte[] encrypted = null;
        SecretKeySpec spec = new SecretKeySpec(key, "Blowfish");
        Cipher c = null;
   
        try{
            c = Cipher.getInstance("Blowfish");
            c.init(Cipher.ENCRYPT_MODE, spec);
            encrypted = c.doFinal(data.getBytes());
   
        }catch(IllegalBlockSizeException d){System.out.println(d);}
        catch(BadPaddingException e){System.out.println(e);}
        catch(InvalidKeyException g){System.out.println(g);}
        catch(NoSuchPaddingException d){System.out.println(d);}
        catch(NoSuchAlgorithmException e){System.out.println(e);}

        return encrypted;
    }

    public static byte[] decrypt(byte[] key, byte[] encrypted_data){
        byte[] decrypted = null;
        try{
            SecretKeySpec spec = new SecretKeySpec(key, "Blowfish");
            Cipher c = Cipher.getInstance("Blowfish");
            c.init(Cipher.DECRYPT_MODE, spec);
            decrypted = c.doFinal(encrypted_data);
        }
        catch(IllegalBlockSizeException d){System.out.println("Something happened");}
        catch(BadPaddingException e){System.out.println("Something happened");}
        catch(InvalidKeyException e){System.out.println("Something happened");}
        catch(NoSuchPaddingException d){System.out.println("Something happened");}
        catch(NoSuchAlgorithmException e){System.out.println("Something happened");}

        return decrypted;
    }

    public static String random_nbit (int number ){
        Random generator = new Random();
        String random_nbit = new String();
        for(int i = 0; i < number; i++){
            int temp = generator.nextInt(2);
            random_nbit = random_nbit + random_nbit.valueOf(temp);
        }

       return random_nbit;
    }

    public static byte[] HMAC(String secret, String data)
    {
        byte[] result = null;
        SecretKeySpec key = null;
        Mac mac = null;
   
        // Generate secret key for HMAC-MD5
        try{
            key = new SecretKeySpec(secret.getBytes(), "HmacMD5");
            mac = Mac.getInstance("HmacMD5");
                try{
                    mac.init(key);
                        try{
                            result = mac.doFinal(data.getBytes());
                        }catch(IllegalArgumentException a){}
                }catch(InvalidKeyException i){}
        }catch(NoSuchAlgorithmException e){}
   
        return result;
    }

    public static String md5( String source )
    {
        try
        {
         MessageDigest md = MessageDigest.getInstance( "MD5" );
         byte[] bytes = md.digest( source.getBytes() );
         return new String(bytes);
        }
        catch( Exception e )
        {
         e.printStackTrace();
         return null;
        }
    }
 
    private static byte[] getBytes( String str )
    {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        StringTokenizer st = new StringTokenizer( str, "-", false );
        while( st.hasMoreTokens() )
        {
          int i = Integer.parseInt( st.nextToken() );
          bos.write( ( byte )i );
        }
        return bos.toByteArray();
    }
}
OBCTCommented:
Let me know how this compares to your complete code.
DiscomonkeyAuthor Commented:
Sorry for the late reply OBCT, was sailing for the day with my folks...

I looked pretty closely at your code and I haven't tried it myself but it looks identical to my code.  I'm not sure If I'm missing something here, I'm accessing my  methods through an object while you access them directly as functions... I don't see the differences other then that.  I'm probably not looking closely enough, but could you point out the changes?
DiscomonkeyAuthor Commented:
OH.... theres something I didn't mention that makes a big difference........

the code I posted isn't EXACTLY what my code does.... before I decrypt the data, I stuff my encrypted data into a string array....

b_encrypted[i][1] = new String(d_enc);      

where d_enc is the encrypted data.... so I printed out my decryption before and after I stuffed it into an array like that and guess what, they don't matchs(before storing to an array the decrytion works 100% of the time)  So, how else should I store an Array of byte array besides converting to and from a String?
DiscomonkeyAuthor Commented:
found this one the web, concering storing binary data (my byte arrays of encrypted data) as strings (in my big string array)

"always the problem child, forces all of its strings to be in a given character encoding, and translates whatever characters it doesn't understand into the dreaded 3F, or the ASCII question mark (?). I figured if I used an 8-bit encoding like ISO-8859-1 then Java should be able to deal with any 8 bits I give it. But instead of trusting the programmer and spitting out whatever bytes I give it, it actually goes through the trouble of translating characters it doesn't understand into question marks. So Java strings are completely useless for storing binary data."

so essentially java was messing up my encoding b/c it forces a certain character set if it doens't understand input when making a String.
OBCTCommented:
Exactly and this is why we base64 encode byte arrays that need to be stored in Strings for whatever reason.
Here is a very good explanation just incase you haven't heard of Base64 encoding/decoding before.
http://en.wikipedia.org/wiki/Base64

I think in your last thread, I recommended using Apache Commons Codec library for hex encoding your keys.
Well that same library has a Base64 class that you can use for this task.
Here is the link again.
http://jakarta.apache.org/commons/codec

So using this library, we take your encrypted byte array (we'll call it enc), then encode it using Base64...
E.g.

String encString = new String(org.apache.commons.codec.binary.Base64.encode(enc));

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
DiscomonkeyAuthor Commented:
Very Intersting... works very well.  I have just one more  question, how do you compare byte arrays for equality?  After decoding, I use .equals() method and == but both do not work.  When printing out the byte arrays I'm comparing I get values like:
[B@1bca5f1
[B@329f3d
[B@1749757
[B@17bd6a1

I remember on an earlier thread you said these values were memory addresses... this leads me to believe that comparing byte[] arrays is impossible without constructing them into something? For now I just use the base 64 encoding to compare values and that works, but it'd be nice if I could use the byte arrays instead?



DiscomonkeyAuthor Commented:
Thanks a ton OBCT.  
OBCTCommented:
Any primitive or Object array is considered an Object.
So... myByteArray instanceof Object would return true.
The toString method in the Object class returns the memory address of that Object in a String form.
The equals method compares two objects and will only return true if they are both exactly the same instance.
E.g.

Object a1 = new Object();
Object a2 = a1;

a1.equals(a2); // true
a1.equals(new Object()); // false

Most subclasses of Object will override the toString and equals methods to suit.
The String class for example, the toString() method will return the String it's representing and equals will only return true if the contents of the string are exactly the same.
E.g.

String b1 = new String("Java Rocks");
b1.equals("Java Rocks"); // true
b1.equals(new String("Eat my socks")); // false

b1.toString() // "Java Rocks"

As for the equal opperator, it compares the value.
Java variables contain references to objects (a memory address) so it will only return true if two objects are the same instance.
E.g.

Object c1 = new Object();

c1 == c1; // true
c1 == new Object(); // false

With primitives, its slightly different. Calling '==' on two primitives, will return true if they have the same value.

int i = 0;
int j = 1;

i == 0; // true
i == j; // false

Now to compare two byte arrays, you'll need to iterate through each element in the two arrays and compare the values.
E.g.

public boolean compareByteArray(byte[] obj1, byte[] obj2)
{
  if (obj1.length != obj1.length) { return false; }

  for (int i = 0; i < obj1.length; i++)
  {
    if (obj1[i] != obj2[i]) { return false; }
  }

  return true;
}

Does this answer your question?
   
OBCTCommented:
>Thanks a ton OBCT.

Your welcome. :-)
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Java

From novice to tech pro — start learning today.