全后端交互数据加密

这篇具有很好参考价值的文章主要介绍了全后端交互数据加密。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前后端交互

  • 通信请求使用https
  • 对请求参数进行签名,防止数据篡改
  • 对请求参数以及响应数据进行加解密
  • app中使用ssl pinning防止抓包操作

https协议

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-78n9M2PH-1677252127361)(安全.assets/https加密流程.jpg)]

签名参数

加签和验签:发送方将请求参数通过加密算法生成一个sign值,放到请求参数里;接收方收到请求后,使用同样的方式对请求参数进行加密得到一个sign值,只要两个sign值相同,就说明参数没有被篡改。

加签操作步骤:

  1. 将所有参数(除了sign本身,以及值是空的参数)按参数键字母升序排序。
  2. 然后把排序后的参数按 参数1值1 参数2值2 … 参数n值n 的方式拼接成一个字符串。
  3. 在上一步得到的字符串前面加上密钥key,然后计算md5值,得到32位字符串,然后转成大写,得到的字符串作为sign的值放到请求参数里。

验签操作步骤:

同 加签操作步骤

现在假设需要传输的数据:/guest/rechargeNotify?p2=v2&p1=v1&method=cancel&p3=&pn=vn(实际情况最好是通过post方式发送)

  1. 拼接字符串,首先去除值是空的参数p3,剩下p2=v2&p1=v1&method=cancel&pn=vn,然后按参数名字符升序排序得到字符串:method=cancel&p1=v1&p2=v2&pn=vn。
  2. 然后做参数名和值的拼接,最后得到methodcancelp1v1p2v2pnvn。
  3. 在上面拼接得到的字符串前面加上验证密钥key,假设是abc,得到新的字符串abcmethodcancelp1v1p2v2pnvn。
  4. 将上面得到的字符串进行md5计算,假设得到的是abcdef,然后转为大写,得到ABCDEF这个值即为sign签名值。最终产生的url应该如下:/guest/rechargeNotify?p2=v2&p1=v1&method=cancel&p3=&pn=vn&sign=ABCDEF

MD5加密:

public String getSignMD5(String param, String sign) {
    StringBuffer str = new StringBuffer(sign);
    if(StringUtils.isNotEmpty(param)){
        JSONObject obj = JSONObject.parseObject(param);
        List<String> keys = new ArrayList<String>(obj.keySet());
        keys.remove(ApiSignUtil.SIGN);
        Collections.sort(keys);
        for (String key : keys) {
            Object value = obj.get(key);
            if (value == null) {
                value = "";
            }
            str.append(value);
        }
    }
    return getMd5(str.toString());
}

public String getMd5(String plainText) {
    try {
        MessageDigest md = MessageDigest.getInstance("MD5");
        md.update(plainText.getBytes());
        byte[] b = md.digest();
        StringBuilder buf = new StringBuilder();
        byte[] var5 = b;
        int var6 = b.length;

        for(int var7 = 0; var7 < var6; ++var7) {
            byte aB = var5[var7];
            int i = aB;
            if (aB < 0) {
                i = aB + 256;
            }

            if (i < 16) {
                buf.append("0");
            }

            buf.append(Integer.toHexString(i));
        }

        return buf.toString();
    } catch (NoSuchAlgorithmException var9) {
        var9.printStackTrace();
        return "";
    }
}

加解密请求响应数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bfRrbNux-1677252127362)(安全.assets/1648114154350.png)]

前后端交互常用的通信加密方案:

客户端:

  1. 生成AES密钥,并保存AES密钥;
  2. 用AES密钥对请求传输数据进行加密;
  3. 使用RSA公钥对AES密钥加密,然后把值放到自定义的请求头;
  4. 向服务器发起请求;

服务端:

  1. 拿到自定义的请求头,用RSA私钥解密,得到AES密钥;
  2. 使用AES密钥对请求数据进行解密;
  3. 使用AES密钥对响应数据进行加密;
  4. 向客户端发送响应;

AES对称加密

AES加解密总共有以下这些

算法/模式/填充                 字节加密后数据长度       不满16字节加密后长度  
AES/CBC/NoPadding                   16                          不支持  
AES/CBC/PKCS5Padding                32                          16  
AES/CBC/ISO10126Padding             32                          16  
AES/CFB/NoPadding                   16                          原始数据长度  
AES/CFB/PKCS5Padding                32                          16  
AES/CFB/ISO10126Padding             32                          16  
AES/ECB/NoPadding                   16                          不支持  
AES/ECB/PKCS5Padding                32                          16  
AES/ECB/ISO10126Padding             32                          16  
AES/OFB/NoPadding                   16                          原始数据长度  
AES/OFB/PKCS5Padding                32                          16  
AES/OFB/ISO10126Padding             32                          16  
AES/PCBC/NoPadding                  16                          不支持  
AES/PCBC/PKCS5Padding               32                          16  
AES/PCBC/ISO10126Padding            32                          16

AES/ECB

  • 不带模式和填充来获取AES算法的时候,其默认使用AES/ECB/PKCS5Padding(输入可以不是16字节,也不需要向量)
