encrypt and encode URL parameters spring mvc

送分小仙女□ 提交于 2021-02-18 07:57:08

问题


I am writing a Spring mvc app and it needs to send an email with a link and encrypted params. The user will click on the link and I need to decrypt the params in the new page. So I am writing a util class to encrypt and decrypt along with encoding and decoding the parameters.

When I run my stand alone java class(using for testing) - I get the following error when the decryption is called(encrypting, encoding, decoding works fine).

java.security.InvalidAlgorithmParameterException: Wrong IV length: must be 16 bytes long
    at com.sun.crypto.provider.CipherCore.init(CipherCore.java:430)
    at com.sun.crypto.provider.AESCipher.engineInit(AESCipher.java:217)
    at javax.crypto.Cipher.implInit(Cipher.java:791)
    at javax.crypto.Cipher.chooseProvider(Cipher.java:849)
    at javax.crypto.Cipher.init(Cipher.java:1348)

My class is below

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;


import org.apache.commons.codec.binary.Base64;

public class TestEncryptionEncode2 {

    private String keyString = "asdfgh";

    public static void main(String[] args) throws Exception {
         TestEncryptionEncode2 api = new TestEncryptionEncode2();

         String input = "abcdwer.comq1234";

        try {       
            String[] encrypted = api.encryptObject(input);  
            // url may differ.. based upon project initial context
            System.out.println("http://localhost:8080/view?d="+encrypted[0]+"&v="+encrypted[1]);

                        Object obj = api.decryptObject(encrypted[0], encrypted[1]);
                        System.out.println("Object Decrypted: "+obj.toString());

        }catch(Exception e) {
            //logger.debug("Unable to encrypt view id: "+id, e);
                    e.printStackTrace();
        }   

                System.out.println("DONEE ");

     }

    private String[] encryptObject(Object obj) throws Exception {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        ObjectOutput out = new ObjectOutputStream(stream);
        try {
            // Serialize the object         
            out.writeObject(obj);       
            byte[] serialized = stream.toByteArray();

                        System.out.println("serialized "+serialized[0]);

            // Setup the cipher and Init Vector
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            byte[] iv = new byte[cipher.getBlockSize()];

                System.out.println("cipher.getBlockSize() "+cipher.getBlockSize());
                System.out.println("iv.length "+iv.length);


            new SecureRandom().nextBytes(iv);
            IvParameterSpec ivSpec = new IvParameterSpec(iv);

            // Hash the key with SHA-256 and trim the output to 128-bit for the key
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            digest.update(keyString.getBytes());
            byte[] key = new byte[16];
            System.arraycopy(digest.digest(), 0, key, 0, key.length);
            SecretKeySpec keySpec = new SecretKeySpec(key, "AES");

            // encrypt
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);

            // Encrypt & Encode the input
            byte[] encrypted = cipher.doFinal(serialized);       
            byte[] base64Encoded = Base64.encodeBase64(encrypted);
            String base64String = new String(base64Encoded);
            String urlEncodedData = URLEncoder.encode(base64String,"UTF-8");

            // Encode the Init Vector
            byte[] base64IV = Base64.encodeBase64(iv);
            String base64IVString = new String(base64IV);
            String urlEncodedIV = URLEncoder.encode(base64IVString, "UTF-8");

                System.out.println("urlEncodedData.length "+urlEncodedData.length());
                System.out.println("urlEncodedIV.length "+urlEncodedIV.length());


            return new String[] {urlEncodedData, urlEncodedIV};
        }finally {
            stream.close();
            out.close();
        }
    }

    /**
     * Decrypts the String and serializes the object
     * @param base64Data
     * @param base64IV
     * @return
     * @throws Exception
     */
    public Object decryptObject(String base64Data, String base64IV) throws Exception {

            System.out.println("decryptObject "+base64Data);
            System.out.println("decryptObject "+base64IV);

        // Decode the data
        byte[] encryptedData = Base64.decodeBase64(base64Data.getBytes()); 

        // Decode the Init Vector
        byte[] rawIV = Base64.decodeBase64(base64IV.getBytes()); 
        System.out.println("rawIV "+rawIV.length);
                for (int i=0;i < rawIV.length;i++ ){
                    System.out.println("---------"+rawIV[i]);
                }
        // Configure the Cipher
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        IvParameterSpec ivSpec = new IvParameterSpec(rawIV); 
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        digest.update(keyString.getBytes());
        byte[] key = new byte[16];
        System.arraycopy(digest.digest(), 0, key, 0, key.length);
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec); //////////////////////////////This is the error line

        // Decrypt the data..
        byte[] decrypted = cipher.doFinal(encryptedData);

        // Deserialize the object       
        ByteArrayInputStream stream = new ByteArrayInputStream(decrypted);
        ObjectInput in = new ObjectInputStream(stream);
        Object obj = null;
        try {
            obj = in.readObject(); 
                        System.out.println("objobj "+obj);

        }
                catch(Exception e) {
            //logger.debug("Unable to encrypt view id: "+id, e);
                    e.printStackTrace();
        }finally {
            stream.close();
            in.close();
        }
        return obj;
    }


}

This is the error line - cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);

Do I need to add anything else? Thanks.

EDIT: Thanks, thanks worked. For some reason, I thought I am already decoding the data.

EDIT2: If the text to decode has + in it, then the decoded text will have space instead of +. So I had to replace all the spaces with + back when decrypting. Hopefully this helps someone.


回答1:


The decryption process should be just reverse of encryption process.

Here in encryption you are doing URL encoding before returning it to user. So you must do URL decoding first in your decryption process.

Here is complete decryption process working with URL decoding:

public Object decryptObject(String base64Data, String base64IV) throws Exception {

        System.out.println("decryptObject " + base64Data);
        System.out.println("decryptObject " + base64IV);

        String urlDecodedData=URLDecoder.decode(base64Data,"UTF-8");
        // Decode the data
        byte[] encryptedData = Base64.decodeBase64(urlDecodedData.getBytes());

        String urlDecodedIV=URLDecoder.decode(base64IV,"UTF-8");
        // Decode the Init Vector
        byte[] rawIV = Base64.decodeBase64(urlDecodedIV.getBytes());
        System.out.println("rawIV " + rawIV.length);

        // Configure the Cipher
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        IvParameterSpec ivSpec = new IvParameterSpec(rawIV);
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        digest.update(keyString.getBytes());
        byte[] key = new byte[16];
        System.arraycopy(digest.digest(), 0, key, 0, key.length);
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec); //////////////////////////////This is the error line

        // Decrypt the data..
        byte[] decrypted = cipher.doFinal(encryptedData);

        // Deserialize the object       
        ByteArrayInputStream stream = new ByteArrayInputStream(decrypted);
        ObjectInput in = new ObjectInputStream(stream);
        Object obj = null;
        try {
            obj = in.readObject();
            System.out.println("objobj " + obj);

        } catch (Exception e) {
            //logger.debug("Unable to encrypt view id: "+id, e);
            e.printStackTrace();
        } finally {
            stream.close();
            in.close();
        }
        return obj;
    }


来源:https://stackoverflow.com/questions/30062440/encrypt-and-encode-url-parameters-spring-mvc

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!