DSA数字签名原理及JAVA实现

    DSA数字签名是Elgamal和Schnorr数字签名的一个变种,DSA数字签名优于Elgamal数字签名的地方在于它的签名长度较短,并且某些可以破解Elgamal方案的攻击不适用DSA数字签名,DSA数字签名的原理如下:

1. 首先生成一个素数p,p满足 2^L-1<p<2^L ;

注:关于L的值的范围看到两种不同的说法

a):L是1024、2048、3072三个值中的一个

b):L满足512<=L<=1024 ,且L是64的倍数

2. 然后再生成q,再此处,假定L=1024,找到一个素数q,q满足 q能整除p-1,即          (p-1)mod q=0,且2^159< q <2^160;

3. 然后再生成g;

g=h^(p-1)/qmod p,  h满足1<h<(p-1),并且g>1

4. 最后生成用户的私钥x和公钥y

  x是随机数或者伪随机数,且满足:0< x <q

  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=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.验证成功;

[java] view plain copy

  1. import java.math.BigInteger;  
  2. import java.security.*;  
  3. import java.security.interfaces.DSAParams;  
  4. import java.security.interfaces.DSAPrivateKey;  
  5. import java.security.spec.*;  
  6. import java.util.HashMap;  
  7. import java.util.Map;  
  8. import java.util.Random;  
  9.   
  10. public class DsaSignCode {  
  11.   
  12.     private static final String SIGNATURE_ALGORITHM="SHA1withDSA";  
  13.     private static final String ALGORITHM = "DSA";  
  14.     private static final int KEY_SIZE = 1024;  
  15.   
  16. //    该方法取一个随机x,x小于q并且大于0,  
  17.     private static BigInteger randbint(BigInteger n){  
  18.         Random rnd = new Random();  
  19.         int maxNumBitLength = n.bitLength();  
  20.         BigInteger aRandomBigInt;  
  21.         do{  
  22.             aRandomBigInt = new BigInteger(maxNumBitLength, rnd);  
  23.         }while (aRandomBigInt.compareTo(n) > 0);  
  24.         return aRandomBigInt;  
  25.     }  
  26.   
  27.     public Map<String,BigInteger> DsaKey() throws NoSuchAlgorithmException {  
  28.   
  29.         KeyPairGenerator keyGen = KeyPairGenerator.getInstance(ALGORITHM);  
  30.         //初始化  
  31.         keyGen.initialize(KEY_SIZE);  
  32.         KeyPair keyPair = keyGen.genKeyPair();  
  33.         //使用KeyPair生成密钥  
  34.         DSAPrivateKey privateKey = (DSAPrivateKey) keyPair.getPrivate();  
  35. //        DSAPublicKey publicKey = (DSAPublicKey) keyPair.getPublic();  
  36.         DSAParams dsaParams = privateKey.getParams();  
  37.         BigInteger p = dsaParams.getP();  
  38.         BigInteger q = dsaParams.getQ();  
  39.         BigInteger g = dsaParams.getG();  
  40.         BigInteger x = randbint(q);  
  41.         BigInteger y = g.modPow(x, p);  
  42.         //使用HASHMAP存储p,q,g,x,y  
  43.         Map<String,BigInteger> map = new HashMap<String,BigInteger>(5);  
  44.         map.put("KEY_P",p);  
  45.         map.put("KEY_Q",q);  
  46.         map.put("KEY_G",g);  
  47.         map.put("KEY_X",x);  
  48.         map.put("KEY_Y",y);  
  49.         return map;  
  50.     }  
  51.   
  52.     //得到标准的公钥  
  53.     public PublicKey getPublicKey(BigInteger y,BigInteger p,BigInteger q,BigInteger g) throws NoSuchAlgorithmException, InvalidKeySpecException {  
  54.   
  55.         DSAPublicKeySpec dsaPublicKeySpec = new DSAPublicKeySpec(y,p,q,g);  
  56.         KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);  
  57.         //根据提供的密钥规范(密钥材料)生成公钥对象  
  58.         return keyFactory.generatePublic(dsaPublicKeySpec);  
  59.     }  
  60.     //得到标准的私钥  
  61.     public PrivateKey getPrivateKey(BigInteger x,BigInteger p,BigInteger q,BigInteger g) throws NoSuchAlgorithmException, InvalidKeySpecException {  
  62.   
  63.         DSAPrivateKeySpec dsaPrivateKeySpec = new DSAPrivateKeySpec(x,p,q,g);  
  64.         PrivateKey privateKey =null;  
  65.         KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);  
  66.         //根据提供的密钥规范(密钥材料)生成私钥对象  
  67.         privateKey= keyFactory.generatePrivate(dsaPrivateKeySpec);  
  68.         return privateKey;  
  69.     }  

[java] view plain copy

  1. import javax.xml.bind.DatatypeConverter;  
  2. import java.math.BigInteger;  
  3. import java.util.Map;  
  4.   
  5.   
  6. public class DsaSignTest {  
  7.     public static void main(String args[]) throws Exception {  
  8.         String str="123456";  
  9.         byte[] content=str.getBytes();  
  10.   
  11.         //获取DsaKey()内的HASHMAP里面的键值对  
  12.         DsaSignCode dsaCode= new DsaSignCode();  
  13.         Map keyMap = dsaCode.DsaKey();  
  14.         BigInteger p= (BigInteger)keyMap.get("KEY_P");  
  15.         BigInteger q= (BigInteger)keyMap.get("KEY_Q");  
  16.         BigInteger g= (BigInteger)keyMap.get("KEY_G");  
  17.         BigInteger y= (BigInteger)keyMap.get("KEY_Y");  
  18.         BigInteger x= (BigInteger)keyMap.get("KEY_X");  
  19.   
  20.         DsaSignCode dsaSignCode = new DsaSignCode();  
  21.         //签名并存储到数组内,再将其转为16进制  
  22.         byte[] dsaSignc = DsaSignCode.sign(content,dsaSignCode.getPrivateKey(x,p,q,g));  
  23.         String stringDate = DatatypeConverter.printHexBinary(dsaSignc);  
  24.         //验证  
  25.         boolean veriftDsa= DsaSignCode.verify(content,dsaSignCode.getPublicKey(y,p,q,g),dsaSignc);  
  26.   
  27.         System.out.println("P:"+p);  
  28.         System.out.println("Q:"+q);  
  29.         System.out.println("X:"+x);  
  30.         System.out.println("Y:"+y);  
  31.         System.out.println("G:"+g);  
  32.   
  33.         System.out.println("签名为:"+stringDate);  
  34.         System.out.println("签名验证:"+veriftDsa);  
  35.     }  
  36. }  

猜你喜欢

转载自my.oschina.net/u/3805464/blog/1824819
今日推荐