aboutsummaryrefslogtreecommitdiff
path: root/nearby/connections/ukey2/ukey2_jni/java
diff options
context:
space:
mode:
Diffstat (limited to 'nearby/connections/ukey2/ukey2_jni/java')
-rw-r--r--nearby/connections/ukey2/ukey2_jni/java/build.gradle.kts5
-rw-r--r--nearby/connections/ukey2/ukey2_jni/java/src/jmh/java/com/google/security/cryptauth/lib/securegcm/Ukey2Benchmark.java83
-rw-r--r--nearby/connections/ukey2/ukey2_jni/java/src/jmh/java/com/google/security/cryptauth/lib/securegcm/ukey2/Ukey2Benchmark.java78
-rw-r--r--nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DConnectionContextV1.java123
-rw-r--r--nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DHandshakeContext.java122
-rw-r--r--nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/ukey2/BadHandleException.java (renamed from nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/BadHandleException.java)7
-rw-r--r--nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/ukey2/CryptoException.java (renamed from nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/CryptoException.java)8
-rw-r--r--nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/ukey2/D2DConnectionContextV1.java139
-rw-r--r--nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/ukey2/D2DHandshakeContext.java129
-rw-r--r--nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/ukey2/HandshakeException.java (renamed from nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/HandshakeException.java)26
-rw-r--r--nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/ukey2/SessionRestoreException.java (renamed from nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/SessionRestoreException.java)8
-rw-r--r--nearby/connections/ukey2/ukey2_jni/java/src/test/java/com/google/security/cryptauth/lib/securegcm/TestUkey2Protocol.kt182
-rw-r--r--nearby/connections/ukey2/ukey2_jni/java/src/test/java/com/google/security/cryptauth/lib/securegcm/ukey2/TestUkey2Protocol.kt167
13 files changed, 538 insertions, 539 deletions
diff --git a/nearby/connections/ukey2/ukey2_jni/java/build.gradle.kts b/nearby/connections/ukey2/ukey2_jni/java/build.gradle.kts
index 58c58fc..78b0ebc 100644
--- a/nearby/connections/ukey2/ukey2_jni/java/build.gradle.kts
+++ b/nearby/connections/ukey2/ukey2_jni/java/build.gradle.kts
@@ -44,6 +44,7 @@ dependencies {
implementation("com.google.code.findbugs:jsr305:3.0.2")
implementation(kotlin("stdlib"))
testImplementation("org.junit.jupiter:junit-jupiter:5.9.2")
+ testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.2")
}
kotlin {
@@ -51,10 +52,10 @@ kotlin {
}
tasks.jmh {
- jvmArgs.value(mutableListOf("-Djava.library.path=../../../../target/release"))
+ jvmArgs.value(mutableListOf("-Djava.library.path=$projectDir/../../../../target/release"))
}
tasks.test {
useJUnitPlatform()
- jvmArgs = mutableListOf("-Djava.library.path=../../../../target/debug")
+ jvmArgs = mutableListOf("-Djava.library.path=$projectDir/../../../../target/debug")
}
diff --git a/nearby/connections/ukey2/ukey2_jni/java/src/jmh/java/com/google/security/cryptauth/lib/securegcm/Ukey2Benchmark.java b/nearby/connections/ukey2/ukey2_jni/java/src/jmh/java/com/google/security/cryptauth/lib/securegcm/Ukey2Benchmark.java
deleted file mode 100644
index eb063cc..0000000
--- a/nearby/connections/ukey2/ukey2_jni/java/src/jmh/java/com/google/security/cryptauth/lib/securegcm/Ukey2Benchmark.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2023 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.security.cryptauth.lib.securegcm;
-
-import org.openjdk.jmh.annotations.*;
-import org.openjdk.jmh.infra.Blackhole;
-import org.openjdk.jmh.profile.GCProfiler;
-import org.openjdk.jmh.runner.Runner;
-import org.openjdk.jmh.runner.RunnerException;
-import org.openjdk.jmh.runner.options.Options;
-import org.openjdk.jmh.runner.options.OptionsBuilder;
-
-import java.nio.charset.StandardCharsets;
-import java.time.Duration;
-import java.util.concurrent.TimeUnit;
-import java.util.Random;
-
-/**
- * Benchmark for encoding and decoding UKEY2 messages over the JNI, analogous to
- * `ukey2_benches.rs`. The parameters and the operations also roughly matches the that of the Rust
- * Criterion benchmark. That said, since the benchmark infrastructure is different, there will
- * inevitably be differences the skews the number in certain ways – comparison of numbers from the
- * different benchmarks should compared on order-of-magnitudes only. To get the JNI overhead, for
- * example, it would be better use this JMH infra to measure a call into a no-op Rust function,
- * which is a more apples-to-apples comparison.
- *
- * To run this benchmark, run
- * cargo build -p ukey2_jni --release && ./gradlew jmh
- */
-@State(Scope.Benchmark)
-@OutputTimeUnit(TimeUnit.SECONDS)
-@BenchmarkMode(Mode.Throughput)
-public class Ukey2Benchmark {
-
- @State(Scope.Thread)
- public static class ConnectionState {
- D2DConnectionContextV1 connContext;
- D2DConnectionContextV1 serverConnContext;
- @Param({"10", "1024"})
- int sizeKibs;
- byte[] inputBytes;
-
- @Setup
- public void setup() throws Exception {
- D2DHandshakeContext initiatorContext =
- new D2DHandshakeContext(D2DHandshakeContext.Role.Initiator);
- D2DHandshakeContext serverContext =
- new D2DHandshakeContext(D2DHandshakeContext.Role.Responder);
- serverContext.parseHandshakeMessage(initiatorContext.getNextHandshakeMessage());
- initiatorContext.parseHandshakeMessage(serverContext.getNextHandshakeMessage());
- serverContext.parseHandshakeMessage(initiatorContext.getNextHandshakeMessage());
- connContext = initiatorContext.toConnectionContext();
- serverConnContext = serverContext.toConnectionContext();
- Random random = new Random();
- inputBytes = new byte[sizeKibs * 1024];
- random.nextBytes(inputBytes);
- }
- }
-
- @Benchmark
- @Fork(3)
- @Warmup(iterations = 2, time = 500, timeUnit = TimeUnit.MILLISECONDS)
- @Measurement(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)
- public void encodeAndDecode(ConnectionState state, Blackhole blackhole) throws Exception {
- byte[] encoded = state.connContext.encodeMessageToPeer(state.inputBytes, null);
- byte[] decoded = state.serverConnContext.decodeMessageFromPeer(encoded, null);
- blackhole.consume(decoded);
- }
-}
diff --git a/nearby/connections/ukey2/ukey2_jni/java/src/jmh/java/com/google/security/cryptauth/lib/securegcm/ukey2/Ukey2Benchmark.java b/nearby/connections/ukey2/ukey2_jni/java/src/jmh/java/com/google/security/cryptauth/lib/securegcm/ukey2/Ukey2Benchmark.java
new file mode 100644
index 0000000..9cca229
--- /dev/null
+++ b/nearby/connections/ukey2/ukey2_jni/java/src/jmh/java/com/google/security/cryptauth/lib/securegcm/ukey2/Ukey2Benchmark.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.security.cryptauth.lib.securegcm.ukey2;
+
+import com.google.security.cryptauth.lib.securegcm.ukey2.D2DHandshakeContext.Role;
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.infra.Blackhole;
+
+import java.util.concurrent.TimeUnit;
+import java.util.Random;
+
+/**
+ * Benchmark for encoding and decoding UKEY2 messages over the JNI, analogous to `ukey2_benches.rs`.
+ * The parameters and the operations also roughly matches the that of the Rust Criterion benchmark.
+ * That said, since the benchmark infrastructure is different, there will inevitably be differences
+ * the skews the number in certain ways – comparison of numbers from the different benchmarks should
+ * compared on order-of-magnitudes only. To get the JNI overhead, for example, it would be better
+ * use this JMH infra to measure a call into a no-op Rust function, which is a more apples-to-apples
+ * comparison.
+ *
+ * <p>To run this benchmark, run cargo build -p ukey2_jni --release && ./gradlew jmh
+ */
+@State(Scope.Benchmark)
+@OutputTimeUnit(TimeUnit.SECONDS)
+@BenchmarkMode(Mode.Throughput)
+public class Ukey2Benchmark {
+
+ @State(Scope.Thread)
+ public static class ConnectionState {
+ D2DConnectionContextV1 connContext;
+ D2DConnectionContextV1 serverConnContext;
+
+ @Param({"10", "1024"})
+ int sizeKibs;
+
+ byte[] inputBytes;
+
+ @Setup
+ public void setup() throws Exception {
+ D2DHandshakeContext initiatorContext =
+ new D2DHandshakeContext(Role.INITIATOR);
+ D2DHandshakeContext serverContext =
+ new D2DHandshakeContext(Role.RESPONDER);
+ serverContext.parseHandshakeMessage(initiatorContext.getNextHandshakeMessage());
+ initiatorContext.parseHandshakeMessage(serverContext.getNextHandshakeMessage());
+ serverContext.parseHandshakeMessage(initiatorContext.getNextHandshakeMessage());
+ connContext = initiatorContext.toConnectionContext();
+ serverConnContext = serverContext.toConnectionContext();
+ Random random = new Random();
+ inputBytes = new byte[sizeKibs * 1024];
+ random.nextBytes(inputBytes);
+ }
+ }
+
+ @Benchmark
+ @Fork(3)
+ @Warmup(iterations = 2, time = 500, timeUnit = TimeUnit.MILLISECONDS)
+ @Measurement(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)
+ public void encodeAndDecode(ConnectionState state, Blackhole blackhole) throws Exception {
+ byte[] encoded = state.connContext.encodeMessageToPeer(state.inputBytes, null);
+ byte[] decoded = state.serverConnContext.decodeMessageFromPeer(encoded, null);
+ blackhole.consume(decoded);
+ }
+}
diff --git a/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DConnectionContextV1.java b/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DConnectionContextV1.java
deleted file mode 100644
index 7874cd9..0000000
--- a/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DConnectionContextV1.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright 2023 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.security.cryptauth.lib.securegcm;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-public class D2DConnectionContextV1 {
-
- static {
- System.loadLibrary("ukey2_jni");
- }
-
- private static native byte[] encode_message_to_peer(long contextPtr, byte[] payload, byte[] associatedData) throws BadHandleException;
-
- private static native byte[] decode_message_from_peer(long contextPtr, byte[] message, byte[] associatedData) throws CryptoException;
-
- private static native byte[] get_session_unique(long contextPtr) throws BadHandleException;
-
- private static native int get_sequence_number_for_encoding(long contextPtr) throws BadHandleException;
-
- private static native int get_sequence_number_for_decoding(long contextPtr) throws BadHandleException;
-
- private static native byte[] save_session(long contextPtr) throws BadHandleException;
-
- private static native long from_saved_session(byte[] savedSessionInfo);
-
- private final long contextPtr;
-
- /**
- * Java wrapper for D2DConnectionContextV1 to interact with the underlying Rust implementation
- *
- * @param contextPtr the handle to the Rust implementation.
- */
- D2DConnectionContextV1(@Nonnull long contextPtr) {
- this.contextPtr = contextPtr;
- }
-
- /**
- * Encode a message to the connection peer using session keys derived from the handshake.
- *
- * @param payload The message to be encrypted.
- * @return The encrypted/encoded message.
- */
- @Nonnull
- public byte[] encodeMessageToPeer(@Nonnull byte[] payload, @Nullable byte[] associatedData) throws BadHandleException {
- return encode_message_to_peer(contextPtr, payload, associatedData);
- }
-
- /**
- * Decodes/decrypts a message from the connection peer.
- *
- * @param message The message received over the connection.
- * @return The decoded message from the connection peer.
- */
- @Nonnull
- public byte[] decodeMessageFromPeer(@Nonnull byte[] message, @Nullable byte[] associatedData) throws CryptoException {
- return decode_message_from_peer(contextPtr, message, associatedData);
- }
-
- /**
- * A unique session identifier derived from session-specific information
- *
- * @return The session unique identifier
- */
- @Nonnull
- public byte[] getSessionUnique() throws BadHandleException {
- return get_session_unique(contextPtr);
- }
-
- /**
- * Returns the encoding sequence number.
- *
- * @return the encoding sequence number.
- */
- public int getSequenceNumberForEncoding() throws BadHandleException {
- return get_sequence_number_for_encoding(contextPtr);
- }
-
- /**
- * Returns the decoding sequence number.
- *
- * @return the decoding sequence number.
- */
- public int getSequenceNumberForDecoding() throws BadHandleException {
- return get_sequence_number_for_decoding(contextPtr);
- }
-
- /**
- * Serializes the current session in a form usable by {@link D2DConnectionContextV1#fromSavedSession}
- *
- * @return a byte array representing the current session.
- */
- @Nonnull
- public byte[] saveSession() throws BadHandleException {
- return save_session(contextPtr);
- }
-
- /**
- * Reconstructs and returns the session originally serialized by {@link D2DConnectionContextV1#saveSession}
- *
- * @param savedSessionInfo the byte array from saveSession()
- * @return a D2DConnectionContextV1 session with the same properties as the context saved.
- */
- public static D2DConnectionContextV1 fromSavedSession(@Nonnull byte[] savedSessionInfo) {
- return new D2DConnectionContextV1(from_saved_session(savedSessionInfo));
- }
-
-}
diff --git a/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DHandshakeContext.java b/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DHandshakeContext.java
deleted file mode 100644
index 39f7aa9..0000000
--- a/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DHandshakeContext.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2023 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.security.cryptauth.lib.securegcm;
-
-import javax.annotation.Nonnull;
-
-public class D2DHandshakeContext {
- static {
- System.loadLibrary("ukey2_jni");
- }
-
- public enum Role {
- INITIATOR,
- RESPONDER,
- }
-
- private final long contextPtr;
-
- private static native boolean is_handshake_complete(long contextPtr) throws BadHandleException;
-
- private static native long create_context(boolean isClient);
-
- private static native byte[] get_next_handshake_message(long contextPtr) throws BadHandleException;
-
- private static native void parse_handshake_message(long contextPtr, byte[] message) throws BadHandleException, HandshakeException;
-
- private static native byte[] get_verification_string(long contextPtr, int length) throws BadHandleException, HandshakeException;
-
- private static native long to_connection_context(long contextPtr) throws HandshakeException;
-
- public D2DHandshakeContext(@Nonnull Role role) {
- this.contextPtr = create_context(role == Role.INITIATOR);
- }
-
- /**
- * Convenience constructor that creates a UKEY2 D2DHandshakeContext for the initiator role.
- *
- * @return a D2DHandshakeContext for the role of initiator in the handshake.
- */
- public static D2DHandshakeContext forInitiator() {
- return new D2DHandshakeContext(Role.INITIATOR);
- }
-
- /**
- * Convenience constructor that creates a UKEY2 D2DHandshakeContext for the initiator role.
- *
- * @return a D2DHandshakeContext for the role of responder/server in the handshake.
- */
- public static D2DHandshakeContext forResponder() {
- return new D2DHandshakeContext(Role.RESPONDER);
- }
-
- /**
- * Function that checks if the handshake is completed.
- *
- * @return true/false depending on if the handshake is complete.
- */
- public boolean isHandshakeComplete() throws BadHandleException {
- return is_handshake_complete(contextPtr);
- }
-
- /**
- * Gets the next handshake message in the exchange.
- *
- * @return handshake message encoded in a SecureMessage.
- */
- @Nonnull
- public byte[] getNextHandshakeMessage() throws BadHandleException {
- return get_next_handshake_message(contextPtr);
- }
-
- /**
- * Parses the handshake message.
- *
- * @param message - handshake message from the other side.
- */
- @Nonnull
- public void parseHandshakeMessage(@Nonnull byte[] message) throws BadHandleException, HandshakeException {
- parse_handshake_message(contextPtr, message);
- }
-
- /**
- * Returns an authentication string suitable for authenticating the handshake out-of-band. Note
- * that the authentication string can be short (e.g., a 6 digit visual confirmation code). Note:
- * this should only be called when {#isHandshakeComplete} returns true.
- * This code is analogous to the authentication string described in the spec.
- *
- * @param length - The length of the returned verification string.
- * @return - The returned verification string as a byte array.
- * @throws BadHandleException - Thrown if the handle is no longer valid, for example after calling {@link D2DHandshakeContext#toConnectionContext}
- * @throws HandshakeException - Thrown if the handshake is not complete when this function is called.
- */
- @Nonnull
- public byte[] getVerificationString(int length) throws BadHandleException, HandshakeException {
- return get_verification_string(contextPtr, length);
- }
-
- /**
- * Function to create a secure communication channel from the handshake after confirming the auth string generated by
- * the handshake out-of-band (i.e. via a user-facing UI).
- *
- * @return a new {@link D2DConnectionContextV1} with the next protocol specified when creating the D2DHandshakeContext.
- * @throws HandshakeException if the handsshake is not complete when this function is called.
- */
- public D2DConnectionContextV1 toConnectionContext() throws HandshakeException {
- return new D2DConnectionContextV1(to_connection_context(contextPtr));
- }
-}
diff --git a/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/BadHandleException.java b/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/ukey2/BadHandleException.java
index 2efd7c4..78f0e5e 100644
--- a/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/BadHandleException.java
+++ b/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/ukey2/BadHandleException.java
@@ -12,10 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.security.cryptauth.lib.securegcm;
+package com.google.security.cryptauth.lib.securegcm.ukey2;
/**
- * Represents an unrecoverable error (invalid handle) that has occurred during the handshake/connection.
+ * Represents an unrecoverable error (invalid handle) that has occurred during the
+ * handshake/connection.
*/
public class BadHandleException extends Exception {
public BadHandleException(String message) {
@@ -29,4 +30,4 @@ public class BadHandleException extends Exception {
public BadHandleException(String message, Exception e) {
super(message, e);
}
-} \ No newline at end of file
+}
diff --git a/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/CryptoException.java b/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/ukey2/CryptoException.java
index 6abeb53..11b5c9b 100644
--- a/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/CryptoException.java
+++ b/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/ukey2/CryptoException.java
@@ -12,11 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.security.cryptauth.lib.securegcm;
+package com.google.security.cryptauth.lib.securegcm.ukey2;
-/**
- * Represents an unrecoverable error that has occurred during the handshake procedure.
- */
+/** Represents an unrecoverable error that has occurred during the handshake procedure. */
public class CryptoException extends Exception {
public CryptoException(String message) {
super(message);
@@ -29,4 +27,4 @@ public class CryptoException extends Exception {
public CryptoException(String message, Exception e) {
super(message, e);
}
-} \ No newline at end of file
+}
diff --git a/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/ukey2/D2DConnectionContextV1.java b/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/ukey2/D2DConnectionContextV1.java
new file mode 100644
index 0000000..9ce2517
--- /dev/null
+++ b/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/ukey2/D2DConnectionContextV1.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.security.cryptauth.lib.securegcm.ukey2;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+public class D2DConnectionContextV1 {
+
+ static {
+ var path = System.getProperty("java.library.path");
+
+ if (path == null) {
+ throw new RuntimeException("Path isn't set.");
+ }
+
+ var paths = java.util.List.of(path.split(";"));
+ paths.forEach(System.out::println);
+
+ System.loadLibrary("ukey2_jni");
+ }
+
+ private static native byte[] encode_message_to_peer(
+ long contextPtr, byte[] payload, byte[] associatedData) throws BadHandleException;
+
+ private static native byte[] decode_message_from_peer(
+ long contextPtr, byte[] message, byte[] associatedData) throws CryptoException;
+
+ private static native byte[] get_session_unique(long contextPtr) throws BadHandleException;
+
+ private static native int get_sequence_number_for_encoding(long contextPtr)
+ throws BadHandleException;
+
+ private static native int get_sequence_number_for_decoding(long contextPtr)
+ throws BadHandleException;
+
+ private static native byte[] save_session(long contextPtr) throws BadHandleException;
+
+ private static native long from_saved_session(byte[] savedSessionInfo);
+
+ private final long contextPtr;
+
+ /**
+ * Java wrapper for D2DConnectionContextV1 to interact with the underlying Rust implementation
+ *
+ * @param contextPtr the handle to the Rust implementation.
+ */
+ D2DConnectionContextV1(@Nonnull long contextPtr) {
+ this.contextPtr = contextPtr;
+ }
+
+ /**
+ * Encode a message to the connection peer using session keys derived from the handshake.
+ *
+ * @param payload The message to be encrypted.
+ * @return The encrypted/encoded message.
+ */
+ @Nonnull
+ public byte[] encodeMessageToPeer(@Nonnull byte[] payload, @Nullable byte[] associatedData)
+ throws BadHandleException {
+ return encode_message_to_peer(contextPtr, payload, associatedData);
+ }
+
+ /**
+ * Decodes/decrypts a message from the connection peer.
+ *
+ * @param message The message received over the connection.
+ * @return The decoded message from the connection peer.
+ */
+ @Nonnull
+ public byte[] decodeMessageFromPeer(@Nonnull byte[] message, @Nullable byte[] associatedData)
+ throws CryptoException {
+ return decode_message_from_peer(contextPtr, message, associatedData);
+ }
+
+ /**
+ * A unique session identifier derived from session-specific information
+ *
+ * @return The session unique identifier
+ */
+ @Nonnull
+ public byte[] getSessionUnique() throws BadHandleException {
+ return get_session_unique(contextPtr);
+ }
+
+ /**
+ * Returns the encoding sequence number.
+ *
+ * @return the encoding sequence number.
+ */
+ public int getSequenceNumberForEncoding() throws BadHandleException {
+ return get_sequence_number_for_encoding(contextPtr);
+ }
+
+ /**
+ * Returns the decoding sequence number.
+ *
+ * @return the decoding sequence number.
+ */
+ public int getSequenceNumberForDecoding() throws BadHandleException {
+ return get_sequence_number_for_decoding(contextPtr);
+ }
+
+ /**
+ * Serializes the current session in a form usable by {@link
+ * D2DConnectionContextV1#fromSavedSession}
+ *
+ * @return a byte array representing the current session.
+ */
+ @Nonnull
+ public byte[] saveSession() throws BadHandleException {
+ return save_session(contextPtr);
+ }
+
+ /**
+ * Reconstructs and returns the session originally serialized by {@link
+ * D2DConnectionContextV1#saveSession}
+ *
+ * @param savedSessionInfo the byte array from saveSession()
+ * @return a D2DConnectionContextV1 session with the same properties as the context saved.
+ */
+ public static D2DConnectionContextV1 fromSavedSession(@Nonnull byte[] savedSessionInfo) {
+ return new D2DConnectionContextV1(from_saved_session(savedSessionInfo));
+ }
+}
diff --git a/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/ukey2/D2DHandshakeContext.java b/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/ukey2/D2DHandshakeContext.java
new file mode 100644
index 0000000..429295e
--- /dev/null
+++ b/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/ukey2/D2DHandshakeContext.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.security.cryptauth.lib.securegcm.ukey2;
+
+import javax.annotation.Nonnull;
+
+public class D2DHandshakeContext {
+ static {
+ System.loadLibrary("ukey2_jni");
+ }
+
+ public enum Role {
+ INITIATOR,
+ RESPONDER,
+ }
+
+ private final long contextPtr;
+
+ private static native boolean is_handshake_complete(long contextPtr) throws BadHandleException;
+
+ private static native long create_context(boolean isClient);
+
+ private static native byte[] get_next_handshake_message(long contextPtr)
+ throws BadHandleException;
+
+ private static native void parse_handshake_message(long contextPtr, byte[] message)
+ throws BadHandleException, HandshakeException;
+
+ private static native byte[] get_verification_string(long contextPtr, int length)
+ throws BadHandleException, HandshakeException;
+
+ private static native long to_connection_context(long contextPtr) throws HandshakeException;
+
+ public D2DHandshakeContext(@Nonnull Role role) {
+ this.contextPtr = create_context(role == Role.INITIATOR);
+ }
+
+ /**
+ * Convenience constructor that creates a UKEY2 D2DHandshakeContext for the initiator role.
+ *
+ * @return a D2DHandshakeContext for the role of initiator in the handshake.
+ */
+ public static D2DHandshakeContext forInitiator() {
+ return new D2DHandshakeContext(Role.INITIATOR);
+ }
+
+ /**
+ * Convenience constructor that creates a UKEY2 D2DHandshakeContext for the initiator role.
+ *
+ * @return a D2DHandshakeContext for the role of responder/server in the handshake.
+ */
+ public static D2DHandshakeContext forResponder() {
+ return new D2DHandshakeContext(Role.RESPONDER);
+ }
+
+ /**
+ * Function that checks if the handshake is completed.
+ *
+ * @return true/false depending on if the handshake is complete.
+ */
+ public boolean isHandshakeComplete() throws BadHandleException {
+ return is_handshake_complete(contextPtr);
+ }
+
+ /**
+ * Gets the next handshake message in the exchange.
+ *
+ * @return handshake message encoded in a SecureMessage.
+ */
+ @Nonnull
+ public byte[] getNextHandshakeMessage() throws BadHandleException {
+ return get_next_handshake_message(contextPtr);
+ }
+
+ /**
+ * Parses the handshake message.
+ *
+ * @param message - handshake message from the other side.
+ */
+ @Nonnull
+ public void parseHandshakeMessage(@Nonnull byte[] message)
+ throws BadHandleException, HandshakeException {
+ parse_handshake_message(contextPtr, message);
+ }
+
+ /**
+ * Returns an authentication string suitable for authenticating the handshake out-of-band. Note
+ * that the authentication string can be short (e.g., a 6 digit visual confirmation code). Note:
+ * this should only be called when {#isHandshakeComplete} returns true. This code is analogous to
+ * the authentication string described in the spec.
+ *
+ * @param length - The length of the returned verification string.
+ * @return - The returned verification string as a byte array.
+ * @throws BadHandleException - Thrown if the handle is no longer valid, for example after calling
+ * {@link D2DHandshakeContext#toConnectionContext}
+ * @throws HandshakeException - Thrown if the handshake is not complete when this function is
+ * called.
+ */
+ @Nonnull
+ public byte[] getVerificationString(int length) throws BadHandleException, HandshakeException {
+ return get_verification_string(contextPtr, length);
+ }
+
+ /**
+ * Function to create a secure communication channel from the handshake after confirming the auth
+ * string generated by the handshake out-of-band (i.e. via a user-facing UI).
+ *
+ * @return a new {@link D2DConnectionContextV1} with the next protocol specified when creating the
+ * D2DHandshakeContext.
+ * @throws HandshakeException if the handsshake is not complete when this function is called.
+ */
+ public D2DConnectionContextV1 toConnectionContext() throws HandshakeException {
+ return new D2DConnectionContextV1(to_connection_context(contextPtr));
+ }
+}
diff --git a/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/HandshakeException.java b/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/ukey2/HandshakeException.java
index 17928e9..20d3112 100644
--- a/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/HandshakeException.java
+++ b/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/ukey2/HandshakeException.java
@@ -12,21 +12,19 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.security.cryptauth.lib.securegcm;
+package com.google.security.cryptauth.lib.securegcm.ukey2;
-/**
- * Represents an unrecoverable error that has occurred during the handshake procedure.
- */
+/** Represents an unrecoverable error that has occurred during the handshake procedure. */
public class HandshakeException extends Exception {
- public HandshakeException(String message) {
- super(message);
- }
+ public HandshakeException(String message) {
+ super(message);
+ }
- public HandshakeException(Exception e) {
- super(e);
- }
+ public HandshakeException(Exception e) {
+ super(e);
+ }
- public HandshakeException(String message, Exception e) {
- super(message, e);
- }
-} \ No newline at end of file
+ public HandshakeException(String message, Exception e) {
+ super(message, e);
+ }
+}
diff --git a/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/SessionRestoreException.java b/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/ukey2/SessionRestoreException.java
index c780973..026f8c5 100644
--- a/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/SessionRestoreException.java
+++ b/nearby/connections/ukey2/ukey2_jni/java/src/main/java/com/google/security/cryptauth/lib/securegcm/ukey2/SessionRestoreException.java
@@ -12,11 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.security.cryptauth.lib.securegcm;
+package com.google.security.cryptauth.lib.securegcm.ukey2;
-/**
- * Represents an unrecoverable error that has occurred during the handshake procedure.
- */
+/** Represents an unrecoverable error that has occurred during the handshake procedure. */
public class SessionRestoreException extends Exception {
public SessionRestoreException(String message) {
super(message);
@@ -29,4 +27,4 @@ public class SessionRestoreException extends Exception {
public SessionRestoreException(String message, Exception e) {
super(message, e);
}
-} \ No newline at end of file
+}
diff --git a/nearby/connections/ukey2/ukey2_jni/java/src/test/java/com/google/security/cryptauth/lib/securegcm/TestUkey2Protocol.kt b/nearby/connections/ukey2/ukey2_jni/java/src/test/java/com/google/security/cryptauth/lib/securegcm/TestUkey2Protocol.kt
deleted file mode 100644
index 79cbd15..0000000
--- a/nearby/connections/ukey2/ukey2_jni/java/src/test/java/com/google/security/cryptauth/lib/securegcm/TestUkey2Protocol.kt
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright 2023 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * This Java source file was generated by the Gradle 'init' task.
- */
-package com.google.security.cryptauth.lib.securegcm
-
-import java.nio.charset.StandardCharsets
-import org.junit.jupiter.api.Assertions.assertArrayEquals
-import org.junit.jupiter.api.Assertions.assertEquals
-import org.junit.jupiter.api.Assertions.assertFalse
-import org.junit.jupiter.api.Assertions.assertNotEquals
-import org.junit.jupiter.api.Assertions.assertTrue
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.assertDoesNotThrow
-import org.junit.jupiter.api.assertThrows
-
-// Driver code
-// Tests exception handling and the handshake routine, as well as encrypting/decrypting short message between the server and initiator contexts.
-@Suppress("UNUSED_VARIABLE")
-class TestUkey2Protocol {
- @Test
- fun testHandshake() {
- val initiatorContext =
- D2DHandshakeContext(D2DHandshakeContext.Role.INITIATOR)
- assertFalse(initiatorContext.isHandshakeComplete)
- val serverContext =
- D2DHandshakeContext(D2DHandshakeContext.Role.RESPONDER)
- assertFalse(serverContext.isHandshakeComplete)
- assertDoesNotThrow {
- serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage)
- initiatorContext.parseHandshakeMessage(serverContext.nextHandshakeMessage)
- serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage)
- assertTrue(initiatorContext.isHandshakeComplete)
- assertTrue(serverContext.isHandshakeComplete)
- }
- }
-
- @Test
- fun testSendReceiveMessage() {
- val initiatorContext =
- D2DHandshakeContext(D2DHandshakeContext.Role.INITIATOR)
- val serverContext =
- D2DHandshakeContext(D2DHandshakeContext.Role.RESPONDER)
- assertDoesNotThrow {
- serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage)
- initiatorContext.parseHandshakeMessage(serverContext.nextHandshakeMessage)
- serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage)
- val connContext = initiatorContext.toConnectionContext()
- val serverConnContext = serverContext.toConnectionContext()
- val initialShareString = "Nearby sharing to server"
- val encoded = connContext.encodeMessageToPeer(
- initialShareString.toByteArray(
- StandardCharsets.UTF_8
- ), null
- )
- val response =
- String(serverConnContext.decodeMessageFromPeer(encoded, null), StandardCharsets.UTF_8)
- assertEquals(response, initialShareString)
- }
- }
-
- @Test
- fun testSaveRestoreSession() {
- val initiatorContext =
- D2DHandshakeContext(D2DHandshakeContext.Role.INITIATOR)
- val serverContext =
- D2DHandshakeContext(D2DHandshakeContext.Role.RESPONDER)
- assertDoesNotThrow {
- serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage)
- initiatorContext.parseHandshakeMessage(serverContext.nextHandshakeMessage)
- serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage)
- val connContext = initiatorContext.toConnectionContext()
- val serverConnContext = serverContext.toConnectionContext()
- val initiatorSavedSession = connContext.saveSession()
- val restored = D2DConnectionContextV1.fromSavedSession(initiatorSavedSession)
- assertArrayEquals(connContext.sessionUnique, restored.sessionUnique)
- val initialShareString = "Nearby sharing to server"
- val encoded = serverConnContext.encodeMessageToPeer(
- initialShareString.toByteArray(
- StandardCharsets.UTF_8
- ), null
- )
- val response = String(restored.decodeMessageFromPeer(encoded, null), StandardCharsets.UTF_8)
- assertEquals(response, initialShareString)
- }
- }
-
- @Test
- fun testSaveRestoreBadSession() {
- val initiatorContext =
- D2DHandshakeContext(D2DHandshakeContext.Role.INITIATOR)
- val serverContext =
- D2DHandshakeContext(D2DHandshakeContext.Role.RESPONDER)
- val deriveInitiatorSavedSession = {
- assertDoesNotThrow {
- serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage)
- initiatorContext.parseHandshakeMessage(serverContext.nextHandshakeMessage)
- serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage)
- val connContext = initiatorContext.toConnectionContext()
- val serverConnContext = serverContext.toConnectionContext()
- connContext.saveSession()
- }
- }
- assertThrows<SessionRestoreException> {
- val unused = D2DConnectionContextV1.fromSavedSession(deriveInitiatorSavedSession().copyOfRange(0, 20))
- }
- }
-
- @Test
- fun tryReuseHandshakeContext() {
- val initiatorContext =
- D2DHandshakeContext(D2DHandshakeContext.Role.INITIATOR)
- val serverContext =
- D2DHandshakeContext(D2DHandshakeContext.Role.RESPONDER)
- assertDoesNotThrow {
- serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage)
- initiatorContext.parseHandshakeMessage(serverContext.nextHandshakeMessage)
- serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage)
- val connContext = initiatorContext.toConnectionContext()
- val serverConnContext = serverContext.toConnectionContext()
- }
- assertThrows<BadHandleException> {
- val unused = serverContext.nextHandshakeMessage
- }
- }
-
- @Test
- fun testSendReceiveMessageWithAssociatedData() {
- val initiatorContext =
- D2DHandshakeContext(D2DHandshakeContext.Role.INITIATOR)
- val serverContext =
- D2DHandshakeContext(D2DHandshakeContext.Role.RESPONDER)
- val associatedData = "Associated data.".toByteArray()
- assertDoesNotThrow {
- serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage)
- initiatorContext.parseHandshakeMessage(serverContext.nextHandshakeMessage)
- serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage)
- val connContext = initiatorContext.toConnectionContext()
- val serverConnContext = serverContext.toConnectionContext()
- val initialShareString = "Nearby sharing to server"
- val encoded = connContext.encodeMessageToPeer(
- initialShareString.toByteArray(
- StandardCharsets.UTF_8
- ), associatedData
- )
- val response =
- String(serverConnContext.decodeMessageFromPeer(encoded, associatedData), StandardCharsets.UTF_8)
- assertEquals(response, initialShareString)
- }
- }
-
- @Test
- fun testVerificationString() {
- val initiatorContext =
- D2DHandshakeContext(D2DHandshakeContext.Role.INITIATOR)
- val serverContext =
- D2DHandshakeContext(D2DHandshakeContext.Role.RESPONDER)
- assertDoesNotThrow {
- serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage)
- initiatorContext.parseHandshakeMessage(serverContext.nextHandshakeMessage)
- serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage)
- }
- assert(serverContext.isHandshakeComplete)
- assert(initiatorContext.isHandshakeComplete)
- assertArrayEquals(serverContext.getVerificationString(32), initiatorContext.getVerificationString(32))
- }
-} \ No newline at end of file
diff --git a/nearby/connections/ukey2/ukey2_jni/java/src/test/java/com/google/security/cryptauth/lib/securegcm/ukey2/TestUkey2Protocol.kt b/nearby/connections/ukey2/ukey2_jni/java/src/test/java/com/google/security/cryptauth/lib/securegcm/ukey2/TestUkey2Protocol.kt
new file mode 100644
index 0000000..f770977
--- /dev/null
+++ b/nearby/connections/ukey2/ukey2_jni/java/src/test/java/com/google/security/cryptauth/lib/securegcm/ukey2/TestUkey2Protocol.kt
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This Java source file was generated by the Gradle 'init' task.
+ */
+package com.google.security.cryptauth.lib.securegcm.ukey2
+
+import java.nio.charset.StandardCharsets
+import org.junit.jupiter.api.Assertions.assertArrayEquals
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.Assertions.assertFalse
+import org.junit.jupiter.api.Assertions.assertTrue
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.assertDoesNotThrow
+import org.junit.jupiter.api.assertThrows
+
+// Driver code
+// Tests exception handling and the handshake routine, as well as encrypting/decrypting short
+// message between the server and initiator contexts.
+@Suppress("UNUSED_VARIABLE")
+class TestUkey2Protocol {
+ @Test
+ fun testHandshake() {
+ val initiatorContext = D2DHandshakeContext(D2DHandshakeContext.Role.INITIATOR)
+ println("got initial context")
+ assertFalse(initiatorContext.isHandshakeComplete)
+ val serverContext = D2DHandshakeContext(D2DHandshakeContext.Role.RESPONDER)
+ assertFalse(serverContext.isHandshakeComplete)
+ assertDoesNotThrow {
+ serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage)
+ initiatorContext.parseHandshakeMessage(serverContext.nextHandshakeMessage)
+ serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage)
+ assertTrue(initiatorContext.isHandshakeComplete)
+ assertTrue(serverContext.isHandshakeComplete)
+ }
+ }
+
+ @Test
+ fun testSendReceiveMessage() {
+ val initiatorContext = D2DHandshakeContext(D2DHandshakeContext.Role.INITIATOR)
+ val serverContext = D2DHandshakeContext(D2DHandshakeContext.Role.RESPONDER)
+ assertDoesNotThrow {
+ serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage)
+ initiatorContext.parseHandshakeMessage(serverContext.nextHandshakeMessage)
+ serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage)
+ val connContext = initiatorContext.toConnectionContext()
+ val serverConnContext = serverContext.toConnectionContext()
+ val initialShareString = "Nearby sharing to server"
+ val encoded =
+ connContext.encodeMessageToPeer(
+ initialShareString.toByteArray(StandardCharsets.UTF_8), null)
+ val response =
+ String(serverConnContext.decodeMessageFromPeer(encoded, null), StandardCharsets.UTF_8)
+ assertEquals(response, initialShareString)
+ }
+ }
+
+ @Test
+ fun testSaveRestoreSession() {
+ val initiatorContext = D2DHandshakeContext(D2DHandshakeContext.Role.INITIATOR)
+ val serverContext = D2DHandshakeContext(D2DHandshakeContext.Role.RESPONDER)
+ assertDoesNotThrow {
+ serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage)
+ initiatorContext.parseHandshakeMessage(serverContext.nextHandshakeMessage)
+ serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage)
+ val connContext = initiatorContext.toConnectionContext()
+ val serverConnContext = serverContext.toConnectionContext()
+ val initiatorSavedSession = connContext.saveSession()
+ val restored = D2DConnectionContextV1.fromSavedSession(initiatorSavedSession)
+ assertArrayEquals(connContext.sessionUnique, restored.sessionUnique)
+ val initialShareString = "Nearby sharing to server"
+ val encoded =
+ serverConnContext.encodeMessageToPeer(
+ initialShareString.toByteArray(StandardCharsets.UTF_8), null)
+ val response = String(restored.decodeMessageFromPeer(encoded, null), StandardCharsets.UTF_8)
+ assertEquals(response, initialShareString)
+ }
+ }
+
+ @Test
+ fun testSaveRestoreBadSession() {
+ val initiatorContext = D2DHandshakeContext(D2DHandshakeContext.Role.INITIATOR)
+ val serverContext = D2DHandshakeContext(D2DHandshakeContext.Role.RESPONDER)
+ val deriveInitiatorSavedSession = {
+ assertDoesNotThrow {
+ serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage)
+ initiatorContext.parseHandshakeMessage(serverContext.nextHandshakeMessage)
+ serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage)
+ val connContext = initiatorContext.toConnectionContext()
+ val serverConnContext = serverContext.toConnectionContext()
+ connContext.saveSession()
+ }
+ }
+ assertThrows<SessionRestoreException> {
+ val unused =
+ D2DConnectionContextV1.fromSavedSession(deriveInitiatorSavedSession().copyOfRange(0, 20))
+ }
+ }
+
+ @Test
+ fun tryReuseHandshakeContext() {
+ val initiatorContext = D2DHandshakeContext(D2DHandshakeContext.Role.INITIATOR)
+ val serverContext = D2DHandshakeContext(D2DHandshakeContext.Role.RESPONDER)
+ assertDoesNotThrow {
+ serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage)
+ initiatorContext.parseHandshakeMessage(serverContext.nextHandshakeMessage)
+ serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage)
+ val connContext = initiatorContext.toConnectionContext()
+ val serverConnContext = serverContext.toConnectionContext()
+ }
+ assertThrows<BadHandleException> {
+ val unused = serverContext.nextHandshakeMessage
+ }
+ }
+
+ @Test
+ fun testSendReceiveMessageWithAssociatedData() {
+ val initiatorContext = D2DHandshakeContext(D2DHandshakeContext.Role.INITIATOR)
+ val serverContext = D2DHandshakeContext(D2DHandshakeContext.Role.RESPONDER)
+ val associatedData = "Associated data.".toByteArray()
+ assertDoesNotThrow {
+ serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage)
+ initiatorContext.parseHandshakeMessage(serverContext.nextHandshakeMessage)
+ serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage)
+ val connContext = initiatorContext.toConnectionContext()
+ val serverConnContext = serverContext.toConnectionContext()
+ val initialShareString = "Nearby sharing to server"
+ val encoded =
+ connContext.encodeMessageToPeer(
+ initialShareString.toByteArray(StandardCharsets.UTF_8), associatedData)
+ val response =
+ String(
+ serverConnContext.decodeMessageFromPeer(encoded, associatedData),
+ StandardCharsets.UTF_8)
+ assertEquals(response, initialShareString)
+ }
+ }
+
+ @Test
+ fun testVerificationString() {
+ val initiatorContext = D2DHandshakeContext(D2DHandshakeContext.Role.INITIATOR)
+ val serverContext = D2DHandshakeContext(D2DHandshakeContext.Role.RESPONDER)
+ assertDoesNotThrow {
+ serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage)
+ initiatorContext.parseHandshakeMessage(serverContext.nextHandshakeMessage)
+ serverContext.parseHandshakeMessage(initiatorContext.nextHandshakeMessage)
+ }
+ assert(serverContext.isHandshakeComplete)
+ assert(initiatorContext.isHandshakeComplete)
+ assertArrayEquals(
+ serverContext.getVerificationString(32), initiatorContext.getVerificationString(32))
+ }
+}