java結(jié)合keytool如何實(shí)現(xiàn)非對稱簽名和驗(yàn)證詳解
前言
本文主要介紹了關(guān)于java結(jié)合keytool實(shí)現(xiàn)非對稱簽名和驗(yàn)證的相關(guān)內(nèi)容,分享出來供大家參考學(xué)習(xí),下面話不多說了,來一起看看詳細(xì)的介紹吧
參考 還有姊妹篇:java結(jié)合keytool實(shí)現(xiàn)非對稱加密和解密
keytool的使用
keytool是JDK自帶的一個(gè)密鑰庫管理工具。這里只用到了keytool的部分功能,包括生成密鑰對,導(dǎo)出公鑰等。keytool生成的公鑰/私鑰對存放到一個(gè)到了一個(gè)文件中,這個(gè)文件有密碼保護(hù),通稱為keystore。
生成密鑰對
$ keytool -genkey -alias signLegal -keystore examplestanstore -validity 1800
生成別名為signLegal的密鑰對,存放在密鑰庫examplestanstore中,證書的有效期是1800天(默認(rèn)是90天)。
輸入一系列的參數(shù)。輸入的參數(shù)遵循了LDAP的風(fēng)格和標(biāo)準(zhǔn)??梢韵胂?,生成的密鑰對可以看成LDAP的一個(gè)條目。
命令執(zhí)行成功后會(huì)在當(dāng)前目錄下創(chuàng)建一個(gè)叫examplestanstore的文件。
查看密鑰對
$ keytool -list -keystore examplestanstore -v
列出了examplestanstore密鑰庫的中所有密鑰對。-v參數(shù)表示詳細(xì)信息,詳細(xì)信息中有證書的失效時(shí)間。
導(dǎo)出公鑰證書
$ keytool -export -keystore examplestanstore -alias signLegal -file StanSmith.cer
導(dǎo)出的公鑰存放在當(dāng)前目錄的StanSmith.cer文件中,是個(gè)二進(jìn)制文件。
java簽名和驗(yàn)證
參考了java安全官方教程。
在該官方教程中,GenSig.java類生成密鑰對,對輸入的文件進(jìn)行簽名,輸出了一個(gè)簽名結(jié)果文件sig和公鑰suepk。
VerSig.java類接受三個(gè)參數(shù):公鑰文件名(suepk)、簽名文件(sig)、被簽名的源文件名(hello.txt)。
該教程解釋了兩個(gè)類的原理,并附加有源碼。將源碼下載并編譯。創(chuàng)建一個(gè)hello.txt的文件作為被簽名的目標(biāo)文件,里面隨便放點(diǎn)字符串。然后執(zhí)行:
$ java GenSig hello.txt (生成文件sig和suepk) $ java VerSig suepk sig hello.txt signature verifies: true
在實(shí)際使用時(shí),密鑰對不可能每次在程序中重新生成。而keytool恰好可以生成并相對安全保存密鑰對。所以下面結(jié)合了keytool和java實(shí)現(xiàn)的功能。
結(jié)合keytool與java簽名/驗(yàn)證
密鑰對由keytool生成并保存到keystore中保護(hù)起來(keystore有密碼)。公鑰也從keystore中導(dǎo)出。GenSig.java類只需要從keystore中取得私鑰進(jìn)行簽名即可。
VerSig.java也要做適當(dāng)?shù)男薷?。貌似因?yàn)閺膋eystore中導(dǎo)出的是證書而不是公鑰,兩者的封裝格式估計(jì)有差異。
具體步驟
- 利用keytool -genkey生成密鑰對保存在keystore中(庫文件是examplestanstore)
- 利用`keytool -export'從keystore中導(dǎo)出公鑰證書(StanSmith.cer)
- 利用新類GenSig2.java生成簽名(文件名是sig),GenSig2.java會(huì)從keystore中取私鑰
- 將公鑰(StanSmith.cer)、簽名(sig)、被簽名文件(hello.txt)發(fā)給驗(yàn)證方
- 驗(yàn)證方利用VerSig2.java進(jìn)行驗(yàn)證
下面是GenSig2.java和VerSig2.java的源碼和執(zhí)行方式。
GenSig2.java
import java.io.*; import java.security.*; class GenSig2 { public static void main(String[] args) { if (args.length != 1) { System.out.println("Usage: java GenSig2 <nameOfFileToSign>"); } else try{ /*create key paire use keytool: $ keytool -genkey -alias signLegal -keystore examplestanstore -validity 1800*/ // read keystore file KeyStore ks = KeyStore.getInstance("JKS"); FileInputStream ksfis = new FileInputStream("examplestanstore"); BufferedInputStream ksbufin = new BufferedInputStream(ksfis); // open keystore and get private key // alias is 'signLeal', kpasswd/spasswd is 'vagrant' ks.load(ksbufin, "vagrant".toCharArray()); PrivateKey priv = (PrivateKey) ks.getKey("signLegal", "vagrant".toCharArray()); /* Create a Signature object and initialize it with the private key */ Signature dsa = Signature.getInstance("SHA1withDSA", "SUN"); dsa.initSign(priv); /* Update and sign the data */ FileInputStream fis = new FileInputStream(args[0]); BufferedInputStream bufin = new BufferedInputStream(fis); byte[] buffer = new byte[1024]; int len; while (bufin.available() != 0) { len = bufin.read(buffer); dsa.update(buffer, 0, len); }; bufin.close(); /* Now that all the data to be signed has been read in, generate a signature for it */ byte[] realSig = dsa.sign(); /* Save the signature in a file */ FileOutputStream sigfos = new FileOutputStream("sig"); sigfos.write(realSig); sigfos.close(); /* public key file can export from keystore use keytool: $ keytool -export -keystore examplestanstore -alias signLegal -file StanSmith.cer */ } catch (Exception e) { System.err.println("Caught exception " + e.toString()); } };
編譯后,這樣運(yùn)行:
$ java GenSig2 hello.txt
會(huì)生成簽名文件sig。
VerSig2.java
import java.io.*; import java.security.*; import java.security.spec.*; class VerSig2 { public static void main(String[] args) { /* Verify a DSA signature */ if (args.length != 3) { System.out.println("Usage: VerSig publickeyfile signaturefile datafile"); } else try{ /* import encoded public cert */ FileInputStream certfis = new FileInputStream(args[0]); java.security.cert.CertificateFactory cf = java.security.cert.CertificateFactory.getInstance("X.509"); java.security.cert.Certificate cert = cf.generateCertificate(certfis); PublicKey pubKey = cert.getPublicKey(); /* input the signature bytes */ FileInputStream sigfis = new FileInputStream(args[1]); byte[] sigToVerify = new byte[sigfis.available()]; sigfis.read(sigToVerify ); sigfis.close(); /* create a Signature object and initialize it with the public key */ Signature sig = Signature.getInstance("SHA1withDSA", "SUN"); sig.initVerify(pubKey); /* Update and verify the data */ FileInputStream datafis = new FileInputStream(args[2]); BufferedInputStream bufin = new BufferedInputStream(datafis); byte[] buffer = new byte[1024]; int len; while (bufin.available() != 0) { len = bufin.read(buffer); sig.update(buffer, 0, len); }; bufin.close(); boolean verifies = sig.verify(sigToVerify); System.out.println("signature verifies: " + verifies); } catch (Exception e) { System.err.println("Caught exception " + e.toString()); }; } }
編譯后,這樣運(yùn)行(StanSmith.cer是利用keytool導(dǎo)出的公鑰證書,見前文):
$ java VerSig2 StanSmith.cer sig hello.txt signature verifies: true
openssl
雖然也研究了一下openssl,但發(fā)現(xiàn)與java難以結(jié)合,難度也很大。例如它的教程中采用的是RSA,而上面的java使用的是DSA。所以只是貼在這里備忘,可以忽略。
生成私鑰
$ openssl genrsa -out key.pem 1024 $ cat key.pem -----BEGIN RSA PRIVATE KEY----- MIICXQIBAAKBgQCzVDmu6Cf2QF7cERCGYU3B8Epm6pkkpMZFgotphXMgAmBBNJbh Si7qPH4R5JlEm1ZXPr5DZH/pyJBWQhiiHGeUAOve+GOgvt9Rk25r7OEWYvn/GCr/ JBfLBGqwtlzn/t2s2x04IooshsGkOd6YpZoztkEDtu2gKHedFczF607IvwIDAQAB AoGAMdbIqUmwQYomUvcTJqXIXIwRwYSVx09cI1lisZL7Kfw/ECAzhq19WHAzgXmM 9zpMxraTXluCCVFKfA6mlfda+ZoBlKSYdOecwNB+TSAumf9XK8uHW/g8C+Ykq9OG g9Uiy8rKnl12Zaiu9H8L82ud0CkTFW2636/PuKgtp+4YbXECQQDhKdh8lwgumg7H YIw5476QOHnPL7c3OFPGtaOZMZJkjMPfRzgR4B5PjcGnOLDoTlkATcBPmXtLwwJJ SzaBdaRjAkEAy+NwdOzC1yQrTrkZQx1brNjO3iytfkl3t1xAWyz5Sy1IB7+4fsod Eh3br5E1o5YRipY2GJZvp2OAAt3tz6iS9QJASvIYwu+qo4hX3vk9847gwTRrJxFk 1JaFHCEdgUJEzf8ku08DVL/alvRCPxzZlZluenFmz5fwuDkCq87DJ7g2rQJBAMDM +SnIPdMeA8n0pRvfJjLD7pMP4pu6M3fzx3Owiqj5T9TsCjXzQBxCmdxizzs7DKll tA/6Kek64PFVFa25tgUCQQCTM1VwfNKjFbd+0HuF6WAs3Odjuo0gKk/QIjdn7M5/ I0kxEApKxTto3oiuCQGeYL/sqy3WjM0476w48+xUsQeF -----END RSA PRIVATE KEY-----
導(dǎo)出公鑰
$ openssl rsa -in key.pem -pubout -out pub-key.pem $ cat pub-key.pem -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCzVDmu6Cf2QF7cERCGYU3B8Epm 6pkkpMZFgotphXMgAmBBNJbhSi7qPH4R5JlEm1ZXPr5DZH/pyJBWQhiiHGeUAOve +GOgvt9Rk25r7OEWYvn/GCr/JBfLBGqwtlzn/t2s2x04IooshsGkOd6YpZoztkED tu2gKHedFczF607IvwIDAQAB -----END PUBLIC KEY-----
摘要計(jì)算
創(chuàng)建一個(gè)內(nèi)容是1234的文本文件hello.txt。用openssl計(jì)算它的SHA256摘要(SHA256是jarsigner的默認(rèn)摘要算法):
$ cat hello.txt 1234 $ openssl dgst -SHA256 -out hello.sha256 hello.txt $ cat hello.sha256 SHA256(hello.txt)= a883dafc480d466ee04e0d6da986bd78eb1fdd2178d04693723da3a8f95d42f4
簽名和驗(yàn)證
對摘要文件hello.sha256進(jìn)行簽名:
$ openssl rsautl -sign -in hello.sha256 -out hello.sign -inkey key.pem
用公鑰對簽名進(jìn)行驗(yàn)證:
$ openssl rsautl -verify -in hello.sign -inkey pub-key.pem -pubin SHA256(hello.txt)= a883dafc480d466ee04e0d6da986bd78eb1fdd2178d04693723da3a8f95d42f4
用公鑰驗(yàn)證必須加上-pubin參數(shù)。 用私鑰對簽名進(jìn)行驗(yàn)證:
$ openssl rsautl -verify -in hello.sign -inkey key.pem SHA256(hello.txt)= a883dafc480d466ee04e0d6da986bd78eb1fdd2178d04693723da3a8f95d42f4
驗(yàn)證的STD輸出與摘要文件hello.sha256的內(nèi)容一樣,說明驗(yàn)證可以通過。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關(guān)文章
一小時(shí)迅速入門Mybatis之Prepared Statement與符號(hào)的使用
這篇文章主要介紹了一小時(shí)迅速入門Mybatis之Prepared Statement與符號(hào)的使用,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-09-09MyBatis-Plus聯(lián)表查詢(Mybatis-Plus-Join)的功能實(shí)現(xiàn)
mybatis-plus作為mybatis的增強(qiáng)工具,簡化了開發(fā)中的數(shù)據(jù)庫操作,這篇文章主要介紹了MyBatis-Plus聯(lián)表查詢(Mybatis-Plus-Join),需要的朋友可以參考下2022-08-08Spring框架基于注解的AOP之各種通知的使用與環(huán)繞通知實(shí)現(xiàn)詳解
這篇文章主要介紹了Spring框架基于注解的AOP之各種通知的使用及其環(huán)繞通知,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2022-11-11詳解如何在Spring Boot項(xiàng)目使用參數(shù)校驗(yàn)
本篇文章主要介紹了如何在Spring Boot項(xiàng)目使用參數(shù)校驗(yàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-06-06關(guān)于Controller層和Service層的類報(bào)錯(cuò)問題及解決方案
這篇文章主要介紹了關(guān)于Controller層和Service層的類報(bào)錯(cuò)問題及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02SpringBoot集成itext實(shí)現(xiàn)html轉(zhuǎn)PDF
iText是著名的開放源碼的站點(diǎn)sourceforge一個(gè)項(xiàng)目,是用于生成PDF文檔的一個(gè)java類庫,本文主要介紹了如何利用itext實(shí)現(xiàn)html轉(zhuǎn)PDF,需要的可以參考下2024-03-03