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)
|
||||
|
||||
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.
|
||||
|
||||
https://jwt.io allows you to decode, verify and generate JWT.
|
||||
`dart_jsonwebtoken` allows you to sign, decode and verify JWT.
|
||||
|
||||
## 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.
|
||||
|
||||
You can also check out the [jwt.io](https://jwt.io) website for more information.
|
||||
|
||||
## Usage
|
||||
|
||||
### Import
|
||||
@ -110,9 +112,16 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEVs/o5+uQbTjL3chynL4wXgUg2R9
|
||||
''');
|
||||
|
||||
|
||||
// EdDSA (PEM parsing is not available for EdDSA keys)
|
||||
final edPrivKey = EdDSAPrivateKey([1, 42, 12, 84, ...]);
|
||||
final edPubKey = EdDSAPublicKey([1, 42, 12, 84, ...]);
|
||||
// EdDSA
|
||||
final edPrivKey = EdDSAPrivateKey.fromPEM('''-----BEGIN PRIVATE KEY-----
|
||||
MC4CAQAwBQYDK2VwBCIEICXCjBHvjArjXquUI5jo3x5SHI4ofZA2azwJ39IC/Qct
|
||||
-----END PRIVATE KEY-----
|
||||
''');
|
||||
|
||||
final edPubKey = EdDSAPublicKey.fromPEM('''-----BEGIN PUBLIC KEY-----
|
||||
MCowBQYDK2VwAyEAEi7MNW0Q9T83UA3Rw+8DbspMgqeuxCqa2wXaWS+tHqY=
|
||||
-----END PUBLIC KEY-----
|
||||
''');
|
||||
```
|
||||
|
||||
### 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 -----');
|
||||
rsaCert();
|
||||
print('---------------------------\n');
|
||||
|
||||
print('----- EdDSA -----');
|
||||
eddsa();
|
||||
print('-----------------\n');
|
||||
}
|
||||
|
||||
// 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/pointycastle.dart';
|
||||
import 'package:pointycastle/ecc/ecc_fp.dart' as ecc_fp;
|
||||
import 'package:ed25519_edwards/ed25519_edwards.dart' as ed;
|
||||
|
||||
import 'helpers.dart';
|
||||
|
||||
@ -245,6 +246,38 @@ abstract class KeyParser {
|
||||
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 //
|
||||
//--------------//
|
||||
|
@ -115,18 +115,19 @@ class ECPublicKey extends JWTKey {
|
||||
|
||||
/// For EdDSA algorithm, in sign method
|
||||
class EdDSAPrivateKey extends JWTKey {
|
||||
late ed.PrivateKey key;
|
||||
ed.PrivateKey key;
|
||||
|
||||
EdDSAPrivateKey(List<int> bytes) {
|
||||
key = ed.PrivateKey(bytes);
|
||||
}
|
||||
EdDSAPrivateKey(List<int> bytes) : key = ed.PrivateKey(bytes);
|
||||
|
||||
EdDSAPrivateKey.fromPEM(String pem)
|
||||
: key = KeyParser.edPrivateKeyFromPEM(pem);
|
||||
}
|
||||
|
||||
/// For EdDSA algorithm, in verify method
|
||||
class EdDSAPublicKey extends JWTKey {
|
||||
late ed.PublicKey key;
|
||||
ed.PublicKey key;
|
||||
|
||||
EdDSAPublicKey(List<int> bytes) {
|
||||
key = ed.PublicKey(bytes);
|
||||
}
|
||||
EdDSAPublicKey(List<int> bytes) : key = ed.PublicKey(bytes);
|
||||
|
||||
EdDSAPublicKey.fromPEM(String pem) : key = KeyParser.edPublicKeyFromPEM(pem);
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart';
|
||||
@ -43,12 +42,9 @@ MHQCAQEEINCRiJnNDnzfo2So2tWY4AIuzeC2ZBp/hmMDcZz3Fh45oAcGBSuBBAAK
|
||||
oUQDQgAE0aELkvG/Xeo5y6o0WXRAjlediLptGz7Q8zjDmpGFXkKBYZ6IiL7JJ2Tk
|
||||
cHzd83bmeUeGX33RGTYFPXs5t/VBnw==
|
||||
-----END EC PRIVATE KEY-----''');
|
||||
final edKey = EdDSAPrivateKey(
|
||||
base64Decode(
|
||||
'nWGxne/9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2DXWpgBgrEKt9VL/' +
|
||||
'tPJZAc6DuFy89qmIyWvAhpo9wdRGg==',
|
||||
),
|
||||
);
|
||||
final edKey = EdDSAPrivateKey.fromPEM('''-----BEGIN PRIVATE KEY-----
|
||||
MC4CAQAwBQYDK2VwBCIEICXCjBHvjArjXquUI5jo3x5SHI4ofZA2azwJ39IC/Qct
|
||||
-----END PRIVATE KEY-----''');
|
||||
|
||||
class MockRSAAlgorithm extends RSAAlgorithm {
|
||||
MockRSAAlgorithm(String name) : super(name, Random(42));
|
||||
@ -218,7 +214,7 @@ void main() {
|
||||
|
||||
final expectedToken = 'eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9' +
|
||||
'.eyJmb28iOiJiYXIifQ' +
|
||||
'.8tRIxs_o_isQItc2FtzA34Ah-EEvBj7Fw6lKh2tD53IOx5CinBM36yIGo2TDHNmm-ElATCdnMisUKt_UJ5pTAg';
|
||||
'.6Bw5vvdpJ_kgDwidU1l7aagtKCD9-QIJxrz44HXxtc6OJoOmImNko0dgXYpTtXhcEuX7vamSR5JPfGP1Q9d9DA';
|
||||
|
||||
expect(token, equals(expectedToken));
|
||||
});
|
||||
|
@ -1,5 +1,3 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
@ -21,9 +19,9 @@ final secp256kKey = ECPublicKey('''-----BEGIN PUBLIC KEY-----
|
||||
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE0aELkvG/Xeo5y6o0WXRAjlediLptGz7Q
|
||||
8zjDmpGFXkKBYZ6IiL7JJ2TkcHzd83bmeUeGX33RGTYFPXs5t/VBnw==
|
||||
-----END PUBLIC KEY-----''');
|
||||
final edKey = EdDSAPublicKey(
|
||||
base64Decode('11qYAYKxCrfVS/7TyWQHOg7hcvPapiMlrwIaaPcHURo='),
|
||||
);
|
||||
final edKey = EdDSAPublicKey.fromPEM('''-----BEGIN PUBLIC KEY-----
|
||||
MCowBQYDK2VwAyEAEi7MNW0Q9T83UA3Rw+8DbspMgqeuxCqa2wXaWS+tHqY=
|
||||
-----END PUBLIC KEY-----''');
|
||||
|
||||
void main() {
|
||||
group('Verify a JWT', () {
|
||||
@ -244,7 +242,7 @@ void main() {
|
||||
test('.verify EdDSA', () {
|
||||
final token = 'eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9' +
|
||||
'.eyJmb28iOiJiYXIifQ' +
|
||||
'.8tRIxs_o_isQItc2FtzA34Ah-EEvBj7Fw6lKh2tD53IOx5CinBM36yIGo2TDHNmm-ElATCdnMisUKt_UJ5pTAg';
|
||||
'.6Bw5vvdpJ_kgDwidU1l7aagtKCD9-QIJxrz44HXxtc6OJoOmImNko0dgXYpTtXhcEuX7vamSR5JPfGP1Q9d9DA';
|
||||
|
||||
final jwt = JWT.tryVerify(token, edKey);
|
||||
|
||||
|
Reference in New Issue
Block a user