signDigest function

Future<String> signDigest(
  1. String digestBase64,
  2. String privateKeyBase64OrPem
)

Implementation

Future<String> signDigest(
    String digestBase64, String privateKeyBase64OrPem) async {
  if (digestBase64.isEmpty) {
    throw ArgumentError('El parámetro "digestBase64" es requerido.');
  }
  if (privateKeyBase64OrPem.isEmpty) {
    throw ArgumentError('El parámetro "privateKeyBase64OrPem" es requerido.');
  }

  // Preparar PEM de la clave privada: si la entrada ya tiene header PEM, la usamos.
  String privatePem;
  final trimmed = privateKeyBase64OrPem.trim();
  if (trimmed.startsWith('-----BEGIN')) {
    privatePem = trimmed;
  } else {
    // Intentamos decodificar base64 y obtener el PEM resultante.
    try {
      final decoded = utf8.decode(base64.decode(trimmed));
      if (decoded.trim().startsWith('-----BEGIN')) {
        privatePem = decoded;
      } else {
        throw FormatException(
            'La clave privada base64 decodificada no contiene un PEM válido.');
      }
    } catch (e) {
      throw FormatException(
          'No se pudo decodificar privateKeyBase64OrPem como base64 PEM: $e');
    }
  }

  // Parsear la clave privada a RSAPrivateKey
  final priv = CryptoUtils.rsaPrivateKeyFromPem(privatePem);
  if (priv == null || priv is! RSAPrivateKey) {
    throw FormatException(
        'No se pudo parsear la clave privada a RSAPrivateKey.');
  }

  // Decodificar el digest (base64) a bytes
  final messageBytes = base64.decode(digestBase64);

  // Firmar usando Signer de pointycastle: SHA-256/RSA (PKCS#1 v1.5)
  final signer = Signer('SHA-256/RSA');
  final privParams = PrivateKeyParameter<RSAPrivateKey>(priv);
  try {
    signer.init(true, privParams);
    final signature = signer.generateSignature(Uint8List.fromList(messageBytes))
        as RSASignature;
    final sigBytes = signature.bytes;
    return base64.encode(sigBytes);
  } catch (e) {
    throw Exception('Error al firmar el digest: $e');
  }
}