Triple DES Perl to Java

A

Alex

Hi,

I am having a base64 encoded data block, which has been triple des
encrypted with Perl's Crypt::TripleDES class
(http://search.cpan.org/dist/Crypt-TripleDES/lib/Crypt/TripleDES.pm) and
am trying to decrypt it with Java.

My problem is now that whatever I already tried I always get some
exception with messages from a wrong padding to nonexistent algorithms.
Below is some sample code with "O2OsvkIsfY0=" as base64 encoded data
block (decoded "data") and "key" as encryption key.

import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import sun.misc.BASE64Decoder;

public class Test
{
public static void main(String args[]) throws Exception
{
String data="O2OsvkIsfY0=";
String key="key";

// PBE parameter specification with random values for salt
// and iteration
PBEParameterSpec pbeParamSpec = new PBEParameterSpec(new
byte[]{5, 10, 20, 30, 10, 85, 86, 3}, 20);

byte b_data[]=new BASE64Decoder().decodeBuffer(data);

PBEKeySpec keyspec=new PBEKeySpec(key.toCharArray());
SecretKeyFactory
skf=SecretKeyFactory.getInstance("PBEWITHSHA1ANDDESEDE");
SecretKey sk=skf.generateSecret(keyspec);

Cipher cipher=Cipher.getInstance("PBEWITHSHA1ANDDESEDE");
cipher.init(Cipher.DECRYPT_MODE, sk, pbeParamSpec);
System.out.println(cipher.doFinal(b_data).toString());
}
}

I hope that someone can shed a bit light into this, as I am really lost.

On a related note, I noticed that SecretKeyFactory.generateSecret()
throws an InvalidKeySpecException "Password is not ASCII" exception when
the key contains a § symbol. Does this mean the Java implementation cant
handle such characters within the key?

Thanks very much,
Alexander
 
A

Alex

Alex said:
Hi,

I am having a base64 encoded data block, which has been triple des
encrypted with Perl's Crypt::TripleDES class
(http://search.cpan.org/dist/Crypt-TripleDES/lib/Crypt/TripleDES.pm) and
am trying to decrypt it with Java.

My problem is now that whatever I already tried I always get some
exception with messages from a wrong padding to nonexistent algorithms.
Below is some sample code with "O2OsvkIsfY0=" as base64 encoded data
block (decoded "data") and "key" as encryption key.

I just noticed that PBE is apparently not the right algorithm and by
using the following code I at least dont get exceptions anymore, but the
output is not the expected one.

import java.security.*;

import javax.crypto.*;
import javax.crypto.spec.*;
import sun.misc.BASE64Decoder;

public class Test
{
public static void main(String args[]) throws Exception
{
String data="O2OsvkIsfY0=";
String key="key ";

byte b_data[]=new BASE64Decoder().decodeBuffer(data);

SecretKeyFactory skf=SecretKeyFactory.getInstance("DESEDE");

DESedeKeySpec dks=new DESedeKeySpec(key.getBytes());

SecretKey sk=skf.generateSecret(dks);

Cipher cipher=Cipher.getInstance("DESEDE/ECB/NOPADDING");
cipher.init(Cipher.DECRYPT_MODE, sk);
System.out.println(new String(cipher.doFinal(b_data)));
}
}

Does somebody know where I am wrong? Thanks.
 
M

Mr. Skeptic

Alex said:
Alex said:
Hi,

I am having a base64 encoded data block, which has been triple des
encrypted with Perl's Crypt::TripleDES class
(http://search.cpan.org/dist/Crypt-TripleDES/lib/Crypt/TripleDES.pm) and
am trying to decrypt it with Java.

My problem is now that whatever I already tried I always get some
exception with messages from a wrong padding to nonexistent algorithms.
Below is some sample code with "O2OsvkIsfY0=" as base64 encoded data
block (decoded "data") and "key" as encryption key.

I just noticed that PBE is apparently not the right algorithm and by
using the following code I at least dont get exceptions anymore, but the
output is not the expected one.

import java.security.*;

import javax.crypto.*;
import javax.crypto.spec.*;
import sun.misc.BASE64Decoder;

public class Test
{
public static void main(String args[]) throws Exception
{
String data="O2OsvkIsfY0=";
String key="key ";

byte b_data[]=new BASE64Decoder().decodeBuffer(data);

SecretKeyFactory skf=SecretKeyFactory.getInstance("DESEDE");

DESedeKeySpec dks=new DESedeKeySpec(key.getBytes());

SecretKey sk=skf.generateSecret(dks);

Cipher cipher=Cipher.getInstance("DESEDE/ECB/NOPADDING");
cipher.init(Cipher.DECRYPT_MODE, sk);
System.out.println(new String(cipher.doFinal(b_data)));
}
}

Does somebody know where I am wrong? Thanks.

Looks pretty good. One likely problem is that the perl module processes
the key slightly differently. I'm not really a perl expert, but it
looks like perl treats the $passphrase argument as a 48-byte hex-ASCII
encoded key. As an added twist, the perl pack function will just use
the last four bits of the ASCII code for non-hex characters, i.e. if
the letter 'k' is put in $passphrase it will be treated as if it was
the hex character 'b'.

For example; your java key is the 24 byte array new byte [] { 'k', 'e',
'y', ' ', ..., ' '}; To get the same key in perl you set $passphrase to
'6a6579202020...' on out to 48 characters. Conversely, if in perl you
set $passphrase to 'key', the equivalent java key is the 24-byte array
new byte[] {0xb5, 0x90, 0x0, ..., 0x0}.


Another nit is the use of String.getBytes() without specifying an
explicit encoding, and similarly the use of the String constructor
without specifying an encoding.
 
A

Alex

Mr. Skeptic said:
Looks pretty good. One likely problem is that the perl module processes
the key slightly differently. I'm not really a perl expert, but it
looks like perl treats the $passphrase argument as a 48-byte hex-ASCII
encoded key.
As an added twist, the perl pack function will just use
the last four bits of the ASCII code for non-hex characters, i.e. if
the letter 'k' is put in $passphrase it will be treated as if it was
the hex character 'b'.

I cant really follow this. How is a non-hex character transformed into a
hex one? Or more specific, how is k transformed to b?

b is ascii 98 is binary 0110 0010
k is ascii 107 is binary 0110 1011

The first nibble is identical, but the second isnt. How would this work?
For example; your java key is the 24 byte array new byte [] { 'k', 'e',
'y', ' ', ..., ' '}; To get the same key in perl you set $passphrase to
'6a6579202020...' on out to 48 characters. Conversely, if in perl you
set $passphrase to 'key', the equivalent java key is the 24-byte array
new byte[] {0xb5, 0x90, 0x0, ..., 0x0}.

The problem here is however that 0xb5 and 0x90 arent valid values for a
byte value (they are larger than 128).
Another nit is the use of String.getBytes() without specifying an
explicit encoding, and similarly the use of the String constructor
without specifying an encoding.

I agree, but in my testing it shouldnt matter also because getBytes()
returns the correct values in this case - just for testing.

Thanks very much,
Alexander
 
J

John W. Kennedy

Alex said:
I cant really follow this. How is a non-hex character transformed into a
hex one? Or more specific, how is k transformed to b?

b is ascii 98 is binary 0110 0010
k is ascii 107 is binary 0110 1011

The first nibble is identical, but the second isnt. How would this work?

Look closely at the "k". Binary 01101011 is hex 6B.
 
G

Greg Stark

Alex said:
I cant really follow this. How is a non-hex character transformed into a
hex one? Or more specific, how is k transformed to b?

b is ascii 98 is binary 0110 0010
k is ascii 107 is binary 0110 1011

It is confusing, and I'm not really a perl expert so I could be wrong.
The perl documentation for the encryption function does not say this,
but the source code I think proves that it is expecting only hex-ascii
characters in the $passphrase argument, not arbitrary strings. You give
two hex-ascii characters for every byte of key. However, it does not
complain if you give it a $passphrase that is not of this form. So,
what happens if it gets a $passphrase that is something like "key", or
"myPassPhrase"? I thought I understood from this blurb from the perl
documentation for the pack function:

"...The h and H fields pack a string that many nybbles (4-bit groups,
representable as hexadecimal digits, 0-9a-f) long.

Each byte of the input field of pack() generates 4 bits of the result.
For non-alphabetical bytes the result is based on the 4
least-significant bits of the input byte, i.e., on ord($byte)%16. In
particular, bytes "0" and "1" generate nybbles 0 and 1, as do bytes
"\0" and "\1". For bytes "a".."f" and "A".."F" the result is compatible
with the usual hexadecimal digits, so that "a" and "A" both generate
the nybble 0xa==10. The result for bytes "g".."z" and "G".."Z" is not
well-defined. ..."

The first nibble is identical, but the second isnt. How would this work?
For example; your java key is the 24 byte array new byte [] { 'k', 'e',
'y', ' ', ..., ' '}; To get the same key in perl you set $passphrase to
'6a6579202020...' on out to 48 characters. Conversely, if in perl you
set $passphrase to 'key', the equivalent java key is the 24-byte array
new byte[] {0xb5, 0x90, 0x0, ..., 0x0}.

The problem here is however that 0xb5 and 0x90 arent valid values for a
byte value (they are larger than 128).

Oops, my bad, that should have been new byte[] {(byte) 0xb5, (byte)
0x90, 0x0, ..., 0x0}.

On second thought, I think this is a poor example, and you should
really test it with valid $passphrase. As a very simple example, you
can try both the perl and java with the all zeros key. Give perl a
$passphrase of "000000000000000000000000000000000000000000000000". If
that works, you can try progressively more complex values until you are
confident you understand the workings. If not, let me know. Maybe I'll
install perl and see if I can play with it myself.
 
O

Oliver Wong

Alex said:
I cant really follow this. How is a non-hex character transformed into a
hex one? Or more specific, how is k transformed to b?

b is ascii 98 is binary 0110 0010
k is ascii 107 is binary 0110 1011

The first nibble is identical, but the second isnt. How would this work?

The hexadecimal value 'b' is equal to the decimal value '11', which is
equal to the binary value '1011' which is the lower half of the ASCII
representation of the character 'k'.

So char 'k' -> 0xb.

- Oliver
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top