Skip to content

Commit 78cd7d5

Browse files
authored
feat: expose jwk prop on ECDSA and RSA keys (#3060)
To allow easy use with webcrypto, expose the internally stored JWK representation of the keys.
1 parent fc51221 commit 78cd7d5

File tree

4 files changed

+61
-30
lines changed

4 files changed

+61
-30
lines changed

packages/crypto/src/keys/ecdsa/ecdsa.ts

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,19 @@ import type { Uint8ArrayList } from 'uint8arraylist'
1111

1212
export class ECDSAPublicKey implements ECDSAPublicKeyInterface {
1313
public readonly type = 'ECDSA'
14-
public readonly raw: Uint8Array
15-
private readonly _key: JsonWebKey
14+
public readonly jwk: JsonWebKey
15+
private _raw?: Uint8Array
1616

17-
constructor (publicKey: JsonWebKey) {
18-
this._key = publicKey
19-
this.raw = publicKeyToPKIMessage(publicKey)
17+
constructor (jwk: JsonWebKey) {
18+
this.jwk = jwk
19+
}
20+
21+
get raw (): Uint8Array {
22+
if (this._raw == null) {
23+
this._raw = publicKeyToPKIMessage(this.jwk)
24+
}
25+
26+
return this._raw
2027
}
2128

2229
toMultihash (): Digest<0x0, number> {
@@ -40,22 +47,29 @@ export class ECDSAPublicKey implements ECDSAPublicKeyInterface {
4047
}
4148

4249
async verify (data: Uint8Array | Uint8ArrayList, sig: Uint8Array): Promise<boolean> {
43-
return hashAndVerify(this._key, sig, data)
50+
return hashAndVerify(this.jwk, sig, data)
4451
}
4552
}
4653

4754
export class ECDSAPrivateKey implements ECDSAPrivateKeyInterface {
4855
public readonly type = 'ECDSA'
49-
public readonly raw: Uint8Array
50-
private readonly _key: JsonWebKey
56+
public readonly jwk: JsonWebKey
5157
public readonly publicKey: ECDSAPublicKey
58+
private _raw?: Uint8Array
5259

53-
constructor (privateKey: JsonWebKey, publicKey: JsonWebKey) {
54-
this._key = privateKey
55-
this.raw = privateKeyToPKIMessage(privateKey)
60+
constructor (jwk: JsonWebKey, publicKey: JsonWebKey) {
61+
this.jwk = jwk
5662
this.publicKey = new ECDSAPublicKey(publicKey)
5763
}
5864

65+
get raw (): Uint8Array {
66+
if (this._raw == null) {
67+
this._raw = privateKeyToPKIMessage(this.jwk)
68+
}
69+
70+
return this._raw
71+
}
72+
5973
equals (key?: any): boolean {
6074
if (key == null || !(key.raw instanceof Uint8Array)) {
6175
return false
@@ -65,6 +79,6 @@ export class ECDSAPrivateKey implements ECDSAPrivateKeyInterface {
6579
}
6680

6781
async sign (message: Uint8Array | Uint8ArrayList): Promise<Uint8Array> {
68-
return hashAndSign(this._key, message)
82+
return hashAndSign(this.jwk, message)
6983
}
7084
}

packages/crypto/src/keys/rsa/rsa.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,18 @@ import type { Uint8ArrayList } from 'uint8arraylist'
88

99
export class RSAPublicKey implements RSAPublicKeyInterface {
1010
public readonly type = 'RSA'
11-
private readonly _key: JsonWebKey
11+
public readonly jwk: JsonWebKey
1212
private _raw?: Uint8Array
1313
private readonly _multihash: Digest<18, number>
1414

15-
constructor (key: JsonWebKey, digest: Digest<18, number>) {
16-
this._key = key
15+
constructor (jwk: JsonWebKey, digest: Digest<18, number>) {
16+
this.jwk = jwk
1717
this._multihash = digest
1818
}
1919

2020
get raw (): Uint8Array {
2121
if (this._raw == null) {
22-
this._raw = utils.jwkToPkix(this._key)
22+
this._raw = utils.jwkToPkix(this.jwk)
2323
}
2424

2525
return this._raw
@@ -46,24 +46,24 @@ export class RSAPublicKey implements RSAPublicKeyInterface {
4646
}
4747

4848
verify (data: Uint8Array | Uint8ArrayList, sig: Uint8Array): boolean | Promise<boolean> {
49-
return hashAndVerify(this._key, sig, data)
49+
return hashAndVerify(this.jwk, sig, data)
5050
}
5151
}
5252

5353
export class RSAPrivateKey implements RSAPrivateKeyInterface {
5454
public readonly type = 'RSA'
55-
private readonly _key: JsonWebKey
55+
public readonly jwk: JsonWebKey
5656
private _raw?: Uint8Array
5757
public readonly publicKey: RSAPublicKey
5858

59-
constructor (key: JsonWebKey, publicKey: RSAPublicKey) {
60-
this._key = key
59+
constructor (jwk: JsonWebKey, publicKey: RSAPublicKey) {
60+
this.jwk = jwk
6161
this.publicKey = publicKey
6262
}
6363

6464
get raw (): Uint8Array {
6565
if (this._raw == null) {
66-
this._raw = utils.jwkToPkcs1(this._key)
66+
this._raw = utils.jwkToPkcs1(this.jwk)
6767
}
6868

6969
return this._raw
@@ -78,6 +78,6 @@ export class RSAPrivateKey implements RSAPrivateKeyInterface {
7878
}
7979

8080
sign (message: Uint8Array | Uint8ArrayList): Uint8Array | Promise<Uint8Array> {
81-
return hashAndSign(this._key, message)
81+
return hashAndSign(this.jwk, message)
8282
}
8383
}

packages/crypto/test/keys/ecdsa.spec.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,7 @@ describe('ECDSA', function () {
6161
const keyMarshal = key.raw
6262
const key2 = unmarshalECDSAPrivateKey(keyMarshal)
6363

64-
// @ts-expect-error private field
65-
expect(key._key.d).to.equal(key2._key.d)
64+
expect(key.jwk.d).to.equal(key2.jwk.d)
6665

6766
const keyMarshal2 = key2.raw
6867
expect(keyMarshal).to.equalBytes(keyMarshal2)
@@ -71,10 +70,8 @@ describe('ECDSA', function () {
7170
const pkMarshal = pk.raw
7271
const pk2 = unmarshalECDSAPublicKey(pkMarshal)
7372

74-
// @ts-expect-error private field
75-
expect(pk._key.x).to.deep.equal(pk2._key.x)
76-
// @ts-expect-error private field
77-
expect(pk._key.y).to.deep.equal(pk2._key.y)
73+
expect(pk.jwk.x).to.deep.equal(pk2.jwk.x)
74+
expect(pk.jwk.y).to.deep.equal(pk2.jwk.y)
7875

7976
const pkMarshal2 = pk2.raw
8077
expect(pkMarshal).to.equalBytes(pkMarshal2)

packages/interface/src/keys.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ export interface RSAPublicKey {
1515
*/
1616
readonly raw: Uint8Array
1717

18+
/**
19+
* The public key as a JSON web key
20+
*/
21+
readonly jwk: JsonWebKey
22+
1823
/**
1924
* Returns `true` if the passed object matches this key
2025
*/
@@ -138,10 +143,15 @@ export interface ECDSAPublicKey {
138143
readonly type: 'ECDSA'
139144

140145
/**
141-
* The raw public key bytes
146+
* The public key as a DER-encoded PKIMessage
142147
*/
143148
readonly raw: Uint8Array
144149

150+
/**
151+
* The public key as a JSON web key
152+
*/
153+
readonly jwk: JsonWebKey
154+
145155
/**
146156
* Returns `true` if the passed object matches this key
147157
*/
@@ -211,6 +221,11 @@ export interface RSAPrivateKey {
211221
*/
212222
readonly raw: Uint8Array
213223

224+
/**
225+
* The private key as a JSON web key
226+
*/
227+
readonly jwk: JsonWebKey
228+
214229
/**
215230
* Returns `true` if the passed object matches this key
216231
*/
@@ -291,10 +306,15 @@ export interface ECDSAPrivateKey {
291306
readonly publicKey: ECDSAPublicKey
292307

293308
/**
294-
* The raw private key bytes
309+
* The private key as a DER-encoded PKIMessage
295310
*/
296311
readonly raw: Uint8Array
297312

313+
/**
314+
* The private key as a JSON web key
315+
*/
316+
readonly jwk: JsonWebKey
317+
298318
/**
299319
* Returns `true` if the passed object matches this key
300320
*/

0 commit comments

Comments
 (0)