Java加解密(七)数字签名

您所在的位置:网站首页 java数字签名验证 Java加解密(七)数字签名

Java加解密(七)数字签名

2024-07-16 16:34| 来源: 网络整理| 查看: 265

目录 数字签名1 定义2 数字签名特点3 应用场景4 JDK支持的信息摘要算法5 Bouncy Castle 支持的信息摘要算法6 算法调用示例

数字签名 1 定义

数字签名(digital signature)是一种电子签名,也可以表示为一种数学算法,通常用于验证消息(例如,电子邮件、信用卡交易或数字文档)的真实性和完整性。

数字签名并没有创建新的算法,主要是结合使用信息摘要算法(MD,SHA)和非对称加密算法(RSA,DSA)。信息摘要算法用来验证数据完整性,非对称加密算法用来进行身份验证。

消息发送方用摘要算法和私钥加密生成签名,接收方用公钥解密验证签名,再用相同的摘要算法验证数据完整性。

一个典型的消息发送过程如下:

在这里插入图片描述

2 数字签名特点 防篡改:数据不会被修改,MAC算法也有这个特点。防抵赖:消息签署者不能抵赖。防伪造:发送的消息不能够伪造,MAC算法也有这个特点。 3 应用场景

数字签名具有许多重要的应用,例如在电子政务活动中的电子公文、网上报税、网上投票,在电子商务活动中的电子订单、电子账单、电子收据、电子合同、电子现金等电子文档都需要通过数字签名来保证文档的真实性和有效性;甚至于人们日常使用频繁的电子邮件,当涉及重要内容时,也需要通过数字签名技术来对邮件的发送者进行确认和保证邮件内容未被篡改,并且邮件的发送者也不能对发出的邮件进行否认。由此可见,数字签名技术早已深入应用到国家的政治、军事、经济和人们生活中的各个方面,并将在国家数字 化进程中发挥越来越重要的作用。

4 JDK支持的信息摘要算法

JDK8原生算法列表,可参第一篇博文: https://blog.csdn.net/yunyun1886358/article/details/128592503#311_JDK_Provider_63

5 Bouncy Castle 支持的信息摘要算法

Bouncy Castle算法列表,可参第一篇博文: https://editor.csdn.net/md/?articleId=128592503#323_Bouncy_Castle_Provider_568

6 算法调用示例

下面的代码将JDK提供的几种数字签名算法用枚枚举类进行了封装。

首先使用ktool生成密钥库,并导出公钥证书:

