dromara / hutool

🍬A set of tools that keep Java sweet.
https://hutool.cn
Other
28.91k stars 7.48k forks source link

sm2算法的优化以及新规定的迭代 #3630

Open CherryRum opened 2 months ago

CherryRum commented 2 months ago

参考文档

GMT 0009-2012.pdf GMT 0009-2023.pdf

looly commented 2 months ago

@CherryRum 你要自己实现么,哈哈

CherryRum commented 2 months ago

看看有啥问题 哈哈,明确下文档

cxhello commented 2 months ago
    public KeyInfo generate() {
        KeyPair keyPair = SecureUtil.generateKeyPair("SM2");
        // 获取公钥和私钥
        PublicKey publicKey = keyPair.getPublic();
        PrivateKey privateKey = keyPair.getPrivate();
        KeyInfo keyInfo = new KeyInfo();
        keyInfo.setPublicKeyStr(Base64.getEncoder().encodeToString(publicKey.getEncoded()));
        keyInfo.setPrivateKeyStr(Base64.getEncoder().encodeToString(privateKey.getEncoded()));
        return keyInfo;
    }
image

最近在对接国密,想咨询下hutool生成的国密密钥对的私钥算法标识符是使用的1.2.840.10045.2.1ANSI X9.62 国际标准吗?

在使用openssl如下命令生成的国密密钥对的私钥算法标识符是使用的1.2.156.10197.1.301中国国家商用密码标准。因为也是第一次接触,客户要求使用国密,我理解这两种都是ECC(椭圆曲线密码学)的实现,请教下用哪一种更符合所谓国密的规范呢?

openssl ecparam -genkey -name SM2 -out "sm2PrivateKey.pem"

image
looly commented 2 months ago

@cxhello 密钥格式的问题。

Hutool中使用密钥支持:

私钥:支持D值、PKCS#8、PKCS#1 公钥:支持Q值、X.509、PKCS#1

密钥标识符使用的是:1.2.156.10197.1.301

见:

image

cxhello commented 2 months ago

@looly 您说的密钥格式的问题,是指的我使用openssl命令不对是吗?

looly commented 2 months ago

@cxhello 我意思是国密的Oid是固定的,只是密钥存储的格式不同。

如果在使用中有问题,可以附上测试的密钥,我这边回复。

cxhello commented 2 months ago

test.zip

证书解析网址:https://lapo.it/asn1js

image

压缩包里面有公私钥和证书,我使用证书解析网址解析出来看到OID使用的是1.2.840.10045.2.1,parameters是1.2.156.10197.1.301,导致我们在前端使用js解密有问题,所以想请教下。😂

looly commented 2 months ago

@cxhello Java生成的密钥确实不是Asni格式,是pkcs8和x509。

现在Hutool只能保证js生成的密钥可以用,但是Java生成的密钥没法在js中使用。

cxhello commented 2 months ago

好的,我自己再研究下。

CherryRum commented 2 months ago

@cxhello 看下这个cxhello 你的意思是想直接在两方用ans.1编码的吗

