From 5e10f7dda92d9af9c553850dc8f5ea7effc6628c Mon Sep 17 00:00:00 2001 From: Rhys Weatherley Date: Sat, 18 Jun 2016 15:57:29 +1000 Subject: [PATCH] Interface to Diffie-Hellman algorithms --- .../noise/crypto/Curve25519.java | 45 ++++++ .../noise/protocol/Curve25519DHState.java | 144 +++++++++++++++++ .../southernstorm/noise/protocol/DHState.java | 146 ++++++++++++++++++ .../southernstorm/noise/protocol/Noise.java | 31 ++++ 4 files changed, 366 insertions(+) create mode 100644 NoiseJava/src/com/southernstorm/noise/crypto/Curve25519.java create mode 100644 NoiseJava/src/com/southernstorm/noise/protocol/Curve25519DHState.java create mode 100644 NoiseJava/src/com/southernstorm/noise/protocol/DHState.java diff --git a/NoiseJava/src/com/southernstorm/noise/crypto/Curve25519.java b/NoiseJava/src/com/southernstorm/noise/crypto/Curve25519.java new file mode 100644 index 0000000..19811ec --- /dev/null +++ b/NoiseJava/src/com/southernstorm/noise/crypto/Curve25519.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2016 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package com.southernstorm.noise.crypto; + +/** + * Implementation of the Curve25519 elliptic-curve algorithm. + */ +public final class Curve25519 { + + private Curve25519() {} + + /** + * Evaluates the Curve25519 curve. + * + * @param result Buffer to place the result of the evaluation into. + * @param offset Offset into the result buffer. + * @param privateKey The private key to use in the evaluation. + * @param publicKey The public key to use in the evaluation, or null + * if the base point of the curve should be used. + */ + public static void eval(byte[] result, int offset, byte[] privateKey, byte[] publicKey) + { + // TODO + } +} diff --git a/NoiseJava/src/com/southernstorm/noise/protocol/Curve25519DHState.java b/NoiseJava/src/com/southernstorm/noise/protocol/Curve25519DHState.java new file mode 100644 index 0000000..935a785 --- /dev/null +++ b/NoiseJava/src/com/southernstorm/noise/protocol/Curve25519DHState.java @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2016 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package com.southernstorm.noise.protocol; + +import java.util.Arrays; + +import com.southernstorm.noise.crypto.Curve25519; + +/** + * Implementation of the Curve25519 algorithm for the Noise protocol. + */ +class Curve25519DHState implements DHState { + + private byte[] publicKey; + private byte[] privateKey; + private int mode; + + /** + * Constructs a new Diffie-Hellman object for Curve25519. + */ + public Curve25519DHState() + { + publicKey = new byte [32]; + privateKey = new byte [32]; + mode = 0; + } + + @Override + public void destroy() { + clearKey(); + } + + @Override + public String getDHName() { + return "25519"; + } + + @Override + public int getPublicKeyLength() { + return 32; + } + + @Override + public int getPrivateKeyLength() { + return 32; + } + + @Override + public int getSharedKeyLength() { + return 32; + } + + @Override + public void generateKeyPair() { + Noise.random(privateKey); + Curve25519.eval(publicKey, 0, privateKey, null); + mode = 0x03; + } + + @Override + public void getPublicKey(byte[] key, int offset) { + System.arraycopy(publicKey, 0, key, offset, 32); + } + + @Override + public void setPublicKey(byte[] key, int offset) { + System.arraycopy(key, offset, publicKey, 0, 32); + Arrays.fill(privateKey, (byte)0); + mode = 0x01; + } + + @Override + public void getPrivateKey(byte[] key, int offset) { + System.arraycopy(privateKey, 0, key, offset, 32); + } + + @Override + public void setPrivateKey(byte[] key, int offset) { + System.arraycopy(key, offset, publicKey, 0, 32); + Curve25519.eval(publicKey, 0, privateKey, null); + mode = 0x03; + } + + @Override + public void setToNullPublicKey() { + Arrays.fill(publicKey, (byte)0); + Arrays.fill(privateKey, (byte)0); + mode = 0x01; + } + + @Override + public void clearKey() { + Noise.destroy(publicKey); + Noise.destroy(privateKey); + mode = 0; + } + + @Override + public boolean hasPublicKey() { + return (mode & 0x01) != 0; + } + + @Override + public boolean hasPrivateKey() { + return (mode & 0x02) != 0; + } + + @Override + public boolean isNullPublicKey() { + if ((mode & 0x01) == 0) + return false; + int temp = 0; + for (int index = 0; index < 32; ++index) + temp |= publicKey[index]; + return temp == 0; + } + + @Override + public void calculate(byte[] sharedKey, int offset, DHState publicDH) { + if (!(publicDH instanceof Curve25519DHState)) + throw new IllegalArgumentException("Incompatible DH algorithms"); + Curve25519.eval(sharedKey, offset, privateKey, ((Curve25519DHState)publicDH).publicKey); + } +} diff --git a/NoiseJava/src/com/southernstorm/noise/protocol/DHState.java b/NoiseJava/src/com/southernstorm/noise/protocol/DHState.java new file mode 100644 index 0000000..be74eef --- /dev/null +++ b/NoiseJava/src/com/southernstorm/noise/protocol/DHState.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2016 Southern Storm Software, Pty Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package com.southernstorm.noise.protocol; + +/** + * Interface to a Diffie-Hellman algorithm for the Noise protocol. + */ +public interface DHState extends Destroyable { + + /** + * Gets the Noise protocol name for this Diffie-Hellman algorithm. + * + * @return The algorithm name. + */ + String getDHName(); + + /** + * Gets the length of public keys for this algorithm. + * + * @return The length of public keys in bytes. + */ + int getPublicKeyLength(); + + /** + * Gets the length of private keys for this algorithm. + * + * @return The length of private keys in bytes. + */ + int getPrivateKeyLength(); + + /** + * Gets the length of shared keys for this algorithm. + * + * @return The length of shared keys in bytes. + */ + int getSharedKeyLength(); + + /** + * Generates a new random keypair. + */ + void generateKeyPair(); + + /** + * Gets the public key associated with this object. + * + * @param key The buffer to copy the public key to. + * @param offset The first offset in the key buffer to copy to. + */ + void getPublicKey(byte[] key, int offset); + + /** + * Sets the public key for this object. + * + * @param key The buffer containing the public key. + * @param offset The first offset in the buffer that contains the key. + * + * If this object previously held a key pair, then this function + * will change it into a public key only object. + */ + void setPublicKey(byte[] key, int offset); + + /** + * Gets the private key associated with this object. + * + * @param key The buffer to copy the private key to. + * @param offset The first offset in the key buffer to copy to. + */ + void getPrivateKey(byte[] key, int offset); + + /** + * Sets the private key for this object. + * + * @param key The buffer containing the [rivate key. + * @param offset The first offset in the buffer that contains the key. + * + * If this object previously held only a public key, then + * this function will change it into a key pair. + */ + void setPrivateKey(byte[] key, int offset); + + /** + * Sets this object to the null public key and clears the private key. + */ + void setToNullPublicKey(); + + /** + * Clears the key pair. + */ + void clearKey(); + + /** + * Determine if this object contains a public key. + * + * @return Returns true if this object contains a public key, + * or false if the public key has not yet been set. + */ + boolean hasPublicKey(); + + /** + * Determine if this object contains a private key. + * + * @return Returns true if this object contains a private key, + * or false if the private key has not yet been set. + */ + boolean hasPrivateKey(); + + /** + * Determine if the public key in this object is the special null value. + * + * @return Returns true if the public key is the special null value, + * or false otherwise. + */ + boolean isNullPublicKey(); + + /** + * Performs a Diffie-Hellman calculation with this object as the private key. + * + * @param sharedKey Buffer to put the shared key into. + * @param offset Offset of the first byte for the shared key. + * @param publicDH Object that contains the public key for the calculation. + * + * @throws IllegalArgumentException The publicDH object is not the same + * type as this object, or one of the objects does not contain a valid key. + */ + void calculate(byte[] sharedKey, int offset, DHState publicDH); +} diff --git a/NoiseJava/src/com/southernstorm/noise/protocol/Noise.java b/NoiseJava/src/com/southernstorm/noise/protocol/Noise.java index c52130e..55ffa67 100644 --- a/NoiseJava/src/com/southernstorm/noise/protocol/Noise.java +++ b/NoiseJava/src/com/southernstorm/noise/protocol/Noise.java @@ -24,6 +24,7 @@ package com.southernstorm.noise.protocol; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; import java.util.Arrays; import com.southernstorm.noise.crypto.Blake2bMessageDigest; @@ -43,7 +44,37 @@ public final class Noise { { Arrays.fill(array, (byte)0); } + + private static SecureRandom random = new SecureRandom(); + /** + * Generates random data using the system random number generator. + * + * @param data The data buffer to fill with random data. + */ + public static void random(byte[] data) + { + random.nextBytes(data); + } + + /** + * Creates a Diffie-Hellman object from its Noise protocol name. + * + * @param name The name of the DH algorithm; e.g. "25519", "448", etc. + * + * @return The Diffie-Hellman object if the name is recognized. + * + * @throws NoSuchAlgorithmException The name is not recognized as a + * valid Noise protocol name, or there is no cryptography provider + * in the system that implements the algorithm. + */ + public static DHState createDH(String name) throws NoSuchAlgorithmException + { + if (name.equals("25519")) + return new Curve25519DHState(); + throw new NoSuchAlgorithmException("Unknown Noise DH algorithm name: " + name); + } + /** * Creates a cipher object from its Noise protocol name. *