mirror of
https://github.com/jonasroussel/dart_jsonwebtoken.git
synced 2025-08-02 10:23:56 +08:00
v2.0.0-nullsafety.1
This commit is contained in:
@ -93,7 +93,7 @@ class _HMACAlgorithm extends JWTAlgorithm {
|
||||
|
||||
final hmac = Hmac(_getHash(name), utf8.encode(secretKey.key));
|
||||
|
||||
return hmac.convert(body).bytes;
|
||||
return Uint8List.fromList(hmac.convert(body).bytes);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -143,9 +143,9 @@ class _RSAAlgorithm extends JWTAlgorithm {
|
||||
|
||||
signer.init(true, params);
|
||||
|
||||
pc.RSASignature signature = signer.generateSignature(
|
||||
final signature = signer.generateSignature(
|
||||
Uint8List.fromList(body),
|
||||
);
|
||||
) as pc.RSASignature;
|
||||
|
||||
return signature.bytes;
|
||||
}
|
||||
@ -202,9 +202,9 @@ class _ECDSAAlgorithm extends JWTAlgorithm {
|
||||
|
||||
signer.init(true, params);
|
||||
|
||||
pc.ECSignature signature = signer.generateSignature(
|
||||
final signature = signer.generateSignature(
|
||||
Uint8List.fromList(body),
|
||||
);
|
||||
) as pc.ECSignature;
|
||||
|
||||
final len = privateKey.size;
|
||||
final bytes = Uint8List(len * 2);
|
||||
|
@ -23,3 +23,8 @@ class JWTExpiredError extends JWTError {
|
||||
class JWTNotActiveError extends JWTError {
|
||||
JWTNotActiveError() : super('jwt not active');
|
||||
}
|
||||
|
||||
/// An error thrown when parsing failed
|
||||
class JWTParseError extends JWTError {
|
||||
JWTParseError(String message) : super(message);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'algorithms.dart';
|
||||
import 'errors.dart';
|
||||
@ -19,16 +20,19 @@ class JWT {
|
||||
bool checkExpiresIn = true,
|
||||
bool checkNotBefore = true,
|
||||
bool throwUndefinedErrors = false,
|
||||
Duration issueAt,
|
||||
String audience,
|
||||
String subject,
|
||||
String issuer,
|
||||
String jwtId,
|
||||
Duration? issueAt,
|
||||
String? audience,
|
||||
String? subject,
|
||||
String? issuer,
|
||||
String? jwtId,
|
||||
}) {
|
||||
try {
|
||||
final parts = token.split('.');
|
||||
final header = jsonBase64.decode(base64Padded(parts[0]));
|
||||
|
||||
Map<String, dynamic> header = jsonBase64.decode(base64Padded(parts[0]));
|
||||
if (header == null || header is! Map<String, dynamic>) {
|
||||
throw JWTInvalidError('invalid header');
|
||||
}
|
||||
|
||||
if (checkHeaderType && header['typ'] != 'JWT') {
|
||||
throw JWTInvalidError('not a jwt');
|
||||
@ -39,7 +43,7 @@ class JWT {
|
||||
final body = utf8.encode(parts[0] + '.' + parts[1]);
|
||||
final signature = base64Url.decode(base64Padded(parts[2]));
|
||||
|
||||
if (!algorithm.verify(key, body, signature)) {
|
||||
if (!algorithm.verify(key, Uint8List.fromList(body), signature)) {
|
||||
throw JWTInvalidError('invalid signature');
|
||||
}
|
||||
|
||||
@ -145,16 +149,16 @@ class JWT {
|
||||
dynamic payload;
|
||||
|
||||
/// Audience claim
|
||||
String audience;
|
||||
String? audience;
|
||||
|
||||
/// Subject claim
|
||||
String subject;
|
||||
String? subject;
|
||||
|
||||
/// Issuer claim
|
||||
String issuer;
|
||||
String? issuer;
|
||||
|
||||
/// JWT Id claim
|
||||
String jwtId;
|
||||
String? jwtId;
|
||||
|
||||
/// Sign and generate a new token.
|
||||
///
|
||||
@ -165,8 +169,8 @@ class JWT {
|
||||
String sign(
|
||||
Key key, {
|
||||
JWTAlgorithm algorithm = JWTAlgorithm.HS256,
|
||||
Duration expiresIn,
|
||||
Duration notBefore,
|
||||
Duration? expiresIn,
|
||||
Duration? notBefore,
|
||||
bool noIssueAt = false,
|
||||
}) {
|
||||
final header = {'alg': algorithm.name, 'typ': 'JWT'};
|
||||
@ -211,7 +215,7 @@ class JWT {
|
||||
base64Url.encode(
|
||||
algorithm.sign(
|
||||
key,
|
||||
utf8.encode(body),
|
||||
Uint8List.fromList(utf8.encode(body)),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:pointycastle/pointycastle.dart' as pc;
|
||||
|
||||
import 'errors.dart';
|
||||
import 'parser.dart';
|
||||
|
||||
abstract class Key {}
|
||||
@ -13,38 +14,52 @@ class SecretKey extends Key {
|
||||
|
||||
/// For RSA algorithm, in sign method
|
||||
class RSAPrivateKey extends Key {
|
||||
pc.RSAPrivateKey key;
|
||||
late pc.RSAPrivateKey key;
|
||||
|
||||
RSAPrivateKey(String pem) {
|
||||
key = parseRSAPrivateKeyPEM(pem);
|
||||
final _key = parseRSAPrivateKeyPEM(pem);
|
||||
if (_key == null) throw JWTParseError('RSAPrivateKey is invalid');
|
||||
key = _key;
|
||||
}
|
||||
}
|
||||
|
||||
/// For RSA algorithm, in verify method
|
||||
class RSAPublicKey extends Key {
|
||||
pc.RSAPublicKey key;
|
||||
late pc.RSAPublicKey key;
|
||||
|
||||
RSAPublicKey(String pem) {
|
||||
key = parseRSAPublicKeyPEM(pem);
|
||||
final _key = parseRSAPublicKeyPEM(pem);
|
||||
if (_key == null) throw JWTParseError('RSAPublicKey is invalid');
|
||||
key = _key;
|
||||
}
|
||||
}
|
||||
|
||||
/// For ECDSA algorithm, in sign method
|
||||
class ECPrivateKey extends Key {
|
||||
pc.ECPrivateKey key;
|
||||
int size;
|
||||
late pc.ECPrivateKey key;
|
||||
late int size;
|
||||
|
||||
ECPrivateKey(String pem) {
|
||||
key = parseECPrivateKeyPEM(pem);
|
||||
size = (key.parameters.curve.fieldSize / 8).round();
|
||||
final _key = parseECPrivateKeyPEM(pem);
|
||||
final _params = _key?.parameters;
|
||||
|
||||
if (_key == null) throw JWTParseError('ECPrivateKey is invalid');
|
||||
if (_params == null) {
|
||||
throw JWTParseError('ECPrivateKey parameters are invalid');
|
||||
}
|
||||
|
||||
key = _key;
|
||||
size = (_params.curve.fieldSize / 8).round();
|
||||
}
|
||||
}
|
||||
|
||||
/// For ECDSA algorithm, in verify method
|
||||
class ECPublicKey extends Key {
|
||||
pc.ECPublicKey key;
|
||||
late pc.ECPublicKey key;
|
||||
|
||||
ECPublicKey(String pem) {
|
||||
key = parseECPublicKeyPEM(pem);
|
||||
final _key = parseECPublicKeyPEM(pem);
|
||||
if (_key == null) throw JWTParseError('ECPublicKey is invalid');
|
||||
key = _key;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import 'dart:typed_data';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:pointycastle/pointycastle.dart' hide ECPoint;
|
||||
import 'package:pointycastle/pointycastle.dart' hide ECPoint, ECCurve;
|
||||
import 'package:pointycastle/ecc/ecc_fp.dart';
|
||||
|
||||
import 'utils.dart';
|
||||
@ -43,117 +43,168 @@ const Map<String, String> _ecCurves = {
|
||||
};
|
||||
|
||||
/// RSA Private Key -> PKCS#1 parser
|
||||
RSAPrivateKey _pkcs1RSAPrivateKey(Uint8List bytes) {
|
||||
RSAPrivateKey? _pkcs1RSAPrivateKey(Uint8List bytes) {
|
||||
final parser = ASN1Parser(bytes);
|
||||
final seq = parser.nextObject() as ASN1Sequence;
|
||||
final values = seq.elements.cast<ASN1Integer>();
|
||||
final values = seq.elements?.cast<ASN1Integer>();
|
||||
|
||||
if (values == null) return null;
|
||||
|
||||
final modulus = values[1].integer;
|
||||
final privateExponent = values[3].integer;
|
||||
final prime1 = values[4].integer;
|
||||
final prime2 = values[5].integer;
|
||||
|
||||
if (modulus == null ||
|
||||
privateExponent == null ||
|
||||
prime1 == null ||
|
||||
prime2 == null) return null;
|
||||
|
||||
return RSAPrivateKey(
|
||||
values[1].integer, // modulus
|
||||
values[3].integer, // privateExponent
|
||||
values[4].integer, // prime1
|
||||
values[5].integer, // prime2
|
||||
modulus,
|
||||
privateExponent,
|
||||
prime1,
|
||||
prime2,
|
||||
);
|
||||
}
|
||||
|
||||
/// RSA Private Key -> PKCS#8 parser
|
||||
RSAPrivateKey _pkcs8RSAPrivateKey(Uint8List bytes) {
|
||||
RSAPrivateKey? _pkcs8RSAPrivateKey(Uint8List bytes) {
|
||||
final parser = ASN1Parser(bytes);
|
||||
final seq = parser.nextObject() as ASN1Sequence;
|
||||
|
||||
final keySeq = seq.elements[2] as ASN1OctetString;
|
||||
final keySeq = seq.elements?[2] as ASN1OctetString?;
|
||||
if (keySeq == null) return null;
|
||||
final keyParser = ASN1Parser(keySeq.octets);
|
||||
|
||||
final valuesSeq = keyParser.nextObject() as ASN1Sequence;
|
||||
final values = valuesSeq.elements.cast<ASN1Integer>();
|
||||
final values = valuesSeq.elements?.cast<ASN1Integer>();
|
||||
|
||||
if (values == null) return null;
|
||||
|
||||
final modulus = values[1].integer;
|
||||
final privateExponent = values[3].integer;
|
||||
final prime1 = values[4].integer;
|
||||
final prime2 = values[5].integer;
|
||||
|
||||
if (modulus == null ||
|
||||
privateExponent == null ||
|
||||
prime1 == null ||
|
||||
prime2 == null) return null;
|
||||
|
||||
return RSAPrivateKey(
|
||||
values[1].integer, // modulus
|
||||
values[3].integer, // privateExponent
|
||||
values[4].integer, // prime1
|
||||
values[5].integer, // prime2
|
||||
modulus,
|
||||
privateExponent,
|
||||
prime1,
|
||||
prime2,
|
||||
);
|
||||
}
|
||||
|
||||
/// RSA Public Key -> PKCS#1 parser
|
||||
RSAPublicKey _pkcs1RSAPublicKey(Uint8List bytes) {
|
||||
RSAPublicKey? _pkcs1RSAPublicKey(Uint8List bytes) {
|
||||
final parser = ASN1Parser(bytes);
|
||||
final seq = parser.nextObject() as ASN1Sequence;
|
||||
final values = seq.elements.cast<ASN1Integer>();
|
||||
final values = seq.elements?.cast<ASN1Integer>();
|
||||
|
||||
if (values == null) return null;
|
||||
|
||||
final modulus = values[0].integer;
|
||||
final publicExponent = values[1].integer;
|
||||
|
||||
if (modulus == null || publicExponent == null) return null;
|
||||
|
||||
return RSAPublicKey(
|
||||
values[0].integer, // modulus
|
||||
values[1].integer, // publicExponent
|
||||
modulus,
|
||||
publicExponent,
|
||||
);
|
||||
}
|
||||
|
||||
/// RSA Public Key -> PKCS#8 parser
|
||||
RSAPublicKey _pkcs8RSAPublicKey(Uint8List bytes) {
|
||||
RSAPublicKey? _pkcs8RSAPublicKey(Uint8List bytes) {
|
||||
final parser = ASN1Parser(bytes);
|
||||
final seq = parser.nextObject() as ASN1Sequence;
|
||||
|
||||
final keySeq = seq.elements[1] as ASN1BitString;
|
||||
final keyParser = ASN1Parser(keySeq.stringValues);
|
||||
final keySeq = seq.elements?[1] as ASN1BitString?;
|
||||
if (keySeq == null || keySeq.stringValues == null) return null;
|
||||
final keyParser = ASN1Parser(Uint8List.fromList(keySeq.stringValues!));
|
||||
|
||||
final valuesSeq = keyParser.nextObject() as ASN1Sequence;
|
||||
final values = valuesSeq.elements.cast<ASN1Integer>();
|
||||
final values = valuesSeq.elements?.cast<ASN1Integer>();
|
||||
|
||||
return RSAPublicKey(
|
||||
values[0].integer, // modulus
|
||||
values[1].integer, // publicExponent
|
||||
);
|
||||
if (values == null) return null;
|
||||
|
||||
final modulus = values[0].integer;
|
||||
final publicExponent = values[1].integer;
|
||||
|
||||
if (modulus == null || publicExponent == null) return null;
|
||||
|
||||
return RSAPublicKey(modulus, publicExponent);
|
||||
}
|
||||
|
||||
/// ECDSA Private Key -> SEC 1 parser
|
||||
ECPrivateKey _sec1ECPrivateKey(Uint8List bytes) {
|
||||
ECPrivateKey? _sec1ECPrivateKey(Uint8List bytes) {
|
||||
final parser = ASN1Parser(bytes);
|
||||
final seq = parser.nextObject() as ASN1Sequence;
|
||||
|
||||
final privateKey = seq.elements[1] as ASN1OctetString;
|
||||
final privateKey = seq.elements?[1] as ASN1OctetString?;
|
||||
if (privateKey == null) return null;
|
||||
|
||||
final params = seq.elements[2];
|
||||
final params = seq.elements?[2];
|
||||
if (params == null || params.valueBytes == null) return null;
|
||||
final paramsParser = ASN1Parser(params.valueBytes);
|
||||
final oid = (paramsParser.nextObject() as ASN1ObjectIdentifier)
|
||||
.objectIdentifierAsString;
|
||||
final curve = _ecCurves[oid];
|
||||
|
||||
if (privateKey.valueBytes == null || curve == null) return null;
|
||||
|
||||
return ECPrivateKey(
|
||||
decodeBigInt(privateKey.valueBytes),
|
||||
decodeBigInt(privateKey.valueBytes!),
|
||||
ECDomainParameters(curve),
|
||||
);
|
||||
}
|
||||
|
||||
/// ECDSA Private Key -> PKCS#8 parser
|
||||
ECPrivateKey _pkcs8ECPrivateKey(Uint8List bytes) {
|
||||
ECPrivateKey? _pkcs8ECPrivateKey(Uint8List bytes) {
|
||||
final parser = ASN1Parser(bytes);
|
||||
final seq = parser.nextObject() as ASN1Sequence;
|
||||
if (seq.elements == null) return null;
|
||||
|
||||
final oidSeq = seq.elements[1] as ASN1Sequence;
|
||||
final oidSeq = seq.elements?[1] as ASN1Sequence?;
|
||||
if (oidSeq == null || oidSeq.elements == null) return null;
|
||||
final oid =
|
||||
(oidSeq.elements[1] as ASN1ObjectIdentifier).objectIdentifierAsString;
|
||||
(oidSeq.elements![1] as ASN1ObjectIdentifier).objectIdentifierAsString;
|
||||
final curve = _ecCurves[oid];
|
||||
|
||||
final privateKeyParser = ASN1Parser(seq.elements[2].valueBytes);
|
||||
final privateKeyParser = ASN1Parser(seq.elements![2].valueBytes);
|
||||
final privateKeySeq = privateKeyParser.nextObject() as ASN1Sequence;
|
||||
final privateKey = (privateKeySeq.elements[1] as ASN1OctetString);
|
||||
if (privateKeySeq.elements == null) return null;
|
||||
final privateKey = (privateKeySeq.elements![1] as ASN1OctetString);
|
||||
|
||||
if (privateKey.valueBytes == null || curve == null) return null;
|
||||
|
||||
return ECPrivateKey(
|
||||
decodeBigInt(privateKey.valueBytes),
|
||||
decodeBigInt(privateKey.valueBytes!),
|
||||
ECDomainParameters(curve),
|
||||
);
|
||||
}
|
||||
|
||||
/// ECDSA Public Key -> PKCS#8 parser
|
||||
ECPublicKey _pkcs8ECPublicKey(Uint8List bytes) {
|
||||
ECPublicKey? _pkcs8ECPublicKey(Uint8List bytes) {
|
||||
final parser = ASN1Parser(bytes);
|
||||
final seq = parser.nextObject() as ASN1Sequence;
|
||||
if (seq.elements == null) return null;
|
||||
|
||||
final oidSeq = seq.elements[0] as ASN1Sequence;
|
||||
final oidSeq = seq.elements![0] as ASN1Sequence;
|
||||
if (oidSeq.elements == null) return null;
|
||||
final oid =
|
||||
(oidSeq.elements[1] as ASN1ObjectIdentifier).objectIdentifierAsString;
|
||||
(oidSeq.elements![1] as ASN1ObjectIdentifier).objectIdentifierAsString;
|
||||
final curve = _ecCurves[oid];
|
||||
|
||||
var publicKeyBytes = seq.elements[1].valueBytes;
|
||||
if (curve == null) return null;
|
||||
|
||||
var publicKeyBytes = seq.elements![1].valueBytes;
|
||||
if (publicKeyBytes == null) return null;
|
||||
if (publicKeyBytes[0] == 0) {
|
||||
publicKeyBytes = publicKeyBytes.sublist(1);
|
||||
}
|
||||
@ -164,12 +215,17 @@ ECPublicKey _pkcs8ECPublicKey(Uint8List bytes) {
|
||||
final bigX = decodeBigIntWithSign(1, x);
|
||||
final bigY = decodeBigIntWithSign(1, y);
|
||||
final params = ECDomainParameters(curve);
|
||||
final ecCurve = ECCurve(
|
||||
null,
|
||||
params.curve.a?.toBigInteger(),
|
||||
params.curve.b?.toBigInteger(),
|
||||
);
|
||||
|
||||
return ECPublicKey(
|
||||
ECPoint(
|
||||
params.curve,
|
||||
params.curve.fromBigInteger(bigX),
|
||||
params.curve.fromBigInteger(bigY),
|
||||
ecCurve,
|
||||
ecCurve.fromBigInteger(bigX),
|
||||
ecCurve.fromBigInteger(bigY),
|
||||
compressed,
|
||||
),
|
||||
params,
|
||||
@ -177,7 +233,7 @@ ECPublicKey _pkcs8ECPublicKey(Uint8List bytes) {
|
||||
}
|
||||
|
||||
/// Parse RSA private key from pem string
|
||||
RSAPrivateKey parseRSAPrivateKeyPEM(String pem) {
|
||||
RSAPrivateKey? parseRSAPrivateKeyPEM(String pem) {
|
||||
if (pem.contains(_pkcs1RSAPrivateHeader) &&
|
||||
pem.contains(_pkcs1RSAPrivateFooter)) {
|
||||
final data = pem
|
||||
@ -204,7 +260,7 @@ RSAPrivateKey parseRSAPrivateKeyPEM(String pem) {
|
||||
}
|
||||
|
||||
/// Parse RSA public key from pem string
|
||||
RSAPublicKey parseRSAPublicKeyPEM(String pem) {
|
||||
RSAPublicKey? parseRSAPublicKeyPEM(String pem) {
|
||||
if (pem.contains(_pkcs1RSAPublicHeader) &&
|
||||
pem.contains(_pkcs1RSAPublicFooter)) {
|
||||
final data = pem
|
||||
@ -231,7 +287,7 @@ RSAPublicKey parseRSAPublicKeyPEM(String pem) {
|
||||
}
|
||||
|
||||
/// Parse ECDSA private key from pem string
|
||||
ECPrivateKey parseECPrivateKeyPEM(String pem) {
|
||||
ECPrivateKey? parseECPrivateKeyPEM(String pem) {
|
||||
if (pem.contains(_sec1ECPrivateHeader) &&
|
||||
pem.contains(_sec1ECPrivateFooter)) {
|
||||
final data = pem
|
||||
@ -258,7 +314,7 @@ ECPrivateKey parseECPrivateKeyPEM(String pem) {
|
||||
}
|
||||
|
||||
/// Parse ECDSA public key from pem string
|
||||
ECPublicKey parseECPublicKeyPEM(String pem) {
|
||||
ECPublicKey? parseECPublicKeyPEM(String pem) {
|
||||
if (pem.contains(_pkcs8ECPublicHeader) &&
|
||||
pem.contains(_pkcs8ECPublicFooter)) {
|
||||
final data = pem
|
||||
|
Reference in New Issue
Block a user