Cipher cipher = Cipher.getInstance("AES");

AES/ECB/PKCS5Padding

        String content = "在线助手";
        // 生成密钥需要的密码值
        String key = "www.it399.com";
        /**
         * AES加密方式一:AES不指定模式和填充,默认为 ECB/PKCS5Padding
         *
         * 不能使用填充向量
         * java.security.InvalidAlgorithmParameterException: ECB mode cannot use IV
         */
        System.out.println("【0】AES不指定模式和填充,默认为 ECB/PKCS5Padding,输入可以不是16字节,也不需要填充向量\n");
        //128
        byte[] encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_128,EncodeType.AES_DEFAULT);
        encryptOrdecrypt(false,encrypt,key,null,AESType.AES_128,EncodeType.AES_DEFAULT);
        //192
        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_192,EncodeType.AES_DEFAULT);
        encryptOrdecrypt(false,encrypt,key,null,AESType.AES_192,EncodeType.AES_DEFAULT);
        //256
        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_256,EncodeType.AES_DEFAULT);
        encryptOrdecrypt(false,encrypt,key,null,AESType.AES_256,EncodeType.AES_DEFAULT);

AES/CBC

  • 输入必须是16字节,不然报错 javax.crypto.IllegalBlockSizeException: Input length not multiple of 16 bytes
  • CBC模式必须提供初始向量IvParameterSpec,不然报错 java.security.InvalidKeyException: Parameters missing
content: 在线助手
key: www.it399.com111
javax.crypto.IllegalBlockSizeException: Input length not multiple of 16 bytes
    at com.sun.crypto.provider.CipherCore.finalNoPadding(CipherCore.java:1041)
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:1009)
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:847)
    at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
    at javax.crypto.Cipher.doFinal(Cipher.java:2165)
    at com.csy.spring.it399.controller.encode.aes.AESUtil.encrypt(AESUtil.java:80)
    at com.csy.spring.it399.controller.encode.aes.AESUtil.main(AESUtil.java:200)
java.security.InvalidKeyException: Parameters missing
    at com.sun.crypto.provider.CipherCore.init(CipherCore.java:470)
    at com.sun.crypto.provider.AESCipher.engineInit(AESCipher.java:313)
    at javax.crypto.Cipher.implInit(Cipher.java:802)
    at javax.crypto.Cipher.chooseProvider(Cipher.java:864)
    at javax.crypto.Cipher.init(Cipher.java:1249)
    at javax.crypto.Cipher.init(Cipher.java:1186)
    at com.csy.spring.it399.controller.encode.aes.AESUtil.decrypt(AESUtil.java:117)
    at com.csy.spring.it399.controller.encode.aes.AESUtil.main(AESUtil.java:202)
encode: null
decode: null

初始化加密模式的时改成

 Cipher cipher = Cipher.getInstance(AES/CBC/NoPadding);

java.security.InvalidKeyException: Parameters missing解决办法:

if (modeAndPadding.equals(EncodeType.AES_CBC_NoPadding)) {
    //指定一个初始化向量 (Initialization vector,IV), IV 必须是16位
    cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(getIV()));
} else {
    cipher.init(Cipher.ENCRYPT_MODE, keySpec);
}

AES/CBC/NoPadding, AES/CBC/PKCS5Padding, AES/CBC/ISO10126Padding

/**
         * 1.1 AES/CBC
         * AES/CBC/NoPadding
         * AES/CBC/PKCS5Padding
         * AES/CBC/ISO10126Padding
         */
System.out.println("【1.1】AES_CBC_NoPadding模式");
content = "在线助手在线助手在线助手在线助手";
key = "www.it399.com";
encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_128,EncodeType.AES_CBC_NoPadding);
encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_128,EncodeType.AES_CBC_NoPadding);
encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_192,EncodeType.AES_CBC_PKCS5Padding);
encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_192,EncodeType.AES_CBC_PKCS5Padding);
encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_256,EncodeType.AES_CBC_ISO10126Padding);
encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_256,EncodeType.AES_CBC_ISO10126Padding);

AES/CFB

  • 需要向量,不然报如下错误

    java.security.InvalidKeyException: Parameters missing
    
  • AES/CFB/NoPadding,AES/CFB/PKCS5Padding,AES/CFB/ISO10126Padding

    /**
           * 1.2 AES/CFB
           * AES/CBC/NoPadding
           * AES/CBC/PKCS5Padding
           * AES/CBC/ISO10126Padding
           */
    System.out.println("【1.2】AES_CFB_NoPadding模式\n");
    content = "在线助手";
    // 生成密钥需要的密码值
    key = "https://www.it399.com";
    encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_128,EncodeType.AES_CFB_PKCS5Padding);
    encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_128,EncodeType.AES_CFB_PKCS5Padding);
    encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_192,EncodeType.AES_CFB_PKCS5Padding);
    encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_192,EncodeType.AES_CFB_PKCS5Padding);
    encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_256,EncodeType.AES_CFB_PKCS5Padding);
    encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_256,EncodeType.AES_CFB_PKCS5Padding);
    

