一,为什么要加签
目的1,加签是为了验签,这样说起来有点废话的意思,为了防止同一个请求多次被响应,服务端发现这个签名已经被处理过了,不再处理,防止浪费资源及对数据产生影响,也是解决重放攻击的思路之一。
目的2,防止黑客劫持你的请求,修改了参数,你的服务拿到请求,比较参数和签名,发现不对应,即被人修改过了,拒绝响应。
二,加签和加密用公钥还是私钥。
结论:私钥加签、公钥加密
1,公私钥是什么
简述下,不详细展开了:对称加密安全性不高,使用非对称加密:公钥和私钥,公钥加密只能用对应的私钥解密,反之亦然,这样双方交换1次秘钥就可以了,大大提升了安全性。
2,为什么私钥加签、公钥加密 因为加签请求被拦截,但拦截方拿不到私钥,伪造不了签名,如果用公钥加签,一般公钥是公开的,签名很容易伪造。 同样的,加密请求被拦截,拦截方拿不到接收方的私钥,解密不了数据,如果用私钥加密,拦截方拿公钥就能破解数据了。
3,非对称加密安全是安全,加解密效率极低,所以传输过程中,会同时使用对称和非对称加密: 把密码放在请求中,告诉对方,我们用这个密码加密的,你用这个密码解密就好。 密码用非对称加密,这样既有安全性又有速度,https就是这么搞的。
三,加密demo
1,生成指定长度的秘钥,这个就是对称加密的密码,使用方要用这个来解密数据
length指定长度,128,256都可以
public static byte[] generateKey(int length) throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(length);
SecretKey key = keyGenerator.generateKey();
return key.getEncoded();
}
2,对string类型(即数据)加密
public static String encryptData(byte[] key, String data) {
try {
SecretKey securekey = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(1, securekey);
byte[] db = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(db);
} catch (Exception e) {
throw new RuntimeException("加密失败!", e);
}
}
对object加密怎么办?转成json不就行了
3,对密码使用非对称加密
public static String encryptKey(PublicKey publicKey, byte[] key) throws Exception {
/** 得到Cipher对象来实现对源数据的RSA加密 */
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
/** 执行加密操作 */
byte[] b1 = cipher.doFinal(key);
return Base64.getEncoder().encodeToString(b1);
}
PublicKey怎么创建呢?
public static PublicKey getPublicKey(String key) throws Exception {
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(key));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(keySpec);
return publicKey;
}
key即是接收方的公钥key,怎么生成对称,后面再讲。
4,加签
public static String sign(PrivateKey privateKey, Map respCom) throws Exception {
try {
return Base64.getEncoder().encodeToString(genSignature(toSignContent(respCom).getBytes("UTF-8"), privateKey, null));
} catch (Exception ex) {
throw new Exception("加签异常", ex);
}
}
private static byte[] genSignature(byte[] input, PrivateKey key, String signAlgorithm) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, IOException, NoSuchProviderException {
signAlgorithm = StringUtils.isEmpty(signAlgorithm) ? "SHA256withRSA" : signAlgorithm;
Signature sig = Signature.getInstance(signAlgorithm);
sig.initSign(key);
sig.update(input);
return sig.sign();
}
privateKey即是自己的私钥,
public static PrivateKey getPrivateKey(String key) throws Exception {
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(key));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
return privateKey;
}
respCom是请求参数转成map,有多种方法,我提供rt包的一种
public static Map<String, Object> objectToMap(Object obj) {
if (obj == null)
return null;
Map<String, Object> map = new HashMap<String, Object>();
BeanInfo beanInfo = null;
try {
beanInfo = Introspector.getBeanInfo(obj.getClass());
} catch (IntrospectionException e) {
e.printStackTrace();
}
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor property : propertyDescriptors) {
String key = property.getName();
if (key.compareToIgnoreCase("class") == 0) {
continue;
}
Method getter = property.getReadMethod();
Object value = null;
try {
value = getter != null ? getter.invoke(obj) : null;
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
map.put(key, value);
}
return map;
}
四,下面说一下如何生成公私钥
百度上有很多种python、工具、app很多,我使用的是keyPairGenerator
public void test() throws Exception {
// 初始化KeyPairGenerator
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(1024);
// 生成一个密钥对
KeyPair pair = keyGen.generateKeyPair();
// 获取公钥和私钥
byte[] publicKey = pair.getPublic().getEncoded();
byte[] privateKey = pair.getPrivate().getEncoded();
// 编码为Base64字符串以便打印
String publicKeyEncoded = Base64.getEncoder().encodeToString(publicKey);
String privateKeyEncoded = Base64.getEncoder().encodeToString(privateKey);
// 打印公私钥
System.out.println("Public Key: " + publicKeyEncoded);
System.out.println("Private Key: " + privateKeyEncoded);
}