java数字签名

RSA非对称加密算法在作加解密的时候用公钥加密,私钥解密;在作数字签名的时候用私钥签名,公钥验证签名。下面就写一个java数字签名的工具类

package cn.cjc.sign;

import org.apache.commons.codec.binary.Base64;
import org.junit.Test;

import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.*;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * java数字签名和验签工具类
 *
 * @author chenjc
 * @since 2017-06-24
 */
public class SignAndVerifyUtil {

    //生成的公钥
    private String pubKeyStr = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC9ZdB9JvyoO8EiDPomoO23Bqb4uUxqNRYwIe+Yr6iNgAAznhVPzcZbeiAF6CFuvX4fZhJaaPoiuK6on6zRaa7YVzbzAxcHIRC+oshXYiBDH4qRRDh2IE4iUclP4p9uAPjrJGkmfKPO4ZCj/JeDSxBmPv7oCz3bWvBXn44/APbC9wIDAQAB";

    //生成的私钥
    private String priKeyStr = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAL1l0H0m/Kg7wSIM+iag7bcGpvi5TGo1FjAh75ivqI2AADOeFU/Nxlt6IAXoIW69fh9mElpo+iK4rqifrNFprthXNvMDFwchEL6iyFdiIEMfipFEOHYgTiJRyU/in24A+OskaSZ8o87hkKP8l4NLEGY+/ugLPdta8Fefjj8A9sL3AgMBAAECgYEAoqPJ048lK/qUMP9f2MgdGiyWOcQ1gIax1QdvTniZj1k50xmPR4Z3LZrD4Q6jlwsWQTRP0l+PXT2mjpr/tpzATQDDf5TH0ZOGzeadD57Pp0+lmEN/4OiTyhAz09ZsrDq39QVvzfAPLHuBAzduHU1eefiiyHYIz3yZ/I9I7+aAS1ECQQDjvEdGaQI80wWJEjwGFPDE/Tjfx1jo4ODd2ZumSbKM7PK7N3KG2vPsi4kkj1T6GXx9dNXIsqiAuIthALHGC+GDAkEA1OdzTYI4n8B+81w2JMwXmEtHOqfOvzBAsqNdeEb7Xgw1RKUcLL9vzSf5GThQQMWIqQ3UByqZ/I4X4HUxF1zifQJBAJWNqUjl4OBMvA/d96kOy2ax3E2ovgyA0WsfYoX7U9QULvsfWIiS9SjcIX3u2qE7Z3OD7HjWSq3tgyp6qEQkvT0CQHEIOFUML9fQsRWu/SfoGxbF0Jk5gjBLA+5TgUpcFRRHUviQ2DaBpG+9KyjSlvjsZrOqHcl4Oqy1G8QVM+z9aVkCQQDFxF26mh/H3I0ZMBZHLHL0/mBlkKEPcf0POwOFrw92579LkyLt0zX+gDmH6ANUewhEEutQf13KAIe4+8Yyu2QS";

    //待签名数据
    private String data = "你好,我是007!";

    //已签名数据
    private String signedData = "n%2F3uUg1Fah32d6f1vIKk3PlUPFPC2MhIeQ%2BmPEXL9jA9dWNsWqoYM6vlMkzztOkNDgPa0NhLJ7suJKeJuos%2FS9vMA0%2BQv6yx6Mxn1Iz4oLZUZfvoVbozbGcvp%2BB2fzFVeQNNcppt2QgFMpvMLJqyf%2FmqsVuqTgzcSW8ZFxiA3Zc%3D";

    /**
     * 生成公钥和私钥
     */
    @Test
    public void createKeyPair() throws NoSuchAlgorithmException {
        KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA");
        keygen.initialize(1024);
        KeyPair keys = keygen.generateKeyPair();
        PublicKey pubKey = keys.getPublic();
        PrivateKey priKey = keys.getPrivate();
        // 获取base64编码的公钥
        System.out.println("pubKeyStr=" + Base64.encodeBase64String(pubKey.getEncoded()));
        // 获取base64编码的私钥
        System.out.println("priKeyStr=" + Base64.encodeBase64String(priKey.getEncoded()));
    }