AES/ECB

  • AES/ECB不要填充变量,不然会报如下错误

    java.security.InvalidAlgorithmParameterException: ECB mode cannot use IV
    

AES/ECB/NoPadding,AES/ECB/PKCS5Padding,AES/ECB/ISO10126Padding

 /**
   * 1.3 AES/ECB
   * AES/ECB/NoPadding
   * AES/ECB/PKCS5Padding
   * AES/ECB/ISO10126Padding
   */
  System.out.println("【1.3】AES_ECB模式");
  content = "在线助手";
  // 生成密钥需要的密码值
  key = "https://www.it399.com";
  encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_128,EncodeType.AES_ECB_PKCS5Padding);
  encryptOrdecrypt(false,encrypt,key,null,AESType.AES_128,EncodeType.AES_ECB_PKCS5Padding);
  encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_192,EncodeType.AES_ECB_PKCS5Padding);
  encryptOrdecrypt(false,encrypt,key,null,AESType.AES_192,EncodeType.AES_ECB_PKCS5Padding);
  encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_256,EncodeType.AES_ECB_PKCS5Padding);
  encryptOrdecrypt(false,encrypt,key,null,AESType.AES_256,EncodeType.AES_ECB_PKCS5Padding);

完整代码

AESUtil .java

import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
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.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
 * 在线助手|在线工具|在线生成|在线制作
 * https://www.it399.com/
 * 在线助手博客
 * https://www.it399.com/blog/index
 */
public class AESUtil {
    public static final String CHARSET = "UTF-8";
    private static byte[] encryptOrDecrypt(int mode,byte[] byteContent, String key,byte[] iv, AESType type, String modeAndPadding) throws InvalidKeyException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        //此处解决mac,linux报错
        SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
        random.setSeed(key.getBytes());
        kgen.init(type.value, random);
        SecretKey secretKey = kgen.generateKey();
        byte[] enCodeFormat = secretKey.getEncoded();
        SecretKeySpec keySpec = new SecretKeySpec(enCodeFormat, "AES");
        Cipher cipher = Cipher.getInstance(modeAndPadding);// 创建密码器
        if ( null !=iv ) {
            //指定一个初始化向量 (Initialization vector,IV), IV 必须是16位
            cipher.init(mode, keySpec, new IvParameterSpec(iv));
        } else {
            cipher.init(mode, keySpec);
        }
        byte[] result = cipher.doFinal(byteContent);
        return result;
    }
    public static void main(String[] args) throws Exception {
//        System.out.println("【1】AES不指定模式和填充,默认为 ECB/PKCS5Padding,输入可以不是16字节,也不需要填充向量\n");
//        // 需要加密的内容
//        String content = "在线助手";
//        // 生成密钥需要的密码值
//        String key = "www.it399.com111";
//        System.out.println("content: " + content + "\nkey: " + key);
//        byte[] encodeByte;
//        byte[] decodeByte;
//        //默认方式  每次加密都不一样,但是秘钥是一样的,所以解密还是一样的
//        // 内容加密后的值
//        encodeByte = encrypt(content.getBytes(CHARSET), key, AESType.AES_128, EncodeType.AES_DEFAULT);
//        String encodeStr = TypeConvert.bytesToHexString(encodeByte);
//        // 被加密的内容解密后的值
//        decodeByte = decrypt(encodeByte, key, AESType.AES_128, EncodeType.AES_DEFAULT);
//        String decodeStr = new String(decodeByte,CHARSET);
//        System.out.println("encode: " + encodeStr + "\ndecode: " + decodeStr);
//
//
//        System.out.println("【2】AES_CBC_NoPadding模式,输入必须是16*n字节,需要填充向量\n");
//        // 内容加密后的值
//        //待加密内容不足16*n位 报错javax.crypto.IllegalBlockSizeException: Input length not multiple of 16 bytes
//        //需要填充向量,不然报错java.security.InvalidKeyException: Parameters missing
//        //得到加密后的内容先base64编码再解码再传给解码,不然直接转回乱码
//        content = "哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈";
//        encodeByte = encrypt(content.getBytes(CHARSET), key, AESType.AES_256, EncodeType.AES_CBC_NoPadding);
//        encodeStr = TypeConvert.bytesToHexString(encodeByte);
//        decodeByte = decrypt(TypeConvert.hexStringToBytes(encodeStr), key, AESType.AES_256, EncodeType.AES_CBC_NoPadding);
//        decodeStr = new String(decodeByte,CHARSET);
//        System.out.println("encode: " + encodeStr + "\ndecode: " + decodeStr);
        String content = "在线助手";
        // 生成密钥需要的密码值
        String key = "www.it399.com";
        byte[] encrypt;
        /**
         * AES加密方式一:AES不指定模式和填充,默认为 ECB/PKCS5Padding
         */
//        System.out.println("【0】AES不指定模式和填充,默认为 ECB/PKCS5Padding,输入可以不是16字节,也不需要填充向量\n");
//        //128
//        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_128,EncodeType.AES_DEFAULT);
//        encryptOrdecrypt(false,encrypt,key,null,AESType.AES_128,EncodeType.AES_DEFAULT);
//        //192
//        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_192,EncodeType.AES_DEFAULT);
//        encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_192,EncodeType.AES_DEFAULT);
//        //256
//        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_256,EncodeType.AES_DEFAULT);
//        encryptOrdecrypt(false,encrypt,key,null,AESType.AES_256,EncodeType.AES_DEFAULT);
//        /**
//         * 1.1 AES/CBC (需要填充向量16*n)
//         * AES/CBC/NoPadding
//         * AES/CBC/PKCS5Padding
//         * AES/CBC/ISO10126Padding
//         */
//        System.out.println("【1.1】AES_CBC_NoPadding模式,需要填充向量,待加密必须是16*n");
//        content = "在线助手在线助手在线助手在线助手";
//        key = "www.it399.com";
//        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_128,EncodeType.AES_CBC_NoPadding);
//        encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_128,EncodeType.AES_CBC_NoPadding);
//        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_192,EncodeType.AES_CBC_PKCS5Padding);
//        encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_192,EncodeType.AES_CBC_PKCS5Padding);
//        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_256,EncodeType.AES_CBC_ISO10126Padding);
//        encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_256,EncodeType.AES_CBC_ISO10126Padding);
//        /**
//         * 1.2 AES/CFB
//         * AES/CBC/NoPadding
//         * AES/CBC/PKCS5Padding
//         * AES/CBC/ISO10126Padding
//         */
//        System.out.println("【1.2】AES_CFB_NoPadding模式\n");
//        content = "在线助手";
//        // 生成密钥需要的密码值
//        key = "https://www.it399.com";
//        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_128,EncodeType.AES_CFB_PKCS5Padding);
//        encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_128,EncodeType.AES_CFB_PKCS5Padding);
//        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_192,EncodeType.AES_CFB_PKCS5Padding);
//        encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_192,EncodeType.AES_CFB_PKCS5Padding);
//        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_256,EncodeType.AES_CFB_PKCS5Padding);
//        encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_256,EncodeType.AES_CFB_PKCS5Padding);
//        /**
//         * 1.2 AES/ECB
//         * AES/ECB/NoPadding
//         * AES/ECB/PKCS5Padding
//         * AES/ECB/ISO10126Padding
//         */
//        System.out.println("【1.3】AES_ECB模式");
//        content = "在线助手";
//        // 生成密钥需要的密码值
//        key = "https://www.it399.com";
//        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_128,EncodeType.AES_ECB_PKCS5Padding);
//        encryptOrdecrypt(false,encrypt,key,null,AESType.AES_128,EncodeType.AES_ECB_PKCS5Padding);
//        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_192,EncodeType.AES_ECB_PKCS5Padding);
//        encryptOrdecrypt(false,encrypt,key,null,AESType.AES_192,EncodeType.AES_ECB_PKCS5Padding);
//        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_256,EncodeType.AES_ECB_PKCS5Padding);
//        encryptOrdecrypt(false,encrypt,key,null,AESType.AES_256,EncodeType.AES_ECB_PKCS5Padding);
        /**
         * 1.4 AES/OFB
         * AES/OFB/NoPadding
         * AES/OFB/PKCS5Padding
         * AES/OFB/ISO10126Padding
         */
        System.out.println("【1.4】AES_OFB模式");
        content = "在线助手";
        // 生成密钥需要的密码值
        key = "https://www.it399.com";
        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_128,EncodeType.AES_OFB_PKCS5Padding);
        encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_128,EncodeType.AES_OFB_PKCS5Padding);
        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_192,EncodeType.AES_OFB_PKCS5Padding);
        encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_192,EncodeType.AES_OFB_PKCS5Padding);
        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_256,EncodeType.AES_OFB_PKCS5Padding);
        encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_256,EncodeType.AES_OFB_PKCS5Padding);
        /**
         * 1.5 AES/PCBC
         * AES/PCBC/NoPadding
         * AES/PCBC/PKCS5Padding
         * AES/PCBC/ISO10126Padding
         */
        System.out.println("【1.5】AES_PCBC模式");
        content = "在线助手";
        // 生成密钥需要的密码值
        key = "https://www.it399.com";
        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_128,EncodeType.AES_PCBC_PKCS5Padding);
        encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_128,EncodeType.AES_PCBC_PKCS5Padding);
        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_192,EncodeType.AES_PCBC_PKCS5Padding);
        encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_192,EncodeType.AES_PCBC_PKCS5Padding);
        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_256,EncodeType.AES_PCBC_PKCS5Padding);
        encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_256,EncodeType.AES_PCBC_PKCS5Padding);
        //
//        /**1.3 AES/CBC
//         * AES_CBC_NoPadding模式(填充向量可选)
//         */
        System.out.println("【1.3】AES_CBC_NoPadding模式");
        content = "在线助手在线助手在线助手在线助手";
        // 生成密钥需要的密码值
        key = "www.it399.com";
        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_128,EncodeType.AES_CBC_NoPadding);
        encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_128,EncodeType.AES_CBC_NoPadding);
        content = "在线助手";
        // 生成密钥需要的密码值
        key = "www.it399.com";
        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_192,EncodeType.AES_CBC_PKCS5Padding);
        encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_192,EncodeType.AES_CBC_PKCS5Padding);
        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,getIV(),AESType.AES_256,EncodeType.AES_CBC_ISO10126Padding);
        encryptOrdecrypt(false,encrypt,key,getIV(),AESType.AES_256,EncodeType.AES_CBC_ISO10126Padding);
//
//
//
//        /**
//         * 2.1 AES/CFB 128/192/256位加解密
//         * AES_CFB_NoPadding模式(填充向量可选)
//         */
//        System.out.println("【2.1】AES_CFB_NoPadding模式,需要填充向量\n");
//        content = "在线助手";
//        // 生成密钥需要的密码值
//        key = "www.it399.com";
//        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_128,EncodeType.AES_CFB_NoPadding);
//        encryptOrdecrypt(false,encrypt,key,null,AESType.AES_128,EncodeType.AES_CFB_NoPadding);
//        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_192,EncodeType.AES_CFB_NoPadding);
//        encryptOrdecrypt(false,encrypt,key,null,AESType.AES_192,EncodeType.AES_CFB_NoPadding);
//        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_256,EncodeType.AES_CFB_NoPadding);
//        encryptOrdecrypt(false,encrypt,key,null,AESType.AES_256,EncodeType.AES_CFB_NoPadding);
//
//        /**
//         * 2.2 AES/CFB
//         * AES_CFB_NoPadding模式(填充向量可选)
//         */
//        System.out.println("【2.2】AES_CFB_NoPadding模式\n");
//        content = "在线助手";
//        // 生成密钥需要的密码值
//        key = "www.it399.com";
//        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_128,EncodeType.AES_CFB_PKCS5Padding);
//        encryptOrdecrypt(false,encrypt,key,null,AESType.AES_128,EncodeType.AES_CFB_PKCS5Padding);
//        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_192,EncodeType.AES_CFB_PKCS5Padding);
//        encryptOrdecrypt(false,encrypt,key,null,AESType.AES_192,EncodeType.AES_CFB_PKCS5Padding);
//        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_256,EncodeType.AES_CFB_PKCS5Padding);
//        encryptOrdecrypt(false,encrypt,key,null,AESType.AES_256,EncodeType.AES_CFB_PKCS5Padding);
//
//        /**2.3 AES/CFB
//         * AES_CFB_NoPadding模式(填充向量可选)
//         */
//        System.out.println("【2.3】AES_CFB_NoPadding模式\n");
//        content = "在线助手";
//        // 生成密钥需要的密码值
//        key = "www.it399.com";
//        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_128,EncodeType.AES_CFB_ISO10126Padding);
//        encryptOrdecrypt(false,encrypt,key,null,AESType.AES_128,EncodeType.AES_CFB_ISO10126Padding);
//        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_192,EncodeType.AES_CFB_ISO10126Padding);
//        encryptOrdecrypt(false,encrypt,key,null,AESType.AES_192,EncodeType.AES_CFB_ISO10126Padding);
//        encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_256,EncodeType.AES_CFB_ISO10126Padding);
//        encryptOrdecrypt(false,encrypt,key,null,AESType.AES_256,EncodeType.AES_CFB_ISO10126Padding);
    }
    /**
     *
     * @param isEncrypt
     * @param source
     * @param key
     * @param type
     * @param encodeType
     */
    public static byte[] encryptOrdecrypt(boolean isEncrypt,byte[] source,String key,byte[] iv,AESType type,String encodeType) throws UnsupportedEncodingException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException, InvalidKeyException {
        if (isEncrypt){
            byte[] encodeByte = encryptOrDecrypt(Cipher.ENCRYPT_MODE,source,key,iv,type,encodeType);
            String encodeStr = TypeConvert.bytesToHexString(encodeByte);
            return encodeByte;
        }else{
            byte[] decodeByte = encryptOrDecrypt(Cipher.DECRYPT_MODE,source, key,iv,type, encodeType);
            String decodeStr = new String(decodeByte,CHARSET);
            return decodeByte;
        }
    }
    /**
     * 指定一个初始化向量 (Initialization vector,IV),IV 必须是16位
     */
    public static final byte[] getIV() throws Exception {
        return "1234567812345678".getBytes(CHARSET);
    }

EncodeType文章来源地址https://www.toymoban.com/news/detail-774867.html

/**
 * 在线助手|在线工具|在线生成|在线制作
 * https://www.it399.com/
 * 在线助手博客
 * https://www.it399.com/blog/index
 */
