mirror of
https://github.com/jonasroussel/dart_jsonwebtoken.git
synced 2025-05-18 00:25:52 +08:00
add support of PEM parsing for EdDSA
This commit is contained in:
19
README.md
19
README.md
@ -2,16 +2,18 @@
|
|||||||
|
|
||||||
[](https://pub.dev/packages/dart_jsonwebtoken)
|
[](https://pub.dev/packages/dart_jsonwebtoken)
|
||||||
|
|
||||||
A dart implementation of the famous javascript library `jsonwebtoken`.
|
An easy to use JSON Web Token implementation in Dart (all algorithms supported).
|
||||||
|
|
||||||
JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.
|
JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.
|
||||||
|
|
||||||
https://jwt.io allows you to decode, verify and generate JWT.
|
`dart_jsonwebtoken` allows you to sign, decode and verify JWT.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
Check out the [Example File](https://github.com/jonasroussel/dart_jsonwebtoken/blob/main/example/example.dart) for a full example code of all the differents algorithms.
|
Check out the [Example File](https://github.com/jonasroussel/dart_jsonwebtoken/blob/main/example/example.dart) for a full example code of all the differents algorithms.
|
||||||
|
|
||||||
|
You can also check out the [jwt.io](https://jwt.io) website for more information.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### Import
|
### Import
|
||||||
@ -110,9 +112,16 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEVs/o5+uQbTjL3chynL4wXgUg2R9
|
|||||||
''');
|
''');
|
||||||
|
|
||||||
|
|
||||||
// EdDSA (PEM parsing is not available for EdDSA keys)
|
// EdDSA
|
||||||
final edPrivKey = EdDSAPrivateKey([1, 42, 12, 84, ...]);
|
final edPrivKey = EdDSAPrivateKey.fromPEM('''-----BEGIN PRIVATE KEY-----
|
||||||
final edPubKey = EdDSAPublicKey([1, 42, 12, 84, ...]);
|
MC4CAQAwBQYDK2VwBCIEICXCjBHvjArjXquUI5jo3x5SHI4ofZA2azwJ39IC/Qct
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
''');
|
||||||
|
|
||||||
|
final edPubKey = EdDSAPublicKey.fromPEM('''-----BEGIN PUBLIC KEY-----
|
||||||
|
MCowBQYDK2VwAyEAEi7MNW0Q9T83UA3Rw+8DbspMgqeuxCqa2wXaWS+tHqY=
|
||||||
|
-----END PUBLIC KEY-----
|
||||||
|
''');
|
||||||
```
|
```
|
||||||
|
|
||||||
### Supported Algorithms
|
### Supported Algorithms
|
||||||
|
3
example/eddsa_private.pem
Normal file
3
example/eddsa_private.pem
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MC4CAQAwBQYDK2VwBCIEICXCjBHvjArjXquUI5jo3x5SHI4ofZA2azwJ39IC/Qct
|
||||||
|
-----END PRIVATE KEY-----
|
3
example/eddsa_public.pem
Normal file
3
example/eddsa_public.pem
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
-----BEGIN PUBLIC KEY-----
|
||||||
|
MCowBQYDK2VwAyEAEi7MNW0Q9T83UA3Rw+8DbspMgqeuxCqa2wXaWS+tHqY=
|
||||||
|
-----END PUBLIC KEY-----
|
@ -26,6 +26,10 @@ void main() {
|
|||||||
print('----- RSA Certificate -----');
|
print('----- RSA Certificate -----');
|
||||||
rsaCert();
|
rsaCert();
|
||||||
print('---------------------------\n');
|
print('---------------------------\n');
|
||||||
|
|
||||||
|
print('----- EdDSA -----');
|
||||||
|
eddsa();
|
||||||
|
print('-----------------\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
// HMAC SHA-256 algorithm
|
// HMAC SHA-256 algorithm
|
||||||
@ -279,3 +283,45 @@ void rsaCert() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void eddsa() {
|
||||||
|
String token;
|
||||||
|
|
||||||
|
/* Sign */ {
|
||||||
|
// Create a json web token
|
||||||
|
final jwt = JWT(
|
||||||
|
{
|
||||||
|
'id': 123,
|
||||||
|
'server': {
|
||||||
|
'id': '3e4fc296',
|
||||||
|
'loc': 'euw-2',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
issuer: 'https://github.com/jonasroussel/dart_jsonwebtoken',
|
||||||
|
);
|
||||||
|
|
||||||
|
// Sign it
|
||||||
|
final privPem = File('./example/eddsa_private.pem').readAsStringSync();
|
||||||
|
final key = EdDSAPrivateKey.fromPEM(privPem);
|
||||||
|
|
||||||
|
token = jwt.sign(key, algorithm: JWTAlgorithm.EdDSA);
|
||||||
|
|
||||||
|
print('Signed token: $token\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Verify */ {
|
||||||
|
try {
|
||||||
|
// Verify a token
|
||||||
|
final pem = File('./example/eddsa_public.pem').readAsStringSync();
|
||||||
|
final key = EdDSAPublicKey.fromPEM(pem);
|
||||||
|
|
||||||
|
final jwt = JWT.verify(token, key);
|
||||||
|
|
||||||
|
print('Payload: ${jwt.payload}');
|
||||||
|
} on JWTExpiredException {
|
||||||
|
print('jwt expired');
|
||||||
|
} on JWTException catch (ex) {
|
||||||
|
print(ex.message); // ex: invalid signature
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -4,6 +4,7 @@ import 'dart:typed_data';
|
|||||||
import 'package:pointycastle/asn1/object_identifiers.dart';
|
import 'package:pointycastle/asn1/object_identifiers.dart';
|
||||||
import 'package:pointycastle/pointycastle.dart';
|
import 'package:pointycastle/pointycastle.dart';
|
||||||
import 'package:pointycastle/ecc/ecc_fp.dart' as ecc_fp;
|
import 'package:pointycastle/ecc/ecc_fp.dart' as ecc_fp;
|
||||||
|
import 'package:ed25519_edwards/ed25519_edwards.dart' as ed;
|
||||||
|
|
||||||
import 'helpers.dart';
|
import 'helpers.dart';
|
||||||
|
|
||||||
@ -245,6 +246,38 @@ abstract class KeyParser {
|
|||||||
return pubKey;
|
return pubKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---------------//
|
||||||
|
// EdDSA Parsing //
|
||||||
|
//---------------//
|
||||||
|
|
||||||
|
static ed.PrivateKey edPrivateKeyFromPEM(String pem) {
|
||||||
|
final bytes = bytesFromPEM(pem);
|
||||||
|
return edPrivateKey(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ed.PrivateKey edPrivateKey(Uint8List bytes) {
|
||||||
|
var asn1Parser = ASN1Parser(bytes);
|
||||||
|
var topLevelSeq = asn1Parser.nextObject() as ASN1Sequence;
|
||||||
|
|
||||||
|
var octetString = topLevelSeq.elements!.elementAt(2) as ASN1OctetString;
|
||||||
|
|
||||||
|
return ed.newKeyFromSeed(octetString.valueBytes!.sublist(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
static ed.PublicKey edPublicKeyFromPEM(String pem) {
|
||||||
|
final bytes = bytesFromPEM(pem);
|
||||||
|
return edPublicKey(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ed.PublicKey edPublicKey(Uint8List bytes) {
|
||||||
|
var asn1Parser = ASN1Parser(bytes);
|
||||||
|
var topLevelSeq = asn1Parser.nextObject() as ASN1Sequence;
|
||||||
|
|
||||||
|
var bitString = topLevelSeq.elements!.elementAt(1) as ASN1BitString;
|
||||||
|
|
||||||
|
return ed.PublicKey(bitString.valueBytes!.sublist(1));
|
||||||
|
}
|
||||||
|
|
||||||
//--------------//
|
//--------------//
|
||||||
// PEM to Bytes //
|
// PEM to Bytes //
|
||||||
//--------------//
|
//--------------//
|
||||||
|
@ -115,18 +115,19 @@ class ECPublicKey extends JWTKey {
|
|||||||
|
|
||||||
/// For EdDSA algorithm, in sign method
|
/// For EdDSA algorithm, in sign method
|
||||||
class EdDSAPrivateKey extends JWTKey {
|
class EdDSAPrivateKey extends JWTKey {
|
||||||
late ed.PrivateKey key;
|
ed.PrivateKey key;
|
||||||
|
|
||||||
EdDSAPrivateKey(List<int> bytes) {
|
EdDSAPrivateKey(List<int> bytes) : key = ed.PrivateKey(bytes);
|
||||||
key = ed.PrivateKey(bytes);
|
|
||||||
}
|
EdDSAPrivateKey.fromPEM(String pem)
|
||||||
|
: key = KeyParser.edPrivateKeyFromPEM(pem);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For EdDSA algorithm, in verify method
|
/// For EdDSA algorithm, in verify method
|
||||||
class EdDSAPublicKey extends JWTKey {
|
class EdDSAPublicKey extends JWTKey {
|
||||||
late ed.PublicKey key;
|
ed.PublicKey key;
|
||||||
|
|
||||||
EdDSAPublicKey(List<int> bytes) {
|
EdDSAPublicKey(List<int> bytes) : key = ed.PublicKey(bytes);
|
||||||
key = ed.PublicKey(bytes);
|
|
||||||
}
|
EdDSAPublicKey.fromPEM(String pem) : key = KeyParser.edPublicKeyFromPEM(pem);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import 'dart:convert';
|
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart';
|
import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart';
|
||||||
@ -43,12 +42,9 @@ MHQCAQEEINCRiJnNDnzfo2So2tWY4AIuzeC2ZBp/hmMDcZz3Fh45oAcGBSuBBAAK
|
|||||||
oUQDQgAE0aELkvG/Xeo5y6o0WXRAjlediLptGz7Q8zjDmpGFXkKBYZ6IiL7JJ2Tk
|
oUQDQgAE0aELkvG/Xeo5y6o0WXRAjlediLptGz7Q8zjDmpGFXkKBYZ6IiL7JJ2Tk
|
||||||
cHzd83bmeUeGX33RGTYFPXs5t/VBnw==
|
cHzd83bmeUeGX33RGTYFPXs5t/VBnw==
|
||||||
-----END EC PRIVATE KEY-----''');
|
-----END EC PRIVATE KEY-----''');
|
||||||
final edKey = EdDSAPrivateKey(
|
final edKey = EdDSAPrivateKey.fromPEM('''-----BEGIN PRIVATE KEY-----
|
||||||
base64Decode(
|
MC4CAQAwBQYDK2VwBCIEICXCjBHvjArjXquUI5jo3x5SHI4ofZA2azwJ39IC/Qct
|
||||||
'nWGxne/9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2DXWpgBgrEKt9VL/' +
|
-----END PRIVATE KEY-----''');
|
||||||
'tPJZAc6DuFy89qmIyWvAhpo9wdRGg==',
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
class MockRSAAlgorithm extends RSAAlgorithm {
|
class MockRSAAlgorithm extends RSAAlgorithm {
|
||||||
MockRSAAlgorithm(String name) : super(name, Random(42));
|
MockRSAAlgorithm(String name) : super(name, Random(42));
|
||||||
@ -218,7 +214,7 @@ void main() {
|
|||||||
|
|
||||||
final expectedToken = 'eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9' +
|
final expectedToken = 'eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9' +
|
||||||
'.eyJmb28iOiJiYXIifQ' +
|
'.eyJmb28iOiJiYXIifQ' +
|
||||||
'.8tRIxs_o_isQItc2FtzA34Ah-EEvBj7Fw6lKh2tD53IOx5CinBM36yIGo2TDHNmm-ElATCdnMisUKt_UJ5pTAg';
|
'.6Bw5vvdpJ_kgDwidU1l7aagtKCD9-QIJxrz44HXxtc6OJoOmImNko0dgXYpTtXhcEuX7vamSR5JPfGP1Q9d9DA';
|
||||||
|
|
||||||
expect(token, equals(expectedToken));
|
expect(token, equals(expectedToken));
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart';
|
import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
@ -21,9 +19,9 @@ final secp256kKey = ECPublicKey('''-----BEGIN PUBLIC KEY-----
|
|||||||
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE0aELkvG/Xeo5y6o0WXRAjlediLptGz7Q
|
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE0aELkvG/Xeo5y6o0WXRAjlediLptGz7Q
|
||||||
8zjDmpGFXkKBYZ6IiL7JJ2TkcHzd83bmeUeGX33RGTYFPXs5t/VBnw==
|
8zjDmpGFXkKBYZ6IiL7JJ2TkcHzd83bmeUeGX33RGTYFPXs5t/VBnw==
|
||||||
-----END PUBLIC KEY-----''');
|
-----END PUBLIC KEY-----''');
|
||||||
final edKey = EdDSAPublicKey(
|
final edKey = EdDSAPublicKey.fromPEM('''-----BEGIN PUBLIC KEY-----
|
||||||
base64Decode('11qYAYKxCrfVS/7TyWQHOg7hcvPapiMlrwIaaPcHURo='),
|
MCowBQYDK2VwAyEAEi7MNW0Q9T83UA3Rw+8DbspMgqeuxCqa2wXaWS+tHqY=
|
||||||
);
|
-----END PUBLIC KEY-----''');
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
group('Verify a JWT', () {
|
group('Verify a JWT', () {
|
||||||
@ -244,7 +242,7 @@ void main() {
|
|||||||
test('.verify EdDSA', () {
|
test('.verify EdDSA', () {
|
||||||
final token = 'eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9' +
|
final token = 'eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9' +
|
||||||
'.eyJmb28iOiJiYXIifQ' +
|
'.eyJmb28iOiJiYXIifQ' +
|
||||||
'.8tRIxs_o_isQItc2FtzA34Ah-EEvBj7Fw6lKh2tD53IOx5CinBM36yIGo2TDHNmm-ElATCdnMisUKt_UJ5pTAg';
|
'.6Bw5vvdpJ_kgDwidU1l7aagtKCD9-QIJxrz44HXxtc6OJoOmImNko0dgXYpTtXhcEuX7vamSR5JPfGP1Q9d9DA';
|
||||||
|
|
||||||
final jwt = JWT.tryVerify(token, edKey);
|
final jwt = JWT.tryVerify(token, edKey);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user