程序員必備基礎(chǔ):加簽驗(yàn)簽
密碼學(xué)相關(guān)概念
明文、密文、密鑰、加密、解密
- 明文:指沒(méi)有經(jīng)過(guò)加密的信息/數(shù)據(jù)。
- 密文:明文被加密算法加密之后,會(huì)變成密文,以確保數(shù)據(jù)安全。
- 密鑰:是一種參數(shù),它是在明文轉(zhuǎn)換為密文或?qū)⒚芪霓D(zhuǎn)換為明文的算法中輸入的參數(shù)。密鑰分為對(duì)稱密鑰與非對(duì)稱密鑰。
- 加密:將明文變成密文的過(guò)程。
- 解密:將密文還原為明文的過(guò)程。
對(duì)稱加密、非對(duì)稱加密
對(duì)稱加密:加密和解密使用相同密鑰的加密算法。
非對(duì)稱加密:非對(duì)稱加密算法需要兩個(gè)密鑰(公開密鑰和私有密鑰)。公鑰與私鑰是成對(duì)存在的,如果用公鑰對(duì)數(shù)據(jù)進(jìn)行加密,只有對(duì)應(yīng)的私鑰才能解密。
什么是公鑰私鑰?
公鑰與私鑰是成對(duì)存在的密鑰,如果用公鑰對(duì)數(shù)據(jù)進(jìn)行加密,只有用對(duì)應(yīng)的私鑰才能解密。
其實(shí),公鑰就是公開的秘鑰,私鑰就是要你私自保存好的秘鑰。
非對(duì)稱加密算法需要有一對(duì)公私鑰~
❝假設(shè)你有一個(gè)文件,你用字母a加密,只有字母b才能解密;或者你用b加密,只有a才能解密,那么a和b就是一對(duì)公私鑰。如果密鑰a公開,密鑰b你就要私自保存好啦,這時(shí)候密鑰a就是公鑰,密鑰b就是私鑰。相反,如果b公開,a就要保存好,這時(shí)候呢,秘鑰b就是公鑰,秘鑰a就是私鑰。❞
加簽驗(yàn)簽概念
「加簽」:用Hash函數(shù)把原始報(bào)文生成報(bào)文摘要,然后用私鑰對(duì)這個(gè)摘要進(jìn)行加密,就得到這個(gè)報(bào)文對(duì)應(yīng)的數(shù)字簽名。通常來(lái)說(shuō)呢,請(qǐng)求方會(huì)把「數(shù)字簽名和報(bào)文原文」一并發(fā)送給接收方。
「驗(yàn)簽」:接收方拿到原始報(bào)文和數(shù)字簽名后,用「同一個(gè)Hash函數(shù)」從報(bào)文中生成摘要A。另外,用對(duì)方提供的公鑰對(duì)數(shù)字簽名進(jìn)行解密,得到摘要B,對(duì)比A和B是否相同,就可以得知報(bào)文有沒(méi)有被篡改過(guò)。
為什么需要加簽驗(yàn)簽
上小節(jié)中,加簽和驗(yàn)簽我們已經(jīng)知道概念啦,那么,為什么需要加簽和驗(yàn)簽?zāi)?有些朋友可能覺得,我們不是用「公鑰加密,私鑰解密」就好了嘛?
接下來(lái)呢,舉個(gè)demo吧。
❝假設(shè)現(xiàn)在有A公司,要接入C公司的轉(zhuǎn)賬系統(tǒng)。在一開始呢,C公司把自己的公鑰寄給A公司,自己收藏好私鑰。A公司這邊的商戶,發(fā)起轉(zhuǎn)賬時(shí),A公司先用C公司的公鑰,對(duì)請(qǐng)求報(bào)文加密,加密報(bào)文到達(dá)C公司的轉(zhuǎn)賬系統(tǒng)時(shí),C公司就用自己的私鑰把報(bào)文揭開。假設(shè)在加密的報(bào)文在傳輸過(guò)程中,被中間人Actor獲取了,他也郁悶,因?yàn)樗麤](méi)有私鑰,看著天鵝肉,又吃不了。本來(lái)想修改報(bào)文,給自己賬號(hào)轉(zhuǎn)一個(gè)億的,哈哈。這個(gè)實(shí)現(xiàn)方式看起來(lái)是天衣無(wú)縫,穩(wěn)得一匹的。❞
但是呢,如果一開始,C公司把公鑰發(fā)給公司A的時(shí)候,就被中間人Actor獲取到呢,醬紫就出問(wèn)題了。
❝中間人Actor截取了C的公鑰,他把自己的公鑰發(fā)給了A公司,A誤以為這就是C公司的公鑰。A在發(fā)起轉(zhuǎn)賬時(shí),用Actor的公鑰,對(duì)請(qǐng)求報(bào)文加密,加密報(bào)文到在傳輸過(guò)程,Actor又截取了,這時(shí)候,他用自己的私鑰解密,然后修改了報(bào)文(給自己轉(zhuǎn)一個(gè)億),再用C的公鑰加密,發(fā)給C公司,C公司收到報(bào)文后,繼續(xù)用自己的私鑰解密。最后是不是A公司的轉(zhuǎn)賬賬戶損失了一個(gè)億呢~❞
C公司是怎么區(qū)分報(bào)文是不是來(lái)自A呢,還是被中間人修改過(guò)呢?為了表明身份和報(bào)文真實(shí)性,這就需要「加簽驗(yàn)簽」啦!
❝A公司把自己的公鑰也發(fā)送給C公司,私鑰自己保留著。在發(fā)起轉(zhuǎn)賬時(shí),先用自己的私鑰對(duì)請(qǐng)求報(bào)文加簽,于是得到自己的數(shù)字簽名。再把數(shù)字簽名和請(qǐng)求報(bào)文一起發(fā)送給C公司。C公司收到報(bào)文后,拿A的公鑰進(jìn)行驗(yàn)簽,如果原始報(bào)文和數(shù)字簽名的摘要內(nèi)容不一致,那就是報(bào)文被篡改啦~❞
有些朋友可能有疑問(wèn),假設(shè)A在發(fā)自己的公鑰給C公司的時(shí)候,也被中間人Actor截取了呢。嗯嗯,我們來(lái)模擬一波Actor又截取了公鑰,看看Actor能干出什么事情來(lái)~哈哈
❝假設(shè)Actor截取到A的公鑰后,隨后也截取了到A發(fā)往C的報(bào)文。他截取到報(bào)文后,第一件想做的事肯定是修改報(bào)文內(nèi)容。但是如果單單修改原始報(bào)文是不可以的,因?yàn)榘l(fā)過(guò)去C公司肯定驗(yàn)簽不過(guò)啦。但是呢,數(shù)字簽名似乎解不開,因?yàn)橄⒄惴?hash算法)無(wú)法逆向解開的,只起驗(yàn)證的作用呢....❞
所以呢,公鑰與私鑰是用來(lái)加密與加密的,「加簽與驗(yàn)簽是用來(lái)證明身份」,以免被篡改的。
常見加密相關(guān)算法簡(jiǎn)介
- 消息摘要算法
- 對(duì)稱加密算法
- 非對(duì)稱加密算法
- 國(guó)密算法
消息摘要算法:
- 相同的明文數(shù)據(jù)經(jīng)過(guò)相同的消息摘要算法會(huì)得到相同的密文結(jié)果值。
- 數(shù)據(jù)經(jīng)過(guò)消息摘要算法處理,得到的摘要結(jié)果值,是無(wú)法還原為處理前的數(shù)據(jù)的。
- 數(shù)據(jù)摘要算法也被稱為哈希(Hash)算法或散列算法。
- 消息摘要算法一般用于簽名驗(yàn)簽。
消息摘要算法主要分三類:MD(Message Digest,消息摘要算法)、SHA(Secure Hash Algorithm,安全散列算法)和MAC(Message Authentication Code,消息認(rèn)證碼算法)。
MD家族算法
MD(Message Digest,消息摘要算法)家族,包括MD2,MD4,MD5。
- MD2,MD4,MD5 計(jì)算的結(jié)果都是是一個(gè)128位(即16字節(jié))的散列值,用于確保信息傳輸完整一致。
- MD2的算法較慢但相對(duì)安全,MD4速度很快,但安全性下降,MD5則比MD4更安全、速度更快。
- MD5被廣泛應(yīng)用于數(shù)據(jù)完整性校驗(yàn)、數(shù)據(jù)(消息)摘要、數(shù)據(jù)加密等。
- MD5,可以被破解,對(duì)于需要高度安全性的數(shù)據(jù),專家一般建議改用其他算法,如SHA-2。2004年,證實(shí)MD5算法無(wú)法防止碰撞攻擊,因此不適用于安全性認(rèn)證,如SSL公開密鑰認(rèn)證或是數(shù)字簽名等用途。
舉個(gè)例子,看看如何獲取字符串的MD5值吧:
- public class MD5Test {
- public static void main(String[] args) throws UnsupportedEncodingException {
- String s = "123";
- byte[] result = getMD5Bytes(s.getBytes());
- StringBuilder stringBuilder = new StringBuilder();
- for (byte temp : result) {
- if (temp >= 0 && temp < 16) {
- stringBuilder.append("0");
- }
- stringBuilder.append(Integer.toHexString(temp & 0xff));
- }
- System.out.println(s + ",MD5加密后:" + stringBuilder.toString());
- }
- private static byte[] getMD5Bytes(byte[] content) {
- try {
- MessageDigest md5 = MessageDigest.getInstance("MD5");
- return md5.digest(content);
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException(e);
- }
- }
- }
運(yùn)行結(jié)果:
- 123,MD5加密后:202cb962ac59075b964b07152d234b70
ShA家族算法
SHA(Secure Hash Algorithm,安全散列算法),包括SHA-0、SHA-1、SHA-2(SHA-256,SHA-512,SHA-224,SHA-384等)、SHA-3。它是在MD算法基礎(chǔ)上實(shí)現(xiàn)的,與MD算法區(qū)別在于「摘要長(zhǎng)度」,SHA 算法的摘要「長(zhǎng)度更長(zhǎng),安全性更高」。
❝SHA-0發(fā)布之后很快就被NSA撤回,因?yàn)楹袝?huì)降低密碼安全性的錯(cuò)誤,它是SHA-1的前身。
SHA-1在許多安全協(xié)議中廣為使用,包括TLS、GnuPG、SSH、S/MIME和IPsec,是MD5的后繼者。
SHA-2包括SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256。它的算法跟SHA-1基本上相似,目前還沒(méi)有出現(xiàn)明顯弱點(diǎn)。
SHA-3是2015年正式發(fā)布,由于對(duì)「MD5出現(xiàn)成功的破解」,以及對(duì)SHA-0和SHA-1出現(xiàn)理論上破解的方法,SHA-3應(yīng)運(yùn)而生。它與之前算法不同的是,它是可替換的加密散列算法。❞
SHA-1、SHA-2(SHA-256,SHA-512,SHA-224,SHA-384)等算法是比較常用的,我們來(lái)看看跟MD5的對(duì)比吧
| 算法類型 | 摘要長(zhǎng)度(bits) | 最大輸入消息長(zhǎng)度(bits) | 碰撞攻擊(bits) | 性能示例(MiB/s) |
|---|---|---|---|---|
| MD5 | 128 | 無(wú)限 | ≤18(發(fā)現(xiàn)碰撞) | 335 |
| SHA-1 | 160 | 2^64 − 1 | <63(發(fā)現(xiàn)碰撞) | 192 |
| SHA-224 | 224 | 2^64 − 1 | 112 | 139 |
| SHA-256 | 256 | 2^64 − 1 | 128 | 139 |
| SHA-384 | 384 | 2^128 − 1 | 192 | 154 |
| SHA-512 | 512 | 2^128 − 1 | 256 | 154 |
MAC算法家族
MAC算法 MAC(Message Authentication Code,消息認(rèn)證碼算法),是帶密鑰的Hash函數(shù)。輸入密鑰和消息,輸出一個(gè)消息摘要。它集合了MD和SHA兩大系列消息摘要算法。
MD 系列算法: HmacMD2、HmacMD4 和 HmacMD5 ;
SHA 系列算法:HmacSHA1、HmacSHA224、HmacSHA256、HmacSHA384 和 HmacSHA512 。
對(duì)稱加密算法
加密和解密使用「相同密鑰」的加密算法就是對(duì)稱加密算法。常見的對(duì)稱加密算法有AES、3DES、DES、RC5、RC6等。
DES
數(shù)據(jù)加密標(biāo)準(zhǔn)(英語(yǔ):Data Encryption Standard,縮寫為 DES)是一種對(duì)稱密鑰加密塊密碼算法。DES算法的入口參數(shù)有三個(gè):Key、Data、Mode。
Key: 7個(gè)字節(jié)共56位,是DES算法的工作密鑰;
Data: 8個(gè)字節(jié)64位,是要被加密或被解密的數(shù)據(jù);
Mode: 加密或解密。
3DES
三重?cái)?shù)據(jù)加密算法(英語(yǔ):Triple Data Encryption Algorithm,又稱3DES(Triple DES),是一種對(duì)稱密鑰加密塊密碼,相當(dāng)于是對(duì)每個(gè)數(shù)據(jù)塊應(yīng)用三次數(shù)據(jù)加密標(biāo)準(zhǔn)(DES)算法。
AES
AES,高級(jí)加密標(biāo)準(zhǔn)(英語(yǔ):Advanced Encryption Standard),在密碼學(xué)中又稱Rijndael加密法,是美國(guó)聯(lián)邦政府采用的一種區(qū)塊加密標(biāo)準(zhǔn)。
采用對(duì)稱分組密碼體制,密鑰長(zhǎng)度為 128 位、 192 位、256 位,分組長(zhǎng)度128位
相對(duì)于DES ,AES具有更好的 安全性、效率 和 靈活性。
非對(duì)稱加密算法
非對(duì)稱加密算法需要兩個(gè)密鑰:公鑰和私鑰。公鑰與私鑰是成對(duì)存在的,如果用公鑰對(duì)數(shù)據(jù)進(jìn)行加密,只有用對(duì)應(yīng)的私鑰才能解密。主要的非對(duì)稱加密算法有:RSA、Elgamal、DSA、D-H、ECC。
RSA算法
RSA加密算法是一種非對(duì)稱加密算法,廣泛應(yīng)用于加密和數(shù)字簽名
RSA算法原理:兩個(gè)大素?cái)?shù)的乘積進(jìn)行因式分解卻極其困難,因此可以將乘積公開作為加密密鑰。
RSA是被研究得最廣泛的公鑰算法,從提出到現(xiàn)在,經(jīng)歷了各種攻擊的考驗(yàn),普遍認(rèn)為是目前最優(yōu)秀的公鑰方案之一。
DSA
DSA(Digital Signature Algorithm,數(shù)字簽名算法),也是一種非對(duì)稱加密算法。
DSA和RSA區(qū)別在,DSA僅用于數(shù)字簽名,不能用于數(shù)據(jù)加密解密。其安全性和RSA相當(dāng),但其性能要比RSA好。
ECC 算法
ECC(Elliptic Curves Cryptography,橢圓曲線密碼編碼學(xué)),基于橢圓曲線加密。
Ecc主要優(yōu)勢(shì)是,在某些情況下,它比其他的方法使用更小的密鑰,比如RSA加密算法,提供相當(dāng)?shù)幕蚋叩燃?jí)的安全級(jí)別。
它的一個(gè)缺點(diǎn)是,加密和解密操作的實(shí)現(xiàn)比其他機(jī)制時(shí)間長(zhǎng) (相比RSA算法,該算法對(duì)CPU 消耗嚴(yán)重)。
國(guó)密算法
國(guó)密即國(guó)家密碼局認(rèn)定的國(guó)產(chǎn)密碼算法。為了保障商用密碼的安全性,國(guó)家商用密碼管理辦公室制定了一系列密碼標(biāo)準(zhǔn),即SM1,SM2,SM3,SM4等國(guó)密算法。
SM1
- SM1,為對(duì)稱加密算法,加密強(qiáng)度為128位,基于硬件實(shí)現(xiàn)。
- SM1的加密強(qiáng)度和性能,與AES相當(dāng)。
SM2
- SM2主要包括三部分:簽名算法、密鑰交換算法、加密算法
- SM2用于替換RSA加密算法,基于ECC,效率較低。
SM3
- SM3,即國(guó)產(chǎn)消息摘要算法。
- 適用于商用密碼應(yīng)用中的數(shù)字簽名和驗(yàn)證,消息認(rèn)證碼的生成與驗(yàn)證以及隨機(jī)數(shù)的生成。
SM4
- SM4是一個(gè)分組算法,用于無(wú)線局域網(wǎng)產(chǎn)品。
- 該算法的分組長(zhǎng)度為128比特,密鑰長(zhǎng)度為128比特。
- 加密算法與密鑰擴(kuò)展算法都采用32輪非線性迭代結(jié)構(gòu)。
- 解密算法與加密算法的結(jié)構(gòu)相同,只是輪密鑰的使用順序相反,解密輪密鑰是加密輪密鑰的逆序。
- 它的功能類似國(guó)際算法的DES。
加簽驗(yàn)簽相關(guān)Java的API
這個(gè)小節(jié)先介紹一下加簽驗(yàn)簽需要用到的API吧~
加簽相關(guān)API
- - java.security.Signature.getInstance(String algorithm); //根據(jù)對(duì)應(yīng)算法,初始化簽名對(duì)象
- - KeyFactory.getInstance(String algorithm);// 根據(jù)對(duì)應(yīng)算法,生成KeyFactory對(duì)象
- - KeyFactory.generatePrivate(KeySpec keySpec); //生成私鑰
- - java.security.Signature.initSign(PrivateKey privateKey) //由私鑰,初始化加簽對(duì)象
- - java.security.Signature.update(byte[] data) //把原始報(bào)文更新到加簽對(duì)象
- - java.security.Signature.sign();//加簽
「Signature.getInstance(String algorithm);」
- 根據(jù)對(duì)應(yīng)算法,初始化簽名對(duì)象
- algorithm參數(shù)可以取SHA256WithRSA或者M(jìn)D5WithRSA等參數(shù),SHA256WithRSA表示生成摘要用的是SHA256算法,簽名加簽用的是RSA算法
「KeyFactory.getInstance(String algorithm);」
- 根據(jù)對(duì)應(yīng)算法,生成KeyFactory對(duì)象,比如你的公私鑰用的是RSA算法,那么就傳入RSA
「KeyFactory.generatePrivate(KeySpec keySpec)」
- 生成私鑰,加簽用的是私鑰哈,所以需要通過(guò)KeyFactory先構(gòu)造一個(gè)私鑰對(duì)象。
「Signature.initSign(PrivateKey privateKey)」
- 加簽用的是私鑰,所以傳入私鑰,初始化加簽對(duì)象
「Signature.update(byte[] data)」
- 把原始報(bào)文更新到加簽對(duì)象
「java.security.Signature.sign();」
- 進(jìn)行加簽操作
驗(yàn)簽相關(guān)API
- - java.security.Signature.getInstance(String algorithm); //根據(jù)對(duì)應(yīng)算法,初始化簽名對(duì)象
- - KeyFactory.getInstance(String algorithm);// 根據(jù)對(duì)應(yīng)算法,生成KeyFactory對(duì)象
- - KeyFactory.generatePublic(KeySpec keySpec); //生成公鑰
- - java.security.Signature.initVerify(publicKey); //由公鑰,初始化驗(yàn)簽對(duì)象
- - java.security.Signature.update(byte[] data) //把原始報(bào)文更新到驗(yàn)簽對(duì)象
- - java.security.Signature.verify(byte[] signature);//驗(yàn)簽
「Signature.getInstance(String algorithm)」
- 根據(jù)對(duì)應(yīng)算法,初始化簽名對(duì)象,注意驗(yàn)簽和加簽是需要用相同的algorithm算法參數(shù)哦~
「KeyFactory.getInstance(String algorithm);」
- 根據(jù)對(duì)應(yīng)算法,生成KeyFactory對(duì)象
「KeyFactory.generatePublic(KeySpec keySpec);」
- 生成公鑰,驗(yàn)簽用的是公鑰,通過(guò)KeyFactory先構(gòu)造一個(gè)公鑰對(duì)象
「Signature.initVerify(publicKey);」
- 公鑰驗(yàn)簽,所以傳入公鑰對(duì)象參數(shù),初始化驗(yàn)簽對(duì)象
「Signature.update(byte[] data)」
- 把原始報(bào)文更新到加簽對(duì)象
「Signature.verify(byte[] signature);」
- 進(jìn)行驗(yàn)簽操作
加簽驗(yàn)簽代碼實(shí)現(xiàn)前幾個(gè)小節(jié)討論完概念,是時(shí)候上代碼實(shí)戰(zhàn)了,我這邊用的是SHA-256作為摘要算法,RSA作為簽名驗(yàn)簽算法,如下:
- package pattern;
- import sun.misc.BASE64Decoder;
- import sun.misc.BASE64Encoder;
- import java.io.IOException;
- import java.io.UnsupportedEncodingException;
- import java.security.*;
- import java.security.spec.InvalidKeySpecException;
- import java.security.spec.PKCS8EncodedKeySpec;
- /**
- * 加簽驗(yàn)簽demo
- * @Author 撿田螺的小男孩
- */
- public class SignatureTest {
- //公鑰字符串
- private static final String PUBLIC_KEY_STR = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDaJzVjC5K6kbS2YE2fiDs6H8pB\n" +
- "JFDGEYqqJJC9I3E0Ebr5FsofdImV5eWdBSeADwcR9ppNbpORdZmcX6SipogKx9PX\n" +
- "5aAO4GPesroVeOs91xrLEGt/arteW8iSD+ZaGDUVV3+wcEdci/eCvFlc5PUuZJou\n" +
- "M2XZaDK4Fg2IRTfDXQIDAQAB";
- //私鑰字符串
- private static final String PRIVATE_KEY_STR = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBANonNWMLkrqRtLZg\n" +
- "TZ+IOzofykEkUMYRiqokkL0jcTQRuvkWyh90iZXl5Z0FJ4APBxH2mk1uk5F1mZxf\n" +
- "pKKmiArH09floA7gY96yuhV46z3XGssQa39qu15byJIP5loYNRVXf7BwR1yL94K8\n" +
- "WVzk9S5kmi4zZdloMrgWDYhFN8NdAgMBAAECgYA9bz1Bn0i68b2KfqRdgOfs/nbe\n" +
- "0XNN1DLQp2t7WDfRCg01iI1zPkZgyFVZWtI85f5/uIrLs5ArLosL1oNuqqc0nNne\n" +
- "CvJK+ZxvA98Hx3ZqYTzDnleR054YhofL5awbhSciYVic204DOG1rhSsYWMqtX7J7\n" +
- "3geoWL7TYdMfYXcCAQJBAPMMKsz6ZJh98EeQ1tDG5gpAGWFQkYNrxZDelP/LjeO0\n" +
- "TP3XkQnIpcaZoCs7V/rRGRGMWwQ2BUdc/01in89ZZ5ECQQDlx2oBc1CtOAm2UAhN\n" +
- "1xWrPkZWENQ53wTrwXO4qbTGDfBKon0AehLlGCSqxQ71aufLkNO7ZlX0IHTAlnk1\n" +
- "TvENAkAGSEQ69CXxgx/Y2beTwfBkR2/gghKg0QJUUkyLqBlMz3ZGAXJwTE1sqr/n\n" +
- "HiuSAiGhwH0ByNuuEotO1sPGukrhAkAMK26a2w+nzPL+u+hkrwKPykGRZ1zGH+Cz\n" +
- "19AYNKzFXJGgclCqiMydY5T1knBDYUEbj/UW1Mmyn1FvrciHoUG1AkAEMEIuDauz\n" +
- "JabEAU08YmZw6OoDGsukRWaPfjOEiVhH88p00veM1R37nwhoDMGyEGXVeVzNPvk7\n" +
- "cELg28MSRzCK";
- public static void main(String[] args) throws SignatureException, NoSuchAlgorithmException, InvalidKeyException, IOException, InvalidKeySpecException {
- //原始報(bào)文
- String plain = "歡迎大家關(guān)注我的公眾號(hào),撿田螺的小男孩";
- //加簽
- byte[] signatureByte = sign(plain);
- System.out.println("原始報(bào)文是:" + plain);
- System.out.println("加簽結(jié)果:");
- System.out.println(new BASE64Encoder().encode(signatureByte));
- //驗(yàn)簽
- boolean verifyResult = verify(plain, signatureByte);
- System.out.println("驗(yàn)簽結(jié)果:" + verifyResult);
- }
- /**
- * 加簽方法
- * @param plain
- * @return
- * @throws NoSuchAlgorithmException
- * @throws InvalidKeyException
- * @throws UnsupportedEncodingException
- * @throws SignatureException
- */
- private static byte[] sign(String plain) throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException, SignatureException {
- //根據(jù)對(duì)應(yīng)算法,獲取簽名對(duì)象實(shí)例
- Signature signature = Signature.getInstance("SHA256WithRSA");
- //獲取私鑰,加簽用的是私鑰,私鑰一般是在配置文件里面讀的,這里為了演示方便,根據(jù)私鑰字符串生成私鑰對(duì)象
- PrivateKey privateKey = getPriveteKey(PRIVATE_KEY_STR);
- //初始化簽名對(duì)象
- signature.initSign(privateKey);
- //把原始報(bào)文更新到對(duì)象
- signature.update(plain.getBytes("UTF-8"));
- //加簽
- return signature.sign();
- }
- /**
- * 驗(yàn)簽方法
- * @param plain
- * @param signatureByte
- * @return
- * @throws NoSuchAlgorithmException
- * @throws InvalidKeyException
- * @throws IOException
- * @throws SignatureException
- * @throws InvalidKeySpecException
- */
- private static boolean verify(String plain, byte[] signatureByte) throws NoSuchAlgorithmException, InvalidKeyException, IOException, SignatureException, InvalidKeySpecException {
- //獲取公鑰
- PublicKey publicKey = getPublicKey(PUBLIC_KEY_STR);
- //根據(jù)對(duì)應(yīng)算法,獲取簽名對(duì)象實(shí)例
- Signature signature = Signature.getInstance("SHA256WithRSA");
- //初始化簽名對(duì)象
- signature.initVerify(publicKey);
- //把原始報(bào)文更新到簽名對(duì)象
- signature.update(plain.getBytes("UTF-8"));
- //進(jìn)行驗(yàn)簽
- return signature.verify(signatureByte);
- }
- private static PublicKey getPublicKey(String publicKeyStr) throws InvalidKeySpecException, IOException {
- PublicKey publicKey = null;
- try {
- java.security.spec.X509EncodedKeySpec bobPubKeySpec = new java.security.spec.X509EncodedKeySpec(
- new BASE64Decoder().decodeBuffer(publicKeyStr));
- // RSA對(duì)稱加密算法
- java.security.KeyFactory keyFactory;
- keyFactory = java.security.KeyFactory.getInstance("RSA");
- // 生成公鑰對(duì)象
- publicKey = keyFactory.generatePublic(bobPubKeySpec);
- } catch (NoSuchAlgorithmException e) {
- e.printStackTrace();
- }
- return publicKey;
- }
- private static PrivateKey getPriveteKey(String privateKeyStr) {
- PrivateKey privateKey = null;
- PKCS8EncodedKeySpec priPKCS8;
- try {
- priPKCS8 = new PKCS8EncodedKeySpec(new BASE64Decoder().decodeBuffer(privateKeyStr));
- KeyFactory keyf = KeyFactory.getInstance("RSA");
- privateKey = keyf.generatePrivate(priPKCS8);
- } catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException e) {
- e.printStackTrace();
- }
- return privateKey;
- }
- }
「運(yùn)行結(jié)果:」
- 原始報(bào)文是:歡迎大家關(guān)注我的公眾號(hào),撿田螺的小男孩
- 加簽結(jié)果:
- Oz15/aybGe42eGHbc+iMoSYHSCc8tfRskTVjjGSTPD4HjadL0CC5JUWNUW0WxHjUb4MvxWo2oeWE
- Qw0+m61d+JgBMto/TWcVDcgwL/AbObsbWdQ6E/fVRqG13clkE8MyKsjt9Z7tcbwpycYTv0rUR4co
- rndAVfBdtv5KeV+OXqM=
- 驗(yàn)簽結(jié)果:true
本文轉(zhuǎn)載自微信公眾號(hào)「 撿田螺的小男孩」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系 撿田螺的小男孩公眾號(hào)。






































