parseDer static method
Parses DER-encoded EC public key.
Currently this is implemented only for very specific inputs: those generated by Apple's CryptoKit. Apple could decide to change their implementation in future (though it has no reason to). Therefore we would like to transition to a proper ASN.1 decoder.
Implementation
static EcKeyPairData parseDer(Uint8List der, {required KeyPairType type}) {
// Parsing of CryptoKit generated keys:
// Unfortunately our current solutions is not future proof. Apple may change
// the format in the future. We want to transition to a proper ASN.1 decoder.
final config = CupertinoEcDer.get(type);
final prefix = config.privateKeyPrefix;
final middle = config.privateKeyMiddle;
final numberLength = config.numberLength;
if (!bytesStartsWith(der, prefix, 0)) {
assert(() {
// ONLY IN DEBUG MODE (i.e. assertions enabled).
// In production, we don't want a parsing error to expose a private key.
throw UnsupportedError(
'Apple has changed CryptoKit $type key DER format prefix.\n'
'Got DER (part of the error message in debug mode only):\n'
'${hexFromBytes(der)}\n'
'Expected bytes at index 0:\n'
'${hexFromBytes(prefix)}\n'
'Actual bytes at 0:\n'
'${hexFromBytes(der.sublist(0, min(der.length, prefix.length)))}\n',
);
}());
throw UnsupportedError(
'Your version of package:cryptography supports only specific DER encodings from Apple CryptoKit',
);
}
final middleIndex = prefix.length + numberLength;
if (!bytesStartsWith(der, middle, middleIndex)) {
assert(() {
// ONLY IN DEBUG MODE (i.e. assertions enabled).
// In production, we don't want a parsing error to expose a private key.
throw UnsupportedError(
'Apple has changed CryptoKit $type key DER format middle part.\n'
'Got DER:\n'
'${hexFromBytes(der)}\n'
'Expected bytes at $middleIndex (part of the error message in debug mode only):\n'
'${hexFromBytes(middle)}\n'
'Actual bytes at $middleIndex:\n'
'${hexFromBytes(der.sublist(middleIndex, min(der.length, middleIndex + 12)))}\n',
);
}());
throw UnsupportedError(
'Your version of package:cryptography supports only specific DER encodings from Apple CryptoKit',
);
}
final dIndex = prefix.length;
final xIndex = middleIndex + middle.length;
final yIndex = xIndex + numberLength;
if (der.length != yIndex + numberLength) {
throw ArgumentError(
'Apple has changed CryptoKit $type key DER pattern. DER length should be ${yIndex + numberLength}, not ${der.length}',
);
}
return EcKeyPairData(
d: Uint8List.fromList(der.sublist(dIndex, dIndex + numberLength)),
x: Uint8List.fromList(der.sublist(xIndex, xIndex + numberLength)),
y: Uint8List.fromList(der.sublist(yIndex, yIndex + numberLength)),
type: type,
);
}