fromRawBytes static method

Future<PrivateKey> fromRawBytes(
  1. Uint8List bytes
)

Implementation

static Future<p2pkeys.PrivateKey> fromRawBytes(Uint8List bytes) async {
  if (bytes.isEmpty) {
    throw FormatException('Empty byte array provided');
  }

  try {
    // Debug information

    final parser = pc.ASN1Parser(bytes);
    final asn1Object = parser.nextObject();

    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) {
    if (e is FormatException) {
      rethrow;
    }
    throw FormatException('Failed to parse RSA private key: $e');
  }
}