常见签名算法之SHA256withRSA

2022/2/24 17:24:07

本文主要是介绍常见签名算法之SHA256withRSA,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

SHA256withRSA 完美工具类 RSAUtils,包含:

1、签名

2、验签

3、公钥加密

4、钥加密私

RSAUtils工具类:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RSAUtils {

	private static final Logger logger = LoggerFactory.getLogger(RSAUtils.class);
	

	// MAX_DECRYPT_BLOCK应等于密钥长度/8(1byte=8bit),所以当密钥位数为2048时,最大解密长度应为256.
	// 128 对应 1024,256对应2048
	private static final int KEYSIZE = 2048;

	// RSA最大加密明文大小
	private static final int MAX_ENCRYPT_BLOCK = 117;

	// RSA最大解密密文大小
	private static final int MAX_DECRYPT_BLOCK = 128;
	
	// 不仅可以使用DSA算法,同样也可以使用RSA算法做数字签名
	private static final String KEY_ALGORITHM = "RSA";
	private static final String SIGNATURE_ALGORITHM = "SHA256withRSA";

	public static final String DEFAULT_SEED = "$%^*%^()(ED47d784sde78"; // 默认种子

	public static final String PUBLIC_KEY = "PublicKey";
	public static final String PRIVATE_KEY = "PrivateKey";

	/**
	 * 
	 * 生成密钥
	 * 
	 * @param seed 种子
	 * 
	 * @return 密钥对象
	 * @throws Exception
	 * 
	 */

	public static Map<String, Key> initKey(String seed) throws Exception {
		logger.info("生成密钥");
		KeyPairGenerator keygen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
		SecureRandom secureRandom = new SecureRandom();
		// 如果指定seed,那么secureRandom结果是一样的,所以生成的公私钥也永远不会变
		// secureRandom.setSeed(seed.getBytes());
		// Modulus size must range from 512 to 1024 and be a multiple of 64
		keygen.initialize(KEYSIZE, secureRandom);
		KeyPair keys = keygen.genKeyPair();
		PrivateKey privateKey = keys.getPrivate();
		PublicKey publicKey = keys.getPublic();
		Map<String, Key> map = new HashMap<>(2);
		map.put(PUBLIC_KEY, publicKey);
		map.put(PRIVATE_KEY, privateKey);
		return map;
	}

	/**
	 * 
	 * 生成默认密钥
	 *
	 * 
	 * @return 密钥对象
	 * @throws Exception
	 * 
	 */

	public static Map<String, Key> initKey() throws Exception {
		return initKey(DEFAULT_SEED);
	}

	/**
	 * 
	 * 取得私钥
	 * 
	 * @param keyMap
	 * 
	 * @return
	 * @throws Exception
	 * 
	 */
	public static String getPrivateKey(Map<String, Key> keyMap) throws Exception {
		Key key = (Key) keyMap.get(PRIVATE_KEY);
		return encryptBASE64(key.getEncoded()); // base64加密私钥
	}

	/**
	 * 
	 * 取得公钥
	 * 
	 * @param keyMap
	 * 
	 * @return
	 * @throws Exception
	 * 
	 */
	public static String getPublicKey(Map<String, Key> keyMap) throws Exception {
		Key key = (Key) keyMap.get(PUBLIC_KEY);
		return encryptBASE64(key.getEncoded()); // base64加密公钥
	}

	/**
	 * 
	 * 用私钥对信息进行数字签名
	 * 
	 * @param data       加密数据
	 * 
	 * @param privateKey 私钥-base64加密的
	 * 
	 * @return
	 * 
	 * @throws Exception
	 * 
	 */
	public static String signByPrivateKey(byte[] data, String privateKey) throws Exception {
		logger.info("用私钥对信息进行数字签名");
		byte[] keyBytes = decryptBASE64(privateKey);
		PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
		KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM);
		PrivateKey priKey = factory.generatePrivate(keySpec);// 生成私钥
		// 用私钥对信息进行数字签名
		Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
		signature.initSign(priKey);
		signature.update(data);
		return encryptBASE64(signature.sign());

	}

	/**
	 * 
	 * BASE64Encoder 加密
	 * 
	 * @param data 要加密的数据
	 * 
	 * @return 加密后的字符串
	 * 
	 */
	private static String encryptBASE64(byte[] data) {
//		BASE64Encoder encoder = new BASE64Encoder();
//		String encode = encoder.encode(data);
//		return encode;
		return new String(Base64.encodeBase64(data));
	}

	private static byte[] decryptBASE64(String data) {
		// BASE64Decoder 每76个字符换行
		// BASE64Decoder decoder = new BASE64Decoder();
		// byte[] buffer = decoder.decodeBuffer(data);
		// return buffer;
		// codec 的 Base64 不换行
		return Base64.decodeBase64(data);
	}

	public static boolean verifyByPublicKey(byte[] data, String publicKey, String sign) throws Exception {
		byte[] keyBytes = decryptBASE64(publicKey);
		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		PublicKey pubKey = keyFactory.generatePublic(keySpec);
		Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
		signature.initVerify(pubKey);
		signature.update(data);
		return signature.verify(decryptBASE64(sign)); // 验证签名
	}

	/**
	 * RSA公钥加密
	 * 
	 * @param str       加密字符串
	 * @param publicKey 公钥
	 * @return 密文
	 * @throws NoSuchAlgorithmException
	 * @throws InvalidKeySpecException
	 * @throws NoSuchPaddingException
	 * @throws InvalidKeyException
	 * @throws UnsupportedEncodingException
	 * @throws BadPaddingException
	 * @throws IllegalBlockSizeException
	 * @throws Exception                    加密过程中的异常信息
	 */
	public static String encryptByPublicKey(String str, String publicKey)
			throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
			IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
		// base64编码的公钥
		byte[] keyBytes = decryptBASE64(publicKey);
		RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance(KEY_ALGORITHM)
				.generatePublic(new X509EncodedKeySpec(keyBytes));
		// RSA加密
		Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
		cipher.init(Cipher.ENCRYPT_MODE, pubKey);

		byte[] data = str.getBytes("UTF-8");
		// 加密时超过117字节就报错。为此采用分段加密的办法来加密
		byte[] enBytes = null;
		for (int i = 0; i < data.length; i += MAX_ENCRYPT_BLOCK) {
			// 注意要使用2的倍数,否则会出现加密后的内容再解密时为乱码
			byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(data, i, i + MAX_ENCRYPT_BLOCK));
			enBytes = ArrayUtils.addAll(enBytes, doFinal);
		}
		String outStr = encryptBASE64(enBytes);
		return outStr;
	}
	
	/**
	 * RSA私钥加密
	 * 
	 * @param str       加密字符串
	 * @param privateKey 公钥
	 * @return 密文
	 * @throws NoSuchAlgorithmException
	 * @throws InvalidKeySpecException
	 * @throws NoSuchPaddingException
	 * @throws InvalidKeyException
	 * @throws UnsupportedEncodingException
	 * @throws BadPaddingException
	 * @throws IllegalBlockSizeException
	 * @throws Exception                    加密过程中的异常信息
	 */
	public static String encryptByPrivateKey(String str, String privateKey)
			throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
			IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
		// base64编码的公钥
		byte[] keyBytes = decryptBASE64(privateKey);
		RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance(KEY_ALGORITHM)
				.generatePrivate(new PKCS8EncodedKeySpec(keyBytes));
		// RSA加密
		Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
		cipher.init(Cipher.ENCRYPT_MODE, priKey);
		
		byte[] data = str.getBytes("UTF-8");
		// 加密时超过117字节就报错。为此采用分段加密的办法来加密
		byte[] enBytes = null;
		for (int i = 0; i < data.length; i += MAX_ENCRYPT_BLOCK) {
			// 注意要使用2的倍数,否则会出现加密后的内容再解密时为乱码
			byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(data, i, i + MAX_ENCRYPT_BLOCK));
			enBytes = ArrayUtils.addAll(enBytes, doFinal);
		}
		String outStr = encryptBASE64(enBytes);
		return outStr;
	}

	/**
	 * 读取公钥
	 * 
	 * @param publicKeyPath
	 * @return
	 */
	public static PublicKey readPublic(String publicKeyPath) {
		if (publicKeyPath != null) {
			try (FileInputStream bais = new FileInputStream(publicKeyPath)) {
				CertificateFactory certificatefactory = CertificateFactory.getInstance("X.509");
				X509Certificate cert = (X509Certificate) certificatefactory.generateCertificate(bais);
				return cert.getPublicKey();
			} catch (CertificateException e) {
				logger.error(e.getMessage(), e);
			} catch (FileNotFoundException e) {
				logger.error(e.getMessage(), e);
			} catch (IOException e) {
				logger.error(e.getMessage(), e);
			}
		}
		return null;
	}

	/**
	 * 读取私钥
	 * 
	 * @param path
	 * @return
	 */
	public static PrivateKey readPrivate(String privateKeyPath, String privateKeyPwd) {
		if (privateKeyPath == null || privateKeyPwd == null) {
			return null;
		}
		try (InputStream stream = new FileInputStream(new File(privateKeyPath));) {
			// 获取JKS 服务器私有证书的私钥,取得标准的JKS的 KeyStore实例
			KeyStore store = KeyStore.getInstance("JKS");// JKS,二进制格式,同时包含证书和私钥,一般有密码保护;PKCS12,二进制格式,同时包含证书和私钥,一般有密码保护。
			// jks文件密码,根据实际情况修改
			store.load(stream, privateKeyPwd.toCharArray());
			// 获取jks证书别名
			Enumeration<String> en = store.aliases();
			String pName = null;
			while (en.hasMoreElements()) {
				String n = (String) en.nextElement();
				if (store.isKeyEntry(n)) {
					pName = n;
				}
			}
			// 获取证书的私钥
			PrivateKey key = (PrivateKey) store.getKey(pName, privateKeyPwd.toCharArray());
			return key;
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		}
		return null;
	}

	/**
	 * RSA私钥解密
	 * 
	 * @param encryStr   加密字符串
	 * @param privateKey 私钥
	 * @return 铭文
	 * @throws NoSuchAlgorithmException
	 * @throws InvalidKeySpecException
	 * @throws NoSuchPaddingException
	 * @throws BadPaddingException
	 * @throws IllegalBlockSizeException
	 * @throws InvalidKeyException
	 * @throws Exception                 解密过程中的异常信息
	 */
	public static String decryptByPrivateKey(String encryStr, String privateKey)
			throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException,
			BadPaddingException, InvalidKeyException {
		// base64编码的私钥
		byte[] decoded = decryptBASE64(privateKey);
		RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance(KEY_ALGORITHM)
				.generatePrivate(new PKCS8EncodedKeySpec(decoded));
		// RSA解密
		Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
		cipher.init(Cipher.DECRYPT_MODE, priKey);

		// 64位解码加密后的字符串
		byte[] data = decryptBASE64(encryStr);
		// 解密时超过128字节报错。为此采用分段解密的办法来解密
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < data.length; i += MAX_DECRYPT_BLOCK) {
			byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(data, i, i + MAX_DECRYPT_BLOCK));
			sb.append(new String(doFinal));
		}

		return sb.toString();
	}
	
	/**
	 * RSA公钥解密
	 * 
	 * @param encryStr   加密字符串
	 * @param privateKey 私钥
	 * @return 铭文
	 * @throws NoSuchAlgorithmException
	 * @throws InvalidKeySpecException
	 * @throws NoSuchPaddingException
	 * @throws BadPaddingException
	 * @throws IllegalBlockSizeException
	 * @throws InvalidKeyException
	 * @throws Exception                 解密过程中的异常信息
	 */
	public static String decryptByPublicKey(String encryStr, String publicKey)
			throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException,
			BadPaddingException, InvalidKeyException {
		// base64编码的私钥
		byte[] decoded = decryptBASE64(publicKey);
		RSAPublicKey priKey = (RSAPublicKey) KeyFactory.getInstance(KEY_ALGORITHM)
				.generatePublic(new X509EncodedKeySpec(decoded));
		// RSA解密
		Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
		cipher.init(Cipher.DECRYPT_MODE, priKey);
		
		// 64位解码加密后的字符串
		byte[] data = decryptBASE64(encryStr);
		// 解密时超过128字节报错。为此采用分段解密的办法来解密
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < data.length; i += MAX_DECRYPT_BLOCK) {
			byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(data, i, i + MAX_DECRYPT_BLOCK));
			sb.append(new String(doFinal));
		}
		
		return sb.toString();
	}

	/**
	 * main方法测试 第一种用法:公钥加密,私钥解密。---用于加解密 第二种用法:私钥签名,公钥验签。---用于签名
	 * 
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		String ss = "hello";
		byte[] data = ss.getBytes();
		Map<String, Key> keyMap = initKey();// 构建密钥
		PublicKey publicKey = (PublicKey) keyMap.get(PUBLIC_KEY);
		PrivateKey privateKey = (PrivateKey) keyMap.get(PRIVATE_KEY);
		logger.info("私钥format:{}", privateKey.getFormat());
		logger.info("公钥format:{}", publicKey.getFormat());
		logger.info("私钥string:{}", getPrivateKey(keyMap));
		logger.info("公钥string:{}", getPublicKey(keyMap));
		// 产生签名
		String sign = signByPrivateKey(data, getPrivateKey(keyMap));
		logger.info("签名sign={}", sign);
		// 验证签名
		boolean verify1 = verifyByPublicKey(ss.getBytes(), getPublicKey(keyMap), sign);
		logger.info("经验证数据和签名匹配:{} ", verify1);
		boolean verify = verifyByPublicKey(data, getPublicKey(keyMap), sign);
		logger.error("经验证数据和签名匹配:{} ", verify);
		// logger.info("数字签名为"+sign);

		String s = "测试,e8986ae53e76e7514ebc7e8a42e81e6cea5b6280fb5d3259d5f0a46f9f6e090c";
		String encryStr = encryptByPublicKey(s, getPublicKey(keyMap));
		logger.info("字符串 {} 的公钥加密结果为:{}", s, encryStr);
		String decryStr = decryptByPrivateKey(encryStr, getPrivateKey(keyMap));
		logger.info("私钥解密结果为:{}", decryStr);
		logger.info("========================================================================================");
		String s2 = "测试222,e8986ae53e76e7514ebc7e8a42e81e6cea5b6280fb5d3259d5f0a46f9f6e090c";
		String encryStr2 = encryptByPrivateKey(s, getPrivateKey(keyMap));
		logger.info("字符串 {} 的私钥加密结果为:{}", s2, encryStr2);
		String decryStr2 = decryptByPublicKey(encryStr2, getPublicKey(keyMap));
		logger.info("公钥解密结果为:{}", decryStr2);

	}

}

 当我在使用springcloud的oauth2时,经常会用到jwt作为用户身份的确认和鉴权。而我们知道jwt是由三部分组成,其中第三部分就是数字签名了,而springcloud的oauth2中的默认jwt签名算法为SHA256withRSA。

    下面通过调用OauthServer的{/oauth/token_key}接口来看一下返回情况:

 

HMAC与SHA256withRSA

    hmac做签名时需要指定一个secret和指定hamc算法,常见的hmac算法有hamcsha1、hamcsha256等,通常用hmac生成信息摘要后会再用RSA算法对其进行加密

    SHA256withRSA做签名则一步到位,需要先生成RSA密钥对,其中私钥用于签名,公钥用于验签。

    为了方便理解:

    hmac数字签名 =  rsa_encrypt(hmac(信息) + RSA私钥)

    SHA256withRSA数字签名 =  SHA256withRSA_encrypt(信息 + RSA私钥)

RSA密钥之PKCS#1、PKCS#8

    pkcs时密钥的语法标准,细心的同学应该会经常遇到PKCS#1,PKCS#8,PKCS#12等标准,具体所代表的含义这里不做赘述了。通常我们生成密钥对时,会对私钥进行加密,加密后的格式为PKCS#1或PKCS#8格式,而一般不会对公钥进行加密。对于开发者而言,JAVA中通常使用的是PKCS8格式的私钥,php、.net使用的是PKCS1格式的私钥。简单例子: 用openssl生成PKCS#1格式的私钥:openssl genrsa -des3 -out test.key 1024

通过文件首尾部能判断:

 

JAVA示例

  1.签名示例

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMWriter;
import org.bouncycastle.util.encoders.Base64;
 
import java.io.IOException;
import java.io.StringWriter;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.Signature;
import java.security.SignatureException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.HashMap;
import java.util.Map;
 
public class SignTest {
 
    /**
     * 生成没有加密的密钥对
     * @param algorithm
     * @param keysize
     * @return
     * @throws Exception
     */
    public static Map<String, Object> createKey(String algorithm,int keysize) throws Exception {
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(algorithm);
        keyPairGen.initialize(keysize);
        KeyPair keyPair = keyPairGen.generateKeyPair();
 
        //通过对象 KeyPair 获取RSA公私钥对象RSAPublicKey RSAPrivateKey
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
 
        //公私钥对象存入map中
        Map<String, Object> keyMap = new HashMap<String, Object>(2);
        keyMap.put("publicKey", publicKey);
        keyMap.put("privateKey", privateKey);
        return keyMap;
    }
 
    /**
     * 生成加过密的密钥对 pkcs#1格式私钥 pkcs#8格式公钥
     *
     * @param algorithm
     * @param keysize
     * @param privateKeyPwd
     * @return
     * @throws Exception
     */
    public static Map<String, Object> createEncryKeyStr(String algorithm, int keysize, String privateKeyPwd) throws Exception {
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(algorithm);
        keyPairGen.initialize(keysize);
        KeyPair keyPair = keyPairGen.generateKeyPair();
 
        //通过对象 KeyPair 获取RSA公私钥对象RSAPublicKey RSAPrivateKey
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
 
        String pubKeyStr = new String(Base64.encode(publicKey.getEncoded())); //pkcs8格式
        String priKeyStr = new String(Base64.encode(privateKey.getEncoded())); //pkcs8格式
        System.out.println(priKeyStr);//从输出结果可以知道是PKCS#8格式的
 
        //私钥加密
        String privateKeyStr = privateKeyPwdToPKCS1(privateKey, privateKeyPwd);//使用BC加密私钥格式会被转为PKSC#1格式
        System.out.println(privateKeyStr);
        System.out.println(privateKeyNoPwdToPKCS1(privateKey));
 
        //公私钥对象存入map中
        Map<String, Object> keyMap = new HashMap<String, Object>(2);
        keyMap.put("publicKeyStr", pubKeyStr);
        keyMap.put("privateKeyStr", privateKeyStr);
        return keyMap;
    }
 
    /**
     * 将私钥转为PKCS#1格式私钥(加密)
     *
     * @param privateKey
     * @param filePasswd
     * @return
     */
    private static String privateKeyPwdToPKCS1(PrivateKey privateKey, String filePasswd) {
        Security.addProvider(new BouncyCastleProvider());
        StringWriter sw = new StringWriter();
        PEMWriter writer = new PEMWriter(sw);
        try {
            writer.writeObject(privateKey, "DESEDE", filePasswd.toCharArray(),
                    new SecureRandom());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (writer != null) {
                    writer.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
 
        return sw.toString();
    }
 
    /**
     * 将私钥转为PKCS#1格式私钥(没有加密)
     * @param privateKey
     * @return
     */
    private static String privateKeyNoPwdToPKCS1(PrivateKey privateKey){
        Security.addProvider(new BouncyCastleProvider());
        StringWriter sw = new StringWriter();
        PEMWriter writer = new PEMWriter(sw);
        try {
            writer.writeObject(privateKey);
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            try {
                if(writer !=null){
                    writer.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
 
        return sw.toString();
    }
 
 
    public static final String SIGNATURE_ALGORITHM = "SHA256withRSA";
    public static final String ENCODE_ALGORITHM = "SHA-256";
    public static final String PLAIN_TEXT = "test string";
 
    /**
     * 签名
     * @param privateKey  私钥
     * @param plainText 明文
     * @return
     */
    public static byte[] sign(PrivateKey privateKey, String plainText) {
        MessageDigest messageDigest;
        byte[] signed = null;
        try {
            messageDigest = MessageDigest.getInstance(ENCODE_ALGORITHM);
            messageDigest.update(plainText.getBytes());
            byte[] outputDigest_sign = messageDigest.digest();
            System.out.println("SHA-256编码后-----》"
                    + org.apache.commons.codec.binary.Base64.encodeBase64String(outputDigest_sign));
            Signature Sign = Signature.getInstance(SIGNATURE_ALGORITHM);
            Sign.initSign(privateKey);
            Sign.update(outputDigest_sign);
            signed = Sign.sign();
            System.out.println("SHA256withRSA签名后-----》"
                    + org.apache.commons.codec.binary.Base64.encodeBase64String(signed));
        } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
            e.printStackTrace();
        }
        return signed;
    }
 
    /**
     * 验签
     * @param publicKey 公钥
     * @param plain_text 明文
     * @param signed 签名
     */
    public static boolean verifySign(PublicKey publicKey, String plain_text, byte[] signed) {
        MessageDigest messageDigest;
        boolean SignedSuccess=false;
        try {
            messageDigest = MessageDigest.getInstance(ENCODE_ALGORITHM);
            messageDigest.update(plain_text.getBytes());
            byte[] outputDigest_verify = messageDigest.digest();
            //System.out.println("SHA-256加密后-----》" +bytesToHexString(outputDigest_verify));
            Signature verifySign = Signature.getInstance(SIGNATURE_ALGORITHM);
            verifySign.initVerify(publicKey);
            verifySign.update(outputDigest_verify);
            SignedSuccess = verifySign.verify(signed);
            System.out.println("验证成功?---" + SignedSuccess);
 
        } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
            e.printStackTrace();
        }
        return SignedSuccess;
    }
 
 
    /**
     * bytes[]换成16进制字符串
     *
     * @param src
     * @return
     */
    public static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder("");
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }
 
 
    public static void main(String[] args) throws Exception {
        Map<String, Object> keyMap = createKey("RSA", 2048);
        PublicKey publicKey = (PublicKey) keyMap.get("publicKey");
        PrivateKey privateKey = (PrivateKey) keyMap.get("privateKey");
        byte[] signBytes = sign(privateKey, PLAIN_TEXT);
        System.out.println(verifySign(publicKey, PLAIN_TEXT, signBytes));
        
    }
}

2.签发JWT示例

import com.cyq.CheckResult;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.SignatureException;
import org.bouncycastle.util.encoders.Base64;
 
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
 
/**
 * maven依赖
 *
 * <dependency>
 * <groupId>io.jsonwebtoken</groupId>
 * <artifactId>jjwt</artifactId>
 * <version>0.9.0</version>
 * </dependency>
 */
 
/**
 * @author cyq
 */
public class JwtUtils {
 
    public static void main(String[] args) throws Exception {
        // 签发jwt(签名算法hmac256)
        System.out.println("签发jwt(签名算法hmac256):");
        String jwt = createJWT("123", "jwt_hmac256", 60);
        System.out.println(jwt);
        // 解析
        SecretKey secretKey = generalKey();
        Claims claims = parseJWT(jwt, secretKey);
        System.out.println(claims);
 
 
        // 签发jwt(签名算法SHA256withRSA)
        System.out.println("\n签发jwt(签名算法SHA256withRSA):");
        Map<String, Object> keyMaps = createRSAKey(2048);
        String jwt2 = createJWT2("456", "jwt_SHA256withRSA", 60, (RSAPrivateKey) keyMaps.get("privateKey"));
        System.out.println(jwt2);
        // 解析
        Claims claims2 = parseJWT(jwt2, (RSAPublicKey) keyMaps.get("publicKey"));
        System.out.println(claims2);
 
    }
 
    /**
     * 签发JWT
     * @param id
     * @param subject 可以是JSON数据 尽可能少
     * @param ttlMillis
     * @return String
     *
     */
    public static String createJWT(String id, String subject, long ttlMillis) {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;// HmacSha256
 
        OffsetDateTime now = OffsetDateTime.now(ZoneId.of("Asia/Shanghai"));
        //Date now = new Date(nowMillis);
        SecretKey secretKey = generalKey();
 
        JwtBuilder builder = Jwts.builder()
                .setId(id)
                .setSubject(subject)   // 主题
                .setIssuer("user")     // 签发者
                .setIssuedAt(Date.from(now.toInstant()))      // 签发时间
                .signWith(signatureAlgorithm, secretKey); // 签名算法以及密匙
        if (ttlMillis >= 0) {
            OffsetDateTime expTime = now.plusSeconds(ttlMillis);
            builder.setExpiration(Date.from(expTime.toInstant())); // 过期时间
        }
        return builder.compact();
    }
 
    /**
     * 签发JWT
     * @param id
     * @param subject 可以是JSON数据 尽可能少
     * @param ttlMillis
     * @return String
     *
     */
    public static String createJWT2(String id, String subject, long ttlMillis, RSAPrivateKey privateKey) {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.RS256;// SHA256withRSA
        OffsetDateTime now = OffsetDateTime.now(ZoneId.of("Asia/Shanghai"));
 
        JwtBuilder builder = Jwts.builder()
                .setId(id)
                .setSubject(subject)   // 主题
                .setIssuer("user")     // 签发者
                .setIssuedAt(Date.from(now.toInstant()))      // 签发时间
                .signWith(signatureAlgorithm, privateKey); // 签名算法以及密匙
        if (ttlMillis >= 0) {
            OffsetDateTime expTime = now.plusSeconds(ttlMillis);
            builder.setExpiration(Date.from(expTime.toInstant())); // 过期时间
        }
        return builder.compact();
    }
 
    /**
     * 生成没有加密的密钥对
     * @param keysize
     * @return
     * @throws Exception
     */
    public static Map<String, Object> createRSAKey(int keysize) throws Exception {
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("rsa");
        keyPairGen.initialize(keysize);
        KeyPair keyPair = keyPairGen.generateKeyPair();
 
        //通过对象 KeyPair 获取RSA公私钥对象RSAPublicKey RSAPrivateKey
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
 
        //公私钥对象存入map中
        Map<String, Object> keyMap = new HashMap<String, Object>(2);
        keyMap.put("publicKey", publicKey);
        keyMap.put("privateKey", privateKey);
        return keyMap;
    }
 
 
    public static SecretKey generalKey() {
        byte[] encodedKey = Base64.decode("testjwt");
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }
 
    /**
     *
     * 解析JWT字符串
     * @param jwt
     * @return
     * @throws Exception
     */
    public static Claims parseJWT(String jwt, Key key) throws Exception {
        return Jwts.parser()
                .setSigningKey(key)
                .parseClaimsJws(jwt)
                .getBody();
    }
 
 
    /**
     * 验证JWT
     * @param jwtStr
     * @return
     */
    public static CheckResult validateJWT(String jwtStr, Key key) {
        CheckResult checkResult = new CheckResult();
        Claims claims = null;
        try {
            claims = parseJWT(jwtStr, key);
            checkResult.setSuccess(true);
            checkResult.setClaims(claims);
        } catch (ExpiredJwtException e) {
            e.printStackTrace();
            checkResult.setErrCode("JWT_ERRCODE_EXPIRE");
            checkResult.setSuccess(false);
        } catch (SignatureException e) {
            e.printStackTrace();
            checkResult.setErrCode("JWT_ERRCODE_FAIL");
            checkResult.setSuccess(false);
        } catch (Exception e) {
            e.printStackTrace();
            checkResult.setErrCode("JWT_ERRCODE_FAIL");
            checkResult.setSuccess(false);
        }
        return checkResult;
    }
}



这篇关于常见签名算法之SHA256withRSA的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程