您的位置 首页 java

Java,安全,数字签名的工作原理及加解密、签名和验签

数字签名的工作原理

1、Alice(密码学中常用A到Z开头的人名代替甲乙丙丁等,字母越靠后出现频率越低)生成一对密钥,一个是sk(signing key),是非公开的;另一个是vk(verification key),是公开的。

这一对密钥同时生成,并且在数学上是相互关联的,同时,根据vk无法推测出关于sk的任何信息。

2、数字签名算法接收两个输出:信息M和sk,生成一个数字签名Sm。

3、验证函数接收信息M、Sm以及vk作为输入,返回结果是yes或者no。这一步的目的是为了验证你看到的针对信息M的数字签名确实是由Alice的sk来签发的,用于确认信息与签名是否相符。

与手写签名不同,手写签名基本都是相似的,但是数字签名却受输入影响很大。对输入轻微的改变都会产生一个完全不同的数字签名。一般不会对信息直接进行数字签名,而是对信息的哈希值进行签名。由加密哈希函数的无碰撞性可知,这样和对原信息进行签名一样安全。

数字签名实现的具体原理:

1、将 报文 按双方约定的 HASH 算法计算得到一个固定位数的报文摘要。

在数学上保证,只要改动报文中任何一位,重新计算出的报文摘要值就会与原先的值不相符。这样就保证了报文的不可更改性。(详见参考资料的”公钥密码技术原理”章节)

2、将该报文摘要值用发送者的私人密钥加密,然后连同原报文和数字证书(包含公钥)一起发送给接收者而产生的报文即称数字签名。

3、接收方收到数字签名后,用同样的HASH算法对报文计算摘要值,然后与用发送者的公开密钥进行解密解开的报文摘要值相比较,如相等则说明报文确实来自所称的发送者。

4、同时通过证书颁发机构CA确认证书的有效性即可确认发送的真实身份。

代码案例(包含签名和验签代码块):

 import java.security.PublicKey;
import java.security. cert .X509Certificate;

public class CertificateCoderDemo {

