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所示。

figure_0319_0076

需要注意的是,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算法签名长度与密钥长度无关,但可能与待签名数据存在某种关联。