getPayloadFor method

  1. @override
List<int>? getPayloadFor(
  1. JsonWebKey? key,
  2. JoseHeader header,
  3. JoseRecipient recipient
)
override

Implementation

@override
List<int>? getPayloadFor(
  JsonWebKey? key,
  JoseHeader header,
  JoseRecipient recipient,
) {
  if (key == null) {
    return null;
  }

  var aad = sharedProtectedHeader?.toBase64EncodedString() ?? '';
  if (additionalAuthenticatedData != null) {
    aad += '.${String.fromCharCodes(additionalAuthenticatedData!)}';
  }
  if (header.encryptionAlgorithm == 'none') {
    throw JoseException('Encryption algorithm cannot be `none`');
  }

  JsonWebKey cek;
  if (header.algorithm == 'dir') {
    cek = key;
  } else if (header.algorithm != null &&
      header.algorithm!.startsWith('ECDH-ES')) {
    // ECDH-ES key agreement
    final epk = header.ephemeralPublicKey;
    if (epk == null) {
      throw JoseException('Missing ephemeral public key (epk) in header');
    }
    final encAlgorithm = header.encryptionAlgorithm!;
    final algId = ecdhAlgorithmId(header.algorithm!, encAlgorithm);
    final keyLen = ecdhKeyDataLen(header.algorithm!, encAlgorithm);

    final apu = header.agreementPartyUInfo != null
        ? Uint8List.fromList(
            decodeBase64EncodedBytes(header.agreementPartyUInfo!))
        : null;
    final apv = header.agreementPartyVInfo != null
        ? Uint8List.fromList(
            decodeBase64EncodedBytes(header.agreementPartyVInfo!))
        : null;

    final derivedKey = ecdhEsDecrypt(
      recipientPrivateKey: key,
      ephemeralPublicKey: epk,
      algorithmId: algId,
      keyDataLen: keyLen,
      apu: apu,
      apv: apv,
    );

    if (header.algorithm == 'ECDH-ES') {
      // Direct key agreement — derived key IS the CEK
      cek = JsonWebKey.fromJson({
        'kty': 'oct',
        'k': encodeBase64EncodedBytes(derivedKey),
        'use': 'enc',
        'key_ops': ['encrypt', 'decrypt'],
      })!;
    } else {
      // ECDH-ES+A*KW — derived key unwraps the CEK
      final unwrappedCekBytes = ecdhEsUnwrapKey(derivedKey, recipient.data);
      cek = JsonWebKey.fromJson({
        'kty': 'oct',
        'k': encodeBase64EncodedBytes(unwrappedCekBytes),
        'use': 'enc',
        'key_ops': ['encrypt', 'decrypt'],
      })!;
    }
  } else {
    cek = key.unwrapKey(recipient.data, algorithm: header.algorithm);
  }

  var uncompressed = cek.decrypt(data,
      initializationVector: initializationVector,
      additionalAuthenticatedData: Uint8List.fromList(aad.codeUnits),
      authenticationTag: authenticationTag,
      algorithm: header.encryptionAlgorithm);
  switch (header.compressionAlgorithm) {
    case null:
      return uncompressed;
    case 'DEF':
      return Inflate(uncompressed).getBytes();
    default:
      throw JoseException(
          'Unsupported compression algorithm ${header.compressionAlgorithm}');
  }
}