您的问题是一个历史遗留问题 您解析证书时看到的OID 1.2.840.10045.2.1(是因为该证书使用了OpenSSL 1.x版本的实现。在OpenSSL 1.x版本中,SM2算法的公钥被错误地标识为标准的EC公钥(OID: 1.2.840.10045.2.1),而不是国密标准中定义的SM2算法的OID(1.2.156.10197.1.301sm2p256v1。这导致了与国密标准的不一致。

建议您使用OpenSSL 3.x版本。OpenSSL 3.x版本中,SM2公钥密码算法已经使用了正确的OID 1.2.156.10197.1.301(参见《GB/T 33560-2017 信息安全技术 密码应用标识规范》附录A)。虽然这一更改可能导致一些后向兼容性问题,但这是为了遵循最新的国密标准,并解决之前版本存在的标准落后于实践的问题。

http://gmssl.org/docs/oid.html

cxhello commented 2 months ago

您解析证书时看到的OID 1.2.840.10045.2.1(是因为该证书使用了OpenSSL 1.x版本的实现。在OpenSSL 1.x版本中,SM2算法的公钥被错误地标识为标准的EC公钥(OID: 1.2.840.10045.2.1),而不是国密标准中定义的SM2算法的OID(1.2.156.10197.1.301)sm2p256v1。这导致了与国密标准的不一致。

@CherryRum 其实我想表达的是 我使用的hutool-5.7.22版本,生成的公私钥OID也是:1.2.840.10045.2.1,是需要更新版本吗?😂

CherryRum commented 2 months ago

那我建议您先升级版本吧,这个虽然不错,但是不符合现有的文档定义的曲线,虽然说这俩oid的椭圆曲线是一样的(没记错的话)

cxhello commented 2 months ago

@CherryRum 我们需要给客户演示的时候在他们的环境使用openss命令生成,所以如果客户的环境上使用openssl 1.x 其实没什么问题。我刚刚测试了,可以正常加解密了。

image

感谢大佬说的这个历史遗留问题。还有个问题想问下,hutool升级到5.8.29 OID就是1.2.156.10197.1.301了吗?

我是在我电脑上使用openssl生成公私钥发现这个问题的,我电脑上openssl版本是3.2.0。所以前端在使用私钥解密的时候报错了,前端用的应该也恰好是以前的库。😂

image
looly commented 2 months ago

确实没注意,我想新版本要做下更新了。

changhr2013 commented 1 month ago

这其实是个算法的归类问题,取决于 SM2 是应该属于 EC 算法的一条曲线,还是应该与 EC 并列的算法。

我觉得业界一直是认为 SM2 就是一条特殊的 EC 曲线,所以一开始大家都是按照 EC 的标准去走的,包括 《GM/T 0015-2012 基于SM2密码算法的数字证书格式规范》 在附录中给出的示例,也是使用 1.2.840.10045.2.1 作为算法 Oid 的。

image

OpenSSL 团队在升级 3.0 时,也解释了他们最初这样做的原因,他们团队内部当时认为应该将 SM2 算法视为一种独立的算法,所以他们参考了《GM/T 0006-2012 密码应用标识规范》给出的 Oid 来标识 SM2 算法。

image

这造成了很大的混乱,我觉得既然 GM/T 0015 已经给出了明确的参考示例,那么正如 OpenSSL 开发人员在 Issue 中说的:『如果有一个标准规定应该以特定的方式进行编码,那么我们就不能以不同的方式进行编码』。


PS: 不过我觉得这个事情大概率还是 0015 制定者的锅,因为在 GM/T 0015 标准的附录表格中是这样描述的:

image

可以明确看到 algorithm 部分给的值是 1.2.156.10197.1.301parameters 部分标记的是:『当使用 SM2 密码算法时,为 SM2 密码算法曲线的 OID』。

但是到下面附录的示例又变成了上面贴图的那样,大家实现的时候即使有疑问,也肯定会优先去符合标准示例

这特么找谁说理去。


再提一嘴,目前所有的国密基础设施都是按照示例走的,所以在实际编码中,使用 1.2.840.10045.2.1 才是正解,会避免 N 多兼容性问题。

cxhello commented 1 month ago

@changhr2013

我公司 arm kylin v10 的服务器上 openssl 版本是 1.1.1f,生成的国密公私钥OID就是1.2.156.10197.1.301,可是坑了我一把。😂

wolf-hunter404 commented 3 weeks ago

@changhr2013

我公司 arm kylin v10 的服务器上 openssl 版本是 1.1.1f,生成的国密公私钥OID就是1.2.156.10197.1.301,可是坑了我一把。😂

这个算是个bug,升级到openssl最新版本就能解决。 相关issue在这里,有过不少讨论 https://github.com/openssl/openssl/issues/20973

CherryRum commented 3 weeks ago

@changhr2013 我公司 arm kylin v10 的服务器上 openssl 版本是 1.1.1f,生成的国密公私钥OID就是1.2.156.10197.1.301,可是坑了我一把。😂

这个算是个bug,升级到openssl最新版本就能解决。 相关issue在这里,有过不少讨论 openssl/openssl#20973

也不算是bug吧,上面我引用了很多,其中就有这个,只是标准太模糊了