public class EncodeType {
//    算法/模式/填充                 16字节加密后数据长度       不满16字节加密后长度
//    AES/CBC/NoPadding                   16                          不支持
//    AES/CBC/PKCS5Padding                32                          16
//    AES/CBC/ISO10126Padding             32                          16
//    AES/CFB/NoPadding                   16                          原始数据长度
//    AES/CFB/PKCS5Padding                32                          16
//    AES/CFB/ISO10126Padding             32                          16
//    AES/ECB/NoPadding                   16                          不支持
//    AES/ECB/PKCS5Padding                32                          16
//    AES/ECB/ISO10126Padding             32                          16
//    AES/OFB/NoPadding                   16                          原始数据长度
//    AES/OFB/PKCS5Padding                32                          16
//    AES/OFB/ISO10126Padding             32                          16
//    AES/PCBC/NoPadding                  16                          不支持
//    AES/PCBC/PKCS5Padding               32                          16
//    AES/PCBC/ISO10126Padding            32                          16
    //默认为 ECB/PKCS5Padding
    public final static String AES_DEFAULT = "AES";
    public final static String AES_CBC_NoPadding = "AES/CBC/NoPadding";
    public final static String AES_CBC_PKCS5Padding = "AES/CBC/PKCS5Padding";
    public final static String AES_CBC_ISO10126Padding = "AES/CBC/ISO10126Padding";
    public final static String AES_CFB_NoPadding = "AES/CFB/NoPadding";
    public final static String AES_CFB_PKCS5Padding = "AES/CFB/PKCS5Padding";
    public final static String AES_CFB_ISO10126Padding = "AES/CFB/ISO10126Padding";
    public final static String AES_ECB_NoPadding = "AES/ECB/NoPadding";
    public final static String AES_ECB_PKCS5Padding = "AES/ECB/PKCS5Padding";
    public final static String AES_ECB_ISO10126Padding = "AES/ECB/ISO10126Padding";
    public final static String AES_OFB_NoPadding = "AES/OFB/NoPadding";
    public final static String AES_OFB_PKCS5Padding = "AES/OFB/PKCS5Padding";
    public final static String AES_OFB_ISO10126Padding = "AES/OFB/ISO10126Padding";
    public final static String AES_PCBC_NoPadding = "AES/PCBC/NoPadding";
    public final static String AES_PCBC_PKCS5Padding = "AES/PCBC/PKCS5Padding";
    public final static String AES_PCBC_ISO10126Padding = "AES/PCBC/ISO10126Padding";
}

另附代码

package net.trueland.employee.common;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

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

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

import com.alibaba.fastjson.JSONObject;

public class SecurityUtils {

    public static final String ALGORITHM_AES = "AES";
    public static final String CHARSET_UTF8 = "UTF-8";

    /**
     * 参数加签
     * @param json 参数,仅支持json对象
     * @param key 密钥
     * @return 密文
     */
    public static String signParam(String json, String key) throws Exception {
        if (StringUtils.isBlank(json)) {
            return StringUtils.EMPTY;
        }
        if (StringUtils.isBlank(key)) {
            throw new Exception("param add sign error: no key");
        }
        StringBuffer stringBuffer = new StringBuffer(key);
        JSONObject jsonObject = JSONObject.parseObject(json);
        List<String> keyList = new ArrayList<String>(jsonObject.keySet());
        keyList.remove("sign");
        Collections.sort(keyList);
        for (String s : keyList) {
            Object o = jsonObject.get(s);
            if (o == null) {
                o = "";
            }
            stringBuffer.append(s);
            stringBuffer.append(o);
        }
        return stringBuffer.toString();
    }

    /**
     * md5 加密
     * @param str 明文
     * @return
     */
    public static String encryptMD5(String str) {
        MessageDigest md = null;
        try {
            md = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            // TODO 异常处理
        }

        md.update(str.getBytes());
        byte[] b = md.digest();
        StringBuilder buf = new StringBuilder();
        byte[] var5 = b;
        int var6 = b.length;

        for (int var7 = 0; var7 < var6; ++var7) {
            byte aB = var5[var7];
            int i = aB;
            if (aB < 0) {
                i = aB + 256;
            }
            if (i < 16) {
                buf.append("0");
            }
            buf.append(Integer.toHexString(i));
        }
        return buf.toString();
    }

    // ------------------------------------------AES/ECB/PKCS5Padding加解密, AES默认的加密方式--------------------------------------------------
    /**
     * 加密速度快
     * 该模式不可以使用向量,否则报错:java.security.InvalidAlgorithmParameterException: ECB mode cannot use IV
     * @param plaintext 明文
     * @param key 密钥 不强制位数
     * @return 密文
     */
    public static String encrypt(String plaintext, String key) throws Exception {
        return encryptOrDecrypt(Cipher.ENCRYPT_MODE, plaintext, key, null, "AES/ECB/PKCS5Padding");
    }

    /**
     * 加密速度快
     * 该模式不可以使用向量,否则报错:java.security.InvalidAlgorithmParameterException: ECB mode cannot use IV
     * @param ciphertext 密文
     * @param key 密钥 不强制位数
     * @return 明文
     */
    public static String decrypt(String ciphertext, String key) throws Exception {
        return encryptOrDecrypt(Cipher.DECRYPT_MODE, ciphertext, key, null, "AES/ECB/PKCS5Padding");
    }

