Break project up into Java and Android build/test.
This commit is contained in:
parent
a4d8f7f6a4
commit
6445ea5f13
|
@ -1,4 +1,4 @@
|
|||
/build
|
||||
build
|
||||
/obj
|
||||
*.iml
|
||||
.gradle
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:1.0.0'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'maven'
|
||||
apply plugin: 'signing'
|
||||
|
||||
archivesBaseName = "axolotl-android"
|
||||
version = version_number
|
||||
group = group_info
|
||||
|
||||
android {
|
||||
compileSdkVersion 21
|
||||
buildToolsVersion "21.1.2"
|
||||
|
||||
sourceSets {
|
||||
androidTest {
|
||||
java.srcDirs = ['src/androidTest/java', project(':tests').file('src/main/java')]
|
||||
}
|
||||
}
|
||||
|
||||
libraryVariants.all { variant ->
|
||||
variant.outputs.each { output ->
|
||||
def outputFile = output.outputFile
|
||||
if (outputFile != null && outputFile.name.endsWith('.aar')) {
|
||||
def fileName = "${archivesBaseName}-${version}.aar"
|
||||
output.outputFile = new File(outputFile.parent, fileName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile "org.whispersystems:curve25519-android:${curve25519_version}"
|
||||
compile (project(':java')) {
|
||||
exclude group: 'org.whispersystems', module: 'curve25519-java'
|
||||
}
|
||||
}
|
||||
|
||||
signing {
|
||||
required { has("release") && gradle.taskGraph.hasTask("uploadArchives") }
|
||||
sign configurations.archives
|
||||
}
|
||||
|
||||
uploadArchives {
|
||||
configuration = configurations.archives
|
||||
repositories.mavenDeployer {
|
||||
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
|
||||
|
||||
repository(url: sonatypeRepo) {
|
||||
authentication(userName: whisperSonatypeUsername, password: whisperSonatypePassword)
|
||||
}
|
||||
|
||||
pom.project {
|
||||
name 'axolotl-android'
|
||||
packaging 'aar'
|
||||
description 'Axolotl library for Android'
|
||||
url 'https://github.com/WhisperSystems/libaxolotl-android'
|
||||
|
||||
scm {
|
||||
url 'scm:git@github.com:WhisperSystems/libaxolotl-android.git'
|
||||
connection 'scm:git@github.com:WhisperSystems/libaxolotl-android.git'
|
||||
developerConnection 'scm:git@github.com:WhisperSystems/libaxolotl-android.git'
|
||||
}
|
||||
|
||||
developers {
|
||||
developer {
|
||||
name 'Moxie Marlinspike'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task installArchives(type: Upload) {
|
||||
description "Installs the artifacts to the local Maven repository."
|
||||
configuration = configurations['archives']
|
||||
repositories {
|
||||
mavenDeployer {
|
||||
repository url: "file://${System.properties['user.home']}/.m2/repository"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package org.whispersystems.libaxolotl;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.whispersystems.libaxolotl.ecc.Curve;
|
||||
import org.whispersystems.libaxolotl.ecc.ECKeyPair;
|
||||
|
||||
public class CurveTest extends TestCase {
|
||||
|
||||
public void testPureJava() {
|
||||
assertTrue(Curve.isNative());
|
||||
}
|
||||
|
||||
public void testSignatureOverflow() throws InvalidKeyException {
|
||||
ECKeyPair keys = Curve.generateKeyPair();
|
||||
byte[] message = new byte[4096];
|
||||
|
||||
try {
|
||||
byte[] signature = Curve.calculateSignature(keys.getPrivateKey(), message);
|
||||
throw new InvalidKeyException("Should have asserted!");
|
||||
} catch (AssertionError e) {
|
||||
// Success!
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.whispersystems.libaxolotl">
|
||||
</manifest>
|
|
@ -0,0 +1,24 @@
|
|||
package org.whispersystems.libaxolotl.util;
|
||||
|
||||
import android.util.Log;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import org.whispersystems.libaxolotl.logging.AxolotlLogger;
|
||||
|
||||
public class AndroidAxolotlLogger implements AxolotlLogger {
|
||||
|
||||
private static final SparseIntArray PRIORITY_MAP = new SparseIntArray(5) {{
|
||||
put(AxolotlLogger.INFO, Log.INFO);
|
||||
put(AxolotlLogger.ASSERT, Log.ASSERT);
|
||||
put(AxolotlLogger.DEBUG, Log.DEBUG);
|
||||
put(AxolotlLogger.VERBOSE, Log.VERBOSE);
|
||||
put(AxolotlLogger.WARN, Log.WARN);
|
||||
|
||||
}};
|
||||
|
||||
@Override
|
||||
public void log(int priority, String tag, String message) {
|
||||
int androidPriority = PRIORITY_MAP.get(priority, Log.WARN);
|
||||
Log.println(androidPriority, tag, message);
|
||||
}
|
||||
}
|
109
build.gradle
109
build.gradle
|
@ -1,110 +1,19 @@
|
|||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:1.0.0'
|
||||
classpath files('libs/gradle-witness.jar')
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'witness'
|
||||
apply plugin: 'maven'
|
||||
apply plugin: 'signing'
|
||||
subprojects {
|
||||
apply plugin: 'witness'
|
||||
|
||||
archivesBaseName = "axolotl-android"
|
||||
version = "1.0.0"
|
||||
group = "org.whispersystems"
|
||||
ext.version_number = "1.0.1"
|
||||
ext.group_info = "org.whispersystems"
|
||||
ext.curve25519_version = "0.1.3"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'com.google.protobuf:protobuf-java:2.5.0'
|
||||
}
|
||||
|
||||
dependencyVerification {
|
||||
verify = [
|
||||
'com.google.protobuf:protobuf-java:e0c1c64575c005601725e7c6a02cebf9e1285e888f756b2a1d73ffa8d725cc74',
|
||||
]
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 21
|
||||
buildToolsVersion '21.1.1'
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_7
|
||||
targetCompatibility JavaVersion.VERSION_1_7
|
||||
}
|
||||
|
||||
android {
|
||||
sourceSets {
|
||||
main {
|
||||
jniLibs.srcDirs = ['libs']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
libraryVariants.all { variant ->
|
||||
variant.outputs.each { output ->
|
||||
def outputFile = output.outputFile
|
||||
if (outputFile != null && outputFile.name.endsWith('.aar')) {
|
||||
def fileName = "${archivesBaseName}-${version}.aar"
|
||||
output.outputFile = new File(outputFile.parent, fileName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
signing {
|
||||
required { has("release") && gradle.taskGraph.hasTask("uploadArchives") }
|
||||
sign configurations.archives
|
||||
}
|
||||
|
||||
uploadArchives {
|
||||
configuration = configurations.archives
|
||||
repositories.mavenDeployer {
|
||||
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
|
||||
|
||||
repository(url: sonatypeRepo) {
|
||||
authentication(userName: whisperSonatypeUsername, password: whisperSonatypePassword)
|
||||
}
|
||||
|
||||
pom.project {
|
||||
name 'axolotl-android'
|
||||
packaging 'aar'
|
||||
description 'Axolotl encryption library for Android'
|
||||
url 'https://github.com/WhisperSystems/libaxolotl-android'
|
||||
|
||||
scm {
|
||||
url 'scm:git@github.com:WhisperSystems/libaxolotl-android.git'
|
||||
connection 'scm:git@github.com:WhisperSystems/libaxolotl-android.git'
|
||||
developerConnection 'scm:git@github.com:WhisperSystems/libaxolotl-android.git'
|
||||
}
|
||||
|
||||
licenses {
|
||||
license {
|
||||
name 'GPLv3'
|
||||
url 'https://www.gnu.org/licenses/gpl-3.0.txt'
|
||||
distribution 'repo'
|
||||
}
|
||||
}
|
||||
|
||||
developers {
|
||||
developer {
|
||||
name 'Moxie Marlinspike'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.whenTaskAdded { task ->
|
||||
if (task.name.equals("lint")) {
|
||||
task.enabled = false
|
||||
dependencyVerification {
|
||||
verify = [
|
||||
'com.google.protobuf:protobuf-java:e0c1c64575c005601725e7c6a02cebf9e1285e888f756b2a1d73ffa8d725cc74',
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
apply plugin: 'java'
|
||||
apply plugin: 'maven'
|
||||
apply plugin: 'signing'
|
||||
|
||||
sourceCompatibility = 1.7
|
||||
archivesBaseName = "axolotl-java"
|
||||
version = version_number
|
||||
group = group_info
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
test {
|
||||
java {
|
||||
srcDirs = ['src/test/java/', project(':tests').file('src/main/java')]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile "org.whispersystems:curve25519-java:${curve25519_version}"
|
||||
compile 'com.google.protobuf:protobuf-java:2.5.0'
|
||||
|
||||
testCompile ('junit:junit:3.8.2')
|
||||
}
|
||||
|
||||
|
||||
test {
|
||||
testLogging {
|
||||
events 'passed'
|
||||
showStandardStreams = true
|
||||
}
|
||||
|
||||
include 'org/whispersystems/**'
|
||||
}
|
||||
|
||||
signing {
|
||||
required { has("release") && gradle.taskGraph.hasTask("uploadArchives") }
|
||||
sign configurations.archives
|
||||
}
|
||||
|
||||
uploadArchives {
|
||||
configuration = configurations.archives
|
||||
repositories.mavenDeployer {
|
||||
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
|
||||
|
||||
repository(url: sonatypeRepo) {
|
||||
authentication(userName: whisperSonatypeUsername, password: whisperSonatypePassword)
|
||||
}
|
||||
|
||||
pom.project {
|
||||
name 'axolotl-java'
|
||||
packaging 'jar'
|
||||
description 'Axolotl library for Java'
|
||||
url 'https://github.com/WhisperSystems/libaxolotl-android'
|
||||
|
||||
scm {
|
||||
url 'scm:git@github.com:WhisperSystems/libaxolotl-android.git'
|
||||
connection 'scm:git@github.com:WhisperSystems/libaxolotl-android.git'
|
||||
developerConnection 'scm:git@github.com:WhisperSystems/libaxolotl-android.git'
|
||||
}
|
||||
|
||||
developers {
|
||||
developer {
|
||||
name 'Moxie Marlinspike'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task installArchives(type: Upload) {
|
||||
description "Installs the artifacts to the local Maven repository."
|
||||
configuration = configurations['archives']
|
||||
repositories {
|
||||
mavenDeployer {
|
||||
repository url: "file://${System.properties['user.home']}/.m2/repository"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
package org.whispersystems.libaxolotl;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.whispersystems.libaxolotl.ecc.Curve;
|
||||
import org.whispersystems.libaxolotl.ecc.ECKeyPair;
|
||||
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
|
||||
import org.whispersystems.libaxolotl.logging.Log;
|
||||
import org.whispersystems.libaxolotl.protocol.CiphertextMessage;
|
||||
import org.whispersystems.libaxolotl.protocol.KeyExchangeMessage;
|
||||
import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage;
|
|
@ -16,25 +16,41 @@
|
|||
*/
|
||||
package org.whispersystems.libaxolotl.ecc;
|
||||
|
||||
import org.whispersystems.curve25519.Curve25519KeyPair;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.curve25519.Curve25519;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
public class Curve {
|
||||
|
||||
public static final int DJB_TYPE = 0x05;
|
||||
|
||||
public static boolean isNative() {
|
||||
return Curve25519.isNative();
|
||||
}
|
||||
|
||||
public static ECKeyPair generateKeyPair() {
|
||||
return Curve25519.generateKeyPair();
|
||||
SecureRandom secureRandom = getSecureRandom();
|
||||
Curve25519KeyPair keyPair = Curve25519.generateKeyPair(secureRandom);
|
||||
|
||||
return new ECKeyPair(new DjbECPublicKey(keyPair.getPublicKey()),
|
||||
new DjbECPrivateKey(keyPair.getPrivateKey()));
|
||||
}
|
||||
|
||||
public static ECPublicKey decodePoint(byte[] bytes, int offset)
|
||||
throws InvalidKeyException
|
||||
{
|
||||
int type = bytes[offset];
|
||||
int type = bytes[offset] & 0xFF;
|
||||
|
||||
if (type == DJB_TYPE) {
|
||||
return Curve25519.decodePoint(bytes, offset);
|
||||
} else {
|
||||
throw new InvalidKeyException("Unknown key type: " + type);
|
||||
switch (type) {
|
||||
case Curve.DJB_TYPE:
|
||||
byte[] keyBytes = new byte[32];
|
||||
System.arraycopy(bytes, offset+1, keyBytes, 0, keyBytes.length);
|
||||
return new DjbECPublicKey(keyBytes);
|
||||
default:
|
||||
throw new InvalidKeyException("Bad key type: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,7 +66,8 @@ public class Curve {
|
|||
}
|
||||
|
||||
if (publicKey.getType() == DJB_TYPE) {
|
||||
return Curve25519.calculateAgreement(publicKey, privateKey);
|
||||
return Curve25519.calculateAgreement(((DjbECPublicKey)publicKey).getPublicKey(),
|
||||
((DjbECPrivateKey)privateKey).getPrivateKey());
|
||||
} else {
|
||||
throw new InvalidKeyException("Unknown type: " + publicKey.getType());
|
||||
}
|
||||
|
@ -60,7 +77,7 @@ public class Curve {
|
|||
throws InvalidKeyException
|
||||
{
|
||||
if (signingKey.getType() == DJB_TYPE) {
|
||||
return Curve25519.verifySignature(signingKey, message, signature);
|
||||
return Curve25519.verifySignature(((DjbECPublicKey)signingKey).getPublicKey(), message, signature);
|
||||
} else {
|
||||
throw new InvalidKeyException("Unknown type: " + signingKey.getType());
|
||||
}
|
||||
|
@ -70,9 +87,17 @@ public class Curve {
|
|||
throws InvalidKeyException
|
||||
{
|
||||
if (signingKey.getType() == DJB_TYPE) {
|
||||
return Curve25519.calculateSignature(signingKey, message);
|
||||
return Curve25519.calculateSignature(getSecureRandom(), ((DjbECPrivateKey)signingKey).getPrivateKey(), message);
|
||||
} else {
|
||||
throw new InvalidKeyException("Unknown type: " + signingKey.getType());
|
||||
}
|
||||
}
|
||||
|
||||
private static SecureRandom getSecureRandom() {
|
||||
try {
|
||||
return SecureRandom.getInstance("SHA1PRNG");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package org.whispersystems.libaxolotl.logging;
|
||||
|
||||
public interface AxolotlLogger {
|
||||
|
||||
public static final int VERBOSE = 2;
|
||||
public static final int DEBUG = 3;
|
||||
public static final int INFO = 4;
|
||||
public static final int WARN = 5;
|
||||
public static final int ERROR = 6;
|
||||
public static final int ASSERT = 7;
|
||||
|
||||
public void log(int priority, String tag, String message);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.whispersystems.libaxolotl.logging;
|
||||
|
||||
public class AxolotlLoggerProvider {
|
||||
|
||||
private static AxolotlLogger provider;
|
||||
|
||||
public static AxolotlLogger getProvider() {
|
||||
return provider;
|
||||
}
|
||||
|
||||
public static void setProvider(AxolotlLogger provider) {
|
||||
AxolotlLoggerProvider.provider = provider;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
package org.whispersystems.libaxolotl.logging;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
public class Log {
|
||||
|
||||
private Log() {}
|
||||
|
||||
public static void v(String tag, String msg) {
|
||||
log(AxolotlLogger.VERBOSE, tag, msg);
|
||||
}
|
||||
|
||||
public static void v(String tag, String msg, Throwable tr) {
|
||||
log(AxolotlLogger.VERBOSE, tag, msg + '\n' + getStackTraceString(tr));
|
||||
}
|
||||
|
||||
public static void d(String tag, String msg) {
|
||||
log(AxolotlLogger.DEBUG, tag, msg);
|
||||
}
|
||||
|
||||
public static void d(String tag, String msg, Throwable tr) {
|
||||
log(AxolotlLogger.DEBUG, tag, msg + '\n' + getStackTraceString(tr));
|
||||
}
|
||||
|
||||
public static void i(String tag, String msg) {
|
||||
log(AxolotlLogger.INFO, tag, msg);
|
||||
}
|
||||
|
||||
public static void i(String tag, String msg, Throwable tr) {
|
||||
log(AxolotlLogger.INFO, tag, msg + '\n' + getStackTraceString(tr));
|
||||
}
|
||||
|
||||
public static void w(String tag, String msg) {
|
||||
log(AxolotlLogger.WARN, tag, msg);
|
||||
}
|
||||
|
||||
public static void w(String tag, String msg, Throwable tr) {
|
||||
log(AxolotlLogger.WARN, tag, msg + '\n' + getStackTraceString(tr));
|
||||
}
|
||||
|
||||
public static void w(String tag, Throwable tr) {
|
||||
log(AxolotlLogger.WARN, tag, getStackTraceString(tr));
|
||||
}
|
||||
|
||||
public static void e(String tag, String msg) {
|
||||
log(AxolotlLogger.ERROR, tag, msg);
|
||||
}
|
||||
|
||||
public static void e(String tag, String msg, Throwable tr) {
|
||||
log(AxolotlLogger.ERROR, tag, msg + '\n' + getStackTraceString(tr));
|
||||
}
|
||||
|
||||
private static String getStackTraceString(Throwable tr) {
|
||||
if (tr == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// This is to reduce the amount of log spew that apps do in the non-error
|
||||
// condition of the network being unavailable.
|
||||
Throwable t = tr;
|
||||
while (t != null) {
|
||||
if (t instanceof UnknownHostException) {
|
||||
return "";
|
||||
}
|
||||
t = t.getCause();
|
||||
}
|
||||
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
tr.printStackTrace(pw);
|
||||
pw.flush();
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
private static void log(int priority, String tag, String msg) {
|
||||
AxolotlLogger logger = AxolotlLoggerProvider.getProvider();
|
||||
|
||||
if (logger != null) {
|
||||
logger.log(priority, tag, msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
package org.whispersystems.libaxolotl.state;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
|
||||
|
@ -29,6 +28,7 @@ import org.whispersystems.libaxolotl.ecc.ECKeyPair;
|
|||
import org.whispersystems.libaxolotl.ecc.ECPrivateKey;
|
||||
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
|
||||
import org.whispersystems.libaxolotl.kdf.HKDF;
|
||||
import org.whispersystems.libaxolotl.logging.Log;
|
||||
import org.whispersystems.libaxolotl.ratchet.ChainKey;
|
||||
import org.whispersystems.libaxolotl.ratchet.MessageKeys;
|
||||
import org.whispersystems.libaxolotl.ratchet.RootKey;
|
|
@ -0,0 +1,26 @@
|
|||
package org.whispersystems.libaxolotl;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.whispersystems.libaxolotl.ecc.Curve;
|
||||
import org.whispersystems.libaxolotl.ecc.ECKeyPair;
|
||||
|
||||
public class CurveTest extends TestCase {
|
||||
|
||||
public void testPureJava() {
|
||||
assertFalse(Curve.isNative());
|
||||
}
|
||||
|
||||
public void testSignatureOverflow() throws InvalidKeyException {
|
||||
ECKeyPair keys = Curve.generateKeyPair();
|
||||
byte[] message = new byte[4096];
|
||||
|
||||
try {
|
||||
byte[] signature = Curve.calculateSignature(keys.getPrivateKey(), message);
|
||||
throw new InvalidKeyException("Should have asserted!");
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Success!
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
include ':java', ':android', ':tests'
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.whispersystems.libaxolotl"
|
||||
android:versionCode="1"
|
||||
android:versionName="0.1">
|
||||
<application />
|
||||
</manifest>
|
|
@ -1,98 +0,0 @@
|
|||
/**
|
||||
* Copyright (C) 2013 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.libaxolotl.ecc;
|
||||
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
public class Curve25519 {
|
||||
|
||||
static {
|
||||
System.loadLibrary("curve25519");
|
||||
|
||||
try {
|
||||
random = SecureRandom.getInstance("SHA1PRNG");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static final SecureRandom random;
|
||||
|
||||
private static native byte[] calculateAgreement(byte[] ourPrivate, byte[] theirPublic);
|
||||
private static native byte[] generatePublicKey(byte[] privateKey);
|
||||
private static native byte[] generatePrivateKey(byte[] random);
|
||||
|
||||
private static native byte[] calculateSignature(byte[] random, byte[] privateKey, byte[] message);
|
||||
private static native boolean verifySignature(byte[] publicKey, byte[] message, byte[] signature);
|
||||
|
||||
public static ECKeyPair generateKeyPair() {
|
||||
byte[] privateKey = generatePrivateKey();
|
||||
byte[] publicKey = generatePublicKey(privateKey);
|
||||
|
||||
return new ECKeyPair(new DjbECPublicKey(publicKey), new DjbECPrivateKey(privateKey));
|
||||
}
|
||||
|
||||
static byte[] calculateAgreement(ECPublicKey publicKey, ECPrivateKey privateKey) {
|
||||
return calculateAgreement(((DjbECPrivateKey)privateKey).getPrivateKey(),
|
||||
((DjbECPublicKey)publicKey).getPublicKey());
|
||||
}
|
||||
|
||||
static byte[] calculateSignature(ECPrivateKey privateKey, byte[] message) {
|
||||
byte[] random = getRandom(64);
|
||||
return calculateSignature(random, ((DjbECPrivateKey)privateKey).getPrivateKey(), message);
|
||||
}
|
||||
|
||||
static boolean verifySignature(ECPublicKey publicKey, byte[] message, byte[] signature) {
|
||||
return verifySignature(((DjbECPublicKey)publicKey).getPublicKey(), message, signature);
|
||||
}
|
||||
|
||||
static ECPublicKey decodePoint(byte[] encoded, int offset)
|
||||
throws InvalidKeyException
|
||||
{
|
||||
int type = encoded[offset] & 0xFF;
|
||||
byte[] keyBytes = new byte[32];
|
||||
System.arraycopy(encoded, offset+1, keyBytes, 0, keyBytes.length);
|
||||
|
||||
if (type != Curve.DJB_TYPE) {
|
||||
throw new InvalidKeyException("Bad key type: " + type);
|
||||
}
|
||||
|
||||
return new DjbECPublicKey(keyBytes);
|
||||
}
|
||||
|
||||
private static byte[] generatePrivateKey() {
|
||||
byte[] privateKey = new byte[32];
|
||||
random.nextBytes(privateKey);
|
||||
|
||||
return generatePrivateKey(privateKey);
|
||||
}
|
||||
|
||||
private static byte[] getRandom(int size) {
|
||||
try {
|
||||
byte[] random = new byte[size];
|
||||
SecureRandom.getInstance("SHA1PRNG").nextBytes(random);
|
||||
|
||||
return random;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
apply plugin: 'java'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'junit:junit:3.8.2'
|
||||
testCompile 'junit:junit:3.8.2'
|
||||
|
||||
compile project(':java')
|
||||
}
|
|
@ -1,8 +1,5 @@
|
|||
package org.whispersystems.test;
|
||||
package org.whispersystems.libaxolotl;
|
||||
|
||||
import org.whispersystems.libaxolotl.IdentityKey;
|
||||
import org.whispersystems.libaxolotl.IdentityKeyPair;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyIdException;
|
||||
import org.whispersystems.libaxolotl.state.AxolotlStore;
|
||||
import org.whispersystems.libaxolotl.state.PreKeyRecord;
|
||||
import org.whispersystems.libaxolotl.state.SessionRecord;
|
|
@ -1,7 +1,5 @@
|
|||
package org.whispersystems.test;
|
||||
package org.whispersystems.libaxolotl;
|
||||
|
||||
import org.whispersystems.libaxolotl.IdentityKey;
|
||||
import org.whispersystems.libaxolotl.IdentityKeyPair;
|
||||
import org.whispersystems.libaxolotl.ecc.Curve;
|
||||
import org.whispersystems.libaxolotl.ecc.ECKeyPair;
|
||||
import org.whispersystems.libaxolotl.state.IdentityKeyStore;
|
|
@ -1,6 +1,5 @@
|
|||
package org.whispersystems.test;
|
||||
package org.whispersystems.libaxolotl;
|
||||
|
||||
import org.whispersystems.libaxolotl.InvalidKeyIdException;
|
||||
import org.whispersystems.libaxolotl.state.PreKeyRecord;
|
||||
import org.whispersystems.libaxolotl.state.PreKeyStore;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package org.whispersystems.test;
|
||||
package org.whispersystems.libaxolotl;
|
||||
|
||||
import org.whispersystems.libaxolotl.state.SessionRecord;
|
||||
import org.whispersystems.libaxolotl.state.SessionStore;
|
|
@ -1,6 +1,5 @@
|
|||
package org.whispersystems.test;
|
||||
package org.whispersystems.libaxolotl;
|
||||
|
||||
import org.whispersystems.libaxolotl.InvalidKeyIdException;
|
||||
import org.whispersystems.libaxolotl.state.SignedPreKeyRecord;
|
||||
import org.whispersystems.libaxolotl.state.SignedPreKeyStore;
|
||||
|
|
@ -1,18 +1,7 @@
|
|||
package org.whispersystems.test;
|
||||
package org.whispersystems.libaxolotl;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.whispersystems.libaxolotl.DuplicateMessageException;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyIdException;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.InvalidVersionException;
|
||||
import org.whispersystems.libaxolotl.LegacyMessageException;
|
||||
import org.whispersystems.libaxolotl.NoSessionException;
|
||||
import org.whispersystems.libaxolotl.SessionBuilder;
|
||||
import org.whispersystems.libaxolotl.SessionCipher;
|
||||
import org.whispersystems.libaxolotl.StaleKeyExchangeException;
|
||||
import org.whispersystems.libaxolotl.UntrustedIdentityException;
|
||||
import org.whispersystems.libaxolotl.ecc.Curve;
|
||||
import org.whispersystems.libaxolotl.ecc.ECKeyPair;
|
||||
import org.whispersystems.libaxolotl.protocol.CiphertextMessage;
|
||||
|
@ -29,7 +18,7 @@ import org.whispersystems.libaxolotl.util.Pair;
|
|||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class SessionBuilderTest extends AndroidTestCase {
|
||||
public class SessionBuilderTest extends TestCase {
|
||||
|
||||
private static final long ALICE_RECIPIENT_ID = 5L;
|
||||
private static final long BOB_RECIPIENT_ID = 2L;
|
|
@ -1,15 +1,7 @@
|
|||
package org.whispersystems.test;
|
||||
package org.whispersystems.libaxolotl;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.whispersystems.libaxolotl.DuplicateMessageException;
|
||||
import org.whispersystems.libaxolotl.IdentityKey;
|
||||
import org.whispersystems.libaxolotl.IdentityKeyPair;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.LegacyMessageException;
|
||||
import org.whispersystems.libaxolotl.NoSessionException;
|
||||
import org.whispersystems.libaxolotl.SessionCipher;
|
||||
import org.whispersystems.libaxolotl.ecc.Curve;
|
||||
import org.whispersystems.libaxolotl.ecc.ECKeyPair;
|
||||
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
|
||||
|
@ -31,7 +23,7 @@ import java.util.List;
|
|||
import java.util.Random;
|
||||
|
||||
|
||||
public class SessionCipherTest extends AndroidTestCase {
|
||||
public class SessionCipherTest extends TestCase {
|
||||
|
||||
public void testBasicSessionV2()
|
||||
throws InvalidKeyException, DuplicateMessageException,
|
|
@ -1,18 +1,7 @@
|
|||
package org.whispersystems.test;
|
||||
package org.whispersystems.libaxolotl;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
import android.util.Log;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.whispersystems.libaxolotl.DuplicateMessageException;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.InvalidKeyIdException;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.InvalidVersionException;
|
||||
import org.whispersystems.libaxolotl.LegacyMessageException;
|
||||
import org.whispersystems.libaxolotl.NoSessionException;
|
||||
import org.whispersystems.libaxolotl.SessionBuilder;
|
||||
import org.whispersystems.libaxolotl.SessionCipher;
|
||||
import org.whispersystems.libaxolotl.UntrustedIdentityException;
|
||||
import org.whispersystems.libaxolotl.ecc.Curve;
|
||||
import org.whispersystems.libaxolotl.ecc.ECKeyPair;
|
||||
import org.whispersystems.libaxolotl.protocol.CiphertextMessage;
|
||||
|
@ -27,7 +16,7 @@ import org.whispersystems.libaxolotl.util.Medium;
|
|||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
|
||||
public class SimultaneousInitiateTests extends AndroidTestCase {
|
||||
public class SimultaneousInitiateTests extends TestCase {
|
||||
|
||||
private static final long BOB_RECIPENT_ID = 12345;
|
||||
private static final long ALICE_RECIPIENT_ID = 6789;
|
||||
|
@ -243,7 +232,6 @@ public class SimultaneousInitiateTests extends AndroidTestCase {
|
|||
assertFalse(isSessionIdEqual(aliceStore, bobStore));
|
||||
|
||||
for (int i=0;i<50;i++) {
|
||||
Log.w("SimultaneousInitiateTests", "Iteration: " + i);
|
||||
CiphertextMessage messageForBobRepeat = aliceSessionCipher.encrypt("hey there".getBytes());
|
||||
CiphertextMessage messageForAliceRepeat = bobSessionCipher.encrypt("sample message".getBytes());
|
||||
|
||||
|
@ -323,7 +311,6 @@ public class SimultaneousInitiateTests extends AndroidTestCase {
|
|||
}
|
||||
|
||||
for (int i=0;i<50;i++) {
|
||||
Log.w("SimultaneousInitiateTests", "Iteration: " + i);
|
||||
CiphertextMessage messageForBobRepeat = aliceSessionCipher.encrypt("hey there".getBytes());
|
||||
CiphertextMessage messageForAliceRepeat = bobSessionCipher.encrypt("sample message".getBytes());
|
||||
|
||||
|
@ -412,7 +399,6 @@ public class SimultaneousInitiateTests extends AndroidTestCase {
|
|||
}
|
||||
|
||||
for (int i=0;i<50;i++) {
|
||||
Log.w("SimultaneousInitiateTests", "Iteration: " + i);
|
||||
CiphertextMessage messageForBobRepeat = aliceSessionCipher.encrypt("hey there".getBytes());
|
||||
CiphertextMessage messageForAliceRepeat = bobSessionCipher.encrypt("sample message".getBytes());
|
||||
|
|
@ -1,20 +1,15 @@
|
|||
package org.whispersystems.test.ecc;
|
||||
package org.whispersystems.libaxolotl.ecc;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.whispersystems.libaxolotl.InvalidKeyException;
|
||||
import org.whispersystems.libaxolotl.ecc.Curve;
|
||||
import org.whispersystems.libaxolotl.ecc.ECKeyPair;
|
||||
import org.whispersystems.libaxolotl.ecc.ECPrivateKey;
|
||||
import org.whispersystems.libaxolotl.ecc.ECPublicKey;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
public class Curve25519Test extends AndroidTestCase {
|
||||
public class Curve25519Test extends TestCase {
|
||||
|
||||
public void testAgreement() throws InvalidKeyException {
|
||||
|
||||
byte[] alicePublic = {(byte) 0x05, (byte) 0x1b, (byte) 0xb7, (byte) 0x59, (byte) 0x66,
|
||||
(byte) 0xf2, (byte) 0xe9, (byte) 0x3a, (byte) 0x36, (byte) 0x91,
|
||||
(byte) 0xdf, (byte) 0xff, (byte) 0x94, (byte) 0x2b, (byte) 0xb2,
|
||||
|
@ -138,17 +133,4 @@ public class Curve25519Test extends AndroidTestCase {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void testSignatureOverflow() throws InvalidKeyException {
|
||||
ECKeyPair keys = Curve.generateKeyPair();
|
||||
byte[] message = new byte[4096];
|
||||
|
||||
try {
|
||||
byte[] signature = Curve.calculateSignature(keys.getPrivateKey(), message);
|
||||
throw new InvalidKeyException("Should have asserted!");
|
||||
} catch (AssertionError e) {
|
||||
// Success!
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,25 +1,20 @@
|
|||
package org.whispersystems.test.groups;
|
||||
package org.whispersystems.libaxolotl.groups;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
import android.util.Log;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.whispersystems.libaxolotl.DuplicateMessageException;
|
||||
import org.whispersystems.libaxolotl.InvalidMessageException;
|
||||
import org.whispersystems.libaxolotl.LegacyMessageException;
|
||||
import org.whispersystems.libaxolotl.NoSessionException;
|
||||
import org.whispersystems.libaxolotl.ecc.ECKeyPair;
|
||||
import org.whispersystems.libaxolotl.groups.GroupCipher;
|
||||
import org.whispersystems.libaxolotl.groups.GroupSessionBuilder;
|
||||
import org.whispersystems.libaxolotl.protocol.SenderKeyDistributionMessage;
|
||||
import org.whispersystems.libaxolotl.util.KeyHelper;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class GroupCipherTest extends AndroidTestCase {
|
||||
public class GroupCipherTest extends TestCase {
|
||||
|
||||
public void testBasicEncryptDecrypt()
|
||||
throws LegacyMessageException, DuplicateMessageException, InvalidMessageException, NoSessionException
|
|
@ -1,4 +1,4 @@
|
|||
package org.whispersystems.test.groups;
|
||||
package org.whispersystems.libaxolotl.groups;
|
||||
|
||||
import org.whispersystems.libaxolotl.groups.state.SenderKeyRecord;
|
||||
import org.whispersystems.libaxolotl.groups.state.SenderKeyStore;
|
|
@ -1,12 +1,10 @@
|
|||
package org.whispersystems.test.kdf;
|
||||
package org.whispersystems.libaxolotl.kdf;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import org.whispersystems.libaxolotl.kdf.HKDF;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class HKDFTest extends AndroidTestCase {
|
||||
public class HKDFTest extends TestCase {
|
||||
|
||||
public void testVectorV3() {
|
||||
byte[] ikm = {0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
|
|
@ -1,14 +1,13 @@
|
|||
package org.whispersystems.test.ratchet;
|
||||
package org.whispersystems.libaxolotl.ratchet;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.whispersystems.libaxolotl.kdf.HKDF;
|
||||
import org.whispersystems.libaxolotl.ratchet.ChainKey;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class ChainKeyTest extends AndroidTestCase {
|
||||
public class ChainKeyTest extends TestCase {
|
||||
|
||||
public void testChainKeyDerivationV2() throws NoSuchAlgorithmException {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue