Search in sources :

Example 81 with PublicKey

use of com.quorum.tessera.encryption.PublicKey in project tessera by ConsenSys.

the class TransactionManagerImpl method storePayload.

@Override
public synchronized MessageHash storePayload(final EncodedPayload payload) {
    final byte[] digest = payloadDigest.digest(payload.getCipherText());
    final MessageHash transactionHash = new MessageHash(digest);
    final List<AffectedTransaction> affectedContractTransactions = privacyHelper.findAffectedContractTransactionsFromPayload(payload);
    final TxHash txHash = TxHash.from(transactionHash.getHashBytes());
    if (!privacyHelper.validatePayload(txHash, payload, affectedContractTransactions)) {
        return transactionHash;
    }
    final Set<TxHash> invalidSecurityHashes = enclave.findInvalidSecurityHashes(payload, affectedContractTransactions);
    final EncodedPayload encodedPayload;
    if (!invalidSecurityHashes.isEmpty()) {
        encodedPayload = privacyHelper.sanitisePrivacyPayload(txHash, payload, invalidSecurityHashes);
    } else {
        encodedPayload = payload;
    }
    LOGGER.debug("AffectedContractTransaction.size={} InvalidSecurityHashes.size={}", affectedContractTransactions.size(), invalidSecurityHashes.size());
    if (enclave.getPublicKeys().contains(encodedPayload.getSenderKey())) {
        // This is our own message that we are rebuilding, handle separately
        this.resendManager.acceptOwnMessage(encodedPayload);
        LOGGER.debug("Stored payload for which we were the sender. Hash = {}", transactionHash);
        return transactionHash;
    }
    // This is a transaction with a different node as the sender
    final Optional<EncryptedTransaction> tx = this.encryptedTransactionDAO.retrieveByHash(transactionHash);
    if (tx.isEmpty()) {
        // This is the first time we have seen the payload, so just save it to the database as is
        this.encryptedTransactionDAO.save(new EncryptedTransaction(transactionHash, encodedPayload));
        LOGGER.debug("Stored new payload with hash {}", transactionHash);
        return transactionHash;
    }
    final EncryptedTransaction encryptedTransaction = tx.get();
    final EncodedPayload existing = encryptedTransaction.getPayload();
    // check all the other bits of the payload match
    final boolean txMatches = Stream.of(Arrays.equals(existing.getCipherText(), encodedPayload.getCipherText()), Objects.equals(existing.getCipherTextNonce(), encodedPayload.getCipherTextNonce()), Objects.equals(existing.getSenderKey(), encodedPayload.getSenderKey()), Objects.equals(existing.getRecipientNonce(), encodedPayload.getRecipientNonce()), Objects.equals(existing.getPrivacyMode(), encodedPayload.getPrivacyMode()), Arrays.equals(existing.getExecHash(), encodedPayload.getExecHash()), // checks the affected contracts contents match
    Objects.equals(existing.getAffectedContractTransactions().size(), payload.getAffectedContractTransactions().size()), existing.getAffectedContractTransactions().entrySet().stream().allMatch(e -> e.getValue().equals(payload.getAffectedContractTransactions().get(e.getKey())))).allMatch(p -> p);
    if (!txMatches) {
        throw new RuntimeException("Invalid existing transaction");
    }
    // this is the easiest way to tell if a recipient has already been included
    for (RecipientBox existingBox : existing.getRecipientBoxes()) {
        if (Objects.equals(existingBox, encodedPayload.getRecipientBoxes().get(0))) {
            // recipient must already exist, so just act as though things went normally
            LOGGER.info("Recipient already existed in payload with hash {}", transactionHash);
            return transactionHash;
        }
    }
    final EncodedPayload.Builder existingPayloadBuilder = EncodedPayload.Builder.from(existing);
    // Boxes are all handled the same way. The new payload will only contain one box, and this will
    // be prepended
    // to the the list of existing boxes.
    final List<RecipientBox> existingBoxes = new ArrayList<>(existing.getRecipientBoxes());
    existingBoxes.add(0, encodedPayload.getRecipientBoxes().get(0));
    existingPayloadBuilder.withRecipientBoxes(existingBoxes.stream().map(RecipientBox::getData).collect(Collectors.toList()));
    // is handled implicitly, as we don't need to add anything to the recipients list
    if (PrivacyMode.PRIVATE_STATE_VALIDATION == encodedPayload.getPrivacyMode()) {
        // PSV transaction, we have one box, and the relevant key is the first value
        // the existing payload will contain the key, but we can remove it and prepend the key again,
        // along with the
        // box
        final List<PublicKey> existingKeys = new ArrayList<>(existing.getRecipientKeys());
        final PublicKey newRecipient = encodedPayload.getRecipientKeys().get(0);
        if (!existingKeys.contains(newRecipient)) {
            throw new RuntimeException("expected recipient not found");
        }
        existingKeys.remove(newRecipient);
        existingKeys.add(0, newRecipient);
        existingPayloadBuilder.withNewRecipientKeys(existingKeys);
    } else if (!encodedPayload.getRecipientKeys().isEmpty()) {
        // Regular tx, add the recipient and the box
        final List<PublicKey> existingKeys = new ArrayList<>(existing.getRecipientKeys());
        final PublicKey newRecipient = encodedPayload.getRecipientKeys().get(0);
        existingKeys.add(0, newRecipient);
        existingPayloadBuilder.withNewRecipientKeys(existingKeys);
    }
    encryptedTransaction.setPayload(existingPayloadBuilder.build());
    this.encryptedTransactionDAO.update(encryptedTransaction);
    LOGGER.info("Updated existing payload with hash {}", transactionHash);
    return transactionHash;
}
Also used : PublicKey(com.quorum.tessera.encryption.PublicKey)

