公私钥加解密和签名验证及license生成

  • Post author:
  • Post category:其他



1、客户之间发消息的公私钥签名主要有以下几点

  • A和B连接的时候需要通知对方自己的公钥
  • A给B发消息,A使用B的公钥加密数据,A使用自己的私钥签名加密后的数据,B拿到加密后的数据和签名信息后,B用A的公钥进行签名信息的验证,然后B用自己的私钥进行数据解密。
  • B给A发消息,B使用A的公钥加密数据,B使用自己的私钥签名加密后的数据,A拿到加密后的数据和签名信息后,A用B的公钥进行签名信息的验证,然后A用自己的私钥进行数据解密。
  • 两者的消息互发是同理的都分为四个步骤:

    公钥加密,私钥签名,公钥签名验证,私钥解密


    具体请看代码中sendClentAClientB方法的实现,步骤清晰。


2、license的生成


这个主要使用自己服务提供者自己的公私钥对生成加密的license数据信息,和签名信息,license的数据信息可以不使用公钥进行加密,使用其他的加密算法的话,才不不需要将自己的私钥暴露出去,主要使用自己的私钥进行签名,然后提供公钥,签名后的信息,加密license信息三个出去,使用方用公钥进行签名验证,通过了则用具体的解密算法解析license数据,查看生效时间啥的。具体实现看generateLicense方法。

