@TOC
1. 算法简述
该算法是微软操作系统及办公软件的序列号验证算法。
ECDSA(Elliptic Curve Digital Signature Algorithm, 椭圆曲线数字签名算法) 于1999年作为ANSI标准, 并于2000年成为IEEE和NIST标准。
ECDSA算法具有速度快、强度高、签名短等有点。
3. 代码实现
Java中未对该算法做实现, 而在Bouncy Castle中有该算法实现。
下面的表格说明了实现细节。
3.1 算法实现
基于Bouncy Castle的 ECDSA算法实现
package com.calvin.android.demo2.secrity;import org.bouncycastle.jce.ECNamedCurveTable;import org.bouncycastle.jce.provider.BouncyCastleProvider;import org.bouncycastle.jce.spec.ECParameterSpec;import java.security.Key;import java.security.KeyFactory;import java.security.KeyPair;import java.security.KeyPairGenerator;import java.security.PrivateKey;import java.security.Provider;import java.security.PublicKey;import java.security.SecureRandom;import java.security.Security;import java.security.Signature;import java.security.spec.PKCS8EncodedKeySpec;import java.security.spec.X509EncodedKeySpec;import java.util.HashMap;import java.util.Map;/*** Author:cl* Email:lhzheng@* Date:20-10-21*///java – 在BouncyCastle上使用数字签名算法(ECDSA)实现的椭圆曲线 /article/p-vmamxfcn-bup.htmlpublic class ECDSACoder {/*** 数字签名密钥算法*/public static final String KEY_ALGORITHM = "ECDSA";/*** 数字签名* 签名/验证算法*/public static final String SIGNATURE_ALGORITHM = "SHA1withECDSA";//公钥 Map Keyprivate static final String PUBLIC_KEY = "ECDSAPublicKey";//私钥Map keyprivate static final String PRIVATE_KEY = "ECDSAPrivateKey";/*** 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(KEY_ALGORITHM);//取私钥对象PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);//实例化SignatureSignature signature = Signature.getInstance(SIGNATURE_ALGORITHM, "BC");//初始化Signaturesignature.initSign(priKey);//更新signature.update(data);//签名return signature.sign();}/*** 校验* @param data 待校验数据* @param publicKey 公钥* @param sign 数字签名* @return boolean 校验成功返回true,校验失败返回false* @throws Exception*/public static boolean verity(byte[] data, byte[] publicKey, byte[] sign) throws Exception{//转换公钥材料X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);//实例化密钥工厂KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);//生成公钥PublicKey pubKey = keyFactory.generatePublic(keySpec);//实例化SignatureSignature signature = Signature.getInstance(SIGNATURE_ALGORITHM, "BC");//初始化Signaturesignature.initVerify(pubKey);//更新signature.update(data);//校验证return signature.verify(sign);}public static Map<String, Object> initKey() throws Exception {//实例化BC ProviderProvider bcProvider = new BouncyCastleProvider();Security.removeProvider("BC");Security.addProvider(bcProvider);ECParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec("B-571");//实例化密钥对生成器KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM, "BC");keyPairGen.initialize(ecSpec, new SecureRandom());//生成密钥对KeyPair keyPair = keyPairGen.generateKeyPair();//公钥PublicKey publicKey = (PublicKey)keyPair.getPublic();//私钥PrivateKey privateKey = (PrivateKey)keyPair.getPrivate();//封装密钥Map<String, Object> keyMap = new HashMap<>(2);keyMap.put(PUBLIC_KEY, publicKey);keyMap.put(PRIVATE_KEY, privateKey);return keyMap;}public static byte[] getPublicKey(Map<String, Object> keyMap){return ((Key)keyMap.get(PUBLIC_KEY)).getEncoded();}public static byte[] getPrivateKey(Map<String, Object> keyMap){return ((Key)keyMap.get(PRIVATE_KEY)).getEncoded();}}
3.2 测试代码
@Testpublic void ecdsaSignTest() throws Exception {//初始化密钥Map<String, Object> keyMap = ECDSACoder.initKey();byte[] publicKey = ECDSACoder.getPublicKey(keyMap);byte[] privateKey = ECDSACoder.getPrivateKey(keyMap);System.out.println("ECDSA公钥:\t"+Base64.encodeToString(publicKey, Base64.DEFAULT));System.out.println("ECDSA私钥:\t"+Base64.encodeToString(privateKey, Base64.DEFAULT));String inputStr = "ECDSA数字签名";byte[] data = inputStr.getBytes();//产生签名byte[] sign = ECDSACoder.sign(data, privateKey);System.out.println("ECDSA签名:\t"+ Hex.toHexString(sign));//验证签名boolean status = ECDSACoder.verity(data, publicKey, sign);System.out.println("ECDSA验签状态:\t"+ status);assertTrue(status);}
3.3 运行结果
-10-21 15:41:36.454 16472-16487/com.calvin.android.demo2 I/System.out: ECDSA公钥:MIGnMBAGByqGSM49AgEGBSuBBAAnA4GSAAQA9ile2ZpcTRb3y22xpaxeMcqJ0GuU8GuovBxpVnAC-10-21 15:41:36.455 16472-16487/com.calvin.android.demo2 I/System.out: xeEjE0UdFe8V+8T0cCrhCw8zkJjvv+lpAlX+NtedI1oIL9APgIzOFEACBNB5qQwFYQn9hh8PA5P+-10-21 15:41:36.455 16472-16487/com.calvin.android.demo2 I/System.out: y+QXTgw6ATLGPfxg73U7Ydp51ZPXLt5VivuN+dOynDpoY8nJhIuhC4N6aNde2P6R+0u8mz2HAJY=-10-21 15:41:36.455 16472-16487/com.calvin.android.demo2 I/System.out: ECDSA私钥:MIIBCQIBADAQBgcqhkjOPQIBBgUrgQQAJwSB8TCB7gIBAQRIA32LqVgupwwD8q7eItT6vM7X1xB8-10-21 15:41:36.455 16472-16487/com.calvin.android.demo2 I/System.out: OUZnP222ZEhIvLkHciYb7AQrRVX1XRuH2a8tX0LyH6YRHDBe9aPZkxyBpzkSGuaV9Ez8oAcGBSuB-10-21 15:41:36.455 16472-16487/com.calvin.android.demo2 I/System.out: BAAnoYGVA4GSAAQA9ile2ZpcTRb3y22xpaxeMcqJ0GuU8GuovBxpVnACxeEjE0UdFe8V+8T0cCrh-10-21 15:41:36.455 16472-16487/com.calvin.android.demo2 I/System.out: Cw8zkJjvv+lpAlX+NtedI1oIL9APgIzOFEACBNB5qQwFYQn9hh8PA5P+y+QXTgw6ATLGPfxg73U7-10-21 15:41:36.455 16472-16487/com.calvin.android.demo2 I/System.out: Ydp51ZPXLt5VivuN+dOynDpoY8nJhIuhC4N6aNde2P6R+0u8mz2HAJY=-10-21 15:41:36.705 16472-16487/com.calvin.android.demo2 I/System.out: ECDSA签名:3081940248019e556404e8cfae0f752bef094de22d35677f231aa2262f353371d1f518b7429b9f49390a19fd212652fb1b271d3bd2170f8b23594d81e4779f61aff13f130d104613479e91ad76024800e4eafe20e9980e0a402693207ec11546f9c2a1fca1aa6e25f9de0b8416fd91b03b62e7090592dda26dd094a2b1338e6801b439cf5072ada0522daa2ef8ecc5c422f46a4efb2b3c-10-21 15:41:36.854 16472-16487/com.calvin.android.demo2 I/System.out: ECDSA验签状态:true