Example 82 with PublicKey

use of com.quorum.tessera.encryption.PublicKey in project tessera by ConsenSys.

the class EncodedPayloadManagerImplTest method createCallsEnclaveCorrectly.

@Test
public void createCallsEnclaveCorrectly() {
    final byte[] payload = "test payload".getBytes();
    final String senderKeyBase64 = "BULeR8JyUWhiuuCMU/HLA0Q5pzkYT+cHII3ZKBey3Bo=";
    final PublicKey sender = PublicKey.from(Base64.getDecoder().decode(senderKeyBase64));
    final String singleRecipientBase64 = "QfeDAys9MPDs2XHExtc84jKGHxZg/aj52DTh0vtA3Xc=";
    final PublicKey singleRecipient = PublicKey.from(Base64.getDecoder().decode(singleRecipientBase64));
    final List<PublicKey> recipients = List.of(singleRecipient);
    final SendRequest request = mock(SendRequest.class);
    when(request.getSender()).thenReturn(sender);
    when(request.getRecipients()).thenReturn(recipients);
    when(request.getPayload()).thenReturn(payload);
    when(request.getPrivacyMode()).thenReturn(PrivacyMode.STANDARD_PRIVATE);
    when(request.getAffectedContractTransactions()).thenReturn(emptySet());
    when(request.getExecHash()).thenReturn(new byte[0]);
    final EncodedPayload sampleReturnPayload = mock(EncodedPayload.class);
    when(enclave.encryptPayload(any(), eq(sender), eq(List.of(singleRecipient, sender)), any())).thenReturn(sampleReturnPayload);
    final EncodedPayload encodedPayload = encodedPayloadManager.create(request);
    assertThat(encodedPayload).isEqualTo(sampleReturnPayload);
    verify(privacyHelper).findAffectedContractTransactionsFromSendRequest(emptySet());
    verify(privacyHelper).validateSendRequest(PrivacyMode.STANDARD_PRIVATE, List.of(singleRecipient, sender), emptyList(), emptySet());
    verify(enclave).encryptPayload(eq(request.getPayload()), eq(sender), eq(List.of(singleRecipient, sender)), any());
    verify(enclave).getForwardingKeys();
}
Also used : SendRequest(com.quorum.tessera.transaction.SendRequest) PublicKey(com.quorum.tessera.encryption.PublicKey) Test(org.junit.Test)

Example 83 with PublicKey

use of com.quorum.tessera.encryption.PublicKey in project tessera by ConsenSys.

the class PrivacyHelperTest method validatePsvPayloadRecipientsMismatched.

@Test
public void validatePsvPayloadRecipientsMismatched() {
    PublicKey recipient1 = PublicKey.from("Recipient1".getBytes());
    PublicKey recipient2 = PublicKey.from("Recipient2".getBytes());
    final TxHash txHash = TxHash.from("someHash".getBytes());
    EncodedPayload payload = mock(EncodedPayload.class);
    when(payload.getPrivacyMode()).thenReturn(PrivacyMode.PRIVATE_STATE_VALIDATION);
    when(payload.getSenderKey()).thenReturn(recipient1);
    when(payload.getRecipientKeys()).thenReturn(List.of(recipient1, recipient2));
    Map<TxHash, SecurityHash> affected = new HashMap<>();
    affected.put(TxHash.from("Hash1".getBytes()), SecurityHash.from("secHash1".getBytes()));
    affected.put(TxHash.from("Hash2".getBytes()), SecurityHash.from("secHash2".getBytes()));
    when(payload.getAffectedContractTransactions()).thenReturn(affected);
    EncodedPayload affectedPayload1 = mock(EncodedPayload.class);
    when(affectedPayload1.getPrivacyMode()).thenReturn(PrivacyMode.PRIVATE_STATE_VALIDATION);
    when(affectedPayload1.getRecipientKeys()).thenReturn(singletonList(recipient1));
    AffectedTransaction affectedTransaction1 = mock(AffectedTransaction.class);
    when(affectedTransaction1.getPayload()).thenReturn(affectedPayload1);
    when(affectedTransaction1.getHash()).thenReturn(TxHash.from("hash1".getBytes()));
    EncodedPayload affectedPayload2 = mock(EncodedPayload.class);
    when(affectedPayload2.getPrivacyMode()).thenReturn(PrivacyMode.PRIVATE_STATE_VALIDATION);
    when(affectedPayload2.getRecipientKeys()).thenReturn(List.of(recipient1, recipient2));
    AffectedTransaction affectedTransaction2 = mock(AffectedTransaction.class);
    when(affectedTransaction2.getPayload()).thenReturn(affectedPayload2);
    when(affectedTransaction2.getHash()).thenReturn(TxHash.from("hash2".getBytes()));
    assertThatExceptionOfType(PrivacyViolationException.class).isThrownBy(() -> privacyHelper.validatePayload(txHash, payload, List.of(affectedTransaction1, affectedTransaction2))).withMessage("Recipients mismatched for Affected Txn " + TxHash.from("hash1".getBytes()).encodeToBase64());
}
Also used : PublicKey(com.quorum.tessera.encryption.PublicKey) Test(org.junit.Test)

