Skip to content

Commit

Permalink
Merge branch 'master' into java14_compat
Browse files Browse the repository at this point in the history
  • Loading branch information
melowe authored Jul 29, 2020
2 parents 7e8a738 + 89e50e4 commit eb81248
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 127 deletions.
30 changes: 30 additions & 0 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Contributing to Tessera code

Thank you for your interest in contributing to our Tessera code. We welcome all meaningful contribution no matter the size.

If you'd like to contribute please send us a pull request with the change. We are very interactive and will respond immediately.
Commits which do not comply with the coding standards and without substance are generally ignored/closed.

## What to contribute

We are happy for all contributions including:

* Improved End to End Flow diagram
* Documentation updates
* Code contributions
* Responding to other issues/supporting our community

Please refer our [Product Roadmap](http://docs.goquorum.com/en/latest/roadmap/) or [Issues](https://github.com/jpmorganchase/tessera/issues) for ideas to contribute.

## What makes a good contribution ?

* Code must adhere to proper coding standards and self-documenting, easy to understand and explain
* Follow standard [style guides](https://google.github.io/styleguide/javaguide.html).
* Include test coverage (both unit and integration). Without 100 % test coverage the build will fail. All submissions must be testable in an automated fashion.
* If the change needs end to end testing with Quorum, please also contribute to our [Quorum acceptance Test suite](https://github.com/jpmorganchase/quorum-acceptance-tests).
* Raise individual features/enhancements separately and do not bundle them as one big change.
* Link each change to an issue (if it is new feature, please create an issue before contributing with the change)
* Add proper commit messages and description of change in the request.
* Always add logging at appropriate level where applicable.
* Be proactive after submitting PR making sure all checks are passing

3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,5 +195,8 @@ The best way to receive security announcements is to subscribe to the Quorum-ann

Comments on This Policy If you have any suggestions to improve this policy, please send an email to [email protected] for discussion.

## Contributing
Tessera is built open source and we welcome external contribution on features and enhancements. Upon review you will be required to complete a Contributor License Agreement (CLA) before we are able to merge. If you have any questions about the contribution process, please feel free to send an email to [[email protected]](mailto:[email protected]). Please see the [Contributors guide](.github/CONTRIBUTING.md) in wiki for more information about the process.

# Getting Help
Stuck at some step? Please join our <a href="https://www.goquorum.com/slack-inviter" target="_blank" rel="noopener">slack community</a> for support.
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,16 @@ public final int hashCode() {
@Override
public String toString() {

final String typeName = Stream.of(getClass())
.map(Class::getInterfaces)
.flatMap(Stream::of)
.map(Class::getName)
.findFirst()
.get();

return typeName + "@" + Integer.toHexString(hashCode());
final String typeName =
Stream.of(getClass())
.map(Class::getInterfaces)
.flatMap(Stream::of)
.map(Class::getName)
.findFirst()
.get();

// we use Object.hashCode to protect against accidentally printing/logging a value derived from the raw bytes
// a side effect of this is 2 instances with the same underlying bytes will have different toString values
return typeName + "@" + Integer.toHexString(super.hashCode());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

import java.util.Arrays;

/**
* A set of random bytes intended for one time use to encrypt a message
*/
/** A set of random bytes intended for one time use to encrypt a message */
public class Nonce {

private final byte[] nonceBytes;
Expand All @@ -29,7 +27,8 @@ public int hashCode() {

@Override
public String toString() {
return Arrays.toString(nonceBytes);
// we use Object.hashCode to protect against accidentally printing/logging a value derived from the raw bytes
// a side effect of this is 2 instances with the same underlying bytes will have different toString values
return getClass().getName() + "@" + Integer.toHexString(super.hashCode());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.quorum.tessera.encryption;

import org.junit.Test;

import static org.assertj.core.api.Assertions.assertThat;

public class BaseKeyTest {

@Test
public void toStringDoesNotUseUnderlyingData() {
final BaseKey k = new TestBaseKeyImpl(new byte[]{5, 6, 7});
final BaseKey k2 = new TestBaseKeyImpl(new byte[]{5, 6, 7});

assertThat(k.toString()).isNotEqualTo(k2.toString());
}

static class TestBaseKeyImpl extends BaseKey implements MyKey {

protected TestBaseKeyImpl(byte[] keyBytes) {
super(keyBytes);
}
}

interface MyKey {

}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.quorum.tessera.encryption;

import com.quorum.tessera.encryption.Nonce;
import com.openpojo.reflection.impl.PojoClassFactory;
import com.openpojo.validation.ValidatorBuilder;
import com.openpojo.validation.test.impl.GetterTester;
Expand All @@ -16,20 +15,14 @@ public class NonceTest {
public void pojo() {
EqualsVerifier.configure().suppress(STRICT_INHERITANCE).forClass(Nonce.class).verify();

ValidatorBuilder.create()
.with(new GetterTester())
.build()
.validate(PojoClassFactory.getPojoClass(Nonce.class));

ValidatorBuilder.create().with(new GetterTester()).build().validate(PojoClassFactory.getPojoClass(Nonce.class));
}

@Test
public void toStringGivesCorrectOutput() {
final Nonce nonce = new Nonce(new byte[]{5, 6, 7});

final String toString = nonce.toString();
public void toStringDoesNotUseUnderlyingData() {
final Nonce nonce = new Nonce(new byte[] {5, 6, 7});
final Nonce nonce2 = new Nonce(new byte[] {5, 6, 7});

assertThat(toString).isEqualTo("[5, 6, 7]");
assertThat(nonce.toString()).isNotEqualTo(nonce2.toString());
}

}
Original file line number Diff line number Diff line change
@@ -1,29 +1,20 @@
package com.quorum.tessera.nacl.jnacl;

import com.quorum.tessera.encryption.EncryptorException;
import com.quorum.tessera.encryption.Encryptor;
import com.quorum.tessera.encryption.Nonce;
import com.quorum.tessera.encryption.KeyPair;
import com.neilalexander.jnacl.NaCl;
import com.quorum.tessera.encryption.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Objects;

import static com.neilalexander.jnacl.crypto.curve25519xsalsa20poly1305.*;
import com.quorum.tessera.encryption.PrivateKey;
import com.quorum.tessera.encryption.PublicKey;
import com.quorum.tessera.encryption.SharedKey;

/** Uses jnacl, which is a pure Java implementation of the NaCl standard */
public class Jnacl implements Encryptor {

private static final Logger LOGGER = LoggerFactory.getLogger(Jnacl.class);

private static final String REDACTED = "REDACTED";

private final SecureRandom secureRandom;

private final SecretBox secretBox;
Expand All @@ -42,9 +33,8 @@ public SharedKey computeSharedKey(final PublicKey publicKey, final PrivateKey pr
secretBox.cryptoBoxBeforenm(precomputed, publicKey.getKeyBytes(), privateKey.getKeyBytes());

if (jnaclResult == -1) {
LOGGER.error("Could not compute the shared key for pub {} and priv {}", publicKey, REDACTED);
LOGGER.debug("Could not compute the shared key for pub {} and priv {}", publicKey, privateKey);
throw new EncryptorException("JNacl could not compute the shared key");
LOGGER.error("Could not compute the shared key for pub {} and priv {}", publicKey, privateKey);
throw new EncryptorException("jnacl could not compute the shared key");
}

final SharedKey sharedKey = SharedKey.from(precomputed);
Expand All @@ -58,10 +48,8 @@ public SharedKey computeSharedKey(final PublicKey publicKey, final PrivateKey pr
public byte[] seal(
final byte[] message, final Nonce nonce, final PublicKey publicKey, final PrivateKey privateKey) {

LOGGER.debug("Sealing message using public key {}", publicKey);
LOGGER.debug(
"Sealing message {} using nonce {}, public key {} and private key {}",
Arrays.toString(message),
"Sealing message using nonce {}, public key {} and private key {}",
nonce,
publicKey,
privateKey);
Expand All @@ -72,10 +60,8 @@ public byte[] seal(

final byte[] cipherText = nacl.encrypt(message, nonce.getNonceBytes());

LOGGER.debug("Created sealed payload for public key {}", publicKey);
LOGGER.debug(
"Created sealed payload {} using nonce {}, public key {} and private key {}",
Arrays.toString(cipherText),
"Created sealed payload using nonce {}, public key {} and private key {}",
nonce,
publicKey,
privateKey);
Expand All @@ -90,10 +76,8 @@ public byte[] seal(
@Override
public byte[] open(
final byte[] cipherText, final Nonce nonce, final PublicKey publicKey, final PrivateKey privateKey) {
LOGGER.debug("Opening message using public key {}", publicKey);
LOGGER.debug(
"Opening message {} using nonce {}, public key {} and private key {}",
Arrays.toString(cipherText),
"Opening message using nonce {}, public key {} and private key {}",
nonce,
publicKey,
privateKey);
Expand All @@ -106,13 +90,11 @@ public byte[] open(

final byte[] plaintext = nacl.decrypt(paddedInput, nonce.getNonceBytes());

LOGGER.debug("Created sealed payload for public key {}", publicKey);
LOGGER.debug(
"Created sealed payload {} using nonce {}, public key {} and private key {}",
Arrays.toString(cipherText),
nonce,
publicKey,
privateKey);
"Opened message using nonce {}, public key {} and private key {}",
nonce,
publicKey,
privateKey);

return plaintext;
} catch (final Exception ex) {
Expand All @@ -126,8 +108,7 @@ public byte[] sealAfterPrecomputation(final byte[] message, final Nonce nonce, f
final byte[] paddedMessage = new byte[message.length + crypto_secretbox_ZEROBYTES];
final byte[] output = new byte[message.length + crypto_secretbox_ZEROBYTES];

LOGGER.debug("Sealing message using public key {}", sharedKey);
LOGGER.debug("Sealing message {} using nonce {} and shared key {}", Arrays.toString(message), nonce, sharedKey);
LOGGER.debug("Sealing message using nonce {} and shared key {}", nonce, sharedKey);

System.arraycopy(message, 0, paddedMessage, crypto_secretbox_ZEROBYTES, message.length);
final int jnaclResult =
Expand All @@ -136,14 +117,11 @@ public byte[] sealAfterPrecomputation(final byte[] message, final Nonce nonce, f

if (jnaclResult == -1) {
LOGGER.error("Could not create sealed payload using shared key {}", sharedKey);
LOGGER.debug("Could not create sealed payload using shared key {}", sharedKey);
throw new EncryptorException("jnacl could not seal the payload using the shared key");
}

LOGGER.debug("Created sealed payload for shared key {}", sharedKey);
LOGGER.debug(
"Created sealed payload {} using nonce {} and shared key {}",
Arrays.toString(output),
"Created sealed payload using nonce {} and shared key {}",
nonce,
sharedKey);

Expand All @@ -152,9 +130,8 @@ public byte[] sealAfterPrecomputation(final byte[] message, final Nonce nonce, f

@Override
public byte[] openAfterPrecomputation(final byte[] cipherText, final Nonce nonce, final SharedKey sharedKey) {
LOGGER.debug("Opening message using shared key {}", sharedKey);
LOGGER.debug(
"Opening message {} using nonce {} and shared key {}", Arrays.toString(cipherText), nonce, sharedKey);
"Opening message using nonce {} and shared key {}", nonce, sharedKey);

final byte[] paddedInput = pad(cipherText, crypto_secretbox_BOXZEROBYTES);
final byte[] paddedOutput = new byte[paddedInput.length];
Expand All @@ -165,18 +142,14 @@ public byte[] openAfterPrecomputation(final byte[] cipherText, final Nonce nonce

if (jnaclResult == -1) {
LOGGER.error("Could not open sealed payload using shared key {}", sharedKey);
LOGGER.debug("Could not open sealed payload using shared key {}", sharedKey);
throw new EncryptorException("jnacl could not open the payload using the shared key");
}

LOGGER.debug("Opened sealed payload for shared key {}", sharedKey);
LOGGER.debug(
"Opened payload {} using nonce {}, public key {} and private key {} to get result {}",
Arrays.toString(cipherText),
"Opened payload using nonce {} and shared key {}",
nonce,
sharedKey,
REDACTED,
Arrays.toString(paddedOutput));
sharedKey);

return extract(paddedOutput, crypto_secretbox_ZEROBYTES);
}
Expand Down Expand Up @@ -211,7 +184,7 @@ public KeyPair generateNewKeys() {
final PublicKey pubKey = PublicKey.from(publicKey);
final PrivateKey privKey = PrivateKey.from(privateKey);

LOGGER.info("Generated public key {} and private key {}", pubKey, REDACTED);
LOGGER.info("Generated new key pair with public key {}", pubKey);
LOGGER.debug("Generated public key {} and private key {}", pubKey, privKey);

return new KeyPair(pubKey, privKey);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,17 @@
package com.quorum.tessera.nacl.jnacl;

import com.quorum.tessera.encryption.KeyPair;
import com.quorum.tessera.encryption.EncryptorException;
import com.quorum.tessera.encryption.Nonce;
import com.quorum.tessera.encryption.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.security.SecureRandom;

import static com.neilalexander.jnacl.crypto.curve25519xsalsa20poly1305.crypto_secretbox_BEFORENMBYTES;
import com.quorum.tessera.encryption.PrivateKey;
import com.quorum.tessera.encryption.PublicKey;
import com.quorum.tessera.encryption.SharedKey;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;

public class JnaclTest {
Expand Down Expand Up @@ -68,7 +61,7 @@ public void computingSharedKeyThrowsExceptionOnFailure() {

final Throwable kaclEx = catchThrowable(() -> this.jnacl.computeSharedKey(publicKey, privateKey));

assertThat(kaclEx).isInstanceOf(EncryptorException.class).hasMessage("JNacl could not compute the shared key");
assertThat(kaclEx).isInstanceOf(EncryptorException.class).hasMessage("jnacl could not compute the shared key");

verify(this.secretBox)
.cryptoBoxBeforenm(any(byte[].class), eq(publicKey.getKeyBytes()), eq(privateKey.getKeyBytes()));
Expand Down
Loading

0 comments on commit eb81248

Please sign in to comment.