1

I am trying to replicate the encryption logic found in a Java library in a C# application.

The Java contains two methods which I have managed to replicate in C#. I get the same results in each program for any set of data.

createKey(byte data1[], MessageDigest md);
createIV(byte data2[], MessageDigest md);

The logic to generate the key and IV in Java is as follows:

public Cipher getCipher(byte[] password) {

    MessageDigest md = MessageDigest.getInstance("SHA-1");

    byte keyData[] = createKey(byte[] password, md);

     SecretKey secretKey = 
        SecretKeyFactory.getInstance("DESede").
        generateSecret(new DESedeKeySpec(keyData[]));

    IVSpec ivspec = createIV(secretKey.getEncoded(), md);

    Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
    cipher.init(1, secretKey, ivSpec, md);

    return cipher;
}

Let's say I have the follow:

Java Key HEX:       9c 3a 79 df ba 49 86 0 ed 58 1 d8 9b a7 94 0 bb 3e 8f 80 4d 67 0 0

When I build the secretKey and then call secretKey.getEncoded() I get:

Java Encoded Key: : 9d 3b 79 df ba 49 86 1 ec 58 1 d9 9b a7 94 1 ba 3e 8f 80 4c 67 1 1     

Because I don't know what the SecretKey is doing internally I don't know how to replicate this in C#.

My current C# code looks like this:

    public static ICryptoTransform createCryptoTransform(String password)
    {

        ICryptoTransform ct = null;

        byte[] keyData = createKey(password);
        byte[] ivData = createInitialisationVector(keyData);

        printByteArray("keyData", keyData);
        printByteArray("ivData", ivData);

        TripleDESCryptoServiceProvider tdcsp = new TripleDESCryptoServiceProvider();

        tdcsp.Key = keyData; / This seems to be ignored by CreateEncryptor method below
        tdcsp.KeySize = 192;            
        tdcsp.IV = ivData; // This seems to be ignored by CreateEncryptor method below
        tdcsp.Mode = CipherMode.CBC;   
        tdcsp.Padding = PaddingMode.PKCS7; // PKCS5 and PKCS7 provide the same padding scheme

        ct = tdcsp.CreateEncryptor(keyData, ivData);

        return ct;

    }

As you can see, I'm using the ivData[] created from the unencoded key.

Everything works, that is I get the same encrypted result, if I pass the same IV data in when creating the encryptor but unfortunately I cannot modify how it generates it's IVSpec.

What is SecretKey doing internally and how do I replicate this in C#?

Karle
  • 880
  • 2
  • 12
  • 21
  • I'm guessing the difference is parity bits... – Karle Jul 28 '11 at 14:58
  • 1
    The issue seems to lie with parity bits: If we look at the two keys: Java Key HEX: 9c 3a 79 df ba 49 86 0 ed 58 1 d8 9b a7 94 0 bb 3e 8f 80 4d 67 0 0 Java Encoded Key: : 9d 3b 79 df ba 49 86 1 ec 58 1 d9 9b a7 94 1 ba 3e 8f 80 4c 67 1 1 Values have either +1, 0 or -1 adjustments: 9C = 10011100, this has an even number of 1s so we flip the last bit = +1 79 = 01111001, this has an odd number of 1s so no change = -0 ED = 11101101, this has an even number of 1s so we flip the last bit = -1 – Karle Jul 28 '11 at 15:02
  • if you're still at it -- Can you post your final code.. I'm in the same boat with a legacy code (in Java) that I have to recreate in C#... and it's causing great pain. Please Help!!! (I cannot post publicly due to security, but maybe we could do a shared session ?!? Thanks in advance!!! Dan – Danimal111 Oct 31 '16 at 19:52
  • At least for my problem above, it does look like the solution was to flip some bits based on the parity. I can't post code at the moment but the basic algorithm was: A. count bits set to 1 B. if even flip least significant bit b = b & 0x01; It's probably best to post your own question with a simple example of your problem. – Karle Nov 01 '16 at 11:21

1 Answers1

2

DES (and DESede) both derive 56 bits of key material from 64 bit input. The remaining 8 bits are used as parity check bits here. The source code shows you how Java handles this, you can apply the same in C#.

See also the section at the beginning of FIPS 46-3.

emboss
  • 38,880
  • 7
  • 101
  • 108
  • It might be better to use AES instead of 3DES. AES doesn't require parity bit setting for its keys and doesn't have the weak keys that DES has. – rossum Jul 28 '11 at 17:14
  • @rossum: Yes sure, I would prefer AES, too, if that is an option. – emboss Jul 28 '11 at 17:53
  • Thanks emboss, I'd figured out what to do but your answer really helps me to understand the background involved. Unfortunately I have no choice on the key as both the current Java library and my new C# one have to talk to a C++ binary which cannot be changed. – Karle Jul 28 '11 at 19:17
  • 1
    @Karle: I thought so. Legacy stuff... causes nothing but trouble :) – emboss Jul 28 '11 at 19:46
  • @Karle if you're still at it -- Can you post your final code.. I'm in the same boat with a legacy code (in Java) that I have to recreate in C#... and it's causing great pain. Please Help!!! (I cannot post publicly due to security, but maybe we could do a shared session ?!? Thanks in advance!!! Dan – Danimal111 Oct 31 '16 at 20:00