Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: add more support for signatures #249

Merged
merged 2 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -305,14 +305,52 @@ public void writeTo(@NonNull final MessageDigest digest, final int offset, final
digest.update(buffer, Math.toIntExact(start + offset), length);
}

/**
* Same as {@link #updateSignature(Signature, int, int)} with offset 0 and length equal to the length of this
* {@link Bytes} object.
*/
public void updateSignature(@NonNull final Signature signature) throws SignatureException {
signature.update(buffer, start, length);
}

/**
* A helper method for efficient copy of our data into a Signature without creating a defensive copy of the data.
* The implementation relies on a well-behaved Signature that doesn't modify the buffer data.
* The implementation relies on a well-behaved Signature that doesn't modify the buffer data. Calls the
* {@link Signature#update(byte[], int, int)} method with all the data in this {@link Bytes} object. This method
* should be used when the data in the buffer should be validated or signed.
*
* @param signature the Signature to copy into
* @param signature The Signature to update
* @param offset The offset from the start of this {@link Bytes} object to get the bytes from
* @param length The number of bytes to extract
* @throws SignatureException If the Signature instance throws this exception
*/
public void writeTo(@NonNull final Signature signature) throws SignatureException {
signature.update(buffer, start, length);
public void updateSignature(@NonNull final Signature signature, final int offset, final int length)
throws SignatureException {
signature.update(buffer, Math.toIntExact(start + offset), length);
anthony-swirldslabs marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Same as {@link #verifySignature(Signature, int, int)} with offset 0 and length equal to the length of this
* {@link Bytes} object.
*/
public void verifySignature(@NonNull final Signature signature) throws SignatureException {
signature.verify(buffer, start, length);
}

/**
* A helper method for efficient copy of our data into a Signature without creating a defensive copy of the data.
* The implementation relies on a well-behaved Signature that doesn't modify the buffer data. Calls the
* {@link Signature#verify(byte[], int, int)} method with all the data in this {@link Bytes} object. This method
* should be used when the data in the buffer is a signature that should be verified.
*
* @param signature the Signature to use to verify
* @param offset The offset from the start of this {@link Bytes} object to get the bytes from
* @param length The number of bytes to extract
* @throws SignatureException If the Signature instance throws this exception
*/
public void verifySignature(@NonNull final Signature signature, final int offset, final int length)
throws SignatureException {
signature.verify(buffer, Math.toIntExact(start + offset), length);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,45 +1,46 @@
package com.hedera.pbj.runtime.io.buffer;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

import com.hedera.pbj.runtime.io.DataEncodingException;
import com.hedera.pbj.runtime.io.ReadableSequentialData;
import com.hedera.pbj.runtime.io.WritableSequentialData;
import com.hedera.pbj.runtime.io.stream.WritableStreamingData;
import edu.umd.cs.findbugs.annotations.NonNull;

import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.security.InvalidKeyException;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.MethodSource;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Stream;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.Mockito;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;

final class BytesTest {

// ================================================================================================================
Expand Down Expand Up @@ -428,36 +429,91 @@ void writeToMessageDigestNo0OffsetPartial() throws NoSuchAlgorithmException {
assertArrayEquals(exp, res);
}

/**
* Mock a Signature object for testing.
*
* @return a mock Signature object
*/
private static Signature mockSignature() throws InvalidKeyException {
final Signature signature = Mockito.mock(Signature.class);
// Signature.update() throws unless we call initVerify() first
signature.initVerify(Mockito.mock(PublicKey.class));
Mockito.verify(signature).initVerify(Mockito.any(PublicKey.class));
return signature;
}

@Test
@DisplayName("Write to Signature")
void writeToSignature() throws SignatureException, InvalidKeyException {
@DisplayName("Update Signature")
void updateSignature() throws SignatureException, InvalidKeyException {
byte[] byteArray = {0, 1, 2, 3, 4, 5};
final Bytes bytes = Bytes.wrap(byteArray);

final Signature signature = Mockito.mock(Signature.class);
// Signature.writeTo() throws unless we call initVerify() first
signature.initVerify(Mockito.mock(PublicKey.class));
bytes.writeTo(signature);
Mockito.verify(signature).initVerify(Mockito.any(PublicKey.class));
final Signature signature = mockSignature();
bytes.updateSignature(signature);
Mockito.verify(signature).update(byteArray, 0, 6);
Mockito.verifyNoMoreInteractions(signature);
}

@Test
@DisplayName("Write to Signature no 0 Offset")
void writeToSignatureNo0Offset() throws InvalidKeyException, SignatureException {
@DisplayName("Update Signature no 0 Offset")
void updateSignatureNo0Offset() throws InvalidKeyException, SignatureException {
final byte[] byteArray = {9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 1, 2, 3, 4, 5};
final Bytes bytes = Bytes.wrap(byteArray, 10, 6);

final Signature signature = Mockito.mock(Signature.class);
// Signature.writeTo() throws unless we call initVerify() first
signature.initVerify(Mockito.mock(PublicKey.class));
bytes.writeTo(signature);
Mockito.verify(signature).initVerify(Mockito.any(PublicKey.class));
final Signature signature = mockSignature();
bytes.updateSignature(signature);
Mockito.verify(signature).update(byteArray, 10, 6);
Mockito.verifyNoMoreInteractions(signature);
}

@Test
@DisplayName("Update Signature no 0 Offset, partial")
void updateSignatureNo0OffsetPartial() throws InvalidKeyException, SignatureException {
final byte[] byteArray = {9, 9, 9, 9, 9, 0, 1, 2, 3, 4, 5, 9, 9, 9, 9, 9};
final Bytes bytes = Bytes.wrap(byteArray, 5, 6);

final Signature signature = mockSignature();
bytes.updateSignature(signature, 1, 4);
Mockito.verify(signature).update(byteArray, 6, 4);
Mockito.verifyNoMoreInteractions(signature);
}

@Test
@DisplayName("Verify Signature")
void verifySignature() throws SignatureException, InvalidKeyException {
byte[] byteArray = {0, 1, 2, 3, 4, 5};
final Bytes bytes = Bytes.wrap(byteArray);

final Signature signature = mockSignature();
bytes.verifySignature(signature);
Mockito.verify(signature).verify(byteArray, 0, 6);
Mockito.verifyNoMoreInteractions(signature);
}

@Test
@DisplayName("Verify Signature no 0 Offset")
void verifySignatureNo0Offset() throws InvalidKeyException, SignatureException {
final byte[] byteArray = {9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 1, 2, 3, 4, 5};
final Bytes bytes = Bytes.wrap(byteArray, 10, 6);

final Signature signature = mockSignature();
bytes.verifySignature(signature);
Mockito.verify(signature).verify(byteArray, 10, 6);
Mockito.verifyNoMoreInteractions(signature);
}

@Test
@DisplayName("Verify Signature no 0 Offset, partial")
void verifySignatureNo0OffsetPartial() throws InvalidKeyException, SignatureException {
final byte[] byteArray = {9, 9, 9, 9, 9, 0, 1, 2, 3, 4, 5, 9, 9, 9, 9, 9};
final Bytes bytes = Bytes.wrap(byteArray, 5, 6);

final Signature signature = mockSignature();
bytes.verifySignature(signature, 1, 4);
Mockito.verify(signature).verify(byteArray, 6, 4);
Mockito.verifyNoMoreInteractions(signature);
}

// asUtf8String throws with null (no offset here? That's wierd. Should have offset, or we should have non-offset
// versions of everything else Or at least "getBytes").

Expand Down