当前位置: 首页 > news >正文

全后端交互数据加密

前后端交互

  • 通信请求使用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");//128byte[] 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);//192encrypt = encryptOrdecrypt(true,content.getBytes(CHARSET),key,null,AESType.AES_192,EncodeType.AES_DEFAULT);encryptOrdecrypt(false,encrypt,key,null,AESType.AES_192,EncodeType.AES_DEFAULT);//256encrypt = 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 bytesat 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 missingat 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.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/PKCS5Paddingpublic 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())));  // 将公钥和私钥保存到MapkeyMap.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;}}

相关文章:

全后端交互数据加密

前后端交互 通信请求使用https对请求参数进行签名&#xff0c;防止数据篡改对请求参数以及响应数据进行加解密app中使用ssl pinning防止抓包操作 https协议 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-78n9M2PH-1677252127361)(安全.assets/ht…...

稀疏特征和密集特征

在机器学习中&#xff0c;特征是指对象、人或现象的可测量和可量化的属性或特征。特征可以大致分为两类&#xff1a;稀疏特征和密集特征。 稀疏特征 稀疏特征是那些在数据集中不连续出现的特征&#xff0c;并且大多数值为零。稀疏特征的示例包括文本文档中特定单词的存在或不存…...

Linux网络TCP sticky分析工具

1 TCP粘包 - TCP_NODELAY TCP粘包&#xff08;sticky&#xff09;的表现是TCP nagle算法将应用层发送的多个包进行合并后&#xff0c;再发送&#xff0c;很容易出现burst导致bcm89230丢包。由于OABR不支持流控&#xff0c;所以需要使用Linux tc对对应的TCP port进行流量整形。 …...

华为OD机试题,用 Java 解【DNA 序列】问题

最近更新的博客 华为OD机试 - 猴子爬山 | 机试题算法思路 【2023】华为OD机试 - 分糖果(Java) | 机试题算法思路 【2023】华为OD机试 - 非严格递增连续数字序列 | 机试题算法思路 【2023】华为OD机试 - 消消乐游戏(Java) | 机试题算法思路 【2023】华为OD机试 - 组成最大数…...

python的所有知识点+代码+注释,不看就亏死了

目录 简介 特点 搭建开发环境 版本 hello world 注释 文件类型 变量 常量 数据类型 运算符和表达式 控制语句 数组相关 函数相关 字符串相关 文件处理 对象和类&#xff0c;注&#xff1a;不是那个对象&#xff01;&#xff01;&#xff01;&#xff01;&…...

读懂分布式事务

一、概述 1.1 什么是分布式事务 事务我们都很熟悉&#xff0c;事务提供一种机制将一个活动涉及的所有操作纳入到一个不可分割的执行单元&#xff0c;组成这组操作的各个单元&#xff0c;要么全部成功&#xff0c;要么全部失败。 事务有四大特性&#xff1a; Atomic&#xf…...

多目标粒子群算法求解帕累托前沿Pareto,Pareto的原理,测试函数100种求解之21

目录 背影 parte前沿的定义 注意事项 基于多目标粒子群的帕累托前沿求解 主要参数 MATLAB代码 效果图 结果分析 展望 背影 在目标优化过程种,很多时候都两个或者多个目标,并且目标函数不能同时达到最优,鱼与熊掌不可兼得,这个时候可以通过求解帕累托前沿,通过帕累托前沿…...

数组:二分查找、移除数组等经典数组题

二分查找&#xff1a;相关题目链接&#xff1a;https://leetcode.cn/problems/binary-search/题目重现&#xff1a;给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值…...

负责任动物纤维标准RAF

【负责任动物纤维标准RAF】RAF-Responsible Animal Fiber, 中文翻译为负责任动物纤维标准。RAF标准包含了三个子标准&#xff0c;即RWS&#xff08;责任羊毛标准&#xff09;、RMS&#xff08;责任马海毛标准&#xff09;和RAS&#xff08;责任羊驼毛标准&#xff09;。RWS&…...

storybook使用info插件报错

报错内容: RangeErrorMaximum call stack size exceededCall StackprettyPrintvendors-node_modules_pmmmwh_react-refresh-webpack-plugin_lib_runtime_RefreshUtils_js-node_mod-4ff2dd.iframe.bundle.js:160:27undefinedvendors-node_modules_pmmmwh_react-refresh-webpack-…...

【每日一题Day129】LC1247交换字符使得字符串相同 | 贪心

交换字符使得字符串相同【LC1247】 有两个长度相同的字符串 s1 和 s2&#xff0c;且它们其中 只含有 字符 "x" 和 "y"&#xff0c;你需要通过「交换字符」的方式使这两个字符串相同。 每次「交换字符」的时候&#xff0c;你都可以在两个字符串中各选一个字…...

性能优化之node中间件耗时

背景 中间件在node框架中是很基本的套件&#xff0c;使用不当很容易对页面性能造成影响。除了node服务端外&#xff0c;前端做的SSR项目也要特别重视这块 哪些场景会造成中间件耗时特别严重&#xff1f; 罪魁祸首是&#xff1a;await阻塞 举个例子&#xff1a; 1.如何得到 …...

