JWK EC 公钥坐标编码是如何工作的?

huangapple go评论70阅读模式
英文:

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生成的数据是正确的。你的不同数据是由于计算过程中的两个问题引起的:

  • x和y没有进行标准化,请参考getX()getY()
  • x和y没有填充到66字节(前导0x00字节)。

第一个问题可以通过以下方式修复:

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() and getY().
  • 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')))

huangapple
  • 本文由 发表于 2023年5月25日 19:35:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/76331830.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定