v2.0.0-nullsafety.1

This commit is contained in:
Jonas Roussel
2021-03-03 16:06:33 +01:00
parent 7a2eadf146
commit 78cb96c7dd
7 changed files with 164 additions and 80 deletions

View File

@ -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);

View File

@ -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);
}

View File

@ -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)),
),
),
);

View File

@ -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;
}
}

View File

@ -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