赞
踩
密码学在计算机领域源远流长,应用广泛。当前每时每刻,每一个连接到互联网的终端,手机,电脑,iPad都会和互联网有无数次的数据交互,如果这些数据都是明文传输那将是难以想象的。为了保护用户隐私,防止重要数据被窃取,篡改,我们需要对我们的数据进行加密。
本节我就如何进行加密,做简单介绍。
这一类算法是加密密钥和解密密钥是相同的,加密密钥是解密密钥的逆运算,也就是一种完全对称的行为,所以叫做对称加密算法。对称加密算法是一种初等的加密算法。从安全性来讲的话没有那么高
下面案例统一以Apache Codec 提供的加密库和jdk本身类库为例,pom坐标如下:
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>
工具类
public class DESUtils { //密钥算法 private static final String KEY_ALGORITHM = "DES"; //加密算法/工作模式/填充方式 private static final String DEFAULT_CIPHER_ALGORITHM = "DES/ECB/PKCS5Padding"; /**使用DES对字符串加密 * @param str utf8编码的字符串 * @param key 密钥(8字节) * @return 加密结果 * @throws Exception */ public static byte[] desEncrypt(String str, String key) throws Exception { if (str == null || key == null) return null; Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getBytes("utf-8"), KEY_ALGORITHM)); byte[] bytes = cipher.doFinal(str.getBytes("utf-8")); return bytes; } /**使用DES对数据解密 * @param bytes utf8编码的二进制数据 * @param key 密钥(8字节) * @return 解密结果 * @throws Exception */ public static String desDecrypt(byte[] bytes, String key) throws Exception { if (bytes == null || key == null) return null; Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getBytes("utf-8"), KEY_ALGORITHM)); bytes = cipher.doFinal(bytes); return new String(bytes, "utf-8"); } }
测试类
@Test
public void testEncrypt() throws Exception{
String data="我是测试数据,用来测试DES";
String key="2234234d";
byte[] bytes = DESUtils.desEncrypt(data, key);
System.out.println("加密后报文为:"+new String(bytes));
String s = DESUtils.desDecrypt(bytes, key);
System.out.println("解密后报文为:"+s);
}
//加密后报文为:]�~;ᠬ$F��/���
//9�'f˕:����N��O��b�A
//解密后报文为:我是测试数据,用来测试DES
工具类:
public class DESUtils { /**使用DES对字符串加密 * @param str utf8编码的字符串 * @param key 密钥(24字节) * @return 加密结果 * @throws Exception */ public static byte[] truibleDesEncrypt(String str, String key) throws Exception { if (str == null || key == null) return null; Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getBytes("utf-8"), "DESede")); byte[] bytes = cipher.doFinal(str.getBytes("utf-8")); return bytes; } /**使用DES对数据解密 * @param bytes utf8编码的二进制数据 * @param key 密钥(24字节) * @return 解密结果 * @throws Exception */ public static String tribleDesDecrypt(byte[] bytes, String key) throws Exception { if (bytes == null || key == null) return null; Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getBytes("utf-8"), "DESede")); bytes = cipher.doFinal(bytes); return new String(bytes, "utf-8"); } }
测试类:
@Test
public void testTribleDES() throws Exception{
String data="我是测试数据,用来测试3DES";
String key="12345678abcdefghABCDEFGH";
byte[] bytes = DESUtils.truibleDesEncrypt(data, key);
System.out.println("加密后报文为:"+new String(bytes));
String s = DESUtils.tribleDesDecrypt(bytes, key);
System.out.println("解密后报文为:"+s);
}
//加密后报文为:
//���1�����u�{��B0\�T��
//��V�j�;�1c�
//解密后报文为:我是测试数据,用来测试3DES
工具类:
public class AESUtils { //密钥算法 private static final String KEY_ALGORITHM = "AES"; //加密算法/工作模式/填充方式 private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding"; /** * 加密 * * @param toEncryptStr key * @return */ public static String encrypt(String toEncryptStr, String key) { byte[] data = toEncryptStr.getBytes(); //统一密钥为8的倍数,这里统一md5处理成32位,解密一样 byte[] secretKey = parseHexStr2Byte(md5(key)); try { // 实例化 Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM); // 使用密钥初始化,设置为加密模式 cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(secretKey, KEY_ALGORITHM)); // 执行操作 return parseByte2HexStr(cipher.doFinal(data)); } catch (Exception e) { return ""; } } //解密 带偏移量 public static String decodeWithIv(String strText, String key, String ivStr) { byte[] StrdoFinal = null; try { Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding"); SecretKeySpec keyByte = new SecretKeySpec(key.getBytes(), "AES"); IvParameterSpec iv = new IvParameterSpec(ivStr.getBytes()); byte[] contents = Base64.getDecoder().decode(strText); cipher.init(Cipher.DECRYPT_MODE, keyByte, iv); StrdoFinal = cipher.doFinal(contents); } catch (Exception e) { e.printStackTrace(); } return new String(StrdoFinal); } /** * 解密 * * @param toDecryptStr key * @return */ public static String decrypt(String toDecryptStr, String key) { byte[] data = parseHexStr2Byte(toDecryptStr); byte[] secretKey = parseHexStr2Byte(md5(key)); try { // 实例化 Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM); // 使用密钥初始化,设置为解密模式 cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(secretKey, KEY_ALGORITHM)); // 执行操作 return new String(cipher.doFinal(data), "utf-8"); } catch (Exception e) { return ""; } } /** * 将二进制转换成16进制 * * @param buf * @return */ public static String parseByte2HexStr(byte buf[]) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < buf.length; i++) { String hex = Integer.toHexString(buf[i] & 0xFF); if (hex.length() == 1) { hex = '0' + hex; } sb.append(hex.toUpperCase()); } return sb.toString(); } /** * 将16进制转换为二进制 * * @param hexStr * @return */ public static byte[] parseHexStr2Byte(String hexStr) { if (hexStr.length() < 1) { return new byte[0]; } byte[] result = new byte[hexStr.length() / 2]; for (int i = 0; i < hexStr.length() / 2; i++) { int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16); int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16); result[i] = (byte) (high * 16 + low); } return result; } /** * MD5加密算法 * 说明:32位加密算法 * * @param s 待加密的数据 * @return 加密结果,全小写的字符串(utf-8) */ public static String md5(String s) { char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; try { byte[] btInput = s.getBytes("utf-8"); // 获得MD5摘要算法的 MessageDigest 对象 MessageDigest mdInst = MessageDigest.getInstance("MD5"); // 使用指定的字节更新摘要 mdInst.update(btInput); // 获得密文 byte[] md = mdInst.digest(); // 把密文转换成十六进制的字符串形式 int j = md.length; char str[] = new char[j * 2]; int k = 0; for (int i = 0; i < j; i++) { byte byte0 = md[i]; str[k++] = hexDigits[byte0 >>> 4 & 0xf]; str[k++] = hexDigits[byte0 & 0xf]; } return new String(str); } catch (Exception e) { e.printStackTrace(); return null; } } }
测试类:
public class TestAES {
@Test
public void testEncrypt() throws Exception{
String data="我是测试数据,用来测试AES";
String key="2234234363456d";
String encrypt = AESUtils.encrypt(data, key);
System.out.println("加密后报文为:"+encrypt);
String s = AESUtils.decrypt(encrypt, key);
System.out.println("解密后报文为:"+s);
}
//加密后报文为:52CE397C7042173E569C5E7FA3F657C32FB658D2DB2F9CE7E3EF5F1914DD1B29FFB95C128E5B10EA8DA4E494B669790F
//解密后报文为:我是测试数据,用来测试AES
}
如下图所示,在非对称算法中,加密方用公钥加密数据,解密方用私钥解密数据,因为公钥和私钥是不同的秘钥,所以秘钥泄漏的风险会极大程度降低。 由于非对称加密的密钥生成麻烦,所以无法做到一次一密,而且其加密速度很慢,无法对大量数据加密。因此最常用的使用场景就是数字签名和密码传输,用作数字签名时使用私钥加签,公钥验;用作加密解密时,使用公钥加密,私钥解密。
工具类:
package com.wanlong.encrypt; import org.apache.commons.codec.binary.Base64; import javax.crypto.Cipher; import java.io.ByteArrayOutputStream; import java.security.*; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.HashMap; import java.util.Map; /** * @author wanlong * @version 1.0 * @description: * @date 2023/4/23 14:58 */ public class RSAUtils { public static final String KEY_ALGORITHM = "RSA"; public static final String SIGNATURE_ALGORITHM = "MD5withRSA"; private static final String PUBLIC_KEY = "RSAPublicKey"; private static final String PRIVATE_KEY = "RSAPrivateKey"; private static final int MAX_ENCRYPT_BLOCK = 117; private static final int MAX_DECRYPT_BLOCK = 256; public RSAUtils() { } public static Map<String, Object> genKeyPair() throws Exception { KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA"); keyPairGen.initialize(2048); KeyPair keyPair = keyPairGen.generateKeyPair(); RSAPublicKey publicKey = (RSAPublicKey)keyPair.getPublic(); RSAPrivateKey privateKey = (RSAPrivateKey)keyPair.getPrivate(); Map<String, Object> keyMap = new HashMap(2); keyMap.put("RSAPublicKey", publicKey); keyMap.put("RSAPrivateKey", privateKey); return keyMap; } public static String sign(String content, String privateKey) throws Exception { byte[] data = content.getBytes(); byte[] keyBytes = Base64.decodeBase64(privateKey); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec); Signature signature = Signature.getInstance("MD5withRSA"); signature.initSign(privateK); signature.update(data); return Base64.encodeBase64String(signature.sign()); } public static boolean verify(String content, String publicKey, String sign) { try { byte[] data = content.getBytes(); byte[] keyBytes = Base64.decodeBase64(publicKey); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PublicKey publicK = keyFactory.generatePublic(keySpec); Signature signature = Signature.getInstance("MD5withRSA"); signature.initVerify(publicK); signature.update(data); return signature.verify(Base64.decodeBase64(sign)); } catch (Exception var9) { var9.printStackTrace(); return false; } } public static String decryptByPrivateKey(String data, String privateKey) throws Exception { byte[] encryptedData = Base64.decodeBase64(data); byte[] keyBytes = Base64.decodeBase64(privateKey); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(2, privateK); int inputLen = encryptedData.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; for(int i = 0; inputLen - offSet > 0; offSet = i * 256) { byte[] cache; if (inputLen - offSet > 256) { cache = cipher.doFinal(encryptedData, offSet, 256); } else { cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); ++i; } byte[] decryptedData = out.toByteArray(); out.close(); return new String(decryptedData); } public static String decryptByPublicKey(String data, String publicKey) throws Exception { byte[] encryptedData = Base64.decodeBase64(data); byte[] keyBytes = Base64.decodeBase64(publicKey); X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); Key publicK = keyFactory.generatePublic(x509KeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(2, publicK); int inputLen = encryptedData.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; for(int i = 0; inputLen - offSet > 0; offSet = i * 256) { byte[] cache; if (inputLen - offSet > 256) { cache = cipher.doFinal(encryptedData, offSet, 256); } else { cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); ++i; } byte[] decryptedData = out.toByteArray(); out.close(); return new String(decryptedData); } public static String encryptByPublicKey(String content, String publicKey) throws Exception { byte[] data = content.getBytes(); byte[] keyBytes = Base64.decodeBase64(publicKey); X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); Key publicK = keyFactory.generatePublic(x509KeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(1, publicK); int inputLen = data.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; for(int i = 0; inputLen - offSet > 0; offSet = i * 117) { byte[] cache; if (inputLen - offSet > 117) { cache = cipher.doFinal(data, offSet, 117); } else { cache = cipher.doFinal(data, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); ++i; } byte[] encryptedData = out.toByteArray(); out.close(); return Base64.encodeBase64String(encryptedData); } public static String encryptByPrivateKey(String content, String privateKey) throws Exception { byte[] data = content.getBytes(); byte[] keyBytes = Base64.decodeBase64(privateKey); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(1, privateK); int inputLen = data.length; ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0; for(int i = 0; inputLen - offSet > 0; offSet = i * 117) { byte[] cache; if (inputLen - offSet > 117) { cache = cipher.doFinal(data, offSet, 117); } else { cache = cipher.doFinal(data, offSet, inputLen - offSet); } out.write(cache, 0, cache.length); ++i; } byte[] encryptedData = out.toByteArray(); out.close(); return Base64.encodeBase64String(encryptedData); } public static String getPrivateKey(Map<String, Object> keyMap) throws Exception { Key key = (Key)keyMap.get("RSAPrivateKey"); return Base64.encodeBase64String(key.getEncoded()); } public static String getPublicKey(Map<String, Object> keyMap) throws Exception { Key key = (Key)keyMap.get("RSAPublicKey"); return Base64.encodeBase64String(key.getEncoded()); } public static void main(String[] args) throws Exception { Map<String, Object> keyMap = genKeyPair(); String publicKey = getPublicKey(keyMap); String privateKey = getPrivateKey(keyMap); System.out.println("publicKey=" + publicKey); System.out.println("privateKey=" + privateKey); String mingwen = "nihaoaaaaadsagdsagdagdaghah哈哈"; System.out.println("明文=" + mingwen); System.out.println("明文长度=" + mingwen.length()); String sign = sign(mingwen, privateKey); System.out.println("签名=" + sign); System.out.println("验签结果=" + verify(mingwen, publicKey, sign)); String miwen = encryptByPublicKey(mingwen, publicKey); System.out.println("公钥加密密文=" + miwen); System.out.println("公钥加密密文长度=" + miwen.length()); System.out.println("私钥解密明文=" + decryptByPrivateKey(miwen, privateKey)); String mi = encryptByPrivateKey(mingwen, privateKey); System.out.println("私钥加密密文=" + mi); System.out.println("私钥加密密文长度=" + mi.length()); System.out.println("公钥解密明文=" + decryptByPublicKey(mi, publicKey)); } }
测试:
@Test
public void testRSA() throws Exception{
RSAUtils.main(new String[2]);
}
代码运行结果:
publicKey=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9A0Lc6M439G7sS5halq8M9uKWWrTpNRgXGoatCFTKQIVK6mjotBvAlAHNNFBs/9AAlLXFoiU/9nj6cCQDSC5PF/Q4G3UP+4KtebVXWfgn+AcW1wyOneb6tk1PpIA3260KCk+Kk67Aazk+EpyRH3OblE3vrUxo9jYljd9TSlfKtEnPYhuLgUIYXnZtjBwSlQhj84zpsN0qg2dewCa3vjHky0rt98j09KRItZOzFtWnCR9fDlPbFUd3LeotNCuEPi18EWjkvz8UYW1z1L1Ct7LePSlu5+kdERRExLxcuaTifqlyqTlZYB6RcHKb2TLG4edE/LPQDobzCfUxZfW4icDmQIDAQAB
privateKey=MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQD0DQtzozjf0buxLmFqWrwz24pZatOk1GBcahq0IVMpAhUrqaOi0G8CUAc00UGz/0ACUtcWiJT/2ePpwJANILk8X9DgbdQ/7gq15tVdZ+Cf4BxbXDI6d5vq2TU+kgDfbrQoKT4qTrsBrOT4SnJEfc5uUTe+tTGj2NiWN31NKV8q0Sc9iG4uBQhhedm2MHBKVCGPzjOmw3SqDZ17AJre+MeTLSu33yPT0pEi1k7MW1acJH18OU9sVR3ct6i00K4Q+LXwRaOS/PxRhbXPUvUK3st49KW7n6R0RFETEvFy5pOJ+qXKpOVlgHpFwcpvZMsbh50T8s9AOhvMJ9TFl9biJwOZAgMBAAECggEAH1rdscmysO7dUnJHCccGjxMRv1M+RdsTVkw7ihEOAiLGXYm6AF0PJhjqFBseeeW9b479G2QI4KY55fpbh5RAuEUHLQ5vSpdmwOAbYZjK/z9n5UT/Hwvm+FFXyeYwPoSWmOJTnlPnKtvvvwaxj6MqNnow00usSQS/Lu2KJ7O9Cl78lL+ff1Ld/LHW1C4kG81RKChUrZA6StGi5YVHJOiJW51lzFWVmWa0slQRMftFx9dTne0+aReQHZCrKzoRLZY/0RGXWy7vreCsxffIUh4TldwMBnb1PFIun5H0ifGhQ6SMWSQd/8hGVVajgjE3duEHmMKHkfPGCgFFEHiOnNCKUQKBgQD8Hw0J5fGoyAelye8mSqgLEOOP2jKbDcn+BcrkVFx6szgNERTn0Ms8Tlu2D62mOF+rOzr/eTMfpA7XWKzmNraybSjMnNtwu0b6yiZSNM8s7O2YsjX1L1zdgqUN7HTKwiVq9DgqlTsoN7HU4aCgT/4f6q1zgfHw4LsN8snOreJ1ZwKBgQD3zjWy4IJeRmNhWHaMOE0y6K0y4fFLl8Q9Vws/x05lzSUdYfl75AHqoOQNLp4hJ2n9wQcuEddn/gRfKprUY7NRAHSC5twEFTNW+N/TyhHg1Ec02aYi8nd51bt52Dm+Z5SH4+jszOsEiXjjKiQxXAA7UB+GqKeDpQfdRPPCuF4e/wKBgQDGlhqqEkHgBPbpIn7JtYJZfQsRkvfLY/gXqy5d3Qke6K2ctTi3Q6HhtYLNi9nmlH7em//jnO6k3I+IFePSTYRoVE0Ppfm++PR2s+WtWMVbCKA5Zx3TK2RFYhNqPTbdQkFA1m6rM/JtwjjDipj/zSJIt4u58L/GUO1lljhZIGPAvwKBgGvqBUCMvLlJdeXinF2b9yKAaUyLUIVW5kLAMUnpBZ8Xo14UWI03Ug5XWnjTIFHX1DSJZxMM+f1zhXvcFekAMgrIY/TNjGrKwLzTTMXyba63Qvsk/VCivpz0EtyQ6TSd7vTur3TQGFi1dUuYAoLsSb2Kuu/tamXN7IrTiEP3/iUJAoGBANKCyFd/jeE4/DkN/GL3NLx4VTXC+lN0OzPA0pt4R4fPNkFsq7j6CWBMpB6NUu+XI7005JTa2vsOGI9alZmUxerEGvIpbvmplDgu/x1kjrR/RbTEVUB+aV2EIqG7u6rslbk8dbMjlTfvYqytLwC9Pk6E3oR/eYS8Dgg8Kpx3Z1BQ
明文=wedfefasdvasdva我打球问答区文昌
明文长度=23
签名=GoNvFHfF3yM1syLnmU9lbbp77jK8bvNlJi54WWPNMQTblOrjuWdiwdiZxwJoZFZNfo1lbmrv9M1fAkJKXBiUh1Nar9YehVytgif4rp2aqeiNmpNO7vT/ZIncDuIXdj2nqPgTbW2o1x8+XNWeKDuhJdrluD+bOWUce6JqI4ZR6LJw35NxckwTFTqNMGF2ta8btISY8/dMuNBlZZX7eCY/HXecgVCfosta5eQHvQY1iIjNh4i787wc7/xcvqIqKsR8XfBCV/g0UPj4FthEt098Fyi4NPXOtOcw5x9Fxz1RYRgU0I22eBsNDWysmOyKi9U2dSLAlPg2BDP7W1Pz0GVrPw==
验签结果=true
公钥加密密文=qnQBSypoQhFupfRWftCcwNTMEuwtmwqZva6uvKfg0Ioyh6ZKGdROtTXMBZ78d3yDMRXgOM5Cjn5/KNC+MiP7qMZQFM4txSqEcOT3qzaI6/qV5FD7FewOkTz585JHkjgxkwFZEUGiMgOTM1xzVfPHDmn34fvO2FkkbK7WscDzNeMOWMvh642L0MSxolWmyBZdAR0YmDhOi2nedN3ltay6dCm+Ozxnpj3BA9PHUQilhZbbjOFYuEf/ZcWkfK9Npd13fUmdfIkiF772AKV0QRCxj1I+bGWxSrspODyqm5vv5r6VMeM0zODT+WOHcx++Fxr7pORusQpAiQN4oCq/FGrv9g==
公钥加密密文长度=344
私钥解密明文=wedfefasdvasdva我打球问答区文昌
私钥加密密文=K5mZQo5f/CcFeXyQFHdfZrcow05ar+s8fpvo6YtkNsueLj5YOZBAdArNugNALs/xPBW9Q9Qj2dGqS3uDIEMEyLMNtl0PPQfymD41SiArFJXJut1z3Wu4BAiwht2XhMyyJfyqdjwLdj1etVKtw+7EYe9hkzSDMKMyNuIBwY9iOkBZf1VdQTSrfVSE/T8vwecYukkDlBZsb7EkveHMLA7Sz0fLhLJZwPQ6l1sY1MCX+wbYH5CdQHnIxbredtdj8gA0EXEe9wUdvOvpUONCbAzeZOqALFPiJh3LlrsD1L3KzNsp1vBmvIJI2xd0/1J7i0fv4JuvEiB+lCNkPPQGE+cXCA==
私钥加密密文长度=344
公钥解密明文=wedfefasdvasdva我打球问答区文昌
工具类:
public class DSAUtil { private static final String ALGORITHM = "DSA"; private static final String DEFAULT_SIGNATURE_ALGORITHM = "SHA1withDSA"; private static final int DEFAULT_KEY_SIZE = 1024; /** * 生成密钥对 */ public static InnerKey generateKey() throws NoSuchAlgorithmException { return generateKey(DEFAULT_KEY_SIZE); } /** * 生成密钥对 * @param keysize * @return * @throws NoSuchAlgorithmException */ public static InnerKey generateKey(int keysize) throws NoSuchAlgorithmException { // 初始化密钥 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM); keyPairGenerator.initialize(keysize); KeyPair keyPair = keyPairGenerator.generateKeyPair(); return InnerKey.builder() .publicKey(keyPair.getPublic().getEncoded()) .privateKey(keyPair.getPrivate().getEncoded()) .build(); } public static byte[] sign(byte[] privateKey, byte[] data) throws InvalidKeySpecException, NoSuchAlgorithmException, InvalidKeyException, SignatureException { return sign(privateKey, data, DEFAULT_SIGNATURE_ALGORITHM); } /** * 使用私钥进行签名 * @param privateKey 私钥 * @param data 数据 * @param signatureAlgorithm 签名算法 * @return * @throws Exception */ public static byte[] sign(byte[] privateKey, byte[] data, String signatureAlgorithm) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException { KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM); PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKey); PrivateKey privateKey2 = keyFactory.generatePrivate(pkcs8EncodedKeySpec); Signature signature = Signature.getInstance(signatureAlgorithm); signature.initSign(privateKey2); signature.update(data); byte[] bytes = signature.sign(); return bytes; } public static boolean verifySign(byte[] publicKey, byte[] data, byte[] sign) throws InvalidKeySpecException, NoSuchAlgorithmException, InvalidKeyException, SignatureException { return verifySign(publicKey, data, sign, DEFAULT_SIGNATURE_ALGORITHM); } /** * 使用公钥验证签名 * * @param publicKey 公钥 * @param data 数据 * @param sign 数据签名 * @param signatureAlgorithm 签名算法 * @return * @throws Exception */ public static boolean verifySign(byte[] publicKey, byte[] data, byte[] sign, String signatureAlgorithm) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException { KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM); X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKey); PublicKey publicKey2 = keyFactory.generatePublic(x509EncodedKeySpec); Signature signature = Signature.getInstance(signatureAlgorithm); signature.initVerify(publicKey2); signature.update(data); boolean bool = signature.verify(sign); return bool; } @Data @NoArgsConstructor @AllArgsConstructor @Builder public static class InnerKey { private byte[] publicKey; private byte[] privateKey; } }
@Test
public void testDSA() throws Exception{
DSAUtil.InnerKey innerKey = DSAUtil.generateKey();
String text = "我是测试数据数据,用来验证DSA";
System.out.println("公钥:" + Base64.encodeBase64String(innerKey.getPublicKey()));
System.out.println("私钥:" + Base64.encodeBase64String(innerKey.getPrivateKey()));
byte[] sign = DSAUtil.sign(innerKey.getPrivateKey(), text.getBytes());
System.out.println("原文:" + text);
System.out.println("数字签名:" + Base64.encodeBase64String(sign));
boolean bool = DSAUtil.verifySign(innerKey.getPublicKey(), text.getBytes(), sign);
System.out.println("验签结果:" + bool);
}
代码运行结果:
公钥:MIIBtzCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYQAAoGAQGnbiw4RQTV5Z+QrMtKWJ2XcfQIVnYtWpkraSwEO689M+Kjy/eegaa2gk+I6MK476TtiC9TH1LlhAcchxEar+NyeDMSEJ/44dIRBG2k+2T9dVKv/YZaFm7bDcwCY1lj0MIQ/Khk5UfG/XspjT6cZ63k3wOO9s3caCa6a8sBqdRY=
私钥:MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoEFgIULc0aRq94NyvcjcbxHCoGCylUPXk=
原文:我是测试数据数据,用来验证DSA
数字签名:MCwCFAlEkt+8er3L2mPwt/cf+81++Y6dAhQte9bmVDUAuFhcQLt3cqKXD6wRuA==
验签结果:true
MD5算法是典型的消息摘要算法,其前身有MD2、MD3和MD4算法,它由MD4、MD3和MD2算法改进而来。不论是哪一种MD算法,它们都需 要获得一个随机长度的信息并产生一个128位的信息摘要。如果将这个128位的二进制摘要信息换算成十六进制,可以得到一个32位的字符串,故我们见到的大部分MD5算法的数字指纹都是32为十六进制的字符串。
@Test
public void testMD5(){
String md5Hex = DigestUtils.md5Hex("这是一串密码");
System.out.println("加密报文为:"+md5Hex);
//加密报文为:122141b53a06a34818d5afa6d17151e5
}
Base64是基于64个可打印字符来表示二进制数据的编解码方式。
正因为可编解码,所以它主要的作用不在于安全性,而在于让内容能在各个网关间无错的传输。
@Test
public void testBase64(){
String base64String = Base64.encodeBase64String("我是一直小菜鸟".getBytes());
System.out.println("base64转码后字符串为"+base64String);
byte[] bytes = Base64.decodeBase64(base64String);
System.out.println("base64解密后的字符串为"+new String(bytes));
// base64转码后字符串为5oiR5piv5LiA55u05bCP6I+c6bif
// base64解密后的字符串为我是一直小菜鸟
}
在访问浏览器的时候,如果是get请求,很多参数信息会直接在请求地址里面,如果此时携带的参数值本身有些特殊字符,比如中文,=,& ,此时直接访问浏览器无法正确识别,需要先将特殊字符转码。
@Test
public void testUrlCodec() throws Exception{
String encode = new URLCodec().encode("我是一个粉刷匠,粉刷本领强");
System.out.println("UrlEncode加密后的报文为:"+encode);
String decode = new URLCodec().decode(encode);
System.out.println("UrlCodeC解密后的报文为:"+decode);
// UrlEncode加密后的报文为:%E6%88%91%E6%98%AF%E4%B8%80%E4%B8%AA%E7%B2%89%E5%88%B7%E5%8C%A0%EF%BC%8C%E7%B2%89%E5%88%B7%E6%9C%AC%E9%A2%86%E5%BC%BA
// UrlCodeC解密后的报文为:我是一个粉刷匠,粉刷本领强
}
优点:算法公开、计算量小、加密速度快、加密效率高。
缺点:安全性差,只要有秘钥,数据没有安全空间。因为秘钥一样,秘钥泄漏风险大
优点:安全性相对较高,公钥和私钥分开保存
缺点:加密解密性能差,花费时间久
每个文件都可以用MD5验证程序算出一个固定的MD5值,是独一无二的。一般来说,开发方会在软件发布时预先算出文件的MD5值,如果文件被盗用,加了木马或者被篡改版权,那么它的MD5值也随之改变,也就是说我们对比文件当前的MD5值和它标准的MD5值来检验它是否正确和完整。
上面提到了,对称加密比较快,但是不安全,非对称加密比较慢,但是相对安全,还有为了保证数据完整性,我们可以加个md5验证签名,那么设计相对来说比较合理的接口对接,这三种加密我们都会涉及到。具体可以设计如下:
对称加密,我们选择算法AES
非对称加密,我们选择算法RSA
签名算法,我们可以选择md5 或者RSA
@Test public void testClientEncrypt() throws Exception { //服务端分配的唯一标识 String clientId = "123445"; String creditCode = "923834342323"; String orderNo = "202304232019011212"; //设置时间戳 long timeStamp = System.currentTimeMillis(); //客户端公钥,会线下提供给服务方 String clientPubKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhAtKgUEJH9zjCiZ1YxbfwAiSVXqPhph6rqL3g8XUooaEhm7a6p8Kj4OvFZIj8++4Ma7fFN6uG9uqmHMeOgWbuqDKIIWiABN0+3AIwX6rveqJ94tR523CayvM2ha0YcRSoWFsgHDFT2nDw/dcZlzYPtXGdtlrOWLpdh9OVAp5u5jC6bowXzl+1va4rwg+BxSYML4kcee33X4TK8a6OVFuoE78z0NNfAtRAW+b6WvlrySZQUkYMUhKxXR4n+aGI+919eTxKQI6wltl5b1k++hlTRhUWq3aSOI3dw+bjVw3hIoWxDnIQVjhS+C4jZnmA3OYMXJmAFCTk+XJKXS/1jOJpwIDAQAB"; //客户端私钥,客户端自己保存,保证不外泄 String clientPriKey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCEC0qBQQkf3OMKJnVjFt/ACJJVeo+GmHquoveDxdSihoSGbtrqnwqPg68VkiPz77gxrt8U3q4b26qYcx46BZu6oMoghaIAE3T7cAjBfqu96on3i1HnbcJrK8zaFrRhxFKhYWyAcMVPacPD91xmXNg+1cZ22Ws5Yul2H05UCnm7mMLpujBfOX7W9rivCD4HFJgwviRx57fdfhMrxro5UW6gTvzPQ018C1EBb5vpa+WvJJlBSRgxSErFdHif5oYj73X15PEpAjrCW2XlvWT76GVNGFRardpI4jd3D5uNXDeEihbEOchBWOFL4LiNmeYDc5gxcmYAUJOT5ckpdL/WM4mnAgMBAAECggEAEFkdhlc4+/rrGSydyADi/vGQvIiKEI38UnbW0jfCFcU1zzcWX4oFUrNpD/CiBuedFHmkIP9Y6xYNTwahrWlYWIjjvZcN8Zh3GVJLozk9pivNnRpgr5iFQ6OOn0nEV35pBJX9SwGrTCO6Gx8bD4lbNJxfEAPnJJm8ceV6WylY3QLju24cuNSZe+iVSsi12lasm0C9cuN+GXxAT/LIAEDHdhO2ve/b2Pmc8A7s3TKpaeDbEYPPQFr5AdOsQWKR3G1Xj5y9zfWYAxYrlKDRaVzn0ZQRMkr78Dc1I5wGBt7zuQ+NV2RcZqN+dwND3CUflr0M0VZ91IzEgA4rjqAYBRgakQKBgQDufi9FBGvYCD2q97J8Yoz3R8dJCNwD7XB4QtgHILu5AL1utWPxV+wEb6e1Np8metgiZ6eRsy0/RITv9Cpw7CXYs6dDO2E50YZ1SCxw48y7DcuUhJ8Gcw1teOW10jrgrgj5mx5lZXk+y+kwDBwJnIV5aPGTkII4L6ZEZdTgqT/OawKBgQCNvLH5VVXACCR59DopSMO72zqa7tpTrZjP2F2RvwUnjm5h0Lg+hUBd3pQxR5tBrgL8K6JidPLu1KYlIKJstRFcPBxRRi2oAp7Xab91IS9AicMqRp/DQ9fGbvOEFfbqrsYSBmkyLTa9/u8tJ4q97cGl7tPDQnsYCXztjKy5VznItQKBgFT7n+pvBeLIJPlcJDzQfTzMVgX/Yy7/F9myr/nyPxJQYjAl8MQaOV7nTpJzMUjr80JnPz3a5B+sUdaTYeA1NdM/STXa3e1VbR0zp6peciChbM6yZ1xL+RfuQaSFkjdnrIkNLkqhWw/2Z1SYrBD8tk8qBxM3Jj/RMuUiiDW5+aObAoGAcXQIlgdLo3IhGIl5ANDg9H8wcxIcKvz7I+wSQfbAfoBRNPTodgsdkcX3o1apHTLX6thWnC72wlvvPirYOOHbKpRnKltdcm3ejZl1CqHse+GKGk371kZ48rqfLCyUwBf0Ljt5exOcDQuCkgdj1FH7PwJj+Zk+hOgbWt7O53C9rT0CgYEA5D1Sj0CPaCUdp9wVnrm+KYyQdxiFk7EpYhIK43g/6o1Ka8Ow/G+1L2sttVJOjqfH4sRVxpYsTBva6/3uo+imPU+8SyLwOGD7m0yschLkPbUtYYver7QRO/dWmcl9OQU1euHjJnvLcQJ12dqWibxD5I8lAVNnhOYUycfNyTZUwjI="; //业务数据对象封装 JSONObject param = new JSONObject(); param.put("clientId", clientId); param.put("creditCode", creditCode); param.put("orderNo", orderNo); param.put("timeStamp", timeStamp); //数据转字符串 String paramJsonString = param.toJSONString(); //使用客户端公钥对称加密 业务数据(因为业务数据可能比较大,所以选择对称加密,提高加解密效率) String encrypt = AESUtils.encrypt(paramJsonString, clientPubKey); //md5摘要加密数据 String md5Hex = DigestUtils.md5Hex(encrypt); //对md5值转大写,加签 String sign = RSAUtils.sign(md5Hex.toUpperCase(), clientPriKey); //组装请求参数 JSONObject reqMsg = new JSONObject(); reqMsg.put("clientId", clientId); reqMsg.put("data", encrypt); reqMsg.put("sign", sign); reqMsg.put("timeStamp", timeStamp); //调用参数 System.out.println(reqMsg.toJSONString()); //{"timeStamp":1682255617696,"clientId":"123445","data":"C69844465FA1D8CDF447B841B434D2777F255A608A09CE0C84767986BD95E3CCA2B778306AA561C79B0B2345F274371F38B5FD7BDBB12828084981BEA7AA6B49E64964D1AF936BD8742EA9F4E6A8C3AE82DD8DA9FCA9949DF64F14728641DF2A91835E37DDA8C6CFA86A832EC1761EDD","sign":"HWZcm/NVMuljAIrCBjcstq5n0uGXDM9oA6xTT6fWm7nfuDPQyFqPLz0F4uNeZdV/GGp1dMH8K+SwGUee3TNorpBRVRRF9g9HUOy6uC3ifpdVpO34/grtxWAfPnUOMXzKEBtn36p2gOz9Nex9NCqr1BmzsfeKV/h3W6k+DXoJIHx3m7hGT4uSa4zwaq0ncsXCnkDh7x6JS5VjC6POGzeoFH7QFex7m1F12yOuTLRy78IVHygCMOML/5Id6xF+r/dUXUcpolsnlRpbMHr4ScqLWoOmT+tODLq5HcY5jYLmADEocpJAik88S7Fvjwr8ksj+xXMTiRV7X5MAMVmRn34bpg=="} }
@Test public void testServerDecrypt() throws Exception { //服务端分配的唯一标识 String clientId = "123445"; //客户端公钥,会线下提供给服务方 String clientPubKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhAtKgUEJH9zjCiZ1YxbfwAiSVXqPhph6rqL3g8XUooaEhm7a6p8Kj4OvFZIj8++4Ma7fFN6uG9uqmHMeOgWbuqDKIIWiABN0+3AIwX6rveqJ94tR523CayvM2ha0YcRSoWFsgHDFT2nDw/dcZlzYPtXGdtlrOWLpdh9OVAp5u5jC6bowXzl+1va4rwg+BxSYML4kcee33X4TK8a6OVFuoE78z0NNfAtRAW+b6WvlrySZQUkYMUhKxXR4n+aGI+919eTxKQI6wltl5b1k++hlTRhUWq3aSOI3dw+bjVw3hIoWxDnIQVjhS+C4jZnmA3OYMXJmAFCTk+XJKXS/1jOJpwIDAQAB"; //服务端接收到请求 JSONObject reqMsg = JSONObject.parseObject("{\"timeStamp\":1682255617696,\"clientId\":\"123445\",\"data\":\"C69844465FA1D8CDF447B841B434D2777F255A608A09CE0C84767986BD95E3CCA2B778306AA561C79B0B2345F274371F38B5FD7BDBB12828084981BEA7AA6B49E64964D1AF936BD8742EA9F4E6A8C3AE82DD8DA9FCA9949DF64F14728641DF2A91835E37DDA8C6CFA86A832EC1761EDD\",\"sign\":\"HWZcm/NVMuljAIrCBjcstq5n0uGXDM9oA6xTT6fWm7nfuDPQyFqPLz0F4uNeZdV/GGp1dMH8K+SwGUee3TNorpBRVRRF9g9HUOy6uC3ifpdVpO34/grtxWAfPnUOMXzKEBtn36p2gOz9Nex9NCqr1BmzsfeKV/h3W6k+DXoJIHx3m7hGT4uSa4zwaq0ncsXCnkDh7x6JS5VjC6POGzeoFH7QFex7m1F12yOuTLRy78IVHygCMOML/5Id6xF+r/dUXUcpolsnlRpbMHr4ScqLWoOmT+tODLq5HcY5jYLmADEocpJAik88S7Fvjwr8ksj+xXMTiRV7X5MAMVmRn34bpg==\"}"); //1.看clientId在系统中是否存在,如果不存在,报错,响应异常 //2.如果存在,验签,确认 数据完整性以及防止篡改 String data = reqMsg.getString("data"); String serverParamSign = reqMsg.getString("sign"); //3.报文验证签名 String md5 = DigestUtils.md5Hex(data).toUpperCase(); boolean verify = RSAUtils.verify(md5, clientPubKey, serverParamSign); //如果签名不对,报错,响应异常 if (!verify) { System.out.println("数据验签失败,非法请求,请确认"); return; } //如果验签通过,解密业务参数(客户端公钥线下已提供给服务端) String decrypt = AESUtils.decrypt(data, clientPubKey); System.out.println("收到的客户端请求参数为" + decrypt); //---------服务端处理请求--------------- // 收到的客户端请求参数为{"timeStamp":1682255617696,"clientId":"123445","creditCode":"923834342323","orderNo":"202304232019011212"} }
@Test public void testServerEncrypt() throws Exception { //服务端私钥 String serverPriKey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCUxuPd/L+ivYUt22APgsUYWgcADVTVOYQtUxqku+5lwOE1TlcYRfP0EBvhkVlbv8KOnLroPRwgpQ4acTz7LObqWkHlmZbP3Z3n4sgZtBzfSb9n7jAqluvdA7HEkfC9MerInfYqxqDe2OLLoF/rxT62zhXiJenZk4+IV86WwhPHgTJ0B/UfYGFB7DK1ylNCUZF9sVkViQx8kwSEFx36XzjMW60sZSr3sRPtSkck5Ce4wZlJSTCVhngz2M1+xTRcSJ0zzIbfITyYiVmfpi7lFnBY27JgguxiVLusPrD6HNhnqX4ksD4vSkTF41AWljN4hRGvVcU0rvsiqzn6dSf+JkPjAgMBAAECggEATttw0ivyo17S5XB+5RnKQFMPnM50JaSb065V0/UsslBeznNcpKgHW1jiflgdRg1JIXAffZNOglsaM5fL29J7/sGiZgFXt4ve85b3uvAF0bB0PLE6ZIikMfyQUAGO2alIqddYMGohwJyy8X1q+jwNNrXbUYgJAGM/U+Q+wxfRhg+2uWD+qALHg0SqlSjtrevojlRVDfpCODq4hYb6x3DS2bcO90+jVbVVOr9ss8zYkZR+e6BjgIxDhFZcV6OMVlNjFhiJldOKRw3ocZcc2xNAsiEslDH3C5JEKINEP4iJOfH8lzdl+eYx60Y3lLYe1FmfmqOePOyzmfU9nUcHKT6vuQKBgQD5ctSpLc2kP3bmZ/xbBnzWgK6nUrExqM7txlvorw9dx4o9u2Xg1V1UG3i2Bt96VnIkeWKbkm+qiEnpqc72B4W3GvbyVN6oDFY7kYQVqmqDCBXlAI0SQDU+bsywSN8l7qfRMj9Eszhl+dpWbYF/ZAAPTxJxV5f4qHn1uahImKZr1wKBgQCYrzFdlEcEvtzBJrZMq0cvZdR/nZoaWaEEuHGLz5muxHO/RFFgIUaWaKu6SjesMcIxshlG7G+7jvb7QK9ggVIB3MJzcLN/WwF8hfPUGbEJL0z05yrlq5RlbEL8a17twhFclFDoYKGcC+gshsM2jJj3d4yr4CJNsdHgeK/kUySG1QKBgQDhBiWxOBB6SoYH82ZC9udG2W60onQWSCHjfT0L+l/yST770UFmQROf++g4zJps0e7F2HqLvN3fCHMkxnpclwyY0UpT8RuqnPZtZiexI7pR2clme8jG3gUp/OnJXPNwVIouvRU19Da8R1ge/0oCkUM8jCgm9s2xEspyULjuREZcoQKBgHE5IVtqtItxWdSl93O9Y6ljUwRbg8ZchsowWIs8JJP0PH0ulUW7B1RMRGR92vEHaSFfF91/QZANgVtqaWMgIwcchNoETid3/g8walLzxlOwTtohfq8X4JChir8ShC+9xRApMCJSXiWQstgqCyMtedWxQpDGQcnpvmA+PvkLKsANAoGBAOSRLf5QVGhaZ6KHp2424aSylcbjD/cyHx8Vcayf/5berXGhWrawonE3TmBOZMPlAfviHUDN2Pmj3uViik2k7A20pLQUsgengxwn9nlnxMyh7eRJa+ov7+xaWx5llfKWSMJ972XTuzZOVRg+IhtE8Gj6cOjn9A3yhhi7ZYw8iFa9"; //假设业务数据如下: String businessData = "我是服务端返回业务数据"; JSONObject result = new JSONObject(); result.put("code", "000000"); result.put("msg", "请求处理成功"); JSONObject resultData = new JSONObject(); resultData.put("data", businessData); result.put("data", resultData.toJSONString()); //返回报文加签,服务端私钥加签 String serverSign = RSAUtils.sign(DigestUtils.md5Hex(businessData).toUpperCase(), serverPriKey); result.put("sign", serverSign); System.out.println("服务端返回为" + result.toJSONString()); //{"msg":"请求处理成功","code":"000000","data":"{\"data\":\"我是服务端返回业务数据\"}","sign":"XEDkV4wx8abvBS41pFhnM1EukH3Nsy4KnFhDQwg2ezwvVvZVQnnS47lDGcOu6S9MuAnqQPYgQIg6GEtryfoYClSOOSkvddCLlLBrlmGNs6CL6hsmVDcA5drnw1YozZfLPi7lbVHb1hOG6MMcQyVHNgxVAzpHtU72gZAYDGYdqZfJ+VPf0IMS5eLUwMxSw+zgvMekMKJYobfQOD/KHr1gT/ui9PWzbqXXG26GkMWlxa+i+gIoVBPSe3R+UiwzY+T6ZOGyB14/195MVXwh1I8WcMzuu7XmsstNa9fCKz5MFnKcXo+vwvQ/tO7X/+IPN4IAw5ZdBT/nveGDbi3XbQh0lw=="} }
@Test public void testClientDecrypt() throws Exception { //服务端公钥,线下提供给客户端 String serverPubKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlMbj3fy/or2FLdtgD4LFGFoHAA1U1TmELVMapLvuZcDhNU5XGEXz9BAb4ZFZW7/Cjpy66D0cIKUOGnE8+yzm6lpB5ZmWz92d5+LIGbQc30m/Z+4wKpbr3QOxxJHwvTHqyJ32Ksag3tjiy6Bf68U+ts4V4iXp2ZOPiFfOlsITx4EydAf1H2BhQewytcpTQlGRfbFZFYkMfJMEhBcd+l84zFutLGUq97ET7UpHJOQnuMGZSUkwlYZ4M9jNfsU0XEidM8yG3yE8mIlZn6Yu5RZwWNuyYILsYlS7rD6w+hzYZ6l+JLA+L0pExeNQFpYzeIURr1XFNK77Iqs5+nUn/iZD4wIDAQAB"; //--------------服务端返回,客户端收到返回验证报文可靠性--------- JSONObject result = JSONObject.parseObject("{\"msg\":\"请求处理成功\",\"code\":\"000000\",\"data\":\"{\\\"data\\\":\\\"我是服务端返回业务数据\\\"}\",\"sign\":\"XEDkV4wx8abvBS41pFhnM1EukH3Nsy4KnFhDQwg2ezwvVvZVQnnS47lDGcOu6S9MuAnqQPYgQIg6GEtryfoYClSOOSkvddCLlLBrlmGNs6CL6hsmVDcA5drnw1YozZfLPi7lbVHb1hOG6MMcQyVHNgxVAzpHtU72gZAYDGYdqZfJ+VPf0IMS5eLUwMxSw+zgvMekMKJYobfQOD/KHr1gT/ui9PWzbqXXG26GkMWlxa+i+gIoVBPSe3R+UiwzY+T6ZOGyB14/195MVXwh1I8WcMzuu7XmsstNa9fCKz5MFnKcXo+vwvQ/tO7X/+IPN4IAw5ZdBT/nveGDbi3XbQh0lw==\"}"); String businessData = result.getJSONObject("data").getString("data"); String serverSign = result.getString("sign"); //1.判断code是否正常,如果正常,验证签名,如果异常,直接报错 //2.验签 boolean verify = RSAUtils.verify(DigestUtils.md5Hex(businessData).toUpperCase(), serverPubKey, serverSign); System.out.println("验签结果:" + verify); //验签通过,可以使用数据 System.out.println("获取到的业务数据为:" + businessData); }
参考文档:
https://www.cnblogs.com/myseries/p/11581170.html
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。