Given Final Block not properly padded while AES decryption

后端 未结 2 1199
遥遥无期
遥遥无期 2021-01-03 15:56

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 s

相关标签:
2条回答
  • 2021-01-03 16:52

    Since you want to use RSA and did already implement it, there is no need to use a password derivation. Create a random key and random iv:

    var key = CryptoJS.lib.WordArray.random(16); // 128bit
    var iv = CryptoJS.lib.WordArray.random(16);  // 128bit
    var encrypted = CryptoJS.AES.encrypt(message, key, { iv: iv }); // CBC/PKCS#7 is default
    

    Then you send iv.toString(Crypto.enc.Base64), encrypted.ciphertext.toString(Crypto.enc.Base64) and "RSAencrypt(key)" to the server, decode the base64 encoded iv and ciphertext, decrypt the RSA ciphertext to get the AES key and combine all of them to decrypt the ciphertext.


    Your original problem probably lies in the sizes that you use. CryptoJS has an internal representation which consists of 4 bytes per word. That is why you need to divide by 32 for example to get a 128-bit hash:

    var key128Bits = CryptoJS.PBKDF2(pass, salt, { keySize: 128/32 });
    

    The WordArray on the other hand works only on bytes which is why you divide by 8:

    var key = CryptoJS.lib.WordArray.random(128/8);
    
    0 讨论(0)
  • 2021-01-03 17:00

    Thanks to Artjom B.

    Solution : Working Code

    Javascript / Client Code

    <script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js"></script>
    <script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/pbkdf2.js"></script>
    <script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/enc-base64-min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
    
    <script type="text/javascript">
    
        $("#submit").click(function() {
    
            var key = CryptoJS.lib.WordArray.random(16);
            var iv= CryptoJS.lib.WordArray.random(16);
            var message = "<username>user</username>";
            var encrypted = CryptoJS.AES.encrypt(message, key, { iv: iv });
    
            // If you want the decryption at client side, use the commented code
    
            /* var decrypted = CryptoJS.AES.decrypt(encrypted, key, { iv:iv });
            function hex2a(hexx) {
                var hex = hexx.toString();//force conversion
                var str = '';
                for (var i = 0; i < hex.length; i += 2)
                    str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
                return str;
            }
            console.log("decrypted: "+hex2a(decrypted)); */
    
            var cipherData = iv.toString(CryptoJS.enc.Base64)+":"+encrypted.ciphertext.toString()+":"+key.toString(CryptoJS.enc.Base64);
    
            $.ajax({
                url: 'encryption',
                type: 'POST',
                data: {
                    cipherData: cipherData
                },
                success: function(data) {
                    console.log(data);
                },
                failure: function(data) {
    
                }
            });
        });
    
    </script>
    

    Server / Java Code

    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.security.InvalidAlgorithmParameterException;
    import java.security.InvalidKeyException;
    import java.security.Key;
    import java.security.NoSuchAlgorithmException;
    import java.security.SecureRandom;
    import javax.crypto.BadPaddingException;
    import javax.crypto.Cipher;
    import javax.crypto.IllegalBlockSizeException;
    import javax.crypto.KeyGenerator;
    import javax.crypto.NoSuchPaddingException;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    // You have to download and add it into your project, others are Java Inbuilt Libraries
    // Do not use sun.misc for Base64 functions
    import org.apache.commons.codec.binary.Base64; 
    
    public class BasicDecryption {
    
    //I've done it in post method of servlet
    
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
        String encryptedData = request.getParameter("cipherData");
        String data[] = encryptedData.split(":");
        String iv = data[0];
        byte[] encryptedByteData = hexStringToByteArray(data[1]);
        String keyString = data[2];
    
        IvParameterSpec iv = new IvParameterSpec(Base64.decodeBase64(iv);
        Key k = new SecretKeySpec(Base64.decodeBase64(keyString),"AES");
    
        try {
            System.out.println("Decrypted String:"+BasicDecryption.decrypt(Base64.encodeBase64String(encryptedByteData),k,iv));
        } catch (InvalidKeyException | NoSuchAlgorithmException
                | NoSuchPaddingException | IllegalBlockSizeException
                | BadPaddingException | InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        }
    }
    
    public static final String decrypt(final String encrypted,final Key key, final IvParameterSpec iv) throws InvalidKeyException,
    NoSuchAlgorithmException, NoSuchPaddingException,
    IllegalBlockSizeException, BadPaddingException, IOException, InvalidAlgorithmParameterException {
    
          Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
          cipher.init(Cipher.DECRYPT_MODE, key,iv);
          byte[] raw = Base64.decodeBase64(encrypted);
          byte[] stringBytes = cipher.doFinal(raw);
          String clearText = new String(stringBytes, "UTF8");
          return clearText;
    }
    
    public static byte[] hexStringToByteArray(String s) {
    
        int len = s.length();
        byte[] data = new byte[len / 2];
    
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                    + Character.digit(s.charAt(i+1), 16));
        }
        return data;
    }
    }
    
    0 讨论(0)
提交回复
热议问题