0

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

5
  • 2
    You have several transformations here - you should log what happens at each stage. See codeblog.jonskeet.uk/2014/01/20/… Commented Sep 13, 2017 at 6:14
  • 1
    You should also work out whether the problem is in the query string handling or not - if it's not, that code is irrelevant to the question. Basically, you need to reduce this to the smallest example of what's not working. Commented Sep 13, 2017 at 6:16
  • _cryptoProvider.Padding = PaddingMode.PKCS7; vs Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - I'd place my bet on wrong padding mode. At least as one part of the problem ... Commented Sep 13, 2017 at 6:55
  • @Fildor: Despite the different names, it's the same padding. Commented Sep 13, 2017 at 13:39
  • @JamesKPolk Really? Oh, that's ... Didn't look it up, just hit my eye being different. Commented Sep 13, 2017 at 14:45

1 Answer 1

0

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.

Sign up to request clarification or add additional context in comments.

2 Comments

The padding is the same. In Java, when you specify PKCS5PADDING you actually get PKCS 7 padding. Java is so old that the Cipher class existed before widespread availability of 128-bit block ciphers. When AES and others came along Java simply changed the functionality so that PKCS5PADDING does the same thing as PKCS 7 padding. MSDN documentation should never be trusted.
@JamesKPolk: Thanks for the clarification and at least the advice. I will keep in mind - adjusted my answer.

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.