    // ------------------------------------------AES/CBC/PKCS5Padding 加解密--------------------------------------------------
    /**
     * 安全性高,加密速度慢
     * CBC模式必须提供向量,否则报错:java.security.InvalidKeyException: Parameters missing
     * @param plaintext 明文
     * @param key 密钥,不强制位数
     * @param offset 偏移量,提高安全性,强制16位
     * @return 密文
     */
    public static String encrypt(String plaintext, String key, String offset) throws Exception {
        return encryptOrDecrypt(Cipher.ENCRYPT_MODE, plaintext, key, offset.getBytes(CHARSET_UTF8), "AES/CBC/PKCS5Padding");
    }

    /**
     * 安全性高,加密速度慢
     * CBC模式必须提供向量,否则报错:java.security.InvalidKeyException: Parameters missing
     * @param ciphertext 密文
     * @param key 密钥,不强制位数
     * @param offset 偏移量,提高安全性,强制16位
     * @return 明文
     */
    public static String decrypt(String ciphertext, String key, String offset) throws Exception {
        return encryptOrDecrypt(Cipher.DECRYPT_MODE, ciphertext, key, offset.getBytes(CHARSET_UTF8), "AES/CBC/PKCS5Padding");
    }

    /**
     * 加密或解密
     * @param mode 加密1 解密2
     * @param content 明文或密文
     * @param key 密钥
     * @param iv 向量
     * @param modeAndPadding 加密类型和填充类型
     * @return
     * @throws Exception
     */
    private static String encryptOrDecrypt(int mode, String content, String key, byte[] iv, String modeAndPadding) throws Exception {
        byte[] byteContent = Cipher.ENCRYPT_MODE == mode ? content.getBytes(CHARSET_UTF8) : Base64.decodeBase64(content);
        // 密钥生成器
        KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM_AES);
        // 随机数,不可以随时间随机,否则mac,linux报错
        SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
        // 设置随机种子
        random.setSeed(key.getBytes(CHARSET_UTF8));
        // 初始化密钥生成器
        keyGenerator.init(128, random);
        // 生成密钥
        SecretKey secretKey = keyGenerator.generateKey();
        // 生成AES专用密钥
        SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getEncoded(), ALGORITHM_AES);

        // 创建加/解密器
        Cipher cipher = Cipher.getInstance(modeAndPadding);
        // 初始化加/解密器
        if (null != iv){
            // 指定向量,提高安全性
            cipher.init(mode,secretKeySpec,new IvParameterSpec(iv));
        }else {
            cipher.init(mode, secretKeySpec);
        }
        // 加密/解密
        byte[] result = cipher.doFinal(byteContent);
        return Cipher.ENCRYPT_MODE == mode ? Base64.encodeBase64String(result) : new String(result);
    }
    
     /**
     * 随机生成指定长度的密钥
     * @param length
     */
    public static String randomKey(int length){
        return RandomStringUtils.randomAlphanumeric(length);
    }
}

RSA非对称加密

public class RSAEncrypt {
	private static Map<Integer, String> keyMap = new HashMap<Integer, String>();  //用于封装随机产生的公钥与私钥
	public static void main(String[] args) throws Exception {
		//生成公钥和私钥
		genKeyPair();
		//加密字符串
		String message = "df723820";
		System.out.println("随机生成的公钥为:" + keyMap.get(0));
		System.out.println("随机生成的私钥为:" + keyMap.get(1));
		String messageEn = encrypt(message,keyMap.get(0));
		System.out.println(message + "\t加密后的字符串为:" + messageEn);
		String messageDe = decrypt(messageEn,keyMap.get(1));
		System.out.println("还原后的字符串为:" + messageDe);
	}

	/** 
	 * 随机生成密钥对 
	 * @throws NoSuchAlgorithmException 
	 */  
	public static void genKeyPair() throws NoSuchAlgorithmException {  
		// KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象  
		KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");  
		// 初始化密钥对生成器,密钥大小为96-1024位  
		keyPairGen.initialize(1024,new SecureRandom());  
		// 生成一个密钥对,保存在keyPair中  
		KeyPair keyPair = keyPairGen.generateKeyPair();  
		RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();   // 得到私钥  
		RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();  // 得到公钥  
		String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));  
		// 得到私钥字符串  
		String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded())));  
		// 将公钥和私钥保存到Map
		keyMap.put(0,publicKeyString);  //0表示公钥
		keyMap.put(1,privateKeyString);  //1表示私钥
	}  
	/** 
	 * RSA公钥加密 
	 *  
	 * @param str 
	 *            加密字符串
	 * @param publicKey 
	 *            公钥 
	 * @return 密文 
	 * @throws Exception 
	 *             加密过程中的异常信息 
	 */  
	public static String encrypt( String str, String publicKey ) throws Exception{
		//base64编码的公钥
		byte[] decoded = Base64.decodeBase64(publicKey);
		RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
		//RSA加密
		Cipher cipher = Cipher.getInstance("RSA");
		cipher.init(Cipher.ENCRYPT_MODE, pubKey);
		String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8")));
		return outStr;
	}

	/** 
	 * RSA私钥解密
	 *  
	 * @param str 
	 *            加密字符串
	 * @param privateKey 
	 *            私钥 
	 * @return 铭文
	 * @throws Exception 
	 *             解密过程中的异常信息 
	 */  
	public static String decrypt(String str, String privateKey) throws Exception{
		//64位解码加密后的字符串
		byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8"));
		//base64编码的私钥
		byte[] decoded = Base64.decodeBase64(privateKey);  
        RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));  
		//RSA解密
		Cipher cipher = Cipher.getInstance("RSA");
		cipher.init(Cipher.DECRYPT_MODE, priKey);
		String outStr = new String(cipher.doFinal(inputByte));
		return outStr;
	}

}

