@@ -3,14 +3,122 @@ import 'dart:typed_data';
33
44import 'package:ed25519_edwards/ed25519_edwards.dart' as ed;
55import 'package:pointycastle/pointycastle.dart' as pc;
6+ import 'package:pointycastle/ecc/ecc_fp.dart' as ecc_fp;
67
78import 'algorithms.dart' ;
89import 'exceptions.dart' ;
910import 'helpers.dart' ;
1011import 'key_parser.dart' ;
1112
1213abstract class JWTKey {
14+ /// Convert the key to a JWK JSON object representation
1315 Map <String , dynamic > toJWK ({String ? keyID});
16+
17+ /// Parse a JWK JSON object into any valid JWTKey,
18+ ///
19+ /// Including `SecretKey` , `RSAPrivateKey` , `RSAPublicKey` , `ECPrivateKey` ,
20+ /// `ECPublicKey` , `EdDSAPrivateKey` and `EdDSAPublicKey` .
21+ ///
22+ /// Throws a `JWTParseException` if the JWK is invalid or unsupported.
23+ static JWTKey fromJWK (Map <String , dynamic > jwk) {
24+ if (jwk['kty' ] == 'oct' ) {
25+ final key = base64Padded (jwk['k' ]);
26+
27+ return SecretKey (key, isBase64Encoded: true );
28+ }
29+
30+ if (jwk['kty' ] == 'RSA' ) {
31+ // Private key
32+ if (jwk['p' ] != null &&
33+ jwk['q' ] != null &&
34+ jwk['d' ] != null &&
35+ jwk['n' ] != null ) {
36+ final p = bigIntFromBytes (base64Url.decode (base64Padded (jwk['p' ])));
37+ final q = bigIntFromBytes (base64Url.decode (base64Padded (jwk['q' ])));
38+ final d = bigIntFromBytes (base64Url.decode (base64Padded (jwk['d' ])));
39+ final n = bigIntFromBytes (base64Url.decode (base64Padded (jwk['n' ])));
40+
41+ return RSAPrivateKey .raw (pc.RSAPrivateKey (n, d, p, q));
42+ }
43+
44+ // Public key
45+ if (jwk['e' ] != null && jwk['n' ] != null ) {
46+ final e = bigIntFromBytes (base64Url.decode (base64Padded (jwk['e' ])));
47+ final n = bigIntFromBytes (base64Url.decode (base64Padded (jwk['n' ])));
48+
49+ return RSAPublicKey .raw (pc.RSAPublicKey (n, e));
50+ }
51+
52+ throw JWTParseException ('Invalid JWK' );
53+ }
54+
55+ if (jwk['kty' ] == 'EC' ) {
56+ final crv = jwk['crv' ];
57+
58+ if (! ['P-256' , 'P-384' , 'P-521' , 'secp256k1' ].contains (crv)) {
59+ throw JWTParseException ('Unsupported curve' );
60+ }
61+
62+ // Private key
63+ if (jwk['d' ] != null ) {
64+ final d = bigIntFromBytes (base64Url.decode (base64Padded (jwk['d' ])));
65+
66+ return ECPrivateKey .raw (pc.ECPrivateKey (
67+ d,
68+ pc.ECDomainParameters (curveNISTToOpenSSL (crv)),
69+ ));
70+ }
71+
72+ // Public key
73+ if (jwk['x' ] != null && jwk['y' ] != null ) {
74+ final x = bigIntFromBytes (base64Url.decode (base64Padded (jwk['x' ])));
75+ final y = bigIntFromBytes (base64Url.decode (base64Padded (jwk['y' ])));
76+
77+ final params = pc.ECDomainParameters (curveNISTToOpenSSL (crv));
78+
79+ return ECPublicKey .raw (pc.ECPublicKey (
80+ ecc_fp.ECPoint (
81+ params.curve as ecc_fp.ECCurve ,
82+ params.curve.fromBigInteger (x) as ecc_fp.ECFieldElement ? ,
83+ params.curve.fromBigInteger (y) as ecc_fp.ECFieldElement ? ,
84+ false ,
85+ ),
86+ params,
87+ ));
88+ }
89+
90+ throw JWTParseException ('Invalid JWK' );
91+ }
92+
93+ if (jwk['kty' ] == 'OKP' ) {
94+ final crv = jwk['crv' ];
95+
96+ if (crv != 'Ed25519' ) throw JWTParseException ('Unsupported curve' );
97+
98+ // Private key
99+ if (jwk['d' ] != null && jwk['x' ] != null ) {
100+ final d = base64Url.decode (base64Padded (jwk['d' ]));
101+ final x = base64Url.decode (base64Padded (jwk['x' ]));
102+
103+ return EdDSAPrivateKey (
104+ Uint8List (d.length + x.length)
105+ ..setAll (0 , d)
106+ ..setAll (d.length, x),
107+ );
108+ }
109+
110+ // Public key
111+ if (jwk['x' ] != null ) {
112+ final x = base64Url.decode (base64Padded (jwk['x' ]));
113+
114+ return EdDSAPublicKey (x);
115+ }
116+
117+ throw JWTParseException ('Invalid JWK' );
118+ }
119+
120+ throw JWTParseException ('Unsupported key type' );
121+ }
14122}
15123
16124/// For HMAC algorithms
0 commit comments