给定种子和盐,如何使用零依赖 JavaScript 和 SubtleCrypto
生成一组
确定性ECDSA 密钥? (这是这个问题的延续。)
我的理解是有两种主要方法可以实现:
x
和 y
(我不确定如何,因为 generateKey
仅接受命名曲线;也许通过 JWK?)我希望解决方案尽可能依赖
SubtleCrypto
API,并使用尽可能少的自定义代码。
代码:
async function generateDeterministicECDSAKey(seed, salt) {
// Step 1: Convert seed and salt to ArrayBuffers
const enc = new TextEncoder();
const seedBuffer = enc.encode(seed); // Seed as a buffer
const saltBuffer = enc.encode(salt); // Salt as a buffer
// Step 2: Derive key material using PBKDF2
const baseKey = await crypto.subtle.importKey(
'raw',
seedBuffer,
{ name: 'PBKDF2' },
false,
['deriveBits', 'deriveKey']
);
// Derive 256 bits (32 bytes) of key material for the private key
const derivedBits = await crypto.subtle.deriveBits(
{
name: 'PBKDF2',
salt: saltBuffer, // Salt for PBKDF2
iterations: 100000, // Use a secure iteration count
hash: 'SHA-256' // Hash function for PBKDF2
},
baseKey,
256 // 256 bits for the derived key
);
// Step 3: Import derived key material as ECDSA private key
// NOTE - that's where it fails due to a mismatch between the "raw" format
// and { name: 'ECDSA', namedCurve: 'P-256' } algo
const privateKey = await crypto.subtle.importKey(
'raw',
derivedBits, // Use derived bits as private key
{ name: 'ECDSA', namedCurve: 'P-256' }, // ECDSA using the P-256 curve
true, // Mark key as exportable
['sign'] // Key usage for signing
);
// Step 4: Export the private key in PKCS8 format (optional)
const pkcs8Key = await crypto.subtle.exportKey('pkcs8', privateKey);
// Step 5: Generate public key pair (optional)
const publicKey = await crypto.subtle.exportKey('jwk', privateKey);
return {
privateKey: privateKey,
pkcs8Key: pkcs8Key,
publicKey: publicKey
};
}
// Helper function to convert ArrayBuffer to base64 string (for display)
function arrayBufferToBase64(buffer) {
const binary = String.fromCharCode.apply(null, new Uint8Array(buffer));
return window.btoa(binary);
}
// Example usage
const seed = "your_deterministic_seed"; // Example seed
const salt = "your_salt_value"; // Example salt
await generateDeterministicECDSAKey(seed, salt).then(keys => {
const privateKeyBase64 = arrayBufferToBase64(keys.pkcs8Key);
console.log("Private Key (PKCS8 Base64):", privateKeyBase64);
console.log("Public Key (JWK):", keys.publicKey);
});
此存储库是作为对涵盖 ECDSA 教育示例的问题的全面答案而创建的,无需任何外部模块即可在大多数现代浏览器上运行: https://github.com/RayRizzling/js-ecdsa