英文:
How does JWK EC public key co-ordinate encoding work?
问题
I'm attempting to re-create a P-521 JWK from just the private key.
根据规范(第4.2.1节):
> “x成员包含椭圆曲线点的x坐标。
> 它表示为坐标的大端表示的base64url编码。”
我尝试对私钥进行base64url解码,然后与P-521基点进行标量乘法运算以获取公钥点。然后,我尝试将x和y坐标转换为大端八位字节表示,并将其编码回base64url格式。结果与JWK中原始的x和y base64url编码字段不匹配。
我也尝试了P-256曲线,但也不起作用。
const elliptic = require('elliptic');
const EC = elliptic.ec;
const {base16, base64url} = require('rfc4648');
const BN = require("bn.js");
const padBase16ToWholeOctets = s => s.length%2===0 ? s : '0'+s;
const bnToB64 = n => base64url.stringify(base16.parse(padBase16ToWholeOctets(n.toString(16))))
console.log('begin'); // 强制将控制台输出显示为异步 IIFE
(async () => {
let keyPair = await crypto.subtle.generateKey({ name: "ECDSA", namedCurve: "P-521" }, true, ['sign'])
let jwk = await crypto.subtle.exportKey("jwk", keyPair.privateKey)
console.log(jwk)
const dHex = base16.stringify(base64url.parse(jwk.d, { loose: true }))
const ec = new EC('p521')
const [x,y] = ec.curve.g.mul(new BN(dHex, 16, 'be')).toJSON()
console.log(`expected x: ` + jwk.x)
console.log(`actual x: ` + bnToB64(x))
console.log(`expected y: ` + jwk.y)
console.log(`actual y: ` + bnToB64(y))
})();
英文:
I'm attempting to re-create a P-521 JWK from just the private key.
According to the spec (section 4.2.1):
> "The x member contains the x coordinate for the elliptic curve point.
> It is represented as the base64url encoding of the coordinate's big
> endian representation."
I've attempted to base64url-decode the private key, and scalar-multiply it with the P-521 base point to get the public key point. I've then attempted to convert the x and y co-ordinates into a big-endian octet representation, and encode that back to base64url format. The results do not match the original x and y base64url-encoded fields in the JWK.
I've also tried this with the P-256 curve, and that does not work either.
const elliptic = require('elliptic');
const EC = elliptic.ec;
const {base16, base64url} = require('rfc4648');
const BN = require("bn.js");
const padBase16ToWholeOctets = s => s.length%2===0 ? s : '0'+s;
const bnToB64 = n => base64url.stringify(base16.parse(padBase16ToWholeOctets(n.toString(16))))
console.log('begin'); // forces console output to show from async IIFE
(async () => {
let keyPair = await crypto.subtle.generateKey({ name: "ECDSA", namedCurve: "P-521" }, true, ['sign'])
let jwk = await crypto.subtle.exportKey("jwk", keyPair.privateKey)
console.log(jwk)
const dHex = base16.stringify(base64url.parse(jwk.d, { loose: true }))
const ec = new EC('p521')
const [x,y] = ec.curve.g.mul(new BN(dHex, 16, 'be')).toJSON()
console.log(`expected x: ` + jwk.x)
console.log(`actual x: ` + bnToB64(x))
console.log(`expected y: ` + jwk.y)
console.log(`actual y: ` + bnToB64(y))
})();
答案1
得分: 1
WebCrypto API生成的数据是正确的。你的不同数据是由于计算过程中的两个问题引起的:
第一个问题可以通过以下方式修复:
const point = ec.curve.g.mul(new BN(dHex, 16, 'be'))
console.log(`actual x: ` + bnToB64(point.getX()))
console.log(`actual y: ` + bnToB64(point.getY()))
第二个问题可以通过以下方式修复:
const bnToB64 = n => base64url.stringify(base16.parse(padBase16ToWholeOctets(n.toString(16)).padStart(132, '0')))
英文:
The data generated with the WebCrypto API is correct. Your different data is caused by two problems during calculation:
- x and y are not normalized, see
getX()
andgetY()
. - x and y are not padded to 66 bytes (with leading 0x00 bytes).
The first problem can be fixed with:
const point = ec.curve.g.mul(new BN(dHex, 16, 'be'))
console.log(`actual x: ` + bnToB64(point.getX()))
console.log(`actual y: ` + bnToB64(point.getY()))
the second with:
const bnToB64 = n => base64url.stringify(base16.parse(padBase16ToWholeOctets(n.toString(16)).padStart(132, '0')))
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论