C# equivalent encryption decryption for Java

4k views Asked by At

C# Code

namespace MWS.DAL
{
   public class StringHelpers
    {
        #region Constants

        private const char QUERY_STRING_DELIMITER = '&';

        #endregion Constants

        #region Members

        private static RijndaelManaged _cryptoProvider;
        //128 bit encyption: DO NOT CHANGE    
        private static readonly byte[] Key = { some byte value };
        private static readonly byte[] IV = { some byte value  };

        #endregion Members

        #region Constructor

        static StringHelpers()
        {
            _cryptoProvider = new RijndaelManaged();
            _cryptoProvider.Mode = CipherMode.CBC;
            _cryptoProvider.Padding = PaddingMode.PKCS7;
        }

        #endregion Constructor

        #region Methods

        /// <summary>
        /// Encrypts a given string.
        /// </summary>
        /// <param name="unencryptedString">Unencrypted string</param>
        /// <returns>Returns an encrypted string</returns>
        public static string Encrypt(string unencryptedString)
        {
            byte[] bytIn = ASCIIEncoding.ASCII.GetBytes(unencryptedString);

            // Create a MemoryStream
            MemoryStream ms = new MemoryStream();

            // Create Crypto Stream that encrypts a stream
            CryptoStream cs = new CryptoStream(ms,
                _cryptoProvider.CreateEncryptor(Key, IV),
                CryptoStreamMode.Write);

            // Write content into MemoryStream
            cs.Write(bytIn, 0, bytIn.Length);
            cs.FlushFinalBlock();

            byte[] bytOut = ms.ToArray();
            return Convert.ToBase64String(bytOut);
        }

        /// <summary>
        /// Decrypts a given string.
        /// </summary>
        /// <param name="encryptedString">Encrypted string</param>
        /// <returns>Returns a decrypted string</returns>
        public static string Decrypt(string encryptedString)
        {
            if (encryptedString.Trim().Length != 0)
            {
                // Convert from Base64 to binary
                byte[] bytIn = Convert.FromBase64String(encryptedString);

                // Create a MemoryStream
                MemoryStream ms = new MemoryStream(bytIn, 0, bytIn.Length);

                // Create a CryptoStream that decrypts the data
                CryptoStream cs = new CryptoStream(ms,
                    _cryptoProvider.CreateDecryptor(Key, IV),
                    CryptoStreamMode.Read);

                // Read the Crypto Stream
                StreamReader sr = new StreamReader(cs);

                return sr.ReadToEnd();
            }
            else
            {
                return "";
            }
        }

        public static NameValueCollection DecryptQueryString(string queryString)
        {
            if (queryString.Length != 0)
            {
                //Decode the string
                string decodedQueryString = HttpUtility.UrlDecode(queryString);

                //Decrypt the string
                string decryptedQueryString = StringHelpers.Decrypt(decodedQueryString);

                //Now split the string based on each parameter
                string[] actionQueryString = decryptedQueryString.Split(new char[] { QUERY_STRING_DELIMITER });

                NameValueCollection newQueryString = new NameValueCollection();

                //loop around for each name value pair.
                for (int index = 0; index < actionQueryString.Length; index++)
                {
                    string[] queryStringItem = actionQueryString[index].Split(new char[] { '=' });
                    newQueryString.Add(queryStringItem[0], queryStringItem[1]);
                }

                return newQueryString;
            }
            else
            {
                //No query string was passed in.
                return null;
            }
        }

        public static string EncryptQueryString(NameValueCollection queryString)
        {
            //create a string for each value in the query string passed in.
            string tempQueryString = "";

            for (int index = 0; index < queryString.Count; index++)
            {
                tempQueryString += queryString.GetKey(index) + "=" + queryString[index];
                if (index != queryString.Count - 1)
                {
                    tempQueryString += QUERY_STRING_DELIMITER;
                }
            }

            return EncryptQueryString(tempQueryString);
        }

        /// <summary>
        /// You must pass in a string that uses the QueryStringHelper.DELIMITER as the delimiter.
        /// This will also append the "?" to the beginning of the query string.
        /// </summary>
        /// <param name="queryString"></param>
        /// <returns></returns>
        public static string EncryptQueryString(string queryString)
        {
            return "?" + HttpUtility.UrlEncode(StringHelpers.Encrypt(queryString));
        }

        #endregion Methods
    }
}

Java Code

 public String decrypt(String text) throws Exception{

    //    byte[] keyBytess={some byte values};
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        byte[] keyBytes= new byte[16];
        byte[] b= { some byte values };
        byte[] iv = { some byte values };


        int len= b.length;
        if (len > keyBytes.length) len = keyBytes.length;
        System.arraycopy(b, 0, keyBytes, 0, len);
        SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        cipher.init(Cipher.DECRYPT_MODE,keySpec,ivSpec);

        BASE64Decoder decoder = new BASE64Decoder();
        byte [] results = cipher.doFinal(decoder.decodeBuffer(text));
        return new String(results,"UTF-8");
    }

    public String encrypt(String text)
            throws Exception {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        byte[] keyBytes= new byte[16];
        byte[] b= { some byte values };
        byte[] iv = { some byte values };
        int len= b.length;
        if (len > keyBytes.length) len = keyBytes.length;
        System.arraycopy(b, 0, keyBytes, 0, len);
        SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        cipher.init(Cipher.ENCRYPT_MODE,keySpec,ivSpec);
        byte[] results = cipher.doFinal(text.getBytes("UTF-8"));
        BASE64Encoder encoder = new BASE64Encoder();
        return encoder.encode(results);
    }

In Case of C# value= just4fun and ecncrypted value= j/Rph4d/Op6sugBxZ/kJbA==

In Case of Java value= just4fun and encrypted value= 8BfD/Jr0Hk35qn8DXwFHmA==

and when I am trying to decrypt C# encrypted value in java it giving javax.crypto.BadPaddingException: Given final block not properly padded

I have some restriction, I can't update C# code it is in use

1

There are 1 answers

2
Martin Backasch On

When you encrypt/decrypt you are using using UTF-8 Encoding in Java

byte[] results = cipher.doFinal(text.getBytes("UTF-8"));

and ASCII in C#

byte[] bytIn = ASCIIEncoding.ASCII.GetBytes(unencryptedString);

You should get the same results when using UFT-8 encoding, like for C#:

byte[] bytIn = UTF8Encoding.UTF8.GetBytes(unencryptedString);

or for Java:

byte[] bytIn = text.getBytes("US_ASCII");

As Fildor mentioned the different PaddingModes see the comment below by James K Polk

I added a quote from msdn.microsoft.com forums for additional information

PKCS7 padding in .Net vs PKCS5 padding in Java

The difference between the PKCS#5 and PKCS#7 padding mechanisms is the block size; PKCS#5 padding is defined for 8-byte block sizes, PKCS#7 padding would work for any block size from 1 to 255 bytes. So fundamentally PKCS#5 padding is a subset of PKCS#7 padding for 8 byte block sizes.

! so, data encrypted with PKCS#5 is able to decrypt with PKCS#7, but data encrypted with PKCS#7 may not be able to decrypt with PKCS#5.


Also found a possible duplicate for your problem here.