9.4.2 实现
Java 6提供了DSA算法实现,在实现层面,我们可以认为DSA算法实现就是RSA数字签名算法实现的简装版。与RSA数字签名算法实现相比,DSA算法仅支持SHA系列的消息摘要算法。Java 6仅支持SHA1withDSA算法,通过Bouncy Castle可以扩展SHA224withDSA、SHA256withDSA、SHA384withDSA和SHA512withDSA共4种数字签名算法。
有关DSA算法的Java 6实现和Bouncy Castle实现如表9-2所示。
需要注意的是,DSA密钥长度默认为1024位,密钥长度必须是64的倍数,范围在512~1024位之间(含)。DSA算法的签名长度与密钥长度无关,且长度不唯一。
具体实现如代码清单9-5所示。
代码清单9-5 DSA算法实现
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
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 java.util.HashMap;
import java.util.Map;
/**
*DSA安全编码组件
*@author梁栋
*@version 1.0
*/
public abstract class DSACoder{
//数字签名密钥算法
public static final String ALGORITHM="DSA";
/**
*数字签名
*签名/验证算法
*/
public static final String SIGNATURE_ALGORITHM="SHA1withDSA";
//公钥
private static final String PUBLIC_KEY="DSAPublicKey";
//私钥
private static final String PRIVATE_KEY="DSAPrivateKey";
/**
*DSA密钥长度
*默认1024位
*密钥长度必须是64的倍数
*范围在512~1024位之间(含)
*/
private static final int KEY_SIZE=1024;
/**
*签名
*@param data待签名数据
*@param privateKey私钥
*@return byte[]数字签名
*@throws Exception
*/
public static byte[]sign(byte[]data, byte[]privateKey)throws Exception{
//还原私钥
//转换私钥材料
PKCS8EncodedKeySpec pkcs8KeySpec=new PKCS8EncodedKeySpec(privateKey);
//实例化密钥工厂
KeyFactory keyFactory=KeyFactory.getInstance(ALGORITHM);
//生成私钥对象
PrivateKey priKey=keyFactory.generatePrivate(pkcs8KeySpec);
//实例化Signature
Signature signature=Signature.getInstance(SIGNATURE_ALGORITHM);
//初始化Signature
signature.initSign(priKey);
//更新
signature.update(data);
//签名
return signature.sign();
}
/**
*校验
*@param data待校验数据
*@param publicKey公钥
*@param sign数字签名
*@return boolean校验成功返回true失败返回false
*@throws Exception
*/
public static boolean verify(byte[]data, byte[]publicKey, byte[]sign)
throws Exception{
//还原公钥
//转换公钥材料
X509EncodedKeySpec keySpec=new X509EncodedKeySpec(publicKey);
//实例化密钥工厂
KeyFactory keyFactory=KeyFactory.getInstance(ALGORITHM);
//取公钥匙对象
PublicKey pubKey=keyFactory.generatePublic(keySpec);
//实例话Signature
Signature signature=Signature.getInstance(SIGNATURE_ALGORITHM);
//初始化Signature
signature.initVerify(pubKey);
//更新
signature.update(data);
//验证
return signature.verify(sign);
}
/**
*生成密钥
*@return密钥对象
*@throws Exception
*/
public static Map<String, Object>initKey()throws Exception{
//初始化密钥对生成器
KeyPairGenerator keygen=KeyPairGenerator.getInstance(ALGORITHM);
//实例化密钥对生成器
keygen.initialize(KEY_SIZE, new SecureRandom());
//实例化密钥对
KeyPair keys=keygen.genKeyPair();
DSAPublicKey publicKey=(DSAPublicKey)keys.getPublic();
DSAPrivateKey privateKey=(DSAPrivateKey)keys.getPrivate();
//封装密钥
Map<String, Object>map=new HashMap<String, Object>(2);
map.put(PUBLIC_KEY, publicKey);
map.put(PRIVATE_KEY, privateKey);
return map;
}
/**
*取得私钥
*@param keyMap密钥Map
*@return byte[]私钥
*@throws Exception
*/
public static byte[]getPrivateKey(Map<String, Object>keyMap)throws Exception{
Key key=(Key)keyMap.get(PRIVATE_KEY);
return key.getEncoded();
}
/**
*取得公钥
*@param keyMap密钥Map
*@return byte[]公钥
*@throws Exception
*/
public static byte[]getPublicKey(Map<String, Object>keyMap)throws Exception{
Key key=(Key)keyMap.get(PUBLIC_KEY);
return key.getEncoded();
}
}
DSA算法实现是最为简单的数字签名算法,若仅仅需要使用数字签名算法,则DSA算法是不错的选择。当然,DSA算法使用起来就更为简单了,测试用例如代码清单9-6所示。
代码清单9-6 DSA算法实现测试用例
import static org.junit.Assert.*;
import java.util.Map;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.junit.Before;
import org.junit.Test;
/**
*DSA签名校验
*@author梁栋
*@version 1.0
*/
public class DSACoderTest{
//公钥
private byte[]publicKey;
//私钥
private byte[]privateKey;
/**
*初始化密钥
*@throws Exception
*/
@Before
public void initKey()throws Exception{
Map<String, Object>keyMap=DSACoder.initKey();
publicKey=DSACoder.getPublicKey(keyMap);
privateKey=DSACoder.getPrivateKey(keyMap);
System.err.println("公钥:\n"+Base64.encodeBase64String(publicKey));
System.err.println("私钥:\n"+Base64.encodeBase64String(privateKey));
}
/**
*校验签名
*@throws Exception
*/
@Test
public void test()throws Exception{
String inputStr="DSA数字签名";
byte[]data=inputStr.getBytes();
//产生签名
byte[]sign=DSACoder.sign(data, privateKey);
System.err.println("签名:\r"+Hex.encodeHexString(sign));
//验证签名
boolean status=DSACoder.verify(data, publicKey, sign);
System.err.println("状态:\r"+status);
assertTrue(status);
}
}
DSA算法的公钥长度略长于私钥,如下所示:
公钥:
MIIBuDCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2US
ZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fn
xqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouu
EC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJ
FnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImo
g9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYUAAoGBAO/C7ZQWHB6bT1W9NAwTEK+VsMXHe7cphNPAY
Hhewy6kpNvfiuANtKF02FrmOtZ+N+sAC7GBrlviL5OBMdD/5j7/NeuMZsIMTjNZ4jLn5EzU/nuxbQPEhx
xIngXj/Wh4It43MVDYBo0Z+pqjPL2vS/QBh4z8rz4ezOYGGxV2B3mw
私钥:
MIIBTAIBADCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2Ebd
SPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClp
J+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmC 
ouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZ
T+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ
7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoEFwIVAIB5fpdgw0p7LP/M8X9lVOidqLej
注意控制台输出的签名及验证结果,如下所示:
签名:
302d021409e9d5a41a479a2ec08151fd21b6965a8f7d803e0215008b18632b91b6cd1d07a9f8db40bc98a65144c89a
状态:
true
DSA算法签名长度与密钥长度无关,但可能与待签名数据存在某种关联。