golang生成公私钥java签名验签

最近在学习golang,决定用golang搭建一个支付中心的服务,客服端与服务器通信使用非对称rsa加签验签,来保证通信的可靠安全。客服端可以请求支付中心golang生成公私钥,支付中心提供sdk,sdk支持各主流语言。golang版本的rsa签名和验签都没问题,

在写java版本的sdk确出现了问题,先把golang版本的sdk贴上。

package sdk

import (
    "crypto"
    "crypto/md5"
    "crypto/rand"
    "crypto/rsa"
    "crypto/sha256"
    "crypto/x509"
    "encoding/base64"
    "encoding/hex"
    "encoding/pem"
    "errors"
    "log"
)

const (
    privateBlockType = "RSA PRIVATE KEY"
    publicBlockType  = "RSA PUBLIC KEY"
)

// Md5 to encode string of src,
// the return string length is 32
func Md5(src string) string {
    defer GetTimer("md5加密")()
    bs := md5.Sum([]byte(src))
    endCodeStr := hex.EncodeToString(bs[:])
    return endCodeStr
}

func GenRsaKeys(bits int) (priKey, pubKey, pkcs8Key string, err error) {
    defer GetTimer("生成rsa密钥对")()
    key, err := rsa.GenerateKey(rand.Reader, bits)
    if err != nil {
        return "", "", "", err
    }
    err = key.Validate()
    if err != nil {
        return "", "","", err
    }
    priBytes := x509.MarshalPKCS1PrivateKey(key)
    priKey = string(pem.EncodeToMemory(&pem.Block{Type: privateBlockType, Bytes: priBytes}))

    pubBytes, err := x509.MarshalPKIXPublicKey(&key.PublicKey)
    if err != nil {
        panic(err)
    }
    pubKey = string(pem.EncodeToMemory(&pem.Block{Type: publicBlockType, Bytes: pubBytes}))

    pkcs8Bytes, err := x509.MarshalPKCS8PrivateKey(key)
    if err != nil {
        return "", "", "", err
    }
    pkcs8Key = string(pem.EncodeToMemory(&pem.Block{Type: privateBlockType, Bytes: pkcs8Bytes}))

    return priKey, pubKey, pkcs8Key, err
}

func decodePrivateKey(privateKey string) (*rsa.PrivateKey, error) {
    block, _ := pem.Decode([]byte(privateKey))
    if block == nil || block.Type != privateBlockType {
        return nil, errors.New("failed to decode PEM block containing private key")
    }
    return x509.ParsePKCS1PrivateKey(block.Bytes)
}

//私钥加签
func SignWithPrivateKey(privateKey string, src []byte) (string, error) {
    defer GetTimer("私钥加签")()
    key, err := decodePrivateKey(privateKey)
    if err != nil {
        return "", err
    }
    hashed := sha256.Sum256(src)
    log.Println("sha256:", base64.StdEncoding.EncodeToString(hashed[:]))
    signBytes, err := rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, hashed[:])
    if err != nil {
        return "", err
    }
    return base64.StdEncoding.EncodeToString(signBytes), nil
}

func decodePublicKey(publicKey string) (*rsa.PublicKey, error) {
    block, _ := pem.Decode([]byte(publicKey))
    if block == nil {
        return nil, errors.New("failed to decode PEM block containing private key")
    }
    pub,err := x509.ParsePKIXPublicKey(block.Bytes)
    if err != nil {
        return nil, err
    }
    return pub.(*rsa.PublicKey), err
}

// VerifyWithPublicKey 公钥验签
func VerifyWithPublicKey(signData string, srcData []byte, publicKey string) error {
    defer GetTimer("公钥验签")()
    key, err := decodePublicKey(publicKey)
    if err != nil {
        return err
    }

    bytes, err := base64.StdEncoding.DecodeString(signData)
    if err != nil {
        return err
    }
    hashed := sha256.Sum256(srcData)
    err = rsa.VerifyPKCS1v15(key, crypto.SHA256, hashed[:], bytes)
    if err != nil {
        return err
    }
    return nil
}

//  DecryptWithPrivateKey私钥解密
func DecryptWithPrivateKey(privateKey string, encryptData string) ([]byte, error) {
    defer GetTimer("私钥解密")()
    key, err := decodePrivateKey(privateKey)
    if err != nil {
        return nil, err
    }
    encryptBytes, err := base64.StdEncoding.DecodeString(encryptData)
    if err != nil {
        return nil, err
    }
    return rsa.DecryptPKCS1v15(rand.Reader, key, encryptBytes)
}

