diff --git a/jni/sodium.i b/jni/sodium.i index 453a534..352c418 100644 --- a/jni/sodium.i +++ b/jni/sodium.i @@ -227,6 +227,21 @@ %typemap(freearg) crypto_auth_hmacsha512256_state *"" +/* + crypto_secretstream_xchacha20poly1305_state +*/ +%typemap(jni) crypto_secretstream_xchacha20poly1305_state *"jbyteArray" +%typemap(jtype) crypto_secretstream_xchacha20poly1305_state *"byte[]" +%typemap(jstype) crypto_secretstream_xchacha20poly1305_state *"byte[]" +%typemap(in) crypto_secretstream_xchacha20poly1305_state *{ + $1 = (crypto_secretstream_xchacha20poly1305_state *) JCALL2(GetByteArrayElements, jenv, $input, 0); +} +%typemap(argout) crypto_secretstream_xchacha20poly1305_state *{ + JCALL3(ReleaseByteArrayElements, jenv, $input, (jbyte *) $1, 0); +} +%typemap(javain) crypto_secretstream_xchacha20poly1305_state *"$javainput" +%typemap(freearg) crypto_secretstream_xchacha20poly1305_state *"" + /* ***************************************************************************** @@ -1375,3 +1390,49 @@ int crypto_stream_xsalsa20_xor_ic(unsigned char *c, const unsigned char *n, uint64_t ic, const unsigned char *k); + +/* + Secret Stream Xchacha20 Poly1305 +*/ + +size_t crypto_secretstream_xchacha20poly1305_keybytes(void); +size_t crypto_secretstream_xchacha20poly1305_headerbytes(void); +size_t crypto_secretstream_xchacha20poly1305_abytes(void); +size_t crypto_secretstream_xchacha20poly1305_statebytes(void); + +size_t crypto_secretstream_xchacha20poly1305_tag_message(void); +size_t crypto_secretstream_xchacha20poly1305_tag_push(void); +size_t crypto_secretstream_xchacha20poly1305_tag_rekey(void); +size_t crypto_secretstream_xchacha20poly1305_tag_final(void); + +size_t crypto_secretstream_xchacha20poly1305_messagebytes_max(void); + +void crypto_secretstream_xchacha20poly1305_keygen(unsigned char *k); + +int crypto_secretstream_xchacha20poly1305_init_push(crypto_secretstream_xchacha20poly1305_state *state, + unsigned char *header, + const unsigned char *k); + +int crypto_secretstream_xchacha20poly1305_push(crypto_secretstream_xchacha20poly1305_state *state, + unsigned char *c, + unsigned long long *clen_p, + const unsigned char *m, + unsigned long long mlen, + const unsigned char *ad, + unsigned long long adlen, + unsigned char tag); + +int crypto_secretstream_xchacha20poly1305_init_pull(crypto_secretstream_xchacha20poly1305_state *state, + const unsigned char *header, + const unsigned char *k); + +int crypto_secretstream_xchacha20poly1305_pull(crypto_secretstream_xchacha20poly1305_state *state, + unsigned char *m, + unsigned long long *mlen_p, + unsigned char *tag_p, + const unsigned char *c, + unsigned long long clen, + const unsigned char *ad, + unsigned long long adlen); + +void crypto_secretstream_xchacha20poly1305_rekey(crypto_secretstream_xchacha20poly1305_state *state); \ No newline at end of file diff --git a/src/main/java/org/libsodium/jni/Sodium.java b/src/main/java/org/libsodium/jni/Sodium.java index a510832..deffcbb 100644 --- a/src/main/java/org/libsodium/jni/Sodium.java +++ b/src/main/java/org/libsodium/jni/Sodium.java @@ -1081,4 +1081,64 @@ public static int crypto_stream_xsalsa20_xor_ic(byte[] c, byte[] m, int mlen, by return SodiumJNI.crypto_stream_xsalsa20_xor_ic(c, m, mlen, n, ic, k); } + public static int crypto_secretstream_xchacha20poly1305_keybytes() { + return SodiumJNI.crypto_secretstream_xchacha20poly1305_keybytes(); + } + + public static int crypto_secretstream_xchacha20poly1305_headerbytes() { + return SodiumJNI.crypto_secretstream_xchacha20poly1305_headerbytes(); + } + + public static int crypto_secretstream_xchacha20poly1305_abytes() { + return SodiumJNI.crypto_secretstream_xchacha20poly1305_abytes(); + } + + public static int crypto_secretstream_xchacha20poly1305_statebytes() { + return SodiumJNI.crypto_secretstream_xchacha20poly1305_statebytes(); + } + + public static int crypto_secretstream_xchacha20poly1305_tag_message() { + return SodiumJNI.crypto_secretstream_xchacha20poly1305_tag_message(); + } + + public static int crypto_secretstream_xchacha20poly1305_tag_push() { + return SodiumJNI.crypto_secretstream_xchacha20poly1305_tag_push(); + } + + public static int crypto_secretstream_xchacha20poly1305_tag_rekey() { + return SodiumJNI.crypto_secretstream_xchacha20poly1305_tag_rekey(); + } + + public static int crypto_secretstream_xchacha20poly1305_tag_final() { + return SodiumJNI.crypto_secretstream_xchacha20poly1305_tag_final(); + } + + public static int crypto_secretstream_xchacha20poly1305_messagebytes_max() { + return SodiumJNI.crypto_secretstream_xchacha20poly1305_messagebytes_max(); + } + + public static void crypto_secretstream_xchacha20poly1305_keygen(byte[] k) { + SodiumJNI.crypto_secretstream_xchacha20poly1305_keygen(k); + } + + public static int crypto_secretstream_xchacha20poly1305_init_push(byte[] state, byte[] header, byte[] k) { + return SodiumJNI.crypto_secretstream_xchacha20poly1305_init_push(state, header, k); + } + + public static int crypto_secretstream_xchacha20poly1305_push(byte[] state, byte[] c, int[] clen_p, byte[] m, int mlen, byte[] ad, int adlen, short tag) { + return SodiumJNI.crypto_secretstream_xchacha20poly1305_push(state, c, clen_p, m, mlen, ad, adlen, tag); + } + + public static int crypto_secretstream_xchacha20poly1305_init_pull(byte[] state, byte[] header, byte[] k) { + return SodiumJNI.crypto_secretstream_xchacha20poly1305_init_pull(state, header, k); + } + + public static int crypto_secretstream_xchacha20poly1305_pull(byte[] state, byte[] m, int[] mlen_p, byte[] tag_p, byte[] c, int clen, byte[] ad, int adlen) { + return SodiumJNI.crypto_secretstream_xchacha20poly1305_pull(state, m, mlen_p, tag_p, c, clen, ad, adlen); + } + + public static void crypto_secretstream_xchacha20poly1305_rekey(byte[] state) { + SodiumJNI.crypto_secretstream_xchacha20poly1305_rekey(state); + } + } diff --git a/src/main/java/org/libsodium/jni/SodiumJNI.java b/src/main/java/org/libsodium/jni/SodiumJNI.java index 8e120fd..507a5a7 100644 --- a/src/main/java/org/libsodium/jni/SodiumJNI.java +++ b/src/main/java/org/libsodium/jni/SodiumJNI.java @@ -277,4 +277,19 @@ public class SodiumJNI { public final static native int crypto_stream_xsalsa20_noncebytes(); public final static native int crypto_stream_xsalsa20_xor(byte[] jarg1, byte[] jarg2, int jarg3, byte[] jarg4, byte[] jarg5); public final static native int crypto_stream_xsalsa20_xor_ic(byte[] jarg1, byte[] jarg2, int jarg3, byte[] jarg4, int jarg5, byte[] jarg6); + public final static native int crypto_secretstream_xchacha20poly1305_keybytes(); + public final static native int crypto_secretstream_xchacha20poly1305_headerbytes(); + public final static native int crypto_secretstream_xchacha20poly1305_abytes(); + public final static native int crypto_secretstream_xchacha20poly1305_statebytes(); + public final static native int crypto_secretstream_xchacha20poly1305_tag_message(); + public final static native int crypto_secretstream_xchacha20poly1305_tag_push(); + public final static native int crypto_secretstream_xchacha20poly1305_tag_rekey(); + public final static native int crypto_secretstream_xchacha20poly1305_tag_final(); + public final static native int crypto_secretstream_xchacha20poly1305_messagebytes_max(); + public final static native void crypto_secretstream_xchacha20poly1305_keygen(byte[] jarg1); + public final static native int crypto_secretstream_xchacha20poly1305_init_push(byte[] jarg1, byte[] jarg2, byte[] jarg3); + public final static native int crypto_secretstream_xchacha20poly1305_push(byte[] jarg1, byte[] jarg2, int[] jarg3, byte[] jarg4, int jarg5, byte[] jarg6, int jarg7, short jarg8); + public final static native int crypto_secretstream_xchacha20poly1305_init_pull(byte[] jarg1, byte[] jarg2, byte[] jarg3); + public final static native int crypto_secretstream_xchacha20poly1305_pull(byte[] jarg1, byte[] jarg2, int[] jarg3, byte[] jarg4, byte[] jarg5, int jarg6, byte[] jarg7, int jarg8); + public final static native void crypto_secretstream_xchacha20poly1305_rekey(byte[] jarg1); } diff --git a/src/test/java/org/libsodium/jni/crypto/SecretStreamTest.java b/src/test/java/org/libsodium/jni/crypto/SecretStreamTest.java new file mode 100644 index 0000000..2862aa9 --- /dev/null +++ b/src/test/java/org/libsodium/jni/crypto/SecretStreamTest.java @@ -0,0 +1,82 @@ +package org.libsodium.jni.crypto; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.fail; + +import org.libsodium.jni.Sodium; +import org.libsodium.jni.encoders.Hex; + +public class SecretStreamTest { + public static final String message1 = "Arbitrary data to encrypt"; + public static final String message2 = "split into"; + public static final String message3 = "three messages"; + public static final String cipherText1 = "e9d5b0eceb20feda8af55547b0d3d8aa32b349cfe1c9e97d4220243691aea56a6281fced9c37bc57cc64"; + public static final String cipherText2 = "24d51ef9c941c8cd7af13bc7260cdb0b4074a5d8da006151610a0a"; + public static final String cipherText3 = "7d6180002f6d0248512fcb048e0d64baf536c994255af0cf7ae493e88f1d6d"; + public static final String testKey = "6ad964e0e2cb155e662521242ef50023b1b03cf4736c7f1e2544aa5aa90c21ad"; + public static final String testHeader = "05a5f60c257d6e004f656d72d764e150da0cc6239e63c444"; + public static final String testState = "e0644ca907a613c71fe0399b17984d8e2868f4fcda4f223adcb662cd6adc8d9001000000da0cc6239e63c4440000000000000000"; + + @Test + public void testEncryption() { + Hex hex = new Hex(); + + byte[] state = hex.decode(testState); + byte[] ad = new byte[1]; + int[] clen = new int[1]; + + byte[] c1 = new byte[25 + 17]; + byte[] c2 = new byte[10 + 17]; + byte[] c3 = new byte[14 + 17]; + + Sodium.crypto_secretstream_xchacha20poly1305_push(state, c1, clen, message1.getBytes(), 25, ad, 0, (short)0); + assertEquals(hex.encode(c1), cipherText1); + + Sodium.crypto_secretstream_xchacha20poly1305_push(state, c2, clen, message2.getBytes(), 10, ad, 0, (short)0); + assertEquals(hex.encode(c2), cipherText2); + + Sodium.crypto_secretstream_xchacha20poly1305_push(state, c3, clen, message3.getBytes(), 14, ad, 0, (short)3); + assertEquals(hex.encode(c3), cipherText3); + } + + @Test + public void testDecryption() { + Hex hex = new Hex(); + + byte[] state = new byte[52]; + byte[] key = hex.decode(testKey); + byte[] header = hex.decode(testHeader); + byte[] ad = new byte[1]; + int[] mlen = new int[1]; + byte[] tag = new byte[1]; + + byte[] c1 = hex.decode(cipherText1); + byte[] c2 = hex.decode(cipherText2); + byte[] c3 = hex.decode(cipherText3); + + byte[] m1 = new byte[25]; + byte[] m2 = new byte[10]; + byte[] m3 = new byte[14]; + + if (Sodium.crypto_secretstream_xchacha20poly1305_init_pull(state, header, key) != 0) { + fail("Should return 0. Header is invalid."); + } + + if (Sodium.crypto_secretstream_xchacha20poly1305_pull(state, m1, mlen, tag, c1, 25 + 17, ad, 0) != 0) { + fail("Should return 0. Corrupted cipherText."); + } + assertArrayEquals(m1, message1.getBytes()); + + if (Sodium.crypto_secretstream_xchacha20poly1305_pull(state, m2, mlen, tag, c2, 10 + 17, ad, 0) != 0) { + fail("Should return 0. Corrupted cipherText."); + } + assertArrayEquals(m2, message2.getBytes()); + + if (Sodium.crypto_secretstream_xchacha20poly1305_pull(state, m3, mlen, tag, c3, 14 + 17, ad, 0) != 0) { + fail("Should return 0. Corrupted cipherText."); + } + assertArrayEquals(m3, message3.getBytes()); + } +} \ No newline at end of file