Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hi, 这个工具又从证书获取公钥或私钥的方法吗? #109

Open
meguoe opened this issue Apr 11, 2024 · 7 comments
Open

hi, 这个工具又从证书获取公钥或私钥的方法吗? #109

meguoe opened this issue Apr 11, 2024 · 7 comments

Comments

@meguoe
Copy link

meguoe commented Apr 11, 2024

hi, 这个工具有类似node-forge中的 forge.pki.certificateFromPem,forge.pki.privateKeyFromPem 方法吗?

@changhr2013
Copy link
Contributor

没有,SM2 属于 ECC 体系,我理解解析 PEM 结构走 ECC 的标准即可,你可以直接使用 forge 解析 ECC 的方法解析 SM2 的私钥和证书。

@meguoe
Copy link
Author

meguoe commented Apr 12, 2024

好,谢谢,另外可以帮忙看一下吗?我从pem获取公私钥后验证不通过,第一次接触国密,有点迷茫。。。

try {
  const crtPem = fs.readFileSync('./ssl/sm2.cnsec.enc.crt.pem', 'utf8');
  const publicKey = crypto.createPublicKey(crtPem).export({type: 'spki', format: 'der'}).toString('hex')
  console.log(publicKey)

  const keyPem = fs.readFileSync('./ssl/sm2.cnsec.enc.key.pem', 'utf8');
  const privateKey = crypto.createPrivateKey(keyPem).export({type: 'pkcs8', format: 'der'}).toString('hex')
  console.log(privateKey)

  // 用publicKey加密数据
  const cipherMode = 1
  const encrypted = sm2.doEncrypt('hello world', publicKey, cipherMode);

  // 用privateKey解密数据
  const decrypted = sm2.doDecrypt(encrypted, privateKey, cipherMode);
  console.log(decrypted.toString());
} catch (e) {
  console.error(e)
}

// 这是从www.gmcrt.cn申请的测试证书

-----BEGIN CERTIFICATE-----
MIICezCCAh6gAwIBAgIGAY7MO36xMAwGCCqBHM9VAYN1BQAwSzELMAkGA1UEBhMC
Q04xDjAMBgNVBAoTBUdNU1NMMRAwDgYDVQQLEwdQS0kvU00yMRowGAYDVQQDExFN
aWRkbGVDQSBmb3IgVGVzdDAiGA8yMDI0MDQxMDE2MDAwMFoYDzIwMjUwNDEwMTYw
MDAwWjCBljELMAkGA1UEBhMCQ04xDzANBgNVBAgMBuWMl+S6rDEjMCEGA1UEBwwa
6LSi5pm65Zu96ZmF5aSn5Y6mQ+W6pzExMTAxDjAMBgNVBAoTBWNuc2VjMRIwEAYD
VQQLEwljbnNlYy5mdW4xDjAMBgNVBAMTBWNuc2VjMR0wGwYJKoZIhvcNAQkBFg5t
ZWd1b2VAMTYzLmNvbTBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABMb0Z97yXn9K
DyH9kxhO9BK4LespdHUzpK92c0YhOXfKjESseVHOVPWa645vnQFWWX76Aa6WsK2j
POT/zkezoHSjgZswgZgwGwYDVR0jBBQwEoAQ+X9VtCeUM2KmVspvzF0a/zAZBgNV
HQ4EEgQQIPdnNRr/XL2fFBz5rAveHTAQBgNVHREECTAHggVjbnNlYzAxBggrBgEF
BQcBAQQlMCMwIQYIKwYBBQUHMAGGFWh0dHBzOi8vb2NzcC5nbXNzbC5jbjAJBgNV
HRMEAjAAMA4GA1UdDwEB/wQEAwIAODAMBggqgRzPVQGDdQUAA0kAMEYCIQC23Isq
Hr45RqQ2Hz06uLUfNTUH8QdCp0R2i3tnkDXZswIhAIzHCrcZ3oOROWcq/hQiPA4F
6hWD2qxbswP0Q0rG5REL
-----END CERTIFICATE-----