Example 84 with PublicKey

use of com.quorum.tessera.encryption.PublicKey in project tessera by ConsenSys.

the class PrivacyHelperTest method testValidateSendPsv.

@Test
public void testValidateSendPsv() {
    PublicKey recipient1 = mock(PublicKey.class);
    PublicKey recipient2 = mock(PublicKey.class);
    final EncodedPayload encodedPayload = mock(EncodedPayload.class);
    when(encodedPayload.getPrivacyMode()).thenReturn(PrivacyMode.PRIVATE_STATE_VALIDATION);
    when(encodedPayload.getRecipientKeys()).thenReturn(List.of(recipient1, recipient2));
    final AffectedTransaction affectedTransaction = mock(AffectedTransaction.class);
    when(affectedTransaction.getPayload()).thenReturn(encodedPayload);
    final TxHash hash = TxHash.from("someHash".getBytes());
    when(affectedTransaction.getHash()).thenReturn(hash);
    boolean isValid = privacyHelper.validateSendRequest(PrivacyMode.PRIVATE_STATE_VALIDATION, List.of(recipient1, recipient2), singletonList(affectedTransaction), emptySet());
    assertThat(isValid).isTrue();
}
Also used : PublicKey(com.quorum.tessera.encryption.PublicKey) Test(org.junit.Test)

Example 85 with PublicKey

use of com.quorum.tessera.encryption.PublicKey in project tessera by ConsenSys.

the class PrivacyHelperTest method testValidateSendPsvMoreRecipientsAffected.

@Test
public void testValidateSendPsvMoreRecipientsAffected() {
    PublicKey recipient1 = mock(PublicKey.class);
    PublicKey recipient2 = mock(PublicKey.class);
    final EncodedPayload encodedPayload = mock(EncodedPayload.class);
    when(encodedPayload.getPrivacyMode()).thenReturn(PrivacyMode.PRIVATE_STATE_VALIDATION);
    when(encodedPayload.getRecipientKeys()).thenReturn(List.of(recipient1, recipient2));
    final AffectedTransaction affectedTransaction = mock(AffectedTransaction.class);
    when(affectedTransaction.getPayload()).thenReturn(encodedPayload);
    final TxHash hash = TxHash.from("someHash".getBytes());
    when(affectedTransaction.getHash()).thenReturn(hash);
    assertThatExceptionOfType(PrivacyViolationException.class).isThrownBy(() -> privacyHelper.validateSendRequest(PrivacyMode.PRIVATE_STATE_VALIDATION, List.of(recipient1), singletonList(affectedTransaction), emptySet())).withMessage("Recipients mismatched for Affected Txn " + hash.encodeToBase64());
}
Also used : PublicKey(com.quorum.tessera.encryption.PublicKey) Test(org.junit.Test)

Aggregations

PublicKey (com.quorum.tessera.encryption.PublicKey)281 Test (org.junit.Test)213 Response (jakarta.ws.rs.core.Response)59 MessageHash (com.quorum.tessera.data.MessageHash)57 EncodedPayload (com.quorum.tessera.enclave.EncodedPayload)48 Collectors (java.util.stream.Collectors)32 PrivacyGroup (com.quorum.tessera.enclave.PrivacyGroup)28 NodeInfo (com.quorum.tessera.partyinfo.node.NodeInfo)25 java.util (java.util)23 SendResponse (com.quorum.tessera.api.SendResponse)21 Nonce (com.quorum.tessera.encryption.Nonce)20 Recipient (com.quorum.tessera.partyinfo.node.Recipient)20 Operation (io.swagger.v3.oas.annotations.Operation)20 ApiResponse (io.swagger.v3.oas.annotations.responses.ApiResponse)20 Stream (java.util.stream.Stream)19 ReceiveResponse (com.quorum.tessera.transaction.ReceiveResponse)18 EncryptedTransaction (com.quorum.tessera.data.EncryptedTransaction)17 PrivacyMode (com.quorum.tessera.enclave.PrivacyMode)17 URI (java.net.URI)17 SendRequest (com.quorum.tessera.api.SendRequest)15