From 0931517a698aa2d1a42aa12d9a0a8587e8dc0763 Mon Sep 17 00:00:00 2001 From: David San Date: Sun, 5 Jul 2020 16:47:26 +0200 Subject: [PATCH 1/5] Create maven.yml --- .github/workflows/maven.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .github/workflows/maven.yml diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 0000000..95194de --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,19 @@ +# This workflow will build a Java project with Maven +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven + +name: Java CI with Maven + +on: [ push, pull_request ] +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + - name: Build with Maven + run: mvn -B package --file pom.xml From cd9b6ea52fc06898222d4dffe4f205241d326257 Mon Sep 17 00:00:00 2001 From: David San Date: Sat, 4 Jul 2020 18:07:10 +0200 Subject: [PATCH 2/5] Added X25519 scalar multiplication tests --- .../neilalexander/jnacl/ScalarMultTest.java | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 src/test/java/com/neilalexander/jnacl/ScalarMultTest.java diff --git a/src/test/java/com/neilalexander/jnacl/ScalarMultTest.java b/src/test/java/com/neilalexander/jnacl/ScalarMultTest.java new file mode 100644 index 0000000..0326892 --- /dev/null +++ b/src/test/java/com/neilalexander/jnacl/ScalarMultTest.java @@ -0,0 +1,125 @@ +package com.neilalexander.jnacl; + +import com.neilalexander.jnacl.crypto.curve25519; +import com.neilalexander.jnacl.crypto.curve25519xsalsa20poly1305; +import com.neilalexander.jnacl.crypto.xsalsa20; +import com.neilalexander.jnacl.crypto.xsalsa20poly1305; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import static com.neilalexander.jnacl.crypto.curve25519xsalsa20poly1305.crypto_secretbox_PUBLICKEYBYTES; +import static com.neilalexander.jnacl.crypto.curve25519xsalsa20poly1305.crypto_secretbox_SECRETKEYBYTES; +import static org.fest.assertions.Assertions.assertThat; + +public class ScalarMultTest { + + @BeforeMethod + public void setUp() throws Exception { + } + + /** + * Test public key computation (Alice) + * See chapter 3 "Example of the sender’s keys" of Cryptography in NaCl, Daniel J. Bernstein + * https://cr.yp.to/highspeed/naclcrypto-20090310.pdf + */ + @Test + public void test_crypto_scalarmult_curve25519_alice() throws Exception { + byte[] alicesk = new byte[]{ + (byte) 0x77, (byte) 0x07, (byte) 0x6d, (byte) 0x0a, (byte) 0x73, (byte) 0x18, (byte) 0xa5, (byte) 0x7d, + (byte) 0x3c, (byte) 0x16, (byte) 0xc1, (byte) 0x72, (byte) 0x51, (byte) 0xb2, (byte) 0x66, (byte) 0x45, + (byte) 0xdf, (byte) 0x4c, (byte) 0x2f, (byte) 0x87, (byte) 0xeb, (byte) 0xc0, (byte) 0x99, (byte) 0x2a, + (byte) 0xb1, (byte) 0x77, (byte) 0xfb, (byte) 0xa5, (byte) 0x1d, (byte) 0xb9, (byte) 0x2c, (byte) 0x2a + }; + byte[] expected_alicepk = new byte[]{ + (byte) 0x85, (byte) 0x20, (byte) 0xf0, (byte) 0x09, (byte) 0x89, (byte) 0x30, (byte) 0xa7, (byte) 0x54, + (byte) 0x74, (byte) 0x8b, (byte) 0x7d, (byte) 0xdc, (byte) 0xb4, (byte) 0x3e, (byte) 0xf7, (byte) 0x5a, + (byte) 0x0d, (byte) 0xbf, (byte) 0x3a, (byte) 0x0d, (byte) 0x26, (byte) 0x38, (byte) 0x1a, (byte) 0xf4, + (byte) 0xeb, (byte) 0xa4, (byte) 0xa9, (byte) 0x8e, (byte) 0xaa, (byte) 0x9b, (byte) 0x4e, (byte) 0x6a + }; + byte[] alicepk = new byte[crypto_secretbox_PUBLICKEYBYTES]; + curve25519.crypto_scalarmult_base(alicepk, alicesk); + assertThat(alicepk).isEqualTo(expected_alicepk); + } + + /** + * Test public key computation (Bob) + * See chapter 4 "Example of the receiver’s keys" of Cryptography in NaCl, Daniel J. Bernstein + * https://cr.yp.to/highspeed/naclcrypto-20090310.pdf + */ + @Test + public void test_crypto_scalarmult_curve25519_bob() throws Exception { + byte[] bobsk = new byte[]{ + (byte) 0x5d, (byte) 0xab, (byte) 0x08, (byte) 0x7e, (byte) 0x62, (byte) 0x4a, (byte) 0x8a, (byte) 0x4b, + (byte) 0x79, (byte) 0xe1, (byte) 0x7f, (byte) 0x8b, (byte) 0x83, (byte) 0x80, (byte) 0x0e, (byte) 0xe6, + (byte) 0x6f, (byte) 0x3b, (byte) 0xb1, (byte) 0x29, (byte) 0x26, (byte) 0x18, (byte) 0xb6, (byte) 0xfd, + (byte) 0x1c, (byte) 0x2f, (byte) 0x8b, (byte) 0x27, (byte) 0xff, (byte) 0x88, (byte) 0xe0, (byte) 0xeb + }; + byte[] expected_bobpk = new byte[]{ + (byte) 0xde, (byte) 0x9e, (byte) 0xdb, (byte) 0x7d, (byte) 0x7b, (byte) 0x7d, (byte) 0xc1, (byte) 0xb4, + (byte) 0xd3, (byte) 0x5b, (byte) 0x61, (byte) 0xc2, (byte) 0xec, (byte) 0xe4, (byte) 0x35, (byte) 0x37, + (byte) 0x3f, (byte) 0x83, (byte) 0x43, (byte) 0xc8, (byte) 0x5b, (byte) 0x78, (byte) 0x67, (byte) 0x4d, + (byte) 0xad, (byte) 0xfc, (byte) 0x7e, (byte) 0x14, (byte) 0x6f, (byte) 0x88, (byte) 0x2b, (byte) 0x4f + }; + byte[] bobpk = new byte[crypto_secretbox_PUBLICKEYBYTES]; + curve25519.crypto_scalarmult_base(bobpk, bobsk); + assertThat(bobpk).isEqualTo(expected_bobpk); + } + + /** + * Test shared secret agreement + * See chapter 6 "Example of the shared secret" of Cryptography in NaCl, Daniel J. Bernstein + * https://cr.yp.to/highspeed/naclcrypto-20090310.pdf + */ + @Test + public void test_crypto_scalarmult_curve25519() throws Exception { + byte[] alicesk = new byte[]{ + (byte) 0x77, (byte) 0x07, (byte) 0x6d, (byte) 0x0a, (byte) 0x73, (byte) 0x18, (byte) 0xa5, (byte) 0x7d, + (byte) 0x3c, (byte) 0x16, (byte) 0xc1, (byte) 0x72, (byte) 0x51, (byte) 0xb2, (byte) 0x66, (byte) 0x45, + (byte) 0xdf, (byte) 0x4c, (byte) 0x2f, (byte) 0x87, (byte) 0xeb, (byte) 0xc0, (byte) 0x99, (byte) 0x2a, + (byte) 0xb1, (byte) 0x77, (byte) 0xfb, (byte) 0xa5, (byte) 0x1d, (byte) 0xb9, (byte) 0x2c, (byte) 0x2a + }; + byte[] alicepk = new byte[crypto_secretbox_PUBLICKEYBYTES]; + curve25519.crypto_scalarmult_base(alicepk, alicesk); + byte[] bobsk = new byte[]{ + (byte) 0x5d, (byte) 0xab, (byte) 0x08, (byte) 0x7e, (byte) 0x62, (byte) 0x4a, (byte) 0x8a, (byte) 0x4b, + (byte) 0x79, (byte) 0xe1, (byte) 0x7f, (byte) 0x8b, (byte) 0x83, (byte) 0x80, (byte) 0x0e, (byte) 0xe6, + (byte) 0x6f, (byte) 0x3b, (byte) 0xb1, (byte) 0x29, (byte) 0x26, (byte) 0x18, (byte) 0xb6, (byte) 0xfd, + (byte) 0x1c, (byte) 0x2f, (byte) 0x8b, (byte) 0x27, (byte) 0xff, (byte) 0x88, (byte) 0xe0, (byte) 0xeb + }; + byte[] bobpk = new byte[crypto_secretbox_PUBLICKEYBYTES]; + curve25519.crypto_scalarmult_base(bobpk, bobsk); + byte[] expected_shared = new byte[]{ + (byte) 0x4a, (byte) 0x5d, (byte) 0x9d, (byte) 0x5b, (byte) 0xa4, (byte) 0xce, (byte) 0x2d, (byte) 0xe1, + (byte) 0x72, (byte) 0x8e, (byte) 0x3b, (byte) 0xf4, (byte) 0x80, (byte) 0x35, (byte) 0x0f, (byte) 0x25, + (byte) 0xe0, (byte) 0x7e, (byte) 0x21, (byte) 0xc9, (byte) 0x47, (byte) 0xd1, (byte) 0x9e, (byte) 0x33, + (byte) 0x76, (byte) 0xf0, (byte) 0x9b, (byte) 0x3c, (byte) 0x1e, (byte) 0x16, (byte) 0x17, (byte) 0x42 + }; + byte[] alice_shared = new byte[32]; + curve25519.crypto_scalarmult(alice_shared, alicesk, bobpk); + byte[] bob_shared = new byte[32]; + curve25519.crypto_scalarmult(bob_shared, bobsk, alicepk); + assertThat(alice_shared).isEqualTo(expected_shared); + assertThat(bob_shared).isEqualTo(expected_shared); + } + + /** + * Test multiple randomly generated shared secret agreements + */ + @Test + public void test_crypto_scalarmult_curve25519_random() throws Exception { + for (int i = 0; i < 50; i++) { + byte[] alicepk = new byte[crypto_secretbox_PUBLICKEYBYTES]; + byte[] alicesk = new byte[crypto_secretbox_SECRETKEYBYTES]; + byte[] bobpk = new byte[crypto_secretbox_PUBLICKEYBYTES]; + byte[] bobsk = new byte[crypto_secretbox_SECRETKEYBYTES]; + curve25519xsalsa20poly1305.crypto_box_keypair(alicepk, alicesk); + curve25519xsalsa20poly1305.crypto_box_keypair(bobpk, bobsk); + byte[] alice_shared = new byte[32]; + byte[] bob_shared = new byte[32]; + curve25519.crypto_scalarmult(alice_shared, alicesk, bobpk); + curve25519.crypto_scalarmult(bob_shared, bobsk, alicepk); + assertThat(alice_shared).isEqualTo(bob_shared); + } + } + +} \ No newline at end of file From d27c129cc3d9b6fad14c346dc994c3f9e0c6d690 Mon Sep 17 00:00:00 2001 From: David San Date: Sat, 4 Jul 2020 23:11:51 +0200 Subject: [PATCH 3/5] Add cryptobox tests (cherry picked from commit 978b485703ff2008d0076921e57f700fcbc5155d) --- .../java/com/neilalexander/jnacl/BoxTest.java | 243 ++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 src/test/java/com/neilalexander/jnacl/BoxTest.java diff --git a/src/test/java/com/neilalexander/jnacl/BoxTest.java b/src/test/java/com/neilalexander/jnacl/BoxTest.java new file mode 100644 index 0000000..5b11f6e --- /dev/null +++ b/src/test/java/com/neilalexander/jnacl/BoxTest.java @@ -0,0 +1,243 @@ +package com.neilalexander.jnacl; + +import com.neilalexander.jnacl.crypto.curve25519xsalsa20poly1305; +import org.fest.assertions.Assert; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.util.Arrays; +import java.util.Random; + +import static com.neilalexander.jnacl.crypto.curve25519xsalsa20poly1305.*; +import static org.fest.assertions.Assertions.assertThat; + +public class BoxTest { + + private byte[] alicepk; + private byte[] alicesk; + private byte[] bobpk; + private byte[] bobsk; + private byte[] nonce; + private byte[] m; + private byte[] mbytes; + + @BeforeMethod + public void setUp() throws Exception { + alicesk = new byte[]{ + (byte) 0x77, (byte) 0x07, (byte) 0x6d, (byte) 0x0a, (byte) 0x73, (byte) 0x18, (byte) 0xa5, (byte) 0x7d, + (byte) 0x3c, (byte) 0x16, (byte) 0xc1, (byte) 0x72, (byte) 0x51, (byte) 0xb2, (byte) 0x66, (byte) 0x45, + (byte) 0xdf, (byte) 0x4c, (byte) 0x2f, (byte) 0x87, (byte) 0xeb, (byte) 0xc0, (byte) 0x99, (byte) 0x2a, + (byte) 0xb1, (byte) 0x77, (byte) 0xfb, (byte) 0xa5, (byte) 0x1d, (byte) 0xb9, (byte) 0x2c, (byte) 0x2a + }; + alicepk = new byte[]{ + (byte) 0x85, (byte) 0x20, (byte) 0xf0, (byte) 0x09, (byte) 0x89, (byte) 0x30, (byte) 0xa7, (byte) 0x54, + (byte) 0x74, (byte) 0x8b, (byte) 0x7d, (byte) 0xdc, (byte) 0xb4, (byte) 0x3e, (byte) 0xf7, (byte) 0x5a, + (byte) 0x0d, (byte) 0xbf, (byte) 0x3a, (byte) 0x0d, (byte) 0x26, (byte) 0x38, (byte) 0x1a, (byte) 0xf4, + (byte) 0xeb, (byte) 0xa4, (byte) 0xa9, (byte) 0x8e, (byte) 0xaa, (byte) 0x9b, (byte) 0x4e, (byte) 0x6a + }; + bobsk = new byte[]{ + (byte) 0x5d, (byte) 0xab, (byte) 0x08, (byte) 0x7e, (byte) 0x62, (byte) 0x4a, (byte) 0x8a, (byte) 0x4b, + (byte) 0x79, (byte) 0xe1, (byte) 0x7f, (byte) 0x8b, (byte) 0x83, (byte) 0x80, (byte) 0x0e, (byte) 0xe6, + (byte) 0x6f, (byte) 0x3b, (byte) 0xb1, (byte) 0x29, (byte) 0x26, (byte) 0x18, (byte) 0xb6, (byte) 0xfd, + (byte) 0x1c, (byte) 0x2f, (byte) 0x8b, (byte) 0x27, (byte) 0xff, (byte) 0x88, (byte) 0xe0, (byte) 0xeb + }; + bobpk = new byte[]{ + (byte) 0xde, (byte) 0x9e, (byte) 0xdb, (byte) 0x7d, (byte) 0x7b, (byte) 0x7d, (byte) 0xc1, (byte) 0xb4, + (byte) 0xd3, (byte) 0x5b, (byte) 0x61, (byte) 0xc2, (byte) 0xec, (byte) 0xe4, (byte) 0x35, (byte) 0x37, + (byte) 0x3f, (byte) 0x83, (byte) 0x43, (byte) 0xc8, (byte) 0x5b, (byte) 0x78, (byte) 0x67, (byte) 0x4d, + (byte) 0xad, (byte) 0xfc, (byte) 0x7e, (byte) 0x14, (byte) 0x6f, (byte) 0x88, (byte) 0x2b, (byte) 0x4f + }; + nonce = new byte[]{ + (byte) 0x69, (byte) 0x69, (byte) 0x6e, (byte) 0xe9, (byte) 0x55, (byte) 0xb6, (byte) 0x2b, (byte) 0x73, + (byte) 0xcd, (byte) 0x62, (byte) 0xbd, (byte) 0xa8, (byte) 0x75, (byte) 0xfc, (byte) 0x73, (byte) 0xd6, + (byte) 0x82, (byte) 0x19, (byte) 0xe0, (byte) 0x03, (byte) 0x6b, (byte) 0x7a, (byte) 0x0b, (byte) 0x37 + }; + // API requires first 32 bytes to be 0 + m = new byte[]{ + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0xbe, (byte) 0x07, (byte) 0x5f, (byte) 0xc5, (byte) 0x3c, (byte) 0x81, (byte) 0xf2, (byte) 0xd5, + (byte) 0xcf, (byte) 0x14, (byte) 0x13, (byte) 0x16, (byte) 0xeb, (byte) 0xeb, (byte) 0x0c, (byte) 0x7b, + (byte) 0x52, (byte) 0x28, (byte) 0xc5, (byte) 0x2a, (byte) 0x4c, (byte) 0x62, (byte) 0xcb, (byte) 0xd4, + (byte) 0x4b, (byte) 0x66, (byte) 0x84, (byte) 0x9b, (byte) 0x64, (byte) 0x24, (byte) 0x4f, (byte) 0xfc, + (byte) 0xe5, (byte) 0xec, (byte) 0xba, (byte) 0xaf, (byte) 0x33, (byte) 0xbd, (byte) 0x75, (byte) 0x1a, + (byte) 0x1a, (byte) 0xc7, (byte) 0x28, (byte) 0xd4, (byte) 0x5e, (byte) 0x6c, (byte) 0x61, (byte) 0x29, + (byte) 0x6c, (byte) 0xdc, (byte) 0x3c, (byte) 0x01, (byte) 0x23, (byte) 0x35, (byte) 0x61, (byte) 0xf4, + (byte) 0x1d, (byte) 0xb6, (byte) 0x6c, (byte) 0xce, (byte) 0x31, (byte) 0x4a, (byte) 0xdb, (byte) 0x31, + (byte) 0x0e, (byte) 0x3b, (byte) 0xe8, (byte) 0x25, (byte) 0x0c, (byte) 0x46, (byte) 0xf0, (byte) 0x6d, + (byte) 0xce, (byte) 0xea, (byte) 0x3a, (byte) 0x7f, (byte) 0xa1, (byte) 0x34, (byte) 0x80, (byte) 0x57, + (byte) 0xe2, (byte) 0xf6, (byte) 0x55, (byte) 0x6a, (byte) 0xd6, (byte) 0xb1, (byte) 0x31, (byte) 0x8a, + (byte) 0x02, (byte) 0x4a, (byte) 0x83, (byte) 0x8f, (byte) 0x21, (byte) 0xaf, (byte) 0x1f, (byte) 0xde, + (byte) 0x04, (byte) 0x89, (byte) 0x77, (byte) 0xeb, (byte) 0x48, (byte) 0xf5, (byte) 0x9f, (byte) 0xfd, + (byte) 0x49, (byte) 0x24, (byte) 0xca, (byte) 0x1c, (byte) 0x60, (byte) 0x90, (byte) 0x2e, (byte) 0x52, + (byte) 0xf0, (byte) 0xa0, (byte) 0x89, (byte) 0xbc, (byte) 0x76, (byte) 0x89, (byte) 0x70, (byte) 0x40, + (byte) 0xe0, (byte) 0x82, (byte) 0xf9, (byte) 0x37, (byte) 0x76, (byte) 0x38, (byte) 0x48, (byte) 0x64, + (byte) 0x5e, (byte) 0x07, (byte) 0x05 + }; + // Original non-padded message for NaCl + mbytes = new byte[]{ + (byte) 0xbe, (byte) 0x07, (byte) 0x5f, (byte) 0xc5, (byte) 0x3c, (byte) 0x81, (byte) 0xf2, (byte) 0xd5, + (byte) 0xcf, (byte) 0x14, (byte) 0x13, (byte) 0x16, (byte) 0xeb, (byte) 0xeb, (byte) 0x0c, (byte) 0x7b, + (byte) 0x52, (byte) 0x28, (byte) 0xc5, (byte) 0x2a, (byte) 0x4c, (byte) 0x62, (byte) 0xcb, (byte) 0xd4, + (byte) 0x4b, (byte) 0x66, (byte) 0x84, (byte) 0x9b, (byte) 0x64, (byte) 0x24, (byte) 0x4f, (byte) 0xfc, + (byte) 0xe5, (byte) 0xec, (byte) 0xba, (byte) 0xaf, (byte) 0x33, (byte) 0xbd, (byte) 0x75, (byte) 0x1a, + (byte) 0x1a, (byte) 0xc7, (byte) 0x28, (byte) 0xd4, (byte) 0x5e, (byte) 0x6c, (byte) 0x61, (byte) 0x29, + (byte) 0x6c, (byte) 0xdc, (byte) 0x3c, (byte) 0x01, (byte) 0x23, (byte) 0x35, (byte) 0x61, (byte) 0xf4, + (byte) 0x1d, (byte) 0xb6, (byte) 0x6c, (byte) 0xce, (byte) 0x31, (byte) 0x4a, (byte) 0xdb, (byte) 0x31, + (byte) 0x0e, (byte) 0x3b, (byte) 0xe8, (byte) 0x25, (byte) 0x0c, (byte) 0x46, (byte) 0xf0, (byte) 0x6d, + (byte) 0xce, (byte) 0xea, (byte) 0x3a, (byte) 0x7f, (byte) 0xa1, (byte) 0x34, (byte) 0x80, (byte) 0x57, + (byte) 0xe2, (byte) 0xf6, (byte) 0x55, (byte) 0x6a, (byte) 0xd6, (byte) 0xb1, (byte) 0x31, (byte) 0x8a, + (byte) 0x02, (byte) 0x4a, (byte) 0x83, (byte) 0x8f, (byte) 0x21, (byte) 0xaf, (byte) 0x1f, (byte) 0xde, + (byte) 0x04, (byte) 0x89, (byte) 0x77, (byte) 0xeb, (byte) 0x48, (byte) 0xf5, (byte) 0x9f, (byte) 0xfd, + (byte) 0x49, (byte) 0x24, (byte) 0xca, (byte) 0x1c, (byte) 0x60, (byte) 0x90, (byte) 0x2e, (byte) 0x52, + (byte) 0xf0, (byte) 0xa0, (byte) 0x89, (byte) 0xbc, (byte) 0x76, (byte) 0x89, (byte) 0x70, (byte) 0x40, + (byte) 0xe0, (byte) 0x82, (byte) 0xf9, (byte) 0x37, (byte) 0x76, (byte) 0x38, (byte) 0x48, (byte) 0x64, + (byte) 0x5e, (byte) 0x07, (byte) 0x05 + }; + } + + @Test + public void test_crypto_cryptobox_1() throws Exception { + byte[] c = new byte[m.length]; + curve25519xsalsa20poly1305.crypto_box(c, m, m.length, nonce, bobpk, alicesk); + byte[] expected_c = new byte[]{ + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0xf3, (byte) 0xff, (byte) 0xc7, (byte) 0x70, (byte) 0x3f, (byte) 0x94, (byte) 0x00, (byte) 0xe5, + (byte) 0x2a, (byte) 0x7d, (byte) 0xfb, (byte) 0x4b, (byte) 0x3d, (byte) 0x33, (byte) 0x05, (byte) 0xd9, + (byte) 0x8e, (byte) 0x99, (byte) 0x3b, (byte) 0x9f, (byte) 0x48, (byte) 0x68, (byte) 0x12, (byte) 0x73, + (byte) 0xc2, (byte) 0x96, (byte) 0x50, (byte) 0xba, (byte) 0x32, (byte) 0xfc, (byte) 0x76, (byte) 0xce, + (byte) 0x48, (byte) 0x33, (byte) 0x2e, (byte) 0xa7, (byte) 0x16, (byte) 0x4d, (byte) 0x96, (byte) 0xa4, + (byte) 0x47, (byte) 0x6f, (byte) 0xb8, (byte) 0xc5, (byte) 0x31, (byte) 0xa1, (byte) 0x18, (byte) 0x6a, + (byte) 0xc0, (byte) 0xdf, (byte) 0xc1, (byte) 0x7c, (byte) 0x98, (byte) 0xdc, (byte) 0xe8, (byte) 0x7b, + (byte) 0x4d, (byte) 0xa7, (byte) 0xf0, (byte) 0x11, (byte) 0xec, (byte) 0x48, (byte) 0xc9, (byte) 0x72, + (byte) 0x71, (byte) 0xd2, (byte) 0xc2, (byte) 0x0f, (byte) 0x9b, (byte) 0x92, (byte) 0x8f, (byte) 0xe2, + (byte) 0x27, (byte) 0x0d, (byte) 0x6f, (byte) 0xb8, (byte) 0x63, (byte) 0xd5, (byte) 0x17, (byte) 0x38, + (byte) 0xb4, (byte) 0x8e, (byte) 0xee, (byte) 0xe3, (byte) 0x14, (byte) 0xa7, (byte) 0xcc, (byte) 0x8a, + (byte) 0xb9, (byte) 0x32, (byte) 0x16, (byte) 0x45, (byte) 0x48, (byte) 0xe5, (byte) 0x26, (byte) 0xae, + (byte) 0x90, (byte) 0x22, (byte) 0x43, (byte) 0x68, (byte) 0x51, (byte) 0x7a, (byte) 0xcf, (byte) 0xea, + (byte) 0xbd, (byte) 0x6b, (byte) 0xb3, (byte) 0x73, (byte) 0x2b, (byte) 0xc0, (byte) 0xe9, (byte) 0xda, + (byte) 0x99, (byte) 0x83, (byte) 0x2b, (byte) 0x61, (byte) 0xca, (byte) 0x01, (byte) 0xb6, (byte) 0xde, + (byte) 0x56, (byte) 0x24, (byte) 0x4a, (byte) 0x9e, (byte) 0x88, (byte) 0xd5, (byte) 0xf9, (byte) 0xb3, + (byte) 0x79, (byte) 0x73, (byte) 0xf6, (byte) 0x22, (byte) 0xa4, (byte) 0x3d, (byte) 0x14, (byte) 0xa6, + (byte) 0x59, (byte) 0x9b, (byte) 0x1f, (byte) 0x65, (byte) 0x4c, (byte) 0xb4, (byte) 0x5a, (byte) 0x74, + (byte) 0xe3, (byte) 0x55, (byte) 0xa5 + }; + assertThat(c).isEqualTo(expected_c); + } + + @Test + public void test_crypto_cryptobox_2() throws Exception { + byte[] c = new byte[m.length]; + curve25519xsalsa20poly1305.crypto_box(c, m, m.length, nonce, alicepk, bobsk); + byte[] expected_c = new byte[]{ + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0xf3, (byte) 0xff, (byte) 0xc7, (byte) 0x70, (byte) 0x3f, (byte) 0x94, (byte) 0x00, (byte) 0xe5, + (byte) 0x2a, (byte) 0x7d, (byte) 0xfb, (byte) 0x4b, (byte) 0x3d, (byte) 0x33, (byte) 0x05, (byte) 0xd9, + (byte) 0x8e, (byte) 0x99, (byte) 0x3b, (byte) 0x9f, (byte) 0x48, (byte) 0x68, (byte) 0x12, (byte) 0x73, + (byte) 0xc2, (byte) 0x96, (byte) 0x50, (byte) 0xba, (byte) 0x32, (byte) 0xfc, (byte) 0x76, (byte) 0xce, + (byte) 0x48, (byte) 0x33, (byte) 0x2e, (byte) 0xa7, (byte) 0x16, (byte) 0x4d, (byte) 0x96, (byte) 0xa4, + (byte) 0x47, (byte) 0x6f, (byte) 0xb8, (byte) 0xc5, (byte) 0x31, (byte) 0xa1, (byte) 0x18, (byte) 0x6a, + (byte) 0xc0, (byte) 0xdf, (byte) 0xc1, (byte) 0x7c, (byte) 0x98, (byte) 0xdc, (byte) 0xe8, (byte) 0x7b, + (byte) 0x4d, (byte) 0xa7, (byte) 0xf0, (byte) 0x11, (byte) 0xec, (byte) 0x48, (byte) 0xc9, (byte) 0x72, + (byte) 0x71, (byte) 0xd2, (byte) 0xc2, (byte) 0x0f, (byte) 0x9b, (byte) 0x92, (byte) 0x8f, (byte) 0xe2, + (byte) 0x27, (byte) 0x0d, (byte) 0x6f, (byte) 0xb8, (byte) 0x63, (byte) 0xd5, (byte) 0x17, (byte) 0x38, + (byte) 0xb4, (byte) 0x8e, (byte) 0xee, (byte) 0xe3, (byte) 0x14, (byte) 0xa7, (byte) 0xcc, (byte) 0x8a, + (byte) 0xb9, (byte) 0x32, (byte) 0x16, (byte) 0x45, (byte) 0x48, (byte) 0xe5, (byte) 0x26, (byte) 0xae, + (byte) 0x90, (byte) 0x22, (byte) 0x43, (byte) 0x68, (byte) 0x51, (byte) 0x7a, (byte) 0xcf, (byte) 0xea, + (byte) 0xbd, (byte) 0x6b, (byte) 0xb3, (byte) 0x73, (byte) 0x2b, (byte) 0xc0, (byte) 0xe9, (byte) 0xda, + (byte) 0x99, (byte) 0x83, (byte) 0x2b, (byte) 0x61, (byte) 0xca, (byte) 0x01, (byte) 0xb6, (byte) 0xde, + (byte) 0x56, (byte) 0x24, (byte) 0x4a, (byte) 0x9e, (byte) 0x88, (byte) 0xd5, (byte) 0xf9, (byte) 0xb3, + (byte) 0x79, (byte) 0x73, (byte) 0xf6, (byte) 0x22, (byte) 0xa4, (byte) 0x3d, (byte) 0x14, (byte) 0xa6, + (byte) 0x59, (byte) 0x9b, (byte) 0x1f, (byte) 0x65, (byte) 0x4c, (byte) 0xb4, (byte) 0x5a, (byte) 0x74, + (byte) 0xe3, (byte) 0x55, (byte) 0xa5 + }; + assertThat(c).isEqualTo(expected_c); + } + + @Test + public void test_crypto_cryptobox_3() throws Exception { + NaCl nacl = new NaCl(bobsk, alicepk); + byte[] c = nacl.encrypt(mbytes, nonce); + byte[] expected_c = new byte[]{ + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0xf3, (byte) 0xff, (byte) 0xc7, (byte) 0x70, (byte) 0x3f, (byte) 0x94, (byte) 0x00, (byte) 0xe5, + (byte) 0x2a, (byte) 0x7d, (byte) 0xfb, (byte) 0x4b, (byte) 0x3d, (byte) 0x33, (byte) 0x05, (byte) 0xd9, + (byte) 0x8e, (byte) 0x99, (byte) 0x3b, (byte) 0x9f, (byte) 0x48, (byte) 0x68, (byte) 0x12, (byte) 0x73, + (byte) 0xc2, (byte) 0x96, (byte) 0x50, (byte) 0xba, (byte) 0x32, (byte) 0xfc, (byte) 0x76, (byte) 0xce, + (byte) 0x48, (byte) 0x33, (byte) 0x2e, (byte) 0xa7, (byte) 0x16, (byte) 0x4d, (byte) 0x96, (byte) 0xa4, + (byte) 0x47, (byte) 0x6f, (byte) 0xb8, (byte) 0xc5, (byte) 0x31, (byte) 0xa1, (byte) 0x18, (byte) 0x6a, + (byte) 0xc0, (byte) 0xdf, (byte) 0xc1, (byte) 0x7c, (byte) 0x98, (byte) 0xdc, (byte) 0xe8, (byte) 0x7b, + (byte) 0x4d, (byte) 0xa7, (byte) 0xf0, (byte) 0x11, (byte) 0xec, (byte) 0x48, (byte) 0xc9, (byte) 0x72, + (byte) 0x71, (byte) 0xd2, (byte) 0xc2, (byte) 0x0f, (byte) 0x9b, (byte) 0x92, (byte) 0x8f, (byte) 0xe2, + (byte) 0x27, (byte) 0x0d, (byte) 0x6f, (byte) 0xb8, (byte) 0x63, (byte) 0xd5, (byte) 0x17, (byte) 0x38, + (byte) 0xb4, (byte) 0x8e, (byte) 0xee, (byte) 0xe3, (byte) 0x14, (byte) 0xa7, (byte) 0xcc, (byte) 0x8a, + (byte) 0xb9, (byte) 0x32, (byte) 0x16, (byte) 0x45, (byte) 0x48, (byte) 0xe5, (byte) 0x26, (byte) 0xae, + (byte) 0x90, (byte) 0x22, (byte) 0x43, (byte) 0x68, (byte) 0x51, (byte) 0x7a, (byte) 0xcf, (byte) 0xea, + (byte) 0xbd, (byte) 0x6b, (byte) 0xb3, (byte) 0x73, (byte) 0x2b, (byte) 0xc0, (byte) 0xe9, (byte) 0xda, + (byte) 0x99, (byte) 0x83, (byte) 0x2b, (byte) 0x61, (byte) 0xca, (byte) 0x01, (byte) 0xb6, (byte) 0xde, + (byte) 0x56, (byte) 0x24, (byte) 0x4a, (byte) 0x9e, (byte) 0x88, (byte) 0xd5, (byte) 0xf9, (byte) 0xb3, + (byte) 0x79, (byte) 0x73, (byte) 0xf6, (byte) 0x22, (byte) 0xa4, (byte) 0x3d, (byte) 0x14, (byte) 0xa6, + (byte) 0x59, (byte) 0x9b, (byte) 0x1f, (byte) 0x65, (byte) 0x4c, (byte) 0xb4, (byte) 0x5a, (byte) 0x74, + (byte) 0xe3, (byte) 0x55, (byte) 0xa5 + }; + assertThat(c).isEqualTo(expected_c); + } + + @Test + public void test_crypto_cryptobox_4() throws Exception { + NaCl nacl = new NaCl(alicesk, bobpk); + byte[] c = nacl.encrypt(mbytes, nonce); + byte[] expected_c = new byte[]{ + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0xf3, (byte) 0xff, (byte) 0xc7, (byte) 0x70, (byte) 0x3f, (byte) 0x94, (byte) 0x00, (byte) 0xe5, + (byte) 0x2a, (byte) 0x7d, (byte) 0xfb, (byte) 0x4b, (byte) 0x3d, (byte) 0x33, (byte) 0x05, (byte) 0xd9, + (byte) 0x8e, (byte) 0x99, (byte) 0x3b, (byte) 0x9f, (byte) 0x48, (byte) 0x68, (byte) 0x12, (byte) 0x73, + (byte) 0xc2, (byte) 0x96, (byte) 0x50, (byte) 0xba, (byte) 0x32, (byte) 0xfc, (byte) 0x76, (byte) 0xce, + (byte) 0x48, (byte) 0x33, (byte) 0x2e, (byte) 0xa7, (byte) 0x16, (byte) 0x4d, (byte) 0x96, (byte) 0xa4, + (byte) 0x47, (byte) 0x6f, (byte) 0xb8, (byte) 0xc5, (byte) 0x31, (byte) 0xa1, (byte) 0x18, (byte) 0x6a, + (byte) 0xc0, (byte) 0xdf, (byte) 0xc1, (byte) 0x7c, (byte) 0x98, (byte) 0xdc, (byte) 0xe8, (byte) 0x7b, + (byte) 0x4d, (byte) 0xa7, (byte) 0xf0, (byte) 0x11, (byte) 0xec, (byte) 0x48, (byte) 0xc9, (byte) 0x72, + (byte) 0x71, (byte) 0xd2, (byte) 0xc2, (byte) 0x0f, (byte) 0x9b, (byte) 0x92, (byte) 0x8f, (byte) 0xe2, + (byte) 0x27, (byte) 0x0d, (byte) 0x6f, (byte) 0xb8, (byte) 0x63, (byte) 0xd5, (byte) 0x17, (byte) 0x38, + (byte) 0xb4, (byte) 0x8e, (byte) 0xee, (byte) 0xe3, (byte) 0x14, (byte) 0xa7, (byte) 0xcc, (byte) 0x8a, + (byte) 0xb9, (byte) 0x32, (byte) 0x16, (byte) 0x45, (byte) 0x48, (byte) 0xe5, (byte) 0x26, (byte) 0xae, + (byte) 0x90, (byte) 0x22, (byte) 0x43, (byte) 0x68, (byte) 0x51, (byte) 0x7a, (byte) 0xcf, (byte) 0xea, + (byte) 0xbd, (byte) 0x6b, (byte) 0xb3, (byte) 0x73, (byte) 0x2b, (byte) 0xc0, (byte) 0xe9, (byte) 0xda, + (byte) 0x99, (byte) 0x83, (byte) 0x2b, (byte) 0x61, (byte) 0xca, (byte) 0x01, (byte) 0xb6, (byte) 0xde, + (byte) 0x56, (byte) 0x24, (byte) 0x4a, (byte) 0x9e, (byte) 0x88, (byte) 0xd5, (byte) 0xf9, (byte) 0xb3, + (byte) 0x79, (byte) 0x73, (byte) 0xf6, (byte) 0x22, (byte) 0xa4, (byte) 0x3d, (byte) 0x14, (byte) 0xa6, + (byte) 0x59, (byte) 0x9b, (byte) 0x1f, (byte) 0x65, (byte) 0x4c, (byte) 0xb4, (byte) 0x5a, (byte) 0x74, + (byte) 0xe3, (byte) 0x55, (byte) 0xa5 + }; + assertThat(c).isEqualTo(expected_c); + } + + @Test + public void test_crypto_cryptobox_5() throws Exception { + Random random = new Random(); + for (int mlen = 0; mlen < 1000; ++mlen) { + byte[] alicepk = new byte[crypto_secretbox_PUBLICKEYBYTES]; + byte[] alicesk = new byte[crypto_secretbox_SECRETKEYBYTES]; + byte[] bobpk = new byte[crypto_secretbox_PUBLICKEYBYTES]; + byte[] bobsk = new byte[crypto_secretbox_SECRETKEYBYTES]; + curve25519xsalsa20poly1305.crypto_box_keypair(alicepk, alicesk); + curve25519xsalsa20poly1305.crypto_box_keypair(bobpk, bobsk); + byte[] nonce = new byte[crypto_secretbox_NONCEBYTES]; + random.nextBytes(nonce); + byte[] m = new byte[mlen]; + random.nextBytes(m); + NaCl nacl = new NaCl(alicesk, bobpk); + byte[] c = nacl.encrypt(m, nonce); + NaCl nacl2 = new NaCl(bobsk, alicepk); + byte[] m2 = nacl2.decrypt(c, nonce); + assertThat(m2).isEqualTo(m); + } + } + +} \ No newline at end of file From 85e44a6661754d190696d17c15c7340488074963 Mon Sep 17 00:00:00 2001 From: David San Date: Sat, 4 Jul 2020 23:12:40 +0200 Subject: [PATCH 4/5] Add ciphertext verification in decrypt method Also add associated test (cherry picked from commit cf495dbd1771f0a74496de90dcbb6f31dc578d84) (cherry picked from commit c58c0dd8e17e1c06f0cd29bbc5e834d80948791e) --- .../java/com/neilalexander/jnacl/NaCl.java | 8 +++-- .../java/com/neilalexander/jnacl/BoxTest.java | 35 +++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/neilalexander/jnacl/NaCl.java b/src/main/java/com/neilalexander/jnacl/NaCl.java index 356cb41..c76bddc 100644 --- a/src/main/java/com/neilalexander/jnacl/NaCl.java +++ b/src/main/java/com/neilalexander/jnacl/NaCl.java @@ -68,15 +68,17 @@ public byte[] encrypt(byte[] input, int inputlength, byte[] nonce) { return output; } - public byte[] decrypt(byte[] input, byte[] nonce) { + public byte[] decrypt(byte[] input, byte[] nonce) throws Exception { return decrypt(input, input.length, nonce); } - public byte[] decrypt(byte[] input, int inputlength, byte[] nonce) { + public byte[] decrypt(byte[] input, int inputlength, byte[] nonce) throws Exception { byte[] paddedoutput = new byte[inputlength]; byte[] output = new byte[inputlength - crypto_secretbox_ZEROBYTES]; - curve25519xsalsa20poly1305.crypto_box_open_afternm(paddedoutput, input, inputlength, nonce, this.precomputed); + if (curve25519xsalsa20poly1305.crypto_box_open_afternm(paddedoutput, input, inputlength, nonce, this.precomputed) != 0) { + throw new SecurityException("ciphertext fails verification"); + } System.arraycopy(paddedoutput, crypto_secretbox_ZEROBYTES, output, 0, paddedoutput.length - crypto_secretbox_ZEROBYTES); return output; diff --git a/src/test/java/com/neilalexander/jnacl/BoxTest.java b/src/test/java/com/neilalexander/jnacl/BoxTest.java index 5b11f6e..bc8beb1 100644 --- a/src/test/java/com/neilalexander/jnacl/BoxTest.java +++ b/src/test/java/com/neilalexander/jnacl/BoxTest.java @@ -240,4 +240,39 @@ public void test_crypto_cryptobox_5() throws Exception { } } + @Test + public void test_crypto_cryptobox_6() throws Exception { + Random random = new Random(); + for (int mlen = 0; mlen < 1000; ++mlen) { + byte[] alicepk = new byte[crypto_secretbox_PUBLICKEYBYTES]; + byte[] alicesk = new byte[crypto_secretbox_SECRETKEYBYTES]; + byte[] bobpk = new byte[crypto_secretbox_PUBLICKEYBYTES]; + byte[] bobsk = new byte[crypto_secretbox_SECRETKEYBYTES]; + curve25519xsalsa20poly1305.crypto_box_keypair(alicepk, alicesk); + curve25519xsalsa20poly1305.crypto_box_keypair(bobpk, bobsk); + byte[] nonce = new byte[crypto_secretbox_NONCEBYTES]; + random.nextBytes(nonce); + byte[] m = new byte[mlen]; + random.nextBytes(m); + + NaCl nacl = new NaCl(bobpk, alicesk); + byte[] c = nacl.encrypt(m, nonce); + int caught = 0; + + while (caught < 10) { + byte[] b = new byte[1]; + random.nextBytes(b); + c[random.nextInt(c.length)] = b[0]; + NaCl nacl2 = new NaCl(alicepk, bobsk); + try { + byte[] m2 = nacl2.decrypt(c, nonce); + assertThat(m2).isNotEqualTo(m); + } catch (Exception e) { + assertThat(e).isInstanceOf(SecurityException.class) + .hasMessage("ciphertext fails verification"); + caught++; + } + } + } + } } \ No newline at end of file From 6f3b823317ccc62fa6643607808903aa618c7c8e Mon Sep 17 00:00:00 2001 From: David San Date: Sun, 5 Jul 2020 16:07:35 +0200 Subject: [PATCH 5/5] Add cryptobox tests for various message lengths and array corruption (cherry picked from commit 3554e12ec8f1dcfd75ed3688a0dcd25ce3eb13d1) (cherry picked from commit 9f65f940c24d8f82141cab4ed35a823509c5e5d6) --- .../java/com/neilalexander/jnacl/BoxTest.java | 102 ++++++++++++++---- .../com/neilalexander/jnacl/RandomBytes.java | 21 ++++ 2 files changed, 100 insertions(+), 23 deletions(-) create mode 100644 src/test/java/com/neilalexander/jnacl/RandomBytes.java diff --git a/src/test/java/com/neilalexander/jnacl/BoxTest.java b/src/test/java/com/neilalexander/jnacl/BoxTest.java index bc8beb1..2888741 100644 --- a/src/test/java/com/neilalexander/jnacl/BoxTest.java +++ b/src/test/java/com/neilalexander/jnacl/BoxTest.java @@ -1,13 +1,14 @@ package com.neilalexander.jnacl; import com.neilalexander.jnacl.crypto.curve25519xsalsa20poly1305; -import org.fest.assertions.Assert; +import org.fest.assertions.Fail; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; -import java.util.Arrays; import java.util.Random; +import static com.neilalexander.jnacl.RandomBytes.random; +import static com.neilalexander.jnacl.RandomBytes.randombytes; import static com.neilalexander.jnacl.crypto.curve25519xsalsa20poly1305.*; import static org.fest.assertions.Assertions.assertThat; @@ -17,7 +18,7 @@ public class BoxTest { private byte[] alicesk; private byte[] bobpk; private byte[] bobsk; - private byte[] nonce; + private byte[] n; private byte[] m; private byte[] mbytes; @@ -47,7 +48,7 @@ public void setUp() throws Exception { (byte) 0x3f, (byte) 0x83, (byte) 0x43, (byte) 0xc8, (byte) 0x5b, (byte) 0x78, (byte) 0x67, (byte) 0x4d, (byte) 0xad, (byte) 0xfc, (byte) 0x7e, (byte) 0x14, (byte) 0x6f, (byte) 0x88, (byte) 0x2b, (byte) 0x4f }; - nonce = new byte[]{ + n = new byte[]{ (byte) 0x69, (byte) 0x69, (byte) 0x6e, (byte) 0xe9, (byte) 0x55, (byte) 0xb6, (byte) 0x2b, (byte) 0x73, (byte) 0xcd, (byte) 0x62, (byte) 0xbd, (byte) 0xa8, (byte) 0x75, (byte) 0xfc, (byte) 0x73, (byte) 0xd6, (byte) 0x82, (byte) 0x19, (byte) 0xe0, (byte) 0x03, (byte) 0x6b, (byte) 0x7a, (byte) 0x0b, (byte) 0x37 @@ -101,7 +102,7 @@ public void setUp() throws Exception { @Test public void test_crypto_cryptobox_1() throws Exception { byte[] c = new byte[m.length]; - curve25519xsalsa20poly1305.crypto_box(c, m, m.length, nonce, bobpk, alicesk); + curve25519xsalsa20poly1305.crypto_box(c, m, m.length, n, bobpk, alicesk); byte[] expected_c = new byte[]{ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, @@ -131,7 +132,7 @@ public void test_crypto_cryptobox_1() throws Exception { @Test public void test_crypto_cryptobox_2() throws Exception { byte[] c = new byte[m.length]; - curve25519xsalsa20poly1305.crypto_box(c, m, m.length, nonce, alicepk, bobsk); + curve25519xsalsa20poly1305.crypto_box(c, m, m.length, n, alicepk, bobsk); byte[] expected_c = new byte[]{ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, @@ -161,7 +162,7 @@ public void test_crypto_cryptobox_2() throws Exception { @Test public void test_crypto_cryptobox_3() throws Exception { NaCl nacl = new NaCl(bobsk, alicepk); - byte[] c = nacl.encrypt(mbytes, nonce); + byte[] c = nacl.encrypt(mbytes, n); byte[] expected_c = new byte[]{ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, @@ -191,7 +192,7 @@ public void test_crypto_cryptobox_3() throws Exception { @Test public void test_crypto_cryptobox_4() throws Exception { NaCl nacl = new NaCl(alicesk, bobpk); - byte[] c = nacl.encrypt(mbytes, nonce); + byte[] c = nacl.encrypt(mbytes, n); byte[] expected_c = new byte[]{ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, @@ -220,7 +221,6 @@ public void test_crypto_cryptobox_4() throws Exception { @Test public void test_crypto_cryptobox_5() throws Exception { - Random random = new Random(); for (int mlen = 0; mlen < 1000; ++mlen) { byte[] alicepk = new byte[crypto_secretbox_PUBLICKEYBYTES]; byte[] alicesk = new byte[crypto_secretbox_SECRETKEYBYTES]; @@ -228,14 +228,15 @@ public void test_crypto_cryptobox_5() throws Exception { byte[] bobsk = new byte[crypto_secretbox_SECRETKEYBYTES]; curve25519xsalsa20poly1305.crypto_box_keypair(alicepk, alicesk); curve25519xsalsa20poly1305.crypto_box_keypair(bobpk, bobsk); - byte[] nonce = new byte[crypto_secretbox_NONCEBYTES]; - random.nextBytes(nonce); + byte[] n = new byte[crypto_secretbox_NONCEBYTES]; + randombytes(n, 0, crypto_secretbox_NONCEBYTES); byte[] m = new byte[mlen]; - random.nextBytes(m); + randombytes(m, 0, mlen); + NaCl nacl = new NaCl(alicesk, bobpk); - byte[] c = nacl.encrypt(m, nonce); + byte[] c = nacl.encrypt(m, n); NaCl nacl2 = new NaCl(bobsk, alicepk); - byte[] m2 = nacl2.decrypt(c, nonce); + byte[] m2 = nacl2.decrypt(c, n); assertThat(m2).isEqualTo(m); } } @@ -250,22 +251,19 @@ public void test_crypto_cryptobox_6() throws Exception { byte[] bobsk = new byte[crypto_secretbox_SECRETKEYBYTES]; curve25519xsalsa20poly1305.crypto_box_keypair(alicepk, alicesk); curve25519xsalsa20poly1305.crypto_box_keypair(bobpk, bobsk); - byte[] nonce = new byte[crypto_secretbox_NONCEBYTES]; - random.nextBytes(nonce); + byte[] n = new byte[crypto_secretbox_NONCEBYTES]; + randombytes(n, 0, crypto_secretbox_NONCEBYTES); byte[] m = new byte[mlen]; - random.nextBytes(m); + randombytes(m, 0, mlen); NaCl nacl = new NaCl(bobpk, alicesk); - byte[] c = nacl.encrypt(m, nonce); + byte[] c = nacl.encrypt(m, this.n); int caught = 0; - while (caught < 10) { - byte[] b = new byte[1]; - random.nextBytes(b); - c[random.nextInt(c.length)] = b[0]; + c[random.nextInt(c.length)] = random(); NaCl nacl2 = new NaCl(alicepk, bobsk); try { - byte[] m2 = nacl2.decrypt(c, nonce); + byte[] m2 = nacl2.decrypt(c, this.n); assertThat(m2).isNotEqualTo(m); } catch (Exception e) { assertThat(e).isInstanceOf(SecurityException.class) @@ -275,4 +273,62 @@ public void test_crypto_cryptobox_6() throws Exception { } } } + + @Test + public void test_crypto_cryptobox_7() throws Exception { + byte[] alicepk = new byte[crypto_secretbox_PUBLICKEYBYTES]; + byte[] alicesk = new byte[crypto_secretbox_SECRETKEYBYTES]; + byte[] bobpk = new byte[crypto_secretbox_PUBLICKEYBYTES]; + byte[] bobsk = new byte[crypto_secretbox_SECRETKEYBYTES]; + byte[] n = new byte[crypto_secretbox_NONCEBYTES]; + byte[] m = new byte[10000]; + byte[] c = new byte[10000]; + byte[] m2 = new byte[10000]; + + for (int mlen = 0; mlen < 1000 && mlen + crypto_secretbox_ZEROBYTES < m.length; ++mlen) { + curve25519xsalsa20poly1305.crypto_box_keypair(alicepk, alicesk); + curve25519xsalsa20poly1305.crypto_box_keypair(bobpk, bobsk); + randombytes(n, 0, crypto_secretbox_NONCEBYTES); + randombytes(m, crypto_secretbox_ZEROBYTES, mlen + crypto_secretbox_ZEROBYTES + mlen); + crypto_box(c, m, mlen + crypto_secretbox_ZEROBYTES, n, bobpk, alicesk); + if (crypto_box_open(m2, c, mlen + crypto_secretbox_ZEROBYTES, n, alicepk, bobsk) == 0) { + for (int i = 0; i < mlen + crypto_secretbox_ZEROBYTES; i++) { + assertThat(m2[i]).isEqualTo(m[i]); + } + } else { + Fail.fail("ciphertext fails verification"); + } + } + } + + @Test + public void test_crypto_cryptobox_8() throws Exception { + byte[] alicepk = new byte[crypto_secretbox_PUBLICKEYBYTES]; + byte[] alicesk = new byte[crypto_secretbox_SECRETKEYBYTES]; + byte[] bobpk = new byte[crypto_secretbox_PUBLICKEYBYTES]; + byte[] bobsk = new byte[crypto_secretbox_SECRETKEYBYTES]; + byte[] n = new byte[crypto_secretbox_NONCEBYTES]; + byte[] m = new byte[10000]; + byte[] c = new byte[10000]; + byte[] m2 = new byte[10000]; + + for (int mlen = 0; mlen < 1000 && mlen + crypto_secretbox_ZEROBYTES < m.length; ++mlen) { + curve25519xsalsa20poly1305.crypto_box_keypair(alicepk, alicesk); + curve25519xsalsa20poly1305.crypto_box_keypair(bobpk, bobsk); + randombytes(n, 0, crypto_secretbox_NONCEBYTES); + randombytes(m, crypto_secretbox_ZEROBYTES, mlen + crypto_secretbox_ZEROBYTES + mlen); + crypto_box(c, m, mlen + crypto_secretbox_ZEROBYTES, n, bobpk, alicesk); + int caught = 0; + while (caught < 10) { + c[random.nextInt(mlen + crypto_secretbox_ZEROBYTES)] = random(); + if (crypto_box_open(m2, c, mlen + crypto_secretbox_ZEROBYTES, n, alicepk, bobsk) == 0) { + for (int i = 0; i < mlen + crypto_secretbox_ZEROBYTES; i++) { + assertThat(m2[i]).isEqualTo(m[i]); + } + } else { + caught++; + } + } + } + } } \ No newline at end of file diff --git a/src/test/java/com/neilalexander/jnacl/RandomBytes.java b/src/test/java/com/neilalexander/jnacl/RandomBytes.java new file mode 100644 index 0000000..d77ad31 --- /dev/null +++ b/src/test/java/com/neilalexander/jnacl/RandomBytes.java @@ -0,0 +1,21 @@ +package com.neilalexander.jnacl; + +import java.util.Random; + +public class RandomBytes { + static Random random = new Random(); + + protected static byte random() { + byte[] b = new byte[1]; + random.nextBytes(b); + return b[0]; + } + + protected static void randombytes(byte[] bytes, int start, int end) { + for (int i = start, len = bytes.length; i < end && i < len; ) + for (int rnd = random.nextInt(), + n = Math.min(len - i, Integer.SIZE / Byte.SIZE); + n-- > 0; rnd >>= Byte.SIZE) + bytes[i++] = (byte) rnd; + } +}