加密算法 — — 对token进行非对称加密【RSA】

RSA对token加密

1 概念

相关概念:

  • 明文:未被加密过的数据
  • 密文:明文被某种加密算法加密后,就会变成密文
  • 密钥:一种参数,明文转换为密文或将密文转换为明文的算法中输入的参数。密钥分为:对称密钥和非对称密钥,分别用在对称加密和非对称加密中。

1.1 对称加密算法(私钥加密)

所谓对称就是指加密和解密都是使用同一个钥匙(密钥)
例如:
①小明要传递一个信息A给小红:A + B = C(小明通过对信息A进行加密后,得到信息C传给小红)
②小红拿到信息C后,C - B = A(小红拿到数据后,用密钥B进行解密,得到初始信息A)

特点:
算法公开、加密和解密速度快,适合对大数据量进行加密;但是与非对称加密相比,安全性降低

1.2 非对称加密算法

非对称加密也要公钥加密。与对称加密相比,安全性更好。对称加密的通信双方使用相同的秘钥,如果任意一方的密钥被泄露,整个通信就会被破解。
非对称加密使用的是一对密钥,即公钥和私钥,且二者成对出现。私钥被自己保存,不能对外泄露。公钥指的是公共的密钥,任何人都可以获得该密钥。用公钥或私钥中的任何一个进行加密,用另一个进行解密。
过程:
明文 + 加密算法 + 公钥 = 密文; 密文 + 解密算法 + 私钥 = 明文

例子:

  1. 小明对小红说,我这里有箱子A(对应钥匙A),我把A箱子给你(箱子A没锁),钥匙不给你,你给我发的信息放在箱子A里,锁起来,然后我自己用钥匙A就能打开来看。
  2. 小红对小明说,我这里有箱子B(对应钥匙B),我把B箱子给你(箱子B没锁),钥匙不给你,你给我发的消息放在箱子B里,锁起来,然后我自己用钥匙B就能打开来看。

1.3 加密算法比较

加密算法分为:对称加密和非对称加密【此外还有一类不需要密钥散列算法】

常见的对称加密算法:DES、3DES、AES、HS256
常见的非对称加密算法:RSA、DSA
散列算法:SHA-1、MD5

2 实际应用

2.1 典型对称加密算法(以HS256为例)

见文章:
https://blog.csdn.net/weixin_45565886/article/details/126557256?spm=1001.2014.3001.5501

企业中开发代码:

package com.zi.api.commons.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.*;

import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.util.HashMap;
import java.util.Map;

/**
 * 生成jwt工具类
 */
public class JJWTRootUtils {

    //定义对应的编码算法
    static SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
    //盐值
    static String secretKey = "d8de020f63754a9fa746ea74b831afc3";

    //获取key(指定算法和盐值的key对象)
    private static Key generateKey(){
        //将盐值转成字节
        byte[] bytes = DatatypeConverter.parseBase64Binary(secretKey);
        //根据算法和盐值生成对应的key值
        Key key = new SecretKeySpec(bytes, signatureAlgorithm.getJcaName());
        return key;
    }