keytool -genkeypair -alias testing-keys -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore testing-keystore.p12 -validity 36500 keytool -list -v -keystore testing-keystore.p12 keytool -export -keystore testing-keystore.p12 -alias testing-keys -file testing-ca.cer -rfc package com.qupeng.crypto.algorithm.oop; import org.junit.Assert; import org.junit.Test; public class DigitalSignatureAlgorithmTest { @Test public void sign() throws Exception { String signatureStr = DigitalSignatureAlgorithm.MD2withRSA.signByPrivateKeyFromKeyStore("1234567890"); Assert.assertTrue(DigitalSignatureAlgorithm.MD2withRSA.verifySignatureByPublicKeyFromCA("1234567890", signatureStr)); signatureStr = DigitalSignatureAlgorithm.MD5withRSA.signByPrivateKeyFromKeyStore("1234567890"); Assert.assertTrue(DigitalSignatureAlgorithm.MD5withRSA.verifySignatureByPublicKeyFromCA("1234567890", signatureStr)); signatureStr = DigitalSignatureAlgorithm.SHA1withRSA.signByPrivateKeyFromKeyStore("1234567890"); Assert.assertTrue(DigitalSignatureAlgorithm.SHA1withRSA.verifySignatureByPublicKeyFromCA("1234567890", signatureStr)); signatureStr = DigitalSignatureAlgorithm.SHA1withDSA.signByPrivateKeyFromFile("1234567890"); Assert.assertTrue(DigitalSignatureAlgorithm.SHA1withDSA.verifySignatureByPublicKeyFromFile("1234567890", signatureStr)); signatureStr = DigitalSignatureAlgorithm.SHA256withRSA.signByPrivateKeyFromKeyStore("1234567890"); Assert.assertTrue(DigitalSignatureAlgorithm.SHA256withRSA.verifySignatureByPublicKeyFromCA("1234567890", signatureStr)); signatureStr = DigitalSignatureAlgorithm.SHA224withRSA.signByPrivateKeyFromKeyStore("1234567890"); Assert.assertTrue(DigitalSignatureAlgorithm.SHA224withRSA.verifySignatureByPublicKeyFromCA("1234567890", signatureStr)); signatureStr = DigitalSignatureAlgorithm.SHA384withRSA.signByPrivateKeyFromKeyStore("1234567890"); Assert.assertTrue(DigitalSignatureAlgorithm.SHA384withRSA.verifySignatureByPublicKeyFromCA("1234567890", signatureStr)); signatureStr = DigitalSignatureAlgorithm.SHA512withRSA.signByPrivateKeyFromKeyStore("1234567890"); Assert.assertTrue(DigitalSignatureAlgorithm.SHA512withRSA.verifySignatureByPublicKeyFromCA("1234567890", signatureStr)); signatureStr = DigitalSignatureAlgorithm.RIPEMD128withRSA.signByPrivateKeyFromKeyStore("1234567890"); Assert.assertTrue(DigitalSignatureAlgorithm.RIPEMD128withRSA.verifySignatureByPublicKeyFromCA("1234567890", signatureStr)); signatureStr = DigitalSignatureAlgorithm.RIPEMD160withRSA.signByPrivateKeyFromKeyStore("1234567890"); Assert.assertTrue(DigitalSignatureAlgorithm.RIPEMD160withRSA.verifySignatureByPublicKeyFromCA("1234567890", signatureStr)); } } package com.qupeng.crypto.algorithm.oop; import com.qupeng.crypto.util.CryptoUtils; import org.bouncycastle.jce.provider.BouncyCastleProvider; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Security; import java.security.Signature; import java.util.Base64; public enum DigitalSignatureAlgorithm { MD2withRSA("MD2withRSA", "RSA", "default"), MD5withRSA("MD5withRSA", "RSA", "default"), SHA1withRSA("SHA1withRSA", "RSA", "default"), SHA1withDSA("SHA1withDSA", "DSA", "default"), SHA256withRSA("SHA256withRSA", "RSA", "default"), SHA224withRSA("SHA224withRSA", "RSA", "BC"), SHA384withRSA("SHA384withRSA", "RSA", "BC"), SHA512withRSA("SHA512withRSA", "RSA", "BC"), RIPEMD128withRSA("RIPEMD128withRSA", "RSA", "BC"), RIPEMD160withRSA("RIPEMD160withRSA", "RSA", "BC"); static { Security.addProvider(new BouncyCastleProvider()); } private String algorithm; private String encryptionAlgorithm; private String providerName; DigitalSignatureAlgorithm(String algorithm, String encryptionAlgorithm, String providerName) { this.algorithm = algorithm; this.encryptionAlgorithm = encryptionAlgorithm; this.providerName = providerName; } public String signByPrivateKeyFromKeyStore(String plainText) throws Exception { PrivateKey privateKey = CryptoUtils.getPrivateKeyFromKeyStore("testing-keys", "123456", "PKCS12"); return sign(plainText, privateKey); } public String signByPrivateKeyFromFile(String plainText) throws Exception { String privateKeyStr = CryptoUtils.readPrivateKeyFromFile(this.encryptionAlgorithm); PrivateKey privateKey = CryptoUtils.getPrivateKeyByStr(this.encryptionAlgorithm, privateKeyStr); return sign(plainText, privateKey); } public String sign(String plainText, PrivateKey privateKey) throws Exception { Signature signature; if ("default".equals(providerName)) { signature = Signature.getInstance(this.algorithm); } else { signature = Signature.getInstance(this.algorithm, providerName); } signature.initSign(privateKey); signature.update(plainText.getBytes()); byte[] signatureBytes = signature.sign(); String cipherText = Base64.getEncoder().encodeToString(signatureBytes); System.out.println(String.format("%s plain text: %s -> digital signature: %s", this.algorithm, plainText, cipherText)); return cipherText; } public boolean verifySignatureByPublicKeyFromCA(String plainText, String signatureStr) throws Exception { PublicKey publicKey = CryptoUtils.getPublicKeyFromCA("X.509"); return verifySignature(plainText, signatureStr, publicKey); } public boolean verifySignatureByPublicKeyFromFile(String plainText, String signatureStr) throws Exception { String publicKeyStr = CryptoUtils.readPublicKeyFromFile(this.encryptionAlgorithm); PublicKey publicKey = CryptoUtils.getPublicKeyByStr(this.encryptionAlgorithm, publicKeyStr); return verifySignature(plainText, signatureStr, publicKey); } public boolean verifySignature(String plainText, String signatureStr, PublicKey publicKey) throws Exception { Signature signature; if ("default".equals(providerName)) { signature = Signature.getInstance(this.algorithm); } else { signature = Signature.getInstance(this.algorithm, providerName); } signature.initVerify(publicKey); signature.update(plainText.getBytes()); boolean verifyResult = signature.verify(Base64.getDecoder().decode(signatureStr)); System.out.println(String.format("Signature: %s is %s", signatureStr, verifyResult ? "valid" : "invalid")); return verifyResult; } } package com.qupeng.crypto.algorithm.oop; import java.io.FileInputStream; import java.io.IOException; import java.net.URISyntaxException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.security.KeyStore; import java.security.PrivateKey; import java.security.PublicKey; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.util.Arrays; public class CryptoUtils { public final static Path RSA_PUBLIC_KEY_FILE_PATH = Paths.get("C:", "Users", "Administrator", "IdeaProjects", "javasedemo", "src", "main", "resources", "rsa-public-key.txt"); public final static Path RSA_PRIVATE_KEY_FILE_PATH = Paths.get("C:", "Users", "Administrator", "IdeaProjects", "javasedemo", "src", "main", "resources", "rsa-private-key.txt"); public final static Path DSA_PUBLIC_KEY_FILE_PATH = Paths.get("C:", "Users", "Administrator", "IdeaProjects", "javasedemo", "src", "main", "resources", "dsa-public-key.txt"); public final static Path DSA_PRIVATE_KEY_FILE_PATH = Paths.get("C:", "Users", "Administrator", "IdeaProjects", "javasedemo", "src", "main", "resources", "dsa-private-key.txt"); private static Path keyStorePath; private static Path certificatePath; static { try { keyStorePath = Paths.get(DigitalSignatureAlgorithm.class.getClassLoader().getResource("testing-keystore.p12").toURI()); certificatePath = Paths.get(DigitalSignatureAlgorithm.class.getClassLoader().getResource("testing-ca.cer").toURI()); } catch (URISyntaxException e) { e.printStackTrace(); } } public static String readPublicKeyFromFile(String algorithm) throws IOException { return readKeyStrFromFile("DSA".equalsIgnoreCase(algorithm) ? DSA_PUBLIC_KEY_FILE_PATH : RSA_PUBLIC_KEY_FILE_PATH); } public static String readPrivateKeyFromFile(String algorithm) throws IOException { return readKeyStrFromFile("DSA".equalsIgnoreCase(algorithm) ? DSA_PRIVATE_KEY_FILE_PATH : RSA_PRIVATE_KEY_FILE_PATH); } public static String readKeyStrFromFile(Path keyFilePath) throws IOException { try (FileChannel keyFileChannel = FileChannel.open(keyFilePath, StandardOpenOption.READ)) { byte[] bytes = new byte[0]; ByteBuffer byteBuffer = ByteBuffer.allocate(128); int readCount = keyFileChannel.read(byteBuffer); while (0


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3