    /**
     * 私钥签名
     */
    @Test
    public void sign() throws Exception {
        KeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(priKeyStr));
        KeyFactory factory = KeyFactory.getInstance("RSA");
        PrivateKey key = factory.generatePrivate(keySpec);
        Signature signature = Signature.getInstance("SHA1withRSA");
        signature.initSign(key);
        signature.update(data.getBytes("utf-8"));//使用UTF-8编码
        byte[] signed = signature.sign();//签名后的字节流数据
        String base64Encode = Base64.encodeBase64String(signed);//将字节流数据编码成字符串,以方便传输
        String urlEncode = URLEncoder.encode(base64Encode, "utf-8");//由于BASE64编码可能会产生“+”、“/”、“=”等符号,不利于HTTP传输,所以对BASE64编码再进行一次URL编码
        System.out.println("signedData=" + urlEncode);
    }

    /**
     * 公钥验签
     */
    @Test
    public void verify() throws Exception {
        KeySpec keySpec = new X509EncodedKeySpec(Base64.decodeBase64(pubKeyStr));
        KeyFactory factory = KeyFactory.getInstance("RSA");
        PublicKey key = factory.generatePublic(keySpec);
        Signature signature = Signature.getInstance("SHA1withRSA");
        signature.initVerify(key);
        signature.update(data.getBytes("utf-8"));//使用UTF-8编码
        String urlDecode = URLDecoder.decode(signedData, "utf-8");
        byte[] base64Decode = Base64.decodeBase64(urlDecode);
        if (signature.verify(base64Decode)) {//验证签名
            System.out.println("签名有效!");
        } else {
            System.out.println("签名无效!");
        }
    }
}

如果签名的一方是java应用,验签的一方是C#应用,则通过createKeyPair方法产生的公钥不能直接给C#应用对接,对接前需要先把java公钥转换成c#格式的公钥。详见各种密钥转换工具方法

package cn.cjc.sign;

import org.apache.commons.codec.binary.Base64;

import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.*;

public class KeyConvertUtil {

    /**
     * JAVA字节流格式的公钥转换成C#兼容的xml格式
     *
     * @param encodedPublicKey java公钥
     * @return c#公钥
     * @throws Exception
     */
    public static String publicKey2Xml(byte[] encodedPublicKey)
            throws Exception {
        KeySpec keySpec = new X509EncodedKeySpec(encodedPublicKey);
        KeyFactory factory = KeyFactory.getInstance("RSA");
        RSAPublicKey publicKey = (RSAPublicKey) factory.generatePublic(keySpec);
        StringBuffer sb = new StringBuffer(1024);
        sb.append("<RSAKeyValue>");
        sb.append("<Modulus>"
                + Base64.encodeBase64String(removeMSZero(publicKey.getModulus()
                .toByteArray())) + "</Modulus>");
        sb.append("<Exponent>"
                + Base64.encodeBase64String(removeMSZero(publicKey.getPublicExponent()
                .toByteArray())) + "</Exponent>");
        sb.append("</RSAKeyValue>");
        return sb.toString();
    }

