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);
- }
- }