數(shù)字簽名技術(shù) -- DSA算法
DSA算法是1991年美國國家標準技術(shù)協(xié)會公布的數(shù)字簽名標準(DSS)的核心算法浦箱。DSA算法本質(zhì)是ElGamal數(shù)字簽名算法棒掠,僅能與SHA系列算法結(jié)合,沒有相應(yīng)的MD融合算法蜂绎。
DSA算法和RSA算法的異同
DSA算法是DSS技術(shù)的核心算法娇昙,與RSA算法的異同如下:
- 二者都是數(shù)字簽名算法中的重要組成谓晌,缺一不可具温;
- DSA算法僅僅包含數(shù)字簽名算法蚕涤,一般不用于加密算法中;
- DSA算法僅產(chǎn)生數(shù)字證書铣猩,信息僅能用于驗證揖铜,不適合進行加密通信,所以HTTPS不會使用這個算法剂习;
- RSA算法包含加解密的密鑰信息蛮位,同時可作為數(shù)字簽名算法较沪;
下面是一段DSA和RSA的不同的比較原文鳞绕,可以參考下:
The main difference is in RSA ,message hash value is generated then this hash value is encryption using sender's private key this is treated as a signature and this signature is pretended with message .then receiver side perform decryption using sender's public key and this compare with new hash value that are generate by msg if both are same then msg is accepted otherwise rejected.
But in DSS approach additional add a signing algorithm that take input as a hash value of msg,random key ,global public key and sender's private key then the output is pretended to the msg . at receiver side pass the result (output), signature and msg, as well as global public key using this four take as the input of verification function then output of verification function is compare with result. The main difference is in RSA compare with hash value other hand in DSS output of verification is compare with result.
算法基本流程
- 發(fā)送方:使用信息摘要算法對原始數(shù)據(jù)計算
摘要
; - 發(fā)送方:產(chǎn)生一個隨機數(shù)尸曼,將
摘要
信息们何、隨機數(shù)
、私鑰
控轿、全局公鑰
(不是私鑰對應(yīng)的公鑰)傳入到算法中冤竹; - 發(fā)送方:算法計算一個簽名串,將簽名串和原始數(shù)據(jù)一起傳輸茬射;
- 接收方:對原始數(shù)據(jù)計算
摘要
鹦蠕; - 接收方:將接受到的簽名串發(fā)送給驗證函數(shù),驗證函數(shù)使用
發(fā)送方公鑰
和全局公鑰
來比較驗證簽名信息在抛;
算法家族
包含:SHA1withDSA
钟病、SHA224withDSA
、SHA256withDSA
刚梭、SHA384withDSA
肠阱、SHA512withDSA
五種算法。
密鑰長度都是512-1024位朴读。
Java中的算法實現(xiàn)
JDK實現(xiàn)了DSA算法屹徘,但僅僅實現(xiàn)了SHA1withDSA
算法。
示例代碼衅金,代碼和RSA數(shù)字簽名算法的一樣噪伊,只不過是算法名字變了下,可見Java的API設(shè)計還是很不錯的氮唯。
public class SignatureTest {
//唯一不一樣的是這里
public static final String SIGN_ALGORITHM = "SHA1withDSA";
private static final String KEY_ALGORITHM = "RSA";
private static final int KEY_SIZE = 1024;
public static void main(String[] args) throws Exception {
KeyPair keyPair = initKey();
String input = "Sign Me";
byte[] sign = sign(input.getBytes(), keyPair.getPrivate().getEncoded());
boolean verify = verify(input.getBytes(), sign, keyPair.getPublic().getEncoded());
String msg = String.format("原始數(shù)據(jù): %s , Sign : %s , Verify : %s", input, toBase64(sign), verify);
System.out.println(msg);
// 從二進制位角度看,sign的長度和密鑰長度一致
System.out.println("Sign Size : " + (sign.length * 8) + " Key Size : " + KEY_SIZE);
}
public static KeyPair initKey() throws Exception {
KeyPairGenerator keyPairGr = KeyPairGenerator.getInstance(KEY_ALGORITHM);
keyPairGr.initialize(KEY_SIZE);
KeyPair keyPair = keyPairGr.generateKeyPair();
return keyPair;
}
public static byte[] sign(byte[] data, byte[] privateKey) throws Exception {
// 將byte[]的key格式化回來
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
// 獲取算法實例并初始化
Signature signature = Signature.getInstance(SIGN_ALGORITHM);
signature.initSign(priKey);
signature.update(data);
byte[] sign = signature.sign();
return sign;
}
public static boolean verify(byte[] data, byte[] sign, byte[] publicKey) throws Exception {
// 獲取算法實例并初始化
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKey);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
Signature signature = Signature.getInstance(SIGN_ALGORITHM);
signature.initVerify(pubKey);
signature.update(data);
// 驗證數(shù)據(jù)和簽名是否一致,放否認,放篡改
boolean verify = signature.verify(sign);
return verify;
}
public static String toBase64(byte[] data) {
return new String(Base64.getEncoder().encode(data));
}
}