Error "Input length must be multiple of 8 when decrypting with padded cipher"

Posted by Ross Peoples on Stack Overflow See other posts from Stack Overflow or by Ross Peoples
Published on 2010-06-14T20:31:14Z Indexed on 2010/06/14 20:42 UTC
Read the original article Hit count: 496

Filed under:
|
|

I am trying to move a project from C# to Java for a learning exercise. I am still very new to Java, but I have a TripleDES class in C# that encrypts strings and returns a string value of the encrypted byte array. Here is my C# code:

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

namespace tDocc.Classes
{
    /// <summary>
    /// Triple DES encryption class
    /// </summary>
    public static class TripleDES
    {
        private static byte[] key = { 110, 32, 73, 24, 125, 66, 75, 18, 79, 150, 211, 122, 213, 14, 156, 136, 171, 218, 119, 240, 81, 142, 23, 4 };
        private static byte[] iv = { 25, 117, 68, 23, 99, 78, 231, 219 };

        /// <summary>
        /// Encrypt a string to an encrypted byte array
        /// </summary>
        /// <param name="plainText">Text to encrypt</param>
        /// <returns>Encrypted byte array</returns>
        public static byte[] Encrypt(string plainText)
        {
            UTF8Encoding utf8encoder = new UTF8Encoding();
            byte[] inputInBytes = utf8encoder.GetBytes(plainText);
            TripleDESCryptoServiceProvider tdesProvider = new TripleDESCryptoServiceProvider();
            ICryptoTransform cryptoTransform = tdesProvider.CreateEncryptor(key, iv);
            MemoryStream encryptedStream = new MemoryStream();
            CryptoStream cryptStream = new CryptoStream(encryptedStream, cryptoTransform, CryptoStreamMode.Write);
            cryptStream.Write(inputInBytes, 0, inputInBytes.Length);
            cryptStream.FlushFinalBlock();
            encryptedStream.Position = 0;
            byte[] result = new byte[encryptedStream.Length];
            encryptedStream.Read(result, 0, (int)encryptedStream.Length);
            cryptStream.Close();
            return result;
        }

        /// <summary>
        /// Decrypt a byte array to a string
        /// </summary>
        /// <param name="inputInBytes">Encrypted byte array</param>
        /// <returns>Decrypted string</returns>
        public static string Decrypt(byte[] inputInBytes)
        {
            UTF8Encoding utf8encoder = new UTF8Encoding();
            TripleDESCryptoServiceProvider tdesProvider = new TripleDESCryptoServiceProvider();
            ICryptoTransform cryptoTransform = tdesProvider.CreateDecryptor(key, iv);
            MemoryStream decryptedStream = new MemoryStream();
            CryptoStream cryptStream = new CryptoStream(decryptedStream, cryptoTransform, CryptoStreamMode.Write);
            cryptStream.Write(inputInBytes, 0, inputInBytes.Length);
            cryptStream.FlushFinalBlock();
            decryptedStream.Position = 0;
            byte[] result = new byte[decryptedStream.Length];
            decryptedStream.Read(result, 0, (int)decryptedStream.Length);
            cryptStream.Close();
            UTF8Encoding myutf = new UTF8Encoding();
            return myutf.GetString(result);
        }

        /// <summary>
        /// Decrypt an encrypted string
        /// </summary>
        /// <param name="text">Encrypted text</param>
        /// <returns>Decrypted string</returns>
        public static string DecryptText(string text)
        {
            if (text == "")
            {
                return text;
            }
            return Decrypt(Convert.FromBase64String(text));
        }

        /// <summary>
        /// Encrypt a string
        /// </summary>
        /// <param name="text">Unencrypted text</param>
        /// <returns>Encrypted string</returns>
        public static string EncryptText(string text)
        {
            if (text == "")
            {
                return text;
            }
            return Convert.ToBase64String(Encrypt(text));
        }
    }

    /// <summary>
    /// Random number generator
    /// </summary>
    public static class RandomGenerator
    {
        /// <summary>
        /// Generate random number
        /// </summary>
        /// <param name="length">Number of randomizations</param>
        /// <returns>Random number</returns>
        public static int GenerateNumber(int length)
        {
            byte[] randomSeq = new byte[length];
            new RNGCryptoServiceProvider().GetBytes(randomSeq);
            int code = Environment.TickCount;

            foreach (byte b in randomSeq)
            {
                code += (int)b;
            }

            return code;
        }
    }

    /// <summary>
    /// Hash generator class
    /// </summary>
    public static class Hasher
    {
        /// <summary>
        /// Hash type
        /// </summary>
        public enum eHashType
        {
            /// <summary>
            /// MD5 hash. Quick but collisions are more likely. This should not be used for anything important
            /// </summary>
            MD5 = 0,

            /// <summary>
            /// SHA1 hash. Quick and secure. This is a popular method for hashing passwords
            /// </summary>
            SHA1 = 1,

            /// <summary>
            /// SHA256 hash. Slower than SHA1, but more secure. Used for encryption keys
            /// </summary>
            SHA256 = 2,

            /// <summary>
            /// SHA348 hash. Even slower than SHA256, but offers more security
            /// </summary>
            SHA348 = 3,

            /// <summary>
            /// SHA512 hash. Slowest but most secure. Probably overkill for most applications
            /// </summary>
            SHA512 = 4,

            /// <summary>
            /// Derrived from MD5, but only returns 12 digits
            /// </summary>
            Digit12 = 5
        }