-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgxkERNjUtWAtJ1IBy
Gsl+0ZyQAbHyaRGoq8L88AMnL/GgCgYIKoEcz1UBgi2hRANCAATG9Gfe8l5/Sg8h
/ZMYTvQSuC3rKXR1M6SvdnNGITl3yoxErHlRzlT1muuOb50BVll++gGulrCtozzk
/85Hs6B0
-----END PRIVATE KEY-----

@meguoe
Copy link
Author

meguoe commented Apr 12, 2024

sm2.verifyPublicKey(publicKey) 结果为 false

// 加解密测试执行异常
TypeError: Cannot read properties of null (reading 'multiply')
at Object.doEncrypt (/Users/meguoe/Downloads/demo-project/node_modules/.pnpm/[email protected]/node_modules/sm-crypto/src/sm2/index.js:25:23)
at Object. (/Users/meguoe/Downloads/demo-project/sm-crypto.js:39:25)
at Module._compile (node:internal/modules/cjs/loader:1256:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1310:10)
at Module.load (node:internal/modules/cjs/loader:1119:32)
at Module._load (node:internal/modules/cjs/loader:960:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
at node:internal/main/run_main_module:23:47

@changhr2013
Copy link
Contributor

js 解 asn1 好难搞,累死我了 😂

import crypto from 'crypto';
import asn1 from 'asn1.js';
import {sm2} from "sm-crypto";

const crtPEM = "-----BEGIN CERTIFICATE-----\n" +
    "MIICezCCAh6gAwIBAgIGAY7MO36xMAwGCCqBHM9VAYN1BQAwSzELMAkGA1UEBhMC\n" +
    "Q04xDjAMBgNVBAoTBUdNU1NMMRAwDgYDVQQLEwdQS0kvU00yMRowGAYDVQQDExFN\n" +
    "aWRkbGVDQSBmb3IgVGVzdDAiGA8yMDI0MDQxMDE2MDAwMFoYDzIwMjUwNDEwMTYw\n" +
    "MDAwWjCBljELMAkGA1UEBhMCQ04xDzANBgNVBAgMBuWMl+S6rDEjMCEGA1UEBwwa\n" +
    "6LSi5pm65Zu96ZmF5aSn5Y6mQ+W6pzExMTAxDjAMBgNVBAoTBWNuc2VjMRIwEAYD\n" +
    "VQQLEwljbnNlYy5mdW4xDjAMBgNVBAMTBWNuc2VjMR0wGwYJKoZIhvcNAQkBFg5t\n" +
    "ZWd1b2VAMTYzLmNvbTBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABMb0Z97yXn9K\n" +
    "DyH9kxhO9BK4LespdHUzpK92c0YhOXfKjESseVHOVPWa645vnQFWWX76Aa6WsK2j\n" +
    "POT/zkezoHSjgZswgZgwGwYDVR0jBBQwEoAQ+X9VtCeUM2KmVspvzF0a/zAZBgNV\n" +
    "HQ4EEgQQIPdnNRr/XL2fFBz5rAveHTAQBgNVHREECTAHggVjbnNlYzAxBggrBgEF\n" +
    "BQcBAQQlMCMwIQYIKwYBBQUHMAGGFWh0dHBzOi8vb2NzcC5nbXNzbC5jbjAJBgNV\n" +
    "HRMEAjAAMA4GA1UdDwEB/wQEAwIAODAMBggqgRzPVQGDdQUAA0kAMEYCIQC23Isq\n" +
    "Hr45RqQ2Hz06uLUfNTUH8QdCp0R2i3tnkDXZswIhAIzHCrcZ3oOROWcq/hQiPA4F\n" +
    "6hWD2qxbswP0Q0rG5REL\n" +
    "-----END CERTIFICATE-----";

const privateKeyPEM = "-----BEGIN PRIVATE KEY-----\n" +
    "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgxkERNjUtWAtJ1IBy\n" +
    "Gsl+0ZyQAbHyaRGoq8L88AMnL/GgCgYIKoEcz1UBgi2hRANCAATG9Gfe8l5/Sg8h\n" +
    "/ZMYTvQSuC3rKXR1M6SvdnNGITl3yoxErHlRzlT1muuOb50BVll++gGulrCtozzk\n" +
    "/85Hs6B0\n" +
    "-----END PRIVATE KEY-----";

// 定义 ASN.1 结构
// 定义 AlgorithmIdentifier
const AlgorithmIdentifier = asn1.define('AlgorithmIdentifier', function () {
    this.seq().obj(
        this.key('algorithm').objid(),
        this.key('parameters').any()
    );
});
// 定义 SubjectPublicKeyInfo
const SubjectPublicKeyInfo = asn1.define('SubjectPublicKeyInfo', function () {
    this.seq().obj(
        this.key('algorithm').use(AlgorithmIdentifier),
        this.key('subjectPublicKey').bitstr()
    );
});
const Attribute = asn1.define('Attribute', function () {
    this.seq().obj(
        this.key('type').objid(),
        this.key('values').set().of(this.any())  // 根据实际的 Attribute 类型具体定义
    );
});
// 定义 PrivateKeyInfo
const PrivateKeyInfo = asn1.define('PrivateKeyInfo', function () {
    this.seq().obj(
        this.key('version').int(),
        this.key('privateKeyAlgorithm').use(AlgorithmIdentifier),
        this.key('privateKey').octstr(),
        this.key('attributes').implicit(0).optional().setof(Attribute)  // 如果需要定义具体的 Attribute 结构
    );
});
// 定义 ECPrivateKey
const ECPrivateKey = asn1.define('ECPrivateKey', function () {
    this.seq().obj(
        this.key('version').int(),
        this.key('privateKey').octstr(),
        this.key('publicKey').explicit(1).optional().bitstr()
    );
});

// 抽取裸公钥
let publicKeyBuffer = new crypto.X509Certificate(crtPEM).publicKey.export({type: 'spki', format: 'der'});
let plainPublicKeyHex = SubjectPublicKeyInfo.decode(publicKeyBuffer, 'der').subjectPublicKey.data.toString('hex');
console.log(plainPublicKeyHex);

// 抽取裸私钥
const privateKeyBuffer = crypto.createPrivateKey(privateKeyPEM).export({type: 'pkcs8', format: 'der'})
let plainPrivateKeyHex = ECPrivateKey.decode(PrivateKeyInfo.decode(privateKeyBuffer, 'der').privateKey, 'der').privateKey.toString('hex');
console.log(plainPrivateKeyHex);

// 加密模式
const cipherMode = 1

// 加密
const encrypted = sm2.doEncrypt('hello world', plainPublicKeyHex, cipherMode);
console.log(encrypted);

// 解密
const decrypted = sm2.doDecrypt(encrypted, plainPrivateKeyHex, cipherMode);
console.log(decrypted);

示例输出:

// 公钥
04c6f467def25e7f4a0f21fd93184ef412b82deb29747533a4af767346213977ca8c44ac7951ce54f59aeb8e6f9d0156597efa01ae96b0ada33ce4ffce47b3a074
// 私钥
c6411136352d580b49d480721ac97ed19c9001b1f26911a8abc2fcf003272ff1
// 加密后的密文
7c2b06673b0aad4cb2d27c6f19d72d338eced762a3f9bb09c7780731066d1f4995994995480fe6767e3494ab2509896b169db948df4ffe6efbf3471f425b43e288163ae216f225f3e1fedd5f2e48f863d213e4174c434cc523a4d94c731fd37f9588a20f53c46c3fe14401
// 解密后的明文
hello world

@meguoe
Copy link
Author

meguoe commented Apr 12, 2024

太牛了,非常感谢。

@ValueLan
Copy link

@changhr2013
-----BEGIN PUBLIC KEY-----
.....=
-----END PUBLIC KEY-----
请问这个如何转换

@changhr2013
Copy link
Contributor

@changhr2013 -----BEGIN PUBLIC KEY----- .....= -----END PUBLIC KEY----- 请问这个如何转换

公钥一般使用的是 SubjectPublicKeyInfo 结构,按照上面 SubjectPublicKeyInfo 结构的方法解析一下应该就 ok。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants