高级数字签名之椭圆曲线数字签名算法(ECDSA)

@TOC

1. 算法简述

该算法是微软操作系统及办公软件的序列号验证算法。
ECDSA(Elliptic Curve Digital Signature Algorithm, 椭圆曲线数字签名算法) 于1999年作为ANSI标准, 并于2000年成为IEEE和NIST标准。

ECDSA算法具有速度快、强度高、签名短等有点。

3. 代码实现

Java中未对该算法做实现, 而在Bouncy Castle中有该算法实现。

下面的表格说明了实现细节。

算法密钥长度密钥默认长度签名长度备注
NONEwithECDSA、RIPEMD160withECDSA、SHA1withECDSA、SHA224withECDSA、SHA256withECDSA、SHA384withECDSA、SHA512withECDSA--128、160、160、224、256、384、512Bouncy 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@grandstream.cn
 * Date:20-10-21
 */
//java – 在BouncyCastle上使用数字签名算法(ECDSA)实现的椭圆曲线 http://www.voidcn.com/article/p-vmamxfcn-bup.html
public class ECDSACoder {
    /**
     * 数字签名密钥算法
     */
    public static final String KEY_ALGORITHM = "ECDSA";

    /**
     * 数字签名
     * 签名/验证算法
     */
    public static final String SIGNATURE_ALGORITHM = "SHA1withECDSA";

    //公钥 Map Key
    private static final String PUBLIC_KEY = "ECDSAPublicKey";
    //私钥Map key
    private 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);
        //实例化Signature
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM, "BC");
        //初始化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 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);
        //实例化Signature
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM, "BC");
        //初始化Signature
        signature.initVerify(pubKey);
        //更新
        signature.update(data);
        //校验证
        return signature.verify(sign);
    }

    public static Map<String, Object> initKey() throws Exception {
        //实例化BC Provider
        Provider 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 测试代码

@Test
    public 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 运行结果

2020-10-21 15:41:36.454 16472-16487/com.calvin.android.demo2 I/System.out: ECDSA公钥:	MIGnMBAGByqGSM49AgEGBSuBBAAnA4GSAAQA9ile2ZpcTRb3y22xpaxeMcqJ0GuU8GuovBxpVnAC
2020-10-21 15:41:36.455 16472-16487/com.calvin.android.demo2 I/System.out: xeEjE0UdFe8V+8T0cCrhCw8zkJjvv+lpAlX+NtedI1oIL9APgIzOFEACBNB5qQwFYQn9hh8PA5P+
2020-10-21 15:41:36.455 16472-16487/com.calvin.android.demo2 I/System.out: y+QXTgw6ATLGPfxg73U7Ydp51ZPXLt5VivuN+dOynDpoY8nJhIuhC4N6aNde2P6R+0u8mz2HAJY=
2020-10-21 15:41:36.455 16472-16487/com.calvin.android.demo2 I/System.out: ECDSA私钥:	MIIBCQIBADAQBgcqhkjOPQIBBgUrgQQAJwSB8TCB7gIBAQRIA32LqVgupwwD8q7eItT6vM7X1xB8
2020-10-21 15:41:36.455 16472-16487/com.calvin.android.demo2 I/System.out: OUZnP222ZEhIvLkHciYb7AQrRVX1XRuH2a8tX0LyH6YRHDBe9aPZkxyBpzkSGuaV9Ez8oAcGBSuB
2020-10-21 15:41:36.455 16472-16487/com.calvin.android.demo2 I/System.out: BAAnoYGVA4GSAAQA9ile2ZpcTRb3y22xpaxeMcqJ0GuU8GuovBxpVnACxeEjE0UdFe8V+8T0cCrh
2020-10-21 15:41:36.455 16472-16487/com.calvin.android.demo2 I/System.out: Cw8zkJjvv+lpAlX+NtedI1oIL9APgIzOFEACBNB5qQwFYQn9hh8PA5P+y+QXTgw6ATLGPfxg73U7
2020-10-21 15:41:36.455 16472-16487/com.calvin.android.demo2 I/System.out: Ydp51ZPXLt5VivuN+dOynDpoY8nJhIuhC4N6aNde2P6R+0u8mz2HAJY=
2020-10-21 15:41:36.705 16472-16487/com.calvin.android.demo2 I/System.out: ECDSA签名:	3081940248019e556404e8cfae0f752bef094de22d35677f231aa2262f353371d1f518b7429b9f49390a19fd212652fb1b271d3bd2170f8b23594d81e4779f61aff13f130d104613479e91ad76024800e4eafe20e9980e0a402693207ec11546f9c2a1fca1aa6e25f9de0b8416fd91b03b62e7090592dda26dd094a2b1338e6801b439cf5072ada0522daa2ef8ecc5c422f46a4efb2b3c
2020-10-21 15:41:36.854 16472-16487/com.calvin.android.demo2 I/System.out: ECDSA验签状态:	true
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Calvin880828

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值