diff options
author | Erin Yan <yiranyan@google.com> | 2020-11-05 10:37:43 -0800 |
---|---|---|
committer | Erin Yan <yiranyan@google.com> | 2020-11-09 10:04:38 -0800 |
commit | 1182deea1e4656a8cda0da2da1f3898e777c573c (patch) | |
tree | 1dc34eee126c3e4d9384526199eb4650fc04ad17 | |
parent | d0f5ee5f7446e510636f03a2f3cbe1fe7128f552 (diff) | |
download | ukey2-1182deea1e4656a8cda0da2da1f3898e777c573c.tar.gz |
Update ukey2
This update is being pulled in from github https://github.com/google/ukey2
This update only includes java lib
Bug: 172576615
Test: Build
Change-Id: I7ee4375b7ed3c3908ec6672f529a88aa6080efb9
30 files changed, 576 insertions, 1053 deletions
@@ -1,3 +1,6 @@ build/** .gradle/** +.idea/** +.gitignore +.gitmodules @@ -3,7 +3,9 @@ This is not an officially supported Google product **Coathored by:** Alexei Czeskis, Thai Duong, Eduardo' Vela'' \<Nava\>, and Adam Stubblefield. -**Status:** Implemented in Java (aczeskis@google.com) +**Status:** +Implemented in Java by Alexei Czeskis (aczeskis@google.com) +Ported from Java to C++ by Tim Song (tengs@google.com) **Design reviewers:** Thai Duong, Bruno Blanchet, Martin Abadi, and Bo Wang @@ -327,3 +329,64 @@ size of the messages were: |`ClientFinished`| 79 | +# Checking out source code + +``` +git clone https://github.com/google/ukey2 +cd ukey2 +git submodule update --init --recursive +``` + +# Building and tesging C++ code + +## Build +``` +cd <source root> +mkdir build; cd build +cmake -Dukey2_USE_LOCAL_PROTOBUF=ON -Dukey2_USE_LOCAL_ABSL=ON .. +make +``` +## Running C++ tests +``` +cd <source root>/build +ctest -V +``` + +# Buillding Java library and running Java Tests + +NOTE: c++ build must be completed as described above, before running java tests. +This requirement exists because Java build runs a c++/java compatibility test, and +this test depends on c++ test helper binary (found in build/src/main/cpp/test/securegcm/ukey2_test). +Gradle build does not know how to build this artifact. Java test uses a relative +path to the artifact, and expects tests to be run from <source root> as follows: + +Pre-reqs: gradle + +1. Create gradle wrapper for a specific gradle version. +This project was built with Gradle-6.1.1. +If you have an incompatible version of gradle it is recommended that +you setup gradle wrapper first. +1.1. The simplest is to run +``` +cd <source root> +gradle wrapper --gradle-version=6.1.1 + +``` + +1.2. If this fails, this is likely because current gradle version is unable to parse the build.gradle +file. In this case, create an empty directory outside your project tree, and create a wrapper there. +``` +mkdir -p $HOME/scratch/gradle-wrapper-611 +cd $HOME/scratch/gradle-wrapper-611 +gradle wrapper --gradle-version=6.1.1 +cp -a gradle gradlew gradlew.bat <source root> +``` + +2. Once you get gradle wrapper installed, run test command + +``` +cd <source root> +./gradlew test -i +``` + +This will build and execute all the tests. diff --git a/build.gradle b/build.gradle index bb46e75..8989eb0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,23 +1,35 @@ +// Copyright 2020 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 +// +// https://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. + apply plugin: 'java' apply plugin: 'com.google.protobuf' repositories { - jcenter() + mavenCentral() } buildscript { repositories { - jcenter() + mavenCentral() } dependencies { - classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.7' + classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.12' } } dependencies { - compile "com.google.code.findbugs:jsr305:3.0.0" - compile "com.google.protobuf:protobuf-java:3.4.0" - compile "com.google.guava:guava:r05" + implementation "com.google.code.findbugs:jsr305:3.0.0" + implementation "com.google.protobuf:protobuf-java:3.8.0" + implementation "com.google.guava:guava:19.0" } - - diff --git a/src/.gradle/3.2.1/taskArtifacts/fileSnapshots.bin b/src/.gradle/3.2.1/taskArtifacts/fileSnapshots.bin Binary files differdeleted file mode 100644 index f0cc1a8..0000000 --- a/src/.gradle/3.2.1/taskArtifacts/fileSnapshots.bin +++ /dev/null diff --git a/src/.gradle/3.2.1/taskArtifacts/taskArtifacts.bin b/src/.gradle/3.2.1/taskArtifacts/taskArtifacts.bin Binary files differdeleted file mode 100644 index b1f5426..0000000 --- a/src/.gradle/3.2.1/taskArtifacts/taskArtifacts.bin +++ /dev/null diff --git a/src/.gradle/3.2.1/taskArtifacts/taskArtifacts.lock b/src/.gradle/3.2.1/taskArtifacts/taskArtifacts.lock Binary files differdeleted file mode 100644 index 6fa2a90..0000000 --- a/src/.gradle/3.2.1/taskArtifacts/taskArtifacts.lock +++ /dev/null diff --git a/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DConnectionContext.java b/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DConnectionContext.java index 09023a5..fb4af63 100644 --- a/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DConnectionContext.java +++ b/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DConnectionContext.java @@ -1,17 +1,17 @@ -/* Copyright 2018 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 - * - * https://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. - */ +// Copyright 2020 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 +// +// https://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 com.google.common.annotations.VisibleForTesting; diff --git a/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DConnectionContextV0.java b/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DConnectionContextV0.java index 92aa02d..d0efa44 100644 --- a/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DConnectionContextV0.java +++ b/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DConnectionContextV0.java @@ -1,17 +1,17 @@ -/* Copyright 2018 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 - * - * https://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. - */ +// Copyright 2020 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 +// +// https://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 java.io.ByteArrayOutputStream; diff --git a/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DConnectionContextV1.java b/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DConnectionContextV1.java index 4b5fb5e..1566849 100644 --- a/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DConnectionContextV1.java +++ b/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DConnectionContextV1.java @@ -1,17 +1,17 @@ -/* Copyright 2018 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 - * - * https://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. - */ +// Copyright 2020 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 +// +// https://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 java.io.ByteArrayOutputStream; diff --git a/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DCryptoOps.java b/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DCryptoOps.java index 48dc52f..a7203d1 100644 --- a/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DCryptoOps.java +++ b/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DCryptoOps.java @@ -1,17 +1,17 @@ -/* Copyright 2018 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 - * - * https://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. - */ +// Copyright 2020 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 +// +// https://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 com.google.common.annotations.VisibleForTesting; @@ -55,6 +55,11 @@ class D2DCryptoOps { (byte) 0x6D, (byte) 0xA8, (byte) 0x55, (byte) 0x10 }; + // Data passed to hkdf to create the key used by the initiator to encode messages. + static final String INITIATOR_PURPOSE = "initiator"; + // Data passed to hkdf to create the key used by the responder to encode messages. + static final String RESPONDER_PURPOSE = "responder"; + // Don't instantiate private D2DCryptoOps() { } @@ -196,7 +201,7 @@ class D2DCryptoOps { /** * Used to derive a distinct key for each initiator and responder. - * + * * @param masterKey the source key used to derive the new key. * @param purpose a string to make the new key different for each purpose. * @return the derived {@link SecretKey}. diff --git a/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DDiffieHellmanKeyExchangeHandshake.java b/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DDiffieHellmanKeyExchangeHandshake.java index ae43d90..f929a3a 100644 --- a/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DDiffieHellmanKeyExchangeHandshake.java +++ b/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DDiffieHellmanKeyExchangeHandshake.java @@ -1,17 +1,17 @@ -/* Copyright 2018 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 - * - * https://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. - */ +// Copyright 2020 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 +// +// https://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 com.google.protobuf.InvalidProtocolBufferException; @@ -64,11 +64,6 @@ import javax.crypto.SecretKey; * </pre> */ public class D2DDiffieHellmanKeyExchangeHandshake implements D2DHandshakeContext { - // Data passed to hkdf to create the key used by the initiator to encode messages. - private static final String INITIATOR_PURPOSE = "initiator"; - // Data passed to hkdf to create the key used by the responder to encode messages. - private static final String RESPONDER_PURPOSE = "responder"; - private KeyPair ourKeyPair; private PublicKey theirPublicKey; private SecretKey initiatorEncodeKey; @@ -176,8 +171,10 @@ public class D2DDiffieHellmanKeyExchangeHandshake implements D2DHandshakeContext responderEncodeKey = masterKey; break; case D2DConnectionContextV1.PROTOCOL_VERSION: - initiatorEncodeKey = D2DCryptoOps.deriveNewKeyForPurpose(masterKey, INITIATOR_PURPOSE); - responderEncodeKey = D2DCryptoOps.deriveNewKeyForPurpose(masterKey, RESPONDER_PURPOSE); + initiatorEncodeKey = D2DCryptoOps.deriveNewKeyForPurpose(masterKey, + D2DCryptoOps.INITIATOR_PURPOSE); + responderEncodeKey = D2DCryptoOps.deriveNewKeyForPurpose(masterKey, + D2DCryptoOps.RESPONDER_PURPOSE); break; default: throw new IllegalStateException("Unexpected protocol version: " + protocolVersionToUse); @@ -238,8 +235,10 @@ public class D2DDiffieHellmanKeyExchangeHandshake implements D2DHandshakeContext initiatorEncodeKey = masterKey; responderEncodeKey = masterKey; } else { - initiatorEncodeKey = D2DCryptoOps.deriveNewKeyForPurpose(masterKey, INITIATOR_PURPOSE); - responderEncodeKey = D2DCryptoOps.deriveNewKeyForPurpose(masterKey, RESPONDER_PURPOSE); + initiatorEncodeKey = D2DCryptoOps.deriveNewKeyForPurpose(masterKey, + D2DCryptoOps.INITIATOR_PURPOSE); + responderEncodeKey = D2DCryptoOps.deriveNewKeyForPurpose(masterKey, + D2DCryptoOps.RESPONDER_PURPOSE); } DeviceToDeviceMessage message = diff --git a/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DHandshakeContext.java b/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DHandshakeContext.java index 8c35d22..5fc1d7b 100644 --- a/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DHandshakeContext.java +++ b/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DHandshakeContext.java @@ -1,17 +1,17 @@ -/* Copyright 2018 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 - * - * https://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. - */ +// Copyright 2020 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 +// +// https://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; /** diff --git a/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DSpakeEd25519Handshake.java b/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DSpakeEd25519Handshake.java deleted file mode 100644 index da5abf1..0000000 --- a/src/main/java/com/google/security/cryptauth/lib/securegcm/D2DSpakeEd25519Handshake.java +++ /dev/null @@ -1,648 +0,0 @@ -/* Copyright 2018 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 - * - * https://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 com.google.common.annotations.VisibleForTesting; -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.security.cryptauth.lib.securegcm.DeviceToDeviceMessagesProto.DeviceToDeviceMessage; -import com.google.security.cryptauth.lib.securegcm.DeviceToDeviceMessagesProto.EcPoint; -import com.google.security.cryptauth.lib.securegcm.DeviceToDeviceMessagesProto.SpakeHandshakeMessage; -import com.google.security.cryptauth.lib.securegcm.Ed25519.Ed25519Exception; -import com.google.security.cryptauth.lib.securegcm.TransportCryptoOps.Payload; -import com.google.security.cryptauth.lib.securegcm.TransportCryptoOps.PayloadType; -import java.math.BigInteger; -import java.security.InvalidKeyException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.security.SignatureException; -import javax.crypto.spec.SecretKeySpec; - -/** - * Implements a {@link D2DHandshakeContext} by using SPAKE2 (Simple Password-Based Encrypted Key - * Exchange Protocol) on top of the Ed25519 curve. - * SPAKE2: http://www.di.ens.fr/~mabdalla/papers/AbPo05a-letter.pdf - * Ed25519: http://ed25519.cr.yp.to/ - * - * <p>Usage: - * {@code - * // initiator: - * D2DHandshakeContext initiatorHandshakeContext = - * D2DSpakeEd25519Handshake.forInitiator(PASSWORD); - * byte[] initiatorMsg = initiatorHandshakeContext.getNextHandshakeMessage(); - * // (send initiatorMsg to responder) - * - * // responder: - * D2DHandshakeContext responderHandshakeContext = - * D2DSpakeEd25519Handshake.forResponder(PASSWORD); - * responderHandshakeContext.parseHandshakeMessage(initiatorMsg); - * byte[] responderMsg = responderHandshakeContext.getNextHandshakeMessage(); - * // (send responderMsg to initiator) - * - * // initiator: - * initiatorHandshakeContext.parseHandshakeMessage(responderMsg); - * initiatorMsg = initiatorHandshakeContext.getNextHandshakeMessage(); - * // (send initiatorMsg to responder) - * - * // responder: - * responderHandshakeContext.parseHandshakeMessage(initiatorMsg); - * responderMsg = responderHandshakeContext.getNextHandshakeMessage(); - * D2DConnectionContext responderCtx = responderHandshakeContext.toConnectionContext(); - * // (send responderMsg to initiator) - * - * // initiator: - * initiatorHandshakeContext.parseHandshakeMessage(responderMsg); - * D2DConnectionContext initiatorCtx = initiatorHandshakeContext.toConnectionContext(); - * } - * - * <p>The initial computation is: - * Initiator Responder - * has KM (pre-agreed point) has KM (pre-agreed point) - * has KN (pre-agreed point) has KN (pre-agreed point) - * has Password (pre-agreed) has Password (pre-agreed) - * picks random scalar Xi (private key) picks random scalar Xr (private key) - * computes the public key Pxi = G*Xi computes the public key Pxr = G*Xr - * computes commitment: computes commitment: - * Ci = KM * password + Pxi Cr = KN * password + Pxr - * - * <p>The flow is: - * Initiator Responder - * ----- Ci ---------------------------------> - * <--------------------------------- Cr ----- - * computes shared key K: computes shared key K: - * (Cr - KN*password) * Xi (Ci - KM*password) * Xr - * computes hash: computes hash: - * Hi = sha256(0|Cr|Ci|K) Hr = sha256(1|Ci|Cr|K) - * ----- Hi ---------------------------------> - * Verify Hi - * <-------------- Hr (optional payload) ----- - * Verify Hr - */ -public class D2DSpakeEd25519Handshake implements D2DHandshakeContext { - // Minimum length password that is acceptable for the handshake - public static final int MIN_PASSWORD_LENGTH = 4; - /** - * Creates a new SPAKE handshake object for the initiator. - * - * @param password the password that should be used in the handshake. Note that this should be - * at least {@value #MIN_PASSWORD_LENGTH} bytes long - */ - public static D2DSpakeEd25519Handshake forInitiator(byte[] password) throws HandshakeException { - return new D2DSpakeEd25519Handshake(State.INITIATOR_START, password); - } - - /** - * Creates a new SPAKE handshake object for the responder. - * - * @param password the password that should be used in the handshake. Note that this should be - * at least {@value #MIN_PASSWORD_LENGTH} bytes long - */ - public static D2DSpakeEd25519Handshake forResponder(byte[] password) throws HandshakeException { - return new D2DSpakeEd25519Handshake(State.RESPONDER_START, password); - } - - // - // The protocol requires two verifiable, randomly generated group point. They were generated - // using the python code below. The algorithm is to first pick a random y in the group and solve - // the elliptic curve equation for a value of x, if possible. We then use (x, y) as the random - // point. - // Source of ed25519 is here: http://ed25519.cr.yp.to/python/ed25519.py - // import ed25519 - // import hashlib - // - // # Seeds - // seed1 = 'D2D Ed25519 point generation seed (M)' - // seed2 = 'D2D Ed25519 point generation seed (N)' - // - // def find_seed(seed): - // # generate a random scalar for the y coordinate - // y = hashlib.sha256(seed).hexdigest() - // - // P = ed25519.scalarmult(ed25519.B, int(y, 16) % ed25519.q) - // if (not ed25519.isoncurve(P)): - // print 'Wat? P should be on curve!' - // - // print ' x: ' + hex(P[0]) - // print ' y: ' + hex(P[1]) - // print - // - // find_seed(seed1) - // find_seed(seed2) - // - // Output is: - // x: 0x1981fb43f103290ecf9772022db8b19bfaf389057ed91e8486eb368763435925L - // y: 0xa714c34f3b588aac92fd2587884a20964fd351a1f147d5c4bbf5c2f37a77c36L - // - // x: 0x201a184f47d9a7973891d148e3d1c864d8084547131c2c1cefb7eebd26c63567L - // y: 0x6da2d3b18ec4f9aa3b08e39c997cd8bf6e9948ffd4feffecaf8dd0b3d648b7e8L - // - // To get extended representation X, Y, Z, T, do: Z = 1, T = X*Y mod P - @VisibleForTesting - static final BigInteger[] KM = new BigInteger[] { - new BigInteger(new byte[] {(byte) 0x19, (byte) 0x81, (byte) 0xFB, (byte) 0x43, - (byte) 0xF1, (byte) 0x03, (byte) 0x29, (byte) 0x0E, (byte) 0xCF, (byte) 0x97, - (byte) 0x72, (byte) 0x02, (byte) 0x2D, (byte) 0xB8, (byte) 0xB1, (byte) 0x9B, - (byte) 0xFA, (byte) 0xF3, (byte) 0x89, (byte) 0x05, (byte) 0x7E, (byte) 0xD9, - (byte) 0x1E, (byte) 0x84, (byte) 0x86, (byte) 0xEB, (byte) 0x36, (byte) 0x87, - (byte) 0x63, (byte) 0x43, (byte) 0x59, (byte) 0x25}), - new BigInteger(new byte[] {(byte) 0x0A, (byte) 0x71, (byte) 0x4C, (byte) 0x34, - (byte) 0xF3, (byte) 0xB5, (byte) 0x88, (byte) 0xAA, (byte) 0xC9, (byte) 0x2F, - (byte) 0xD2, (byte) 0x58, (byte) 0x78, (byte) 0x84, (byte) 0xA2, (byte) 0x09, - (byte) 0x64, (byte) 0xFD, (byte) 0x35, (byte) 0x1A, (byte) 0x1F, (byte) 0x14, - (byte) 0x7D, (byte) 0x5C, (byte) 0x4B, (byte) 0xBF, (byte) 0x5C, (byte) 0x2F, - (byte) 0x37, (byte) 0xA7, (byte) 0x7C, (byte) 0x36}), - BigInteger.ONE, - new BigInteger(new byte[] {(byte) 0x04, (byte) 0x8F, (byte) 0xC1, (byte) 0xCE, - (byte) 0xE5, (byte) 0x83, (byte) 0x99, (byte) 0x25, (byte) 0xE5, (byte) 0x9B, - (byte) 0x80, (byte) 0xEA, (byte) 0xAD, (byte) 0x82, (byte) 0xAC, (byte) 0x0A, - (byte) 0x3C, (byte) 0xFE, (byte) 0xC5, (byte) 0x60, (byte) 0x93, (byte) 0x59, - (byte) 0x8B, (byte) 0x48, (byte) 0x44, (byte) 0xDD, (byte) 0x2A, (byte) 0x3E, - (byte) 0x24, (byte) 0x5D, (byte) 0x88, (byte) 0x33})}; - - @VisibleForTesting - static final BigInteger[] KN = new BigInteger[] { - new BigInteger(new byte[] {(byte) 0x20, (byte) 0x1A, (byte) 0x18, (byte) 0x4F, - (byte) 0x47, (byte) 0xD9, (byte) 0xA7, (byte) 0x97, (byte) 0x38, (byte) 0x91, - (byte) 0xD1, (byte) 0x48, (byte) 0xE3, (byte) 0xD1, (byte) 0xC8, (byte) 0x64, - (byte) 0xD8, (byte) 0x08, (byte) 0x45, (byte) 0x47, (byte) 0x13, (byte) 0x1C, - (byte) 0x2C, (byte) 0x1C, (byte) 0xEF, (byte) 0xB7, (byte) 0xEE, (byte) 0xBD, - (byte) 0x26, (byte) 0xC6, (byte) 0x35, (byte) 0x67}), - new BigInteger(new byte[] {(byte) 0x6D, (byte) 0xA2, (byte) 0xD3, (byte) 0xB1, - (byte) 0x8E, (byte) 0xC4, (byte) 0xF9, (byte) 0xAA, (byte) 0x3B, (byte) 0x08, - (byte) 0xE3, (byte) 0x9C, (byte) 0x99, (byte) 0x7C, (byte) 0xD8, (byte) 0xBF, - (byte) 0x6E, (byte) 0x99, (byte) 0x48, (byte) 0xFF, (byte) 0xD4, (byte) 0xFE, - (byte) 0xFF, (byte) 0xEC, (byte) 0xAF, (byte) 0x8D, (byte) 0xD0, (byte) 0xB3, - (byte) 0xD6, (byte) 0x48, (byte) 0xB7, (byte) 0xE8}), - BigInteger.ONE, - new BigInteger(new byte[] {(byte) 0x16, (byte) 0x40, (byte) 0xED, (byte) 0x5A, - (byte) 0x54, (byte) 0xFA, (byte) 0x0B, (byte) 0x07, (byte) 0x22, (byte) 0x86, - (byte) 0xE9, (byte) 0xD2, (byte) 0x2F, (byte) 0x46, (byte) 0x47, (byte) 0x63, - (byte) 0xFB, (byte) 0xF6, (byte) 0x0D, (byte) 0x79, (byte) 0x1D, (byte) 0x37, - (byte) 0xB9, (byte) 0x09, (byte) 0x3B, (byte) 0x58, (byte) 0x4D, (byte) 0xF4, - (byte) 0xC9, (byte) 0x95, (byte) 0xF7, (byte) 0x81})}; - - // Base point B as per ed25519.cr.yp.to - @VisibleForTesting - /* package */ static final BigInteger[] B = new BigInteger[] { - new BigInteger(new byte[] {(byte) 0x21, (byte) 0x69, (byte) 0x36, (byte) 0xD3, - (byte) 0xCD, (byte) 0x6E, (byte) 0x53, (byte) 0xFE, (byte) 0xC0, (byte) 0xA4, - (byte) 0xE2, (byte) 0x31, (byte) 0xFD, (byte) 0xD6, (byte) 0xDC, (byte) 0x5C, - (byte) 0x69, (byte) 0x2C, (byte) 0xC7, (byte) 0x60, (byte) 0x95, (byte) 0x25, - (byte) 0xA7, (byte) 0xB2, (byte) 0xC9, (byte) 0x56, (byte) 0x2D, (byte) 0x60, - (byte) 0x8F, (byte) 0x25, (byte) 0xD5, (byte) 0x1A}), - new BigInteger(new byte[] {(byte) 0x66, (byte) 0x66, (byte) 0x66, (byte) 0x66, - (byte) 0x66, (byte) 0x66, (byte) 0x66, (byte) 0x66, (byte) 0x66, (byte) 0x66, - (byte) 0x66, (byte) 0x66, (byte) 0x66, (byte) 0x66, (byte) 0x66, (byte) 0x66, - (byte) 0x66, (byte) 0x66, (byte) 0x66, (byte) 0x66, (byte) 0x66, (byte) 0x66, - (byte) 0x66, (byte) 0x66, (byte) 0x66, (byte) 0x66, (byte) 0x66, (byte) 0x66, - (byte) 0x66, (byte) 0x66, (byte) 0x66, (byte) 0x58}), - BigInteger.ONE, - new BigInteger(new byte[] {(byte) 0x67, (byte) 0x87, (byte) 0x5F, (byte) 0x0F, - (byte) 0xD7, (byte) 0x8B, (byte) 0x76, (byte) 0x65, (byte) 0x66, (byte) 0xEA, - (byte) 0x4E, (byte) 0x8E, (byte) 0x64, (byte) 0xAB, (byte) 0xE3, (byte) 0x7D, - (byte) 0x20, (byte) 0xF0, (byte) 0x9F, (byte) 0x80, (byte) 0x77, (byte) 0x51, - (byte) 0x52, (byte) 0xF5, (byte) 0x6D, (byte) 0xDE, (byte) 0x8A, (byte) 0xB3, - (byte) 0xA5, (byte) 0xB7, (byte) 0xDD, (byte) 0xA3})}; - - // Number of bits needed to represent a point - private static final int POINT_SIZE_BITS = 256; - - // Java Message Digest name for SHA 256 - private static final String SHA256 = "SHA-256"; - - // Pre-shared password hash represented as an integer - private BigInteger passwordHash; - - // Current state of the handshake - private State handshakeState; - - // Derived shared key - private byte[] sharedKey; - - // Private key (random scalar) - private BigInteger valueX; - - // Public key (random point, in extended notation, based on valueX) - private BigInteger[] pointX; - - // Commitment we've received from the other party (their password-authenticated public key) - private BigInteger[] theirCommitmentPointAffine; - private BigInteger[] theirCommitmentPointExtended; - - // Commitment we've sent to the other party (our password-authenticated public key) - private BigInteger[] ourCommitmentPointAffine; - private BigInteger[] ourCommitmentPointExtended; - - private enum State { - // Initiator state - INITIATOR_START, - INITIATOR_WAITING_FOR_RESPONDER_COMMITMENT, - INITIATOR_AFTER_RESPONDER_COMMITMENT, - INITIATOR_WAITING_FOR_RESPONDER_HASH, - - // Responder state - RESPONDER_START, - RESPONDER_AFTER_INITIATOR_COMMITMENT, - RESPONDER_WAITING_FOR_INITIATOR_HASH, - RESPONDER_AFTER_INITIATOR_HASH, - - // Common completion state - HANDSHAKE_FINISHED, - HANDSHAKE_ALREADY_USED - } - - @VisibleForTesting - D2DSpakeEd25519Handshake(State state, byte[] password) throws HandshakeException { - if (password == null || password.length < MIN_PASSWORD_LENGTH) { - throw new HandshakeException("Passwords must be at least " + MIN_PASSWORD_LENGTH + " bytes"); - } - - handshakeState = state; - passwordHash = new BigInteger(1 /* positive */, hash(password)); - - do { - valueX = new BigInteger(POINT_SIZE_BITS, new SecureRandom()); - } while (valueX.equals(BigInteger.ZERO)); - - try { - pointX = Ed25519.scalarMultiplyExtendedPoint(B, valueX); - } catch (Ed25519Exception e) { - throw new HandshakeException("Could not make public key point", e); - } - } - - @Override - public boolean isHandshakeComplete() { - switch (handshakeState) { - case HANDSHAKE_FINISHED: - // fall-through intentional - case HANDSHAKE_ALREADY_USED: - return true; - - default: - return false; - } - } - - @Override - public byte[] getNextHandshakeMessage() throws HandshakeException { - byte[] nextMessage; - - switch(handshakeState) { - case INITIATOR_START: - nextMessage = makeCommitmentPointMessage(true /* is initiator */); - handshakeState = State.INITIATOR_WAITING_FOR_RESPONDER_COMMITMENT; - break; - - case RESPONDER_AFTER_INITIATOR_COMMITMENT: - nextMessage = makeCommitmentPointMessage(false /* is initiator */); - handshakeState = State.RESPONDER_WAITING_FOR_INITIATOR_HASH; - break; - - case INITIATOR_AFTER_RESPONDER_COMMITMENT: - nextMessage = makeSharedKeyHashMessage(true /* is initiator */, null /* no payload */); - handshakeState = State.INITIATOR_WAITING_FOR_RESPONDER_HASH; - break; - - case RESPONDER_AFTER_INITIATOR_HASH: - nextMessage = makeSharedKeyHashMessage(false /* is initiator */, null /* no payload */); - handshakeState = State.HANDSHAKE_FINISHED; - break; - - default: - throw new HandshakeException("Cannot get next message in state: " + handshakeState); - } - - return nextMessage; - } - - @Override - public byte[] getNextHandshakeMessage(byte[] payload) throws HandshakeException { - byte[] nextMessage; - - switch (handshakeState) { - case RESPONDER_AFTER_INITIATOR_HASH: - nextMessage = makeSharedKeyHashMessage(false /* is initiator */, payload); - handshakeState = State.HANDSHAKE_FINISHED; - break; - - default: - throw new HandshakeException( - "Cannot send handshake message with payload in state: " + handshakeState); - } - - return nextMessage; - } - - private byte[] makeCommitmentPointMessage(boolean isInitiator) throws HandshakeException { - try { - ourCommitmentPointExtended = - Ed25519.scalarMultiplyExtendedPoint(isInitiator ? KM : KN, passwordHash); - ourCommitmentPointExtended = Ed25519.addExtendedPoints(ourCommitmentPointExtended, pointX); - ourCommitmentPointAffine = Ed25519.toAffine(ourCommitmentPointExtended); - - return SpakeHandshakeMessage.newBuilder() - .setEcPoint( - EcPoint.newBuilder() - .setCurve(DeviceToDeviceMessagesProto.Curve.ED_25519) - .setX(ByteString.copyFrom(ourCommitmentPointAffine[0].toByteArray())) - .setY(ByteString.copyFrom(ourCommitmentPointAffine[1].toByteArray())) - .build()) - .setFlowNumber(isInitiator ? 1 : 2 /* first or second message */) - .build() - .toByteArray(); - } catch (Ed25519Exception e) { - throw new HandshakeException("Could not make commitment point message", e); - } - } - - private void makeSharedKey(boolean isInitiator) throws HandshakeException { - - if (handshakeState != State.RESPONDER_START - && handshakeState != State.INITIATOR_WAITING_FOR_RESPONDER_COMMITMENT) { - throw new HandshakeException("Cannot make shared key in state: " + handshakeState); - } - - try { - BigInteger[] kNMP = Ed25519.scalarMultiplyExtendedPoint(isInitiator ? KN : KM, passwordHash); - - // TheirPublicKey = TheirCommitment - kNMP = (TheirPublicKey + kNMP) - kNMP - BigInteger[] theirPublicKey = - Ed25519.subtractExtendedPoints(theirCommitmentPointExtended, kNMP); - - BigInteger[] sharedKeyPoint = Ed25519.scalarMultiplyExtendedPoint(theirPublicKey, valueX); - sharedKey = hash(pointToByteArray(Ed25519.toAffine(sharedKeyPoint))); - } catch (Ed25519Exception e) { - throw new HandshakeException("Error computing shared key", e); - } - } - - private byte[] makeSharedKeyHashMessage(boolean isInitiator, byte[] payload) - throws HandshakeException { - SpakeHandshakeMessage.Builder handshakeMessage = SpakeHandshakeMessage.newBuilder() - .setHashValue(ByteString.copyFrom(computeOurKeyHash(isInitiator))) - .setFlowNumber(isInitiator ? 3 : 4 /* third or fourth message */); - - if (canSendPayloadInHandshakeMessage() && payload != null) { - DeviceToDeviceMessage deviceToDeviceMessage = - D2DConnectionContext.createDeviceToDeviceMessage(payload, 1 /* sequence number */); - try { - handshakeMessage.setPayload(ByteString.copyFrom( - D2DCryptoOps.signcryptPayload( - new Payload(PayloadType.DEVICE_TO_DEVICE_RESPONDER_HELLO_PAYLOAD, - deviceToDeviceMessage.toByteArray()), - new SecretKeySpec(sharedKey, "AES")))); - } catch (InvalidKeyException | NoSuchAlgorithmException e) { - throw new HandshakeException("Cannot set payload", e); - } - } - - return handshakeMessage.build().toByteArray(); - } - - private byte[] computeOurKeyHash(boolean isInitiator) throws HandshakeException { - return hash(concat( - new byte[] { (byte) (isInitiator ? 0 : 1) }, - pointToByteArray(theirCommitmentPointAffine), - pointToByteArray(ourCommitmentPointAffine), - sharedKey)); - } - - private byte[] computeTheirKeyHash(boolean isInitiator) throws HandshakeException { - return hash(concat( - new byte[] { (byte) (isInitiator ? 1 : 0) }, - pointToByteArray(ourCommitmentPointAffine), - pointToByteArray(theirCommitmentPointAffine), - sharedKey)); - } - - private byte[] pointToByteArray(BigInteger[] p) { - return concat(p[0].toByteArray(), p[1].toByteArray()); - } - - @Override - public boolean canSendPayloadInHandshakeMessage() { - return handshakeState == State.RESPONDER_AFTER_INITIATOR_HASH; - } - - @Override - public byte[] parseHandshakeMessage(byte[] handshakeMessage) throws HandshakeException { - if (handshakeMessage == null || handshakeMessage.length == 0) { - throw new HandshakeException("Handshake message too short"); - } - - byte[] payload = new byte[0]; - - switch(handshakeState) { - case RESPONDER_START: - // no payload can be sent in this message - parseCommitmentMessage(handshakeMessage, false /* is initiator */); - makeSharedKey(false /* is initiator */); - handshakeState = State.RESPONDER_AFTER_INITIATOR_COMMITMENT; - break; - - case INITIATOR_WAITING_FOR_RESPONDER_COMMITMENT: - // no payload can be sent in this message - parseCommitmentMessage(handshakeMessage, true /* is initiator */); - makeSharedKey(true /* is initiator */); - handshakeState = State.INITIATOR_AFTER_RESPONDER_COMMITMENT; - break; - - case RESPONDER_WAITING_FOR_INITIATOR_HASH: - // no payload can be sent in this message - parseHashMessage(handshakeMessage, false /* is initiator */); - handshakeState = State.RESPONDER_AFTER_INITIATOR_HASH; - break; - - case INITIATOR_WAITING_FOR_RESPONDER_HASH: - payload = parseHashMessage(handshakeMessage, true /* is initiator */); - handshakeState = State.HANDSHAKE_FINISHED; - break; - - default: - throw new HandshakeException("Cannot parse message in state: " + handshakeState); - } - - return payload; - } - - private byte[] parseHashMessage(byte[] handshakeMessage, boolean isInitiator) - throws HandshakeException { - SpakeHandshakeMessage hashMessage; - - // Parse the message - try { - hashMessage = SpakeHandshakeMessage.parseFrom(handshakeMessage); - } catch (InvalidProtocolBufferException e) { - throw new HandshakeException("Could not parse hash message", e); - } - - // Check flow number - if (!hashMessage.hasFlowNumber()) { - throw new HandshakeException("Hash message missing flow number"); - } - int expectedFlowNumber = isInitiator ? 4 : 3; - int actualFlowNumber = hashMessage.getFlowNumber(); - if (actualFlowNumber != expectedFlowNumber) { - throw new HandshakeException("Hash message has flow number " + actualFlowNumber - + ", but expected flow number " + expectedFlowNumber); - } - - // Check and extract hash - if (!hashMessage.hasHashValue()) { - throw new HandshakeException("Hash message missing hash value"); - } - - byte[] theirHash = hashMessage.getHashValue().toByteArray(); - byte[] theirCorrectHash = computeTheirKeyHash(isInitiator); - - if (!constantTimeArrayEquals(theirCorrectHash, theirHash)) { - throw new HandshakeException("Hash message had incorrect hash value"); - } - - if (isInitiator && hashMessage.hasPayload()) { - try { - DeviceToDeviceMessage message = D2DCryptoOps.decryptResponderHelloMessage( - new SecretKeySpec(sharedKey, "AES"), - hashMessage.getPayload().toByteArray()); - - if (message.getSequenceNumber() != 1) { - throw new HandshakeException("Incorrect sequence number in responder hello"); - } - - return message.getMessage().toByteArray(); - - } catch (SignatureException e) { - throw new HandshakeException("Error recovering payload from hash message", e); - } - } - - // empty/no payload - return new byte[0]; - } - - private void parseCommitmentMessage(byte[] handshakeMessage, boolean isInitiator) - throws HandshakeException { - SpakeHandshakeMessage commitmentMessage; - - // Parse the message - try { - commitmentMessage = SpakeHandshakeMessage.parseFrom(handshakeMessage); - } catch (InvalidProtocolBufferException e) { - throw new HandshakeException("Could not parse commitment message", e); - } - - // Check flow number - if (!commitmentMessage.hasFlowNumber()) { - throw new HandshakeException("Commitment message missing flow number"); - } - if (commitmentMessage.getFlowNumber() != (isInitiator ? 2 : 1)) { - throw new HandshakeException("Commitment message has wrong flow number"); - } - - // Check point and curve; and extract point - if (!commitmentMessage.hasEcPoint()) { - throw new HandshakeException("Commitment message missing point"); - } - EcPoint commitmentPoint = commitmentMessage.getEcPoint(); - if (!commitmentPoint.hasCurve() - || commitmentPoint.getCurve() != DeviceToDeviceMessagesProto.Curve.ED_25519) { - throw new HandshakeException("Commitment message has wrong curve"); - } - - if (!commitmentPoint.hasX()) { - throw new HandshakeException("Commitment point missing x coordinate"); - } - - if (!commitmentPoint.hasY()) { - throw new HandshakeException("Commitment point missing y coordinate"); - } - - // Build the point - theirCommitmentPointAffine = new BigInteger[] { - new BigInteger(commitmentPoint.getX().toByteArray()), - new BigInteger(commitmentPoint.getY().toByteArray()) - }; - - // Validate the point to be sure - try { - Ed25519.validateAffinePoint(theirCommitmentPointAffine); - theirCommitmentPointExtended = Ed25519.toExtended(theirCommitmentPointAffine); - } catch (Ed25519Exception e) { - throw new HandshakeException("Error validating their commitment point", e); - } - } - - @Override - public D2DConnectionContext toConnectionContext() throws HandshakeException { - if (handshakeState == State.HANDSHAKE_ALREADY_USED) { - throw new HandshakeException("Cannot reuse handshake context; is has already been used"); - } - - if (!isHandshakeComplete()) { - throw new HandshakeException("Handshake is not complete; cannot create connection context"); - } - - handshakeState = State.HANDSHAKE_ALREADY_USED; - - // Both sides start with an initial sequence number of 1 because the last message of the - // handshake had an optional payload with sequence number 1. D2DConnectionContext remembers - // the last sequence number used. - return new D2DConnectionContextV0( - new SecretKeySpec(sharedKey, "AES"), 1 /* initialSequenceNumber */); - } - - /** - * Implementation of byte array concatenation copied from Guava. - */ - private static byte[] concat(byte[]... arrays) { - int length = 0; - for (byte[] array : arrays) { - length += array.length; - } - - byte[] result = new byte[length]; - int pos = 0; - for (byte[] array : arrays) { - System.arraycopy(array, 0, result, pos, array.length); - pos += array.length; - } - - return result; - } - - private static byte[] hash(byte[] message) throws HandshakeException { - try { - return MessageDigest.getInstance(SHA256).digest(message); - } catch (NoSuchAlgorithmException e) { - throw new HandshakeException("Error performing hash", e); - } - } - - private static boolean constantTimeArrayEquals(byte[] a, byte[] b) { - if (a == null || b == null) { - return (a == b); - } - if (a.length != b.length) { - return false; - } - byte result = 0; - for (int i = 0; i < b.length; i++) { - result = (byte) (result | (a[i] ^ b[i])); - } - return (result == 0); - } -} diff --git a/src/main/java/com/google/security/cryptauth/lib/securegcm/Ed25519.java b/src/main/java/com/google/security/cryptauth/lib/securegcm/Ed25519.java index 2ea2563..454b942 100644 --- a/src/main/java/com/google/security/cryptauth/lib/securegcm/Ed25519.java +++ b/src/main/java/com/google/security/cryptauth/lib/securegcm/Ed25519.java @@ -1,24 +1,23 @@ -/* Copyright 2018 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 - * - * https://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. - */ +// Copyright 2020 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 +// +// https://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 static java.math.BigInteger.ONE; import static java.math.BigInteger.ZERO; import com.google.common.annotations.VisibleForTesting; - import java.math.BigInteger; /** @@ -208,20 +207,20 @@ public class Ed25519 { }; } - /** - * Converts a point in affine representation to extended representation - */ - @VisibleForTesting + /** Converts a point in affine representation to extended representation */ + // TODO(b/120887495): This @VisibleForTesting annotation was being ignored by prod code. + // Please check that removing it is correct, and remove this comment along with it. + // @VisibleForTesting static BigInteger[] toExtended(BigInteger[] p) throws Ed25519Exception { checkPointIsInAffineRepresentation(p); return new BigInteger[] {p[X], p[Y], ONE, p[X].multiply(p[Y]).mod(Ed25519_P)}; // x, y, 1, x*y } - /** - * Converts a point in extended representation to affine representation - */ - @VisibleForTesting + /** Converts a point in extended representation to affine representation */ + // TODO(b/120887495): This @VisibleForTesting annotation was being ignored by prod code. + // Please check that removing it is correct, and remove this comment along with it. + // @VisibleForTesting static BigInteger[] toAffine(BigInteger[] p) throws Ed25519Exception { checkPointIsInExtendedRepresentation(p); diff --git a/src/main/java/com/google/security/cryptauth/lib/securegcm/EnrollmentCryptoOps.java b/src/main/java/com/google/security/cryptauth/lib/securegcm/EnrollmentCryptoOps.java index 328cb53..450c806 100644 --- a/src/main/java/com/google/security/cryptauth/lib/securegcm/EnrollmentCryptoOps.java +++ b/src/main/java/com/google/security/cryptauth/lib/securegcm/EnrollmentCryptoOps.java @@ -1,17 +1,17 @@ -/* Copyright 2018 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 - * - * https://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. - */ +// Copyright 2020 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 +// +// https://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 com.google.protobuf.InvalidProtocolBufferException; diff --git a/src/main/java/com/google/security/cryptauth/lib/securegcm/HandshakeException.java b/src/main/java/com/google/security/cryptauth/lib/securegcm/HandshakeException.java index bb5fffc..b717eb6 100644 --- a/src/main/java/com/google/security/cryptauth/lib/securegcm/HandshakeException.java +++ b/src/main/java/com/google/security/cryptauth/lib/securegcm/HandshakeException.java @@ -1,17 +1,17 @@ -/* Copyright 2018 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 - * - * https://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. - */ +// Copyright 2020 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 +// +// https://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; /** diff --git a/src/main/java/com/google/security/cryptauth/lib/securegcm/KeyEncoding.java b/src/main/java/com/google/security/cryptauth/lib/securegcm/KeyEncoding.java index 9690a89..67e4ace 100644 --- a/src/main/java/com/google/security/cryptauth/lib/securegcm/KeyEncoding.java +++ b/src/main/java/com/google/security/cryptauth/lib/securegcm/KeyEncoding.java @@ -1,17 +1,17 @@ -/* Copyright 2018 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 - * - * https://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. - */ +// Copyright 2020 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 +// +// https://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 com.google.protobuf.InvalidProtocolBufferException; @@ -58,6 +58,10 @@ public class KeyEncoding { return sk.getEncoded(); } + public static byte[] encodeDeviceSyncGroupPublicKey(PublicKey pk) { + return PublicKeyProtoUtil.encodePaddedEcPublicKey(pk).toByteArray(); + } + public static PrivateKey parseUserPrivateKey(byte[] encodedPrivateKey, boolean isLegacy) throws InvalidKeySpecException { PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedPrivateKey); @@ -71,6 +75,11 @@ public class KeyEncoding { return parsePublicKey(keyBytes); } + public static PublicKey parseDeviceSyncGroupPublicKey(byte[] keyBytes) + throws InvalidKeySpecException { + return parsePublicKey(keyBytes); + } + public static byte[] encodeKeyAgreementPublicKey(PublicKey pk) { return encodePublicKey(pk); } diff --git a/src/main/java/com/google/security/cryptauth/lib/securegcm/SecureGcmConstants.java b/src/main/java/com/google/security/cryptauth/lib/securegcm/SecureGcmConstants.java index 8482628..a69431f 100644 --- a/src/main/java/com/google/security/cryptauth/lib/securegcm/SecureGcmConstants.java +++ b/src/main/java/com/google/security/cryptauth/lib/securegcm/SecureGcmConstants.java @@ -1,17 +1,17 @@ -/* Copyright 2018 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 - * - * https://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. - */ +// Copyright 2020 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 +// +// https://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; /** diff --git a/src/main/java/com/google/security/cryptauth/lib/securegcm/TransportCryptoOps.java b/src/main/java/com/google/security/cryptauth/lib/securegcm/TransportCryptoOps.java index a22edc4..b053bf4 100644 --- a/src/main/java/com/google/security/cryptauth/lib/securegcm/TransportCryptoOps.java +++ b/src/main/java/com/google/security/cryptauth/lib/securegcm/TransportCryptoOps.java @@ -1,17 +1,17 @@ -/* Copyright 2018 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 - * - * https://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. - */ +// Copyright 2020 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 +// +// https://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 com.google.protobuf.InvalidProtocolBufferException; diff --git a/src/main/java/com/google/security/cryptauth/lib/securegcm/Ukey2Handshake.java b/src/main/java/com/google/security/cryptauth/lib/securegcm/Ukey2Handshake.java index 0d01c9a..8e00ea9 100644 --- a/src/main/java/com/google/security/cryptauth/lib/securegcm/Ukey2Handshake.java +++ b/src/main/java/com/google/security/cryptauth/lib/securegcm/Ukey2Handshake.java @@ -1,17 +1,17 @@ -/* Copyright 2018 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 - * - * https://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. - */ +// Copyright 2020 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 +// +// https://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 com.google.protobuf.ByteString; diff --git a/src/main/java/com/google/security/cryptauth/lib/securemessage/CryptoOps.java b/src/main/java/com/google/security/cryptauth/lib/securemessage/CryptoOps.java index 1e3b196..876bd93 100644 --- a/src/main/java/com/google/security/cryptauth/lib/securemessage/CryptoOps.java +++ b/src/main/java/com/google/security/cryptauth/lib/securemessage/CryptoOps.java @@ -1,17 +1,17 @@ -/* Copyright 2018 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 - * - * https://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. - */ +// Copyright 2020 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 +// +// https://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.securemessage; import com.google.security.annotations.SuppressInsecureCipherModeCheckerReviewed; @@ -132,7 +132,6 @@ public class CryptoOps { * A salt value specific to this library, generated as SHA-256("SecureMessage") */ private static final byte[] SALT = sha256("SecureMessage"); - private static final byte[] CONSTANT_01 = { 0x01 }; // For convenience /** * Signs {@code data} using the algorithm specified by {@code sigType} with {@code signingKey}. @@ -412,10 +411,31 @@ public class CryptoOps { */ public static byte[] hkdf(SecretKey inputKeyMaterial, byte[] salt, byte[] info) throws NoSuchAlgorithmException, InvalidKeyException { + return hkdf(inputKeyMaterial, salt, info, /* length= */ 32); + } + + /** + * Implements HKDF (RFC 5869) with the SHA-256 hash. + * + * <p>Please make sure to select a salt that is fixed and unique for your codebase, and use the + * {@code info} parameter to specify any additional bits that should influence the derived key. + * + * @param inputKeyMaterial master key from which to derive sub-keys + * @param salt a (public) randomly generated 256-bit input that can be re-used + * @param info arbitrary information that is bound to the derived key (i.e., used in its creation) + * @param length length of returned key material + * @return raw derived key bytes = HKDF-SHA256(inputKeyMaterial, salt, info) + * @throws InvalidKeyException if the encoded form of {@code inputKeyMaterial} cannot be accessed + */ + public static byte[] hkdf(SecretKey inputKeyMaterial, byte[] salt, byte[] info, int length) + throws NoSuchAlgorithmException, InvalidKeyException { if ((inputKeyMaterial == null) || (salt == null) || (info == null)) { throw new NullPointerException(); } - return hkdfSha256Expand(hkdfSha256Extract(inputKeyMaterial, salt), info); + if (length < 0) { + throw new IllegalArgumentException("Length must be positive"); + } + return hkdfSha256Expand(hkdfSha256Extract(inputKeyMaterial, salt), info, length); } /** @@ -464,12 +484,12 @@ public class CryptoOps { } /** - * The HKDF (RFC 5869) extraction function, using the SHA-256 hash function. This function is - * used to pre-process the inputKeyMaterial and mix it with the salt, producing output suitable - * for use with HKDF expansion function (which produces the actual derived key). + * The HKDF (RFC 5869) extraction function, using the SHA-256 hash function. This function is used + * to pre-process the inputKeyMaterial and mix it with the salt, producing output suitable for use + * with HKDF expansion function (which produces the actual derived key). * - * @see #hkdfSha256Expand(byte[], byte[]) - * @return HMAC-SHA256(salt, inputKeyMaterial) (salt is the "key" for the HMAC) + * @see #hkdfSha256Expand(byte[], byte[], int) + * @return HMAC-SHA256(salt, inputKeyMaterial) (salt is the "key" for the HMAC) * @throws InvalidKeyException if the encoded form of {@code inputKeyMaterial} cannot be accessed * @throws NoSuchAlgorithmException if the HmacSHA256 or AES algorithms are unavailable */ @@ -491,15 +511,15 @@ public class CryptoOps { } /** - * Special case of HKDF (RFC 5869) expansion function, using the SHA-256 hash function and - * allowing for a maximum output length of 256 bits. + * HKDF (RFC 5869) expansion function, using the SHA-256 hash function. * - * @param pseudoRandomKey should be generated by {@link #hkdfSha256Expand(byte[], byte[])} + * @param pseudoRandomKey should be generated by {@link #hkdfSha256Extract(SecretKey, byte[])} * @param info arbitrary information the derived key should be bound to + * @param length length of the output key material in bytes * @return raw derived key bytes = HMAC-SHA256(pseudoRandomKey, info | 0x01) * @throws NoSuchAlgorithmException if the HmacSHA256 or AES algorithms are unavailable */ - private static byte[] hkdfSha256Expand(byte[] pseudoRandomKey, byte[] info) + private static byte[] hkdfSha256Expand(byte[] pseudoRandomKey, byte[] info, int length) throws NoSuchAlgorithmException { Mac macScheme = Mac.getInstance("HmacSHA256"); try { @@ -507,11 +527,38 @@ public class CryptoOps { } catch (InvalidKeyException e) { throw new AssertionError(e); // This should never happen } - // Arbitrary "info" to be included in the MAC. - macScheme.update(info); - // Note that RFC 5869 computes number of blocks N = ceil(hash length / output length), but - // here we only deal with a 256 bit hash up to a 256 bit output, yielding N=1. - return macScheme.doFinal(CONSTANT_01); + + // Number of blocks N = ceil(hash length / output length). + int blocks = length / 32; + if (length % 32 > 0) { + blocks += 1; + } + + // The counter used to generate the blocks according to the RFC is only one byte long, + // which puts a limit on the number of blocks possible. + if (blocks > 0xFF) { + throw new IllegalArgumentException("Maximum HKDF output length exceeded."); + } + + byte[] outputBlock = new byte[32]; + byte[] counter = new byte[1]; + byte[] output = new byte[32 * blocks]; + for (int i = 0; i < blocks; ++i) { + macScheme.reset(); + if (i > 0) { + // Previous block + macScheme.update(outputBlock); + } + // Arbitrary info + macScheme.update(info); + // Counter + counter[0] = (byte) (i + 1); + outputBlock = macScheme.doFinal(counter); + + System.arraycopy(outputBlock, 0, output, 32 * i, 32); + } + + return subarray(output, 0, length); } } diff --git a/src/main/java/com/google/security/cryptauth/lib/securemessage/PublicKeyProtoUtil.java b/src/main/java/com/google/security/cryptauth/lib/securemessage/PublicKeyProtoUtil.java index ab97cca..0c593fe 100644 --- a/src/main/java/com/google/security/cryptauth/lib/securemessage/PublicKeyProtoUtil.java +++ b/src/main/java/com/google/security/cryptauth/lib/securemessage/PublicKeyProtoUtil.java @@ -1,19 +1,20 @@ -/* Copyright 2018 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 - * - * https://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. - */ +// Copyright 2020 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 +// +// https://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.securemessage; +import com.google.common.collect.Lists; import com.google.protobuf.ByteString; import com.google.security.annotations.SuppressInsecureCipherModeCheckerPendingReview; import com.google.security.cryptauth.lib.securemessage.SecureMessageProto.DhPublicKey; @@ -194,6 +195,37 @@ public class PublicKeyProtoUtil { } /** + * Encodes an {@link ECPublicKey} to an {@link GenericPublicKey} proto message. The returned key + * has a null-byte padded to the front in order to match the C++ implementation. + */ + public static GenericPublicKey encodePaddedEcPublicKey(PublicKey pk) { + if (pk == null) { + throw new NullPointerException(); + } + if (!(pk instanceof ECPublicKey)) { + throw new IllegalArgumentException("Expected ECPublicKey PublicKey type"); + } + + ECPublicKey epk = pkToECPublicKey(pk); + ByteString nullByteString = ByteString.copyFrom(new byte[] {0}); + ByteString xByteString = extractX(epk); + if (xByteString.size() < MAX_P256_ENCODING_BYTES) { + xByteString = ByteString.copyFrom(Lists.newArrayList(nullByteString, xByteString)); + } + ByteString yByteString = extractY(epk); + if (yByteString.size() < MAX_P256_ENCODING_BYTES) { + yByteString = ByteString.copyFrom(Lists.newArrayList(nullByteString, yByteString)); + } + EcP256PublicKey newKey = + EcP256PublicKey.newBuilder().setX(xByteString).setY(yByteString).build(); + + return GenericPublicKey.newBuilder() + .setType(SecureMessageProto.PublicKeyType.EC_P256) + .setEcP256PublicKey(newKey) + .build(); + } + + /** * Encodes an {@link ECPublicKey} to an {@link EcP256PublicKey} proto message. */ public static EcP256PublicKey encodeEcPublicKey(PublicKey pk) { diff --git a/src/main/java/com/google/security/cryptauth/lib/securemessage/SecureMessageBuilder.java b/src/main/java/com/google/security/cryptauth/lib/securemessage/SecureMessageBuilder.java index f59ce4e..f1a9464 100644 --- a/src/main/java/com/google/security/cryptauth/lib/securemessage/SecureMessageBuilder.java +++ b/src/main/java/com/google/security/cryptauth/lib/securemessage/SecureMessageBuilder.java @@ -1,17 +1,17 @@ -/* Copyright 2018 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 - * - * https://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. - */ +// Copyright 2020 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 +// +// https://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.securemessage; import com.google.protobuf.ByteString; diff --git a/src/main/java/com/google/security/cryptauth/lib/securemessage/SecureMessageParser.java b/src/main/java/com/google/security/cryptauth/lib/securemessage/SecureMessageParser.java index e1c60e3..d634d40 100644 --- a/src/main/java/com/google/security/cryptauth/lib/securemessage/SecureMessageParser.java +++ b/src/main/java/com/google/security/cryptauth/lib/securemessage/SecureMessageParser.java @@ -1,17 +1,17 @@ -/* Copyright 2018 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 - * - * https://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. - */ +// Copyright 2020 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 +// +// https://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.securemessage; import com.google.protobuf.ByteString; diff --git a/src/main/proto/device_to_device_messages.proto b/src/main/proto/device_to_device_messages.proto index c3bd2cf..5600373 100644 --- a/src/main/proto/device_to_device_messages.proto +++ b/src/main/proto/device_to_device_messages.proto @@ -1,27 +1,28 @@ -/* Copyright 2018 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 - * - * https://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. - */ +// Copyright 2020 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 +// +// https://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. + syntax = "proto2"; package securegcm; +import "securemessage.proto"; + +option optimize_for = LITE_RUNTIME; option java_package = "com.google.security.cryptauth.lib.securegcm"; option java_outer_classname = "DeviceToDeviceMessagesProto"; option objc_class_prefix = "SGCM"; -import "securemessage.proto"; - // Used by protocols between devices message DeviceToDeviceMessage { // the payload of the message @@ -52,9 +53,7 @@ message ResponderHello { } // Type of curve -enum Curve { - ED_25519 = 1; -} +enum Curve { ED_25519 = 1; } // A convenience proto for encoding curve points in affine representation message EcPoint { @@ -80,4 +79,3 @@ message SpakeHandshakeMessage { // since the key exchange is already complete on the sender's side. optional bytes payload = 4; } - diff --git a/src/main/proto/passwordless_auth_payloads.proto b/src/main/proto/passwordless_auth_payloads.proto index 054d91c..69c2784 100644 --- a/src/main/proto/passwordless_auth_payloads.proto +++ b/src/main/proto/passwordless_auth_payloads.proto @@ -1,28 +1,27 @@ -/* Copyright 2018 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 - * - * https://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. - */ +// Copyright 2020 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 +// +// https://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. + syntax = "proto2"; package securegcm; +option optimize_for = LITE_RUNTIME; option java_package = "com.google.security.cryptauth.lib.securegcm"; option java_outer_classname = "SecureGcmPasswordlessAuthProto"; option objc_class_prefix = "SGCM"; - message IdentityAssertion { - // Browser data contains the challenge, origin, etc. optional bytes browser_data_hash = 1; diff --git a/src/main/proto/proximity_payloads.proto b/src/main/proto/proximity_payloads.proto index 9c2f1ec..d7a4956 100644 --- a/src/main/proto/proximity_payloads.proto +++ b/src/main/proto/proximity_payloads.proto @@ -1,33 +1,34 @@ -/* Copyright 2018 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 - * - * https://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. - */ -syntax = "proto2"; +// Copyright 2020 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 +// +// https://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. -import "securegcm.proto"; +syntax = "proto2"; package securegcm; +import "securegcm.proto"; + +option optimize_for = LITE_RUNTIME; option java_package = "com.google.security.cryptauth.lib.securegcm"; option java_outer_classname = "SecureGcmProximityAuthProto"; option objc_class_prefix = "SGCM"; -// Message used when one device wants to initiate a Proximity Auth pairing with another device -// DEPRECATED. DO NOT USE +// Message used when one device wants to initiate a Proximity Auth pairing with +// another device DEPRECATED. DO NOT USE message CloudToDeviceProximityAuthPairing { -// The name or description of the device that wants to pair with another -// personal device of the user. This is a string that may be shown to the -// user or may be kept in logs. + // The name or description of the device that wants to pair with another + // personal device of the user. This is a string that may be shown to the + // user or may be kept in logs. optional string initiating_device_name = 1; // The original device's Bluetooth address in human readable form diff --git a/src/main/proto/securegcm.proto b/src/main/proto/securegcm.proto index b7dae25..0325f06 100644 --- a/src/main/proto/securegcm.proto +++ b/src/main/proto/securegcm.proto @@ -1,21 +1,22 @@ -/* Copyright 2018 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 - * - * https://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. - */ +// Copyright 2020 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 +// +// https://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. + syntax = "proto2"; package securegcm; +option optimize_for = LITE_RUNTIME; option java_package = "com.google.security.cryptauth.lib.securegcm"; option java_outer_classname = "SecureGcmProto"; option objc_class_prefix = "SGCM"; @@ -36,7 +37,7 @@ message GcmDeviceInfo { optional bytes apn_registration_id = 202; // Does the user have notifications enabled for the given device address. - optional bool notification_enabled = 203 [ default = true ]; + optional bool notification_enabled = 203 [default = true]; // Used for device_address of DeviceInfo field 2, a Bluetooth Mac address for // the device (e.g., to be used with EasyUnlock) @@ -104,45 +105,45 @@ message GcmDeviceInfo { optional string device_manufacturer = 31; // Used to indicate which type of device this is. - optional DeviceType device_type = 32 [ default = ANDROID ]; + optional DeviceType device_type = 32 [default = ANDROID]; // Fields corresponding to screenlock type/features and hardware features // should be numbered in the 400 range. // Is this device using a secure screenlock (e.g., pattern or pin unlock) - optional bool using_secure_screenlock = 400 [ default = false ]; + optional bool using_secure_screenlock = 400 [default = false]; // Is auto-unlocking the screenlock (e.g., when at "home") supported? - optional bool auto_unlock_screenlock_supported = 401 [ default = false ]; + optional bool auto_unlock_screenlock_supported = 401 [default = false]; // Is auto-unlocking the screenlock (e.g., when at "home") enabled? - optional bool auto_unlock_screenlock_enabled = 402 [ default = false ]; + optional bool auto_unlock_screenlock_enabled = 402 [default = false]; // Does the device have a Bluetooth (classic) radio? - optional bool bluetooth_radio_supported = 403 [ default = false ]; + optional bool bluetooth_radio_supported = 403 [default = false]; // Is the Bluetooth (classic) radio on? - optional bool bluetooth_radio_enabled = 404 [ default = false ]; + optional bool bluetooth_radio_enabled = 404 [default = false]; // Does the device hardware support a mobile data connection? - optional bool mobile_data_supported = 405 [ default = false ]; + optional bool mobile_data_supported = 405 [default = false]; // Does the device support tethering? - optional bool tethering_supported = 406 [ default = false ]; + optional bool tethering_supported = 406 [default = false]; // Does the device have a BLE radio? - optional bool ble_radio_supported = 407 [ default = false ]; + optional bool ble_radio_supported = 407 [default = false]; // Is the device a "Pixel Experience" Android device? - optional bool pixel_experience = 408 [ default = false ]; + optional bool pixel_experience = 408 [default = false]; // Is the device running in the ARC++ container on a chromebook? - optional bool arc_plus_plus = 409 [ default = false ]; + optional bool arc_plus_plus = 409 [default = false]; // Is the value set in |using_secure_screenlock| reliable? On some Android // devices, the platform API to get the screenlock state is not trustworthy. // See b/32212161. - optional bool is_screenlock_state_flaky = 410 [ default = false ]; + optional bool is_screenlock_state_flaky = 410 [default = false]; // A list of multi-device software features supported by the device. repeated SoftwareFeature supported_software_features = 411; @@ -178,7 +179,7 @@ enum DeviceType { OSX = 5; } -// MultiDevice features which may be supported and enabled on a device. +// MultiDevice features which may be supported and enabled on a device. See enum SoftwareFeature { UNKNOWN_FEATURE = 0; BETTER_TOGETHER_HOST = 1; diff --git a/src/main/proto/securemessage.proto b/src/main/proto/securemessage.proto index 062e425..5118d35 100644 --- a/src/main/proto/securemessage.proto +++ b/src/main/proto/securemessage.proto @@ -1,22 +1,24 @@ -/* Copyright 2018 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 - * - * https://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. - */ +// Copyright 2020 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 +// +// https://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. + // Proto definitions for SecureMessage format syntax = "proto2"; package securemessage; + +option optimize_for = LITE_RUNTIME; option java_package = "com.google.security.cryptauth.lib.securemessage"; option java_outer_classname = "SecureMessageProto"; option objc_class_prefix = "SMSG"; @@ -56,7 +58,7 @@ message Header { optional bytes public_metadata = 6; // The length of some associated data this is not sent in this SecureMessage, // but which will be bound to the signature. - optional uint32 associated_data_length = 7 [ default = 0 ]; + optional uint32 associated_data_length = 7 [default = 0]; } message HeaderAndBody { diff --git a/src/main/proto/ukey.proto b/src/main/proto/ukey.proto index 155b279..327d8d3 100644 --- a/src/main/proto/ukey.proto +++ b/src/main/proto/ukey.proto @@ -1,21 +1,22 @@ -/* Copyright 2018 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 - * - * https://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. - */ +// Copyright 2020 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 +// +// https://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. + syntax = "proto2"; package securegcm; +option optimize_for = LITE_RUNTIME; option java_package = "com.google.security.cryptauth.lib.securegcm"; option java_outer_classname = "UkeyProto"; @@ -36,12 +37,12 @@ message Ukey2Message { message Ukey2Alert { enum AlertType { // Framing errors - BAD_MESSAGE = 1; // The message could not be deserialized - BAD_MESSAGE_TYPE = 2; // message_type has an undefined value - INCORRECT_MESSAGE = 3; // message_type received does not correspond to - // expected type at this stage of the protocol - BAD_MESSAGE_DATA = 4; // Could not deserialize message_data as per - // value inmessage_type + BAD_MESSAGE = 1; // The message could not be deserialized + BAD_MESSAGE_TYPE = 2; // message_type has an undefined value + INCORRECT_MESSAGE = 3; // message_type received does not correspond to + // expected type at this stage of the protocol + BAD_MESSAGE_DATA = 4; // Could not deserialize message_data as per + // value inmessage_type // ClientInit and ServerInit errors BAD_VERSION = 100; // version is invalid; server cannot find @@ -54,9 +55,9 @@ message Ukey2Alert { BAD_PUBLIC_KEY = 104; // The public key could not be parsed // Other errors - INTERNAL_ERROR = 200; // An internal error has occurred. error_message - // may contain additional details for logging - // and debugging. + INTERNAL_ERROR = 200; // An internal error has occurred. error_message + // may contain additional details for logging + // and debugging. } optional AlertType type = 1; |