如果你们其中一个人熟悉DSA算法,你能检查一下我是否理解算法吗?或者至少回答以下两个问题?我的工作基于Wikipedia DSA article。
我尽量让代码尽可能清晰地阅读。
public static class KeyGenerator {
private final BigInteger TWO = new BigInteger("2");
private final BigInteger P, Q, G;
public KeyGenerator(int pLength) {
this.Q = generateQ();
this.P = generateP(Q,pLength);
this.G = generateG(P,Q,TWO);
}
private BigInteger generateQ() {
return BigInteger.probablePrime(160, new Random());
}
private BigInteger generateP(BigInteger Q, int l) {
//l should be multiple of 64
if(l%64!=0) throw new InvalidParameterException("64 should divide l");
//P is prime and P mod Q == 1 ( i.e. P-1 = Q*Z )
BigInteger P = BigInteger.probablePrime(512, new Random());//We generate a potential random P
BigInteger remainder = P.mod(Q);//We calculate the remainder
P = P.subtract(remainder).add(BigInteger.ONE);//We make P being P = Q*Z + 1 by removing the remainder
while(!P.isProbablePrime(100)) {P = P.add(Q);}//Z++ until P = Q*Z + 1 is primal
//P has to be l bits (l = 512 or 1024 generally)
if(P.bitCount()>l) {return generateP(Q,l);}
return P;
}
private BigInteger generateG(BigInteger P, BigInteger Q, BigInteger H) {
//G is H^((P-1)/Q) mod P with H being any value 1<H<Q
BigInteger G = H.modPow(P.subtract(BigInteger.ONE).divide(Q),P);
if(G.compareTo(BigInteger.ONE)<=0) return generateG(P, Q, H.add(BigInteger.ONE));//G must be >1
return G;
}
public KeyPair generateKeyPair() {
BigInteger privateKey = new BigInteger(159, new Random());//private key should be <Q, but Q is 160 bits.
//public key is G^X mod P where X is the private key
BigInteger publicKey = G.modPow(privateKey,P);
return new KeyPair(privateKey, publicKey);
}
}
public static class SignatureMaker {
...
public Signature sign(String message) {
BigInteger K = new BigInteger(159,new Random());//Random K < Q
BigInteger R = G.modPow(K, P).mod(Q);//R = G^K mod P mod Q
if(R.compareTo(BigInteger.ZERO)==0) {return sign(message);}//R should be >0
BigInteger M = new BigInteger(DigestUtils.sha1(message));//M = sha1(message) (i.e. M = H(m))
BigInteger S = K.modInverse(Q).multiply(M.add(privateKey.multiply(R))).mod(Q);//S = K^-1*(H(m)+X*R) mod Q
if(S.compareTo(BigInteger.ZERO)==0) {return sign(message);}//S should be >0
return new Signature(R, S);
}
}
public static class SignatureChecker {
...
public boolean check(String message, Signature signature) {
BigInteger R = signature.R;
BigInteger S = signature.S;
if(R.signum()<1 || R.compareTo(Q)>=0 || S.signum()<1 || S.compareTo(Q)>=0) return false;//0<R<Q and 0<S<Q
BigInteger W = S.modInverse(Q);//W = S^-1 mod Q
BigInteger M = new BigInteger(DigestUtils.sha1(message));//M = sha1(message) i.e. M = H(m)
BigInteger U1 = M.multiply(W).mod(Q);//U1 = (H(M)*W) mod Q
BigInteger U2 = R.multiply(W).mod(Q);//U2 = (R*W) mod Q
BigInteger V = G.modPow(U1, P).multiply(publicKey.modPow(U2, P)).mod(P).mod(Q);//V = (G^U1 mod P)*(Y^U2 mod P) mod P mod Q
return V.compareTo(R)==0;//Valid only if V==R
}
}
我进行了一些测试,似乎有效,但这并不意味着我没有犯任何错误。
我特别不确定S
期间sign
和V
期间check
的计算,因为我无法确定公式这是用维基百科写的。
[在评论中解决] 我也完全不明白为什么维基百科中的算法会在验证过程中要求mod P mod Q
。通常,mod P mod Q应返回与mod Q ...
如果你看到可能的改善,我也很乐意接受它。
非常感谢!