0

I am developing an android application in which i need to implement some encryption. At the same time i have to keep compatibility with other versions of application (e.g. for the WP platform), which are already in production.

This is C# code:

static public byte[] Encrypt(String passphrase, byte[] data)
    {
        //encrypted data
        byte[] buffer = null;

        //crypto handles
        IntPtr hProvider = IntPtr.Zero;
        IntPtr hKey = IntPtr.Zero;

        try
        {

            if (!WinApi.CryptAcquireContext(ref hProv, null, WinApi.MS_DEF_PROV,
                WinApi.PROV_RSA_FULL, WinApi.CRYPT_VERIFYCONTEXT))
                Failed("CryptAcquireContext");

           //128 bit hash object
            if (!WinApi.CryptCreateHash(hProv,
                WinApi.CALG_MD5, IntPtr.Zero, 0, ref hHash))
                Failed("CryptCreateHash");

     // add passphrase to hash  
            byte[] keyData = ASCIIEncoding.ASCII.GetBytes(passphrase);
            if (!WinApi.CryptHashData(hHash, keyData, (uint)keyData.Length, 0))
                Failed("CryptHashData");

            // create 40 bit crypto key from passphrase hash
            if (!WinApi.CryptDeriveKey(hProv, WinApi.CALG_RC2,
                hHash, WinApi.CRYPT_EXPORTABLE, ref hKey))
                Failed("CryptDeriveKey");

            // determine how large of a buffer is required
            // to hold the encrypted data
            uint dataLength = (uint)data.Length;
            uint bufLength = (uint)data.Length;
            if (!WinApi.CryptEncrypt(hKey, IntPtr.Zero, true,
                0, null, ref dataLength, bufLength))
                Failed("CryptEncrypt");

            // allocate and fill buffer with encrypted data
            buffer = new byte[dataLength];
            Buffer.BlockCopy(data, 0, buffer, 0, data.Length);

            dataLength = (uint)data.Length;
            bufLength = (uint)buffer.Length;
            if (!WinApi.CryptEncrypt(hKey, IntPtr.Zero, true,
                0, buffer, ref dataLength, bufLength))
                Failed("CryptEncrypt");
        }
      .......
     }

I have tried to implement it in Java. AFAIK, there is no default RC2 crypto provider in android, so i used Spongy Castle library (bouncycastle fork for android).

This is my Java code:

public static byte[] encryptLB(byte[] key, byte[] iv, byte[] unencrypted)
               throws NoSuchAlgorithmException, ... {
            MessageDigest digest = MessageDigest.getInstance("MD5");
            digest.update(key);
            byte[] hash = digest.digest(); //build the hash (128 bit)

              Cipher cipher = Cipher.getInstance("RC2/CBC/PKCS5Padding");
              cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(hash, "RC2"));
              byte[] unByte = unencrypted;
              byte[] encrypted = cipher.doFinal(unencrypted);
              return encrypted;
             }

And the results of these functions are different. What i am doing wrong?

How do i do it right? Any examples and suggestions are welcome.

With best regards.

UPD The main goal is to get identical byte arrays from both functions. I can't modify c# code. First, i want to clarify am i right with c#-code:

  • it creates MD5 hash from the passphrase's bytes array
  • it generates crypto key using proprietary WinApi.CryptDeriveKey function
  • this key is used to encrypt data using RC2 algorithm

Second, i want to know whether there is an analogue of WinApi.CryptDeriveKey function - as i see this is the main problem.

Sorry, my question is too general, because i am not sure that the problem above (CryptDeriveKey) is the only.

Johnny Doe
  • 3,280
  • 4
  • 29
  • 45
  • Are you trying to perform *encryption* or *hashing*? They're very different - you seem to be hashing in the Java code. The C# code isn't terribly clear, as you're using Windows APIs for no obvious reason - there are plenty of cryptography APIs directly in .NET. – Jon Skeet Jul 19 '14 at 10:29
  • I am just trying to implement algorithm, that is written in C#, in java. Unfortunately, i am not familiar with WinApi and best practices in C#, also this code is not mine. As i understand, this method(c#) creates MD5 hash from `passphrase` and, then, uses it as a secret key. And this step `if (!WinApi.CryptDeriveKey(hProv, WinApi.CALG_RC2, hHash, WinApi.CRYPT_EXPORTABLE, ref hKey))` is still unclear to me. MSDN says, that it somehow generates a key from the hash data. Does any java or open source analog exists for this function? – Johnny Doe Jul 19 '14 at 11:08
  • 1
    Well what are you actually trying to achieve? You need to be clear about that before anything else. – Jon Skeet Jul 19 '14 at 11:36
  • Thanks! I have updated my question. I hope, it become more clear. – Johnny Doe Jul 19 '14 at 12:39

1 Answers1

0

Unfortunately I don't have access to a Windows machine to test this on right now but here is what I think should be interoperable.

public static byte[] encrypt(String passphrase, byte[] data) throws Exception {

    // Hash the ASCII-encoded passphrase with md5

    byte[] keyData = passphrase.getBytes(Charset.forName("US-ASCII"));
    MessageDigest md = MessageDigest.getInstance("MD5");
    byte [] md5HashOfKey = md.digest(keyData);

    // Need to use bouncycastle (spongycastle on Android) to get RC2

    Security.addProvider(new BouncyCastleProvider());

    Cipher rc2 = Cipher.getInstance("RC2/CBC/PKCS5PADDING");

    // Create an RC2 40-bit key from the 1st 5 bytes of the hash.

    SecretKeySpec rc2KeySpec = new SecretKeySpec(md5HashOfKey, 0, 5, "RC2");
    rc2.init(Cipher.ENCRYPT_MODE, rc2KeySpec);

    byte [] cipher = rc2.doFinal(data);

    return cipher;
}
President James K. Polk
  • 40,516
  • 21
  • 95
  • 125