0

I have tried several attempts to port this code over to C# but I can not seem to get the outputs to match. Can someone help point me in the direction of what I am missing. I have included the actual code as well as links to online tools to run the samples and see the results.

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Base64;
 
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
 
public class JavaEncryption {
 
    private static SecretKeySpec secretKey;
    private static byte[] key;

    private static void processEncryptionKey(String secret)
    {
        try
        {
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(secret.getBytes("UTF-8"));
            byte[] base_hash = new byte[20];
            base_hash = crypt.digest();

            byte[] buffer = new byte[64];
            for (int i = 0; i < 64; i++) buffer [i] = 0x36;
            for (int i = 0; i < 20; i++) buffer [i] ^= base_hash[i];

            crypt.reset();
            crypt.update(buffer, 0, buffer.length);
            byte[] final_hash = new byte[20];
            final_hash = crypt.digest();
            key = Arrays.copyOf(final_hash, 16); 
             secretKey = new SecretKeySpec(key, "AES");
        }
        catch(NoSuchAlgorithmException e)
        {
            e.printStackTrace();
        }
        catch(UnsupportedEncodingException e)
        {
            e.printStackTrace();
        }
    }

    public static String encrypt(String strToEncrypt, String secret) 
    {
        try
        {
            processEncryptionKey(secret);
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(new byte[16]));
            return Base64.getEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes("UTF-8")));
        } 
        catch (Exception e) 
        {
            System.out.println("Error while encrypting: " + e.toString());
        }
        return null;
    }

    public static String decrypt(String strToDecrypt, String secret) 
    {
        try
        {
            processEncryptionKey(secret);
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(new byte[16]));
            return new String(cipher.doFinal(Base64.getDecoder().decode(strToDecrypt)));
        } 
        catch (Exception e) 
        {
            System.out.println("Error while decrypting: " + e.toString());
        }
        return null;
    }

  public static void main(String[] args){
    final String secretKey = "YVr_wlp8_fFa";

    System.out.println("Secret = " + secretKey);

    String originalString = "testing";
    
    System.out.println("Clear text = " + originalString);

    String encryptedString = JavaEncryption.encrypt(originalString, secretKey) ;
    System.out.println("Encrypted = " + encryptedString);

    String decryptedString = JavaEncryption.decrypt(encryptedString, secretKey);
    System.out.println("Decrypted = " + decryptedString);
  }
}

Here is the C# code I am trying to use but not getting the same result. I'm hoping it is just something small that I am missing:

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

public class CSharpEncryption
{
    public static void Main()
    {
        Console.WriteLine(new CSharpEncryption().EncryptText());
    }
    
        public string EncryptText()
        {
            using (var aes = new AesManaged())
            {
                aes.Key = CreateSecretKey();
                aes.IV = new byte[16];
                aes.Mode = CipherMode.CBC;
                aes.Padding = PaddingMode.PKCS7;

                byte[] encrypted = GetEncryptedBytes("testing", aes.Key, aes.IV);
                string encString = Convert.ToBase64String(encrypted);

                return encString;
            }
        }

        protected byte[] GetEncryptedBytes(string textToEncrypt, byte[] Key, byte[] IV)
        {
            byte[] encrypted;

            using (var rij = new RijndaelManaged())
            {
                rij.Key = Key;
                rij.IV = IV;

                ICryptoTransform encryptor = rij.CreateEncryptor(rij.Key, rij.IV);

                using (var msEncrypt = new MemoryStream())
                {
                    using (var cs = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (var sw = new StreamWriter(cs))
                        {
                            sw.Write(textToEncrypt);
                        }
                        encrypted = msEncrypt.ToArray();
                    }
                }
            }

            return encrypted;
        }

        private static byte[] CreateSecretKey()
        {
            var keyHash = CreateHashedKey();

            byte[] key = null;
            using (Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(keyHash, new byte[16], 1))
            {
                key = rfc2898.GetBytes(16);
            }

            return key;
        }

        private static string CreateHashedKey()
        {
            var hashBase64 = String.Empty;
            using (SHA1Managed sha1 = new SHA1Managed())
            {
                byte[] hash = sha1.ComputeHash(Encoding.UTF8.GetBytes("YVr_wlp8_fFa"));

                hashBase64 = CreateBase64Hash(hash, true);
            }
            return hashBase64;
        }

        private static string CreateBase64Hash(byte[] arr, bool withoutPadding)
        {
            var base64String = Convert.ToBase64String(arr);
            if (withoutPadding)
            {
                base64String = base64String.TrimEnd('=');
            }

            base64String += "\n";

            return base64String;
        }
    }

https://dotnetfiddle.net/ktULKG

3
  • Probably error in calculating big integers, java calculates in another way then in C# Commented Oct 20, 2022 at 17:37
  • What is the expected result? Easier to know it in advance without running java code. Commented Oct 20, 2022 at 18:18
  • The output from the java code is: 7z4ECK2P3181PKUKkIxsTQ== The output from the c# code is: QKKBf7coPazZgFXP/l4hBw== I need those to match Commented Oct 20, 2022 at 18:25

1 Answer 1

2

Both codes differ in the key derivation. For instance, the C# code uses Rfc2898DeriveBytes, which implements PBKDF2. But there is nothing of this in the Java code. So you just have to port the logic of processEncryptionKey() from the Java code to C#, e.g.:

private static byte[] ProcessEncryptionKey(string secret)
{
    using (SHA1Managed sha1 = new SHA1Managed())
    {
        byte[] hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(secret));
        byte[] extHash = new byte[64];
        for (int i = 0; i < 64; i++){
            extHash[i] = (byte)(i < 20 ? hash[i]^0x36 : 0x36);
        }
        byte[] finHash = sha1.ComputeHash(extHash);
        byte[] secretKey = new byte[16];
        Buffer.BlockCopy(finHash, 0, secretKey, 0, secretKey.Length);
        return secretKey;
    }
}

which is called with aes.Key = ProcessEncryptionKey("YVr_wlp8_fFa") in EncryptText(). This gives the same ciphertext as the Java code.

Be aware that the code has vulnerabilities:

  • As key derivation, a dedicated key derivation function such as PBKDF2 should be used.
  • A static IV (like a zero IV) is insecure.
Sign up to request clarification or add additional context in comments.

1 Comment

This is a huge help. Thank you. I didn't even notice that oversight. I am not great with encryption so I didn't even consider that. I was hoping it was just an easy fix that I was missing. As for the vulnerabilities, I just posted test code so the key derivation is auto generated so we should be ok there. As for the static IV, I will make a note of that and see about a change there. Very much appreciated.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.