package com.chw.lincense;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.Cipher;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.SignatureException;
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.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class PrivatePublicSignEncDec {


    public static final String PUBLIC_KEY = "public";
    public static final String PRIVATE_KEY = "private";
    public static final int KEY_SIZE = 1024;
    public static final Base64.Decoder DECODER64 = Base64.getDecoder();
    public static final Base64.Encoder ENCODER64 = Base64.getEncoder();
    public static final String KEY_ALGORITHM = "RSA";
    public static final String SIGN_ALGORITHM = "SHA256withRSA";
    public static final String SIGN_STR = "signStr";
    public static final String ENCODE_DATA = "encodeData";

    /**
     * 生成公私钥
     *
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static Map<String, String> createPrivatePublicKey() throws NoSuchAlgorithmException {
        Map<String, String> keyMap = new HashMap<>();
        KeyPairGenerator generator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        generator.initialize(KEY_SIZE, new SecureRandom());
        KeyPair keyPair = generator.generateKeyPair();

        String privateKeyStr = ENCODER64.encodeToString(keyPair.getPrivate().getEncoded());
        String publicKeyStr = ENCODER64.encodeToString(keyPair.getPublic().getEncoded());
        keyMap.put(PRIVATE_KEY, privateKeyStr);
        keyMap.put(PUBLIC_KEY, publicKeyStr);
        return keyMap;
    }

    /**
     * 获取公钥
     *
     * @param publicKeyStr
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    public static PublicKey getPublicKey(String publicKeyStr) throws NoSuchAlgorithmException, InvalidKeySpecException {
        byte[] decodeKey = DECODER64.decode(publicKeyStr.getBytes());
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        return keyFactory.generatePublic(new X509EncodedKeySpec(decodeKey));
    }

    /**
     * 获取私钥
     *
     * @param privateKeyStr
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    public static PrivateKey getPrivateKey(String privateKeyStr) throws NoSuchAlgorithmException, InvalidKeySpecException {
        byte[] decodeKey = DECODER64.decode(privateKeyStr.getBytes());
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(decodeKey));
    }


    /**
     * 私钥对数据签名结果
     *
     * @param privateKeyStr
     * @param data
     * @return
     */
    public static String signByPrivateKey(String privateKeyStr, String data) throws InvalidKeySpecException, NoSuchAlgorithmException, SignatureException, InvalidKeyException {
        PrivateKey privateKey = getPrivateKey(privateKeyStr);
        Signature signature = Signature.getInstance(SIGN_ALGORITHM);
        signature.initSign(privateKey);
        signature.update(data.getBytes());
        byte[] sign = signature.sign();
        String signStr = ENCODER64.encodeToString(sign);
        return signStr;
    }

    /**
     * 通过公钥验证私钥对数据的签名
     *
     * @param publicKeyStr
     * @param data
     * @param signStr
     * @return
     */
    public static boolean verifySign(String publicKeyStr, String data, String signStr) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException {
        PublicKey publicKey = getPublicKey(publicKeyStr);
        Signature verifySign = Signature.getInstance(SIGN_ALGORITHM);
        verifySign.initVerify(publicKey);
        verifySign.update(data.getBytes());
        return verifySign.verify(DECODER64.decode(signStr));
    }


    /**
     * 通过公钥加密
     *
     * @param str
     * @param publicKeyStr
     * @return
     * @throws Exception
     */
    public static String encrypt(String str, String publicKeyStr) throws Exception {
        byte[] decodePublic = DECODER64.decode(publicKeyStr);
        RSAPublicKey publicKey = (RSAPublicKey) KeyFactory.getInstance(KEY_ALGORITHM).generatePublic(new X509EncodedKeySpec(decodePublic));
        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        String outStr = ENCODER64.encodeToString(cipher.doFinal(str.getBytes()));
        return outStr;
    }


    /**
     * 将str通过私钥解密
     *
     * @param str
     * @param privateKeyStr
     * @return
     */
    public static String decrypt(String str, String privateKeyStr) throws Exception {
        byte[] decodeInput = DECODER64.decode(str.getBytes());
        byte[] decodePrivate = DECODER64.decode(privateKeyStr.getBytes());
        RSAPrivateKey privateKey = (RSAPrivateKey) KeyFactory.getInstance(KEY_ALGORITHM).generatePrivate(new PKCS8EncodedKeySpec(decodePrivate));
        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        String outStr = new String(cipher.doFinal(decodeInput));
        return outStr;
    }

    /**
     * 生成license加密信息
     *
     * @return
     */
    public static Map<String, String> generateLicense() {
        try {
            Map<String, String> keyPairMap = createPrivatePublicKey();
            String privateKeyStr = keyPairMap.get(PRIVATE_KEY);
            String publicKeyStr = keyPairMap.get(PUBLIC_KEY);

            LicenseInfo licenseInfo = new LicenseInfo();  // 设置一些license信息
            licenseInfo.setCreateDate(new Date());
            licenseInfo.setLinceseCde("chw");
            licenseInfo.setValidTime(7 * 24 * 3600 * 1000L);

            String data = JSONObject.toJSONString(licenseInfo);
            log.info("原始data:" + data);
            String encodeData = encrypt(data, publicKeyStr);
            log.info("加密后的data:" + encodeData);

            String signStr = signByPrivateKey(privateKeyStr, encodeData);

            // 这个map里面的东西就是给到使用方的整体license信息,使用方可以用对应的公钥,签名信息,加密的数据进行
            Map<String, String> resultMap = new HashMap<>();
            resultMap.put(PUBLIC_KEY, publicKeyStr);
            resultMap.put(SIGN_STR, signStr);
            resultMap.put(ENCODE_DATA, encodeData);
            // 生成license的话可以是不用publicKey加密license信息,使用其他加密算法,后用私钥进行签名就行,如果这样,就不要对外暴露私钥,暴露私钥会给使用方人员篡改data的
            resultMap.put(PRIVATE_KEY, privateKeyStr);

            // 下面是使用
            boolean result = verifySign(publicKeyStr, encodeData, signStr);
            log.info("签名验证结果result:" + result);
            if (result) {
                String decodeData = decrypt(encodeData, privateKeyStr);
                log.info("解密后的data:" + decodeData);
                LicenseInfo decodeObj = JSONObject.parseObject(decodeData, LicenseInfo.class);
                log.info("decodeObj:" + decodeObj);
            }
            return resultMap;
        }
        catch (Exception e) {
            log.error(e.getMessage(), e);
            return null;
        }
    }


    /**
     * A和B连接的时候需要通知对方自己的公钥
     * A给B发消息,A使用B的公钥加密数据,A使用自己的私钥签名加密后的数据,B拿到加密后的数据和签名信息后,B用A的公钥进行签名信息的验证,然后B用自己的私钥进行数据解密。
     * B给A发消息,B使用A的公钥加密数据,B使用自己的私钥签名加密后的数据,A拿到加密后的数据和签名信息后,A用B的公钥进行签名信息的验证,然后A用自己的私钥进行数据解密。
     * 两者的消息互发是同理的都分为四个步骤
     */
    public static void sendClentAClientB() throws Exception {
        Map<String, String> kepMapOfA = createPrivatePublicKey();
        Map<String, String> keyMapOfB = createPrivatePublicKey();
        String privateKeyStrA = kepMapOfA.get(PRIVATE_KEY);
        String publicKeyStrA = kepMapOfA.get(PUBLIC_KEY);
        String privateKeyStrB = keyMapOfB.get(PRIVATE_KEY);
        String publicKeyStrB = keyMapOfB.get(PUBLIC_KEY);

        // a发给b的消息用b的公钥加密,用a自己的私钥签名
        String msgAToB = "哈哈哈哈哈这是A发送给B";
        // 步骤1,用对方的公钥加密
        String encodeData = encrypt(msgAToB, publicKeyStrB);
        // 步骤2,用自己的私钥签名
        String signStr = signByPrivateKey(privateKeyStrA, encodeData);

        //b收到消息后,用a的公钥验证签名,然后用b自己的私钥解密
        // 步骤3,用对方的公钥验证签名
        boolean validResult = verifySign(publicKeyStrA, encodeData, signStr);
        if (validResult) {
            log.info("验证签名成功");
            // 步骤4,用自己的私钥解密数据
            String decodeData = decrypt(encodeData, privateKeyStrB);
            log.info("decodeData:" + decodeData);
        }
        else {
            log.info("验证失败");
        }

    }

    /**
     * 公私钥总体流程: 公钥加密,私钥签名,公钥签名验证,私钥解密
     *
     * @param args
     */
    public static void main(String[] args) throws Exception {
//        Map<String,String> encodeMap = generateLicense();
        sendClentAClientB();
    }
}

package com.chw.lincense;

import lombok.Data;

import java.util.Date;

@Data
public class LicenseInfo {
    private String linceseCde;

    /**
     * 创建时期
     */
    private Date createDate;

    /**
     * 有效期 毫秒为单位
     */
    private Long validTime;
}



版权声明:本文为qq_44079295原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。