//EncryptWithPublicKey 公钥加密
func EncryptWithPublicKey(publicKey string, bs []byte) (string, error) {
    defer GetTimer("公钥加密")()
    key, err := decodePublicKey(publicKey)
    if err != nil {
        return "", err
    }
    encryptBytes, err := rsa.EncryptPKCS1v15(rand.Reader, key, bs)
    if err != nil {
        return "", err
    }
    return base64.StdEncoding.EncodeToString(encryptBytes), nil

}
GenRsaKeys(int)参数是生成私钥字节大小,一般是1024或者2048,第一个返回值是cs1版本的私钥,第二个参数是公钥,第三个参数是pkcs8的私钥,java语言只能使用
pkcs8的私钥,cs1的会报错,另外java使用公钥私钥都要去掉开头和结尾的block type,不然会报错。这个函数生成的公私钥下面命令生成的等价
//生成cs1私钥
openssl genrsa -out rsa_private_key.pem 2048
//生成公钥
openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
//生成pkcs8私钥
openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform pem -nocrypt -out private_pkcs8.pem

 java版本的有公钥加密,pkcs8私钥解密,私钥加签,公钥验签

package com.zhqn.rsa.util;


import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Base64;

/**
 * Date:     2022/1/27 18:10
 * Description:
 *
 * @author zhouquan3
 */
public class CryptoUtils {

    public static final String RSA_ALGORITHM = "rsa";


    /**
     * 非对称加密
     *
     * @param src       待加密字符串
     * @param publicKey 公钥
     * @return 解密后的字符串
     */
    public static String encryptWithPublicKey(String src, String publicKey) {
        try {

            byte[] publicKeyBytes = parseKey(publicKey);
            KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
            PublicKey key = keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyBytes));
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] encodeBytes = cipher.doFinal(src.getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(encodeBytes);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 去掉公钥或者私钥blockType
     * @param key 私钥或者公钥
     * @return bytes
     */
    private static byte[] parseKey(String key) {
        String newKey = Arrays.stream(key.split("\n")).filter(line -> line.length() > 0 && line.charAt(0) != '-').reduce(String::concat).orElse("");
        return Base64.getDecoder().decode(newKey.getBytes());
    }


    /**
     * 非对称解密
     *
     * @param src        待解密字符串
     * @param privateKey 符合pkcs8私钥
     * @return 解密后的字符串
     */
    public static String decryptWithPkcs8(String src, String privateKey) {
        try {
            byte[] srcBytes = Base64.getDecoder().decode(src);
            byte[] privateKeyBytes = parseKey(privateKey);
            KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
            PrivateKey key = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes));
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, key);
            byte[] decryptBytes = cipher.doFinal(srcBytes);
            return new String(decryptBytes);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static PublicKey getPublicKey(String publicKey) {
        byte[] keyBytes = parseKey(publicKey);
        try {
            KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
            return keyFactory.generatePublic(new X509EncodedKeySpec(keyBytes));
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 用公钥验签
     * @param sign 签名
     * @param publicKey 公钥
     * @param plain 原文
     * @return true 通过 false 未通过
     */
    public static boolean verifySignWithPublicKey(String publicKey, String sign, String plain) {
        try {
            Signature signature = Signature.getInstance("SHA256WithRSA");
            signature.initVerify(getPublicKey(publicKey));
            signature.update(plain.getBytes(StandardCharsets.UTF_8));
            return signature.verify(Base64.getDecoder().decode(sign));
        } catch (Exception e ) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 用pkcs8格式的私钥加签名
     * @param privateKey 私钥
     * @param plain 原文
     * @return base64
     */
    public static String signWithPkcs8(String privateKey, String plain) {
        try {
            Signature signature = Signature.getInstance("SHA256WithRSA");
            signature.initSign(getPrivateKey(privateKey));
            signature.update(plain.getBytes());
            byte[] bytes = signature.sign();
            return Base64.getEncoder().encodeToString(bytes);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static PrivateKey getPrivateKey(String privateKey) {
        byte[] privateKeyBytes = parseKey(privateKey);
        KeyFactory keyFactory = null;
        try {
            keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
            return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }
}

java加签流程:signWithPkcs8(pkcs8私钥,明文)得到签名sign,golang调用VerifyWithPublicKey(签名,原文,公钥),验证通过

golang加签流程: SignWithPrivateKey(cs1版本的私钥,明文)得到签名sign,java调用verifySignWithPublicKey(公钥,签名,原文)

java加密流程: encryptWithPublicKey(公钥,原文)得到密文,golang调用DecryptWithPrivateKey(cs1版本的私钥,密文)得到原文

golang加密流程:EncryptWithPublicKey(公钥,原文)得到密文, java调用decryptWithPkcs8(密文,pkcs8密钥)得到原文

以上流程都充分测试,未发现问题,可以放心使用

 

posted @ 2022-01-28 18:03  风的低吟  阅读(1136)  评论(0编辑  收藏  举报