    public static void main(String[] args) {
        String keyStorePath = "c:/server.jks";
        String alias = "server";
        String pwd = "123456";
        String cerPath = "c:/server.cer";
        // 1、根据keyStore路径获取证书
        try {
            X509Certificate x509 = (X509Certificate) CertificateCoder.getCertificate(keyStorePath, alias, pwd);
            System.out.println("证书内容:rn" + x509);
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 2、根据cert路径获取公钥
        try {
            PublicKey publicKey = CertificateCoder.getPublicKeyByCertificate(cerPath);
            System.out.println("公钥内容:rn" + publicKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 3、 私钥 加密公钥解密;
        String data = "[私钥加密公钥解密]";
        try {
             byte [] decryptData = CertificateCoder.encryptByPrivateKey(data.getBytes(), keyStorePath, alias, pwd);
            System.out.println("私钥加密内容:" + decryptData);
            byte[] encryptData = CertificateCoder.decryptByPublicKey(decryptData, cerPath);
            System.out.println("公钥加密内容:" + new String(decryptData));
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 4、公钥加密公钥解密;
        String text = "[公钥加密私钥解密]";
        try {
            byte[] decryptData = CertificateCoder.encryptByPublicKey(text.getBytes(), cerPath);
            System.out.println("公钥加密内容:" + decryptData);
            byte[] encryptData = CertificateCoder.decryptByPrivateKey(decryptData, keyStorePath, alias, pwd);
            System.out.println("私钥加密内容:" + new String(encryptData));
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 5、证书签名(私钥签名)
        String signData = "证书签名(私钥签名)";
        byte[] signedData = null;
        try {
            signedData = CertificateCoder.sign(signData.getBytes(), keyStorePath, pwd, alias);
            System.out.println("证书签名结果:" + signedData);
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 6、验签(公钥验签)
        try {
            boolean verifyResult = CertificateCoder.verify(signData.getBytes(), signedData, cerPath);
            System.out.println("证书验签结果:" + verifyResult);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}  
 import javax.crypto.Cipher;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

public class CertificateCoder {

    public static final String CERT_TYPE = "X.509";

    /**
     * 获取私匙
     *
     * @param keyStorePath
     * @param pwd
     * @param alias
     * @return PrivateKey 私匙
     * @throws Exception
     */    private static PrivateKey getPrivateKey(String keyStorePath, String pwd, String alias) throws Exception {
        KeyStore ks = getKeyStore(keyStorePath, pwd);
        return (PrivateKey) ks.getKey(alias, pwd.toCharArray());
    }


    /**
     * @param keyStorePath
     * @param pwd
     * @return keyStore 密匙库
     * @throws Exception
     */    private static KeyStore getKeyStore(String keyStorePath, String pwd) throws Exception {
        KeyStore ks = KeyStore. getInstance (KeyStore.getDefaultType());
        FileInputStream in = new FileInputStream(keyStorePath);
        ks.load(in, pwd.toCharArray());
        in. close ();
        return ks;
    }


    /**
     * @param certificatePath
     * @return Certificate 证书
     * @throws Exception
     */    private static Certificate getCertificate(String certificatePath) throws Exception {
        CertificateFactory factory = CertificateFactory.getInstance(CERT_TYPE);
        FileInputStream in = new FileInputStream(certificatePath);
        Certificate certificate = factory.generateCertificate(in);
        in.close();
        return certificate;

    }

    /**
     * 通过证书返回公匙
     *
     * @param certificatePath
     * @return Publickey 返回公匙
     * @throws Exception
     */    public static PublicKey getPublicKeyByCertificate(String certificatePath) throws Exception {
        Certificate certificate = getCertificate(certificatePath);
        return certificate.getPublicKey();
    }

    /**
     * @param keyStorePath
     * @param alias
     * @param pwd
     * @return Certificate 证书
     * @throws Exception
     */    public static Certificate getCertificate(String keyStorePath, String alias, String pwd) throws Exception {
        KeyStore ks = getKeyStore(keyStorePath, pwd);
        //获取证书
        return ks.getCertificate(alias);
    }

    /**
     * 私匙加密
     *
     * @param data
     * @param keyStorePath
     * @param alias
     * @param pwd
     * @return byte[] 被私匙加密的数据
     * @throws Exception
     */    public static byte[] encryptByPrivateKey(byte[] data, String keyStorePath, String alias, String pwd) throws Exception {
        PrivateKey privateKey = getPrivateKey(keyStorePath, pwd, alias);
        //对数据进行加密
        Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);
        return cipher.doFinal(data);
    }


    /**
     * 私匙解密
     *
     * @param data
     * @param keyStorePath
     * @param alias
     * @param pwd
     * @return byte[] 私匙解密的数据
     * @throws Exception
     */    public static byte[] decryptByPrivateKey(byte[] data, String keyStorePath, String alias, String pwd) throws Exception {
        PrivateKey privateKey = getPrivateKey(keyStorePath, pwd, alias);
        Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
        cipher.init(cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(data);
    }


    /**
     * 公匙加密
     *
     * @param data
     * @param cerPath
     * @return byte[] 被公匙加密的数据
     * @throws Exception
     */    public static byte[] encryptByPublicKey(byte[] data, String cerPath) throws Exception {
        //获取公匙
        PublicKey publicKey = getPublicKeyByCertificate(cerPath);
        System.out.println(publicKey.getAlgorithm());
        Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(data);
    }

    /**
     * 公匙解密
     *
     * @param data
     * @param cerPath
     * @return
     * @throws Exception
     */    public static byte[] decryptByPublicKey(byte[] data, String cerPath) throws Exception {
        PublicKey publicKey = getPublicKeyByCertificate(cerPath);
        Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicKey);
        return cipher.doFinal(data);
    }

    /**
     * 签名
     *
     * @param sign
     * @param keyStorePath
     * @param pwd
     * @param alias
     * @return
     * @throws Exception
     */    public static byte[] sign(byte[] sign, String keyStorePath, String pwd, String alias) throws Exception {
        //获取证书
        X509Certificate x509 = (X509Certificate) getCertificate(keyStorePath, alias, pwd);
        //构建签名,由证书指定签名算法
        Signature sa = Signature.getInstance(x509.getSigAlgName());
        //获取私匙
        PrivateKey privateKey = getPrivateKey(keyStorePath, pwd, alias);
        sa.initSign(privateKey);
        sa.update(sign);
        return sa.sign();
    }

    /**
     * 验证签名
     *
     * @param data
     * @param sign
     * @param cerPath
     * @return
     * @throws Exception
     */    public static boolean verify(byte[] data, byte[] sign, String cerPath) throws Exception {
        X509Certificate x509 = (X509Certificate) getCertificate(cerPath);
        Signature sa = Signature.getInstance(x509.getSigAlgName());
        sa.initVerify(x509);
        sa.update(data);
        return sa.verify(sign);
    }
}  

文章来源:智云一二三科技

文章标题:Java,安全,数字签名的工作原理及加解密、签名和验签

文章地址:https://www.zhihuclub.com/188200.shtml

关于作者: 智云科技

热门文章

网站地图