Java ECDSA使用总结

1.  说明

与合作机构对接时,合作机构使用ECDSA算法用于交易签名。

ECDSA为公开密钥加密算法。

以下为wiki(https://zh.wikipedia.org/wiki/%E6%A4%AD%E5%9C%86%E6%9B%B2%E7%BA%BF%E6%95%B0%E5%AD%97%E7%AD%BE%E5%90%8D%E7%AE%97%E6%B3%95)中关于ECDSA的说明:

椭圆曲线数字签名算法(Elliptic Curve Digital Signature Algorithm,缩写ECDSA)是一种被广泛应用于数字签名的加密算法。

2.  Java对ECDSA的支持

2.1  JDK支持

参考“Java Cryptography Architecture Oracle Providers Documentation for JDK 8”(https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html)。

JDK 8的SunEC Provider支持的ECDSA算法如下:

NONEwithECDSA

SHA1withECDSA

SHA224withECDSA

SHA256withECDSA

SHA384withECDSA

SHA512withECDSA

默认密钥长度为256,支持的密钥长度为112至571(含)。

以下均使用JDK支持的ECDSA实现。

2.2  bouncycastle支持

bouncycastle提供了对ECDSA的支持,说明略。

3.  密钥生成

3.1  Java生成

可使用以下Java代码生成ECDSA密钥对。

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
keyPairGenerator.initialize(
256);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
ECPublicKey ecPublicKey = (ECPublicKey) keyPair.getPublic();
ECPrivateKey ecPrivateKey = (ECPrivateKey) keyPair.getPrivate();

KeyPairGenerator类的initialize方法用于设置密钥长度;

ECPublicKey对象为生成的ECDSA公钥;

ECPrivateKey对象为生成的ECDSA私钥。

3.2  openssl生成

可使用以下openssl命令生成ECDSA密钥对。

openssl ecparam -list_curves

openssl ecparam -genkey -name secp521r1 -noout -out ECDSAPrivateKey.pem

openssl ec -in ECDSAPrivateKey.pem -pubout -outform PEM -out ECDSAPublicKey.pem

“openssl ecparam -list_curves”命令用于查看EC参数。

“openssl ecparam -genkey”命令用于生成ECDSA私钥。

“openssl ec -in ... -pubout”命令用于根据ECDSA私钥生成ECDSA公钥。

4.  PEM密钥文件读取

使用openssl命令生成的ECDSA密钥为PEM格式,不是二进制形式,私钥内容经过BASE64编码后,包含在“-----BEGIN EC PRIVATE KEY-----”与“-----END EC PRIVATE KEY-----”之间。

可使用bouncycastle的PEMReader类读取PEM密钥文件中的密钥,读取ECDSA私钥的示例代码如下:

PEMReader pemReader = new PEMReader(new FileReader([私钥文件路径]));

  

Security.addProvider(new BouncyCastleProvider());

  

KeyPair keyPair = (KeyPair) pemReader.readObject();

  

  return keyPair.getPrivate();

5.  生成签名

5.1  生成签名示例代码

生成ECDSA签名示例代码如下:

Signature signature = Signature.getInstance(algorithm);

signature.initSign(privateKey);

signature.update(bytes);

  byte[] signResult = signature.sign();

以上algorithm为String类型的签名算法,如“NONEwithECDSA”“SHA1withECDSA”等;

privateKey为PrivateKey类型的私钥;

bytes为byte[]类型的原始数据;

byte[] signResult为签名结果。

5.2  NONEwith与SHA[x]with算法的区别

当使用“NONEwithECDSA”算法进行签名时,直接对原始数据进行ECDSA签名,不会事先对原始数据进行HASH。

当使用“SHA[x]withECDSA”算法进行签名时,会先对原始数据进行SHA[x]算法HASH,再对HASH结果的二进制形式进行ECDSA签名。

HASH示例代码如下:

MessageDigest md = MessageDigest.getInstance(algorithm);

  byte[] digestResult = md.digest(bytes);

以上algorithm为String类型的签名算法,如“SHA-1”“SHA-256”等,对应ECDSA算法中的“SHA[x]”;

bytes为byte[]类型的原始数据;

byte[] digestResult为HASH结果。

通过以上代码先使用SHA[x]算法生成原始数据的HASH,再对HASH结果的二进制形式进行ECDSA签名,与直接使用“SHA[x]withECDSA”算法对原始数据进行ECDSA签名,效果相同。

5.3  签名结果不唯一

经测试,使用相同的原始数据,相同的算法,生成ECDSA签名时,每次产生的签名结果的长度与内容均可能不同。

关于以上现象,“Deterministic Usage of the Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA)”(https://www.ietf.org/rfc/rfc6979.txt)有以下说明:

One characteristic of DSA and ECDSA is that they need to produce, for each signature generation, a fresh random value (hereafter designated as k).  For effective security, k must be chosen randomly and uniformly from a set of modular integers, using a cryptographically secure process.

DSA和ECDSA的一个特征是它们需要为每个签名生成产生新的随机值(以下称为k)。为了有效的安全性,必须使用加密安全过程从一组模块化整数中随机均匀地选择k。

6.  签名验证

合作机构系统不使用Java实现,使用openssl库对ECDSA签名进行验证。

因此以下使用openssl命令验证ECDSA签名。

6.1  openssl命令

openssl的dgst命令可用于数字签名与验证,说明可见https://wiki.openssl.org/index.php/Command_Line_Utilities#Signing_.2F_Digest

OpenSSL 1.0.1e版本的dgst命令,支持的ecdsa-with-SHA[x]算法如下:

ecdsa-with-SHA1

dgst命令,支持的sha[x]算法如下:

sha1

sha224

sha256

sha384

sha512

使用ecdsa-with-SHA[x]算法与sha[x]算法的验证效果相同。

[x]与前文生成签名Java代码的SHA[x]withECDSA中的[x]应一致,在生成签名与验证签名时,使用相同的算法。

6.2  签名验证命令

6.2.1  使用文件作为原始数据

可使用以下命令验证签名:

openssl dgst -ecdsa-with-SHA[x] -verify [公钥文件] -signature [签名结果文件] [原始文件]

openssl dgst -sha[x] -verify [公钥文件] -signature [签名结果文件] [原始文件]

以上[公钥文件]应为[签名结果文件]生成时使用的私钥(对应前文生成签名Java代码中的PrivateKey privateKey)对应的公钥;

[签名结果文件]为签名结果(对应前文生成签名Java代码中的byte[] signResult)的二进制形式保存的文件;

[原始文件]为原始数据(对应前文生成签名Java代码中的byte[] bytes)的二进制形式保存的文件。

6.2.2  使用标准输入作为原始数据

也可使用以下使用以下命令验证签名:

echo [原始数据] | openssl dgst -ecdsa-with-SHA[x] -verify [公钥文件] -signature [签名结果文件]

echo [原始数据] | openssl dgst -sha[x] -verify [公钥文件] -signature [签名结果文件]

[原始数据]为原始数据(对应前文生成签名Java代码中的byte[] bytes)的字符串形式,需要为可见字符。

6.2.3  验证结果

当签名验证成功时,提示为“Verified OK”;验证失败时,提示为“Verification Failure”;命令有误时,提示为其他信息。

经测试,使用前文的Java代码,先通过SHA[x]算法生成原始数据的HASH,再对HASH结果的二进制形式进行ECDSA签名,与直接使用“SHA[x]withECDSA”算法对原始数据进行ECDSA签名,生成的签名均能通过验证。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ECDSA是一种基于椭圆曲线密码学的数字签名算法,Java中提供了相应的API来实现ECDSA。下面是一个简单的示例代码: ```java import java.security.*; import java.security.spec.*; import java.math.BigInteger; public class ECDSASample { public static void main(String[] args) throws Exception { // 生成密钥对 KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC"); SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); keyGen.initialize(256, random); KeyPair pair = keyGen.generateKeyPair(); PrivateKey privateKey = pair.getPrivate(); PublicKey publicKey = pair.getPublic(); // 显示公钥和私钥 System.out.println("Private key: " + bytesToHex(privateKey.getEncoded())); System.out.println("Public key: " + bytesToHex(publicKey.getEncoded())); // 签名数据 String data = "hello"; Signature ecdsa = Signature.getInstance("SHA256withECDSA"); ecdsa.initSign(privateKey); ecdsa.update(data.getBytes("UTF-8")); byte[] signature = ecdsa.sign(); System.out.println("Signature: " + bytesToHex(signature)); // 验证签名 ecdsa.initVerify(publicKey); ecdsa.update(data.getBytes("UTF-8")); boolean result = ecdsa.verify(signature); System.out.println("Signature verification result: " + result); } private static String bytesToHex(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) { sb.append(String.format("%02x", b)); } return sb.toString(); } } ``` 在上面的示例代码中,首先使用`KeyPairGenerator`类生成一对公钥和私钥,然后使用`Signature`类对数据进行签名和验证。其中,签名算法使用的是SHA256withECDSA,密钥长度为256位。 需要注意的是,ECDSA算法的安全性与密钥长度有关,一般情况下建议使用256位或更长的密钥长度。此外,在实际应用中,还需要考虑密钥管理、密钥保护等问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值