admin管理员组文章数量:1406177
The private key is generated using Elliptic Curve. None of the methods from the SubtleCrypto interface of the Web Crypto API seem to be able to derive a public key from a private key, correct me if I'm wrong. Do I have to use a 3rd party library for that?
The private key is generated using Elliptic Curve. None of the methods from the SubtleCrypto interface of the Web Crypto API seem to be able to derive a public key from a private key, correct me if I'm wrong. Do I have to use a 3rd party library for that?
Share Improve this question edited May 10, 2022 at 7:28 Topaco 49.8k4 gold badges45 silver badges80 bronze badges asked May 7, 2022 at 9:14 Maxim LopinMaxim Lopin 1292 silver badges9 bronze badges 4- 1 AFAIK, there is no support. However, this can easily be done by exporting and importing as JWK, removing the private part before importing. – Topaco Commented May 7, 2022 at 10:17
- 1 I'll clarify: When I generate a key pair with subtle.generateKeys, I want to be able to recover the public key having only the private key saved. – Maxim Lopin Commented May 7, 2022 at 14:40
- 1 In my answer you will find an implementation that illustrates the suggested approach. Without a third party library this is the easiest way. – Topaco Commented May 7, 2022 at 17:59
- Maxim, we had the same question, and it appears it's not possible natively in the Web Crypto API. If this changes, please send me a message (I'm Zamicol everywhere) and let me know. We'll update our libraries with native support. – Zamicol Commented Jul 21, 2022 at 19:25
2 Answers
Reset to default 7WebCrypto is a low level API with only a relatively small feature set. To my knowledge there is no dedicated method for deriving a public key from a private key.
However, you can export the private CryptoKey
as JWK (JSON Web Key), remove the private portions, and re-import the remaining portion, which thereby bees the public CryptoKey
. The following code shows this for an ECDSA key:
async function getPublic(privateKey){
const jwkPrivate = await crypto.subtle.exportKey("jwk", privateKey);
delete jwkPrivate.d;
jwkPrivate.key_ops = ["verify"];
return crypto.subtle.importKey("jwk", jwkPrivate, {name: "ECDSA", namedCurve: "P-256"}, true, ["verify"]);
}
async function test(){
// Generate test key pair
const keyPair = await crypto.subtle.generateKey({name: "ECDSA", namedCurve: "P-256"}, true, ["sign", "verify"]);
// Derive public from private key
const publicKeyFromPrivate = await getPublic(keyPair.privateKey)
// Compare CryptoKeys
console.log(keyPair.publicKey);
console.log(publicKeyFromPrivate)
// Compare keys (in JWK format)
const jwkPublic = await crypto.subtle.exportKey("jwk", keyPair.publicKey);
const jwkPublicFromPrivate = await crypto.subtle.exportKey("jwk", publicKeyFromPrivate);
console.log(jwkPublic);
console.log(jwkPublicFromPrivate);
}
(async () => {
await test()
})();
As you can see, the original and the reconstructed public key are identical.
However, it should be mentioned that this solutin has one drawback: the private key must be exportable.
This post shows the same approach for RSA.
the noble curves library also has functions for that :
// export and extract private key
const { d } = await crypto.subtle.exportKey("jwk", privateKey);
// transforms url encoded base64 string from the jwk into big number
const validPrivateKey = b64ToBn(urlBase64ToBase64(d))
// get x,y from the noble curves lib ProjectivePoint
const pointFromPK = p256.ProjectivePoint.fromPrivateKey(validPrivateKey)
// import using constructed public key jwk x,y
crypto.subtle.importKey(
"jwk",
{
x: base64ToUrlBase64(bnToB64(pointFromPK.x)),
y: base64ToUrlBase64(bnToB64(pointFromPK.y)),
},
{name: "ECDSA", namedCurve: "P-256"}, true, [/*must be empty for public keys*/]
)
support functions from coolaj
function b64ToBn(b64) {
var bin = atob(b64);
var hex = [];
bin.split('').forEach(function (ch) {
var h = ch.charCodeAt(0).toString(16);
if (h.length % 2) { h = '0' + h; }
hex.push(h);
});
return BigInt('0x' + hex.join(''));
}
function urlBase64ToBase64(str) {
var r = str % 4;
if (2 === r) {
str += '==';
} else if (3 === r) {
str += '=';
}
return str.replace(/-/g, '+').replace(/_/g, '/');
}
function base64ToUrlBase64(str) {
return str.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
}
function bnToB64(bn) {
var hex = BigInt(bn).toString(16);
if (hex.length % 2) { hex = '0' + hex; }
var bin = [];
var i = 0;
var d;
var b;
while (i < hex.length) {
d = parseInt(hex.slice(i, i + 2), 16);
b = String.fromCharCode(d);
bin.push(b);
i += 2;
}
return btoa(bin.join(''));
}
本文标签: javascriptHow to derive public key from private key using WebCryptoApiStack Overflow
版权声明:本文标题:javascript - How to derive public key from private key using WebCryptoApi? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744960096a2634599.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论