使用微妙加密生成适合ECDSA私钥导入的pkcs8密钥

问题描述 投票:0回答:1

我需要使用零依赖性ECDSA生成一个

确定性
javascript
密钥,为此我用原始字节生成一个
pkcs8
密钥,然后将其导入为
ECDSA
私钥。这在逻辑上是否可能,如果是,下面的代码有什么问题,因为它在导入调用期间给了我DataError错误。

// Example function to convert derived bits to a PKCS#8 formatted key and import it
function convertRawKeyToPKCS8(rawKey, curveOid) {
    // PKCS#8 header for ECDSA with the chosen curve OID
    const pkcs8Header = [
        0x30, 0x81, 0x87,       // SEQUENCE (header, total length)
        0x02, 0x01, 0x00,       // INTEGER (version 0)
        0x30, 0x13,             // SEQUENCE (AlgorithmIdentifier header)
        0x06, 0x07,             // OBJECT IDENTIFIER (1.2.840.10045.2.1 - ecPublicKey OID)
        0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01,
        0x06, 0x08,             // OBJECT IDENTIFIER for curve (this is curve specific, provided as parameter)
        ...curveOid,
        0x04, 0x6d,             // OCTET STRING (privateKey length follows)
        0x30, 0x6b,             // SEQUENCE
        0x02, 0x01, 0x01,       // INTEGER (version 1)
        0x04, 0x20              // OCTET STRING (private key length, 32 bytes for P-256)
    ];

    // Append the raw private key bytes
    const pkcs8Key = new Uint8Array(pkcs8Header.length + rawKey.length);
    pkcs8Key.set(pkcs8Header);
    pkcs8Key.set(rawKey, pkcs8Header.length);

    return pkcs8Key;
}

// Example OIDs for different elliptic curves:
const OID_P256 = [0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07]; // P-256 curve OID

// Example raw ECDSA private key for P-256 (32 bytes):
const rawPrivateKey = new Uint8Array([
    0x93, 0x6a, 0x62, 0x91, 0x62, 0xa9, 0xba, 0x46,
    0x0c, 0x12, 0xfa, 0xb7, 0xdb, 0xe0, 0x2f, 0x91,
    0x52, 0xfa, 0xd2, 0xda, 0x47, 0x9a, 0x7d, 0xf2,
    0xbe, 0xab, 0xaa, 0x04, 0x48, 0x67, 0x6b, 0xa1
]);

// Generate the PKCS#8 key
const pkcs8Key = convertRawKeyToPKCS8(rawPrivateKey, OID_P256);

// Log the resulting PKCS#8 key as a hexadecimal string for display (optional)
console.log(Array.from(pkcs8Key).map(b => b.toString(16).padStart(2, '0')).join(''));

// Use the SubtleCrypto API to import the PKCS#8 key
async function importECDSAPrivateKey(pkcs8Key) {
    const privateKey = await crypto.subtle.importKey(
        "pkcs8",
        pkcs8Key.buffer,
        {
            name: "ECDSA",
            namedCurve: "P-256",
        },
        true,    // Extractable
        ["sign"] // Key usage
    );
    return privateKey;
}

// Example usage
importECDSAPrivateKey(pkcs8Key).then(privateKey => {
    console.log('Private key imported:', privateKey);
}).catch(console.error);
javascript private-key ecdsa subtlecrypto
1个回答
0
投票

有两个问题:

  1. 当包含公钥时,第一个序列长度仅为0x87。由于您没有添加它,因此 ASN.1 结构无效。

  2. 如果您尝试在没有公钥的情况下加载 EC 私钥,您将在 Firefox 和 Safari 中遇到问题。

解决方案很简单:添加公钥:

// Example function to convert derived bits to a PKCS#8 formatted key and import it
function convertRawKeyToPKCS8(rawPrivateKey, rawPublicKey, curveOid) {
    // PKCS#8 header for ECDSA with the chosen curve OID
    let pkcs8Key = [
        0x30, 0x81, 0x87,       // SEQUENCE (header, total length)
        0x02, 0x01, 0x00,       // INTEGER (version 0)
        0x30, 0x13,             // SEQUENCE (AlgorithmIdentifier header)
        0x06, 0x07,             // OBJECT IDENTIFIER (1.2.840.10045.2.1 - ecPublicKey OID)
        0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01,
        0x06, 0x08,             // OBJECT IDENTIFIER for curve (this is curve specific, provided as parameter)
        ...curveOid,
        0x04, 0x6d,             // OCTET STRING (privateKey length follows)
        0x30, 0x6b,             // SEQUENCE
        0x02, 0x01, 0x01,       // INTEGER (version 1)
        0x04, 0x20,             // OCTET STRING (private key length, 32 bytes for P-256)
        ...rawPrivateKey,
        0xa1, 0x44,             // [1] (tag)
        0x03, 0x42,             // BIT STRING (public key length, 66 bytes for P-256)
        ...rawPublicKey,
    ];

    return new Uint8Array(pkcs8Key);
}


// Example OIDs for different elliptic curves:
const OID_P256 = [0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07]; // P-256 curve OID

// Example raw ECDSA private key for P-256 (32 bytes):
const rawPrivateKey = [
    0x17, 0x4f, 0xa3, 0x30, 0xdb, 0xd7, 0xf9, 0x66,
    0xee, 0xb2, 0x36, 0xcc, 0xbc, 0x29, 0xb0, 0x25,
    0x5a, 0xd2, 0xcf, 0x0c, 0x91, 0x06, 0x9a, 0x9f,
    0x33, 0x53, 0x37, 0x24, 0x87, 0x8e, 0x03, 0x2b,
];
const rawPublicKey = [
    0x00, 0x04, 0x87, 0x44, 0x7e, 0xc5, 0xc8, 0xff,
    0xfb, 0x77, 0xf7, 0x24, 0x0d, 0xdd, 0x8b, 0xa2,
    0x03, 0x8b, 0xf9, 0x7c, 0x3b, 0x86, 0x4a, 0xb8,
    0x4b, 0xb1, 0xea, 0x3d, 0x3a, 0xe2, 0x2f, 0xca,
    0xbf, 0xb1, 0xfe, 0xbd, 0xf4, 0xda, 0x4b, 0xfd,
    0x12, 0x30, 0x79, 0xe2, 0x8b, 0x3b, 0x35, 0xae,
    0x22, 0x2b, 0x06, 0xd2, 0xd2, 0x26, 0x24, 0x6f,
    0x95, 0x5a, 0xa2, 0x51, 0x87, 0x4c, 0x42, 0x41,
    0xdd, 0x67,
]

// Generate the PKCS#8 key
const pkcs8Key = convertRawKeyToPKCS8(rawPrivateKey, rawPublicKey, OID_P256);

// Log the resulting PKCS#8 key as a hexadecimal string for display (optional)
console.log(Array.from(pkcs8Key).map(b => b.toString(16).padStart(2, '0')).join(''));

// Use the SubtleCrypto API to import the PKCS#8 key
async function importECDSAPrivateKey(pkcs8Key) {
    const privateKey = await crypto.subtle.importKey(
        "pkcs8",
        pkcs8Key.buffer,
        {
            name: "ECDSA",
            namedCurve: "P-256",
        },
        true,    // Extractable
        ["sign"] // Key usage
    );
    return privateKey;
}

// Example usage
importECDSAPrivateKey(pkcs8Key).then(privateKey => {
    console.log('Private key imported:', privateKey);
}).catch(console.error);
© www.soinside.com 2019 - 2024. All rights reserved.