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方法用于设置密钥长度;
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私钥的示例代码如下:
|
5. 生成签名
5.1 生成签名示例代码
生成ECDSA签名示例代码如下:
|
以上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示例代码如下:
|
以上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签名,生成的签名均能通过验证。
还没有评论,来说两句吧...