DSA算法
DSA(Digital Signature Algorithm)是Schnorr和ElGamal簽名算法的變種,被美國NIST作為DSS(DigitalSignature Standard)。
DSA加密算法主要依賴於整數有限域離散對數難題,素數P必須足夠大,且p-1至少包含一個大素數因子以抵抗Pohlig &Hellman算法的攻擊。M一般都應采用信息的HASH值。DSA加密算法的安全性主要依賴於p和g,若選取不當則簽名容易偽造,應保證g對於p-1的大素數因子不可約。其安全性與RSA相比差不多。
DSA 一般用於數字簽名和認證。在DSA數字簽名和認證中,發送者使用自己的私鑰對文件或消息進行簽名,接受者收到消息后使用發送者的公鑰來驗證簽名的真實性。DSA只是一種算法,和RSA不同之處在於它不能用作加密和解密,也不能進行密鑰交換,只用於簽名,它比RSA要快很多.
1. DSA簽名及驗證
DSA算法中應用了下述參數:
p:L bits長的素數。L是64的倍數,范圍是512到1024;
q:p – 1的160bits的素因子;
g:g = h^((p-1)/q) mod p,h滿足h < p – 1, h^((p-1)/q) mod p > 1;
x:x < q,x為私鑰 ;
y:y = g^x mod p ,( p, q, g, y )為公鑰;
H( x ):One-Way Hash函數。DSS中選用SHA( Secure Hash Algorithm )。
p, q, g可由一組用戶共享,但在實際應用中,使用公共模數可能會帶來一定的威脅。
簽名及驗證協議:
- 1.P產生隨機數k,k < q;
- 2.P計算 r = ( g^k mod p ) mod q
s = ( k^(-1) (H(m) xr)) mod q
簽名結果是( m, r, s )。 - 3.驗證時計算 w = s^(-1)mod q
u1 = ( H( m ) w ) mod q
u2 = ( r w ) mod q
v = (( g^u1 * y^u2 ) mod p ) mod q
若v = r,則認為簽名有效。
舉例:B 發消息給A,使用DSA算法進行簽名
1.生成素數p=59、素數q=29、h=11、私鑰x=7,臨時密鑰k=10,消息摘要H(M)=26
2.生成g:
g=h^(p-1)/qmod p → g=11^2 mod 59 → g=3
3.計算公鑰y
y=g^xmod p → y=3^7 mod 59 →y=2187 mod 59 →y=4
4.進行簽名計算
r = (g^k mod p) mod q → r=(59049 mod 59) mod 29 →r=20
s = [k^-1 (H(M) + xr) ] mod q → s=3·(26+140)mod 29 → s=5
5.A收到消息后進行簽名驗證
w=(s’)^-1mod q → w=6 mod 29 =6
u1=[H(M’)w] mod q → u1=156 mod 29 = 11
u2=(r’)wmod q → u2=120 mod 29=4
v=[(g^u1 · y^u2) mod p] mod q → v= (45349632 mod 59) mod 29 =20
v=r=20
6.驗證成功;
2.DSA使用過程
過程:
構建密鑰對:
發送方: 1.構建密鑰對
2.公布密鑰
發送數據 :
發送方: 1.使用私鑰對數據簽名
2.發送簽名,數據
3.使用公鑰,簽名驗證數據
3. Java實現DSA生成公私鑰並加解密
3.1代碼如下
package com.tencent.blue.utils; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.security.*; /** * Created by cuiran on 19/1/11. * 生成一對文件 publicKey.key 和 privateKey.key , * 公鑰要用戶發送 ( 文件 , 網絡等方法 ) 給其它用戶 , 私鑰保存在本地 * 1.生成秘鑰對 * 2.使用私鑰進行簽名 * 3.使用公鑰校驗簽名 * 意義上的加密解密 非內容型的加密解密 */ public class DSA { public static void main(String[] args) { //初始化秘鑰對寫入到文件 生成的是X.509編碼格式的 生成的私鑰是PKCS#8編碼格式 getKeyPairs(); //明文簽名 SignatureData("我是cayden,銀行賬戶為622XXXX"); //校驗簽名文件 checkSignature(); } /** * 生成秘鑰對寫入到文件 * @return */ public static boolean getKeyPairs() { try { //初始化秘鑰管理器 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA"); keyPairGenerator.initialize(512); KeyPair keyPair = keyPairGenerator.genKeyPair(); //獲取秘鑰對 PublicKey publicKey = keyPair.getPublic(); PrivateKey privateKey = keyPair.getPrivate(); //直接寫入公鑰 ObjectOutputStream out_pub = new ObjectOutputStream(new FileOutputStream("publicKey.key")); out_pub.writeObject(publicKey); out_pub.close(); System.out.println("生成的公鑰內容為_____:\n "+publicKey); //直接寫入私鑰 ObjectOutputStream out_pri = new ObjectOutputStream(new FileOutputStream("privateKey.key")); out_pri.writeObject(privateKey); out_pri.close(); System.out.println("生成的私鑰內容為_____:\n "+privateKey); System.out.println("\n生成密鑰對成功..."); return true; } catch (java.lang.Exception e) { e.printStackTrace(); return false; } } /** * 使用私鑰進行簽名 * @return */ public static boolean SignatureData(String info){ try { //1.讀取生成的私鑰對明文進行簽名 ObjectInputStream in_pri = new ObjectInputStream(new java.io.FileInputStream("privateKey.key")); PrivateKey privateKey = (PrivateKey) in_pri.readObject(); in_pri.close(); //初始化簽名 對明文開始簽名 Signature signature = Signature.getInstance("DSA"); signature.initSign(privateKey); signature.update(info