fromRawBytes static method
Implementation
static Future<p2pkeys.PrivateKey> fromRawBytes(Uint8List bytes) async {
if (bytes.isEmpty) {
throw FormatException('Empty byte array provided');
}
try {
// Debug information
print('Parsing DER bytes of length: ${bytes.length}');
print('First few bytes: ${bytes.take(10).map((b) => b.toRadixString(16).padLeft(2, '0')).join(' ')}');
final parser = pc.ASN1Parser(bytes);
final asn1Object = parser.nextObject();
if (asn1Object == null) {
throw FormatException('Failed to parse ASN.1 object from bytes');
}
if (asn1Object is! pc.ASN1Sequence) {
throw FormatException('Expected ASN.1 SEQUENCE but got: ${asn1Object.runtimeType}');
}
final asn1Sequence = asn1Object;
// Parse the ASN.1 structure according to PKCS#1
// RSAPrivateKey ::= SEQUENCE {
// version Version,
// modulus INTEGER, -- n
// publicExponent INTEGER, -- e
// privateExponent INTEGER, -- d
// prime1 INTEGER, -- p
// prime2 INTEGER, -- q
// exponent1 INTEGER, -- d mod (p-1)
// exponent2 INTEGER, -- d mod (q-1)
// coefficient INTEGER, -- (inverse of q) mod p
// otherPrimeInfos OtherPrimeInfos OPTIONAL
// }
if (asn1Sequence.elements == null || asn1Sequence.elements!.length < 9) {
throw FormatException('RSA private key sequence does not contain required elements. Found: ${asn1Sequence.elements?.length ?? 0}');
}
// Validate and extract each element with proper type checking
if (asn1Sequence.elements![0] is! pc.ASN1Integer) {
throw FormatException('Expected version to be ASN1Integer');
}
final version = (asn1Sequence.elements![0] as pc.ASN1Integer).integer;
if (version != BigInt.from(0)) {
throw FormatException('Unsupported RSA private key version: $version');
}
// Extract and check all the required integers
final elements = <BigInt?>[];
for (int i = 0; i < 9; i++) {
if (asn1Sequence.elements![i] is! pc.ASN1Integer) {
throw FormatException('Expected ASN1Integer at position $i but got ${asn1Sequence.elements![i].runtimeType}');
}
elements.add((asn1Sequence.elements![i] as pc.ASN1Integer).integer);
}
final modulus = elements[1];
final publicExponent = elements[2];
final privateExponent = elements[3];
final p = elements[4];
final q = elements[5];
final dP = elements[6];
final dQ = elements[7];
final qInv = elements[8];
// Validate that no required values are null
if (modulus == null || publicExponent == null || privateExponent == null ||
p == null || q == null || dP == null || dQ == null || qInv == null) {
throw FormatException('One or more required RSA parameters are null');
}
final privateKey = pc.RSAPrivateKey(
modulus,
privateExponent,
p,
q
);
final publicKey = pc.RSAPublicKey(
modulus,
publicExponent,
);
return RsaPrivateKey(privateKey, RsaPublicKey(publicKey));
} catch (e) {
print('Error parsing RSA private key: $e');
if (e is FormatException) {
rethrow;
}
throw FormatException('Failed to parse RSA private key: $e');
}
}