        /// <summary>
        /// Hashes text using a specific hashing method
        /// </summary>
        /// <param name="text">Input text</param>
        /// <param name="hash">Hash method</param>
        /// <returns>Hashed text</returns>
        public static string GetHash(string text, eHashType hash)
        {
            if (text == "")
            {
                return text;
            }
            if (hash == eHashType.MD5)
            {
                MD5CryptoServiceProvider hasher = new MD5CryptoServiceProvider();
                return ByteToHex(hasher.ComputeHash(Encoding.ASCII.GetBytes(text)));
            }
            else if (hash == eHashType.SHA1)
            {
                SHA1Managed hasher = new SHA1Managed();
                return ByteToHex(hasher.ComputeHash(Encoding.ASCII.GetBytes(text)));
            }
            else if (hash == eHashType.SHA256)
            {
                SHA256Managed hasher = new SHA256Managed();
                return ByteToHex(hasher.ComputeHash(Encoding.ASCII.GetBytes(text)));
            }
            else if (hash == eHashType.SHA348)
            {
                SHA384Managed hasher = new SHA384Managed();
                return ByteToHex(hasher.ComputeHash(Encoding.ASCII.GetBytes(text)));
            }
            else if (hash == eHashType.SHA512)
            {
                SHA512Managed hasher = new SHA512Managed();
                return ByteToHex(hasher.ComputeHash(Encoding.ASCII.GetBytes(text)));
            }
            else if (hash == eHashType.Digit12)
            {
                MD5CryptoServiceProvider hasher = new MD5CryptoServiceProvider();
                string newHash = ByteToHex(hasher.ComputeHash(Encoding.ASCII.GetBytes(text)));
                return newHash.Substring(0, 12);
            }
            return "";
        }

        /// <summary>
        /// Generates a hash based on a file's contents. Used for detecting changes to a file and testing for duplicate files
        /// </summary>
        /// <param name="info">FileInfo object for the file to be hashed</param>
        /// <param name="hash">Hash method</param>
        /// <returns>Hash string representing the contents of the file</returns>
        public static string GetHash(FileInfo info, eHashType hash)
        {
            FileStream hashStream = new FileStream(info.FullName, FileMode.Open, FileAccess.Read);
            string hashString = "";
            if (hash == eHashType.MD5)
            {
                MD5CryptoServiceProvider hasher = new MD5CryptoServiceProvider();
                hashString = ByteToHex(hasher.ComputeHash(hashStream));
            }
            else if (hash == eHashType.SHA1)
            {
                SHA1Managed hasher = new SHA1Managed();
                hashString = ByteToHex(hasher.ComputeHash(hashStream));
            }
            else if (hash == eHashType.SHA256)
            {
                SHA256Managed hasher = new SHA256Managed();
                hashString = ByteToHex(hasher.ComputeHash(hashStream));
            }
            else if (hash == eHashType.SHA348)
            {
                SHA384Managed hasher = new SHA384Managed();
                hashString = ByteToHex(hasher.ComputeHash(hashStream));
            }
            else if (hash == eHashType.SHA512)
            {
                SHA512Managed hasher = new SHA512Managed();
                hashString = ByteToHex(hasher.ComputeHash(hashStream));
            }
            hashStream.Close();
            hashStream.Dispose();
            hashStream = null;
            return hashString;
        }

        /// <summary>
        /// Converts a byte array to a hex string
        /// </summary>
        /// <param name="data">Byte array</param>
        /// <returns>Hex string</returns>
        public static string ByteToHex(byte[] data)
        {
            StringBuilder builder = new StringBuilder();
            foreach (byte hashByte in data)
            {
                builder.Append(string.Format("{0:X1}", hashByte));
            }
            return builder.ToString();
        }

        /// <summary>
        /// Converts a hex string to a byte array
        /// </summary>
        /// <param name="hexString">Hex string</param>
        /// <returns>Byte array</returns>
        public static byte[] HexToByte(string hexString)
        {
            byte[] returnBytes = new byte[hexString.Length / 2];
            for (int i = 0; i <= returnBytes.Length - 1; i++)
            {
                returnBytes[i] = byte.Parse(hexString.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber);
            }
            return returnBytes;
        }
    }
}

And her is what I've got for Java code so far, but I'm getting the error "Input length must be multiple of 8 when decrypting with padded cipher" when I run the test on this:

import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import com.tdocc.utils.Base64;

public class TripleDES {
    private static byte[] keyBytes = { 110, 32, 73, 24, 125, 66, 75, 18, 79, (byte)150, (byte)211, 122, (byte)213, 14, (byte)156, (byte)136, (byte)171, (byte)218, 119, (byte)240, 81, (byte)142, 23, 4 };
    private static byte[] ivBytes = { 25, 117, 68, 23, 99, 78, (byte)231, (byte)219 };

    public static String encryptText(String plainText) {
        try {
            if (plainText.isEmpty()) return plainText;
            return Base64.decode(TripleDES.encrypt(plainText)).toString();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    public static byte[] encrypt(String plainText) throws InvalidKeyException, InvalidAlgorithmParameterException, NoSuchPaddingException {
        try {
            final SecretKey key = new SecretKeySpec(keyBytes, "DESede");
            final IvParameterSpec iv = new IvParameterSpec(ivBytes);
            final Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, key, iv);

            final byte[] plainTextBytes = plainText.getBytes("utf-8");
            final byte[] cipherText = cipher.doFinal(plainTextBytes);

            return cipherText;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    public static String decryptText(String message) {
        try {
            if (message.isEmpty()) return message;
            else return TripleDES.decrypt(message.getBytes());
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    public static String decrypt(byte[] message) {
        try {
            final SecretKey key = new SecretKeySpec(keyBytes, "DESede");
            final IvParameterSpec iv = new IvParameterSpec(ivBytes);
            final Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, key, iv);

            final byte[] plainText = cipher.doFinal(message);

            return plainText.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

}

© Stack Overflow or respective owner

Related posts about c#

Related posts about java