到了这里,关于全后端交互数据加密的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Oracle数据传输加密方法

    服务器端“dbhome_1NETWORKADMIN”sqlnet.ora文件中添加 SQLNET.ENCRYPTION_SERVER = requested SQLNET.ENCRYPTION_TYPES_SERVER= (RC4_256) 添加后新的链接即刻生效,服务器无需重新启动。 也可以通过Net manager管理工具添加  各个参数含义如下: 是否加密(ENCRYPTION_SERVER)取值包含REJECTED、ACCEPTED、REQ

    2024年02月10日
    浏览(53)
  • 实战:加密传输数据解密

    下面将分享一些实际的渗透测试经验,帮助你应对在测试中遇到的数据包内容加密的情况。我们将以实战为主,技巧为辅,进入逆向的大门。 开局先讲一下技巧,掌握好了技巧,方便逆向的时候可以更加快速的找到关键函数位置! 后续也会有更多的实战会按照技巧去操作。

    2024年01月23日
    浏览(47)
  • 前后端分离数据传输加解密方案(建议方案二)

          a.优点:实现简单,比明文传输安全       b.缺点:1)由于加密所有参数,效率低下 2)信息全加密,不利于前后端联调  3)密钥传输不安全,容易被拦截        优化点:前端生成AES对称加密密钥,用rsa私钥非对称加密将AES密钥加密,传给到后端,后端用rsa公钥解密后获

    2024年02月02日
    浏览(36)
  • JS使用RSA非对称加密方式加密传输数据

    场景:出于安全考虑,要求对页面提交的关键信息进行加密,在网络传输过程中使用密文传递,在服务器端解密后使用。这样不管在浏览器端还是网络传输中截获了数据,都无法获取实际的信息。 方法:使用非对称加密算法,在前端页面使用公钥进行加密,在后端服务使用密

    2023年04月08日
    浏览(38)
  • Linkerd 的数据加密与安全传输

    在现代互联网时代,数据的安全性和传输的隐私性已经成为了重要的问题。随着微服务架构的普及,服务之间的通信量和复杂性都增加了。因此,在这种情况下,如何确保数据的安全传输成为了关键问题。Linkerd 是一款开源的服务网格,它可以帮助我们实现数据的加密和安全

    2024年04月16日
    浏览(34)
  • SSL加密:保护数据传输的安全盾牌

    🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_ CSDN 博客专家、23年度博客之星前端领域TOP1 🕠 牛客 高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课 签约作者、上架课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你

    2024年03月28日
    浏览(47)
  • Android实现与PHP后端的交互(数据传输,文件传输)(超详细/附源码)

    为方便大家浏览,源码先行奉上 github源码链接 https://github.com/Recycle1/Android-connect-PHP csdn源码链接 https://download.csdn.net/download/weixin_52263647/87751491 在Android开发中,经常涉及与服务器端交互的过程,在现在的APP制作中,经常利用互联网通信,从云端获取图片,数据等信息,本篇文

    2024年01月19日
    浏览(39)
  • 基于netty框架不使用SSL证书,实现websocket数据加密传输

    1、简介 2、实现方式 3、服务端主要代码 4、客户端主要代码 5、调用方式 为什么不使用SSL证书? 1、服务器运行在专网环境,不能访问互联网。证书有有效期,CA机构规定,证书有效期最多2年。在客户的专网环境里更新和维护证书就会增加运营成本。 实现逻辑? 参照SSL的实

    2024年02月04日
    浏览(57)
  • vhost-net-原理-初始化流程-数据传输流程-vhost-net后端

    传统的virtio网卡是通过虚拟机内部的virtio驱动作为前端,负责将虚拟机内部的IO请求封装到vring descriptor中,然后通过写MMIO或PIO的方式通知QEMU中的virtio后端设备,QEMU将这些IO请求设备发送到tap设备,然后通过网桥发送到真实的网卡上 vhost方案也是通过虚拟机中的virtio驱动将I

    2024年02月11日
    浏览(41)
  • 【IMX6ULL驱动开发学习】04.应用程序和驱动程序数据传输和交互的4种方式:非阻塞、阻塞、POLL、异步通知 一、数据传输

    目录 一、数据传输 1.1 APP和驱动  1.2 驱动和硬件 二、APP使用驱动的4种方式 2.1 非阻塞(查询) 2.2 阻塞(休眠+唤醒) 2.3 POLL(休眠+唤醒+超时时间) 2.3.1 POLL机制流程 2.3.2 POLL执行流程 2.3.3 POLL应用和驱动编程  2.4 异步通知 2.4.1 异步通知流程 2.4.1 异步通知应用和驱动编程

    2024年02月13日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包