    /**
     * JAVA字节流格式的私钥转换成C#兼容的xml格式
     *
     * @param encodedPrivateKey java私钥
     * @return c#私钥
     * @throws Exception
     */
    public static String privateKey2Xml(byte[] encodedPrivateKey) throws Exception {
        KeySpec keySpec = new PKCS8EncodedKeySpec(encodedPrivateKey);
        KeyFactory factory = KeyFactory.getInstance("RSA");
        RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey) factory.generatePrivate(keySpec);
        StringBuffer sb = new StringBuffer(1024);
        sb.append("<RSAKeyValue>");
        sb.append("<Modulus>"
                + Base64.encodeBase64String(removeMSZero(privateKey.getModulus()
                .toByteArray())) + "</Modulus>");
        sb.append("<Exponent>"
                + Base64.encodeBase64String(removeMSZero(privateKey.getPublicExponent()
                .toByteArray())) + "</Exponent>");
        sb.append("<P>"
                + Base64.encodeBase64String(removeMSZero(privateKey.getPrimeP()
                .toByteArray())) + "</P>");
        sb.append("<Q>"
                + Base64.encodeBase64String(removeMSZero(privateKey.getPrimeQ()
                .toByteArray())) + "</Q>");
        sb.append("<DP>"
                + Base64.encodeBase64String(removeMSZero(privateKey.getPrimeExponentP()
                .toByteArray())) + "</DP>");
        sb.append("<DQ>"
                + Base64.encodeBase64String(removeMSZero(privateKey.getPrimeExponentQ()
                .toByteArray())) + "</DQ>");
        sb.append("<InverseQ>"
                + Base64.encodeBase64String(removeMSZero(privateKey.getCrtCoefficient()
                .toByteArray())) + "</InverseQ>");
        sb.append("<D>"
                + Base64.encodeBase64String(removeMSZero(privateKey
                .getPrivateExponent().toByteArray())) + "</D>");
        sb.append("</RSAKeyValue>");
        return sb.toString();
    }

    private static byte[] removeMSZero(byte[] data) {
        byte[] data1;
        int len = data.length;
        if (data[0] == 0) {
            data1 = new byte[data.length - 1];
            System.arraycopy(data, 1, data1, 0, len - 1);
        } else
            data1 = data;
        return data1;
    }

    private static String getMiddleString(String source, String strHead,
                                          String strTail) {
        try {
            int indexHead, indexTail;
            if (strHead == null || strHead.isEmpty()) {
                indexHead = 0;
            } else {
                indexHead = source.indexOf(strHead);
            }
            if (strTail == null || strTail.isEmpty()) {
                indexTail = source.length();
            } else {
                indexTail = source.indexOf(strTail,
                        indexHead + strHead.length());
            }
            if (indexTail < 0) {
                indexTail = source.length();
            }
            String rtnStr = "";
            if ((indexHead >= 0) && (indexTail >= 0)) {
                rtnStr = source.substring(indexHead + strHead.length(),
                        indexTail);
            }
            return rtnStr;
        } catch (Exception ex) {
            return "";
        }
    }

    /**
     * C#兼容的xml格式公钥转换成JAVA公钥
     *
     * @param publicKeyXml c#公钥
     * @return java公钥
     */
    public static PublicKey xml2PublicKey(String publicKeyXml) {
        publicKeyXml = publicKeyXml.replaceAll("\r", "").replaceAll("\n", "");
        BigInteger modulus = new BigInteger(1,
                Base64.decodeBase64(getMiddleString(publicKeyXml, "<Modulus>",
                        "</Modulus>")));
        BigInteger publicExponent = new BigInteger(1,
                Base64.decodeBase64(getMiddleString(publicKeyXml, "<Exponent>",
                        "</Exponent>")));
        RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, publicExponent);
        try {
            KeyFactory factory = KeyFactory.getInstance("RSA");
            return factory.generatePublic(keySpec);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * C#兼容的xml格式私钥转换成JAVA私钥
     *
     * @param privateKeyXml c#私钥
     * @return java私钥
     */
    public static PrivateKey xml2PrivateKey(String privateKeyXml) {
        privateKeyXml = privateKeyXml.replaceAll("\r", "").replaceAll("\n", "");
        BigInteger modulus = new BigInteger(1,
                Base64.decodeBase64(getMiddleString(privateKeyXml, "<Modulus>",
                        "</Modulus>")));
        BigInteger publicExponent = new BigInteger(1,
                Base64.decodeBase64(getMiddleString(privateKeyXml, "<Exponent>",
                        "</Exponent>")));
        BigInteger privateExponent = new BigInteger(1,
                Base64.decodeBase64(getMiddleString(privateKeyXml, "<D>", "</D>")));
        BigInteger primeP = new BigInteger(1,
                Base64.decodeBase64(getMiddleString(privateKeyXml, "<P>", "</P>")));
        BigInteger primeQ = new BigInteger(1,
                Base64.decodeBase64(getMiddleString(privateKeyXml, "<Q>", "</Q>")));
        BigInteger primeExponentP = new BigInteger(1,
                Base64.decodeBase64(getMiddleString(privateKeyXml, "<DP>",
                        "</DP>")));
        BigInteger primeExponentQ = new BigInteger(1,
                Base64.decodeBase64(getMiddleString(privateKeyXml, "<DQ>",
                        "</DQ>")));
        BigInteger crtCoefficient = new BigInteger(1,
                Base64.decodeBase64(getMiddleString(privateKeyXml, "<InverseQ>",
                        "</InverseQ>")));
        RSAPrivateCrtKeySpec keySpec = new RSAPrivateCrtKeySpec(modulus,
                publicExponent, privateExponent, primeP, primeQ,
                primeExponentP, primeExponentQ, crtCoefficient);
        try {
            KeyFactory factory = KeyFactory.getInstance("RSA");
            return factory.generatePrivate(keySpec);
        } catch (Exception e) {
            return null;
        }
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值