    /**
     * 将我们的数据使用JWT的方式变成一个token xxx.yyy.zzz
     * @param payLoad   负载(数据信息)
     * @return
     */
    public static String generatorToken(Map<String, String> payLoad){
        ObjectMapper objectMapper = new ObjectMapper();
        try{
            //构建jwt生成器
            JwtBuilder builder = Jwts.builder();
            //将负载信息设置到jwt生成器中
            JwtBuilder jwtBuilder = builder.setPayload(objectMapper.writeValueAsString(payLoad));
            //根据签名算法和key值,生成新的jwtBuilder
            JwtBuilder jwtBuilder1 = jwtBuilder.signWith(signatureAlgorithm, generateKey());
            String token = jwtBuilder1.compact();
            return token;
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据指定的token, 返回对应的body信息
     * @param token
     * @return
     */
    public static Claims phaseTokenGetBody(String token){
        JwtParser jwtParser = Jwts.parser().setSigningKey(generateKey());
        Jws<Claims> claimsJws = jwtParser.parseClaimsJws(token);
        Claims body = claimsJws.getBody();//主要存放的信息
        return body;
    }

    /**
     * 根据指定的token获取签名信息
     * @param token
     * @return
     */
    public static String phaseTokenGetSignature(String token){
        JwtParser jwtParser = Jwts.parser().setSigningKey(generateKey());
        Jws<Claims> claimsJws = jwtParser.parseClaimsJws(token);
        String signature = claimsJws.getSignature();
        return signature;
    }


    /**
     * 根据指定的token获取头信息
     * @param token
     * @return
     */
    public static JwsHeader phaseTokenGetHeader(String token){
        //获取解析器
        JwtParser parser = Jwts.parser();
        //设置签名key(盐值)
        parser = parser.setSigningKey(generateKey());
        //解析token
        Jws<Claims> claimsJws = parser.parseClaimsJws(token);
        JwsHeader header = claimsJws.getHeader();
        return header;
    }


    public static void main(String[] args) {
        //随机获取盐值
//        System.out.println(UUID.randomUUID().toString().replaceAll("-", ""));
        Map<String, String> payLoad = new HashMap<>();
        payLoad.put("name", "curry");
        String s = generatorToken(payLoad);
        //eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiY3VycnkifQ.Sf3GiF3p56nLzoAxEHLXcAckPmmPTtecj1_lGT9oV8s
        System.out.println(s);

        //调用自定义API获取结果
        Claims claims = phaseTokenGetBody(s);
        //{name=curry}
        System.out.println(claims);
    }

}

2.2 典型非对称加密算法(以RSA为例)

2.2.1 概念介绍

RSA算法

RSA算法 的保密强度随其密钥的长度增加而增强。但是,密钥越长,其加解密所耗用的时间也越长。

  • RSA加密算法是目前最右影响力的公钥加密算法,且被普遍认为是最优秀的公钥方案之一。
  • RSA是第一个能同时用于加密和数字签名的算法,它能够抵抗到目前为止已知的所有密码攻击,已经被ISO推荐为公钥数据加密标准。
  • RSA核心思想:将两个大素数相乘十分容易,但是要想对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。
2.2.2 具体实现(企业中工具类编写格式)
2.2.2.1 RSAUtil编写

首先编写RSAUtil工具类,用于生成RSA的公钥私钥


//RSA是一种非对称加密算法【公钥、私钥】
public class RASUtil {

    /**
     * 生成一对公私钥
     */
    public static void generatorKey() throws NoSuchAlgorithmException {

        //构建一个生成公私钥 RAS算法生成的对象
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");

        //初始化生成器 keySize:512起
        keyPairGenerator.initialize(512, new SecureRandom());

        //密钥对
        KeyPair keyPair = keyPairGenerator.generateKeyPair();

        //获取私钥
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();

        //获取公钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();

        //获取私钥字符串
        String privateKeyStr = new String(Base64.encodeBase64(privateKey.getEncoded()));
        String publicKeyStr = new String(Base64.encodeBase64(publicKey.getEncoded()));

        System.out.println("privateKeyStr:" + privateKeyStr);
        System.out.println("publicKeyStr:" + publicKeyStr);
        //privateKeyStr:MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEAhUfkmkFtrOlFiX8FmHiYx9mAPpfTA6oKE6VgFLDNQzYO1YMugA0ACChp6n3hfDWOp3XgWWRVmzU+z30h+01lyQIDAQABAkBtvjvKlDNFnDJou9GUsUBD1qDVaVgT/VAcyyApCUeKnehPLMISa5JBTUpJ03cMPh3hV7q4OJQweM7nuJ+GXcCBAiEAx5xHdUM3XnFZ6aQnAvKzPWqV/eqpDRj9aSFiR/vbJ3kCIQCq7rDN2qs1DUo8XS2WcbBOFLMU+uHDuV8rigFe0yyM0QIgfQ5hCotRDh9P6HwKYONy/kBftlQlE2qboRjkPRsCQ2kCIBUoVlokpux6KKYwImRszhXcGg6Ov0Mqvsz02BaUrP8BAiBrxV/0jPm2pr3GJXW5MHhJ4a2LrkYFfWdHQx+gpSJESg==
        //publicKeyStr:MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIVH5JpBbazpRYl/BZh4mMfZgD6X0wOqChOlYBSwzUM2DtWDLoANAAgoaep94Xw1jqd14FlkVZs1Ps99IftNZckCAwEAAQ==

    }


    public static void main(String[] args) throws NoSuchAlgorithmException {
        generatorKey();
    }
}

注意:企业中工具类中一般是没有main方法的,此处只是为了方便测试

2.2.2.2 JWTAuth0Util工具类编写【包含对称加密与非对称加密】

一般包含方法:

  • String genTokenRAS(Map<String, String> payload):基于RSA加密生成token
  • DecodedJWT decodedRSA(String token):基于RSA解密生成DecodedJWT
  • String getToken(Map<String, String> payload):获取token
  • DecodedJWT decodedJWT(String token):解析token
①非对称加密:根据RSA加密生成token
 /**
   * 根据RSA算法加密生成token
   * @param payload
   * @return
   */
  public static String genTokenRAS(Map<String, String> payload){
      //指定过期时间 【3天】
      Calendar calendar = Calendar.getInstance();
      calendar.add(Calendar.DATE, 3);

      //获取一个构建对象【静态内部类】
      JWTCreator.Builder builder = JWT.create();

      //将信息、数据(body)信息放到需要的claim里面
      payload.forEach((k, v) -> builder.withClaim(k, v));

      //通过hutool工具类来创建RSA对象
      RSA rsa = new RSA(PRIVATE_KEY_STR, null);

      //获取私钥
      RSAPrivateKey privateKey = (RSAPrivateKey) rsa.getPrivateKey();

      String token = builder.withExpiresAt(calendar.getTime()).sign(Algorithm.RSA256(null, privateKey));
      return token;
  }
②非对称加密:根据RSA解密token
/**
  * 使用RSA的方式来解密
  * @param token
  * @return
  * 根据不同的异常来判断当前token到底是什么情况
  */
 public static DecodedJWT decodedRSA(String token){
     //通过公钥获取我们的RSA的公钥对象
     RSA rsa = new RSA(null, PUBLIC_KEY_STR);
     RSAPublicKey publicKey = (RSAPublicKey) rsa.getPublicKey();

     //jwt的验证对象
     JWTVerifier jwtVerifier = JWT.require(Algorithm.RSA256(publicKey, null)).build();
     DecodedJWT decodedJWT = jwtVerifier.verify(token);
     return decodedJWT;
 }
③对称加密:HMAC256,定义盐值
private static final String SECRET = "H2OJ20FC35APACHE";
④对称加密:HMAC256,加密获取token
/**
  * 获取token
  * @param payload
  * @return
  */
 public static String getToken(Map<String, String> payload){
     //指定过期时间【3天】
     Calendar calendar = Calendar.getInstance();
     calendar.add(Calendar.DATE, 3);

     //获取一个构建对象【静态内部类】
     JWTCreator.Builder builder = JWT.create();

     //将body信息放到我们需要生成的claim里面
     payload.forEach((k, v) -> builder.withClaim(k, v));

     //通过指定签名算法和过期时间生成一个token
     String token = builder.withExpiresAt(calendar.getTime()).sign(Algorithm.HMAC256(SECRET));
     return token;
 }
⑤对称加密:HMAC256,解密获取数据
/**
  * 解析token
  * @param token
  * @return
  */
 public static DecodedJWT decodedJWT(String token){
     //构建一个验证jwt token的对象
     JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
     //验证以后获取信息的对象
     DecodedJWT decodedJWT = jwtVerifier.verify(token);
     //返回信息对象
     return decodedJWT;
 }
2.2.2.3 全部代码
package com.zi.api.commons.util;

import cn.hutool.crypto.asymmetric.RSA;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;

/**
 * 加密解密token
 */
public class JWTAuth0Util {

    private static final String SECRET = "H2OJ20FC35APACHE";

    //私钥和公钥
    private static final String PRIVATE_KEY_STR = "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAjX+A8rA2a8tJNQ2DK5pnfaXqHyv5iSG2KdWJk3GMkfN0VuEO/JvbM0ljQgi6/qPmgUIFgL65meavzJXDMr8IZQIDAQABAkEAh7JZdWRsLGAd6tT0kGJZEXSF3DMN8eb0jZYNg+sHRgdovJtlHZBTiMbSoQphvsYe8dBHplOjktzTipTe0y/rmQIhAMP13C1UFEPdFv9D6mFg+hehr0Jk+vcxOoGFA1o0vOz/AiEAuNnk/2etuErfNdgN9ujc88TAG2mpzBvyxpIHNQridpsCIC44dYBzjnwbT+tRt5zUZOjiCBae/tsDT4txNkM2oUE9AiBoN4jxKi36KlRAEiiFXXI9CV9Z1S/DALrWkzv2/sUBIwIgXgMe3SW4vML/ieQHIEmk+GhDD/NJad9Hs4HOBkNcA1I=";
    private static final String PUBLIC_KEY_STR = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAI1/gPKwNmvLSTUNgyuaZ32l6h8r+YkhtinViZNxjJHzdFbhDvyb2zNJY0IIuv6j5oFCBYC+uZnmr8yVwzK/CGUCAwEAAQ==";

    /**
     * 根据RSA算法加密生成token【非对称】
     * @param payload
     * @return
     */
    public static String genTokenRAS(Map<String, String> payload){
        //指定过期时间 【3天】
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE, 3);

        //获取一个构建对象【静态内部类】
        JWTCreator.Builder builder = JWT.create();

        //将信息、数据(body)信息放到需要的claim里面
        payload.forEach((k, v) -> builder.withClaim(k, v));

        //通过hutool工具类来创建RSA对象
        RSA rsa = new RSA(PRIVATE_KEY_STR, null);

        //获取私钥
        RSAPrivateKey privateKey = (RSAPrivateKey) rsa.getPrivateKey();

        String token = builder.withExpiresAt(calendar.getTime()).sign(Algorithm.RSA256(null, privateKey));
        return token;
    }

    /**
     * 使用RSA的方式来解密【非对称】
     * @param token
     * @return
     * 根据不同的异常来判断当前token到底是什么情况【比如被伪造...】
     */
    public static DecodedJWT decodedRSA(String token){
        //通过公钥获取我们的RSA的公钥对象
        RSA rsa = new RSA(null, PUBLIC_KEY_STR);
        RSAPublicKey publicKey = (RSAPublicKey) rsa.getPublicKey();

        //jwt的验证对象
        JWTVerifier jwtVerifier = JWT.require(Algorithm.RSA256(publicKey, null)).build();
        DecodedJWT decodedJWT = jwtVerifier.verify(token);
        return decodedJWT;
    }


    /**
     * 获取token【对称加密】
     * @param payload
     * @return
     */
    public static String getToken(Map<String, String> payload){
        //指定过期时间【3天】
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE, 3);

        //获取一个构建对象【静态内部类】
        JWTCreator.Builder builder = JWT.create();

        //将body信息放到我们需要生成的claim里面
        payload.forEach((k, v) -> builder.withClaim(k, v));

        //通过指定签名算法和过期时间生成一个token
        String token = builder.withExpiresAt(calendar.getTime()).sign(Algorithm.HMAC256(SECRET));
        return token;
    }

    /**
     * 解析token【对称加密】
     * @param token
     * @return
     */
    public static DecodedJWT decodedJWT(String token){
        //构建一个验证jwt token的对象
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
        //验证以后获取信息的对象
        DecodedJWT decodedJWT = jwtVerifier.verify(token);
        //返回信息对象
        return decodedJWT;
    }

    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();
        map.put("helicopter", "apache");
        String rsaCodeStr = genTokenRAS(map);
        System.out.println("非对称加密后的token:" + rsaCodeStr);
        DecodedJWT decodedJWT = decodedRSA(rsaCodeStr);
        String rsaDecodeStr = decodedJWT.getToken();
        System.out.println("非对称解密后的token:" + rsaDecodeStr);

        String hmacCodeStr = getToken(map);
        System.out.println("对称加密后的token:" + hmacCodeStr);
        DecodedJWT decodedJWT1 = decodedJWT(hmacCodeStr);
        String hmacDeCodeStr = decodedJWT1.getToken();
        System.out.println("对称解密后的token:" + hmacDeCodeStr);

    }
}

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值