密码学 DSA算法
Digital Signature Algorithm (DSA)是Schnorr和ElGamal签名算法的变种,被美国NIST作为DSS(DigitalSignature Standard)。
算法步骤
算法中应用了下述参数: 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(FIPS186-4)中选用SHA-1或者SHA-2( Secure Hash Algorithm系列中的2个较新版本,其中SHA-2有4个,SHA-224,SHA-256,SHA-384,SHA-512,最原始的SHA已经不再被使用)。 p, q, g可由一组用户共享,但在实际应用中,使用公共模数可能会带来一定的威胁。签名及验证协议如下:
- P产生随机数k,k < q;
- P计算 r = ( g^k mod p ) mod q s = ( k^(-1) (H(m) + xr)) mod q 签名结果是( m, r, s )。
- 验证时计算 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,则认为签名有效。 DSA是基于整数有限域离散对数难题的,其安全性与RSA相比差不多。DSA的一个重要特点是两个素数公开,这样,当使用别人的p和q时,即使不知道私钥,你也能确认它们是否是随机产生的,还是作了手脚。RSA算法却做不到。
JAVA代码实现
(1)编码实现DSA算法,源代码如下:
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.DSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.xml.bind.DatatypeConverter;
public class DSAUtil {
private static String src = "I LOVE CHINA!";
public static void main(String[] args) {
jdkDSA();
}
public static void jdkDSA() {
// 1. 初始化 秘钥
try {
KeyPairGenerator generator = KeyPairGenerator.getInstance("DSA");
generator.initialize(512);
KeyPair keyPair = generator.generateKeyPair();
DSAPublicKey dsaPublicKey = (DSAPublicKey) keyPair.getPublic();
DSAPrivateKey dsaPrivateKey = (DSAPrivateKey) keyPair.getPrivate();
System.out.println("public="+dsaPublicKey);
System.out.println("x="+dsaPrivateKey.getX());
// 2。 执行签名
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(dsaPrivateKey.getEncoded());
KeyFactory factory = KeyFactory.getInstance("DSA");
PrivateKey privateKey = factory.generatePrivate(pkcs8EncodedKeySpec);
Signature signature = Signature.getInstance("SHA1withDSA");
signature.initSign(privateKey);
signature.update(src.getBytes());
byte[] sign = signature.sign();
System.out.println("sign=\n"+DatatypeConverter.printHexBinary(sign));
// 验证签名
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(dsaPublicKey.getEncoded());
factory = KeyFactory.getInstance("DSA");
PublicKey publicKey = factory.generatePublic(x509EncodedKeySpec);
signature = Signature.getInstance("SHA1withDSA");
signature.initVerify(publicKey);
signature.update(src.getBytes());
boolean verify = signature.verify(sign);
System.out.println(verify);
} catch (Exception e) {
e.printStackTrace();
}
}
}
解析
1、KeyPairGenerator KeyPairGenerator 类用于生成公钥和私钥对。密钥对生成器是使用 getInstance 工厂方法(返回一个给定类的实例的静态方法)构造的。 特定算法的密钥对生成器可以创建能够与此算法一起使用的公钥/私钥对。它还可以将特定于算法的参数与每个生成的密钥关联。 有两种生成密钥对的方式:与算法无关的方式和特定于算法的方式。 下面我们将按照指定RSA算法去生成秘钥KeyPairGenerator.getInstance("RSA"); 2、DSAPublicKey DSA 公用密钥的接口 3、DSAPublicKey DSA 专用密钥的接口 4、PKCS8EncodedKeySpec PKCS8EncodedKeySpec类继承EncodedKeySpec类,以编码格式来表示私钥。 PKCS8EncodedKeySpec类使用PKCS#8标准作为密钥规范管理的编码格式 5、Signature Signature 类用来为应用程序提供数字签名算法功能。数字签名用于确保数字数据的验证和完整性。 在所有算法当中,数字签名可以是 NIST 标准的 DSA,它使用 DSA 和 SHA-1。可以将使用 SHA-1 消息摘要算法的 DSA 算法指定为 SHA1withDSA。
实验例子
①选取密钥
q= fca682ce 8e12caba 26efccf7 110e526d b078b05e decbcd1e b4a208f3 ae1617ae 01f35b91 a47e6df6 3413c5e1 2ed0899b cd132acd 50d99151 bdc43ee7 37592e17 ,
p= 962eddcc 369cba8e bb260ee6 b6a126d9 346e38c5
,
g= 678471b2 7a9cf44e e91a49c5 147db1a9 aaf244f0 5a434d64 86931d2d 14271b9e
35030b71 fd73da17 9069b32e 2935630e 1c206235 4d0da20a 6c416e50 be794ca4 ;
x=138516119351592938244070748724284462948007803693 ,
y= 49db7b9c a9183fbb 00a501e7 6daf9d92 860858cd adf45cfb 9d872326 3dd7c6b5 4fc5f98e adba02dc f3ba65c3 5f3514d8 4c9c9425 ee761ceb a54a05ed 084e3e7c 。
对明文“I LOVE CHINA.”生成签名消息
302D021500833DF27D1E55304611F1E82AF7602747D85F01DA0214711A399689EF29756E3D46A59CBE219C9E590A67
更多建议: