diff --git a/.gitignore b/.gitignore index 63910de..b926917 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ .DS_Store -coniks_common/src/org/coniks/coniks_common/*.class -coniks_common/src/com/google/protobuf/*.java -coniks_server/src/org/coniks/coniks_server/*.class -coniks_test_client/src/org/coniks/coniks_test_client/*.class +target +bin +logs diff --git a/.travis.yml b/.travis.yml index f6f589d..53ca23e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,12 @@ env: global: secure: B5ZEHKFRa11V7e9JZwr4vGFSdo1lvnbxijd00mm41qbvwT5YFSMZhEQLRVlDmxhsqcc6guC84Q49LsY3/4rlzspHe8fkByY2sQUM3aXuK13/lJJT8CeDXxYAicWMPBLvybpt3ML1wXcbskQzv5C7oNLgkeMwvpd2zw5pYMV2dHwRhRkfsYgH7hzlVgCOMnPLHfPiDgjuQK6KJUr1qlO4Y9vmFsCiCi94fLHIxu+MsvFy3XRnnlTERTGQCeBD2GGHTH5wjiwTL0GHdKX/ntpODyWZAnbYs8OYsLuCq7QQHJDk4uBVCnMIj1zt6lwxa0iiz+uuvxnL6msSeF/BkIWG/yxRkBjdVtdJL0WBEIDmfzeEugdNFke1I2dsH68Fe+R2syUwIjJ654HSoLZ/xL9Dbnxo8wmix2cO46ictXN3WVNrWwB4KUV5N+aGW/hB0KRqSsO2iUmXqweifJz7qfWm20Y//pgtMtVTnZVTneiSCPucY1QWQmiOgC0jcseV+oIbpFjbYArxGhhPhqJqAWYhJeR/7uX872zMwPqpyHRF3y1XQ+C2xI9IWC2SqjinCsgUnZei1pu7A4Qd34Isd8uCICrLMu8JPe98+Dc+jksGrH/SgOcDI/pffnD2rk/ablNU7JY8yE2t5me9B6SAxOEOyle60i5WiRHcM+pZukBwvwU= -script: mvn test +script: + # TODO check style + - mvn test notifications: + # Email notifications are disabled to not annoy anybody. + # See http://about.travis-ci.org/docs/user/build-configuration/ to learn more + # about configuring notification recipients and more. email: false diff --git a/README.md b/README.md index e0a0933..7031ef1 100644 --- a/README.md +++ b/README.md @@ -9,10 +9,10 @@ http://coniks.org CONIKS is a key management system that provides transparency and privacy for end-user public keys. CONIKS protects end-to-end encrypted communications against malicious or compromised communication providers and surveillance by storing users' encryption keys in tamper-evident and publicly auditable key directories on the server side. This allows messaging clients to verify the identity of users automatically, and prevents malicious/compromised servers from hijacking secure communications without getting caught. ##Java Library -This software package serves as a Java library for the CONIKS system and includes reference implementations for the CONIKS server and client. The basic [CONIKS server](https://github.com/coniks-sys/coniks-java/tree/master/coniks_server) and simple [CONIKS test client](https://github.com/coniks-sys/coniks-java/tree/master/coniks_test_client) demonstrate the functionality of the system and the CONIKS protocols, so anyone interested in deploying CONIKS in their secure messaging system can then use this software package as a reference when implementing the service. This package also contains the [common message format definitions](https://github.com/coniks-sys/coniks-java/tree/master/coniks_common) that CONIKS servers and clients use to communicate. +This software package serves as a Java library for the CONIKS system and includes reference implementations for the CONIKS server and client. The basic [CONIKS server](https://github.com/coniks-sys/coniks-java/tree/master/coniks_server) and simple [CONIKS test client](https://github.com/coniks-sys/coniks-java/tree/master/coniks_test_client) demonstrate the functionality of the system and the CONIKS protocols, so anyone interested in deploying CONIKS in their secure messaging system can then use this software package as a reference when implementing the service. This package also contains the [common message format definitions](https://github.com/coniks-sys/coniks-java/tree/master/coniks_common) that CONIKS servers and clients use to communicate. ## Disclaimer -Please keep in mind that this CONIKS reference implementation is under active development. The repository may contain experimental features that aren't fully tested. We recommend using a [tagged release](https://github.com/coniks-sys/coniks-java/releases). +Please keep in mind that this CONIKS Java implementation is under active development. The repository may contain experimental features that aren't fully tested. We recommend using a [tagged release](https://github.com/coniks-sys/coniks-java/releases). ##Documentation [Read the package's Java API (javadoc)](https://coniks-sys.github.io/coniks-java/) diff --git a/coniks_common/README.md b/coniks_common/README.md index b6aa7e5..eaa616c 100644 --- a/coniks_common/README.md +++ b/coniks_common/README.md @@ -23,7 +23,7 @@ The coniks_common build is managed using Maven. (Instructions for building witho These instructions will install the ``coniks_common`` Maven artifact. ## Disclaimer -Please keep in mind that this CONIKS reference implementation is under active development. The repository may contain experimental features that aren't fully tested. We recommend using a [tagged release](https://github.com/coniks-sys/coniks-java/releases). +Please keep in mind that this CONIKS Java implementation is under active development. The repository may contain experimental features that aren't fully tested. We recommend using a [tagged release](https://github.com/coniks-sys/coniks-java/releases). ##Documentation [Read the common files' Java API (javadoc)](https://coniks-sys.github.io/coniks-java/org/coniks/coniks_common/package-summary.html) diff --git a/coniks_common/pom.xml b/coniks_common/pom.xml index 401a9b8..9838439 100644 --- a/coniks_common/pom.xml +++ b/coniks_common/pom.xml @@ -5,24 +5,19 @@ org.coniks coniks-java - 1.2-SNAPSHOT + 1.3-SNAPSHOT org.coniks.coniks_common coniks_common + 1.3-SNAPSHOT jar - 1.2-SNAPSHOT - coniks_common + + CONIKS [Common] http://coniks.org + Common message spec and encoding library for CONIKS. - - junit - junit - 3.8.1 - test - - com.google.protobuf protobuf-java diff --git a/coniks_server/README.md b/coniks_server/README.md index 1b3db1f..909f35a 100644 --- a/coniks_server/README.md +++ b/coniks_server/README.md @@ -11,18 +11,24 @@ The coniks_server build is managed using Maven. (Instructions for building witho 1) Install Apache Maven, if you don't have it. Visit the [Maven downloads page](https://maven.apache.org/download.cgi) for details. 2) Install the library into your Maven repository: + ```$ mvn install``` 3) If you don't use Maven to manage your own build, you can build a .jar file to use: + ```$ mvn package``` These instructions will install the ``coniks_server`` Maven artifact. +The build configuration for coniks_server assembles all dependencies, +and includes them in the generated .jar file, so you can run the server +only using the coniks_server .jar file. ##Using the Server -The CONIKS server has two operating modes: Test Mode and Full Operation. -Running the server in test mode allows you to still test all CONIKS protocols and operations, -but requires less setup as you can simply use the default configuration in the included *config* file. +The CONIKS server has two operating modes: Test Mode and Full Operation. +Running the server in test mode allows you to still test all CONIKS +protocols and operations, but requires less setup as you can simply use +the default configuration in the included *config* file. **Note:** You must be running the test client in the same operating mode. ### Setup @@ -32,21 +38,20 @@ Run the following command, using the default settings if setting up test mode: ``` keytool -genkeypair -alias -keyalg RSA -validity 365 -keystore ``` -Follow the prompts and enter suitable information. Make sure to enter legitimate information if running -in full operation mode. Notice that the key pair is set to expire within 365 days here, but you may -change this setting when running this command. -- Full operation mode only: Generate self-signed certificates for SSL/TLS communication, -if you don't already have certs for your server: -Make sure the alias and the keystore used in this step match the values used when generating the -signing key pair in the previous step. +Follow the prompts and enter suitable information. Make sure to enter +legitimate information if running +in full operation mode. Notice that the key pair is set to expire within 365 days here, but you may change this setting when running this command. +- Full operation mode only: Generate self-signed certificates for SSL/TLS +communication, if you don't already have certs for your server: +Make sure the alias and the keystore used in this step match the values used when generating the signing key pair in the previous step. ``` keytool -export -alias -keystore -rfc -file .cer keytool -import -alias -file .cer -keystore ``` - Set all of the configurations in the config file: -Defaults are already set, except for the absolute path to the keystore generated in the -previous step along with its password. You'll have to set these using the format -described below. +Defaults are already set, except for the absolute path to the +keystore generated in the previous step along with its password. +You'll have to set these using the format described below. You may write your own config file, but it must follow the following format: ``` (must be the same in the CONIKS client config) @@ -58,19 +63,20 @@ You may write your own config file, but it must follow the following format: / (not used in test mode) (not used for test mode) ``` -Especially if you're running in full operating mode, make sure the config file is only readable -by the users allowed to run the CONIKS server to protect your keystore password. +Especially if you're running in full operating mode, make sure the +config file is only readable by the users allowed to run the CONIKS +server to protect your keystore password. - Set all of the configs in the run script *coniks_server.sh*: Defaults are already set, but you may change the following variables: -```CLASS_DEST``` if you used a different classpath when building the server. +```CLASS_DEST``` if you've changed configurations such as the artifactID or version in the server's pom.xml file before building. ```CONIKS_SERVERCONFIG``` if you're using a different config file ```CONIKS_SERVERLOGS``` to store the server logs somewhere other than a *logs* directory ###Running -We provide a run script for the CONIKS server *coniks_server.sh*, which allows you to run the server in -full operation mode and test mode. +We provide a run script for the CONIKS server *coniks_server.sh*, +which allows you to run the server in full operation mode and test mode. -The run script supports four commands: +The run script supports four commands: - ```start```: start the server in full operation mode (runs in background). - ```test```: start the server in test mode (runs in foreground). - ```stop```: stop the server. @@ -80,7 +86,7 @@ For example, to start the server in full operation mode, use Analogously to test and stop the server, and remove the logs. ## Disclaimer -Please keep in mind that this CONIKS reference implementation is under active development. The repository may contain experimental features that aren't fully tested. We recommend using a [tagged release](https://github.com/coniks-sys/coniks-java/releases). +Please keep in mind that this CONIKS Java implementation is under active development. The repository may contain experimental features that aren't fully tested. We recommend using a [tagged release](https://github.com/coniks-sys/coniks-java/releases). ##Documentation [Read the server's Java API (javadoc)](https://coniks-sys.github.io/coniks-java/org/coniks/coniks_server/package-summary.html) diff --git a/coniks_server/coniks_server.sh b/coniks_server/coniks_server.sh index 38a4dd7..2ed1a3f 100755 --- a/coniks_server/coniks_server.sh +++ b/coniks_server/coniks_server.sh @@ -4,37 +4,38 @@ # All rights reserved. # # Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are +# modification, are permitted provided that the following conditions are # met: -# * Redistributions of source code must retain the above copyright +# * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the # distribution. # * Neither the name of Princeton University nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. ## Runs or stops a CONIKS server instance # Set all the configs here -CLASS_DEST="bin" #change this if you built the server somewhere else +# mvn builds our jar with dependencies +CLASS_DEST="./target/coniks_server-1.3-SNAPSHOT.jar" CLASSPATH="-cp $CLASS_DEST" SERVER_BIN="org.coniks.coniks_server.ConiksServer" CONIKS_SERVERCONFIG="config" #change this if using a different config file @@ -100,7 +101,7 @@ elif [ "$CMD" = "stop" ]; then fi echo "Stopping the CONIKS server." - + kill `cat $CONIKS_SERVERLOGS/pid` >/dev/null rm -f $CONIKS_SERVERLOGS/pid @@ -112,7 +113,7 @@ elif [ "$CMD" = "clean" ]; then # write to one of the logs if [ `ps ax | grep -c $SERVER_BIN` -gt 1 ]; then echo "Stopping the CONIKS server." - + kill `cat $CONIKS_SERVERLOGS/pid` >/dev/null rm -f $CONIKS_SERVERLOGS/pid fi diff --git a/coniks_server/pom.xml b/coniks_server/pom.xml index 0b9bd16..8f4e9d3 100644 --- a/coniks_server/pom.xml +++ b/coniks_server/pom.xml @@ -5,28 +5,31 @@ org.coniks coniks-java - 1.2-SNAPSHOT + 1.3-SNAPSHOT org.coniks.coniks_server coniks_server + 1.3-SNAPSHOT jar - 1.2-SNAPSHOT - coniks_server + + CONIKS [Reference Server] http://coniks.org + CONIKS server library and reference implementation. + - junit - junit - 3.8.1 - test + org.coniks.coniks_common + coniks_common + 1.3-SNAPSHOT + compile - org.coniks.coniks_common - coniks_common - 1.2-SNAPSHOT + org.coniks.crypto + coniks-crypto + 1.3-SNAPSHOT compile @@ -48,4 +51,26 @@ UTF-8 + + + + + maven-assembly-plugin + + + package + + single + + + + + + jar-with-dependencies + + false + + + + diff --git a/coniks_server/src/main/java/org/coniks/coniks_server/ConiksServer.java b/coniks_server/src/main/java/org/coniks/coniks_server/ConiksServer.java index 969c32f..550ac64 100644 --- a/coniks_server/src/main/java/org/coniks/coniks_server/ConiksServer.java +++ b/coniks_server/src/main/java/org/coniks/coniks_server/ConiksServer.java @@ -1,38 +1,40 @@ /* Copyright (c) 2015-16, Princeton University. All rights reserved. - + Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are + modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the distribution. * Neither the name of Princeton University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.coniks.coniks_server; +// coniks-java imports +import org.coniks.crypto.Util; import org.coniks.coniks_common.MsgType; import org.coniks.coniks_common.C2SProtos.Registration; import org.coniks.coniks_common.C2SProtos.CommitmentReq; @@ -88,27 +90,27 @@ public class ConiksServer{ private static long initEpoch; - /** Initialize the directory: get the latest root node from the + /** Initialize the directory: get the latest root node from the * database (if using one) and update the directory internally (i.e. build the hash tree) * Because users are stored in lexicographic order, we can simply load them all at once. * N.B. Designed for few restarts in mind. */ private static RootNode initDirectory(){ - PriorityQueue> initUsers = - new PriorityQueue>( - 16384, new ServerUtils.PrefixComparator()); + PriorityQueue> initUsers = + new PriorityQueue>( + 16384, new ServerUtils.PrefixComparator()); // At this point, if we're using a DB, we want to check if we already have // a commitment history stored in the DB // if so, retrieve the latest commitment and root node stored in the DB - + RootNode initRoot = TreeBuilder.copyExtendTree(null, initUsers); - + initUsers.clear(); return initRoot; } - + /** Configures the server and begins listening for * incoming connections from CONIKS clients. *

@@ -116,7 +118,7 @@ private static RootNode initDirectory(){ * {@code ./coniks_server.sh } */ public static void main(String[] args){ - + if (args.length != NUM_ARGS) { System.out.println("Need "+(NUM_ARGS-1)+" arguments: CONIKS_SERVERCONFIG, and CONIKS_SERVERLOGS"); System.out.println("The run script may expect these to be passed as env vars, make sure to export these before running the run script again."); @@ -134,7 +136,7 @@ public static void main(String[] args){ if (!configFile.exists() || !logDir.isDirectory()) { throw new FileNotFoundException(); } - + String opMode = args[2]; if (opMode.equalsIgnoreCase("full")) { isFullOp = true; @@ -155,12 +157,12 @@ else if (opMode.equalsIgnoreCase("test")) { System.out.println("The path you entered for CONIKS_SERVERCONFIG or CONIKS_SERVERLOGS doesn't exist."); System.exit(-1); } - + // false indicates an error, so exit if (!ServerConfig.readServerConfig(configFile, isFullOp)) { System.exit(-1); } - + // set some more configs initEpoch = ServerConfig.getStartupTime(); MsgHandlerLogger.setup(logPath+"/msg-handler-%g"); @@ -191,30 +193,30 @@ else if (opMode.equalsIgnoreCase("test")) { } // init the history - if (!ServerHistory.initHistory(initRoot, initEpoch, 0, - new byte[ServerUtils.HASH_SIZE_BYTES])) { + if (!ServerHistory.initHistory(initRoot, initEpoch, 0, + new byte[Util.HASH_SIZE_BYTES])) { ServerUtils.printStatusMsg(true, "Error initializing the history"); System.exit(-1); } - + EpochTimerTask epochSnapshotTaker = new EpochTimerTask(); - - ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); - scheduler.scheduleWithFixedDelay(epochSnapshotTaker, - ServerConfig.getEpochInterval(), - ServerConfig.getEpochInterval(), - TimeUnit.MILLISECONDS); + + ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); + scheduler.scheduleWithFixedDelay(epochSnapshotTaker, + ServerConfig.getEpochInterval(), + ServerConfig.getEpochInterval(), + TimeUnit.MILLISECONDS); ServerMessaging.listenForRequests(isFullOp); - + } - + /** Implements a TimerTask that updates the STR history every epoch. */ private static class EpochTimerTask implements Runnable { public void run() { - TimerLogger.log("Timer task started."); + TimerLogger.log("Timer task started."); RootNode nextRoot = DirectoryOps.updateDirectory(); // check that we got a good first tree @@ -253,7 +255,7 @@ public void run() { ServerUtils.printStatusMsg(false, "Directory update successful. Next epoch: "+nextEpoch); } } - + } - + } diff --git a/coniks_server/src/main/java/org/coniks/coniks_server/KeyChange.java b/coniks_server/src/main/java/org/coniks/coniks_server/KeyChange.java index 29f0138..7b9941e 100644 --- a/coniks_server/src/main/java/org/coniks/coniks_server/KeyChange.java +++ b/coniks_server/src/main/java/org/coniks/coniks_server/KeyChange.java @@ -36,9 +36,13 @@ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, import java.security.interfaces.DSAPublicKey; import java.util.Arrays; +// coniks-java imports +import org.coniks.crypto.*; + /** Implements a key change operation. * *@author Michael Rochlin + *@author Marcela S. Melara (melara@cs.princeton.edu) */ public class KeyChange extends Operation { private String newKeyData; @@ -97,10 +101,21 @@ public boolean canChangeInfo(UserLeafNode uln) { ServerLogger.error("Tried to make unsigned KeyChange but wasn't allowed"); return false; } - if (!uln.allowsUnsignedKeychange() - && !SignatureOps.verifySigFromDSA(msg, sig, uln.getChangeKey())) { - ServerLogger.error("Requires that key changes be signed, but the signature was invalid"); - return false; + if (!uln.allowsUnsignedKeychange()) { + + boolean res = false; + + try { + res = Signing.dsaVerify(uln.getChangeKey(), msg, sig); + } + catch (Exception e) { + ServerLogger.error("[KeyChange] "+e.getMessage()); + } + + if(!res) { + ServerLogger.error("Requires that key changes be signed, but the signature was invalid"); + return false; + } } return true; } diff --git a/coniks_server/src/main/java/org/coniks/coniks_server/KeyOps.java b/coniks_server/src/main/java/org/coniks/coniks_server/KeyOps.java index 446d91a..f1b0cfd 100644 --- a/coniks_server/src/main/java/org/coniks/coniks_server/KeyOps.java +++ b/coniks_server/src/main/java/org/coniks/coniks_server/KeyOps.java @@ -1,33 +1,33 @@ /* Copyright (c) 2015-16, Princeton University. All rights reserved. - + Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are + modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the distribution. * Neither the name of Princeton University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ @@ -45,7 +45,7 @@ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, import org.coniks.coniks_common.C2SProtos.DSAPublicKeyProto; -/** Implements all encryption-key related operations that a +/** Implements all encryption-key related operations that a * CONIKS server must perform. * Current encryption/signing algorithm used: RSA with SHA-256. * @@ -70,14 +70,14 @@ public static RSAPrivateKey loadSigningKey(){ // get user password and file input stream char[] ks_password = ServerConfig.getKeystorePassword().toCharArray(); - + FileInputStream fis = null; - + fis = new FileInputStream(ServerConfig.getKeystorePath()); ks.load(fis, ks_password); if(ks.isKeyEntry(ServerConfig.getName())){ - KeyStore.ProtectionParameter protParam = + KeyStore.ProtectionParameter protParam = new KeyStore.PasswordProtection(ks_password); KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry) @@ -92,13 +92,13 @@ public static RSAPrivateKey loadSigningKey(){ } catch(IOException e){ TimerLogger.error("KeyOps:loadSigningKey: Problem loading the keystore"); - } + } catch(NoSuchAlgorithmException e){ TimerLogger.error("KeyOps:loadSigningKey: Problem with integrity check algorithm"); } catch(CertificateException e){ TimerLogger.error("KeyOps:loadSigningKey: Problem with the cert(s) in keystore"); - } + } catch(KeyStoreException e){ TimerLogger.error("KeyOps:loadSigningKey: Problem getting Keystore instance"); } @@ -111,7 +111,7 @@ public static RSAPrivateKey loadSigningKey(){ /** Load the given server {@code keyOwner}'s public key from the truststore * indicated in this server's configuration {@code config}. * - *@return The {@code keyOwner}'s public RSA key, or {@code null} in + *@return The {@code keyOwner}'s public RSA key, or {@code null} in * the case of an Exception. */ public static RSAPublicKey loadPublicKey(String keyOwner){ @@ -122,20 +122,24 @@ public static RSAPublicKey loadPublicKey(String keyOwner){ try{ ks = KeyStore.getInstance(KeyStore.getDefaultType()); - char[] ts_password = ServerConfig.getTruststorePassword().toCharArray(); - + char[] ts_password = + ServerConfig.getTruststorePassword().toCharArray(); + FileInputStream fis = null; - + fis = new FileInputStream(ServerConfig.getTruststorePath()); ks.load(fis, ts_password); if(ks.isKeyEntry(keyOwner)){ - KeyStore.ProtectionParameter protParam = + KeyStore.ProtectionParameter protParam = new KeyStore.PasswordProtection(ts_password); - KeyStore.TrustedCertificateEntry pkEntry = (KeyStore.TrustedCertificateEntry) + KeyStore.TrustedCertificateEntry pkEntry = + (KeyStore.TrustedCertificateEntry) ks.getEntry(keyOwner, protParam); - publicKey = (RSAPublicKey)pkEntry.getTrustedCertificate().getPublicKey(); + + publicKey = + (RSAPublicKey)pkEntry.getTrustedCertificate().getPublicKey(); } else{ throw new CertificateException(); @@ -145,13 +149,13 @@ public static RSAPublicKey loadPublicKey(String keyOwner){ } catch(IOException e){ ServerLogger.error("KeyOps:loadPublicKey: Problem loading the keystore"); - } + } catch(NoSuchAlgorithmException e){ ServerLogger.error("KeyOps:loadPublicKey: Problem with integrity check algorithm"); } catch(CertificateException e){ ServerLogger.error("KeyOps:loadPublicKey: Problem with the cert(s) in keystore"); - } + } catch(KeyStoreException e){ ServerLogger.error("KeyOps:loadPublicKey: Problem getting Keystore instance"); } @@ -165,9 +169,13 @@ public static RSAPublicKey loadPublicKey(String keyOwner){ * {@code g} and {@code y} parameters. * *@return the DSAPublicKey, or {@code null} in case of an error. + *@deprecated Replaced with {@link org.coniks.crypto.Keys#getDSAPublicFromParams(BigInteger, BigInteger, BigInteger, BigInteger)}. */ - public static DSAPublicKey makeDSAPublicKeyFromParams(BigInteger p, BigInteger q, - BigInteger g, BigInteger y) { + @Deprecated + public static DSAPublicKey makeDSAPublicKeyFromParams(BigInteger p, + BigInteger q, + BigInteger g, + BigInteger y) { try { KeyFactory keyFactory = KeyFactory.getInstance("DSA"); KeySpec publicKeySpec = new DSAPublicKeySpec(y, p, q, g); @@ -187,7 +195,8 @@ public static DSAPublicKey makeDSAPublicKeyFromParams(BigInteger p, BigInteger q /** Converts a {@link DSAPublicKeyProto} to a {@link DSAPublicKey}. * - *@param pkProto the DSA public key protobuf to convert into a DSAPublicKey. + *@param pkProto the DSA public key protobuf to convert into a + * DSAPublicKey. *@return the DSAPublicKey, or {@code null} in case of an error. */ public static DSAPublicKey makeDSAPublicKeyFromProto(DSAPublicKeyProto pkProto) { diff --git a/coniks_server/src/main/java/org/coniks/coniks_server/RequestHandler.java b/coniks_server/src/main/java/org/coniks/coniks_server/RequestHandler.java index b9d646a..b2e02c9 100644 --- a/coniks_server/src/main/java/org/coniks/coniks_server/RequestHandler.java +++ b/coniks_server/src/main/java/org/coniks/coniks_server/RequestHandler.java @@ -45,6 +45,9 @@ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, import com.google.protobuf.AbstractMessage; import com.google.protobuf.ByteString; +// coniks-java imports +import org.coniks.crypto.*; + import org.coniks.coniks_common.MsgType; import org.coniks.coniks_common.C2SProtos.Registration; import org.coniks.coniks_common.C2SProtos.CommitmentReq; @@ -302,7 +305,18 @@ private synchronized void handleSignedULNChangeProto(SignedULNChangeReq signedRe byte[] reqMsg = changeReq.toByteArray(); byte[] sig = signedReq.getSig().toByteArray(); - if (!SignatureOps.verifySigFromDSA(reqMsg, sig, publicChangeKey)) { + + boolean res = false; + + try { + res = Signing.dsaVerify(publicChangeKey, reqMsg, sig); + } + // let's catch the panic here and log it + catch (Exception e) { + ServerLogger.error("[RequestHandler] "+e.getMessage()); + } + + if (!res) { MsgHandlerLogger.log("Failed to verify message"); MsgHandlerLogger.log("Failed sig said\n" + Arrays.toString(sig)); ServerMessaging.sendSimpleResponseProto(ServerErr.SIGNED_CHANGE_VERIF_ERR, clientSocket); diff --git a/coniks_server/src/main/java/org/coniks/coniks_server/ServerMessaging.java b/coniks_server/src/main/java/org/coniks/coniks_server/ServerMessaging.java index a9a41b8..70f5138 100644 --- a/coniks_server/src/main/java/org/coniks/coniks_server/ServerMessaging.java +++ b/coniks_server/src/main/java/org/coniks/coniks_server/ServerMessaging.java @@ -1,33 +1,33 @@ /* Copyright (c) 2015-16, Princeton University. All rights reserved. - + Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are + modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the distribution. * Neither the name of Princeton University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ @@ -37,12 +37,15 @@ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, import java.net.*; import java.io.*; import java.util.ArrayList; +import java.security.NoSuchAlgorithmException; import com.google.protobuf.AbstractMessage; import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; import org.javatuples.*; +// coniks-java imports +import org.coniks.crypto.Util; import org.coniks.coniks_common.*; import org.coniks.coniks_common.C2SProtos.*; import org.coniks.coniks_common.UtilProtos.*; @@ -55,20 +58,20 @@ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, */ public class ServerMessaging { - /** Sends a simple server response protobuf based on the + /** Sends a simple server response protobuf based on the * result (often an error) of a client request. * - *@param reqResult the result of the request + *@param reqResult the result of the request *@param socket the client socket to which to send the message */ public static synchronized void sendSimpleResponseProto(int reqResult, Socket socket){ MsgHandlerLogger.log("Sending simple server response... "); - + ServerResp respMsg = buildServerRespMsg(reqResult); - sendMsgProto(MsgType.SERVER_RESP, respMsg, socket); + sendMsgProto(MsgType.SERVER_RESP, respMsg, socket); } - + /** Sends the signed tree root protobuf returned for a client's signed tree root request. * *@param str the signed tree root to send @@ -76,12 +79,12 @@ public static synchronized void sendSimpleResponseProto(int reqResult, Socket so */ public static synchronized void sendCommitmentProto(SignedTreeRoot str, Socket socket){ MsgHandlerLogger.log("Sending commitment response... "); - + Commitment comm = buildCommitmentMsg(str); - + sendMsgProto(MsgType.COMMITMENT, comm, socket); } - + /** Sends a basic registration response protobuf for a new name-to-key mapping * registration. *@param regEpoch the epoch at which the mapping will be registered in the directory @@ -91,11 +94,11 @@ public static synchronized void sendCommitmentProto(SignedTreeRoot str, Socket s public static synchronized void sendRegistrationRespProto(long regEpoch, int epochInterval, Socket socket){ MsgHandlerLogger.log("Sending registration response... "); - + RegistrationResp regResp = buildRegistrationRespMsg(regEpoch, epochInterval); sendMsgProto(MsgType.REGISTRATION_RESP, regResp, socket); } - + /** Sends the authentication path protobuf returned for a client's key lookup. * *@param uln the key directory entry for which to send the authentication path @@ -104,11 +107,11 @@ public static synchronized void sendRegistrationRespProto(long regEpoch, int epo */ public static synchronized void sendAuthPathProto(UserLeafNode uln, RootNode root, Socket socket){ MsgHandlerLogger.log("Sending authentication path response... "); - + AuthPath authPath = buildAuthPathMsg(uln, root); sendMsgProto(MsgType.AUTH_PATH, authPath, socket); } - + /** Sends any protobuf message {@code msg} of type {@code msgType} * to the given socket. */ @@ -132,10 +135,10 @@ private static synchronized void sendMsgProto (int msgType, AbstractMessage msg, CommonMessaging.close(dout); } - } + } /* Message building functions */ - + // create the simple server response message private static synchronized ServerResp buildServerRespMsg(int respType){ ServerResp.Builder respMsg = ServerResp.newBuilder(); @@ -157,20 +160,28 @@ private static synchronized ServerResp buildServerRespMsg(int respType){ break; default: respMsg.setMessage(ServerResp.Message.SERVER_ERR); - break; + break; } return respMsg.build(); } - + // create the commitment response message - private static synchronized Commitment buildCommitmentMsg(SignedTreeRoot str){ - + private static synchronized Commitment buildCommitmentMsg(SignedTreeRoot str){ + Commitment.Builder commMsg = Commitment.newBuilder(); byte[] rootBytes = ServerUtils.getRootNodeBytes(str.getRoot()); - byte[] rootHashBytes = ServerUtils.hash(rootBytes); - - Hash.Builder rootHash = Hash.newBuilder(); - if(rootHashBytes.length != ServerUtils.HASH_SIZE_BYTES){ + byte[] rootHashBytes = null; + + try { + rootHashBytes = Util.digest(rootBytes); + } + catch(NoSuchAlgorithmException e) { + ServerLogger.error("[ServerMessagging] "+e.getMessage()); + return null; + } + + Hash.Builder rootHash = Hash.newBuilder(); + if(rootHashBytes.length != Util.HASH_SIZE_BYTES){ MsgHandlerLogger.error("Bad length of root hash: "+rootHashBytes.length); return null; } @@ -181,18 +192,18 @@ private static synchronized Commitment buildCommitmentMsg(SignedTreeRoot str){ commMsg.setSignature(ByteString.copyFrom(str.getSignature())); return commMsg.build(); } - + // create the registration response message - private static synchronized RegistrationResp buildRegistrationRespMsg(long initEpoch, int epochInterval){ - + private static synchronized RegistrationResp buildRegistrationRespMsg(long initEpoch, int epochInterval){ + RegistrationResp.Builder regRespMsg = RegistrationResp.newBuilder(); regRespMsg.setInitEpoch(initEpoch); regRespMsg.setEpochInterval(epochInterval); return regRespMsg.build(); } - + // create the commitment response message - private static synchronized AuthPath buildAuthPathMsg(UserLeafNode uln, RootNode root){ + private static synchronized AuthPath buildAuthPathMsg(UserLeafNode uln, RootNode root){ return TransparencyOps.generateAuthPathProto(uln, root); } @@ -205,17 +216,17 @@ private static synchronized AuthPath buildAuthPathMsg(UserLeafNode uln, RootNode * indicated by the client. */ public static synchronized AbstractMessage receiveMsgProto(Socket socket) { - + DataInputStream din = null; try { din = new DataInputStream(socket.getInputStream()); - + // get the message type of the message and read in the stream int msgType = din.readUnsignedByte(); - + if (msgType == MsgType.REGISTRATION){ Registration reg = Registration.parseDelimitedFrom(din); - + if(!reg.hasBlob() || !reg.hasChangeKey() || !reg.hasAllowsUnsignedKeychange() || !reg.hasAllowsPublicLookup()) { MsgHandlerLogger.log("Malformed registration message"); @@ -226,8 +237,8 @@ public static synchronized AbstractMessage receiveMsgProto(Socket socket) { } else if (msgType == MsgType.KEY_LOOKUP) { KeyLookup lookup = KeyLookup.parseDelimitedFrom(din); - - if(!lookup.hasName() || !lookup.hasEpoch() || + + if(!lookup.hasName() || !lookup.hasEpoch() || lookup.getEpoch() <= 0){ MsgHandlerLogger.log("Malformed key lookup"); } @@ -237,7 +248,7 @@ else if (msgType == MsgType.KEY_LOOKUP) { } else if (msgType == MsgType.COMMITMENT_REQ) { CommitmentReq commReq = CommitmentReq.parseDelimitedFrom(din); - + if (!commReq.hasType() || !commReq.hasEpoch() || commReq.getEpoch() <= 0) { MsgHandlerLogger.log("Malformed commitment request message"); } @@ -274,27 +285,27 @@ else if (msgType == MsgType.SIGNED_ULNCHANGE_REQ) { catch (IOException e) { MsgHandlerLogger.error("receiving data from client"); } - + // unexpected message type from the client return null; } /* Functions for handling the lower-level communication with the client */ - /** Listens for incoming requests. Uses an SSL connection if the server is running in + /** Listens for incoming requests. Uses an SSL connection if the server is running in * full operating mode. * - *@param isFullOp indicates whether the client is operating in full mode + *@param isFullOp indicates whether the client is operating in full mode * or in testing mode */ public static void listenForRequests (boolean isFullOp) { ServerSocket s = null; - + try{ if (isFullOp) { - SSLServerSocketFactory sslSrvFact = + SSLServerSocketFactory sslSrvFact = (SSLServerSocketFactory)SSLServerSocketFactory.getDefault(); s =(SSLServerSocket)sslSrvFact.createServerSocket(ServerConfig.getPort()); } @@ -302,18 +313,18 @@ public static void listenForRequests (boolean isFullOp) { s = new ServerSocket(ServerConfig.getPort()); System.out.println("Listening for connections on port "+ServerConfig.getPort()+"..."); - } + } MsgHandlerLogger.log("Listening for connections on port "+ServerConfig.getPort()+"..."); - + // loop to listen for requests while(true){ Socket c = s.accept(); // closing done by thread - + MsgHandlerLogger.log("Server accepted new connection."); RequestHandler th; - + if (isFullOp) { th = new RequestHandler((SSLSocket)c); } @@ -322,13 +333,13 @@ public static void listenForRequests (boolean isFullOp) { } th.start(); - + } } catch(IOException e){ MsgHandlerLogger.error("hello: "+e.getMessage()); } - + } - + } diff --git a/coniks_server/src/main/java/org/coniks/coniks_server/ServerUtils.java b/coniks_server/src/main/java/org/coniks/coniks_server/ServerUtils.java index 8eb7ef7..68fb9d9 100644 --- a/coniks_server/src/main/java/org/coniks/coniks_server/ServerUtils.java +++ b/coniks_server/src/main/java/org/coniks/coniks_server/ServerUtils.java @@ -1,33 +1,33 @@ /* Copyright (c) 2015-16, Princeton University. All rights reserved. - + Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are + modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the distribution. * Neither the name of Princeton University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ @@ -61,17 +61,26 @@ public class ServerUtils{ /** The size of the Merkle tree hashes in bits. * Current hashing algorithm: SHA-256 + * + *@deprecated Moved to {@link org.coniks.crypto.Util}. */ - public static final int HASH_SIZE_BITS = 256; + @Deprecated + public static final int HASH_SIZE_BITS = 256; /** The size of the Merkle tree hashes in bytes. * Current hashing algorithm: SHA-256 + * + *@deprecated Moved to {@link org.coniks.crypto.Util}. */ + @Deprecated public static final int HASH_SIZE_BYTES = HASH_SIZE_BITS/8; - + /** The size of the CONIKS server's STR signatures in bytes. * Server signature scheme: RSAwithSHA256. + * + *@deprecated Moved to {@link org.coniks.crypto.Signing}. */ + @Deprecated public static final int SIG_SIZE_BYTES = 256; /** The maximum number of bytes logged per log file. @@ -84,7 +93,7 @@ public class ServerUtils{ private static final char[] hexArray = "0123456789ABCDEF".toCharArray(); - /** Prints server status and error messages. + /** Prints server status and error messages. * Used primarily for testing mode. * *@param isErr indicates whether this is an error message @@ -103,25 +112,27 @@ public static void printStatusMsg (boolean isErr, String msg) { * Current hashing algorithm: SHA-256. * *@return The hash as a {@code byte[]} or null in case of an error. + *@deprecated Replaced with {@link org.coniks.crypto.Util#digest(byte[])} */ + @Deprecated public static byte[] hash(byte[] input){ - try{ - MessageDigest md = MessageDigest.getInstance("SHA-256"); - - byte[] digest = md.digest(input); + try{ + MessageDigest md = MessageDigest.getInstance("SHA-256"); + + byte[] digest = md.digest(input); - return digest; + return digest; - } - catch(NoSuchAlgorithmException e){ - ServerLogger.error("SHA-256 is not a valid algorithm for some reason"); - } + } + catch(NoSuchAlgorithmException e){ + ServerLogger.error("SHA-256 is not a valid algorithm for some reason"); + } - return null; // should never get here + return null; // should never get here } - /** Generates the cryptographic hash of the {@code left} + /** Generates the cryptographic hash of the {@code left} * and {@code right} subtree hashes of a Merkle tree node. * This is really just a wrapper around {@link ServerUtils#hash(byte[])}. * @@ -129,27 +140,27 @@ public static byte[] hash(byte[] input){ */ public static byte[] hashChildren(byte[] left, byte[] right){ - byte[] childrenBytes = new byte[left.length+right.length]; - - ByteBuffer arr = ByteBuffer.wrap(childrenBytes); - arr.put(left); - arr.put(right); + byte[] childrenBytes = new byte[left.length+right.length]; - byte[] children = arr.array(); + ByteBuffer arr = ByteBuffer.wrap(childrenBytes); + arr.put(left); + arr.put(right); - try{ - MessageDigest md = MessageDigest.getInstance("SHA-256"); - - byte[] digest = md.digest(children); + byte[] children = arr.array(); - return digest; + try{ + MessageDigest md = MessageDigest.getInstance("SHA-256"); - } - catch(NoSuchAlgorithmException e){ - TimerLogger.error("SHA-256 is not a valid algorithm for some reason"); - } + byte[] digest = md.digest(children); - return null; // should never get here + return digest; + + } + catch(NoSuchAlgorithmException e){ + TimerLogger.error("SHA-256 is not a valid algorithm for some reason"); + } + + return null; // should never get here } @@ -179,12 +190,12 @@ public static byte[] strToBytes (String str) { * index using a verifiable unpredicctable function (VUF). * Current VUF algorithm: SHA-256. * - *@return The {@code byte[]} representation of the + *@return The {@code byte[]} representation of the * lookup index. */ public static byte[] unameToIndex (String uname){ - byte[] b = strToBytes(uname); - return ServerUtils.hash(b); + byte[] b = strToBytes(uname); + return ServerUtils.hash(b); } /** Converts a long {@code val} into an array of bytes. @@ -193,7 +204,7 @@ public static byte[] unameToIndex (String uname){ */ public static byte[] longToBytes(long val) { byte[] byteArr = new byte[8]; - + for(int i = 0; i < 8; i++) { byte nextByte = (byte)((val >> i*8) & 0xff); byteArr[i] = nextByte; @@ -202,16 +213,16 @@ public static byte[] longToBytes(long val) { return byteArr; } - /** Finds the byte in the byte array {@code arr} + /** Finds the byte in the byte array {@code arr} * at offset {@code offset}, and determines whether it is 1 or 0. * *@return true if the nth bit is 1, false otherwise. */ public static boolean getNthBit(byte[] arr, int offset){ - int arrayOffset = offset / 8; - int bitOfByte = offset % 8; - int maskedBit = arr[arrayOffset] & (1 << (7 - bitOfByte)); - return (maskedBit != 0); + int arrayOffset = offset / 8; + int bitOfByte = offset % 8; + int maskedBit = arr[arrayOffset] & (1 << (7 - bitOfByte)); + return (maskedBit != 0); } /** Gets the 16-bit prefix of a byte array {@code arr}. @@ -220,7 +231,7 @@ public static boolean getNthBit(byte[] arr, int offset){ * of the array is less than 2 bytes. */ public static byte[] getPrefixBytes(byte[] arr){ - byte[] out = new byte[2]; + byte[] out = new byte[2]; if (arr.length < 2) { out[0] = 0; @@ -230,7 +241,7 @@ public static byte[] getPrefixBytes(byte[] arr){ out[0] = arr[0]; out[1] = arr[1]; } - return out; + return out; } /** Compares two byte buffers for byte-by-byte equality. @@ -242,14 +253,14 @@ public static boolean compareByteBuffers(byte[] buf1, byte[] buf2){ return false; } - for(int i = 0; i < buf1.length; i++){ - if(buf1[i] != buf2[i]){ - return false; - } - } - return true; + for(int i = 0; i < buf1.length; i++){ + if(buf1[i] != buf2[i]){ + return false; + } + } + return true; } - + /** Converts an RSAPublicKey {@code pub} to a hashable array of bytes. * This function is currently unused. @@ -257,16 +268,16 @@ public static boolean compareByteBuffers(byte[] buf1, byte[] buf2){ *@return The {@code byte[]} containing the serialized RSAPublicKey. */ public static byte[] convertRSAPubKey(RSAPublicKey pub){ - byte[] exp = pub.getPublicExponent().toByteArray(); - byte[] mod = pub.getModulus().toByteArray(); + byte[] exp = pub.getPublicExponent().toByteArray(); + byte[] mod = pub.getModulus().toByteArray(); - byte[] pubKey = new byte[exp.length+mod.length]; + byte[] pubKey = new byte[exp.length+mod.length]; - ByteBuffer arr = ByteBuffer.wrap(pubKey); - arr.put(exp); - arr.put(mod); + ByteBuffer arr = ByteBuffer.wrap(pubKey); + arr.put(exp); + arr.put(mod); - return arr.array(); + return arr.array(); } /** Converts an DSAPublicKey {@code pub} to a hashable array of bytes. @@ -275,20 +286,20 @@ public static byte[] convertRSAPubKey(RSAPublicKey pub){ *@return The {@code byte[]} containing the serialized DSAPublicKey. */ public static byte[] convertDSAPubKey(DSAPublicKey pub){ - byte[] g = pub.getParams().getG().toByteArray(); + byte[] g = pub.getParams().getG().toByteArray(); byte[] p = pub.getParams().getP().toByteArray(); byte[] q = pub.getParams().getQ().toByteArray(); byte[] y = pub.getY().toByteArray(); - byte[] pubKey = new byte[g.length+p.length+q.length+y.length]; + byte[] pubKey = new byte[g.length+p.length+q.length+y.length]; - ByteBuffer arr = ByteBuffer.wrap(pubKey); - arr.put(g); + ByteBuffer arr = ByteBuffer.wrap(pubKey); + arr.put(g); arr.put(p); arr.put(q); - arr.put(y); + arr.put(y); - return arr.array(); + return arr.array(); } // TODO: use real dsa keys @@ -298,24 +309,24 @@ public static byte[] convertDSAPubKey(DSAPublicKey pub){ */ public static byte[] getUserLeafNodeBytes(UserLeafNode uln){ byte[] pubKey = strToBytes(uln.getPublicKey()); - byte[] usr = strToBytes(uln.getUsername()); + byte[] usr = strToBytes(uln.getUsername()); byte[] ck = convertDSAPubKey(uln.getChangeKey()); byte[] ep_add = longToBytes(uln.getEpochAdded()); byte[] auk = new byte[]{(byte)(uln.allowsUnsignedKeychange() ? 0x01 : 0x00)}; byte[] apl = new byte[]{(byte)(uln.allowsPublicLookups() ? 0x01 : 0x00)}; - byte[] leafBytes = new byte[pubKey.length+usr.length+ck.length+ep_add.length+auk.length+ + byte[] leafBytes = new byte[pubKey.length+usr.length+ck.length+ep_add.length+auk.length+ apl.length]; - - ByteBuffer arr = ByteBuffer.wrap(leafBytes); - arr.put(usr); - arr.put(pubKey); + + ByteBuffer arr = ByteBuffer.wrap(leafBytes); + arr.put(usr); + arr.put(pubKey); arr.put(ck); - arr.put(ep_add); - arr.put(auk); + arr.put(ep_add); + arr.put(auk); arr.put(apl); - return arr.array(); + return arr.array(); } /** Converts a {@link InteriorNode} {@code in} to a hashable array of bytes. @@ -323,16 +334,16 @@ public static byte[] getUserLeafNodeBytes(UserLeafNode uln){ *@return The {@code byte[]} containing the serialized InteriorNode. */ public static byte[] getInteriorNodeBytes(InteriorNode in){ - byte[] left = in.getLeftHash(); - byte[] right = in.getRightHash(); + byte[] left = in.getLeftHash(); + byte[] right = in.getRightHash(); - byte[] nodeBytes = new byte[left.length+right.length]; - - ByteBuffer arr = ByteBuffer.wrap(nodeBytes); - arr.put(left); - arr.put(right); + byte[] nodeBytes = new byte[left.length+right.length]; - return arr.array(); + ByteBuffer arr = ByteBuffer.wrap(nodeBytes); + arr.put(left); + arr.put(right); + + return arr.array(); } /** Converts a {@link RootNode} {@code rn} to a hashable array of bytes. @@ -340,20 +351,20 @@ public static byte[] getInteriorNodeBytes(InteriorNode in){ *@return The {@code byte[]} containing the serialized RootNode. */ public static byte[] getRootNodeBytes(RootNode rn){ - byte[] left = rn.getLeftHash(); - byte[] right = rn.getRightHash(); + byte[] left = rn.getLeftHash(); + byte[] right = rn.getRightHash(); + + byte[] rootBytes = new byte[left.length+right.length]; - byte[] rootBytes = new byte[left.length+right.length]; - - ByteBuffer arr = ByteBuffer.wrap(rootBytes); - arr.put(left); - arr.put(right); + ByteBuffer arr = ByteBuffer.wrap(rootBytes); + arr.put(left); + arr.put(right); - return arr.array(); + return arr.array(); } /** Takes the components of a signed tree root: root node, current epoch, - * previous epoch, hash of previous STR, and serializes them into + * previous epoch, hash of previous STR, and serializes them into * a byte[] that can be used to generate the STR's digital signature. * *@return The {@code byte[]} containing the serialized STR components. @@ -371,19 +382,19 @@ public static byte[] getSTRBytesForSig(RootNode rn, long ep, long prevEp, byte[] epBytes = longToBytes(ep); byte[] prevEpBytes = longToBytes(prevEp); - byte[] strBytes = new byte[rootBytes.length+epBytes.length+prevEpBytes.length+ + byte[] strBytes = new byte[rootBytes.length+epBytes.length+prevEpBytes.length+ prevStrHash.length]; - - ByteBuffer arr = ByteBuffer.wrap(strBytes); - arr.put(rootBytes); - arr.put(epBytes); + + ByteBuffer arr = ByteBuffer.wrap(strBytes); + arr.put(rootBytes); + arr.put(epBytes); arr.put(prevEpBytes); arr.put(prevStrHash); - return arr.array(); + return arr.array(); } - + /** Converts a {@link SignedTreeRoot} {@code str} to a hashable array of bytes * *@return The {@code byte[]} containing the serialized STR components. @@ -402,17 +413,17 @@ public static byte[] getSTRBytes(SignedTreeRoot str) { byte[] prevStrHash = str.getPrevSTRHash(); byte[] sig = str.getSignature(); - byte[] strBytes = new byte[rootBytes.length+epBytes.length+prevEpBytes.length+ + byte[] strBytes = new byte[rootBytes.length+epBytes.length+prevEpBytes.length+ prevStrHash.length+sig.length]; - - ByteBuffer arr = ByteBuffer.wrap(strBytes); - arr.put(rootBytes); - arr.put(epBytes); + + ByteBuffer arr = ByteBuffer.wrap(strBytes); + arr.put(rootBytes); + arr.put(epBytes); arr.put(prevEpBytes); arr.put(prevStrHash); arr.put(sig); - return arr.array(); + return arr.array(); } @@ -423,8 +434,8 @@ public static byte[] getSTRBytes(SignedTreeRoot str) { *@author Marcela S. Melara (melara@cs.princeton.edu) *@author Michael Rochlin */ - public static class PrefixComparator implements Comparator> { - + public static class PrefixComparator implements Comparator> { + /** Compares the first 24 bits of two data binding lookup indeces. * *@return 0 if they are equal, 1 if the lookup index of {@code p1} is greater, and @@ -434,21 +445,21 @@ public static class PrefixComparator implements Comparator p1, Triplet p2) { - byte[] buf1 = p1.getValue0(); - byte[] buf2 = p2.getValue0(); - - if (buf1.length < 3 || buf2.length < 3) { - throw new RuntimeException("bad byte array length"); - } - - for(int i = 0; i < 3; i++){ - if(buf1[i] > buf2[i]){ - return 1; - }else if (buf1[i] < buf2[i]){ - return -1; - } - } - + byte[] buf1 = p1.getValue0(); + byte[] buf2 = p2.getValue0(); + + if (buf1.length < 3 || buf2.length < 3) { + throw new RuntimeException("bad byte array length"); + } + + for(int i = 0; i < 3; i++){ + if(buf1[i] > buf2[i]){ + return 1; + }else if (buf1[i] < buf2[i]){ + return -1; + } + } + // registrations must always happen before ulnChanges // earlier ulnChanges must always happen before later ones Operation op1 = p1.getValue2(); @@ -462,9 +473,9 @@ public int compare(Triplet p1, Triplet ((KeyChange)op2).getCounter()) ? 1 : -1; } - - return 0; - } + + return 0; + } } } //ends ServerUtils class diff --git a/coniks_server/src/main/java/org/coniks/coniks_server/SignatureOps.java b/coniks_server/src/main/java/org/coniks/coniks_server/SignatureOps.java index eb4662c..5b9c24e 100644 --- a/coniks_server/src/main/java/org/coniks/coniks_server/SignatureOps.java +++ b/coniks_server/src/main/java/org/coniks/coniks_server/SignatureOps.java @@ -1,33 +1,33 @@ /* Copyright (c) 2015-16, Princeton University. All rights reserved. - + Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are + modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the distribution. * Neither the name of Princeton University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ @@ -58,71 +58,80 @@ public class SignatureOps{ * of the {@code input}. *@throws A RuntimeException if there is a problem with the private key * loaded from the server's keystore. + *@deprecated Replaced with {@link org.coniks.crypto.Signing#rsaSign(RSAPublicKey, byte[])}. */ + @Deprecated public static byte[] sign(byte[] input) { RSAPrivateKey MY_PRIV_KEY = KeyOps.loadSigningKey(); - byte[] signed = null; + byte[] signed = null; if(MY_PRIV_KEY == null){ - throw new RuntimeException("borked pk?"); + throw new RuntimeException("borked pk?"); } - - try{ - Signature signer = Signature.getInstance("SHA256withRSA"); - signer.initSign(MY_PRIV_KEY, new SecureRandom()); + + try{ + Signature signer = Signature.getInstance("SHA256withRSA"); + signer.initSign(MY_PRIV_KEY, new SecureRandom()); signer.update(input); - - signed = signer.sign(); - return signed; - } - catch(NoSuchAlgorithmException e){ - TimerLogger.error("RSA is invalid for some reason."); - } - catch(InvalidKeyException e){ - TimerLogger.error("The given key is invalid."); - } + + signed = signer.sign(); + return signed; + } + catch(NoSuchAlgorithmException e){ + TimerLogger.error("RSA is invalid for some reason."); + } + catch(InvalidKeyException e){ + TimerLogger.error("The given key is invalid."); + } catch(SignatureException e){ - TimerLogger.error("The format of the sig input is invalid."); - } - - return signed; + TimerLogger.error("The format of the sig input is invalid."); + } + + return signed; } - /** Verify a given server {@code keyOwner}'s digital signature {@code signature} - * on the message {@code msg}. + /** Verify a given server {@code keyOwner}'s digital signature + * {@code signature} on the message {@code msg}. * - *@return {@code true} if the signature on the message is valid, {@code false} - * otherwise. + *@return {@code true} if the signature on the message is valid, + * {@code false} otherwise. + *@deprecated Replaced with {@link org.coniks.crypto.Signing#rsaVerify(RSAPublicKey, byte[], byte[])}. */ - public static boolean verifySig(byte[] msg, byte[] signature, String keyOwner){ + @Deprecated + public static boolean verifySig(byte[] msg, byte[] signature, + String keyOwner){ RSAPublicKey pubKey = KeyOps.loadPublicKey(keyOwner); - try{ - - Signature verifier = Signature.getInstance("SHA256withRSA"); - verifier.initVerify(pubKey); - verifier.update(msg); - - return verifier.verify(signature); - } - catch(NoSuchAlgorithmException e){ - TimerLogger.error("SHA256withRSA is invalid for some reason."); - } - catch(InvalidKeyException e){ - TimerLogger.error("The given key is invalid."); - } - catch(SignatureException e){ - TimerLogger.error("The format of the input is invalid: "+e.getMessage()); - } - - return false; + try{ + + Signature verifier = Signature.getInstance("SHA256withRSA"); + verifier.initVerify(pubKey); + verifier.update(msg); + + return verifier.verify(signature); + } + catch(NoSuchAlgorithmException e){ + TimerLogger.error("SHA256withRSA is invalid for some reason."); + } + catch(InvalidKeyException e){ + TimerLogger.error("The given key is invalid."); + } + catch(SignatureException e){ + TimerLogger.error("The format of the input is invalid: "+e.getMessage()); + } + + return false; } - /** Verify {@code msg} with {@code sig} using {@code pk} */ + /** Verify {@code msg} with {@code sig} using {@code pk} + * + *@deprecated Replaced with {@link org.coniks.crypto.Signing#dsaVerify(DSAPublicKey, byte[], byte[])}. + */ + @Deprecated public static boolean verifySigFromDSA(byte[] msg, byte[] sig, PublicKey pk) { try { Signature verifyalg = Signature.getInstance("DSA"); diff --git a/coniks_server/src/main/java/org/coniks/coniks_server/TransparencyOps.java b/coniks_server/src/main/java/org/coniks/coniks_server/TransparencyOps.java index 00a8663..84fcbd6 100644 --- a/coniks_server/src/main/java/org/coniks/coniks_server/TransparencyOps.java +++ b/coniks_server/src/main/java/org/coniks/coniks_server/TransparencyOps.java @@ -1,39 +1,43 @@ /* Copyright (c) 2015-16, Princeton University. All rights reserved. - + Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are + modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the distribution. * Neither the name of Princeton University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.coniks.coniks_server; import com.google.protobuf.ByteString; + +// coniks-java imports +import org.coniks.crypto.Signing; +import org.coniks.crypto.Util; import org.coniks.coniks_common.C2SProtos.AuthPath; import org.coniks.coniks_common.C2SProtos.*; import org.coniks.coniks_common.UtilProtos.Hash; @@ -43,16 +47,15 @@ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, import java.util.TreeMap; import java.util.PriorityQueue; import java.security.*; -import java.security.interfaces.RSAPublicKey; -import java.security.interfaces.DSAPublicKey; +import java.security.interfaces.*; import java.nio.ByteBuffer; import org.javatuples.*; -/** Implements all transparency-related operations done by a +/** Implements all transparency-related operations done by a * CONIKS server. * These allow a CONIKS client to perform the consistency checks. - * + * *@author Marcela S. Melara (melara@cs.princeton.edu) *@author Aaron Blankstein *@author Michael Rochlin @@ -67,13 +70,22 @@ public class TransparencyOps{ */ public static SignedTreeRoot generateSTR(RootNode root, long ep, long prevEp, byte[] prevStrHash) { - + byte[] strBytesPreSig = ServerUtils.getSTRBytesForSig(root, ep, prevEp, prevStrHash); - byte[] sig = SignatureOps.sign(strBytesPreSig); - - return new SignedTreeRoot(root, ep, prevEp, prevStrHash, sig, null); + RSAPrivateKey key = KeyOps.loadSigningKey(); + + byte[] sig = null; + try { + sig = Signing.rsaSign(key, strBytesPreSig); + } + catch (Exception e) { + ServerLogger.error("[RequestHandler] "+e.getMessage()); + return null; + } + + return new SignedTreeRoot(root, ep, prevEp, prevStrHash, sig, null); } /** Generates the STR from the root node {@code root} for the epoch @@ -88,24 +100,41 @@ public static synchronized SignedTreeRoot generateNextSTR(RootNode root, long ep // generate the hash of the current STR to include is in the next // STR as the previous STR hash - byte[] prevStrHash = ServerUtils.hash(ServerUtils.getSTRBytes(ServerHistory.getCurSTR())); + byte[] prevStrHash = null; + + try { + prevStrHash = Util.digest(ServerUtils.getSTRBytes(ServerHistory.getCurSTR())); + } + catch(NoSuchAlgorithmException e) { + ServerLogger.error("[TransparencyOps] "+e.getMessage()); + return null; + } byte[] strBytesPreSig = ServerUtils.getSTRBytesForSig(root, ep, prevEpoch, prevStrHash); - byte[] sig = SignatureOps.sign(strBytesPreSig); - - return new SignedTreeRoot(root, ep, prevEpoch, prevStrHash, sig, ServerHistory.getCurSTR()); + RSAPrivateKey key = KeyOps.loadSigningKey(); + + byte[] sig = null; + try { + sig = Signing.rsaSign(key, strBytesPreSig); + } + catch (Exception e) { + ServerLogger.error("[TransparencyOps] "+e.getMessage()); + return null; + } + + return new SignedTreeRoot(root, ep, prevEpoch, prevStrHash, sig, ServerHistory.getCurSTR()); } - - /** Generates the authentication path protobuf message from the + + /** Generates the authentication path protobuf message from the * root node {@code root} to the user leaf node {@code uln}. * - *@return The {@link org.coniks.coniks_common.C2SProtos.AuthPath} + *@return The {@link org.coniks.coniks_common.C2SProtos.AuthPath} * protobuf message or {@code null} upon failure. */ public static AuthPath generateAuthPathProto(UserLeafNode uln, RootNode root){ - + AuthPath.Builder authPath = AuthPath.newBuilder(); //first take care of setting the UserLeafNode @@ -136,18 +165,18 @@ public static AuthPath generateAuthPathProto(UserLeafNode uln, RootNode root){ // book-keeping for interior nodes int numInteriors = 0; - ArrayList interiorList = new ArrayList(); - + ArrayList interiorList = new ArrayList(); + // get the prefix from the key - - byte[] lookupIndex = ServerUtils.unameToIndex(uln.getUsername()); - byte[] prefix = ServerUtils.getPrefixBytes(lookupIndex); + byte[] lookupIndex = ServerUtils.unameToIndex(uln.getUsername()); + + byte[] prefix = ServerUtils.getPrefixBytes(lookupIndex); String prefixStr = ServerUtils.bytesToHex(prefix); // not worth doing this recursively int curOffset = 0; - TreeNode runner = root; + TreeNode runner = root; while (!(runner instanceof UserLeafNode)) { @@ -155,18 +184,18 @@ public static AuthPath generateAuthPathProto(UserLeafNode uln, RootNode root){ // true = right boolean direction = ServerUtils.getNthBit(lookupIndex, curOffset); - byte[] prunedChildHash = new byte[ServerUtils.HASH_SIZE_BYTES]; + byte[] prunedChildHash = new byte[Util.HASH_SIZE_BYTES]; - if (runner == null){ - ServerLogger.error("Null runner" + curOffset); - } + if (runner == null){ + ServerLogger.error("Null runner" + curOffset); + } if (runner instanceof RootNode) { RootNode curNodeR = (RootNode) runner; AuthPath.RootNode.Builder rootBuilder = AuthPath.RootNode.newBuilder(); - + if(!direction){ prunedChildHash = curNodeR.getRightHash(); rootBuilder.setPrunedchild(AuthPath.PrunedChild.RIGHT); @@ -179,36 +208,36 @@ public static AuthPath generateAuthPathProto(UserLeafNode uln, RootNode root){ } Hash.Builder subtree = Hash.newBuilder(); - if(prunedChildHash.length != ServerUtils.HASH_SIZE_BYTES){ + if(prunedChildHash.length != Util.HASH_SIZE_BYTES){ ServerLogger.error("Bad length of pruned child hash: "+prunedChildHash.length); return null; } subtree.setLen(prunedChildHash.length); subtree.setHash(ByteString.copyFrom(prunedChildHash)); rootBuilder.setSubtree(subtree.build()); - + authPath.setRoot(rootBuilder.build()); - + curOffset++; } else { InteriorNode curNodeI = (InteriorNode) runner; - + AuthPath.InteriorNode.Builder inBuilder = AuthPath.InteriorNode.newBuilder(); - + if(!direction){ prunedChildHash = curNodeI.getRightHash(); inBuilder.setPrunedchild(AuthPath.PrunedChild.RIGHT); runner = curNodeI.getLeft(); - } + } else { prunedChildHash = curNodeI.getLeftHash(); inBuilder.setPrunedchild(AuthPath.PrunedChild.LEFT); runner = curNodeI.getRight(); } Hash.Builder subtree = Hash.newBuilder(); - if(prunedChildHash.length != ServerUtils.HASH_SIZE_BYTES){ + if(prunedChildHash.length != Util.HASH_SIZE_BYTES){ ServerLogger.error("Bad length of pruned child hash: "+prunedChildHash.length); return null; } @@ -216,22 +245,22 @@ public static AuthPath generateAuthPathProto(UserLeafNode uln, RootNode root){ subtree.setHash(ByteString.copyFrom(prunedChildHash)); inBuilder.setSubtree(subtree.build()); interiorList.add(0, inBuilder.build()); - - if (runner == null){ - ServerLogger.error("such sadness..."); - } + + if (runner == null){ + ServerLogger.error("such sadness..."); + } curOffset++; numInteriors++; } - + } ulnBuilder.setIntlevels(numInteriors); authPath.setLeaf(ulnBuilder.build()); authPath.addAllInterior(interiorList); - + return authPath.build(); } - + } diff --git a/coniks_server/src/main/java/org/coniks/coniks_server/TreeBuilder.java b/coniks_server/src/main/java/org/coniks/coniks_server/TreeBuilder.java index bd14682..65899d2 100644 --- a/coniks_server/src/main/java/org/coniks/coniks_server/TreeBuilder.java +++ b/coniks_server/src/main/java/org/coniks/coniks_server/TreeBuilder.java @@ -1,33 +1,33 @@ /* Copyright (c) 2015-16, Princeton University. All rights reserved. - + Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are + modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the distribution. * Neither the name of Princeton University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ @@ -35,13 +35,17 @@ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, import java.util.PriorityQueue; import java.security.KeyPair; +import java.security.NoSuchAlgorithmException; import java.security.interfaces.DSAPublicKey; import java.security.interfaces.RSAPublicKey; +// coniks-java imports +import org.coniks.crypto.Util; + import org.javatuples.*; /** Implements all operations necessary for building a CONIKS - * Merkle prefix tree on the server. + * Merkle prefix tree on the server. * Current hashing algorithm used: SHA-256. * *@author Marcela S. Melara (melara@cs.princeton.edu) @@ -49,29 +53,29 @@ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, *@author Michael Rochlin */ public class TreeBuilder{ - + private static int lastLevel; - + // inserts a new user leaf node into the tree private static void insertNode(byte[] key, UserLeafNode toAdd, RootNode root, Operation op){ int curOffset = 0; // This code would be a lot more natural // if our tries were byte-branching rather than bit-branching, but whatevs. - + toAdd.level = 0; TreeNode curNode = root; - + curNode.setName("root"); int counter = 1; - + insertLoop: while(true){ int arrayOffset = curOffset / 8; int bitOfByte = curOffset % 8; // 0 is left-most byte in string - // 0 of left-most byte is the *left-most* bit of that byte. + // 0 of left-most byte is the *left-most* bit of that byte. toAdd.level++; - + if( curNode instanceof UserLeafNode ){ // reached a "bottom" of the tree. // add a new interior node and push the previous leaf down @@ -79,11 +83,11 @@ private static void insertNode(byte[] key, UserLeafNode toAdd, RootNode root, Op if (curNode.parent == null){ throw new UnsupportedOperationException("parent is null!!"); } - + // TODO: Does this need to be moved? InteriorNode newInt = new InteriorNode(curNode.parent, curNode.level); - + UserLeafNode curNodeUL = (UserLeafNode) curNode; if (curNodeUL.username.equals( toAdd.username )) { if (op instanceof Register) { @@ -106,11 +110,11 @@ else if (op instanceof KeyChange) { throw new UnsupportedOperationException("Weird operation happened. Make sure you've added this functionality"); } } - + if (!(op instanceof Register)) { throw new UnsupportedOperationException("Failed to make key-change!"); } - + byte[] curNodeKey = ServerUtils.unameToIndex(curNodeUL.username); curNodeUL.setIndex(curNodeKey); // This is what's happening below: @@ -118,7 +122,7 @@ else if (op instanceof KeyChange) { int maskedBit = curNodeKey[arrayOffset] & (1 << (7 - bitOfByte)); // direction here is going to be false = left, // true = right - + boolean direction = (maskedBit != 0); if (direction){ newInt.right = curNodeUL; @@ -127,7 +131,7 @@ else if (op instanceof KeyChange) { } curNode.level++; curNode.parent = newInt; - + if (newInt.parent.left == curNode) { newInt.parent.left = newInt; } @@ -135,16 +139,16 @@ else if (op instanceof KeyChange) { newInt.parent.right = newInt; } curNode = newInt; - toAdd.level--; - } + toAdd.level--; + } else { InteriorNode curNodeI = (InteriorNode) curNode; int maskedBit = key[arrayOffset] & (1 << (7 - bitOfByte)); // direction here is going to be false = left, // true = right - + boolean direction = (maskedBit != 0); - + if(direction){ // mark right tree as needing hash recompute curNodeI.rightHash = null; @@ -175,47 +179,49 @@ else if (op instanceof KeyChange) { lastLevel = toAdd.level; } } - + // Compute the hashes of the left and right subtrees // of the Merkle tree root // Wrapper for innerComputeHash - private static void computeHashes(RootNode root){ + private static void computeHashes(RootNode root) + throws NoSuchAlgorithmException { if (root.leftHash == null){ - root.leftHash = innerComputeHash(root.left); + root.leftHash = innerComputeHash(root.left); } if (root.rightHash == null){ root.rightHash = innerComputeHash(root.right); } } - + // this recursively computes the hash of the subtree specified // by curNode - private static byte[] innerComputeHash(TreeNode curNode){ - if(curNode == null) { - return ServerUtils.hash(new byte[ServerUtils.HASH_SIZE_BYTES]); - } - - if(curNode instanceof InteriorNode){ - InteriorNode curNodeI = (InteriorNode) curNode; - if(curNodeI.leftHash == null){ - // compute left-side hash - curNodeI.leftHash = innerComputeHash(curNode.left); - } - if(curNodeI.rightHash == null){ - // compute right-side hash - curNodeI.rightHash = innerComputeHash(curNode.right); - } - - return ServerUtils.hash(ServerUtils.getInteriorNodeBytes(curNodeI)); - } + private static byte[] innerComputeHash(TreeNode curNode) + throws NoSuchAlgorithmException { + if(curNode == null) { + return Util.digest(new byte[Util.HASH_SIZE_BYTES]); + } + + if(curNode instanceof InteriorNode){ + InteriorNode curNodeI = (InteriorNode) curNode; + if(curNodeI.leftHash == null){ + // compute left-side hash + curNodeI.leftHash = innerComputeHash(curNode.left); + } + if(curNodeI.rightHash == null){ + // compute right-side hash + curNodeI.rightHash = innerComputeHash(curNode.right); + } + + return Util.digest(ServerUtils.getInteriorNodeBytes(curNodeI)); + } else{ - // assertion: must be user leaf node. - UserLeafNode curNodeU = (UserLeafNode) curNode; - return ServerUtils.hash(ServerUtils.getUserLeafNodeBytes(curNodeU)); - } + // assertion: must be user leaf node. + UserLeafNode curNodeU = (UserLeafNode) curNode; + return Util.digest(ServerUtils.getUserLeafNodeBytes(curNodeU)); + } } - - /** Clones a Merkle prefix tree {@code prevRoot} and + + /** Clones a Merkle prefix tree {@code prevRoot} and * extends it with any new nodes in {@code pendingQ}. * *@return The {@link RootNode} for the next epoch's Merkle tree. @@ -229,52 +235,62 @@ public static RootNode copyExtendTree(RootNode prevRoot, }else{ newRoot = new RootNode(null, null, 0); } - + if(pendingQ == null) { ServerLogger.error("Trying to extend using null pending queue"); return null; } - return extendTree(pendingQ, newRoot); + + RootNode r = null; + + try { + r = extendTree(pendingQ, newRoot); + } + catch(NoSuchAlgorithmException e) { + ServerLogger.error("Trying to extend using null pending queue"); + } + return r; } - - /** Inserts any new nodes in {@code pendingQ} ordered by the 24-bit prefix - * of their lookup index into the Merkle tree, and recomputes all necessary - * hashes. + + /** Inserts any new nodes in {@code pendingQ} ordered by the 24-bit + * prefix of their lookup index into the Merkle tree, and recomputes + * all necessary hashes. * *@return The {@link RootNode} of the extended Merkle tree. */ - private static RootNode extendTree( - PriorityQueue> pendingQ, - RootNode root) { - + private static RootNode extendTree(PriorityQueue> pendingQ, + RootNode root) + throws NoSuchAlgorithmException { + RootNode newRoot = root; - + byte[] prefix = null; - + int toInsert = pendingQ.size(); - + Triplet p = pendingQ.poll(); while(p != null){ // while we're handing the same prefix, // insert as normal byte[] index = p.getValue0(); prefix = ServerUtils.getPrefixBytes(index); - + UserLeafNode toAdd = p.getValue1(); Operation op = p.getValue2(); - + insertNode(index, toAdd, newRoot, op); - + p = pendingQ.poll(); - + toInsert--; - + } - + // recompute hashes computeHashes(newRoot); - + return newRoot; } - + } diff --git a/coniks_test_client/README.md b/coniks_test_client/README.md index 613b7ae..49bf051 100644 --- a/coniks_test_client/README.md +++ b/coniks_test_client/README.md @@ -17,12 +17,16 @@ The coniks_test_client build is managed using Maven. (Instructions for building ```$ mvn package``` These instructions will install the ``coniks_test_client`` Maven artifact. +The build configuration for coniks_test_client assembles all dependencies, +and includes them in the generated .jar file, so you can run the server +only using the coniks_test_client .jar file. ##Using the Test Client -The CONIKS test client has two operating modes: Test Mode and Full Operation. -Running the client in test mode allows you to still test all CONIKS protocols and operations, -but requires less setup as you can simply use the default configuration in the included *config* file. +The CONIKS test client has two operating modes: Test Mode and Full Operation. +Running the client in test mode allows you to still test all CONIKS +protocols and operations, but requires less setup as you can simply use +the default configuration in the included *config* file. **Note:** You must be running the server in the same operating mode. ### Setup @@ -34,8 +38,8 @@ keytool -import -alias -file -keystore ```: start the client in full operation mode, connecting it to the given server. - ```test ```: start the client in test mode, connecting it to the given server. - ```clean```: remove all logs written by the client. @@ -66,7 +70,7 @@ perform the operation and the first dummy user for which to run the operation. D identified by numbers, so user "5" is the 5th dummy user. The test client will prompt you until you no longer want to continue. -Supported operations: +Supported operations: - ```REGISTER```: register a new name-to-public key mapping with the CONIKS server. - ```LOOKUP```: look up a public key, and verify the cryptographic proof of inclusion if the user exists. - ```SIGNED```: change the public key registered for an existing name and authorize this change via a digital signature. @@ -81,7 +85,7 @@ Some examples: - POLICY 1 18: changes the key change policy for user 18. ## Disclaimer -Please keep in mind that this CONIKS reference implementation is under active development. The repository may contain experimental features that aren't fully tested. We recommend using a [tagged release](https://github.com/coniks-sys/coniks-java/releases). +Please keep in mind that this CONIKS Java implementation is under active development. The repository may contain experimental features that aren't fully tested. We recommend using a [tagged release](https://github.com/coniks-sys/coniks-java/releases). ##Documentation [Read the test client's Java API (javadoc)](https://coniks-sys.github.io/coniks-java/org/coniks/coniks_test_client/package-summary.html) diff --git a/coniks_test_client/coniks_test_client.sh b/coniks_test_client/coniks_test_client.sh index ac36cb3..9507c01 100755 --- a/coniks_test_client/coniks_test_client.sh +++ b/coniks_test_client/coniks_test_client.sh @@ -4,37 +4,38 @@ # All rights reserved. # # Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are +# modification, are permitted provided that the following conditions are # met: -# * Redistributions of source code must retain the above copyright +# * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the # distribution. # * Neither the name of Princeton University nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. ## Runs or a CONIKS test client instance # Set all the configs here -CLASS_DEST="bin" #change this if you built the server somewhere else +# mvn builds our jar with dependencies +CLASS_DEST="./target/coniks_test_client-1.3-SNAPSHOT.jar" CLASSPATH="-cp $CLASS_DEST" CLIENT_BIN="org.coniks.coniks_test_client.TestClient" CONIKS_CLIENTCONFIG="config" diff --git a/coniks_test_client/pom.xml b/coniks_test_client/pom.xml index e535fa8..a36d01a 100644 --- a/coniks_test_client/pom.xml +++ b/coniks_test_client/pom.xml @@ -5,28 +5,31 @@ org.coniks coniks-java - 1.2-SNAPSHOT + 1.3-SNAPSHOT org.coniks.coniks_test_client coniks_test_client + 1.3-SNAPSHOT jar - 1.2-SNAPSHOT - coniks_test_client + + CONIKS [Test Client] http://coniks.org + CONIKS client library and reference implementation. + - junit - junit - 3.8.1 - test + org.coniks.coniks_common + coniks_common + 1.3-SNAPSHOT + compile - org.coniks.coniks_common - coniks_common - 1.2-SNAPSHOT + org.coniks.crypto + coniks-crypto + 1.3-SNAPSHOT compile @@ -48,4 +51,26 @@ UTF-8 + + + + + maven-assembly-plugin + + + package + + single + + + + + + jar-with-dependencies + + false + + + + diff --git a/coniks_test_client/src/main/java/org/coniks/coniks_test_client/ClientUtils.java b/coniks_test_client/src/main/java/org/coniks/coniks_test_client/ClientUtils.java index cccafe2..a91ad40 100644 --- a/coniks_test_client/src/main/java/org/coniks/coniks_test_client/ClientUtils.java +++ b/coniks_test_client/src/main/java/org/coniks/coniks_test_client/ClientUtils.java @@ -1,33 +1,33 @@ /* Copyright (c) 2015-16, Princeton University. All rights reserved. - + Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are + modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the distribution. * Neither the name of Princeton University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ @@ -65,17 +65,26 @@ public class ClientUtils{ /** The size of the Merkle tree hashes in bits. * Current hashing algorithm: SHA-256 + * + *@deprecated Moved to {@link org.coniks.crypto.Util}. */ - public static final int HASH_SIZE_BITS = 256; + @Deprecated + public static final int HASH_SIZE_BITS = 256; /** The size of the Merkle tree hashes in bytes. * Current hashing algorithm: SHA-256 + * + *@deprecated Moved to {@link org.coniks.crypto.Util}. */ + @Deprecated public static final int HASH_SIZE_BYTES = HASH_SIZE_BITS/8; - + /** The size of the CONIKS server's STR signatures in bytes. * Expected server signature scheme: RSAwithSHA256. + * + *@deprecated Moved to {@link org.coniks.crypto.Signing}. */ + @Deprecated public static final int SIG_SIZE_BYTES = 256; /** The maximum number of bytes logged per log file. @@ -97,25 +106,27 @@ public class ClientUtils{ * Current hashing algorithm: SHA-256. * *@return The hash as a {@code byte[]} or null in case of an error. + *@deprecated Replaced with {@link org.coniks.crypto.Util#digest(byte[])} */ + @Deprecated public static byte[] hash(byte[] input){ - try{ - MessageDigest md = MessageDigest.getInstance("SHA-256"); - - byte[] digest = md.digest(input); + try{ + MessageDigest md = MessageDigest.getInstance("SHA-256"); + + byte[] digest = md.digest(input); - return digest; + return digest; - } - catch(NoSuchAlgorithmException e){ - ClientLogger.error("SHA-256 is not a valid algorithm for some reason"); - } + } + catch(NoSuchAlgorithmException e){ + ClientLogger.error("SHA-256 is not a valid algorithm for some reason"); + } - return null; // should never get here + return null; // should never get here } - /** Generates the cryptographic hash of the {@code left} + /** Generates the cryptographic hash of the {@code left} * and {@code right} subtree hashes of a Merkle tree node. * This is really just a wrapper around {@link ClientUtils#hash(byte[])}. * @@ -123,27 +134,27 @@ public static byte[] hash(byte[] input){ */ public static byte[] hashChildren(byte[] left, byte[] right){ - byte[] childrenBytes = new byte[left.length+right.length]; - - ByteBuffer arr = ByteBuffer.wrap(childrenBytes); - arr.put(left); - arr.put(right); + byte[] childrenBytes = new byte[left.length+right.length]; + + ByteBuffer arr = ByteBuffer.wrap(childrenBytes); + arr.put(left); + arr.put(right); - byte[] children = arr.array(); + byte[] children = arr.array(); - try{ - MessageDigest md = MessageDigest.getInstance("SHA-256"); - - byte[] digest = md.digest(children); + try{ + MessageDigest md = MessageDigest.getInstance("SHA-256"); - return digest; + byte[] digest = md.digest(children); - } - catch(NoSuchAlgorithmException e){ - ClientLogger.error("SHA-256 is not a valid algorithm for some reason"); - } + return digest; + + } + catch(NoSuchAlgorithmException e){ + ClientLogger.error("SHA-256 is not a valid algorithm for some reason"); + } - return null; // should never get here + return null; // should never get here } @@ -173,12 +184,12 @@ public static byte[] strToBytes (String str) { * index using a verifiable unpredicctable function (VUF). * Current VUF algorithm: SHA-256. * - *@return The {@code byte[]} representation of the + *@return The {@code byte[]} representation of the * lookup index. */ public static byte[] unameToIndex (String username){ - byte[] b = strToBytes(username); - return ClientUtils.hash(b); + byte[] b = strToBytes(username); + return ClientUtils.hash(b); } /** Converts a long {@code val} into an array of bytes. @@ -187,7 +198,7 @@ public static byte[] unameToIndex (String username){ */ public static byte[] longToBytes(long val) { byte[] byteArr = new byte[8]; - + for(int i = 0; i < 8; i++) { byte nextByte = (byte)((val >> i*8) & 0xff); byteArr[i] = nextByte; @@ -196,25 +207,25 @@ public static byte[] longToBytes(long val) { return byteArr; } - /** Finds the byte in the byte array {@code arr} + /** Finds the byte in the byte array {@code arr} * at offset {@code offset}, and determines whether it is 1 or 0. * *@return true if the nth bit is 1, false otherwise. */ public static boolean getNthBit(byte[] arr, int offset){ - int arrayOffset = offset / 8; - int bitOfByte = offset % 8; - int maskedBit = arr[arrayOffset] & (1 << (7 - bitOfByte)); - return (maskedBit != 0); + int arrayOffset = offset / 8; + int bitOfByte = offset % 8; + int maskedBit = arr[arrayOffset] & (1 << (7 - bitOfByte)); + return (maskedBit != 0); } - + /** Gets the 16-bit prefix of a byte array {@code arr}. * *@return the first 16 bits of {@code arr} or all zeros if the length * of the array is less than 2 bytes. */ public static byte[] getPrefixBytes(byte[] arr){ - byte[] out = new byte[2]; + byte[] out = new byte[2]; if (arr.length < 2) { out[0] = 0; @@ -224,9 +235,9 @@ public static byte[] getPrefixBytes(byte[] arr){ out[0] = arr[0]; out[1] = arr[1]; } - return out; + return out; } - + /** Compares two byte buffers for byte-by-byte equality. * @@ -237,17 +248,17 @@ public static boolean compareByteBuffers(byte[] buf1, byte[] buf2){ return false; } - for(int i = 0; i < buf1.length; i++){ - if(buf1[i] != buf2[i]){ - return false; - } - } - return true; + for(int i = 0; i < buf1.length; i++){ + if(buf1[i] != buf2[i]){ + return false; + } + } + return true; } /** Converts a DSAPublicKey {@code pub} to a byte array. * - *@return the DSA public key as a {@code byte[]} in g-p-q-y order + *@return the DSA public key as a {@code byte[]} in g-p-q-y order */ public static byte[] convertDSAPubKey(DSAPublicKey pub){ byte[] g = strToBytes(pub.getParams().getG().toString()); @@ -268,7 +279,7 @@ public static byte[] convertDSAPubKey(DSAPublicKey pub){ /** Converts a DSAPublicKeyProto {@code pub} to a byte array. * - *@return the DSA public key protobuf as a {@code byte[]} in g-p-q-y order + *@return the DSA public key protobuf as a {@code byte[]} in g-p-q-y order */ public static byte[] convertDSAPubKey(DSAPublicKeyProto pub){ byte[] g = strToBytes(pub.getG()); @@ -304,7 +315,7 @@ public static DSAPublicKeyProto buildDSAPublicKeyProto(DSAPublicKey pub) { * *@return the DSAPublicKeyProto */ - public static DSAPublicKeyProto buildDSAPublicKeyProto(BigInteger p, + public static DSAPublicKeyProto buildDSAPublicKeyProto(BigInteger p, BigInteger q, BigInteger g, BigInteger y) { @@ -318,7 +329,7 @@ public static DSAPublicKeyProto buildDSAPublicKeyProto(BigInteger p, } - /** Converts an AuthPath.UserLeafNode protobuf {@code uln} + /** Converts an AuthPath.UserLeafNode protobuf {@code uln} * to a {@code byte[]}. */ public static byte[] ulnProtoToBytes(AuthPath.UserLeafNode uln){ @@ -335,7 +346,7 @@ public static byte[] ulnProtoToBytes(AuthPath.UserLeafNode uln){ byte[] leafBytes = new byte[pubKey.length+usr.length+ep_add.length+auk.length+ apl.length+ep_changed.length+ck.length+sig.length+lastMsg.length]; - + ByteBuffer arr = ByteBuffer.wrap(leafBytes); arr.put(usr); arr.put(pubKey); @@ -362,12 +373,12 @@ public static byte[] computeInteriorNodeProtoHashes(byte[] ulnHash, for(int i = 0; i < inList.size(); i++){ AuthPath.InteriorNode in = inList.get(i); - + if(!in.hasPrunedchild() && !in.hasSubtree()){ ClientLogger.error("No pruned child at level: "+i); return null; } - + Hash pcHash = in.getSubtree(); AuthPath.PrunedChild pcSide = in.getPrunedchild(); @@ -379,14 +390,14 @@ public static byte[] computeInteriorNodeProtoHashes(byte[] ulnHash, } byte[] prunedChild = subtreeHash.toByteArray(); - + if(pcSide == AuthPath.PrunedChild.LEFT){ curHash = ClientUtils.hashChildren(prunedChild, curHash); } else if(pcSide == AuthPath.PrunedChild.RIGHT){ curHash = ClientUtils.hashChildren(curHash, prunedChild); } - + } // at this point, curHash should be the root node's direct child @@ -395,7 +406,7 @@ else if(pcSide == AuthPath.PrunedChild.RIGHT){ } /** Takes the hash {@code authPathHash} computed from an authentication path - * and incorporates it into the root node {@code root} of an + * and incorporates it into the root node {@code root} of an * AuthPath.RootNode protobuf. Returns this root node as a byte[]. */ public static byte[] rootProtoToBytes(byte[] authPathHash, AuthPath.RootNode root){ @@ -409,12 +420,12 @@ public static byte[] rootProtoToBytes(byte[] authPathHash, AuthPath.RootNode roo ClientLogger.error("Bad hash length"); return null; } - + byte[] prunedChild = subtreeHash.toByteArray(); byte[] rootBytes = new byte[authPathHash.length+prunedChild.length]; - - ByteBuffer arr = ByteBuffer.wrap(rootBytes); + + ByteBuffer arr = ByteBuffer.wrap(rootBytes); if(pcSide == AuthPath.PrunedChild.LEFT){ arr.put(prunedChild); diff --git a/coniks_test_client/src/main/java/org/coniks/coniks_test_client/ConsistencyChecks.java b/coniks_test_client/src/main/java/org/coniks/coniks_test_client/ConsistencyChecks.java index ff00ff9..5c06030 100644 --- a/coniks_test_client/src/main/java/org/coniks/coniks_test_client/ConsistencyChecks.java +++ b/coniks_test_client/src/main/java/org/coniks/coniks_test_client/ConsistencyChecks.java @@ -1,33 +1,33 @@ /* Copyright (c) 2015-16, Princeton University. All rights reserved. - + Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are + modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the distribution. * Neither the name of Princeton University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ @@ -44,6 +44,8 @@ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, import com.google.protobuf.ByteString; import org.javatuples.*; +// coniks-java imports +import org.coniks.crypto.Util; import org.coniks.coniks_common.ServerErr; import org.coniks.coniks_common.C2SProtos.RegistrationResp; import org.coniks.coniks_common.C2SProtos.AuthPath; @@ -54,7 +56,7 @@ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * on data received from a CONIKS server. * These include data binding proof verification, * and non-equivocation checks. - * + * *@author Marcela S. Melara (melara@cs.princeton.edu) *@author Aaron Blankstein */ @@ -91,26 +93,27 @@ public static int verifyPubKeyProto (ConiksUser user, AuthPath authPath) { /** Recomputes the root node from an AuthPath protobuf message * {@code authPath}. * - *@return The recomputed root node as a {@code byte[]} or {@code null} + *@return The recomputed root node as a {@code byte[]} or {@code null} * upon failure. */ - private static byte[] recomputeAuthPathRootProto(AuthPath authPath){ - - AuthPath.UserLeafNode apUln = authPath.getLeaf(); + private static byte[] recomputeAuthPathRootProto(AuthPath authPath) + throws NoSuchAlgorithmException{ + + AuthPath.UserLeafNode apUln = authPath.getLeaf(); ByteString index = apUln.getLookupIndex(); // verify the input: expect the index to be the size of the hash - if(index.size() != ClientUtils.HASH_SIZE_BYTES){ + if(index.size() != Util.HASH_SIZE_BYTES){ ClientLogger.error("Bad index length"); return null; } - + byte[] lookupIndex = index.toByteArray(); int numInteriors = apUln.getIntlevels(); - byte[] ulnHash = ClientUtils.hash(ClientUtils.ulnProtoToBytes(apUln)); - - ArrayList inList = + byte[] ulnHash = Util.digest(ClientUtils.ulnProtoToBytes(apUln)); + + ArrayList inList = new ArrayList(authPath.getInteriorList()); if(inList.size() != numInteriors){ @@ -130,7 +133,7 @@ private static byte[] recomputeAuthPathRootProto(AuthPath authPath){ ClientLogger.error("Root malformed"); return null; } - + return ClientUtils.rootProtoToBytes(interiorsHash, root); } @@ -141,16 +144,24 @@ private static byte[] recomputeAuthPathRootProto(AuthPath authPath){ *@return A {@link ConsistencyErr} error code. {@code NO_ERR} indicates * that the verification passed. */ - public static int verifyMappingProto (AuthPath authPath, Commitment comm){ + public static int verifyMappingProto (AuthPath authPath, + Commitment comm){ // this really shouldn't be null at this point, but we'll check jic if (authPath == null /*|| comm == null*/) { return ServerErr.MALFORMED_SERVER_MSG_ERR; } - + // first recompute the root node from the authentication path - byte[] recomputedRoot = recomputeAuthPathRootProto(authPath); - + byte[] recomputedRoot = null; + + try { + recomputedRoot = recomputeAuthPathRootProto(authPath); + } + catch(NoSuchAlgorithmException e) { + return ClientUtils.INTERNAL_CLIENT_ERR; + } + if (recomputedRoot == null) { return ServerErr.MALFORMED_SERVER_MSG_ERR; } @@ -159,7 +170,18 @@ public static int verifyMappingProto (AuthPath authPath, Commitment comm){ // TODO: implement this // compute the hash of the recomputed root - byte[] recomputedRootHash = ClientUtils.hash(recomputedRoot); + byte[] recomputedRootHash = null; + try { + recomputedRootHash = Util.digest(recomputedRoot); + } + catch(NoSuchAlgorithmException e) { + return ClientUtils.INTERNAL_CLIENT_ERR; + } + + // something still went wrong with the hash computation + if (recomputedRootHash == null) { + return ClientUtils.INTERNAL_CLIENT_ERR; + } // get the received root hash from the commitment and compare // the two byte buffers diff --git a/coniks_test_client/src/main/java/org/coniks/coniks_test_client/KeyOps.java b/coniks_test_client/src/main/java/org/coniks/coniks_test_client/KeyOps.java index e68046e..2d85419 100644 --- a/coniks_test_client/src/main/java/org/coniks/coniks_test_client/KeyOps.java +++ b/coniks_test_client/src/main/java/org/coniks/coniks_test_client/KeyOps.java @@ -1,33 +1,33 @@ /* Copyright (c) 2015-16, Princeton University. All rights reserved. - + Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are + modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the distribution. * Neither the name of Princeton University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ @@ -71,7 +71,7 @@ public static DSAPublicKey loadDSAPublicKeyFile (String uname) { try { fis = new FileInputStream(filename); - byte[] keyBytes = new byte[fis.available()]; + byte[] keyBytes = new byte[fis.available()]; fis.read(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance("DSA", "SUN"); @@ -115,7 +115,7 @@ public static DSAPrivateKey loadDSAPrivateKeyFile(String uname){ try { fis = new FileInputStream(filename); - byte[] keyBytes = new byte[fis.available()]; + byte[] keyBytes = new byte[fis.available()]; fis.read(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance("DSA", "SUN"); @@ -152,7 +152,8 @@ public static DSAPrivateKey loadDSAPrivateKeyFile(String uname){ *@param pubKey the public key to store for this user *@return whether the save succeeded */ - public static boolean saveDSAPublicKeyFile (String uname, DSAPublicKey pubKey) { + public static boolean saveDSAPublicKeyFile (String uname, + DSAPublicKey pubKey) { byte[] keyBytes = pubKey.getEncoded(); String filename = ClientConfig.getUserKeysPath()+"/"+uname+".pub"; @@ -183,7 +184,8 @@ public static boolean saveDSAPublicKeyFile (String uname, DSAPublicKey pubKey) { *@param pr the private key to be saved *@return whether the private key was successfully saved or not */ - public static boolean saveDSAPrivateKeyFile(String uname, DSAPrivateKey pr) { + public static boolean saveDSAPrivateKeyFile(String uname, + DSAPrivateKey pr) { byte[] keyBytes = pr.getEncoded(); String filename = ClientConfig.getUserKeysPath()+"/"+uname+".pr"; @@ -209,7 +211,6 @@ public static boolean saveDSAPrivateKeyFile(String uname, DSAPrivateKey pr) { } - /** Saves the given key pair to disk. Generates an empty * keystore for the private key if one doesn't exist. * @@ -218,11 +219,12 @@ public static boolean saveDSAPrivateKeyFile(String uname, DSAPrivateKey pr) { *@return whether the save succeeded */ public static boolean saveDSAKeyPairFile(String uname, KeyPair kp) { - + boolean success = false; if (saveDSAPrivateKeyFile(uname, (DSAPrivateKey)kp.getPrivate())) { - success = saveDSAPublicKeyFile(uname, (DSAPublicKey)kp.getPublic()); + success = + saveDSAPublicKeyFile(uname, (DSAPublicKey)kp.getPublic()); } return success; @@ -231,11 +233,14 @@ public static boolean saveDSAKeyPairFile(String uname, KeyPair kp) { /** Generates a DSA key pair for the client. * *@return the DSA key pair or null in case of an error + *@deprecated Replaced with + *{@link org.coniks.crypto.Keys#generateDSAKeyPair()}. */ + @Deprecated public static KeyPair generateDSAKeyPair(){ KeyPairGenerator kg; - + try{ kg = KeyPairGenerator.getInstance("DSA"); kg.initialize(1024, new SecureRandom()); diff --git a/coniks_test_client/src/main/java/org/coniks/coniks_test_client/SignatureOps.java b/coniks_test_client/src/main/java/org/coniks/coniks_test_client/SignatureOps.java index a45712e..5746b4e 100644 --- a/coniks_test_client/src/main/java/org/coniks/coniks_test_client/SignatureOps.java +++ b/coniks_test_client/src/main/java/org/coniks/coniks_test_client/SignatureOps.java @@ -1,32 +1,32 @@ /* Copyright (c) 2015-16, Princeton University. All rights reserved. - + Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are + modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the distribution. * Neither the name of Princeton University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ @@ -39,17 +39,6 @@ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, import javax.crypto.*; import java.math.BigInteger; -// TODO(mrochlin) -// Should use protected keystore instead of just file streams -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; - /** Implements all operations involving digital signatures * that a CONIKS client must perform. * @@ -57,11 +46,17 @@ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, */ public class SignatureOps{ - /** Verifies {@code msg} and the {@code sig} using the DSA PublicKey {@code pk} + /** Verifies {@code msg} and the {@code sig} using the DSA PublicKey + * {@code pk} * - *@return {@code true} if the signature is valid, {@code false} otherwise. + *@return {@code true} if the signature is valid, + * {@code false} otherwise. + *@deprecated Replaced with + *{@link org.coniks.crypto.Signing#dsaVerify(DSAPublicKey, byte[], byte[])}. */ - public static boolean verifySigFromDSA(byte[] msg, byte[] sig, PublicKey pk) { + @Deprecated + public static boolean verifySigFromDSA(byte[] msg, byte[] sig, + PublicKey pk) { try { Signature verifyalg = Signature.getInstance("DSA"); verifyalg.initVerify(pk); @@ -84,10 +79,12 @@ public static boolean verifySigFromDSA(byte[] msg, byte[] sig, PublicKey pk) { return false; } - /** Signs {@code msg} using DSAPrivateKey {@code prk} + /** Signs {@code msg} using DSAPrivateKey {@code prk} * - *@return the signature or null on an error + *@return the signature or null on an error + *@deprecated Replaced with {@link org.coniks.crypto.Signing#dsaSign(DSAPublicKey, byte[], byte[])}. */ + @Deprecated public static byte[] signDSA(byte[] msg, DSAPrivateKey prk) throws InvalidKeyException { if (prk == null) { ClientLogger.error("The given key is invalid."); diff --git a/coniks_test_client/src/main/java/org/coniks/coniks_test_client/TestClient.java b/coniks_test_client/src/main/java/org/coniks/coniks_test_client/TestClient.java index a75f4fd..15cf118 100644 --- a/coniks_test_client/src/main/java/org/coniks/coniks_test_client/TestClient.java +++ b/coniks_test_client/src/main/java/org/coniks/coniks_test_client/TestClient.java @@ -1,33 +1,33 @@ /* Copyright (c) 2015-16, Princeton University. All rights reserved. - + Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are + modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the distribution. * Neither the name of Princeton University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ @@ -44,6 +44,10 @@ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, import java.lang.NumberFormatException; import com.google.protobuf.*; + +// coniks-java imports +import org.coniks.crypto.Signing; +import org.coniks.crypto.Keys; import org.coniks.coniks_common.C2SProtos.*; import org.coniks.coniks_common.UtilProtos.ServerResp; import org.coniks.coniks_common.ServerErr; @@ -52,9 +56,9 @@ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * that simply displays how each component of the * protocol works. * The client is completely agnostic to the underlying format - * of the data sent to the server (it only needs to know + * of the data sent to the server (it only needs to know * whether it's using protobufs)). - * + * *@author Marcela S. Melara (melara@cs.princeton.edu) *@author Aaron Blankstein *@author Michael Rochlin @@ -72,15 +76,15 @@ public class TestClient { private static final String FAKE_PK_DATA = "fake key data"; /** List of coniks users - for now used for testing */ - private static HashMap users; + private static HashMap users; private static int changeCtr = 0; // this is just used to change the key data - + /** Sets the default truststore according to the {@link ClientConfig}. * This is needed to set up SSL connections with a CONIKS server. */ private static void setDefaultTruststore () { - System.setProperty("javax.net.ssl.trustStore", + System.setProperty("javax.net.ssl.trustStore", ClientConfig.getTruststorePath()); System.setProperty("javax.net.ssl.trustStorePassword", ClientConfig.getTruststorePassword()); @@ -118,7 +122,7 @@ private static int getServerErr (ServerResp serverResp) { break; default: serverErr = ServerErr.SERVER_ERR; - break; + break; } return serverErr; @@ -133,14 +137,23 @@ private static int getServerErr (ServerResp serverResp) { *@return whether the registration succeeded or an error code */ private static int register (String uname, String server) { - KeyPair kp = KeyOps.generateDSAKeyPair(); + KeyPair kp = null; + + try { + kp = Keys.generateDSAKeyPair(); + } + catch(NoSuchAlgorithmException e) { + ClientLogger.error("[TestClient] "+e.getMessage()); + return ClientUtils.INTERNAL_CLIENT_ERR; + } + String pk = uname+" "+FAKE_PK_DATA; ClientUser user = new ClientUser(uname, pk, kp); users.put(uname, user); ClientMessaging.sendRegistrationProto(user, server); - + AbstractMessage serverMsg = ClientMessaging.receiveRegistrationRespProto(); if (serverMsg == null) { @@ -223,7 +236,7 @@ private static int signedKeyChange(String uname, String server) { System.out.println("user "+uname+" allows unsigned key changes"); } - // ugh, maybe this isn't the best. + // ugh, maybe this isn't the best. // we're testing the signing, mostly, so the key data doesn't really matter right now String newKeyData = user.getKeyData()+changeCtr; @@ -235,22 +248,32 @@ private static int signedKeyChange(String uname, String server) { } // update the change key for good measure - KeyPair newCk = KeyOps.generateDSAKeyPair(); + KeyPair newCk = null; + + try { + newCk = Keys.generateDSAKeyPair(); + } + catch(NoSuchAlgorithmException e) { + ClientLogger.error("[TestClient] "+e.getMessage()); + user.unloadChangePrivKey(); + return ClientUtils.INTERNAL_CLIENT_ERR; + } // sign the whole key change request (including all unchanged data) byte[] sig = null; try { - ULNChangeReq changeReq = ClientMessaging.buildULNChangeReqMsgProto(user.getUsername(), - newKeyData, - (DSAPublicKey)newCk.getPublic(), - user.isAllowsUnsignedChanges(), - user.isAllowsPublicVisibility()); + ULNChangeReq changeReq = + ClientMessaging.buildULNChangeReqMsgProto(user.getUsername(), + newKeyData, + (DSAPublicKey)newCk.getPublic(), + user.isAllowsUnsignedChanges(), + user.isAllowsPublicVisibility()); - sig = SignatureOps.signDSA(changeReq.toByteArray(), prKey); + sig = Signing.dsaSign(prKey, changeReq.toByteArray()); } - catch (InvalidKeyException e) { - ClientLogger.error(e.getMessage()); + catch (NoSuchAlgorithmException e) { + ClientLogger.error("[TestClient] "+e.getMessage()); user.unloadChangePrivKey(); return ClientUtils.INTERNAL_CLIENT_ERR; } @@ -284,7 +307,7 @@ else if (serverMsg instanceof ServerResp) { else { // TODO: verify registration resp and save the new key data to disk changeCtr++; - + return ConsistencyErr.CHECK_PASSED; } @@ -306,7 +329,7 @@ private static int unsignedKeyChange(String uname, String server) { return ConsistencyErr.DISALLOWED_OP_ERR; } - // ugh, maybe this isn't the best. + // ugh, maybe this isn't the best. // we're testing the signing, mostly, so the key data doesn't really matter right now String newKeyData = user.getKeyData()+changeCtr; user.setKeyData(newKeyData); @@ -324,7 +347,7 @@ else if (serverMsg instanceof ServerResp) { else { // TODO: check the registration resp and save the new key data to disk changeCtr++; - + return ConsistencyErr.CHECK_PASSED; } } @@ -355,23 +378,32 @@ private static int changeKeyChangePolicy(String uname, String server) { System.out.println("no private key for "+uname); return ConsistencyErr.KEYSTORE_ERR; } - + // update the change key for good measure - KeyPair newCk = KeyOps.generateDSAKeyPair(); - + KeyPair newCk = null; + + try { + newCk = Keys.generateDSAKeyPair(); + } + catch(NoSuchAlgorithmException e) { + ClientLogger.error("[TestClient] "+e.getMessage()); + user.unloadChangePrivKey(); + return ClientUtils.INTERNAL_CLIENT_ERR; + } + // sign the whole policy change request (including all unchanged data) byte[] sig = null; try { - ULNChangeReq changeReq = ClientMessaging.buildULNChangeReqMsgProto(user.getUsername(), user.getKeyData(), - (DSAPublicKey)newCk.getPublic(), - user.isAllowsUnsignedChanges(), + ULNChangeReq changeReq = ClientMessaging.buildULNChangeReqMsgProto(user.getUsername(), user.getKeyData(), + (DSAPublicKey)newCk.getPublic(), + user.isAllowsUnsignedChanges(), user.isAllowsPublicVisibility()); - sig = SignatureOps.signDSA(changeReq.toByteArray(), prKey); + sig = Signing.dsaSign(prKey, changeReq.toByteArray()); } - catch (InvalidKeyException e) { - ClientLogger.error(e.getMessage()); + catch (NoSuchAlgorithmException e) { + ClientLogger.error("[TestClient] "+e.getMessage()); user.unloadChangePrivKey(); return ClientUtils.INTERNAL_CLIENT_ERR; } @@ -384,7 +416,7 @@ private static int changeKeyChangePolicy(String uname, String server) { ClientLogger.error("Couldn't get a signature for the new policy"); return ClientUtils.INTERNAL_CLIENT_ERR; } - + // now we can update the user's data internally user.saveChangeKeyPair(newCk); @@ -480,7 +512,7 @@ private static void printErrMsg (int err, String uname) { break; default: printErr("Some unknown server error occurred: "+err); - break; + break; } } @@ -491,9 +523,9 @@ private static void printErrMsg (int err, String uname) { *@return {@code true} if it's valid, {@code false} otherwise. */ private static boolean isValidOperation (String op) { - if (op.equalsIgnoreCase("LOOKUP") || - op.equalsIgnoreCase("REGISTER") || - op.equalsIgnoreCase("SIGNED") || + if (op.equalsIgnoreCase("LOOKUP") || + op.equalsIgnoreCase("REGISTER") || + op.equalsIgnoreCase("SIGNED") || op.equalsIgnoreCase("UNSIGNED") || op.equalsIgnoreCase("POLICY")) { return true; @@ -537,7 +569,7 @@ else if (numUsers >= 100 && i % (1+ (numUsers / 50)) == 0) { String uname = "test-"+(offset+i); int error = 0; - + if(op.equalsIgnoreCase("LOOKUP")){ error = lookup(uname, server); } @@ -553,7 +585,7 @@ else if (op.equalsIgnoreCase("UNSIGNED")) { else if (op.equalsIgnoreCase("POLICY")) { error = changeKeyChangePolicy(uname, server); } - + // if we got an error, print a new line so the error msg doesn't // appear next to the progress dots if (error != ServerErr.SUCCESS && error != ConsistencyErr.CHECK_PASSED) { @@ -635,7 +667,7 @@ else if (opMode.equalsIgnoreCase("test")) { // prompt for the user's name System.out.print("Enter the next operation (or h for help): "); - + // get their input as a String String op = scanner.next(); @@ -683,11 +715,11 @@ else if (isValidOperation(op)) { doOperation(op, numUsers, offset); System.out.print("Would you like to perform another operation? [y/n]: "); - + cont = scanner.next(); while (!cont.equalsIgnoreCase("y") && !cont.equalsIgnoreCase("n")) { - System.out.print("Please enter y or n: "); + System.out.print("Please enter y or n: "); cont = scanner.next(); } } @@ -696,7 +728,7 @@ else if (isValidOperation(op)) { usage(); break; } - + } System.out.println("Goodbye."); diff --git a/crypto/pom.xml b/crypto/pom.xml new file mode 100644 index 0000000..ae287bd --- /dev/null +++ b/crypto/pom.xml @@ -0,0 +1,26 @@ + + + 4.0.0 + + + org.coniks + coniks-java + 1.3-SNAPSHOT + + + org.coniks.crypto + coniks-crypto + 1.3-SNAPSHOT + jar + + CONIKS [Crypto] + http://coniks.org + + Cryptographic algorithms and operations library for CONIKS. + + + + UTF-8 + + diff --git a/crypto/src/main/java/org/coniks/crypto/Keys.java b/crypto/src/main/java/org/coniks/crypto/Keys.java new file mode 100644 index 0000000..f331bbb --- /dev/null +++ b/crypto/src/main/java/org/coniks/crypto/Keys.java @@ -0,0 +1,137 @@ +/* + Copyright (c) 2016, Princeton University. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + * Neither the name of Princeton University nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + */ + +package org.coniks.crypto; + +import java.security.*; +import java.security.interfaces.*; +import java.security.spec.*; +import java.math.BigInteger; + +/** Implements all encryption-key related operations for CONIKS. + * Currently supported algorithms: RSA with SHA-256 and DSA. + * + *@author Marcela S. Melara (melara@cs.princeton.edu) + *@author Michael Rochlin + */ +public class Keys { + + /** Generates a DSA key pair. + * + *@return the DSA key pair or null in case of an error. + *@throws java.security.NoSuchAlgorithmException + */ + public static KeyPair generateDSAKeyPair() + throws NoSuchAlgorithmException { + KeyPairGenerator gen = KeyPairGenerator.getInstance("DSA"); + gen.initialize(1024); + + KeyPair pair = gen.generateKeyPair(); + + return pair; + } + + /** Get the private key from the DSA key pair. + * + *@param kp The DSA KeyPair. + *@return the DSA private key. + */ + public static DSAPrivateKey getDSAPrivate(KeyPair kp) { + return (DSAPrivateKey)kp.getPrivate(); + } + + /** Get the public key from the DSA key pair. + * + *@param kp The DSA KeyPair. + *@return the DSA public key. + */ + public static DSAPublicKey getDSAPublic(KeyPair kp) { + return (DSAPublicKey)kp.getPublic(); + } + + /** Makes a {@link DSAPublicKey} from its {@code p}, {@code q}, + * {@code g} and {@code y} parameters. + * + *@return the DSAPublicKey, or {@code null} in case of an error. + */ + public static DSAPublicKey getDSAPublicFromParams(BigInteger p, + BigInteger q, + BigInteger g, + BigInteger y) { + + DSAPublicKey pk = null; + try { + KeyFactory keyFactory = KeyFactory.getInstance("DSA"); + KeySpec publicKeySpec = new DSAPublicKeySpec(y, p, q, g); + pk = (DSAPublicKey)keyFactory.generatePublic(publicKeySpec); + } + // let's panic if an exception occurs + finally { + return pk; + } + } + + /** Generates an RSA key pair. + * + *@return the RSA key pair or null in case of an error. + *@throws java.security.NoSuchAlgorithmException + */ + public static KeyPair generateRSAKeyPair() + throws NoSuchAlgorithmException { + KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA"); + gen.initialize(2048); + + KeyPair pair = gen.generateKeyPair(); + + return pair; + } + + /** Get the private key from the RSA key pair. + * + *@param kp The RSA KeyPair. + *@return the RSA private key. + */ + public static RSAPrivateKey getRSAPrivate(KeyPair kp) { + return (RSAPrivateKey)kp.getPrivate(); + } + + /** Get the public key from the RSA key pair. + * + *@param kp The RSA KeyPair. + *@return the RSA public key. + */ + public static RSAPublicKey getRSAPublic(KeyPair kp) { + return (RSAPublicKey)kp.getPublic(); + } + +} diff --git a/crypto/src/main/java/org/coniks/crypto/Signing.java b/crypto/src/main/java/org/coniks/crypto/Signing.java new file mode 100644 index 0000000..fababda --- /dev/null +++ b/crypto/src/main/java/org/coniks/crypto/Signing.java @@ -0,0 +1,158 @@ +/* + Copyright (c) 2016, Princeton University. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + * Neither the name of Princeton University nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + */ + +package org.coniks.crypto; + +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.Signature; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.DSAPublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +/** Implements all digital signature operations for CONIKS. + * Currently supported algorithms: RSA with SHA-256 and DSA. + * + *@author Marcela S. Melara (melara@cs.princeton.edu) + *@author Michael Rochlin + */ +public class Signing { + + /** The size of a 2048-bit RSA signature in bytes. + */ + public static final int SIG_SIZE_BYTES = 256; + + /** Generate the RSA digital signature of {@code msg} using {@code key}. + * + *@param msg The message to be signed. + *@param key The {@link java.security.interfaces.RSAPrivateKey} to use + * for signing. + *@return The {@code byte[]} containing the digital signature + * of the {@code msg}, or null in case of an error. + *@throws java.security.NoSuchAlgorithmException + */ + public static byte[] rsaSign(RSAPrivateKey key, byte[] msg) + throws NoSuchAlgorithmException { + + byte[] sig = null; + try { + Signature signer = Signature.getInstance("SHA256withRSA"); + signer.initSign(key, new SecureRandom()); + signer.update(msg); + + sig = signer.sign(); + } + // let's panic if an exception occurs + finally { + return sig; + } + } + + /** Verify the RSA signature {@code sig} of {@code msg} using {@code pk}. + * + *@return {@code true} if the signature on the message is valid, {@code false} + * otherwise. + *@throws {@link java.security.NoSuchAlgorithmException NoSuchAlgorithmException} + */ + public static boolean rsaVerify(RSAPublicKey pk, byte[] msg, byte[] sig) + throws NoSuchAlgorithmException { + + boolean res = false; + try { + Signature verifier = Signature.getInstance("SHA256withRSA"); + verifier.initVerify(pk); + verifier.update(msg); + + res = verifier.verify(sig); + } + // let's panic if an exception occurs + finally { + return res; + } + } + + /** Generate the DSA digital signature of {@code msg} using {@code key}. + * + *@param msg The message to be signed. + *@param key The {@link java.security.interfaces.DSAPrivateKey} to use + * for signing. + *@return The {@code byte[]} containing the digital signature + * of the {@code msg}, or null in case of an error. + *@throws + *{@link java.security.NoSuchAlgorithmException NoSuchAlgorithmException} + */ + public static byte[] dsaSign(DSAPrivateKey key, byte[] msg) + throws NoSuchAlgorithmException { + + byte[] sig = null; + try { + Signature sigProcess = Signature.getInstance("DSA"); + sigProcess.initSign(key); + sigProcess.update(msg); + sig = sigProcess.sign(); + } + // let's panic if an exception occurs + finally { + return sig; + } + } + + /** Verify the DSA signature {@code sig} of {@code msg} using {@code pk}. + * + *@return {@code true} if the signature on the message is valid, + * {@code false} + * otherwise. + *@throws + *{@link java.security.NoSuchAlgorithmException NoSuchAlgorithmException} + */ + public static boolean dsaVerify(DSAPublicKey pk, byte[] msg, byte[] sig) + throws NoSuchAlgorithmException { + + boolean res = false; + try { + Signature verifyalg = Signature.getInstance("DSA"); + verifyalg.initVerify(pk); + verifyalg.update(msg); + + res = verifyalg.verify(sig); + } + // let's panic if an exception occurs + finally { + return res; + } + } + +} diff --git a/crypto/src/main/java/org/coniks/crypto/Util.java b/crypto/src/main/java/org/coniks/crypto/Util.java new file mode 100644 index 0000000..9e77c9e --- /dev/null +++ b/crypto/src/main/java/org/coniks/crypto/Util.java @@ -0,0 +1,80 @@ +/* + Copyright (c) 2016, Princeton University. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + * Neither the name of Princeton University nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + */ + +package org.coniks.crypto; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** Implements all cryptographic utility functions for CONIKS. + * Currently supported hash algorithms: SHA-256. + * + *@author Marcela S. Melara (melara@cs.princeton.edu) + *@author Michael Rochlin + */ +public class Util { + + /** The size of a SHA-256 hash in bits. + */ + public static final int HASH_SIZE_BITS = 256; + + /** The size of a SHA-256 hash in bytes. + */ + public static final int HASH_SIZE_BYTES = HASH_SIZE_BITS/8; + + /** The supported hashing scheme. + */ + public static final String HASH_ID = "SHA-256"; + + /** Generates the cryptographic hash of {@code input}. + * Current hashing algorithm: SHA-256. + * + *@return The hash as a {@code byte[]} or null in case of an error. + */ + public static byte[] digest(byte[] input) + throws NoSuchAlgorithmException { + + byte [] digest = null; + try{ + MessageDigest md = MessageDigest.getInstance(HASH_ID); + digest = md.digest(input); + return digest; + + } + // let's panic if an exception occurs + finally { + return digest; + } + } + +} diff --git a/crypto/src/test/java/org/coniks/crypto/KeysTest.java b/crypto/src/test/java/org/coniks/crypto/KeysTest.java new file mode 100644 index 0000000..ff44c88 --- /dev/null +++ b/crypto/src/test/java/org/coniks/crypto/KeysTest.java @@ -0,0 +1,120 @@ +/* + Copyright (c) 2016, Princeton University. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + * Neither the name of Princeton University nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + */ + +package org.coniks.crypto; + +import org.junit.Test; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +import static org.hamcrest.core.StringContains.containsString; + +import java.security.KeyPair; +import java.security.NoSuchAlgorithmException; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.DSAPublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +/** + * Unit tests for Keys. + */ +public class KeysTest +{ + + @Test + public void testGetDSAPrivateFail() + throws NoSuchAlgorithmException { + + KeyPair pair = Keys.generateRSAKeyPair(); + + try { + DSAPrivateKey pk = Keys.getDSAPrivate(pair); + fail("Expected a ClassCastException to be thrown"); + } + catch(ClassCastException e) { + assertThat(e.getMessage(), + containsString("sun.security.rsa.RSAPrivateCrtKeyImpl cannot be cast to java.security.interfaces.DSAPrivateKey")); + } + } + + @Test + public void testGetDSAPublicFail() + throws NoSuchAlgorithmException { + + KeyPair pair = Keys.generateRSAKeyPair(); + + try { + DSAPublicKey pk = Keys.getDSAPublic(pair); + fail("Expected a ClassCastException to be thrown"); + } + catch(ClassCastException e) { + assertThat(e.getMessage(), + containsString("sun.security.rsa.RSAPublicKeyImpl cannot be cast to java.security.interfaces.DSAPublicKey")); + } + } + + @Test + public void testGetRSAPrivateFail() + throws NoSuchAlgorithmException { + + KeyPair pair = Keys.generateDSAKeyPair(); + + try { + RSAPrivateKey pk = Keys.getRSAPrivate(pair); + fail("Expected a ClassCastException to be thrown"); + } + catch(ClassCastException e) { + assertThat(e.getMessage(), + containsString("sun.security.provider.DSAPrivateKey cannot be cast to java.security.interfaces.RSAPrivateKey")); + } + } + + @Test + public void testGetRSAPublicFail() + throws NoSuchAlgorithmException { + + KeyPair pair = Keys.generateDSAKeyPair(); + + try { + RSAPublicKey pk = Keys.getRSAPublic(pair); + fail("Expected a ClassCastException to be thrown"); + } + catch(ClassCastException e) { + assertThat(e.getMessage(), + containsString("sun.security.provider.DSAPublicKeyImpl cannot be cast to java.security.interfaces.RSAPublicKey")); + } + } + +} diff --git a/crypto/src/test/java/org/coniks/crypto/SigningTest.java b/crypto/src/test/java/org/coniks/crypto/SigningTest.java new file mode 100644 index 0000000..fcdc5cc --- /dev/null +++ b/crypto/src/test/java/org/coniks/crypto/SigningTest.java @@ -0,0 +1,80 @@ +/* + Copyright (c) 2016, Princeton University. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + * Neither the name of Princeton University nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + */ + +package org.coniks.crypto; + +import org.junit.Test; +import static org.junit.Assert.assertTrue; + +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.DSAPublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +/** + * Unit tests for Signing. + */ +public class SigningTest +{ + + @Test + public void testRsaSignVerify() + throws NoSuchAlgorithmException { + + KeyPair pair = Keys.generateRSAKeyPair(); + + byte[] msg = "message".getBytes(); + + byte[] sig = Signing.rsaSign(Keys.getRSAPrivate(pair), msg); + + assertTrue("Verification of RSA signature failed", + Signing.rsaVerify(Keys.getRSAPublic(pair), msg, sig)); + } + + @Test + public void testDsaSignVerify() + throws NoSuchAlgorithmException { + + KeyPair pair = Keys.generateDSAKeyPair(); + + byte[] msg = "message".getBytes(); + + byte[] sig = Signing.dsaSign(Keys.getDSAPrivate(pair), msg); + + assertTrue("Verification of DSA signature failed", + Signing.dsaVerify(Keys.getDSAPublic(pair), msg, sig)); + } +} diff --git a/crypto/src/test/java/org/coniks/crypto/UtilTest.java b/crypto/src/test/java/org/coniks/crypto/UtilTest.java new file mode 100644 index 0000000..961aaaa --- /dev/null +++ b/crypto/src/test/java/org/coniks/crypto/UtilTest.java @@ -0,0 +1,70 @@ +/* + Copyright (c) 2016, Princeton University. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + * Neither the name of Princeton University nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + */ + +package org.coniks.crypto; + +import org.junit.Test; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +import static org.hamcrest.core.StringContains.containsString; + +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; + +/** + * Unit tests for Util. + */ +public class UtilTest +{ + + @Test + public void testDigest() + throws NoSuchAlgorithmException { + + byte[] msg = "message".getBytes(); + + byte[] hash = Util.digest(msg); + + if(hash.length != Util.HASH_SIZE_BYTES) { + fail("Computation of hash failed - wrong length."); + } + + assertNotNull("Computation of hash failed - null", hash); + + assertFalse("Computation of hash failed - hash is all zeros", + Arrays.equals(hash, new byte[Util.HASH_SIZE_BYTES])); + + } +} diff --git a/pom.xml b/pom.xml index 0fa462c..d64e157 100644 --- a/pom.xml +++ b/pom.xml @@ -1,12 +1,32 @@ - + + 4.0.0 + org.coniks coniks-java + 1.3-SNAPSHOT pom - 1.2-SNAPSHOT - CONIKS Java lib and reference + + CONIKS [Parent] http://coniks.org + CONIKS is a key management system that provides transparency for end-user public keys. + + + + + junit + junit + 4.12 + test + + + + + crypto + coniks_common + coniks_server + coniks_test_client + @@ -18,12 +38,57 @@ $COVERALLS_TOKEN + + org.apache.maven.plugins + maven-compiler-plugin + 3.5.1 + + 1.7 + 1.7 + true + true + + -Werror + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.19.1 + - - coniks_common - coniks_server - coniks_test_client - + + + + org.apache.maven.plugins + maven-surefire-report-plugin + 2.19.1 + + + + unit-tests + + report + + + + + + unit-tests-aggregate + false + + report + + + true + + + + + + + diff --git a/protos/README.md b/protos/README.md index df70c29..0fe2e44 100644 --- a/protos/README.md +++ b/protos/README.md @@ -28,7 +28,7 @@ protoc --proto_path=. --java_out=../coniks_common/src .proto This command will automatically place the generated Java code in the appropriate package hierarchy in coniks_common/src. ## Disclaimer -Please keep in mind that this CONIKS reference implementation is under active development. The repository may contain experimental features that aren't fully tested. We recommend using a [tagged release](https://github.com/coniks-sys/coniks-java/releases). +Please keep in mind that this CONIKS Java implementation is under active development. The repository may contain experimental features that aren't fully tested. We recommend using a [tagged release](https://github.com/coniks-sys/coniks-java/releases). ##Documentation [Read the official Google Protobuf documentation](https://developers.google.com/protocol-buffers/)