2 Replies Latest reply: Sep 5, 2011 7:15 PM by 800207 RSS

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

    886180
      Hi, all.

      I get this error on a Linux server. On my local Mac it works fine.

      Below is the code, which includes the main() where the exception gets thrown.

      //***
      package org.ofbiz.webapp.control;



      import java.io.IOException;
      import java.security.NoSuchAlgorithmException;
      import java.security.InvalidKeyException;
      import java.security.InvalidAlgorithmParameterException;
      import java.security.Provider;
      import java.security.Provider.Service;
      import java.security.Security;
      import java.security.spec.InvalidKeySpecException;
      import java.util.Iterator;
      import java.util.Set;

      import javax.crypto.Cipher;
      import javax.crypto.IllegalBlockSizeException;
      import javax.crypto.BadPaddingException;
      import javax.crypto.SecretKey;
      import javax.crypto.NoSuchPaddingException;
      import javax.crypto.KeyGenerator;
      import javax.crypto.SecretKeyFactory;
      import javax.crypto.spec.DESKeySpec;
      import javax.crypto.spec.IvParameterSpec;
      import javax.crypto.spec.DESedeKeySpec;

      import org.ofbiz.base.util.Base64_IHarder;
      import org.ofbiz.base.util.GeneralException;

      import sun.security.jca.Providers;

      /**
      * Utility class for doing DES encryption and decryption
      *
      */
      public class ReorderEmailDecrypter {

      public static final String module = ReorderEmailDecrypter.class.getName();
      public static final String DEFAULT_RAW_KEY = "MyOwnKey"; //NB - not the real key used - but results are same


      public static SecretKey generateKey() throws NoSuchAlgorithmException {
      KeyGenerator keyGen = KeyGenerator.getInstance("DES");

      // generate the DES key
      return keyGen.generateKey();
      }

      //Encryption Methods
      public static byte[] encrypt(SecretKey key, byte[] bytes) throws GeneralException {
      Cipher cipher = ReorderEmailDecrypter.getCipher(key, Cipher.ENCRYPT_MODE);
      byte[] encBytes = null;
      try {
      encBytes = cipher.doFinal(bytes);
      } catch (IllegalStateException e) {
      throw new GeneralException(e);
      } catch (IllegalBlockSizeException e) {
      throw new GeneralException(e);
      } catch (BadPaddingException e) {
      throw new GeneralException(e);
      }
      return encBytes;
      }

      public static String encrypt(String rawKey,String stringToEncrypt) throws GeneralException {
           return new String(encrypt(getDesKey(rawKey.getBytes()), stringToEncrypt.getBytes()));

      }

      public static String encrypt(String stringToEncrypt) throws GeneralException {
           return new String(encrypt(getDesKey(DEFAULT_RAW_KEY.getBytes()), stringToEncrypt.getBytes()));

      }

      //Decryption Methods

      public static byte[] decrypt(SecretKey key, byte[] bytes) throws GeneralException {
      Cipher cipher = ReorderEmailDecrypter.getCipher(key, Cipher.DECRYPT_MODE);
      byte[] decBytes = null;
      try {
      decBytes = cipher.doFinal(bytes);
      } catch (IllegalStateException e) {
      throw new GeneralException(e);
      } catch (IllegalBlockSizeException e) {
      throw new GeneralException(e);
      } catch (BadPaddingException e) {
      throw new GeneralException(e);
      }
      return decBytes;
      }

      public static String decrypt(String rawKey,String stringToDecrypt) throws GeneralException {
           return new String(decrypt(getDesKey(rawKey.getBytes()), stringToDecrypt.getBytes()));

      }

      public static String decrypt(String stringToDecrypt) throws GeneralException {
           System.out.println("Trying to decrypt string "+stringToDecrypt + " - raw key value = "+DEFAULT_RAW_KEY);
           return new String(decrypt(getDesKey(DEFAULT_RAW_KEY.getBytes()), stringToDecrypt.getBytes()));

      }


      public static SecretKey getDesKey(byte[] rawKey) throws GeneralException {
      SecretKeyFactory skf = null;
      try {
      skf = SecretKeyFactory.getInstance("DES");
      } catch (NoSuchAlgorithmException e) {
      throw new GeneralException(e);
      }

      // load the raw key
      if (rawKey.length > 0) {
      DESKeySpec desSpec1 = null;
      try {
      desSpec1 = new DESKeySpec(rawKey);
      } catch (InvalidKeyException e) {
      throw new GeneralException(e);
      }

      // create the SecretKey Object
      SecretKey key = null;
      try {
      key = skf.generateSecret(desSpec1);
      } catch (InvalidKeySpecException e) {
      throw new GeneralException(e);
      }
      return key;
      } else {
      throw new GeneralException("Not a valid DES key!");
      }
      }

      // return a cipher for a key - DESede/CBC/PKCS5Padding IV = 0
      protected static Cipher getCipher(SecretKey key, int mode) throws GeneralException {
      byte[] zeros = { 0, 0, 0, 0, 0, 0, 0, 0 };
      IvParameterSpec iv = new IvParameterSpec(zeros);

      // create the Cipher - DESede/CBC/NoPadding
      Cipher encCipher = null;
      try {
      encCipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
      //encCipher = Cipher.getInstance("DES/CFB8/NoPadding");
      } catch (NoSuchAlgorithmException e) {
      throw new GeneralException(e);
      } catch (NoSuchPaddingException e) {
      throw new GeneralException(e);
      }
      try {
      encCipher.init(mode, key, iv);
      } catch (InvalidKeyException e) {
      throw new GeneralException(e);
      } catch (InvalidAlgorithmParameterException e) {
      throw new GeneralException(e);
      }
      return encCipher;
      }

      //MAIN TESTER/DEBUGGER METHOD
      public static void main(String [] args)
      {
           ReorderEmailDecrypter red = new ReorderEmailDecrypter();
           //String rawKey = "Va1ha11a";
           //String stringToEncrypt = "userLoginId=ikarpov_int";
           String stringToEncrypt = args[0];
           byte[] stringToEncryptBytes = stringToEncrypt.getBytes();
           
           String encodedString = null;
           String decodedString = null;

           String decryptedString = null;
           String encryptedString = null;
           
           String encodedEncryptedString= null;
           String decodedEncryptedString= null;
           
           

                
           try {
                
                
                //Encrypt
                encryptedString = red.encrypt(stringToEncrypt);
                byte [] encryptedBytes = encryptedString.getBytes();
                
                System.out.println("stringToEncrypt="+stringToEncrypt);
                System.out.println("encryptedString="+encryptedString);
                System.out.println("encryptedBytes="+encryptedBytes);

                     
                     //Decrypt and compare to the original string
                decryptedString = red.decrypt(encryptedString);
                     
                     if (encryptedString != null && decryptedString != null)
                     {
                          System.out.println("Original String: " + stringToEncrypt);
                          System.out.println("Encrypted String: " + encryptedString);
                          System.out.println("Decrypted String: " + decryptedString + "- better be " + stringToEncrypt);
                          
                          if(stringToEncrypt.equals(decryptedString))
                               System.out.println("encrypt/decrypt:):):):):)");
                          else
                               System.out.println("encrypt/decrypt:(:(:(:(:(");
                     }
                     
                } catch (GeneralException e) {
                     // TODO Auto-generated catch block
                     e.printStackTrace();
                }
           
      }
      }





      //***



      Here is the console output:

      stringToEncrypt=abcd
      encryptedString=��*u�G
      encryptedBytes=[B@1ff7a1e
      Trying to decrypt string ��*u�G - raw key value = MyOwnKey
      org.ofbiz.base.util.GeneralException: Input length must be multiple of 8 when decrypting with padded cipher
           at org.ofbiz.webapp.control.ReorderEmailDecrypter.decrypt(ReorderEmailDecrypter.java:85)
           at org.ofbiz.webapp.control.ReorderEmailDecrypter.decrypt(ReorderEmailDecrypter.java:99)
           at org.ofbiz.webapp.control.ReorderEmailDecrypter.main(ReorderEmailDecrypter.java:193)
      javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher
           at com.sun.crypto.provider.SunJCE_h.b(DashoA12275)
           at com.sun.crypto.provider.SunJCE_h.b(DashoA12275)
           at com.sun.crypto.provider.DESCipher.engineDoFinal(DashoA12275)
           at javax.crypto.Cipher.doFinal(DashoA12275)
           at org.ofbiz.webapp.control.ReorderEmailDecrypter.decrypt(ReorderEmailDecrypter.java:81)
           at org.ofbiz.webapp.control.ReorderEmailDecrypter.decrypt(ReorderEmailDecrypter.java:99)
           at org.ofbiz.webapp.control.ReorderEmailDecrypter.main(ReorderEmailDecrypter.java:193)
      javax.crypto.IllegalBlockSizeException: Input length must be multiple of 8 when decrypting with padded cipher
           at com.sun.crypto.provider.SunJCE_h.b(DashoA12275)
           at com.sun.crypto.provider.SunJCE_h.b(DashoA12275)
           at com.sun.crypto.provider.DESCipher.engineDoFinal(DashoA12275)
           at javax.crypto.Cipher.doFinal(DashoA12275)
           at org.ofbiz.webapp.control.ReorderEmailDecrypter.decrypt(ReorderEmailDecrypter.java:81)
           at org.ofbiz.webapp.control.ReorderEmailDecrypter.decrypt(ReorderEmailDecrypter.java:99)
           at org.ofbiz.webapp.control.ReorderEmailDecrypter.main(ReorderEmailDecrypter.java:193)

      I tried different transformations and paddings, as well as changing the algorithm to 3DES, with corresponding change to key generation - no luck


      NB GeneralException is the OFBiz framework wrapper over the java crypto exception

      Any input or insight will be greatly appreciated.

      Regards.

      Igor Karpov

      Edited by: user8224122 on Sep 4, 2011 5:35 AM

      Edited by: user8224122 on Sep 4, 2011 5:36 AM

      Edited by: user8224122 on Sep 4, 2011 5:39 AM
        • 1. Re: Input length must be multiple of 8 when decrypting with padded cipher
          EJP
          You are comitting the #1 beginner's mistake in encryption. The result of encryption is a byte[] array fr good reason. It is binary data. Stringis not a container for binary data. It is a container for character data. Don't use it to hold cipher text. Use the byte[] array that the APIs already giving you.

          Also you are bamboozling yourself with all that extra exception handling. Just declare all those methods to throw GeneralSecurityException and remove the inner trys and catches completely. You also have a lot of things initialized to null and then tested for null that can never be null.

          Your code works when you fix all this.
          • 2. Re: Input length must be multiple of 8 when decrypting with padded cipher
            800207
            In addition, do not use defaults for the getBytes() method, because it ends up using the platform default charset which can change from platform to platform. Instead explicitly specify UTF-8 as the charset. In my code I usually create a class constant ala
            private static final  java.nio.Charset UTF8 = Charset.forName("UTF-8");
            and then use this in all the getBytes() calls.