3-1 图文并茂说明raid0,raid1, raid10, raid01, raid5等原理

文章目录简介RAID类型RAID0RAID1RAID5RAID6RAID10RAID01RAID对比图简介 一、RAID 是什么&#xff1f; RAID &#xff08; Redundant Array of Independent Disks &#xff09;即独立磁盘冗余阵列&#xff0c;简称为「磁盘阵列」&#xff0c;其实就是用多个独立的磁盘组成在一起…...

西北工业大学大学物理(I)下2019-2020选填考题解析

单选题12个&#xff0c;24分。1量子数考查前三个量子数由薛定谔方程决定&#xff0c;最后一个关于自旋的由狄拉克方程决定由这些量子数可以给出原子的壳层结构。考试其实考的不深&#xff0c;记住这个表就够了。2 书上18、19章量子物理的著名实验&#xff1a;光电效应&#xff…...

自动化测试selenium

目录 一、为什么引入自动化测试&#xff1f; 二、为什么选择selenium作为自动化测试工具&#xff1f; 三、环境部署 四、什么是驱动&#xff1f;驱动的工作原理&#xff1f; 五、selenium的基础语法 元素定位 元素操作 点击元素 模拟键盘输入 清除对象输入的文本…...

熟悉GC常用算法,熟悉常见垃圾收集器,具有实际JVM调优实战经验

程序的栈和堆 栈先进后出&#xff0c;且里面的数据自动释放&#xff0c; 堆内的空间则需要手动释放 java python go 只管创建&#xff0c;不用像c,c需要手动释放空间&#xff0c; 因为他们都会开一个进程GC&#xff08;Garbage Collector&#xff09;&#xff0c;由垃圾回收…...

常量和变量——“Python”

各位CSDN的uu们你们好呀&#xff0c;今天&#xff0c;小雅兰的内容是Python的一些基础语法噢&#xff0c;会讲解一些常量和变量的知识点&#xff0c;那么&#xff0c;现在就让我们进入Python的世界吧 常量和表达式 变量和类型 变量是什么 变量的语法 变量的类型 常量和表达式 …...

《蓝桥杯每日一题》KMP算法·AcWing 141. 周期

1.题目描述一个字符串的前缀是从第一个字符开始的连续若干个字符&#xff0c;例如 abaab 共有 55 个前缀&#xff0c;分别是 a&#xff0c;ab&#xff0c;aba&#xff0c;abaa&#xff0c;abaab。我们希望知道一个 N 位字符串 S 的前缀是否具有循环节。换言之&#xff0c;对于每…...

URL介绍

前言Internet上的每一个网页都具有一个唯一的名称标识&#xff0c;通常称之为URL&#xff08;Uniform Resource Locator, 统一资源定位器&#xff09;。它是www的统一资源定位标志&#xff0c;简单地说URL就是web地址&#xff0c;俗称“网址”。一、URL概念URL是对互联网上得到…...

学习 Python 之 Pygame 开发魂斗罗(一)

学习 Python 之 Pygame 开发魂斗罗&#xff08;一&#xff09;Pygame回忆Pygame1. 使用pygame创建窗口2. 设置窗口背景颜色3. 获取窗口中的事件4. 在窗口中展示图片(1). pygame中的直角坐标系(2). 展示图片(3). 给部分区域设置颜色5. 在窗口中显示文字6. 播放音乐7. 图片翻转与…...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

CTF show Web 红包题第六弹

提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框&#xff0c;很难让人不联想到SQL注入&#xff0c;但提示都说了不是SQL注入&#xff0c;所以就不往这方面想了 ​ 先查看一下网页源码&#xff0c;发现一段JavaScript代码&#xff0c;有一个关键类ctfs…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练

前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1)&#xff1a;从基础到实战的深度解析-CSDN博客&#xff0c;但实际面试中&#xff0c;企业更关注候选人对复杂场景的应对能力&#xff08;如多设备并发扫描、低功耗与高发现率的平衡&#xff09;和前沿技术的…...

精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南

精益数据分析&#xff08;97/126&#xff09;&#xff1a;邮件营销与用户参与度的关键指标优化指南 在数字化营销时代&#xff0c;邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天&#xff0c;我们将深入解析邮件打开率、网站可用性、页面参与时…...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台

🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...

React---day11

14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store&#xff1a; 我们在使用异步的时候理应是要使用中间件的&#xff0c;但是configureStore 已经自动集成了 redux-thunk&#xff0c;注意action里面要返回函数 import { configureS…...

Mysql中select查询语句的执行过程

目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析&#xff08;Parser&#xff09; 2.4、执行sql 1. 预处理&#xff08;Preprocessor&#xff09; 2. 查询优化器&#xff08;Optimizer&#xff09; 3. 执行器…...

JavaScript基础-API 和 Web API

在学习JavaScript的过程中&#xff0c;理解API&#xff08;应用程序接口&#xff09;和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能&#xff0c;使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...