DSA數字簽名是Elgamal和Schnorr數字簽名的一個變種,DSA數字簽名優於Elgamal數字簽名的地方在於它的簽名長度較短,而且某些能夠破解Elgamal方案的攻擊不適用DSA數字簽名,DSA數字簽名的原理以下:java
1. 首先生成一個素數p,p知足 2^L-1<p<2^L ;算法
注:關於L的值的範圍看到兩種不一樣的說法數組
a):L是102四、204八、3072三個值中的一個app
b):L知足512<=L<=1024 ,且L是64的倍數dom
2. 而後再生成q,再此處,假定L=1024,找到一個素數q,q知足 q能整除p-1,即 (p-1)mod q=0,且2^159< q <2^160;spa
3. 而後再生成g;.net
g=h^(p-1)/qmod p, h知足1<h<(p-1),而且g>1xml
4. 最後生成用戶的私鑰x和公鑰y對象
x是隨機數或者僞隨機數,且知足:0< x <qblog
y 知足 y=g^x mod p
5. 簽名,DSA簽名也是由兩個整數r、s構成,下面是r、s的獲取方式:
r =(g^k mod p) mod q
s = [k^-1(H(M) + xr) ] mod q
注:M是明文消息,H(M)是明文消息的哈希值,k是臨時密鑰
6.驗證,假設收到的明文爲M’,收到的簽名爲s’、r’,則驗證方式以下:
w=(s’)^-1mod q
u1=[H(M’)w] mod q
u2=(r’)wmod q
v=[(g^u1 · y^u2) mod p] mod q
檢驗 v=r’ 簽名有效,反之則簽名無效;
舉例:B 發消息給A,使用DSA算法進行簽名
1.生成素數p=5九、素數q=2九、h=十一、私鑰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.驗證成功;
[java] view plain copy
- import java.math.BigInteger;
- import java.security.*;
- import java.security.interfaces.DSAParams;
- import java.security.interfaces.DSAPrivateKey;
- import java.security.spec.*;
- import java.util.HashMap;
- import java.util.Map;
- import java.util.Random;
-
- public class DsaSignCode {
-
- private static final String SIGNATURE_ALGORITHM="SHA1withDSA";
- private static final String ALGORITHM = "DSA";
- private static final int KEY_SIZE = 1024;
-
- // 該方法取一個隨機x,x小於q而且大於0,
- private static BigInteger randbint(BigInteger n){
- Random rnd = new Random();
- int maxNumBitLength = n.bitLength();
- BigInteger aRandomBigInt;
- do{
- aRandomBigInt = new BigInteger(maxNumBitLength, rnd);
- }while (aRandomBigInt.compareTo(n) > 0);
- return aRandomBigInt;
- }
-
- public Map<String,BigInteger> DsaKey() throws NoSuchAlgorithmException {
-
- KeyPairGenerator keyGen = KeyPairGenerator.getInstance(ALGORITHM);
- //初始化
- keyGen.initialize(KEY_SIZE);
- KeyPair keyPair = keyGen.genKeyPair();
- //使用KeyPair生成密鑰
- DSAPrivateKey privateKey = (DSAPrivateKey) keyPair.getPrivate();
- // DSAPublicKey publicKey = (DSAPublicKey) keyPair.getPublic();
- DSAParams dsaParams = privateKey.getParams();
- BigInteger p = dsaParams.getP();
- BigInteger q = dsaParams.getQ();
- BigInteger g = dsaParams.getG();
- BigInteger x = randbint(q);
- BigInteger y = g.modPow(x, p);
- //使用HASHMAP存儲p,q,g,x,y
- Map<String,BigInteger> map = new HashMap<String,BigInteger>(5);
- map.put("KEY_P",p);
- map.put("KEY_Q",q);
- map.put("KEY_G",g);
- map.put("KEY_X",x);
- map.put("KEY_Y",y);
- return map;
- }
-
- //獲得標準的公鑰
- public PublicKey getPublicKey(BigInteger y,BigInteger p,BigInteger q,BigInteger g) throws NoSuchAlgorithmException, InvalidKeySpecException {
-
- DSAPublicKeySpec dsaPublicKeySpec = new DSAPublicKeySpec(y,p,q,g);
- KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
- //根據提供的密鑰規範(密鑰材料)生成公鑰對象
- return keyFactory.generatePublic(dsaPublicKeySpec);
- }
- //獲得標準的私鑰
- public PrivateKey getPrivateKey(BigInteger x,BigInteger p,BigInteger q,BigInteger g) throws NoSuchAlgorithmException, InvalidKeySpecException {
-
- DSAPrivateKeySpec dsaPrivateKeySpec = new DSAPrivateKeySpec(x,p,q,g);
- PrivateKey privateKey =null;
- KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
- //根據提供的密鑰規範(密鑰材料)生成私鑰對象
- privateKey= keyFactory.generatePrivate(dsaPrivateKeySpec);
- return privateKey;
- }
[java] view plain copy
- import javax.xml.bind.DatatypeConverter;
- import java.math.BigInteger;
- import java.util.Map;
-
-
- public class DsaSignTest {
- public static void main(String args[]) throws Exception {
- String str="123456";
- byte[] content=str.getBytes();
-
- //獲取DsaKey()內的HASHMAP裏面的鍵值對
- DsaSignCode dsaCode= new DsaSignCode();
- Map keyMap = dsaCode.DsaKey();
- BigInteger p= (BigInteger)keyMap.get("KEY_P");
- BigInteger q= (BigInteger)keyMap.get("KEY_Q");
- BigInteger g= (BigInteger)keyMap.get("KEY_G");
- BigInteger y= (BigInteger)keyMap.get("KEY_Y");
- BigInteger x= (BigInteger)keyMap.get("KEY_X");
-
- DsaSignCode dsaSignCode = new DsaSignCode();
- //簽名並存儲到數組內,再將其轉爲16進制
- byte[] dsaSignc = DsaSignCode.sign(content,dsaSignCode.getPrivateKey(x,p,q,g));
- String stringDate = DatatypeConverter.printHexBinary(dsaSignc);
- //驗證
- boolean veriftDsa= DsaSignCode.verify(content,dsaSignCode.getPublicKey(y,p,q,g),dsaSignc);
-
- System.out.println("P:"+p);
- System.out.println("Q:"+q);
- System.out.println("X:"+x);
- System.out.println("Y:"+y);
- System.out.println("G:"+g);
-
- System.out.println("簽名爲:"+stringDate);
- System.out.println("簽名驗證:"+veriftDsa);
- }
- }