Skip to content
This repository has been archived by the owner on Apr 18, 2024. It is now read-only.

Commit

Permalink
Refactored into provider model for initial support of J2ME.
Browse files Browse the repository at this point in the history
  • Loading branch information
moxie0 committed Jan 11, 2015
1 parent 834de83 commit 0f10718
Show file tree
Hide file tree
Showing 74 changed files with 528 additions and 215 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

public class NativeCurve25519ProviderTest extends Curve25519ProviderTest {
@Override
protected Curve25519Provider createProvider() {
protected Curve25519Provider createProvider() throws NoSuchProviderException {
return new NativeCurve25519Provider();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@
public class NativeCurve25519Test extends Curve25519Test {

@Override
public void testCheckProvider() {
assertTrue(Curve25519.isNative());
public void testCheckProvider() throws NoSuchProviderException {
assertTrue(Curve25519.getInstance(getProviderName()).isNative());
}

@Override
public String getProviderName() {
return "native";
}

}
3 changes: 3 additions & 0 deletions common/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
apply plugin: 'java'

sourceCompatibility = 1.2
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/**
* Copyright (C) 2015 Open Whisper Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whispersystems.curve25519;

import org.whispersystems.curve25519.java.Sha512;
import org.whispersystems.curve25519.java.curve_sigs;
import org.whispersystems.curve25519.java.scalarmult;

abstract class BaseJavaCurve25519Provider implements Curve25519Provider {

// @Override
public boolean isNative() {
return false;
}

// @Override
public byte[] calculateAgreement(byte[] ourPrivate, byte[] theirPublic) {
byte[] agreement = new byte[32];
scalarmult.crypto_scalarmult(agreement, ourPrivate, theirPublic);

return agreement;
}

// @Override
public byte[] generatePublicKey(byte[] privateKey) {
byte[] publicKey = new byte[32];
curve_sigs.curve25519_keygen(publicKey, privateKey);

return publicKey;
}

// @Override
public byte[] generatePrivateKey() {
byte[] random = getRandom(PRIVATE_KEY_LEN);
return generatePrivateKey(random);
}

// @Override
public byte[] generatePrivateKey(byte[] random) {
byte[] privateKey = new byte[32];

System.arraycopy(random, 0, privateKey, 0, 32);

privateKey[0] &= 248;
privateKey[31] &= 127;
privateKey[31] |= 64;

return privateKey;
}

// @Override
public byte[] calculateSignature(byte[] random, byte[] privateKey, byte[] message) {
byte[] result = new byte[64];

if (curve_sigs.curve25519_sign(getSha512(), result, privateKey, message, message.length, random) != 0) {
throw new IllegalArgumentException("Message exceeds max length!");
}

return result;
}

// @Override
public boolean verifySignature(byte[] publicKey, byte[] message, byte[] signature) {
return curve_sigs.curve25519_verify(getSha512(), signature, publicKey, message, message.length) == 0;
}

protected abstract Sha512 getSha512();

}
155 changes: 155 additions & 0 deletions common/src/main/java/org/whispersystems/curve25519/Curve25519.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/**
* Copyright (C) 2015 Open Whisper Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whispersystems.curve25519;

/**
* A Curve25519 interface for generating keys, calculating agreements, creating signatures,
* and verifying signatures.
*
* @author Moxie Marlinspike
*/
public class Curve25519 {

public static final String NATIVE = "native";
public static final String JAVA = "java";
public static final String J2ME = "j2me";
public static final String BEST = "best";

public static Curve25519 getInstance(String type) throws NoSuchProviderException {
if (NATIVE.equals(type)) return new Curve25519(constructNativeProvider());
else if (JAVA.equals(type)) return new Curve25519(constructJavaProvider());
else if (J2ME.equals(type)) return new Curve25519(constructJ2meProvider());
else if (BEST.equals(type)) return new Curve25519(constructOpportunisticProvider());
else throw new NoSuchProviderException(type);
}

private final Curve25519Provider provider;

private Curve25519(Curve25519Provider provider) {
this.provider = provider;
}


// static {
// try {
// provider = new NativeCurve25519Provider();
// } catch (UnsatisfiedLinkError ule) {
// provider = new JavaCurve25519Provider();
// }
// }

/**
* {@link Curve25519} is backed by either a native (via JNI)
* or pure-Java provider. By default it prefers the native provider, and falls back to the
* pure-Java provider if the native library fails to load.
*
* @return true if backed by a native provider, false otherwise.
*/
public boolean isNative() {
return provider.isNative();
}

/**
* Generates a Curve25519 keypair.
*
* @return A randomly generated Curve25519 keypair.
*/
public Curve25519KeyPair generateKeyPair() {
byte[] privateKey = provider.generatePrivateKey();
byte[] publicKey = provider.generatePublicKey(privateKey);

return new Curve25519KeyPair(publicKey, privateKey);
}

/**
* Calculates an ECDH agreement.
*
* @param publicKey The Curve25519 (typically remote party's) public key.
* @param privateKey The Curve25519 (typically yours) private key.
* @return A 32-byte shared secret.
*/
public byte[] calculateAgreement(byte[] publicKey, byte[] privateKey) {
return provider.calculateAgreement(privateKey, publicKey);
}

/**
* Calculates a Curve25519 signature.
*
* @param privateKey The private Curve25519 key to create the signature with.
* @param message The message to sign.
* @return A 64-byte signature.
*/
public byte[] calculateSignature(byte[] privateKey, byte[] message) {
byte[] random = provider.getRandom(64);
return provider.calculateSignature(random, privateKey, message);
}

/**
* Verify a Curve25519 signature.
*
* @param publicKey The Curve25519 public key the signature belongs to.
* @param message The message that was signed.
* @param signature The signature to verify.
* @return true if valid, false if not.
*/
public boolean verifySignature(byte[] publicKey, byte[] message, byte[] signature) {
return provider.verifySignature(publicKey, message, signature);
}

// private byte[] generatePrivateKey() {
// byte[] privateKey = new byte[32];
// random.nextBytes(privateKey);
//
// return provider.generatePrivateKey(privateKey);
// }

// private byte[] getRandom(SecureRandom secureRandom, int size) {
// byte[] output = new byte[size];
// secureRandom.nextBytes(output);
//
// return output;
// }

private static Curve25519Provider constructNativeProvider() throws NoSuchProviderException {
return constructClass("NativeCurve25519Provider");
}

private static Curve25519Provider constructJavaProvider() throws NoSuchProviderException {
return constructClass("JavaCurve25519Provider");
}

private static Curve25519Provider constructJ2meProvider() throws NoSuchProviderException {
return constructClass("J2meCurve25519Provider");
}

private static Curve25519Provider constructOpportunisticProvider() throws NoSuchProviderException {
return constructClass("OpportunisticCurve25519Provider");
}

private static Curve25519Provider constructClass(String name) throws NoSuchProviderException {
try {
return (Curve25519Provider)Class.forName("org.whispersystems.curve25519." + name).newInstance();
} catch (InstantiationException e) {
throw new NoSuchProviderException(e);
} catch (IllegalAccessException e) {
throw new NoSuchProviderException(e);
} catch (ClassNotFoundException e) {
throw new NoSuchProviderException(e);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@

interface Curve25519Provider {

static final int PRIVATE_KEY_LEN = 32;

boolean isNative();
byte[] calculateAgreement(byte[] ourPrivate, byte[] theirPublic);
byte[] generatePublicKey(byte[] privateKey);
byte[] generatePrivateKey();
byte[] generatePrivateKey(byte[] random);
byte[] getRandom(int length);

byte[] calculateSignature(byte[] random, byte[] privateKey, byte[] message);
boolean verifySignature(byte[] publicKey, byte[] message, byte[] signature);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.whispersystems.curve25519;

public class NoSuchProviderException extends Exception {
public NoSuchProviderException(Throwable e) {
super(e);
}

public NoSuchProviderException(String type) {
super(type);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.whispersystems.curve25519.java;

public class Arrays {
/**
* Assigns the specified byte value to each element of the specified array
* of bytes.
*
* @param a the array to be filled
* @param val the value to be stored in all elements of the array
*/
public static void fill(byte[] a, byte val) {
for (int i = 0, len = a.length; i < len; i++)
a[i] = val;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.whispersystems.curve25519.java;

public interface Sha512 {

public void calculateDigest(byte[] out, byte[] in, long length);

}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public static void curve25519_keygen(byte[] curve25519_pubkey_out,
fe_tobytes.fe_tobytes(curve25519_pubkey_out, mont_x);
}

public static int curve25519_sign(byte[] signature_out,
public static int curve25519_sign(Sha512 sha512provider, byte[] signature_out,
byte[] curve25519_privkey,
byte[] msg, long msg_len,
byte[] random)
Expand All @@ -48,7 +48,7 @@ public static int curve25519_sign(byte[] signature_out,
byte sign_bit = 0;

if (msg_len > MAX_MSG_LEN) {
java.util.Arrays.fill(signature_out, (byte)0);
Arrays.fill(signature_out, (byte)0);
return -1;
}

Expand All @@ -58,7 +58,7 @@ public static int curve25519_sign(byte[] signature_out,
sign_bit = (byte)(ed_pubkey[31] & 0x80);

/* Perform an Ed25519 signature with explicit private key */
sign_modified.crypto_sign_modified(sigbuf, msg, msg_len, curve25519_privkey,
sign_modified.crypto_sign_modified(sha512provider, sigbuf, msg, msg_len, curve25519_privkey,
ed_pubkey, random);
System.arraycopy(sigbuf, 0, signature_out, 0, 64);

Expand All @@ -68,7 +68,7 @@ public static int curve25519_sign(byte[] signature_out,
return 0;
}

public static int curve25519_verify(byte[] signature,
public static int curve25519_verify(Sha512 sha512provider, byte[] signature,
byte[] curve25519_pubkey,
byte[] msg, long msg_len)
{
Expand Down Expand Up @@ -119,6 +119,6 @@ public static int curve25519_verify(byte[] signature,
/* verifybuf2 = java to next call gets a copy of verifybuf, S gets
replaced with pubkey for hashing, then the whole thing gets zeroized
(if bad sig), or contains a copy of msg (good sig) */
return open.crypto_sign_open(verifybuf2, some_retval, verifybuf, 64 + msg_len, ed_pubkey);
return open.crypto_sign_open(sha512provider, verifybuf2, some_retval, verifybuf, 64 + msg_len, ed_pubkey);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public class open {
//CONVERT #include "sc.h"

public static int crypto_sign_open(
Sha512 sha512provider,
byte[] m, long mlen,
byte[] sm, long smlen,
byte[] pk
Expand All @@ -28,15 +29,15 @@ public static int crypto_sign_open(
if (ge_frombytes.ge_frombytes_negate_vartime(A,pk) != 0) return -1;

byte[] pubkeyhash = new byte[64];
crypto_hash_sha512.crypto_hash_sha512(pubkeyhash,pk,32);
sha512provider.calculateDigest(pubkeyhash,pk,32);

System.arraycopy(pk, 0, pkcopy, 0, 32);
System.arraycopy(sm, 0, rcopy, 0, 32);
System.arraycopy(sm, 32, scopy, 0, 32);

System.arraycopy(sm, 0, m, 0, (int)smlen);
System.arraycopy(pkcopy, 0, m, 32, 32);
crypto_hash_sha512.crypto_hash_sha512(h,m,smlen);
sha512provider.calculateDigest(h,m,smlen);
sc_reduce.sc_reduce(h);

ge_double_scalarmult.ge_double_scalarmult_vartime(R,h,A,scopy);
Expand Down
Loading

0 comments on commit 0f10718

Please sign in to comment.