decryptWithJwk method

DidcommMessage decryptWithJwk(
  1. Map<String, dynamic> privateKeyJwk, [
  2. Map<String, dynamic>? senderPublicKeyJwk
])

Implementation

DidcommMessage decryptWithJwk(Map<String, dynamic> privateKeyJwk,
    [Map<String, dynamic>? senderPublicKeyJwk]) {
  _decodeProtected();

  var crv = privateKeyJwk['crv'];
  elliptic.Curve? c;
  dynamic receiverPrivate, epkPublic;

  if (crv.startsWith('P') || crv.startsWith('secp256k1')) {
    if (crv == 'P-256') {
      c = elliptic.getP256();
    } else if (crv == 'P-384') {
      c = elliptic.getP384();
    } else if (crv == 'P-521') {
      c = elliptic.getP521();
    } else if (crv == 'secp256k1') {
      c = elliptic.getSecp256k1();
    } else {
      throw UnimplementedError("Curve `$crv` not supported");
    }

    receiverPrivate = elliptic.PrivateKey(
        c,
        bytesToUnsignedInt(
            base64Decode(addPaddingToBase64(privateKeyJwk['d']))));
    epkPublic = elliptic.PublicKey.fromPoint(
        c,
        elliptic.AffinePoint.fromXY(
            bytesToUnsignedInt(
                base64Decode(addPaddingToBase64(protectedHeaderEpk!['x']))),
            bytesToUnsignedInt(
                base64Decode(addPaddingToBase64(protectedHeaderEpk!['y'])))));
  } else if (crv.startsWith('X')) {
    receiverPrivate = base64Decode(addPaddingToBase64(privateKeyJwk['d']));
    epkPublic = base64Decode(addPaddingToBase64(protectedHeaderEpk!['x']));
  } else {
    throw UnimplementedError("Curve `$crv` not supported");
  }

  //2) compute shared Secret
  List<int> sharedSecret;
  bool authcrypt = false;
  if (protectedHeaderAlg!.startsWith('ECDH-ES')) {
    sharedSecret =
        _ecdhES(receiverPrivate, epkPublic, apv: protectedHeaderApv);
  } else if (protectedHeaderAlg!.startsWith('ECDH-1PU')) {
    authcrypt = true;
    if (senderPublicKeyJwk == null) {
      throw Exception('Public key of sender needed');
    }
    //var senderDid = base64Decode(addPaddingToBase64(apu));
    Object senderPubKey;
    if (crv.startsWith('P') || crv.startsWith('secp256k1')) {
      senderPubKey = elliptic.PublicKey.fromPoint(
          c!,
          elliptic.AffinePoint.fromXY(
              bytesToUnsignedInt(
                  base64Decode(addPaddingToBase64(senderPublicKeyJwk['x']))),
              bytesToUnsignedInt(base64Decode(
                  addPaddingToBase64(senderPublicKeyJwk['y'])))));
    } else if (crv.startsWith('X')) {
      senderPubKey =
          base64Decode(addPaddingToBase64(senderPublicKeyJwk['x']));
    } else {
      throw UnimplementedError("Curve `$crv` is not supported");
    }

    sharedSecret = _ecdh1PU(
        receiverPrivate,
        receiverPrivate,
        epkPublic,
        senderPubKey,
        base64Decode(addPaddingToBase64(tag)),
        protectedHeaderAlg!,
        protectedHeaderApu!,
        protectedHeaderApv!);
  } else {
    throw UnimplementedError("Algorithm `${protectedHeaderAlg!}`"
        " is not supported");
  }
  //3) Decrypt cek

  //a)search encrypted cek
  String encryptedCek = '';
  for (var entry in recipients) {
    var kid = entry['header']['kid']!;
    if (kid == privateKeyJwk['kid']) {
      encryptedCek = entry['encrypted_key'];
      break;
    }
  }

  Map<String, dynamic> sharedSecretJwk = {
    'kty': 'oct',
    'k': base64UrlEncode(sharedSecret)
  };

  var keyWrapKey = KeyPair.fromJwk(sharedSecretJwk);
  Encrypter kw = keyWrapKey.publicKey!
      .createEncrypter(algorithms.encryption.aes.keyWrap);
  var decryptedCek = kw.decrypt(
      EncryptionResult(base64Decode(addPaddingToBase64(encryptedCek))));
  var cek = SymmetricKey(keyValue: decryptedCek);
  //4) Decrypt Body
  Encrypter e;
  if (protectedHeaderEnc! == 'A256CBC-HS512') {
    e = cek.createEncrypter(algorithms.encryption.aes.cbcWithHmac.sha512);
  } else if (protectedHeaderEnc == 'A256GCM') {
    e = cek.createEncrypter(algorithms.encryption.aes.gcm);
  } else {
    throw UnimplementedError();
  }

  var toDecrypt = EncryptionResult(
      base64Decode(addPaddingToBase64(ciphertext)),
      authenticationTag: base64Decode(addPaddingToBase64(tag)),
      additionalAuthenticatedData: ascii.encode(protectedHeader),
      initializationVector: base64Decode(addPaddingToBase64(iv)));

  var plain = e.decrypt(toDecrypt);
  //5)return body
  DidcommMessage m;
  Map message = jsonDecode(utf8.decode(plain));

  if (message.containsKey('id')) {
    m = DidcommPlaintextMessage.fromJson(message);
    m as DidcommPlaintextMessage;
    if (authcrypt) {
      if (m.from != null) {
        if (m.from != protectedHeaderSkid!.split('#').first) {
          throw Exception(
              'From value of plaintext Message do not match skid of encrypted message');
        }
      } else {
        throw Exception(
            'from header in plaintext message is required if authcrypt is used');
      }
    }
  } else if (message.containsKey('ciphertext')) {
    m = DidcommSignedMessage.fromJson(message);
  } else if (message.containsKey('signatures')) {
    m = DidcommEncryptedMessage.fromJson(message);
  } else {
    throw Exception('Unknown Message type');
  }

  return m;
}