title: Given Final Block not properly padded while AES decryption
body: <p>First, I'll tell what is my primary goal. I'm going to use AES to encrypt some content in the client side, then use RSA public key to encrypt the important AES specs and sending both AES encrypted data and RSA encrypted AES specs to server. So at server, I'll decrypt the AES key specs using RSA private key, then using those AES specs, I'll decrypt the AES encrypted data. I've successfully made the RSA part working by test encrypting and decrypting. I've to made this AES art working before implementing RSa in this.</p>
  
  <p>For client side, I'm using crypto-js</p>
  
  <pre><code>&lt;script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js"&gt;&lt;/script&gt;
  &lt;script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/pbkdf2.js"&gt;&lt;/script&gt;
  &lt;script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/enc-base64-min.js"&gt;&lt;/script&gt;
  &lt;script type="text/javascript" src="jquery-1.7.1.js"&gt;&lt;/script&gt;
  &lt;script type="text/javascript"&gt;
  
      $("#submit").click(function() {
          var salt = CryptoJS.lib.WordArray.random(16);
          var iv = CryptoJS.lib.WordArray.random(16);
          var pass = CryptoJS.lib.WordArray.random(16);
          var message = "Test Message for encryption";
          var key128Bits = CryptoJS.PBKDF2(pass, salt, { keySize: 128 }); 
          var key128Bits10Iterations = CryptoJS.PBKDF2(pass, salt, { keySize: 128, iterations: 10 });
          var encrypted = CryptoJS.AES.encrypt(message, key128Bits10Iterations, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7  });
          var cipherData = encrypted.toString()+":"+salt.toString()+":"+iv.toString()+":"+pass.toString();
          console.log(cipherData);
  
          $.ajax({
              url: 'encryption',
              type: 'POST',
              data: {
                  cipherData: cipherData
              },
              success: function(data) {
                  console.log(data);
              },
              failure: function(data) {
  
              }
          });
      });
  
  &lt;/script&gt;
  </code></pre>
  
  <p>And this is the code I'm using in server side</p>
  
  <pre><code>protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      String encryptedData = request.getParameter("cipherData");
      String data[] = encryptedData.split(":");
  
      String encrypted = data[0];     
      String salt = data[1];
      String iv = data[2];
      String password = data[3];
  
      byte[] saltBytes = hexStringToByteArray(salt);
      byte[] ivBytes = hexStringToByteArray(iv);
      IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);        
      SecretKeySpec sKey = null;
      try {
          sKey = (SecretKeySpec) generateKeyFromPassword(password, saltBytes);
      } catch (GeneralSecurityException e) {
          e.printStackTrace();
      }
      try {
          System.out.println( decrypt( encrypted , sKey ,ivParameterSpec));
      } catch (Exception e) {
          e.printStackTrace();
      }
  }
  
  public static SecretKey generateKeyFromPassword(String password, byte[] saltBytes) throws GeneralSecurityException {
  
      KeySpec keySpec = new PBEKeySpec(password.toCharArray(), saltBytes, 10, 128);
      SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
      SecretKey secretKey = keyFactory.generateSecret(keySpec);
  
      return new SecretKeySpec(secretKey.getEncoded(), "AES");
  }
  
  public static byte[] hexStringToByteArray(String s) {
  
      int len = s.length();
      byte[] data = new byte[len / 2];
  
      for (int i = 0; i &lt; len; i += 2) {
          data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) &lt;&lt; 4)
                  + Character.digit(s.charAt(i+1), 16));
      }
  
      return data;
  
  }
  
  public static String decrypt(String encryptedData, SecretKeySpec sKey, IvParameterSpec ivParameterSpec) throws Exception { 
  
      Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
      c.init(Cipher.DECRYPT_MODE, sKey, ivParameterSpec);
      byte[] decordedValue = Base64.decodeBase64(encryptedData);
      byte[] decValue = c.doFinal(decordedValue);
      String decryptedValue = new String(decValue);
  
      return decryptedValue;
  }
  </code></pre>
  
  <p>First I've to make sure that the server is receiving the same data which I'm sending. So I tested it through sysout for encrypted,salt,iv and password. It's received the same data. But I got the exception at line</p>
  
  <pre><code>byte[] decValue = c.doFinal(decordedValue);
  
  javax.crypto.BadPaddingException: Given final block not properly padded
  at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:966)
  at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:824)
  at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:436)
  at javax.crypto.Cipher.doFinal(Cipher.java:2121)
  at com.Encryption.decrypt(Encryption.java:95)
  at com.Encryption.doPost(Encryption.java:60)
  at javax.servlet.http.HttpServlet.service(HttpServlet.java:644)
  at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
  at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
  at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
  at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
  at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:503)
  at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:136)
  at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
  at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
  at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
  at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:526)
  at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1078)
  at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:655)
  at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
  at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1566)
  at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1523)
  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
  at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
  at java.lang.Thread.run(Thread.java:745)
  </code></pre>
  
  <p>You can see that in Javascript side, it's CryptoJS.pad.Pkcs7 and at server side it's AES/CBC/PKCS5Padding , I've done some searches on that and found that both are identical. Neither I can change it to CryptoJS.pad.Pkcs5 nor AES/CBC/PKCS7Padding which is not defined for both Crypto-js libraries and Java inbuild libraries.</p>
  
  <p>And also I'm having the following thought. In javascript, I'm using random salt and pass to generate a 128bits key. And using the same salt and pass, I'm generating the same key in Java by defining appropriate Iteration count and key size. Why should I have to lengthen the process in Java by generating the same key again? I can simply send the key (encrypted.key), encrytedData(encrypted.toString()) and Iv (encrypted.iv) to server and decrypt the data instantly without have to go through the process of generating the key again. Am I right about this..? I've tried this too, where I'm getting "Invalid AES key length exception". For maintaining security, I'll encrypt the key and Iv in client side using RSA public key. One of the reasons for Implementing Symmetric with Asymmetric is due to RSA's limited size of data to be encrypted. But I cant Implement it if I can't clear this BadPaddingException.</p>