數(shù)字簽名(digital signature)是一種電子簽名,也可以表示為一種數(shù)學算法,通常用于驗證消息(例如,電子郵件、信用卡交易或數(shù)字文檔)的真實性和完整性。
數(shù)字簽名并沒有創(chuàng)建新的算法,主要是結(jié)合使用信息摘要算法(MD,SHA)和非對稱加密算法(RSA,DSA)。信息摘要算法用來驗證數(shù)據(jù)完整性,非對稱加密算法用來進行身份驗證。
消息發(fā)送方用摘要算法和私鑰加密生成簽名,接收方用公鑰解密驗證簽名,再用相同的摘要算法驗證數(shù)據(jù)完整性。
一個典型的消息發(fā)送過程如下:
2 數(shù)字簽名特點數(shù)字簽名具有許多重要的應用,例如在電子政務活動中的電子公文、網(wǎng)上報稅、網(wǎng)上投票,在電子商務活動中的電子訂單、電子賬單、電子收據(jù)、電子合同、電子現(xiàn)金等電子文檔都需要通過數(shù)字簽名來保證文檔的真實性和有效性;甚至于人們?nèi)粘J褂妙l繁的電子郵件,當涉及重要內(nèi)容時,也需要通過數(shù)字簽名技術來對郵件的發(fā)送者進行確認和保證郵件內(nèi)容未被篡改,并且郵件的發(fā)送者也不能對發(fā)出的郵件進行否認。由此可見,數(shù)字簽名技術早已深入應用到國家的政治、軍事、經(jīng)濟和人們生活中的各個方面,并將在國家數(shù)字 化進程中發(fā)揮越來越重要的作用。
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
下面的代碼將JDK提供的幾種數(shù)字簽名算法用枚枚舉類進行了封裝。
首先使用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< readCount) {byteBuffer.flip();
int length = bytes.length;
bytes = Arrays.copyOf(bytes, bytes.length + readCount);
System.arraycopy(byteBuffer.array(), 0, bytes, length, readCount);
byteBuffer.clear();
readCount = keyFileChannel.read(byteBuffer);
}
String keyStr = new String(bytes);
return keyStr;
}
}
public static PublicKey getPublicKeyFromCA(String certificationType) throws Exception {CertificateFactory certificateFactory = CertificateFactory.getInstance(certificationType);
try (FileInputStream in = new FileInputStream(certificatePath.toFile())) {Certificate certificate = certificateFactory.generateCertificate(in);
return certificate.getPublicKey();
}
}
public static PublicKey getPublicKeyFromKeyStore(String alias, String password, String keyStoreType) throws Exception {try (FileInputStream is = new FileInputStream(keyStorePath.toFile())) {KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(is, password.toCharArray());
return keyStore.getCertificate(alias).getPublicKey();
}
}
public static PrivateKey getPrivateKeyFromKeyStore(String alias, String password, String keyStoreType) throws Exception {try (FileInputStream is = new FileInputStream(keyStorePath.toFile())) {KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(is, password.toCharArray());
return (PrivateKey) keyStore.getKey(alias, password.toCharArray());
}
}
}
你是否還在尋找穩(wěn)定的海外服務器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調(diào)度確保服務器高可用性,企業(yè)級服務器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧
新聞標題:Java加解密(七)數(shù)字簽名-創(chuàng)新互聯(lián)
轉(zhuǎn)載來源:http://aaarwkj.com/article6/ccheig.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供營銷型網(wǎng)站建設、小程序開發(fā)、定制網(wǎng)站、品牌網(wǎng)站建設、面包屑導航、定制開發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容