mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-21 23:29:52 +01:00
Removed all uses of JCE so we can use full-strength crypto on all JVMs.
This commit is contained in:
@@ -13,7 +13,6 @@ import static net.sf.briar.android.util.CommonLayoutParams.MATCH_MATCH;
|
|||||||
import static net.sf.briar.android.util.CommonLayoutParams.WRAP_WRAP;
|
import static net.sf.briar.android.util.CommonLayoutParams.WRAP_WRAP;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.KeyPair;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
@@ -23,6 +22,7 @@ import net.sf.briar.api.LocalAuthor;
|
|||||||
import net.sf.briar.api.android.ReferenceManager;
|
import net.sf.briar.api.android.ReferenceManager;
|
||||||
import net.sf.briar.api.crypto.CryptoComponent;
|
import net.sf.briar.api.crypto.CryptoComponent;
|
||||||
import net.sf.briar.api.crypto.CryptoExecutor;
|
import net.sf.briar.api.crypto.CryptoExecutor;
|
||||||
|
import net.sf.briar.api.crypto.KeyPair;
|
||||||
import net.sf.briar.api.db.DatabaseConfig;
|
import net.sf.briar.api.db.DatabaseConfig;
|
||||||
import net.sf.briar.util.StringUtils;
|
import net.sf.briar.util.StringUtils;
|
||||||
import roboguice.activity.RoboActivity;
|
import roboguice.activity.RoboActivity;
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import static net.sf.briar.android.util.CommonLayoutParams.MATCH_MATCH;
|
|||||||
import static net.sf.briar.android.util.CommonLayoutParams.WRAP_WRAP;
|
import static net.sf.briar.android.util.CommonLayoutParams.WRAP_WRAP;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.KeyPair;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
@@ -29,6 +28,7 @@ import net.sf.briar.api.ContactId;
|
|||||||
import net.sf.briar.api.android.DatabaseUiExecutor;
|
import net.sf.briar.api.android.DatabaseUiExecutor;
|
||||||
import net.sf.briar.api.crypto.CryptoComponent;
|
import net.sf.briar.api.crypto.CryptoComponent;
|
||||||
import net.sf.briar.api.crypto.CryptoExecutor;
|
import net.sf.briar.api.crypto.CryptoExecutor;
|
||||||
|
import net.sf.briar.api.crypto.KeyPair;
|
||||||
import net.sf.briar.api.db.DatabaseComponent;
|
import net.sf.briar.api.db.DatabaseComponent;
|
||||||
import net.sf.briar.api.db.DbException;
|
import net.sf.briar.api.db.DbException;
|
||||||
import net.sf.briar.api.lifecycle.LifecycleManager;
|
import net.sf.briar.api.lifecycle.LifecycleManager;
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import static net.sf.briar.android.util.CommonLayoutParams.MATCH_WRAP;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.PrivateKey;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
@@ -27,6 +26,7 @@ import net.sf.briar.api.LocalAuthor;
|
|||||||
import net.sf.briar.api.android.DatabaseUiExecutor;
|
import net.sf.briar.api.android.DatabaseUiExecutor;
|
||||||
import net.sf.briar.api.crypto.CryptoComponent;
|
import net.sf.briar.api.crypto.CryptoComponent;
|
||||||
import net.sf.briar.api.crypto.KeyParser;
|
import net.sf.briar.api.crypto.KeyParser;
|
||||||
|
import net.sf.briar.api.crypto.PrivateKey;
|
||||||
import net.sf.briar.api.db.DatabaseComponent;
|
import net.sf.briar.api.db.DatabaseComponent;
|
||||||
import net.sf.briar.api.db.DbException;
|
import net.sf.briar.api.db.DbException;
|
||||||
import net.sf.briar.api.lifecycle.LifecycleManager;
|
import net.sf.briar.api.lifecycle.LifecycleManager;
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import static net.sf.briar.android.util.CommonLayoutParams.MATCH_WRAP;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.PrivateKey;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -30,6 +29,7 @@ import net.sf.briar.api.LocalAuthor;
|
|||||||
import net.sf.briar.api.android.DatabaseUiExecutor;
|
import net.sf.briar.api.android.DatabaseUiExecutor;
|
||||||
import net.sf.briar.api.crypto.CryptoComponent;
|
import net.sf.briar.api.crypto.CryptoComponent;
|
||||||
import net.sf.briar.api.crypto.KeyParser;
|
import net.sf.briar.api.crypto.KeyParser;
|
||||||
|
import net.sf.briar.api.crypto.PrivateKey;
|
||||||
import net.sf.briar.api.db.DatabaseComponent;
|
import net.sf.briar.api.db.DatabaseComponent;
|
||||||
import net.sf.briar.api.db.DbException;
|
import net.sf.briar.api.db.DbException;
|
||||||
import net.sf.briar.api.lifecycle.LifecycleManager;
|
import net.sf.briar.api.lifecycle.LifecycleManager;
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import static net.sf.briar.android.util.CommonLayoutParams.WRAP_WRAP;
|
|||||||
import static net.sf.briar.api.messaging.Rating.GOOD;
|
import static net.sf.briar.api.messaging.Rating.GOOD;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.KeyPair;
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@@ -25,6 +24,7 @@ import net.sf.briar.api.LocalAuthor;
|
|||||||
import net.sf.briar.api.android.DatabaseUiExecutor;
|
import net.sf.briar.api.android.DatabaseUiExecutor;
|
||||||
import net.sf.briar.api.crypto.CryptoComponent;
|
import net.sf.briar.api.crypto.CryptoComponent;
|
||||||
import net.sf.briar.api.crypto.CryptoExecutor;
|
import net.sf.briar.api.crypto.CryptoExecutor;
|
||||||
|
import net.sf.briar.api.crypto.KeyPair;
|
||||||
import net.sf.briar.api.db.DatabaseComponent;
|
import net.sf.briar.api.db.DatabaseComponent;
|
||||||
import net.sf.briar.api.db.DbException;
|
import net.sf.briar.api.db.DbException;
|
||||||
import net.sf.briar.api.lifecycle.LifecycleManager;
|
import net.sf.briar.api.lifecycle.LifecycleManager;
|
||||||
|
|||||||
@@ -1,28 +1,20 @@
|
|||||||
package net.sf.briar.api.crypto;
|
package net.sf.briar.api.crypto;
|
||||||
|
|
||||||
import java.security.InvalidKeyException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.Key;
|
|
||||||
|
|
||||||
import javax.crypto.BadPaddingException;
|
/** An authenticated cipher that support additional authenticated data. */
|
||||||
import javax.crypto.IllegalBlockSizeException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A wrapper for a provider-dependent cipher class, since javax.crypto.Cipher
|
|
||||||
* doesn't support additional authenticated data until Java 7.
|
|
||||||
*/
|
|
||||||
public interface AuthenticatedCipher {
|
public interface AuthenticatedCipher {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes this cipher with a key, an initialisation vector (IV) and
|
* Initializes this cipher with a key, an initialisation vector (IV) and
|
||||||
* additional authenticated data (AAD).
|
* additional authenticated data (AAD).
|
||||||
*/
|
*/
|
||||||
void init(int opmode, Key key, byte[] iv, byte[] aad)
|
void init(int opmode, SecretKey key, byte[] iv, byte[] aad)
|
||||||
throws InvalidKeyException;
|
throws GeneralSecurityException;
|
||||||
|
|
||||||
/** Encrypts or decrypts data in a single-part operation. */
|
/** Encrypts or decrypts data in a single-part operation. */
|
||||||
int doFinal(byte[] input, int inputOff, int len, byte[] output,
|
int doFinal(byte[] input, int inputOff, int len, byte[] output,
|
||||||
int outputOff) throws IllegalBlockSizeException,
|
int outputOff) throws GeneralSecurityException;
|
||||||
BadPaddingException;
|
|
||||||
|
|
||||||
/** Returns the length of the message authenticated code (MAC) in bytes. */
|
/** Returns the length of the message authenticated code (MAC) in bytes. */
|
||||||
int getMacLength();
|
int getMacLength();
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
package net.sf.briar.api.crypto;
|
package net.sf.briar.api.crypto;
|
||||||
|
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.KeyPair;
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.security.Signature;
|
|
||||||
|
|
||||||
public interface CryptoComponent {
|
public interface CryptoComponent {
|
||||||
|
|
||||||
ErasableKey generateSecretKey();
|
SecretKey generateSecretKey();
|
||||||
|
|
||||||
MessageDigest getMessageDigest();
|
MessageDigest getMessageDigest();
|
||||||
|
|
||||||
@@ -67,7 +65,7 @@ public interface CryptoComponent {
|
|||||||
* @param alice indicates whether the key is for connections initiated by
|
* @param alice indicates whether the key is for connections initiated by
|
||||||
* Alice or Bob.
|
* Alice or Bob.
|
||||||
*/
|
*/
|
||||||
ErasableKey deriveTagKey(byte[] secret, boolean alice);
|
SecretKey deriveTagKey(byte[] secret, boolean alice);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Derives a frame key from the given temporary secret and connection
|
* Derives a frame key from the given temporary secret and connection
|
||||||
@@ -77,14 +75,14 @@ public interface CryptoComponent {
|
|||||||
* @param initiator indicates whether the key is for the initiator's or the
|
* @param initiator indicates whether the key is for the initiator's or the
|
||||||
* responder's side of the connection.
|
* responder's side of the connection.
|
||||||
*/
|
*/
|
||||||
ErasableKey deriveFrameKey(byte[] secret, long connection, boolean alice,
|
SecretKey deriveFrameKey(byte[] secret, long connection, boolean alice,
|
||||||
boolean initiator);
|
boolean initiator);
|
||||||
|
|
||||||
/** Returns a cipher for encrypting and authenticating connections. */
|
/** Returns a cipher for encrypting and authenticating connections. */
|
||||||
AuthenticatedCipher getFrameCipher();
|
AuthenticatedCipher getFrameCipher();
|
||||||
|
|
||||||
/** Encodes the pseudo-random tag that is used to recognise a connection. */
|
/** Encodes the pseudo-random tag that is used to recognise a connection. */
|
||||||
void encodeTag(byte[] tag, ErasableKey tagKey, long connection);
|
void encodeTag(byte[] tag, SecretKey tagKey, long connection);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encrypts and authenticates the given plaintext so it can be written to
|
* Encrypts and authenticates the given plaintext so it can be written to
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
package net.sf.briar.api.crypto;
|
|
||||||
|
|
||||||
import javax.crypto.SecretKey;
|
|
||||||
|
|
||||||
public interface ErasableKey extends SecretKey {
|
|
||||||
|
|
||||||
/** Returns a copy of the key. */
|
|
||||||
ErasableKey copy();
|
|
||||||
|
|
||||||
/** Erases the key from memory. */
|
|
||||||
void erase();
|
|
||||||
}
|
|
||||||
21
briar-api/src/net/sf/briar/api/crypto/KeyPair.java
Normal file
21
briar-api/src/net/sf/briar/api/crypto/KeyPair.java
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package net.sf.briar.api.crypto;
|
||||||
|
|
||||||
|
/** A key pair consisting of a {@link PublicKey} and a {@link PrivateKey). */
|
||||||
|
public class KeyPair {
|
||||||
|
|
||||||
|
private final PublicKey publicKey;
|
||||||
|
private final PrivateKey privateKey;
|
||||||
|
|
||||||
|
public KeyPair(PublicKey publicKey, PrivateKey privateKey) {
|
||||||
|
this.publicKey = publicKey;
|
||||||
|
this.privateKey = privateKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PublicKey getPublic() {
|
||||||
|
return publicKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrivateKey getPrivate() {
|
||||||
|
return privateKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,11 @@
|
|||||||
package net.sf.briar.api.crypto;
|
package net.sf.briar.api.crypto;
|
||||||
|
|
||||||
import java.security.PrivateKey;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.PublicKey;
|
|
||||||
import java.security.spec.InvalidKeySpecException;
|
|
||||||
|
|
||||||
public interface KeyParser {
|
public interface KeyParser {
|
||||||
|
|
||||||
PublicKey parsePublicKey(byte[] encodedKey) throws InvalidKeySpecException;
|
PublicKey parsePublicKey(byte[] encodedKey) throws GeneralSecurityException;
|
||||||
|
|
||||||
PrivateKey parsePrivateKey(byte[] encodedKey)
|
PrivateKey parsePrivateKey(byte[] encodedKey)
|
||||||
throws InvalidKeySpecException;
|
throws GeneralSecurityException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
package net.sf.briar.api.crypto;
|
package net.sf.briar.api.crypto;
|
||||||
|
|
||||||
/**
|
|
||||||
* A wrapper around a {@link java.security.MessageDigest} that allows it to be
|
|
||||||
* replaced for testing.
|
|
||||||
*/
|
|
||||||
public interface MessageDigest {
|
public interface MessageDigest {
|
||||||
|
|
||||||
/** @see {@link java.security.MessageDigest#digest()} */
|
/** @see {@link java.security.MessageDigest#digest()} */
|
||||||
|
|||||||
8
briar-api/src/net/sf/briar/api/crypto/PrivateKey.java
Normal file
8
briar-api/src/net/sf/briar/api/crypto/PrivateKey.java
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package net.sf.briar.api.crypto;
|
||||||
|
|
||||||
|
/** The private half of a public/private {@link KeyPair}. */
|
||||||
|
public interface PrivateKey {
|
||||||
|
|
||||||
|
/** Returns the encoded representation of this key. */
|
||||||
|
byte[] getEncoded();
|
||||||
|
}
|
||||||
8
briar-api/src/net/sf/briar/api/crypto/PublicKey.java
Normal file
8
briar-api/src/net/sf/briar/api/crypto/PublicKey.java
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package net.sf.briar.api.crypto;
|
||||||
|
|
||||||
|
/** The public half of a public/private {@link KeyPair}. */
|
||||||
|
public interface PublicKey {
|
||||||
|
|
||||||
|
/** Returns the encoded representation of this key. */
|
||||||
|
byte[] getEncoded();
|
||||||
|
}
|
||||||
21
briar-api/src/net/sf/briar/api/crypto/SecretKey.java
Normal file
21
briar-api/src/net/sf/briar/api/crypto/SecretKey.java
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package net.sf.briar.api.crypto;
|
||||||
|
|
||||||
|
/** A secret key used for encryption and/or authentication. */
|
||||||
|
public interface SecretKey {
|
||||||
|
|
||||||
|
/** Returns the encoded representation of this key. */
|
||||||
|
byte[] getEncoded();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a copy of this key - erasing this key will erase the copy and
|
||||||
|
* vice versa.
|
||||||
|
*/
|
||||||
|
SecretKey copy();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erases this key from memory. Any copies derived from this key via the
|
||||||
|
* {@link #copy()} method, and any keys from which this key was derived via
|
||||||
|
* the {@link #copy()} method, are also erased.
|
||||||
|
*/
|
||||||
|
void erase();
|
||||||
|
}
|
||||||
31
briar-api/src/net/sf/briar/api/crypto/Signature.java
Normal file
31
briar-api/src/net/sf/briar/api/crypto/Signature.java
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package net.sf.briar.api.crypto;
|
||||||
|
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
|
||||||
|
public interface Signature {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see {@link java.security.Signature#initSign(java.security.PrivateKey)}
|
||||||
|
*/
|
||||||
|
void initSign(PrivateKey k) throws GeneralSecurityException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see {@link java.security.Signature#initVafiry(java.security.PublicKey)}
|
||||||
|
*/
|
||||||
|
void initVerify(PublicKey k) throws GeneralSecurityException;
|
||||||
|
|
||||||
|
/** @see {@link java.security.Signature#update(byte)} */
|
||||||
|
void update(byte b);
|
||||||
|
|
||||||
|
/** @see {@link java.security.Signature#update(byte[])} */
|
||||||
|
void update(byte[] b);
|
||||||
|
|
||||||
|
/** @see {@link java.security.Signature#update(byte[], int, int)} */
|
||||||
|
void update(byte[] b, int off, int len);
|
||||||
|
|
||||||
|
/** @see {@link java.security.Signature#sign()} */
|
||||||
|
byte[] sign();
|
||||||
|
|
||||||
|
/** @see {@link java.security.Signature#verify(byte[])} */
|
||||||
|
boolean verify(byte[] signature);
|
||||||
|
}
|
||||||
@@ -2,9 +2,9 @@ package net.sf.briar.api.messaging;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.PrivateKey;
|
|
||||||
|
|
||||||
import net.sf.briar.api.Author;
|
import net.sf.briar.api.Author;
|
||||||
|
import net.sf.briar.api.crypto.PrivateKey;
|
||||||
|
|
||||||
public interface MessageFactory {
|
public interface MessageFactory {
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package net.sf.briar.api.serial;
|
package net.sf.briar.api.serial;
|
||||||
|
|
||||||
import java.io.IOException;
|
import net.sf.briar.api.crypto.Signature;
|
||||||
import java.security.Signature;
|
|
||||||
import java.security.SignatureException;
|
|
||||||
|
|
||||||
/** A consumer that passes its input through a signature. */
|
/** A consumer that passes its input through a signature. */
|
||||||
public class SigningConsumer implements Consumer {
|
public class SigningConsumer implements Consumer {
|
||||||
@@ -13,19 +11,11 @@ public class SigningConsumer implements Consumer {
|
|||||||
this.signature = signature;
|
this.signature = signature;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(byte b) throws IOException {
|
public void write(byte b) {
|
||||||
try {
|
signature.update(b);
|
||||||
signature.update(b);
|
|
||||||
} catch(SignatureException e) {
|
|
||||||
throw new IOException(e.toString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(byte[] b, int off, int len) throws IOException {
|
public void write(byte[] b, int off, int len) {
|
||||||
try {
|
signature.update(b, off, len);
|
||||||
signature.update(b, off, len);
|
|
||||||
} catch(SignatureException e) {
|
|
||||||
throw new IOException(e.toString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
<classpathentry kind="lib" path="libs/jnotify-0.93.jar"/>
|
<classpathentry kind="lib" path="libs/jnotify-0.93.jar"/>
|
||||||
<classpathentry kind="lib" path="libs/jssc-0.9-briar.jar" sourcepath="libs/source/jssc-0.9-briar-source.jar"/>
|
<classpathentry kind="lib" path="libs/jssc-0.9-briar.jar" sourcepath="libs/source/jssc-0.9-briar-source.jar"/>
|
||||||
<classpathentry kind="lib" path="libs/sc-light-jdk15on-1.47.0.3-SNAPSHOT.jar" sourcepath="libs/source/sc-light-jdk15on-1.47.0.3-SNAPSHOT-source.jar"/>
|
<classpathentry kind="lib" path="libs/sc-light-jdk15on-1.47.0.3-SNAPSHOT.jar" sourcepath="libs/source/sc-light-jdk15on-1.47.0.3-SNAPSHOT-source.jar"/>
|
||||||
<classpathentry kind="lib" path="libs/scprov-jdk15on-1.47.0.3-SNAPSHOT.jar" sourcepath="libs/source/scprov-jdk15on-1.47.0.3-SNAPSHOT-source.jar"/>
|
|
||||||
<classpathentry kind="lib" path="libs/weupnp-0.1.1.jar"/>
|
<classpathentry kind="lib" path="libs/weupnp-0.1.1.jar"/>
|
||||||
<classpathentry kind="lib" path="libs/bluecove-2.1.1-SNAPSHOT-briar.jar"/>
|
<classpathentry kind="lib" path="libs/bluecove-2.1.1-SNAPSHOT-briar.jar"/>
|
||||||
<classpathentry kind="lib" path="libs/bluecove-gpl-2.1.1-SNAPSHOT.jar"/>
|
<classpathentry kind="lib" path="libs/bluecove-gpl-2.1.1-SNAPSHOT.jar"/>
|
||||||
|
|||||||
Binary file not shown.
@@ -1,13 +1,11 @@
|
|||||||
package net.sf.briar.crypto;
|
package net.sf.briar.crypto;
|
||||||
|
|
||||||
import java.security.InvalidKeyException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.Key;
|
|
||||||
|
|
||||||
import javax.crypto.BadPaddingException;
|
|
||||||
import javax.crypto.Cipher;
|
import javax.crypto.Cipher;
|
||||||
import javax.crypto.IllegalBlockSizeException;
|
|
||||||
|
|
||||||
import net.sf.briar.api.crypto.AuthenticatedCipher;
|
import net.sf.briar.api.crypto.AuthenticatedCipher;
|
||||||
|
import net.sf.briar.api.crypto.SecretKey;
|
||||||
|
|
||||||
import org.spongycastle.crypto.DataLengthException;
|
import org.spongycastle.crypto.DataLengthException;
|
||||||
import org.spongycastle.crypto.InvalidCipherTextException;
|
import org.spongycastle.crypto.InvalidCipherTextException;
|
||||||
@@ -26,8 +24,7 @@ class AuthenticatedCipherImpl implements AuthenticatedCipher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int doFinal(byte[] input, int inputOff, int len, byte[] output,
|
public int doFinal(byte[] input, int inputOff, int len, byte[] output,
|
||||||
int outputOff) throws IllegalBlockSizeException,
|
int outputOff) throws GeneralSecurityException {
|
||||||
BadPaddingException {
|
|
||||||
int processed = 0;
|
int processed = 0;
|
||||||
if(len != 0) {
|
if(len != 0) {
|
||||||
processed = cipher.processBytes(input, inputOff, len, output,
|
processed = cipher.processBytes(input, inputOff, len, output,
|
||||||
@@ -36,14 +33,14 @@ class AuthenticatedCipherImpl implements AuthenticatedCipher {
|
|||||||
try {
|
try {
|
||||||
return processed + cipher.doFinal(output, outputOff + processed);
|
return processed + cipher.doFinal(output, outputOff + processed);
|
||||||
} catch(DataLengthException e) {
|
} catch(DataLengthException e) {
|
||||||
throw new IllegalBlockSizeException(e.getMessage());
|
throw new GeneralSecurityException(e.getMessage());
|
||||||
} catch(InvalidCipherTextException e) {
|
} catch(InvalidCipherTextException e) {
|
||||||
throw new BadPaddingException(e.getMessage());
|
throw new GeneralSecurityException(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init(int opmode, Key key, byte[] iv, byte[] aad)
|
public void init(int opmode, SecretKey key, byte[] iv, byte[] aad)
|
||||||
throws InvalidKeyException {
|
throws GeneralSecurityException {
|
||||||
KeyParameter k = new KeyParameter(key.getEncoded());
|
KeyParameter k = new KeyParameter(key.getEncoded());
|
||||||
AEADParameters params = new AEADParameters(k, macLength * 8, iv, aad);
|
AEADParameters params = new AEADParameters(k, macLength * 8, iv, aad);
|
||||||
try {
|
try {
|
||||||
@@ -59,8 +56,8 @@ class AuthenticatedCipherImpl implements AuthenticatedCipher {
|
|||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
} catch(Exception e) {
|
} catch(IllegalArgumentException e) {
|
||||||
throw new InvalidKeyException(e.getMessage());
|
throw new GeneralSecurityException(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,72 +1,54 @@
|
|||||||
package net.sf.briar.crypto;
|
package net.sf.briar.crypto;
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
|
||||||
import static javax.crypto.Cipher.DECRYPT_MODE;
|
import static javax.crypto.Cipher.DECRYPT_MODE;
|
||||||
import static javax.crypto.Cipher.ENCRYPT_MODE;
|
import static javax.crypto.Cipher.ENCRYPT_MODE;
|
||||||
import static net.sf.briar.api.invitation.InvitationConstants.CODE_BITS;
|
import static net.sf.briar.api.invitation.InvitationConstants.CODE_BITS;
|
||||||
import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
|
import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
|
import static net.sf.briar.crypto.P384Constants.P_384_PARAMS;
|
||||||
|
import static net.sf.briar.crypto.P384Constants.P_384_Q;
|
||||||
import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.KeyFactory;
|
|
||||||
import java.security.KeyPair;
|
|
||||||
import java.security.KeyPairGenerator;
|
|
||||||
import java.security.PrivateKey;
|
|
||||||
import java.security.PublicKey;
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.security.Security;
|
|
||||||
import java.security.Signature;
|
|
||||||
import java.security.interfaces.ECPrivateKey;
|
|
||||||
import java.security.interfaces.ECPublicKey;
|
|
||||||
import java.security.spec.ECField;
|
|
||||||
import java.security.spec.ECFieldFp;
|
|
||||||
import java.security.spec.ECParameterSpec;
|
|
||||||
import java.security.spec.ECPoint;
|
|
||||||
import java.security.spec.EllipticCurve;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import javax.crypto.KeyAgreement;
|
|
||||||
|
|
||||||
import net.sf.briar.api.crypto.AuthenticatedCipher;
|
import net.sf.briar.api.crypto.AuthenticatedCipher;
|
||||||
import net.sf.briar.api.crypto.CryptoComponent;
|
import net.sf.briar.api.crypto.CryptoComponent;
|
||||||
import net.sf.briar.api.crypto.ErasableKey;
|
import net.sf.briar.api.crypto.KeyPair;
|
||||||
import net.sf.briar.api.crypto.KeyParser;
|
import net.sf.briar.api.crypto.KeyParser;
|
||||||
import net.sf.briar.api.crypto.MessageDigest;
|
import net.sf.briar.api.crypto.MessageDigest;
|
||||||
|
import net.sf.briar.api.crypto.PrivateKey;
|
||||||
import net.sf.briar.api.crypto.PseudoRandom;
|
import net.sf.briar.api.crypto.PseudoRandom;
|
||||||
|
import net.sf.briar.api.crypto.PublicKey;
|
||||||
|
import net.sf.briar.api.crypto.SecretKey;
|
||||||
|
import net.sf.briar.api.crypto.Signature;
|
||||||
import net.sf.briar.util.ByteUtils;
|
import net.sf.briar.util.ByteUtils;
|
||||||
|
|
||||||
|
import org.spongycastle.crypto.AsymmetricCipherKeyPair;
|
||||||
import org.spongycastle.crypto.BlockCipher;
|
import org.spongycastle.crypto.BlockCipher;
|
||||||
import org.spongycastle.crypto.CipherParameters;
|
import org.spongycastle.crypto.CipherParameters;
|
||||||
|
import org.spongycastle.crypto.agreement.ECDHCBasicAgreement;
|
||||||
|
import org.spongycastle.crypto.digests.SHA384Digest;
|
||||||
import org.spongycastle.crypto.engines.AESFastEngine;
|
import org.spongycastle.crypto.engines.AESFastEngine;
|
||||||
|
import org.spongycastle.crypto.generators.ECKeyPairGenerator;
|
||||||
import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator;
|
import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator;
|
||||||
import org.spongycastle.crypto.modes.AEADBlockCipher;
|
import org.spongycastle.crypto.modes.AEADBlockCipher;
|
||||||
import org.spongycastle.crypto.modes.GCMBlockCipher;
|
import org.spongycastle.crypto.modes.GCMBlockCipher;
|
||||||
|
import org.spongycastle.crypto.params.ECKeyGenerationParameters;
|
||||||
|
import org.spongycastle.crypto.params.ECPrivateKeyParameters;
|
||||||
|
import org.spongycastle.crypto.params.ECPublicKeyParameters;
|
||||||
import org.spongycastle.crypto.params.KeyParameter;
|
import org.spongycastle.crypto.params.KeyParameter;
|
||||||
import org.spongycastle.jcajce.provider.asymmetric.ec.KeyPairGeneratorSpi;
|
|
||||||
import org.spongycastle.jcajce.provider.digest.SHA384;
|
|
||||||
import org.spongycastle.jce.provider.BouncyCastleProvider;
|
|
||||||
import org.spongycastle.util.Strings;
|
import org.spongycastle.util.Strings;
|
||||||
|
|
||||||
class CryptoComponentImpl implements CryptoComponent {
|
class CryptoComponentImpl implements CryptoComponent {
|
||||||
|
|
||||||
private static final Logger LOG =
|
|
||||||
Logger.getLogger(CryptoComponentImpl.class.getName());
|
|
||||||
|
|
||||||
private static final String PROVIDER = "SC"; // Spongy Castle
|
|
||||||
private static final String CIPHER_ALGO = "AES";
|
|
||||||
private static final int CIPHER_BLOCK_BYTES = 16; // 128 bits
|
private static final int CIPHER_BLOCK_BYTES = 16; // 128 bits
|
||||||
private static final int CIPHER_KEY_BYTES = 32; // 256 bits
|
private static final int CIPHER_KEY_BYTES = 32; // 256 bits
|
||||||
private static final String AGREEMENT_ALGO = "ECDHC";
|
|
||||||
private static final String AGREEMENT_KEY_PAIR_ALGO = "ECDH";
|
|
||||||
private static final int AGREEMENT_KEY_PAIR_BITS = 384;
|
private static final int AGREEMENT_KEY_PAIR_BITS = 384;
|
||||||
private static final String SIGNATURE_ALGO = "ECDSA";
|
|
||||||
private static final String SIGNATURE_KEY_PAIR_ALGO = "ECDSA";
|
|
||||||
private static final int SIGNATURE_KEY_PAIR_BITS = 384;
|
private static final int SIGNATURE_KEY_PAIR_BITS = 384;
|
||||||
private static final int GCM_MAC_BYTES = 16; // 128 bits
|
private static final int MAC_BYTES = 16; // 128 bits
|
||||||
private static final int STORAGE_IV_BYTES = 16; // 128 bits
|
private static final int STORAGE_IV_BYTES = 16; // 128 bits
|
||||||
private static final int PBKDF_SALT_BYTES = 16; // 128 bits
|
private static final int PBKDF_SALT_BYTES = 16; // 128 bits
|
||||||
private static final int PBKDF_ITERATIONS = 1000;
|
private static final int PBKDF_ITERATIONS = 1000;
|
||||||
@@ -93,83 +75,33 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
// Blank secret for argument validation
|
// Blank secret for argument validation
|
||||||
private static final byte[] BLANK_SECRET = new byte[CIPHER_KEY_BYTES];
|
private static final byte[] BLANK_SECRET = new byte[CIPHER_KEY_BYTES];
|
||||||
|
|
||||||
// Parameters for NIST elliptic curve P-384 - see "Suite B Implementer's
|
|
||||||
// Guide to NIST SP 800-56A", section A.2
|
|
||||||
private static final BigInteger P_384_Q = new BigInteger("FFFFFFFF" +
|
|
||||||
"FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" +
|
|
||||||
"FFFFFFFF" + "FFFFFFFE" + "FFFFFFFF" + "00000000" + "00000000" +
|
|
||||||
"FFFFFFFF", 16);
|
|
||||||
private static final BigInteger P_384_A = new BigInteger("FFFFFFFF" +
|
|
||||||
"FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" +
|
|
||||||
"FFFFFFFF" + "FFFFFFFE" + "FFFFFFFF" + "00000000" + "00000000" +
|
|
||||||
"FFFFFFFC", 16);
|
|
||||||
private static final BigInteger P_384_B = new BigInteger("B3312FA7" +
|
|
||||||
"E23EE7E4" + "988E056B" + "E3F82D19" + "181D9C6E" + "FE814112" +
|
|
||||||
"0314088F" + "5013875A" + "C656398D" + "8A2ED19D" + "2A85C8ED" +
|
|
||||||
"D3EC2AEF", 16);
|
|
||||||
private static final BigInteger P_384_G_X = new BigInteger("AA87CA22" +
|
|
||||||
"BE8B0537" + "8EB1C71E" + "F320AD74" + "6E1D3B62" + "8BA79B98" +
|
|
||||||
"59F741E0" + "82542A38" + "5502F25D" + "BF55296C" + "3A545E38" +
|
|
||||||
"72760AB7", 16);
|
|
||||||
private static final BigInteger P_384_G_Y = new BigInteger("3617DE4A" +
|
|
||||||
"96262C6F" + "5D9E98BF" + "9292DC29" + "F8F41DBD" + "289A147C" +
|
|
||||||
"E9DA3113" + "B5F0B8C0" + "0A60B1CE" + "1D7E819D" + "7A431D7C" +
|
|
||||||
"90EA0E5F", 16);
|
|
||||||
private static final BigInteger P_384_N = new BigInteger("FFFFFFFF" +
|
|
||||||
"FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" +
|
|
||||||
"C7634D81" + "F4372DDF" + "581A0DB2" + "48B0A77A" + "ECEC196A" +
|
|
||||||
"CCC52973", 16);
|
|
||||||
private static final int P_384_H = 1;
|
|
||||||
// Static parameter objects derived from the above parameters
|
|
||||||
private static final ECField P_384_FIELD = new ECFieldFp(P_384_Q);
|
|
||||||
private static final EllipticCurve P_384_CURVE =
|
|
||||||
new EllipticCurve(P_384_FIELD, P_384_A, P_384_B);
|
|
||||||
private static final ECPoint P_384_G = new ECPoint(P_384_G_X, P_384_G_Y);
|
|
||||||
private static final ECParameterSpec P_384_PARAMS =
|
|
||||||
new ECParameterSpec(P_384_CURVE, P_384_G, P_384_N, P_384_H);
|
|
||||||
|
|
||||||
private final KeyParser agreementKeyParser, signatureKeyParser;
|
private final KeyParser agreementKeyParser, signatureKeyParser;
|
||||||
private final KeyPairGenerator agreementKeyPairGenerator;
|
|
||||||
private final KeyPairGenerator signatureKeyPairGenerator;
|
|
||||||
private final SecureRandom secureRandom;
|
private final SecureRandom secureRandom;
|
||||||
|
private final ECKeyPairGenerator agreementKeyPairGenerator;
|
||||||
|
private final ECKeyPairGenerator signatureKeyPairGenerator;
|
||||||
|
|
||||||
CryptoComponentImpl() {
|
CryptoComponentImpl() {
|
||||||
Security.addProvider(new BouncyCastleProvider());
|
agreementKeyParser = new Sec1KeyParser(P_384_PARAMS, P_384_Q,
|
||||||
try {
|
AGREEMENT_KEY_PAIR_BITS);
|
||||||
KeyFactory agreementKeyFactory = KeyFactory.getInstance(
|
signatureKeyParser = new Sec1KeyParser(P_384_PARAMS, P_384_Q,
|
||||||
AGREEMENT_KEY_PAIR_ALGO, PROVIDER);
|
SIGNATURE_KEY_PAIR_BITS);
|
||||||
if(LOG.isLoggable(INFO)) {
|
|
||||||
LOG.info("Agreement KeyFactory: "
|
|
||||||
+ agreementKeyFactory.getClass().getName());
|
|
||||||
}
|
|
||||||
agreementKeyParser = new Sec1KeyParser(agreementKeyFactory,
|
|
||||||
P_384_PARAMS, P_384_Q, AGREEMENT_KEY_PAIR_BITS);
|
|
||||||
KeyFactory signatureKeyFactory = KeyFactory.getInstance(
|
|
||||||
SIGNATURE_KEY_PAIR_ALGO, PROVIDER);
|
|
||||||
if(LOG.isLoggable(INFO)) {
|
|
||||||
LOG.info("Signature KeyFactory: "
|
|
||||||
+ signatureKeyFactory.getClass().getName());
|
|
||||||
}
|
|
||||||
signatureKeyParser = new Sec1KeyParser(signatureKeyFactory,
|
|
||||||
P_384_PARAMS, P_384_Q, SIGNATURE_KEY_PAIR_BITS);
|
|
||||||
agreementKeyPairGenerator = new KeyPairGeneratorSpi.ECDH();
|
|
||||||
agreementKeyPairGenerator.initialize(AGREEMENT_KEY_PAIR_BITS);
|
|
||||||
signatureKeyPairGenerator = new KeyPairGeneratorSpi.ECDSA();
|
|
||||||
signatureKeyPairGenerator.initialize(SIGNATURE_KEY_PAIR_BITS);
|
|
||||||
} catch(GeneralSecurityException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
secureRandom = new SecureRandom();
|
secureRandom = new SecureRandom();
|
||||||
|
ECKeyGenerationParameters params = new ECKeyGenerationParameters(
|
||||||
|
P_384_PARAMS, secureRandom);
|
||||||
|
agreementKeyPairGenerator = new ECKeyPairGenerator();
|
||||||
|
agreementKeyPairGenerator.init(params);
|
||||||
|
signatureKeyPairGenerator = new ECKeyPairGenerator();
|
||||||
|
signatureKeyPairGenerator.init(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ErasableKey generateSecretKey() {
|
public SecretKey generateSecretKey() {
|
||||||
byte[] b = new byte[CIPHER_KEY_BYTES];
|
byte[] b = new byte[CIPHER_KEY_BYTES];
|
||||||
secureRandom.nextBytes(b);
|
secureRandom.nextBytes(b);
|
||||||
return new ErasableKeyImpl(b, CIPHER_ALGO);
|
return new SecretKeyImpl(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MessageDigest getMessageDigest() {
|
public MessageDigest getMessageDigest() {
|
||||||
return new DoubleDigest(new SHA384.Digest());
|
return new DoubleDigest(new SHA384Digest());
|
||||||
}
|
}
|
||||||
|
|
||||||
public PseudoRandom getPseudoRandom(int seed1, int seed2) {
|
public PseudoRandom getPseudoRandom(int seed1, int seed2) {
|
||||||
@@ -181,25 +113,21 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Signature getSignature() {
|
public Signature getSignature() {
|
||||||
try {
|
return new SignatureImpl(secureRandom);
|
||||||
Signature signature = Signature.getInstance(SIGNATURE_ALGO,
|
|
||||||
PROVIDER);
|
|
||||||
if(LOG.isLoggable(INFO))
|
|
||||||
LOG.info("Signature: " + signature.getClass().getName());
|
|
||||||
return signature;
|
|
||||||
} catch(GeneralSecurityException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeyPair generateAgreementKeyPair() {
|
public KeyPair generateAgreementKeyPair() {
|
||||||
KeyPair keyPair = agreementKeyPairGenerator.generateKeyPair();
|
AsymmetricCipherKeyPair keyPair =
|
||||||
// Check that the key pair uses NIST curve P-384
|
agreementKeyPairGenerator.generateKeyPair();
|
||||||
ECPublicKey publicKey = checkP384Params(keyPair.getPublic());
|
|
||||||
// Return a wrapper that uses the SEC 1 encoding
|
// Return a wrapper that uses the SEC 1 encoding
|
||||||
publicKey = new Sec1PublicKey(publicKey, AGREEMENT_KEY_PAIR_BITS);
|
ECPublicKeyParameters ecPublicKey =
|
||||||
ECPrivateKey privateKey = (ECPrivateKey) keyPair.getPrivate();
|
(ECPublicKeyParameters) keyPair.getPublic();
|
||||||
privateKey = new Sec1PrivateKey(privateKey, AGREEMENT_KEY_PAIR_BITS);
|
PublicKey publicKey = new Sec1PublicKey(ecPublicKey,
|
||||||
|
AGREEMENT_KEY_PAIR_BITS);
|
||||||
|
ECPrivateKeyParameters ecPrivateKey =
|
||||||
|
(ECPrivateKeyParameters) keyPair.getPrivate();
|
||||||
|
PrivateKey privateKey = new Sec1PrivateKey(ecPrivateKey,
|
||||||
|
AGREEMENT_KEY_PAIR_BITS);
|
||||||
return new KeyPair(publicKey, privateKey);
|
return new KeyPair(publicKey, privateKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,13 +136,17 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public KeyPair generateSignatureKeyPair() {
|
public KeyPair generateSignatureKeyPair() {
|
||||||
KeyPair keyPair = signatureKeyPairGenerator.generateKeyPair();
|
AsymmetricCipherKeyPair keyPair =
|
||||||
// Check that the key pair uses NIST curve P-384
|
signatureKeyPairGenerator.generateKeyPair();
|
||||||
ECPublicKey publicKey = checkP384Params(keyPair.getPublic());
|
|
||||||
// Return a wrapper that uses the SEC 1 encoding
|
// Return a wrapper that uses the SEC 1 encoding
|
||||||
publicKey = new Sec1PublicKey(publicKey, SIGNATURE_KEY_PAIR_BITS);
|
ECPublicKeyParameters ecPublicKey =
|
||||||
ECPrivateKey privateKey = (ECPrivateKey) keyPair.getPrivate();
|
(ECPublicKeyParameters) keyPair.getPublic();
|
||||||
privateKey = new Sec1PrivateKey(privateKey, SIGNATURE_KEY_PAIR_BITS);
|
PublicKey publicKey = new Sec1PublicKey(ecPublicKey,
|
||||||
|
SIGNATURE_KEY_PAIR_BITS);
|
||||||
|
ECPrivateKeyParameters ecPrivateKey =
|
||||||
|
(ECPrivateKeyParameters) keyPair.getPrivate();
|
||||||
|
PrivateKey privateKey = new Sec1PrivateKey(ecPrivateKey,
|
||||||
|
SIGNATURE_KEY_PAIR_BITS);
|
||||||
return new KeyPair(publicKey, privateKey);
|
return new KeyPair(publicKey, privateKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,13 +214,16 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
// Package access for testing
|
// Package access for testing
|
||||||
byte[] deriveSharedSecret(PrivateKey priv, PublicKey pub)
|
byte[] deriveSharedSecret(PrivateKey priv, PublicKey pub)
|
||||||
throws GeneralSecurityException {
|
throws GeneralSecurityException {
|
||||||
KeyAgreement keyAgreement = KeyAgreement.getInstance(AGREEMENT_ALGO,
|
if(!(priv instanceof Sec1PrivateKey))
|
||||||
PROVIDER);
|
throw new IllegalArgumentException();
|
||||||
if(LOG.isLoggable(INFO))
|
if(!(pub instanceof Sec1PublicKey))
|
||||||
LOG.info("KeyAgreement: " + keyAgreement.getClass().getName());
|
throw new IllegalArgumentException();
|
||||||
keyAgreement.init(priv);
|
ECPrivateKeyParameters ecPriv = ((Sec1PrivateKey) priv).getKey();
|
||||||
keyAgreement.doPhase(pub, true);
|
ECPublicKeyParameters ecPub = ((Sec1PublicKey) pub).getKey();
|
||||||
return keyAgreement.generateSecret();
|
ECDHCBasicAgreement agreement = new ECDHCBasicAgreement();
|
||||||
|
agreement.init(ecPriv);
|
||||||
|
// FIXME: Should we use another format for the shared secret?
|
||||||
|
return agreement.calculateAgreement(ecPub).toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] deriveInitialSecret(byte[] secret, int transportIndex) {
|
public byte[] deriveInitialSecret(byte[] secret, int transportIndex) {
|
||||||
@@ -310,7 +245,7 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
return counterModeKdf(secret, ROTATE, period);
|
return counterModeKdf(secret, ROTATE, period);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ErasableKey deriveTagKey(byte[] secret, boolean alice) {
|
public SecretKey deriveTagKey(byte[] secret, boolean alice) {
|
||||||
if(secret.length != CIPHER_KEY_BYTES)
|
if(secret.length != CIPHER_KEY_BYTES)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
if(Arrays.equals(secret, BLANK_SECRET))
|
if(Arrays.equals(secret, BLANK_SECRET))
|
||||||
@@ -319,7 +254,7 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
else return deriveKey(secret, B_TAG, 0);
|
else return deriveKey(secret, B_TAG, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ErasableKey deriveFrameKey(byte[] secret, long connection,
|
public SecretKey deriveFrameKey(byte[] secret, long connection,
|
||||||
boolean alice, boolean initiator) {
|
boolean alice, boolean initiator) {
|
||||||
if(secret.length != CIPHER_KEY_BYTES)
|
if(secret.length != CIPHER_KEY_BYTES)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
@@ -336,21 +271,21 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ErasableKey deriveKey(byte[] secret, byte[] label, long context) {
|
private SecretKey deriveKey(byte[] secret, byte[] label, long context) {
|
||||||
if(secret.length != CIPHER_KEY_BYTES)
|
if(secret.length != CIPHER_KEY_BYTES)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
if(Arrays.equals(secret, BLANK_SECRET))
|
if(Arrays.equals(secret, BLANK_SECRET))
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
byte[] key = counterModeKdf(secret, label, context);
|
byte[] key = counterModeKdf(secret, label, context);
|
||||||
return new ErasableKeyImpl(key, CIPHER_ALGO);
|
return new SecretKeyImpl(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AuthenticatedCipher getFrameCipher() {
|
public AuthenticatedCipher getFrameCipher() {
|
||||||
AEADBlockCipher cipher = new GCMBlockCipher(new AESFastEngine());
|
AEADBlockCipher cipher = new GCMBlockCipher(new AESFastEngine());
|
||||||
return new AuthenticatedCipherImpl(cipher, GCM_MAC_BYTES);
|
return new AuthenticatedCipherImpl(cipher, MAC_BYTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void encodeTag(byte[] tag, ErasableKey tagKey, long connection) {
|
public void encodeTag(byte[] tag, SecretKey tagKey, long connection) {
|
||||||
if(tag.length < TAG_LENGTH) throw new IllegalArgumentException();
|
if(tag.length < TAG_LENGTH) throw new IllegalArgumentException();
|
||||||
if(connection < 0 || connection > MAX_32_BIT_UNSIGNED)
|
if(connection < 0 || connection > MAX_32_BIT_UNSIGNED)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
@@ -367,12 +302,12 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
secureRandom.nextBytes(salt);
|
secureRandom.nextBytes(salt);
|
||||||
// Derive the key from the password
|
// Derive the key from the password
|
||||||
byte[] keyBytes = pbkdf2(password, salt);
|
byte[] keyBytes = pbkdf2(password, salt);
|
||||||
ErasableKey key = new ErasableKeyImpl(keyBytes, CIPHER_ALGO);
|
SecretKey key = new SecretKeyImpl(keyBytes);
|
||||||
// Generate a random IV
|
// Generate a random IV
|
||||||
byte[] iv = new byte[STORAGE_IV_BYTES];
|
byte[] iv = new byte[STORAGE_IV_BYTES];
|
||||||
secureRandom.nextBytes(iv);
|
secureRandom.nextBytes(iv);
|
||||||
// The output contains the salt, IV, ciphertext and MAC
|
// The output contains the salt, IV, ciphertext and MAC
|
||||||
int outputLen = salt.length + iv.length + input.length + GCM_MAC_BYTES;
|
int outputLen = salt.length + iv.length + input.length + MAC_BYTES;
|
||||||
byte[] output = new byte[outputLen];
|
byte[] output = new byte[outputLen];
|
||||||
System.arraycopy(salt, 0, output, 0, salt.length);
|
System.arraycopy(salt, 0, output, 0, salt.length);
|
||||||
System.arraycopy(iv, 0, output, salt.length, iv.length);
|
System.arraycopy(iv, 0, output, salt.length, iv.length);
|
||||||
@@ -380,7 +315,7 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
try {
|
try {
|
||||||
AEADBlockCipher c = new GCMBlockCipher(new AESFastEngine());
|
AEADBlockCipher c = new GCMBlockCipher(new AESFastEngine());
|
||||||
AuthenticatedCipher cipher = new AuthenticatedCipherImpl(c,
|
AuthenticatedCipher cipher = new AuthenticatedCipherImpl(c,
|
||||||
GCM_MAC_BYTES);
|
MAC_BYTES);
|
||||||
cipher.init(ENCRYPT_MODE, key, iv, null);
|
cipher.init(ENCRYPT_MODE, key, iv, null);
|
||||||
int outputOff = salt.length + iv.length;
|
int outputOff = salt.length + iv.length;
|
||||||
cipher.doFinal(input, 0, input.length, output, outputOff);
|
cipher.doFinal(input, 0, input.length, output, outputOff);
|
||||||
@@ -394,7 +329,7 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
|
|
||||||
public byte[] decryptWithPassword(byte[] input, char[] password) {
|
public byte[] decryptWithPassword(byte[] input, char[] password) {
|
||||||
// The input contains the salt, IV, ciphertext and MAC
|
// The input contains the salt, IV, ciphertext and MAC
|
||||||
if(input.length < PBKDF_SALT_BYTES + STORAGE_IV_BYTES + GCM_MAC_BYTES)
|
if(input.length < PBKDF_SALT_BYTES + STORAGE_IV_BYTES + MAC_BYTES)
|
||||||
return null; // Invalid
|
return null; // Invalid
|
||||||
byte[] salt = new byte[PBKDF_SALT_BYTES];
|
byte[] salt = new byte[PBKDF_SALT_BYTES];
|
||||||
System.arraycopy(input, 0, salt, 0, salt.length);
|
System.arraycopy(input, 0, salt, 0, salt.length);
|
||||||
@@ -402,12 +337,12 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
System.arraycopy(input, salt.length, iv, 0, iv.length);
|
System.arraycopy(input, salt.length, iv, 0, iv.length);
|
||||||
// Derive the key from the password
|
// Derive the key from the password
|
||||||
byte[] keyBytes = pbkdf2(password, salt);
|
byte[] keyBytes = pbkdf2(password, salt);
|
||||||
ErasableKey key = new ErasableKeyImpl(keyBytes, CIPHER_ALGO);
|
SecretKey key = new SecretKeyImpl(keyBytes);
|
||||||
// Initialise the cipher
|
// Initialise the cipher
|
||||||
AuthenticatedCipher cipher;
|
AuthenticatedCipher cipher;
|
||||||
try {
|
try {
|
||||||
AEADBlockCipher c = new GCMBlockCipher(new AESFastEngine());
|
AEADBlockCipher c = new GCMBlockCipher(new AESFastEngine());
|
||||||
cipher = new AuthenticatedCipherImpl(c, GCM_MAC_BYTES);
|
cipher = new AuthenticatedCipherImpl(c, MAC_BYTES);
|
||||||
cipher.init(DECRYPT_MODE, key, iv, null);
|
cipher.init(DECRYPT_MODE, key, iv, null);
|
||||||
} catch(GeneralSecurityException e) {
|
} catch(GeneralSecurityException e) {
|
||||||
key.erase();
|
key.erase();
|
||||||
@@ -417,7 +352,7 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
try {
|
try {
|
||||||
int inputOff = salt.length + iv.length;
|
int inputOff = salt.length + iv.length;
|
||||||
int inputLen = input.length - salt.length - iv.length;
|
int inputLen = input.length - salt.length - iv.length;
|
||||||
byte[] output = new byte[inputLen - GCM_MAC_BYTES];
|
byte[] output = new byte[inputLen - MAC_BYTES];
|
||||||
cipher.doFinal(input, inputOff, inputLen, output, 0);
|
cipher.doFinal(input, inputOff, inputLen, output, 0);
|
||||||
return output;
|
return output;
|
||||||
} catch(GeneralSecurityException e) {
|
} catch(GeneralSecurityException e) {
|
||||||
@@ -427,23 +362,6 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ECPublicKey checkP384Params(PublicKey publicKey) {
|
|
||||||
if(!(publicKey instanceof ECPublicKey)) throw new RuntimeException();
|
|
||||||
ECPublicKey ecPublicKey = (ECPublicKey) publicKey;
|
|
||||||
ECParameterSpec params = ecPublicKey.getParams();
|
|
||||||
EllipticCurve curve = params.getCurve();
|
|
||||||
ECField field = curve.getField();
|
|
||||||
if(!(field instanceof ECFieldFp)) throw new RuntimeException();
|
|
||||||
BigInteger q = ((ECFieldFp) field).getP();
|
|
||||||
if(!q.equals(P_384_Q)) throw new RuntimeException();
|
|
||||||
if(!curve.getA().equals(P_384_A)) throw new RuntimeException();
|
|
||||||
if(!curve.getB().equals(P_384_B)) throw new RuntimeException();
|
|
||||||
if(!params.getGenerator().equals(P_384_G)) throw new RuntimeException();
|
|
||||||
if(!params.getOrder().equals(P_384_N)) throw new RuntimeException();
|
|
||||||
if(!(params.getCofactor() == P_384_H)) throw new RuntimeException();
|
|
||||||
return ecPublicKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Key derivation function based on a hash function - see NIST SP 800-56A,
|
// Key derivation function based on a hash function - see NIST SP 800-56A,
|
||||||
// section 5.8
|
// section 5.8
|
||||||
private byte[] concatenationKdf(byte[] rawSecret, byte[] label,
|
private byte[] concatenationKdf(byte[] rawSecret, byte[] label,
|
||||||
@@ -499,8 +417,6 @@ class CryptoComponentImpl implements CryptoComponent {
|
|||||||
|
|
||||||
// Password-based key derivation function - see PKCS#5 v2.1, section 5.2
|
// Password-based key derivation function - see PKCS#5 v2.1, section 5.2
|
||||||
private byte[] pbkdf2(char[] password, byte[] salt) {
|
private byte[] pbkdf2(char[] password, byte[] salt) {
|
||||||
// This code is specific to Spongy Castle because the password-based
|
|
||||||
// KDF exposed through the JCE interface is PKCS#12
|
|
||||||
byte[] utf8 = toUtf8ByteArray(password);
|
byte[] utf8 = toUtf8ByteArray(password);
|
||||||
PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator();
|
PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator();
|
||||||
gen.init(utf8, salt, PBKDF_ITERATIONS);
|
gen.init(utf8, salt, PBKDF_ITERATIONS);
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package net.sf.briar.crypto;
|
|||||||
|
|
||||||
import net.sf.briar.api.crypto.MessageDigest;
|
import net.sf.briar.api.crypto.MessageDigest;
|
||||||
|
|
||||||
|
import org.spongycastle.crypto.Digest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A message digest that prevents length extension attacks - see Ferguson and
|
* A message digest that prevents length extension attacks - see Ferguson and
|
||||||
* Schneier, <i>Practical Cryptography</i>, chapter 6.
|
* Schneier, <i>Practical Cryptography</i>, chapter 6.
|
||||||
@@ -13,20 +15,22 @@ import net.sf.briar.api.crypto.MessageDigest;
|
|||||||
*/
|
*/
|
||||||
class DoubleDigest implements MessageDigest {
|
class DoubleDigest implements MessageDigest {
|
||||||
|
|
||||||
private final java.security.MessageDigest delegate;
|
private final Digest delegate;
|
||||||
|
|
||||||
DoubleDigest(java.security.MessageDigest delegate) {
|
DoubleDigest(Digest delegate) {
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] digest() {
|
public byte[] digest() {
|
||||||
byte[] digest = delegate.digest(); // h(m)
|
byte[] digest = new byte[delegate.getDigestSize()];
|
||||||
delegate.update(digest);
|
delegate.doFinal(digest, 0); // h(m)
|
||||||
return delegate.digest(); // h(h(m))
|
delegate.update(digest, 0, digest.length);
|
||||||
|
delegate.doFinal(digest, 0); // h(h(m))
|
||||||
|
return digest;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] digest(byte[] input) {
|
public byte[] digest(byte[] input) {
|
||||||
delegate.update(input);
|
delegate.update(input, 0, input.length);
|
||||||
return digest();
|
return digest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +42,7 @@ class DoubleDigest implements MessageDigest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getDigestLength() {
|
public int getDigestLength() {
|
||||||
return delegate.getDigestLength();
|
return delegate.getDigestSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reset() {
|
public void reset() {
|
||||||
@@ -50,7 +54,7 @@ class DoubleDigest implements MessageDigest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void update(byte[] input) {
|
public void update(byte[] input) {
|
||||||
delegate.update(input);
|
delegate.update(input, 0, input.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(byte[] input, int offset, int len) {
|
public void update(byte[] input, int offset, int len) {
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
package net.sf.briar.crypto;
|
|
||||||
|
|
||||||
import net.sf.briar.api.crypto.ErasableKey;
|
|
||||||
import net.sf.briar.util.ByteUtils;
|
|
||||||
|
|
||||||
class ErasableKeyImpl implements ErasableKey {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = -4438380720846443120L;
|
|
||||||
|
|
||||||
private final byte[] key;
|
|
||||||
private final String algorithm;
|
|
||||||
|
|
||||||
private boolean erased = false; // Locking: this
|
|
||||||
|
|
||||||
ErasableKeyImpl(byte[] key, String algorithm) {
|
|
||||||
this.key = key;
|
|
||||||
this.algorithm = algorithm;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAlgorithm() {
|
|
||||||
return algorithm;
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized byte[] getEncoded() {
|
|
||||||
if(erased) throw new IllegalStateException();
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFormat() {
|
|
||||||
return "RAW";
|
|
||||||
}
|
|
||||||
|
|
||||||
public ErasableKey copy() {
|
|
||||||
return new ErasableKeyImpl(key.clone(), algorithm);
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void erase() {
|
|
||||||
if(erased) throw new IllegalStateException();
|
|
||||||
ByteUtils.erase(key);
|
|
||||||
erased = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
41
briar-core/src/net/sf/briar/crypto/P384Constants.java
Normal file
41
briar-core/src/net/sf/briar/crypto/P384Constants.java
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package net.sf.briar.crypto;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
import org.spongycastle.crypto.params.ECDomainParameters;
|
||||||
|
import org.spongycastle.math.ec.ECCurve;
|
||||||
|
import org.spongycastle.math.ec.ECFieldElement;
|
||||||
|
import org.spongycastle.math.ec.ECPoint;
|
||||||
|
|
||||||
|
interface P384Constants {
|
||||||
|
|
||||||
|
// Parameters for NIST elliptic curve P-384 - see "Suite B Implementer's
|
||||||
|
// Guide to NIST SP 800-56A", section A.2
|
||||||
|
BigInteger P_384_Q = new BigInteger("FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" +
|
||||||
|
"FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFE" +
|
||||||
|
"FFFFFFFF" + "00000000" + "00000000" + "FFFFFFFF", 16);
|
||||||
|
BigInteger P_384_A = new BigInteger("FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" +
|
||||||
|
"FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFE" +
|
||||||
|
"FFFFFFFF" + "00000000" + "00000000" + "FFFFFFFC", 16);
|
||||||
|
BigInteger P_384_B = new BigInteger("B3312FA7" + "E23EE7E4" + "988E056B" +
|
||||||
|
"E3F82D19" + "181D9C6E" + "FE814112" + "0314088F" + "5013875A" +
|
||||||
|
"C656398D" + "8A2ED19D" + "2A85C8ED" + "D3EC2AEF", 16);
|
||||||
|
BigInteger P_384_G_X = new BigInteger("AA87CA22" + "BE8B0537" + "8EB1C71E" +
|
||||||
|
"F320AD74" + "6E1D3B62" + "8BA79B98" + "59F741E0" + "82542A38" +
|
||||||
|
"5502F25D" + "BF55296C" + "3A545E38" + "72760AB7", 16);
|
||||||
|
BigInteger P_384_G_Y = new BigInteger("3617DE4A" + "96262C6F" + "5D9E98BF" +
|
||||||
|
"9292DC29" + "F8F41DBD" + "289A147C" + "E9DA3113" + "B5F0B8C0" +
|
||||||
|
"0A60B1CE" + "1D7E819D" + "7A431D7C" + "90EA0E5F", 16);
|
||||||
|
BigInteger P_384_N = new BigInteger("FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" +
|
||||||
|
"FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "C7634D81" + "F4372DDF" +
|
||||||
|
"581A0DB2" + "48B0A77A" + "ECEC196A" + "CCC52973", 16);
|
||||||
|
BigInteger P_384_H = BigInteger.ONE;
|
||||||
|
|
||||||
|
// Static parameter objects derived from the above parameters
|
||||||
|
ECCurve P_384_CURVE = new ECCurve.Fp(P_384_Q, P_384_A, P_384_B);
|
||||||
|
ECPoint P_384_G = new ECPoint.Fp(P_384_CURVE,
|
||||||
|
new ECFieldElement.Fp(P_384_Q, P_384_G_X),
|
||||||
|
new ECFieldElement.Fp(P_384_Q, P_384_G_Y));
|
||||||
|
ECDomainParameters P_384_PARAMS = new ECDomainParameters(P_384_CURVE,
|
||||||
|
P_384_G, P_384_N, P_384_H);
|
||||||
|
}
|
||||||
@@ -1,18 +1,17 @@
|
|||||||
package net.sf.briar.crypto;
|
package net.sf.briar.crypto;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.security.KeyFactory;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.PrivateKey;
|
|
||||||
import java.security.PublicKey;
|
|
||||||
import java.security.interfaces.ECPrivateKey;
|
|
||||||
import java.security.interfaces.ECPublicKey;
|
|
||||||
import java.security.spec.ECParameterSpec;
|
|
||||||
import java.security.spec.ECPoint;
|
|
||||||
import java.security.spec.ECPrivateKeySpec;
|
|
||||||
import java.security.spec.ECPublicKeySpec;
|
|
||||||
import java.security.spec.InvalidKeySpecException;
|
|
||||||
|
|
||||||
import net.sf.briar.api.crypto.KeyParser;
|
import net.sf.briar.api.crypto.KeyParser;
|
||||||
|
import net.sf.briar.api.crypto.PrivateKey;
|
||||||
|
import net.sf.briar.api.crypto.PublicKey;
|
||||||
|
|
||||||
|
import org.spongycastle.crypto.params.ECDomainParameters;
|
||||||
|
import org.spongycastle.crypto.params.ECPrivateKeyParameters;
|
||||||
|
import org.spongycastle.crypto.params.ECPublicKeyParameters;
|
||||||
|
import org.spongycastle.math.ec.ECFieldElement;
|
||||||
|
import org.spongycastle.math.ec.ECPoint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A key parser that uses the encoding defined in "SEC 1: Elliptic Curve
|
* A key parser that uses the encoding defined in "SEC 1: Elliptic Curve
|
||||||
@@ -21,14 +20,11 @@ import net.sf.briar.api.crypto.KeyParser;
|
|||||||
*/
|
*/
|
||||||
class Sec1KeyParser implements KeyParser {
|
class Sec1KeyParser implements KeyParser {
|
||||||
|
|
||||||
private final KeyFactory keyFactory;
|
private final ECDomainParameters params;
|
||||||
private final ECParameterSpec params;
|
|
||||||
private final BigInteger modulus;
|
private final BigInteger modulus;
|
||||||
private final int keyBits, bytesPerInt, publicKeyBytes, privateKeyBytes;
|
private final int keyBits, bytesPerInt, publicKeyBytes, privateKeyBytes;
|
||||||
|
|
||||||
Sec1KeyParser(KeyFactory keyFactory, ECParameterSpec params,
|
Sec1KeyParser(ECDomainParameters params, BigInteger modulus, int keyBits) {
|
||||||
BigInteger modulus, int keyBits) {
|
|
||||||
this.keyFactory = keyFactory;
|
|
||||||
this.params = params;
|
this.params = params;
|
||||||
this.modulus = modulus;
|
this.modulus = modulus;
|
||||||
this.keyBits = keyBits;
|
this.keyBits = keyBits;
|
||||||
@@ -38,43 +34,48 @@ class Sec1KeyParser implements KeyParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public PublicKey parsePublicKey(byte[] encodedKey)
|
public PublicKey parsePublicKey(byte[] encodedKey)
|
||||||
throws InvalidKeySpecException {
|
throws GeneralSecurityException {
|
||||||
if(encodedKey.length != publicKeyBytes)
|
if(encodedKey.length != publicKeyBytes)
|
||||||
throw new InvalidKeySpecException();
|
throw new GeneralSecurityException();
|
||||||
// The first byte must be 0x04
|
// The first byte must be 0x04
|
||||||
if(encodedKey[0] != 4) throw new InvalidKeySpecException();
|
if(encodedKey[0] != 4) throw new GeneralSecurityException();
|
||||||
// The x co-ordinate must be >= 0 and < q
|
// The x co-ordinate must be >= 0 and < q
|
||||||
byte[] xBytes = new byte[bytesPerInt];
|
byte[] xBytes = new byte[bytesPerInt];
|
||||||
System.arraycopy(encodedKey, 1, xBytes, 0, bytesPerInt);
|
System.arraycopy(encodedKey, 1, xBytes, 0, bytesPerInt);
|
||||||
BigInteger x = new BigInteger(1, xBytes); // Positive signum
|
BigInteger x = new BigInteger(1, xBytes); // Positive signum
|
||||||
if(x.compareTo(modulus) >= 0) throw new InvalidKeySpecException();
|
if(x.compareTo(modulus) >= 0) throw new GeneralSecurityException();
|
||||||
// The y co-ordinate must be >= 0 and < q
|
// The y co-ordinate must be >= 0 and < q
|
||||||
byte[] yBytes = new byte[bytesPerInt];
|
byte[] yBytes = new byte[bytesPerInt];
|
||||||
System.arraycopy(encodedKey, bytesPerInt + 1, yBytes, 0, bytesPerInt);
|
System.arraycopy(encodedKey, bytesPerInt + 1, yBytes, 0, bytesPerInt);
|
||||||
BigInteger y = new BigInteger(1, yBytes); // Positive signum
|
BigInteger y = new BigInteger(1, yBytes); // Positive signum
|
||||||
if(y.compareTo(modulus) >= 0) throw new InvalidKeySpecException();
|
if(y.compareTo(modulus) >= 0) throw new GeneralSecurityException();
|
||||||
// Verify that y^2 == x^3 + ax + b (mod q)
|
// Verify that y^2 == x^3 + ax + b (mod q)
|
||||||
BigInteger a = params.getCurve().getA(), b = params.getCurve().getB();
|
BigInteger a = params.getCurve().getA().toBigInteger();
|
||||||
|
BigInteger b = params.getCurve().getB().toBigInteger();
|
||||||
BigInteger lhs = y.multiply(y).mod(modulus);
|
BigInteger lhs = y.multiply(y).mod(modulus);
|
||||||
BigInteger rhs = x.multiply(x).add(a).multiply(x).add(b).mod(modulus);
|
BigInteger rhs = x.multiply(x).add(a).multiply(x).add(b).mod(modulus);
|
||||||
if(!lhs.equals(rhs)) throw new InvalidKeySpecException();
|
if(!lhs.equals(rhs)) throw new GeneralSecurityException();
|
||||||
// FIXME: Verify that n times the point (x, y) = the point at infinity
|
// Verify that the point (x, y) times n = the point at infinity
|
||||||
|
ECFieldElement elementX = new ECFieldElement.Fp(modulus, x);
|
||||||
|
ECFieldElement elementY = new ECFieldElement.Fp(modulus, y);
|
||||||
|
ECPoint pub = new ECPoint.Fp(params.getCurve(), elementX, elementY);
|
||||||
|
if(!pub.multiply(params.getN()).isInfinity())
|
||||||
|
throw new GeneralSecurityException();
|
||||||
// Construct a public key from the point (x, y) and the params
|
// Construct a public key from the point (x, y) and the params
|
||||||
ECPoint pub = new ECPoint(x, y);
|
ECPublicKeyParameters k = new ECPublicKeyParameters(pub, params);
|
||||||
ECPublicKeySpec keySpec = new ECPublicKeySpec(pub, params);
|
|
||||||
ECPublicKey k = (ECPublicKey) keyFactory.generatePublic(keySpec);
|
|
||||||
return new Sec1PublicKey(k, keyBits);
|
return new Sec1PublicKey(k, keyBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PrivateKey parsePrivateKey(byte[] encodedKey)
|
public PrivateKey parsePrivateKey(byte[] encodedKey)
|
||||||
throws InvalidKeySpecException {
|
throws GeneralSecurityException {
|
||||||
if(encodedKey.length != privateKeyBytes)
|
if(encodedKey.length != privateKeyBytes)
|
||||||
throw new InvalidKeySpecException();
|
throw new GeneralSecurityException();
|
||||||
BigInteger s = new BigInteger(1, encodedKey); // Positive signum
|
BigInteger d = new BigInteger(1, encodedKey); // Positive signum
|
||||||
if(s.compareTo(params.getOrder()) >= 0)
|
// Verify that the private value is < n
|
||||||
throw new InvalidKeySpecException();
|
if(d.compareTo(params.getN()) >= 0)
|
||||||
ECPrivateKeySpec keySpec = new ECPrivateKeySpec(s, params);
|
throw new GeneralSecurityException();
|
||||||
ECPrivateKey k = (ECPrivateKey) keyFactory.generatePrivate(keySpec);
|
// Construct a private key from the private value and the params
|
||||||
|
ECPrivateKeyParameters k = new ECPrivateKeyParameters(d, params);
|
||||||
return new Sec1PrivateKey(k, keyBits);
|
return new Sec1PrivateKey(k, keyBits);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,57 +1,32 @@
|
|||||||
package net.sf.briar.crypto;
|
package net.sf.briar.crypto;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.security.interfaces.ECPrivateKey;
|
|
||||||
import java.security.spec.ECParameterSpec;
|
|
||||||
|
|
||||||
class Sec1PrivateKey implements ECPrivateKey,
|
import net.sf.briar.api.crypto.PrivateKey;
|
||||||
org.spongycastle.jce.interfaces.ECPrivateKey {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = -493100835871466670L;
|
import org.spongycastle.crypto.params.ECPrivateKeyParameters;
|
||||||
|
|
||||||
private final ECPrivateKey key;
|
class Sec1PrivateKey implements PrivateKey {
|
||||||
|
|
||||||
|
private final ECPrivateKeyParameters key;
|
||||||
private final int privateKeyBytes;
|
private final int privateKeyBytes;
|
||||||
|
|
||||||
Sec1PrivateKey(ECPrivateKey key, int keyBits) {
|
Sec1PrivateKey(ECPrivateKeyParameters key, int keyBits) {
|
||||||
// Spongy Castle only accepts instances of its own interface, so we
|
|
||||||
// have to wrap an instance of that interface and delegate to it
|
|
||||||
if(!(key instanceof org.spongycastle.jce.interfaces.ECPrivateKey))
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
this.key = key;
|
this.key = key;
|
||||||
privateKeyBytes = (int) Math.ceil(keyBits / 8.0);
|
privateKeyBytes = (int) Math.ceil(keyBits / 8.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAlgorithm() {
|
|
||||||
return key.getAlgorithm();
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getEncoded() {
|
public byte[] getEncoded() {
|
||||||
byte[] encodedKey = new byte[privateKeyBytes];
|
byte[] encodedKey = new byte[privateKeyBytes];
|
||||||
BigInteger s = key.getS();
|
BigInteger d = key.getD();
|
||||||
// Copy up to privateKeyBytes bytes into exactly privateKeyBytes bytes
|
// Copy up to privateKeyBytes bytes into exactly privateKeyBytes bytes
|
||||||
byte[] sBytes = s.toByteArray();
|
byte[] dBytes = d.toByteArray();
|
||||||
for(int i = 0; i < sBytes.length && i < privateKeyBytes; i++)
|
for(int i = 0; i < dBytes.length && i < privateKeyBytes; i++)
|
||||||
encodedKey[privateKeyBytes - 1 - i] = sBytes[sBytes.length - 1 - i];
|
encodedKey[privateKeyBytes - 1 - i] = dBytes[dBytes.length - 1 - i];
|
||||||
return encodedKey;
|
return encodedKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFormat() {
|
ECPrivateKeyParameters getKey() {
|
||||||
return "SEC1";
|
return key;
|
||||||
}
|
|
||||||
|
|
||||||
public ECParameterSpec getParams() {
|
|
||||||
return key.getParams();
|
|
||||||
}
|
|
||||||
|
|
||||||
public BigInteger getS() {
|
|
||||||
return key.getS();
|
|
||||||
}
|
|
||||||
|
|
||||||
public org.spongycastle.jce.spec.ECParameterSpec getParameters() {
|
|
||||||
return ((org.spongycastle.jce.interfaces.ECPrivateKey) key).getParameters();
|
|
||||||
}
|
|
||||||
|
|
||||||
public BigInteger getD() {
|
|
||||||
return ((org.spongycastle.jce.interfaces.ECPrivateKey) key).getD();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,42 +1,32 @@
|
|||||||
package net.sf.briar.crypto;
|
package net.sf.briar.crypto;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.security.interfaces.ECPublicKey;
|
|
||||||
import java.security.spec.ECParameterSpec;
|
import net.sf.briar.api.crypto.PublicKey;
|
||||||
import java.security.spec.ECPoint;
|
|
||||||
|
import org.spongycastle.crypto.params.ECPublicKeyParameters;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An elliptic curve public key that uses the encoding defined in "SEC 1:
|
* An elliptic curve public key that uses the encoding defined in "SEC 1:
|
||||||
* Elliptic Curve Cryptography", section 2.3 (Certicom Corporation, May 2009).
|
* Elliptic Curve Cryptography", section 2.3 (Certicom Corporation, May 2009).
|
||||||
* Point compression is not used.
|
* Point compression is not used.
|
||||||
*/
|
*/
|
||||||
class Sec1PublicKey implements ECPublicKey,
|
class Sec1PublicKey implements PublicKey {
|
||||||
org.spongycastle.jce.interfaces.ECPublicKey {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = -2722797033851423987L;
|
private final ECPublicKeyParameters key;
|
||||||
|
|
||||||
private final ECPublicKey key;
|
|
||||||
private final int bytesPerInt, publicKeyBytes;
|
private final int bytesPerInt, publicKeyBytes;
|
||||||
|
|
||||||
Sec1PublicKey(ECPublicKey key, int keyBits) {
|
Sec1PublicKey(ECPublicKeyParameters key, int keyBits) {
|
||||||
// Spongy Castle only accepts instances of its own interface, so we
|
|
||||||
// have to wrap an instance of that interface and delegate to it
|
|
||||||
if(!(key instanceof org.spongycastle.jce.interfaces.ECPublicKey))
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
this.key = key;
|
this.key = key;
|
||||||
bytesPerInt = (int) Math.ceil(keyBits / 8.0);
|
bytesPerInt = (int) Math.ceil(keyBits / 8.0);
|
||||||
publicKeyBytes = 1 + 2 * bytesPerInt;
|
publicKeyBytes = 1 + 2 * bytesPerInt;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAlgorithm() {
|
|
||||||
return key.getAlgorithm();
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getEncoded() {
|
public byte[] getEncoded() {
|
||||||
byte[] encodedKey = new byte[publicKeyBytes];
|
byte[] encodedKey = new byte[publicKeyBytes];
|
||||||
encodedKey[0] = 4;
|
encodedKey[0] = 4;
|
||||||
BigInteger x = key.getW().getAffineX();
|
BigInteger x = key.getQ().getX().toBigInteger();
|
||||||
BigInteger y = key.getW().getAffineY();
|
BigInteger y = key.getQ().getY().toBigInteger();
|
||||||
// Copy up to bytesPerInt bytes into exactly bytesPerInt bytes
|
// Copy up to bytesPerInt bytes into exactly bytesPerInt bytes
|
||||||
byte[] xBytes = x.toByteArray();
|
byte[] xBytes = x.toByteArray();
|
||||||
for(int i = 0; i < xBytes.length && i < bytesPerInt; i++)
|
for(int i = 0; i < xBytes.length && i < bytesPerInt; i++)
|
||||||
@@ -47,23 +37,7 @@ org.spongycastle.jce.interfaces.ECPublicKey {
|
|||||||
return encodedKey;
|
return encodedKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFormat() {
|
ECPublicKeyParameters getKey() {
|
||||||
return "SEC1";
|
return key;
|
||||||
}
|
|
||||||
|
|
||||||
public ECParameterSpec getParams() {
|
|
||||||
return key.getParams();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ECPoint getW() {
|
|
||||||
return key.getW();
|
|
||||||
}
|
|
||||||
|
|
||||||
public org.spongycastle.jce.spec.ECParameterSpec getParameters() {
|
|
||||||
return ((org.spongycastle.jce.interfaces.ECPublicKey) key).getParameters();
|
|
||||||
}
|
|
||||||
|
|
||||||
public org.spongycastle.math.ec.ECPoint getQ() {
|
|
||||||
return ((org.spongycastle.jce.interfaces.ECPublicKey) key).getQ();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
30
briar-core/src/net/sf/briar/crypto/SecretKeyImpl.java
Normal file
30
briar-core/src/net/sf/briar/crypto/SecretKeyImpl.java
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package net.sf.briar.crypto;
|
||||||
|
|
||||||
|
import net.sf.briar.api.crypto.SecretKey;
|
||||||
|
import net.sf.briar.util.ByteUtils;
|
||||||
|
|
||||||
|
class SecretKeyImpl implements SecretKey {
|
||||||
|
|
||||||
|
private final byte[] key;
|
||||||
|
|
||||||
|
private boolean erased = false; // Locking: this
|
||||||
|
|
||||||
|
SecretKeyImpl(byte[] key) {
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized byte[] getEncoded() {
|
||||||
|
if(erased) throw new IllegalStateException();
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SecretKey copy() {
|
||||||
|
return new SecretKeyImpl(key.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void erase() {
|
||||||
|
if(erased) throw new IllegalStateException();
|
||||||
|
ByteUtils.erase(key);
|
||||||
|
erased = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
58
briar-core/src/net/sf/briar/crypto/SignatureImpl.java
Normal file
58
briar-core/src/net/sf/briar/crypto/SignatureImpl.java
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package net.sf.briar.crypto;
|
||||||
|
|
||||||
|
import java.security.GeneralSecurityException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
|
||||||
|
import net.sf.briar.api.crypto.PrivateKey;
|
||||||
|
import net.sf.briar.api.crypto.PublicKey;
|
||||||
|
import net.sf.briar.api.crypto.Signature;
|
||||||
|
|
||||||
|
import org.spongycastle.crypto.digests.SHA384Digest;
|
||||||
|
import org.spongycastle.crypto.params.ECPrivateKeyParameters;
|
||||||
|
import org.spongycastle.crypto.params.ECPublicKeyParameters;
|
||||||
|
import org.spongycastle.crypto.params.ParametersWithRandom;
|
||||||
|
import org.spongycastle.crypto.signers.DSADigestSigner;
|
||||||
|
import org.spongycastle.crypto.signers.ECDSASigner;
|
||||||
|
|
||||||
|
class SignatureImpl implements Signature {
|
||||||
|
|
||||||
|
private final SecureRandom secureRandom;
|
||||||
|
private final DSADigestSigner signer;
|
||||||
|
|
||||||
|
SignatureImpl(SecureRandom secureRandom) {
|
||||||
|
this.secureRandom = secureRandom;
|
||||||
|
signer = new DSADigestSigner(new ECDSASigner(), new SHA384Digest());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initSign(PrivateKey k) throws GeneralSecurityException {
|
||||||
|
if(!(k instanceof Sec1PrivateKey)) throw new GeneralSecurityException();
|
||||||
|
ECPrivateKeyParameters priv = ((Sec1PrivateKey) k).getKey();
|
||||||
|
signer.init(true, new ParametersWithRandom(priv, secureRandom));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initVerify(PublicKey k) throws GeneralSecurityException {
|
||||||
|
if(!(k instanceof Sec1PublicKey)) throw new GeneralSecurityException();
|
||||||
|
ECPublicKeyParameters pub = ((Sec1PublicKey) k).getKey();
|
||||||
|
signer.init(false, pub);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(byte b) {
|
||||||
|
signer.update(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(byte[] b) {
|
||||||
|
update(b, 0, b.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(byte[] b, int off, int len) {
|
||||||
|
signer.update(b, off, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] sign() {
|
||||||
|
return signer.generateSignature();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean verify(byte[] signature) {
|
||||||
|
return signer.verifySignature(signature);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,8 +13,6 @@ import static net.sf.briar.api.messaging.Rating.GOOD;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.KeyPair;
|
|
||||||
import java.security.Signature;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -36,9 +34,11 @@ import net.sf.briar.api.UniqueId;
|
|||||||
import net.sf.briar.api.clock.Clock;
|
import net.sf.briar.api.clock.Clock;
|
||||||
import net.sf.briar.api.crypto.CryptoComponent;
|
import net.sf.briar.api.crypto.CryptoComponent;
|
||||||
import net.sf.briar.api.crypto.KeyManager;
|
import net.sf.briar.api.crypto.KeyManager;
|
||||||
|
import net.sf.briar.api.crypto.KeyPair;
|
||||||
import net.sf.briar.api.crypto.KeyParser;
|
import net.sf.briar.api.crypto.KeyParser;
|
||||||
import net.sf.briar.api.crypto.MessageDigest;
|
import net.sf.briar.api.crypto.MessageDigest;
|
||||||
import net.sf.briar.api.crypto.PseudoRandom;
|
import net.sf.briar.api.crypto.PseudoRandom;
|
||||||
|
import net.sf.briar.api.crypto.Signature;
|
||||||
import net.sf.briar.api.db.DatabaseComponent;
|
import net.sf.briar.api.db.DatabaseComponent;
|
||||||
import net.sf.briar.api.db.DbException;
|
import net.sf.briar.api.db.DbException;
|
||||||
import net.sf.briar.api.db.NoSuchTransportException;
|
import net.sf.briar.api.db.NoSuchTransportException;
|
||||||
|
|||||||
@@ -16,14 +16,14 @@ import java.nio.ByteBuffer;
|
|||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.charset.CharsetDecoder;
|
import java.nio.charset.CharsetDecoder;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.PrivateKey;
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.security.Signature;
|
|
||||||
|
|
||||||
import net.sf.briar.api.Author;
|
import net.sf.briar.api.Author;
|
||||||
import net.sf.briar.api.clock.Clock;
|
import net.sf.briar.api.clock.Clock;
|
||||||
import net.sf.briar.api.crypto.CryptoComponent;
|
import net.sf.briar.api.crypto.CryptoComponent;
|
||||||
import net.sf.briar.api.crypto.MessageDigest;
|
import net.sf.briar.api.crypto.MessageDigest;
|
||||||
|
import net.sf.briar.api.crypto.PrivateKey;
|
||||||
|
import net.sf.briar.api.crypto.Signature;
|
||||||
import net.sf.briar.api.messaging.Group;
|
import net.sf.briar.api.messaging.Group;
|
||||||
import net.sf.briar.api.messaging.Message;
|
import net.sf.briar.api.messaging.Message;
|
||||||
import net.sf.briar.api.messaging.MessageFactory;
|
import net.sf.briar.api.messaging.MessageFactory;
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
package net.sf.briar.messaging;
|
package net.sf.briar.messaging;
|
||||||
|
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.security.PublicKey;
|
|
||||||
import java.security.Signature;
|
|
||||||
|
|
||||||
import net.sf.briar.api.Author;
|
import net.sf.briar.api.Author;
|
||||||
import net.sf.briar.api.crypto.CryptoComponent;
|
import net.sf.briar.api.crypto.CryptoComponent;
|
||||||
import net.sf.briar.api.crypto.KeyParser;
|
import net.sf.briar.api.crypto.KeyParser;
|
||||||
import net.sf.briar.api.crypto.MessageDigest;
|
import net.sf.briar.api.crypto.MessageDigest;
|
||||||
|
import net.sf.briar.api.crypto.PublicKey;
|
||||||
|
import net.sf.briar.api.crypto.Signature;
|
||||||
import net.sf.briar.api.messaging.Group;
|
import net.sf.briar.api.messaging.Group;
|
||||||
import net.sf.briar.api.messaging.Message;
|
import net.sf.briar.api.messaging.Message;
|
||||||
import net.sf.briar.api.messaging.MessageId;
|
import net.sf.briar.api.messaging.MessageId;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package net.sf.briar.transport;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
import net.sf.briar.api.crypto.CryptoComponent;
|
import net.sf.briar.api.crypto.CryptoComponent;
|
||||||
import net.sf.briar.api.crypto.ErasableKey;
|
import net.sf.briar.api.crypto.SecretKey;
|
||||||
import net.sf.briar.api.transport.ConnectionContext;
|
import net.sf.briar.api.transport.ConnectionContext;
|
||||||
import net.sf.briar.api.transport.ConnectionReader;
|
import net.sf.briar.api.transport.ConnectionReader;
|
||||||
import net.sf.briar.api.transport.ConnectionReaderFactory;
|
import net.sf.briar.api.transport.ConnectionReaderFactory;
|
||||||
@@ -26,7 +26,7 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory {
|
|||||||
long connection = ctx.getConnectionNumber();
|
long connection = ctx.getConnectionNumber();
|
||||||
boolean weAreAlice = ctx.getAlice();
|
boolean weAreAlice = ctx.getAlice();
|
||||||
boolean initiatorIsAlice = incoming ? !weAreAlice : weAreAlice;
|
boolean initiatorIsAlice = incoming ? !weAreAlice : weAreAlice;
|
||||||
ErasableKey frameKey = crypto.deriveFrameKey(secret, connection,
|
SecretKey frameKey = crypto.deriveFrameKey(secret, connection,
|
||||||
initiatorIsAlice, initiator);
|
initiatorIsAlice, initiator);
|
||||||
FrameReader encryption = new IncomingEncryptionLayer(in,
|
FrameReader encryption = new IncomingEncryptionLayer(in,
|
||||||
crypto.getFrameCipher(), frameKey, maxFrameLength);
|
crypto.getFrameCipher(), frameKey, maxFrameLength);
|
||||||
@@ -35,7 +35,7 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory {
|
|||||||
|
|
||||||
public ConnectionReader createInvitationConnectionReader(InputStream in,
|
public ConnectionReader createInvitationConnectionReader(InputStream in,
|
||||||
int maxFrameLength, byte[] secret, boolean alice) {
|
int maxFrameLength, byte[] secret, boolean alice) {
|
||||||
ErasableKey frameKey = crypto.deriveFrameKey(secret, 0, true, alice);
|
SecretKey frameKey = crypto.deriveFrameKey(secret, 0, true, alice);
|
||||||
FrameReader encryption = new IncomingEncryptionLayer(in,
|
FrameReader encryption = new IncomingEncryptionLayer(in,
|
||||||
crypto.getFrameCipher(), frameKey, maxFrameLength);
|
crypto.getFrameCipher(), frameKey, maxFrameLength);
|
||||||
return new ConnectionReaderImpl(encryption, maxFrameLength);
|
return new ConnectionReaderImpl(encryption, maxFrameLength);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
|
|||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
import net.sf.briar.api.crypto.CryptoComponent;
|
import net.sf.briar.api.crypto.CryptoComponent;
|
||||||
import net.sf.briar.api.crypto.ErasableKey;
|
import net.sf.briar.api.crypto.SecretKey;
|
||||||
import net.sf.briar.api.transport.ConnectionContext;
|
import net.sf.briar.api.transport.ConnectionContext;
|
||||||
import net.sf.briar.api.transport.ConnectionWriter;
|
import net.sf.briar.api.transport.ConnectionWriter;
|
||||||
import net.sf.briar.api.transport.ConnectionWriterFactory;
|
import net.sf.briar.api.transport.ConnectionWriterFactory;
|
||||||
@@ -28,12 +28,12 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory {
|
|||||||
long connection = ctx.getConnectionNumber();
|
long connection = ctx.getConnectionNumber();
|
||||||
boolean weAreAlice = ctx.getAlice();
|
boolean weAreAlice = ctx.getAlice();
|
||||||
boolean initiatorIsAlice = incoming ? !weAreAlice : weAreAlice;
|
boolean initiatorIsAlice = incoming ? !weAreAlice : weAreAlice;
|
||||||
ErasableKey frameKey = crypto.deriveFrameKey(secret, connection,
|
SecretKey frameKey = crypto.deriveFrameKey(secret, connection,
|
||||||
initiatorIsAlice, initiator);
|
initiatorIsAlice, initiator);
|
||||||
FrameWriter encryption;
|
FrameWriter encryption;
|
||||||
if(initiator) {
|
if(initiator) {
|
||||||
byte[] tag = new byte[TAG_LENGTH];
|
byte[] tag = new byte[TAG_LENGTH];
|
||||||
ErasableKey tagKey = crypto.deriveTagKey(secret, initiatorIsAlice);
|
SecretKey tagKey = crypto.deriveTagKey(secret, initiatorIsAlice);
|
||||||
crypto.encodeTag(tag, tagKey, connection);
|
crypto.encodeTag(tag, tagKey, connection);
|
||||||
tagKey.erase();
|
tagKey.erase();
|
||||||
encryption = new OutgoingEncryptionLayer(out, capacity,
|
encryption = new OutgoingEncryptionLayer(out, capacity,
|
||||||
@@ -47,7 +47,7 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory {
|
|||||||
|
|
||||||
public ConnectionWriter createInvitationConnectionWriter(OutputStream out,
|
public ConnectionWriter createInvitationConnectionWriter(OutputStream out,
|
||||||
int maxFrameLength, byte[] secret, boolean alice) {
|
int maxFrameLength, byte[] secret, boolean alice) {
|
||||||
ErasableKey frameKey = crypto.deriveFrameKey(secret, 0, true, alice);
|
SecretKey frameKey = crypto.deriveFrameKey(secret, 0, true, alice);
|
||||||
FrameWriter encryption = new OutgoingEncryptionLayer(out,
|
FrameWriter encryption = new OutgoingEncryptionLayer(out,
|
||||||
Long.MAX_VALUE, crypto.getFrameCipher(), frameKey,
|
Long.MAX_VALUE, crypto.getFrameCipher(), frameKey,
|
||||||
maxFrameLength);
|
maxFrameLength);
|
||||||
|
|||||||
@@ -13,13 +13,13 @@ import java.security.GeneralSecurityException;
|
|||||||
|
|
||||||
import net.sf.briar.api.FormatException;
|
import net.sf.briar.api.FormatException;
|
||||||
import net.sf.briar.api.crypto.AuthenticatedCipher;
|
import net.sf.briar.api.crypto.AuthenticatedCipher;
|
||||||
import net.sf.briar.api.crypto.ErasableKey;
|
import net.sf.briar.api.crypto.SecretKey;
|
||||||
|
|
||||||
class IncomingEncryptionLayer implements FrameReader {
|
class IncomingEncryptionLayer implements FrameReader {
|
||||||
|
|
||||||
private final InputStream in;
|
private final InputStream in;
|
||||||
private final AuthenticatedCipher frameCipher;
|
private final AuthenticatedCipher frameCipher;
|
||||||
private final ErasableKey frameKey;
|
private final SecretKey frameKey;
|
||||||
private final byte[] iv, aad, ciphertext;
|
private final byte[] iv, aad, ciphertext;
|
||||||
private final int frameLength;
|
private final int frameLength;
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ class IncomingEncryptionLayer implements FrameReader {
|
|||||||
private boolean finalFrame;
|
private boolean finalFrame;
|
||||||
|
|
||||||
IncomingEncryptionLayer(InputStream in, AuthenticatedCipher frameCipher,
|
IncomingEncryptionLayer(InputStream in, AuthenticatedCipher frameCipher,
|
||||||
ErasableKey frameKey, int frameLength) {
|
SecretKey frameKey, int frameLength) {
|
||||||
this.in = in;
|
this.in = in;
|
||||||
this.frameCipher = frameCipher;
|
this.frameCipher = frameCipher;
|
||||||
this.frameKey = frameKey;
|
this.frameKey = frameKey;
|
||||||
|
|||||||
@@ -12,13 +12,13 @@ import java.io.OutputStream;
|
|||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
|
|
||||||
import net.sf.briar.api.crypto.AuthenticatedCipher;
|
import net.sf.briar.api.crypto.AuthenticatedCipher;
|
||||||
import net.sf.briar.api.crypto.ErasableKey;
|
import net.sf.briar.api.crypto.SecretKey;
|
||||||
|
|
||||||
class OutgoingEncryptionLayer implements FrameWriter {
|
class OutgoingEncryptionLayer implements FrameWriter {
|
||||||
|
|
||||||
private final OutputStream out;
|
private final OutputStream out;
|
||||||
private final AuthenticatedCipher frameCipher;
|
private final AuthenticatedCipher frameCipher;
|
||||||
private final ErasableKey frameKey;
|
private final SecretKey frameKey;
|
||||||
private final byte[] tag, iv, aad, ciphertext;
|
private final byte[] tag, iv, aad, ciphertext;
|
||||||
private final int frameLength, maxPayloadLength;
|
private final int frameLength, maxPayloadLength;
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ class OutgoingEncryptionLayer implements FrameWriter {
|
|||||||
|
|
||||||
/** Constructor for the initiator's side of a connection. */
|
/** Constructor for the initiator's side of a connection. */
|
||||||
OutgoingEncryptionLayer(OutputStream out, long capacity,
|
OutgoingEncryptionLayer(OutputStream out, long capacity,
|
||||||
AuthenticatedCipher frameCipher, ErasableKey frameKey,
|
AuthenticatedCipher frameCipher, SecretKey frameKey,
|
||||||
int frameLength, byte[] tag) {
|
int frameLength, byte[] tag) {
|
||||||
this.out = out;
|
this.out = out;
|
||||||
this.capacity = capacity;
|
this.capacity = capacity;
|
||||||
@@ -45,7 +45,7 @@ class OutgoingEncryptionLayer implements FrameWriter {
|
|||||||
|
|
||||||
/** Constructor for the responder's side of a connection. */
|
/** Constructor for the responder's side of a connection. */
|
||||||
OutgoingEncryptionLayer(OutputStream out, long capacity,
|
OutgoingEncryptionLayer(OutputStream out, long capacity,
|
||||||
AuthenticatedCipher frameCipher, ErasableKey frameKey,
|
AuthenticatedCipher frameCipher, SecretKey frameKey,
|
||||||
int frameLength) {
|
int frameLength) {
|
||||||
this.out = out;
|
this.out = out;
|
||||||
this.capacity = capacity;
|
this.capacity = capacity;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import net.sf.briar.api.Bytes;
|
|||||||
import net.sf.briar.api.ContactId;
|
import net.sf.briar.api.ContactId;
|
||||||
import net.sf.briar.api.TransportId;
|
import net.sf.briar.api.TransportId;
|
||||||
import net.sf.briar.api.crypto.CryptoComponent;
|
import net.sf.briar.api.crypto.CryptoComponent;
|
||||||
import net.sf.briar.api.crypto.ErasableKey;
|
import net.sf.briar.api.crypto.SecretKey;
|
||||||
import net.sf.briar.api.db.DatabaseComponent;
|
import net.sf.briar.api.db.DatabaseComponent;
|
||||||
import net.sf.briar.api.db.DbException;
|
import net.sf.briar.api.db.DbException;
|
||||||
import net.sf.briar.api.transport.ConnectionContext;
|
import net.sf.briar.api.transport.ConnectionContext;
|
||||||
@@ -41,7 +41,7 @@ class TransportConnectionRecogniser {
|
|||||||
TagContext t = tagMap.remove(new Bytes(tag));
|
TagContext t = tagMap.remove(new Bytes(tag));
|
||||||
if(t == null) return null; // The tag was not expected
|
if(t == null) return null; // The tag was not expected
|
||||||
// Update the connection window and the expected tags
|
// Update the connection window and the expected tags
|
||||||
ErasableKey key = crypto.deriveTagKey(t.secret, !t.alice);
|
SecretKey key = crypto.deriveTagKey(t.secret, !t.alice);
|
||||||
for(long connection : t.window.setSeen(t.connection)) {
|
for(long connection : t.window.setSeen(t.connection)) {
|
||||||
byte[] tag1 = new byte[TAG_LENGTH];
|
byte[] tag1 = new byte[TAG_LENGTH];
|
||||||
crypto.encodeTag(tag1, key, connection);
|
crypto.encodeTag(tag1, key, connection);
|
||||||
@@ -72,7 +72,7 @@ class TransportConnectionRecogniser {
|
|||||||
long centre = s.getWindowCentre();
|
long centre = s.getWindowCentre();
|
||||||
byte[] bitmap = s.getWindowBitmap();
|
byte[] bitmap = s.getWindowBitmap();
|
||||||
// Create the connection window and the expected tags
|
// Create the connection window and the expected tags
|
||||||
ErasableKey key = crypto.deriveTagKey(secret, !alice);
|
SecretKey key = crypto.deriveTagKey(secret, !alice);
|
||||||
ConnectionWindow window = new ConnectionWindow(centre, bitmap);
|
ConnectionWindow window = new ConnectionWindow(centre, bitmap);
|
||||||
for(long connection : window.getUnseen()) {
|
for(long connection : window.getUnseen()) {
|
||||||
byte[] tag = new byte[TAG_LENGTH];
|
byte[] tag = new byte[TAG_LENGTH];
|
||||||
@@ -98,7 +98,7 @@ class TransportConnectionRecogniser {
|
|||||||
// Locking: this
|
// Locking: this
|
||||||
private void removeSecret(RemovalContext r) {
|
private void removeSecret(RemovalContext r) {
|
||||||
// Remove the expected tags
|
// Remove the expected tags
|
||||||
ErasableKey key = crypto.deriveTagKey(r.secret, !r.alice);
|
SecretKey key = crypto.deriveTagKey(r.secret, !r.alice);
|
||||||
byte[] tag = new byte[TAG_LENGTH];
|
byte[] tag = new byte[TAG_LENGTH];
|
||||||
for(long connection : r.window.getUnseen()) {
|
for(long connection : r.window.getUnseen()) {
|
||||||
crypto.encodeTag(tag, key, connection);
|
crypto.encodeTag(tag, key, connection);
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
<classpathentry combineaccessrules="false" kind="src" path="/briar-core"/>
|
<classpathentry combineaccessrules="false" kind="src" path="/briar-core"/>
|
||||||
<classpathentry kind="lib" path="/briar-core/libs/commons-io-2.0.1.jar"/>
|
<classpathentry kind="lib" path="/briar-core/libs/commons-io-2.0.1.jar"/>
|
||||||
<classpathentry kind="lib" path="/briar-core/libs/jnotify-0.93.jar"/>
|
<classpathentry kind="lib" path="/briar-core/libs/jnotify-0.93.jar"/>
|
||||||
<classpathentry kind="lib" path="/briar-core/libs/scprov-jdk15on-1.47.0.3-SNAPSHOT.jar"/>
|
|
||||||
<classpathentry kind="lib" path="/briar-core/libs/jssc-0.9-briar.jar"/>
|
<classpathentry kind="lib" path="/briar-core/libs/jssc-0.9-briar.jar"/>
|
||||||
<classpathentry kind="output" path="bin"/>
|
<classpathentry kind="output" path="bin"/>
|
||||||
</classpath>
|
</classpath>
|
||||||
|
|||||||
@@ -70,12 +70,11 @@
|
|||||||
<jvmarg value='-Djava.library.path=../briar-core/libs'/>
|
<jvmarg value='-Djava.library.path=../briar-core/libs'/>
|
||||||
<test name='net.sf.briar.LockFairnessTest'/>
|
<test name='net.sf.briar.LockFairnessTest'/>
|
||||||
<test name='net.sf.briar.ProtocolIntegrationTest'/>
|
<test name='net.sf.briar.ProtocolIntegrationTest'/>
|
||||||
<test name='net.sf.briar.crypto.CounterModeTest'/>
|
|
||||||
<test name='net.sf.briar.crypto.ErasableKeyTest'/>
|
|
||||||
<test name='net.sf.briar.crypto.KeyAgreementTest'/>
|
<test name='net.sf.briar.crypto.KeyAgreementTest'/>
|
||||||
<test name='net.sf.briar.crypto.KeyDerivationTest'/>
|
<test name='net.sf.briar.crypto.KeyDerivationTest'/>
|
||||||
<test name='net.sf.briar.crypto.KeyEncodingAndParsingTest'/>
|
<test name='net.sf.briar.crypto.KeyEncodingAndParsingTest'/>
|
||||||
<test name="net.sf.briar.crypto.PasswordBasedKdfTest"/>
|
<test name="net.sf.briar.crypto.PasswordBasedKdfTest"/>
|
||||||
|
<test name='net.sf.briar.crypto.SecretKeyImplTest'/>
|
||||||
<test name='net.sf.briar.db.BasicH2Test'/>
|
<test name='net.sf.briar.db.BasicH2Test'/>
|
||||||
<test name='net.sf.briar.db.DatabaseCleanerImplTest'/>
|
<test name='net.sf.briar.db.DatabaseCleanerImplTest'/>
|
||||||
<test name='net.sf.briar.db.DatabaseComponentImplTest'/>
|
<test name='net.sf.briar.db.DatabaseComponentImplTest'/>
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import java.io.ByteArrayInputStream;
|
|||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.security.KeyPair;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -21,6 +20,7 @@ import net.sf.briar.api.ContactId;
|
|||||||
import net.sf.briar.api.TransportId;
|
import net.sf.briar.api.TransportId;
|
||||||
import net.sf.briar.api.TransportProperties;
|
import net.sf.briar.api.TransportProperties;
|
||||||
import net.sf.briar.api.crypto.CryptoComponent;
|
import net.sf.briar.api.crypto.CryptoComponent;
|
||||||
|
import net.sf.briar.api.crypto.KeyPair;
|
||||||
import net.sf.briar.api.messaging.Ack;
|
import net.sf.briar.api.messaging.Ack;
|
||||||
import net.sf.briar.api.messaging.Group;
|
import net.sf.briar.api.messaging.Group;
|
||||||
import net.sf.briar.api.messaging.GroupFactory;
|
import net.sf.briar.api.messaging.GroupFactory;
|
||||||
|
|||||||
@@ -1,155 +0,0 @@
|
|||||||
package net.sf.briar.crypto;
|
|
||||||
|
|
||||||
import java.security.GeneralSecurityException;
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.security.Security;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import javax.crypto.Cipher;
|
|
||||||
import javax.crypto.spec.IvParameterSpec;
|
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
|
||||||
|
|
||||||
import net.sf.briar.BriarTestCase;
|
|
||||||
import net.sf.briar.api.Bytes;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.spongycastle.jce.provider.BouncyCastleProvider;
|
|
||||||
|
|
||||||
public class CounterModeTest extends BriarTestCase {
|
|
||||||
|
|
||||||
private static final String CIPHER_ALGO = "AES";
|
|
||||||
private static final String CIPHER_MODE = "AES/CTR/NoPadding";
|
|
||||||
private static final String PROVIDER = "SC";
|
|
||||||
private static final int KEY_SIZE_BYTES = 32; // AES-256
|
|
||||||
private static final int BLOCK_SIZE_BYTES = 16;
|
|
||||||
|
|
||||||
private final SecureRandom random;
|
|
||||||
private final byte[] keyBytes;
|
|
||||||
private final SecretKeySpec key;
|
|
||||||
|
|
||||||
public CounterModeTest() {
|
|
||||||
Security.addProvider(new BouncyCastleProvider());
|
|
||||||
random = new SecureRandom();
|
|
||||||
keyBytes = new byte[KEY_SIZE_BYTES];
|
|
||||||
random.nextBytes(keyBytes);
|
|
||||||
key = new SecretKeySpec(keyBytes, CIPHER_ALGO);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testEveryBitOfIvIsSignificant()
|
|
||||||
throws GeneralSecurityException {
|
|
||||||
// Set each bit of the IV in turn, encrypt the same plaintext and check
|
|
||||||
// that all the resulting ciphertexts are distinct
|
|
||||||
byte[] plaintext = new byte[BLOCK_SIZE_BYTES];
|
|
||||||
random.nextBytes(plaintext);
|
|
||||||
Set<Bytes> ciphertexts = new HashSet<Bytes>();
|
|
||||||
for(int i = 0; i < BLOCK_SIZE_BYTES * 8; i++) {
|
|
||||||
// Set the i^th bit of the IV
|
|
||||||
byte[] ivBytes = new byte[BLOCK_SIZE_BYTES];
|
|
||||||
ivBytes[i / 8] |= (byte) (128 >> i % 8);
|
|
||||||
IvParameterSpec iv = new IvParameterSpec(ivBytes);
|
|
||||||
// Encrypt the plaintext
|
|
||||||
Cipher cipher = Cipher.getInstance(CIPHER_MODE, PROVIDER);
|
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
|
|
||||||
byte[] ciphertext =
|
|
||||||
new byte[cipher.getOutputSize(plaintext.length)];
|
|
||||||
cipher.doFinal(plaintext, 0, plaintext.length, ciphertext);
|
|
||||||
ciphertexts.add(new Bytes(ciphertext));
|
|
||||||
}
|
|
||||||
// All the ciphertexts should be distinct using Arrays.equals()
|
|
||||||
assertEquals(BLOCK_SIZE_BYTES * 8, ciphertexts.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRepeatedIvsProduceRepeatedCiphertexts()
|
|
||||||
throws GeneralSecurityException {
|
|
||||||
// This is the inverse of the previous test, to check that the
|
|
||||||
// distinct ciphertexts were due to using distinct IVs
|
|
||||||
byte[] plaintext = new byte[BLOCK_SIZE_BYTES];
|
|
||||||
random.nextBytes(plaintext);
|
|
||||||
byte[] ivBytes = new byte[BLOCK_SIZE_BYTES];
|
|
||||||
random.nextBytes(ivBytes);
|
|
||||||
IvParameterSpec iv = new IvParameterSpec(ivBytes);
|
|
||||||
Set<Bytes> ciphertexts = new HashSet<Bytes>();
|
|
||||||
for(int i = 0; i < BLOCK_SIZE_BYTES * 8; i++) {
|
|
||||||
Cipher cipher = Cipher.getInstance(CIPHER_MODE, PROVIDER);
|
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
|
|
||||||
byte[] ciphertext =
|
|
||||||
new byte[cipher.getOutputSize(plaintext.length)];
|
|
||||||
cipher.doFinal(plaintext, 0, plaintext.length, ciphertext);
|
|
||||||
ciphertexts.add(new Bytes(ciphertext));
|
|
||||||
}
|
|
||||||
assertEquals(1, ciphertexts.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testLeastSignificantBitsUsedAsCounter()
|
|
||||||
throws GeneralSecurityException {
|
|
||||||
// Initialise the least significant 16 bits of the IV to zero and
|
|
||||||
// encrypt ten blocks of zeroes
|
|
||||||
byte[] plaintext = new byte[BLOCK_SIZE_BYTES * 10];
|
|
||||||
byte[] ivBytes = new byte[BLOCK_SIZE_BYTES];
|
|
||||||
random.nextBytes(ivBytes);
|
|
||||||
ivBytes[BLOCK_SIZE_BYTES - 2] = 0;
|
|
||||||
ivBytes[BLOCK_SIZE_BYTES - 1] = 0;
|
|
||||||
IvParameterSpec iv = new IvParameterSpec(ivBytes);
|
|
||||||
Cipher cipher = Cipher.getInstance(CIPHER_MODE, PROVIDER);
|
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
|
|
||||||
byte[] ciphertext = new byte[cipher.getOutputSize(plaintext.length)];
|
|
||||||
cipher.doFinal(plaintext, 0, plaintext.length, ciphertext);
|
|
||||||
// Make sure the IV array hasn't been modified
|
|
||||||
assertEquals(0, ivBytes[BLOCK_SIZE_BYTES - 2]);
|
|
||||||
assertEquals(0, ivBytes[BLOCK_SIZE_BYTES - 1]);
|
|
||||||
// Initialise the least significant 16 bits of the IV to one and
|
|
||||||
// encrypt another ten blocks of zeroes
|
|
||||||
ivBytes[BLOCK_SIZE_BYTES - 1] = 1;
|
|
||||||
iv = new IvParameterSpec(ivBytes);
|
|
||||||
cipher = Cipher.getInstance(CIPHER_MODE, PROVIDER);
|
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
|
|
||||||
byte[] ciphertext1 = new byte[cipher.getOutputSize(plaintext.length)];
|
|
||||||
cipher.doFinal(plaintext, 0, plaintext.length, ciphertext1);
|
|
||||||
// The last nine blocks of the first ciphertext should be identical to
|
|
||||||
// the first nine blocks of the second ciphertext
|
|
||||||
for(int i = 0; i < BLOCK_SIZE_BYTES * 9; i++) {
|
|
||||||
assertEquals(ciphertext[i + BLOCK_SIZE_BYTES], ciphertext1[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCounterUsesMoreThan16Bits()
|
|
||||||
throws GeneralSecurityException {
|
|
||||||
// Initialise the least significant bits of the IV to 2^16-1 and
|
|
||||||
// encrypt ten blocks of zeroes
|
|
||||||
byte[] plaintext = new byte[BLOCK_SIZE_BYTES * 10];
|
|
||||||
byte[] ivBytes = new byte[BLOCK_SIZE_BYTES];
|
|
||||||
random.nextBytes(ivBytes);
|
|
||||||
ivBytes[BLOCK_SIZE_BYTES - 3] = 0;
|
|
||||||
ivBytes[BLOCK_SIZE_BYTES - 2] = (byte) 255;
|
|
||||||
ivBytes[BLOCK_SIZE_BYTES - 1] = (byte) 255;
|
|
||||||
IvParameterSpec iv = new IvParameterSpec(ivBytes);
|
|
||||||
Cipher cipher = Cipher.getInstance(CIPHER_MODE, PROVIDER);
|
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
|
|
||||||
byte[] ciphertext = new byte[cipher.getOutputSize(plaintext.length)];
|
|
||||||
cipher.doFinal(plaintext, 0, plaintext.length, ciphertext);
|
|
||||||
// Make sure the IV array hasn't been modified
|
|
||||||
assertEquals(0, ivBytes[BLOCK_SIZE_BYTES - 3]);
|
|
||||||
assertEquals((byte) 255, ivBytes[BLOCK_SIZE_BYTES - 2]);
|
|
||||||
assertEquals((byte) 255, ivBytes[BLOCK_SIZE_BYTES - 1]);
|
|
||||||
// Initialise the least significant bits of the IV to 2^16 and
|
|
||||||
// encrypt another ten blocks of zeroes
|
|
||||||
ivBytes[BLOCK_SIZE_BYTES - 3] = 1;
|
|
||||||
ivBytes[BLOCK_SIZE_BYTES - 2] = 0;
|
|
||||||
ivBytes[BLOCK_SIZE_BYTES - 1] = 0;
|
|
||||||
iv = new IvParameterSpec(ivBytes);
|
|
||||||
cipher = Cipher.getInstance(CIPHER_MODE, PROVIDER);
|
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
|
|
||||||
byte[] ciphertext1 = new byte[cipher.getOutputSize(plaintext.length)];
|
|
||||||
cipher.doFinal(plaintext, 0, plaintext.length, ciphertext1);
|
|
||||||
// The last nine blocks of the first ciphertext should be identical to
|
|
||||||
// the first nine blocks of the second ciphertext
|
|
||||||
for(int i = 0; i < BLOCK_SIZE_BYTES * 9; i++) {
|
|
||||||
assertEquals(ciphertext[i + BLOCK_SIZE_BYTES], ciphertext1[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
package net.sf.briar.crypto;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
|
||||||
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import javax.crypto.Cipher;
|
|
||||||
import javax.crypto.Mac;
|
|
||||||
import javax.crypto.spec.IvParameterSpec;
|
|
||||||
|
|
||||||
import net.sf.briar.BriarTestCase;
|
|
||||||
import net.sf.briar.api.crypto.ErasableKey;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
public class ErasableKeyTest extends BriarTestCase {
|
|
||||||
|
|
||||||
private static final String CIPHER = "AES";
|
|
||||||
private static final String CIPHER_MODE = "AES/CTR/NoPadding";
|
|
||||||
private static final int IV_BYTES = 16; // 128 bits
|
|
||||||
private static final int KEY_BYTES = 32; // 256 bits
|
|
||||||
private static final String MAC = "HMacSHA384";
|
|
||||||
|
|
||||||
private final Random random = new Random();
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCopiesAreErased() {
|
|
||||||
byte[] master = new byte[KEY_BYTES];
|
|
||||||
random.nextBytes(master);
|
|
||||||
ErasableKey k = new ErasableKeyImpl(master, CIPHER);
|
|
||||||
byte[] copy = k.getEncoded();
|
|
||||||
assertArrayEquals(master, copy);
|
|
||||||
k.erase();
|
|
||||||
byte[] blank = new byte[KEY_BYTES];
|
|
||||||
assertArrayEquals(blank, master);
|
|
||||||
assertArrayEquals(blank, copy);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testErasureDoesNotAffectCipher() throws Exception {
|
|
||||||
byte[] key = new byte[KEY_BYTES];
|
|
||||||
random.nextBytes(key);
|
|
||||||
ErasableKey k = new ErasableKeyImpl(key, CIPHER);
|
|
||||||
Cipher c = Cipher.getInstance(CIPHER_MODE);
|
|
||||||
IvParameterSpec iv = new IvParameterSpec(new byte[IV_BYTES]);
|
|
||||||
c.init(Cipher.ENCRYPT_MODE, k, iv);
|
|
||||||
// Encrypt a blank plaintext
|
|
||||||
byte[] plaintext = new byte[123];
|
|
||||||
byte[] ciphertext = c.doFinal(plaintext);
|
|
||||||
// Erase the key and encrypt again - erase() was called after doFinal()
|
|
||||||
k.erase();
|
|
||||||
byte[] ciphertext1 = c.doFinal(plaintext);
|
|
||||||
// Encrypt again - this time erase() was called before doFinal()
|
|
||||||
byte[] ciphertext2 = c.doFinal(plaintext);
|
|
||||||
// The ciphertexts should match
|
|
||||||
assertArrayEquals(ciphertext, ciphertext1);
|
|
||||||
assertArrayEquals(ciphertext, ciphertext2);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testErasureDoesNotAffectMac() throws Exception {
|
|
||||||
byte[] key = new byte[KEY_BYTES];
|
|
||||||
random.nextBytes(key);
|
|
||||||
ErasableKey k = new ErasableKeyImpl(key, CIPHER);
|
|
||||||
Mac m = Mac.getInstance(MAC);
|
|
||||||
m.init(k);
|
|
||||||
// Authenticate a blank plaintext
|
|
||||||
byte[] plaintext = new byte[123];
|
|
||||||
byte[] mac = m.doFinal(plaintext);
|
|
||||||
// Erase the key and authenticate again
|
|
||||||
k.erase();
|
|
||||||
byte[] mac1 = m.doFinal(plaintext);
|
|
||||||
// Authenticate again
|
|
||||||
byte[] mac2 = m.doFinal(plaintext);
|
|
||||||
// The MACs should match
|
|
||||||
assertArrayEquals(mac, mac1);
|
|
||||||
assertArrayEquals(mac, mac2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,10 +2,9 @@ package net.sf.briar.crypto;
|
|||||||
|
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
|
||||||
import java.security.KeyPair;
|
|
||||||
|
|
||||||
import net.sf.briar.BriarTestCase;
|
import net.sf.briar.BriarTestCase;
|
||||||
import net.sf.briar.api.crypto.CryptoComponent;
|
import net.sf.briar.api.crypto.CryptoComponent;
|
||||||
|
import net.sf.briar.api.crypto.KeyPair;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import java.util.Random;
|
|||||||
|
|
||||||
import net.sf.briar.BriarTestCase;
|
import net.sf.briar.BriarTestCase;
|
||||||
import net.sf.briar.api.crypto.CryptoComponent;
|
import net.sf.briar.api.crypto.CryptoComponent;
|
||||||
import net.sf.briar.api.crypto.ErasableKey;
|
import net.sf.briar.api.crypto.SecretKey;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ public class KeyDerivationTest extends BriarTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testKeysAreDistinct() {
|
public void testKeysAreDistinct() {
|
||||||
List<ErasableKey> keys = new ArrayList<ErasableKey>();
|
List<SecretKey> keys = new ArrayList<SecretKey>();
|
||||||
keys.add(crypto.deriveFrameKey(secret, 0, false, false));
|
keys.add(crypto.deriveFrameKey(secret, 0, false, false));
|
||||||
keys.add(crypto.deriveFrameKey(secret, 0, false, true));
|
keys.add(crypto.deriveFrameKey(secret, 0, false, true));
|
||||||
keys.add(crypto.deriveFrameKey(secret, 0, true, false));
|
keys.add(crypto.deriveFrameKey(secret, 0, true, false));
|
||||||
|
|||||||
@@ -2,12 +2,11 @@ package net.sf.briar.crypto;
|
|||||||
|
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
|
||||||
import java.security.KeyPair;
|
|
||||||
import java.security.PrivateKey;
|
|
||||||
import java.security.PublicKey;
|
|
||||||
|
|
||||||
import net.sf.briar.BriarTestCase;
|
import net.sf.briar.BriarTestCase;
|
||||||
|
import net.sf.briar.api.crypto.KeyPair;
|
||||||
import net.sf.briar.api.crypto.KeyParser;
|
import net.sf.briar.api.crypto.KeyParser;
|
||||||
|
import net.sf.briar.api.crypto.PrivateKey;
|
||||||
|
import net.sf.briar.api.crypto.PublicKey;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
|||||||
28
briar-tests/src/net/sf/briar/crypto/SecretKeyImplTest.java
Normal file
28
briar-tests/src/net/sf/briar/crypto/SecretKeyImplTest.java
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package net.sf.briar.crypto;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import net.sf.briar.BriarTestCase;
|
||||||
|
import net.sf.briar.api.crypto.SecretKey;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class SecretKeyImplTest extends BriarTestCase {
|
||||||
|
|
||||||
|
private static final int KEY_BYTES = 32; // 256 bits
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCopiesAreErased() {
|
||||||
|
byte[] master = new byte[KEY_BYTES];
|
||||||
|
new Random().nextBytes(master);
|
||||||
|
SecretKey k = new SecretKeyImpl(master);
|
||||||
|
byte[] copy = k.getEncoded();
|
||||||
|
assertArrayEquals(master, copy);
|
||||||
|
k.erase();
|
||||||
|
byte[] blank = new byte[KEY_BYTES];
|
||||||
|
assertArrayEquals(blank, master);
|
||||||
|
assertArrayEquals(blank, copy);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,9 +12,6 @@ import static net.sf.briar.api.messaging.MessagingConstants.MAX_PACKET_LENGTH;
|
|||||||
import static net.sf.briar.api.messaging.MessagingConstants.MAX_SUBSCRIPTIONS;
|
import static net.sf.briar.api.messaging.MessagingConstants.MAX_SUBSCRIPTIONS;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.security.KeyPair;
|
|
||||||
import java.security.PrivateKey;
|
|
||||||
import java.security.Signature;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
@@ -29,6 +26,9 @@ import net.sf.briar.api.TransportId;
|
|||||||
import net.sf.briar.api.TransportProperties;
|
import net.sf.briar.api.TransportProperties;
|
||||||
import net.sf.briar.api.UniqueId;
|
import net.sf.briar.api.UniqueId;
|
||||||
import net.sf.briar.api.crypto.CryptoComponent;
|
import net.sf.briar.api.crypto.CryptoComponent;
|
||||||
|
import net.sf.briar.api.crypto.KeyPair;
|
||||||
|
import net.sf.briar.api.crypto.PrivateKey;
|
||||||
|
import net.sf.briar.api.crypto.Signature;
|
||||||
import net.sf.briar.api.messaging.Ack;
|
import net.sf.briar.api.messaging.Ack;
|
||||||
import net.sf.briar.api.messaging.Group;
|
import net.sf.briar.api.messaging.Group;
|
||||||
import net.sf.briar.api.messaging.GroupFactory;
|
import net.sf.briar.api.messaging.GroupFactory;
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ public class ConsumersTest extends BriarTestCase {
|
|||||||
private final java.security.MessageDigest delegate;
|
private final java.security.MessageDigest delegate;
|
||||||
|
|
||||||
private TestMessageDigest() throws GeneralSecurityException {
|
private TestMessageDigest() throws GeneralSecurityException {
|
||||||
delegate = java.security.MessageDigest.getInstance("SHA-256");
|
delegate = java.security.MessageDigest.getInstance("SHA-384");
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] digest() {
|
public byte[] digest() {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import net.sf.briar.TestLifecycleModule;
|
|||||||
import net.sf.briar.api.FormatException;
|
import net.sf.briar.api.FormatException;
|
||||||
import net.sf.briar.api.crypto.AuthenticatedCipher;
|
import net.sf.briar.api.crypto.AuthenticatedCipher;
|
||||||
import net.sf.briar.api.crypto.CryptoComponent;
|
import net.sf.briar.api.crypto.CryptoComponent;
|
||||||
import net.sf.briar.api.crypto.ErasableKey;
|
import net.sf.briar.api.crypto.SecretKey;
|
||||||
import net.sf.briar.crypto.CryptoModule;
|
import net.sf.briar.crypto.CryptoModule;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -31,7 +31,7 @@ public class IncomingEncryptionLayerTest extends BriarTestCase {
|
|||||||
|
|
||||||
private final CryptoComponent crypto;
|
private final CryptoComponent crypto;
|
||||||
private final AuthenticatedCipher frameCipher;
|
private final AuthenticatedCipher frameCipher;
|
||||||
private final ErasableKey frameKey;
|
private final SecretKey frameKey;
|
||||||
|
|
||||||
public IncomingEncryptionLayerTest() {
|
public IncomingEncryptionLayerTest() {
|
||||||
Injector i = Guice.createInjector(new CryptoModule(),
|
Injector i = Guice.createInjector(new CryptoModule(),
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import net.sf.briar.api.TransportId;
|
|||||||
import net.sf.briar.api.clock.Clock;
|
import net.sf.briar.api.clock.Clock;
|
||||||
import net.sf.briar.api.clock.Timer;
|
import net.sf.briar.api.clock.Timer;
|
||||||
import net.sf.briar.api.crypto.CryptoComponent;
|
import net.sf.briar.api.crypto.CryptoComponent;
|
||||||
import net.sf.briar.api.crypto.ErasableKey;
|
import net.sf.briar.api.crypto.SecretKey;
|
||||||
import net.sf.briar.api.db.DatabaseComponent;
|
import net.sf.briar.api.db.DatabaseComponent;
|
||||||
import net.sf.briar.api.db.event.DatabaseListener;
|
import net.sf.briar.api.db.event.DatabaseListener;
|
||||||
import net.sf.briar.api.transport.ConnectionContext;
|
import net.sf.briar.api.transport.ConnectionContext;
|
||||||
@@ -112,9 +112,9 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
|
|||||||
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
final Clock clock = context.mock(Clock.class);
|
final Clock clock = context.mock(Clock.class);
|
||||||
final Timer timer = context.mock(Timer.class);
|
final Timer timer = context.mock(Timer.class);
|
||||||
final ErasableKey k0 = context.mock(ErasableKey.class, "k0");
|
final SecretKey k0 = context.mock(SecretKey.class, "k0");
|
||||||
final ErasableKey k1 = context.mock(ErasableKey.class, "k1");
|
final SecretKey k1 = context.mock(SecretKey.class, "k1");
|
||||||
final ErasableKey k2 = context.mock(ErasableKey.class, "k2");
|
final SecretKey k2 = context.mock(SecretKey.class, "k2");
|
||||||
|
|
||||||
final ConnectionRecogniser connectionRecogniser =
|
final ConnectionRecogniser connectionRecogniser =
|
||||||
new ConnectionRecogniserImpl(crypto, db);
|
new ConnectionRecogniserImpl(crypto, db);
|
||||||
@@ -235,9 +235,9 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
|
|||||||
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
final Clock clock = context.mock(Clock.class);
|
final Clock clock = context.mock(Clock.class);
|
||||||
final Timer timer = context.mock(Timer.class);
|
final Timer timer = context.mock(Timer.class);
|
||||||
final ErasableKey k0 = context.mock(ErasableKey.class, "k0");
|
final SecretKey k0 = context.mock(SecretKey.class, "k0");
|
||||||
final ErasableKey k1 = context.mock(ErasableKey.class, "k1");
|
final SecretKey k1 = context.mock(SecretKey.class, "k1");
|
||||||
final ErasableKey k2 = context.mock(ErasableKey.class, "k2");
|
final SecretKey k2 = context.mock(SecretKey.class, "k2");
|
||||||
|
|
||||||
final ConnectionRecogniser connectionRecogniser =
|
final ConnectionRecogniser connectionRecogniser =
|
||||||
new ConnectionRecogniserImpl(crypto, db);
|
new ConnectionRecogniserImpl(crypto, db);
|
||||||
@@ -369,9 +369,9 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
|
|||||||
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
final Clock clock = context.mock(Clock.class);
|
final Clock clock = context.mock(Clock.class);
|
||||||
final Timer timer = context.mock(Timer.class);
|
final Timer timer = context.mock(Timer.class);
|
||||||
final ErasableKey k0 = context.mock(ErasableKey.class, "k0");
|
final SecretKey k0 = context.mock(SecretKey.class, "k0");
|
||||||
final ErasableKey k1 = context.mock(ErasableKey.class, "k1");
|
final SecretKey k1 = context.mock(SecretKey.class, "k1");
|
||||||
final ErasableKey k2 = context.mock(ErasableKey.class, "k2");
|
final SecretKey k2 = context.mock(SecretKey.class, "k2");
|
||||||
|
|
||||||
final ConnectionRecogniser connectionRecogniser =
|
final ConnectionRecogniser connectionRecogniser =
|
||||||
new ConnectionRecogniserImpl(crypto, db);
|
new ConnectionRecogniserImpl(crypto, db);
|
||||||
@@ -514,9 +514,9 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
|
|||||||
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
final Clock clock = context.mock(Clock.class);
|
final Clock clock = context.mock(Clock.class);
|
||||||
final Timer timer = context.mock(Timer.class);
|
final Timer timer = context.mock(Timer.class);
|
||||||
final ErasableKey k0 = context.mock(ErasableKey.class, "k0");
|
final SecretKey k0 = context.mock(SecretKey.class, "k0");
|
||||||
final ErasableKey k1 = context.mock(ErasableKey.class, "k1");
|
final SecretKey k1 = context.mock(SecretKey.class, "k1");
|
||||||
final ErasableKey k2 = context.mock(ErasableKey.class, "k2");
|
final SecretKey k2 = context.mock(SecretKey.class, "k2");
|
||||||
|
|
||||||
final ConnectionRecogniser connectionRecogniser =
|
final ConnectionRecogniser connectionRecogniser =
|
||||||
new ConnectionRecogniserImpl(crypto, db);
|
new ConnectionRecogniserImpl(crypto, db);
|
||||||
@@ -628,9 +628,9 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
|
|||||||
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
final Clock clock = context.mock(Clock.class);
|
final Clock clock = context.mock(Clock.class);
|
||||||
final Timer timer = context.mock(Timer.class);
|
final Timer timer = context.mock(Timer.class);
|
||||||
final ErasableKey k1 = context.mock(ErasableKey.class, "k1");
|
final SecretKey k1 = context.mock(SecretKey.class, "k1");
|
||||||
final ErasableKey k2 = context.mock(ErasableKey.class, "k2");
|
final SecretKey k2 = context.mock(SecretKey.class, "k2");
|
||||||
final ErasableKey k3 = context.mock(ErasableKey.class, "k3");
|
final SecretKey k3 = context.mock(SecretKey.class, "k3");
|
||||||
|
|
||||||
final ConnectionRecogniser connectionRecogniser =
|
final ConnectionRecogniser connectionRecogniser =
|
||||||
new ConnectionRecogniserImpl(crypto, db);
|
new ConnectionRecogniserImpl(crypto, db);
|
||||||
@@ -752,9 +752,9 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
|
|||||||
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
final Clock clock = context.mock(Clock.class);
|
final Clock clock = context.mock(Clock.class);
|
||||||
final Timer timer = context.mock(Timer.class);
|
final Timer timer = context.mock(Timer.class);
|
||||||
final ErasableKey k2 = context.mock(ErasableKey.class, "k2");
|
final SecretKey k2 = context.mock(SecretKey.class, "k2");
|
||||||
final ErasableKey k3 = context.mock(ErasableKey.class, "k3");
|
final SecretKey k3 = context.mock(SecretKey.class, "k3");
|
||||||
final ErasableKey k4 = context.mock(ErasableKey.class, "k4");
|
final SecretKey k4 = context.mock(SecretKey.class, "k4");
|
||||||
|
|
||||||
final ConnectionRecogniser connectionRecogniser =
|
final ConnectionRecogniser connectionRecogniser =
|
||||||
new ConnectionRecogniserImpl(crypto, db);
|
new ConnectionRecogniserImpl(crypto, db);
|
||||||
@@ -885,7 +885,7 @@ public class KeyRotationIntegrationTest extends BriarTestCase {
|
|||||||
|
|
||||||
public Object invoke(Invocation invocation) throws Throwable {
|
public Object invoke(Invocation invocation) throws Throwable {
|
||||||
byte[] tag = (byte[]) invocation.getParameter(0);
|
byte[] tag = (byte[]) invocation.getParameter(0);
|
||||||
ErasableKey key = (ErasableKey) invocation.getParameter(1);
|
SecretKey key = (SecretKey) invocation.getParameter(1);
|
||||||
long connection = (Long) invocation.getParameter(2);
|
long connection = (Long) invocation.getParameter(2);
|
||||||
encodeTag(tag, key.getEncoded(), connection);
|
encodeTag(tag, key.getEncoded(), connection);
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import net.sf.briar.BriarTestCase;
|
|||||||
import net.sf.briar.TestLifecycleModule;
|
import net.sf.briar.TestLifecycleModule;
|
||||||
import net.sf.briar.api.crypto.AuthenticatedCipher;
|
import net.sf.briar.api.crypto.AuthenticatedCipher;
|
||||||
import net.sf.briar.api.crypto.CryptoComponent;
|
import net.sf.briar.api.crypto.CryptoComponent;
|
||||||
import net.sf.briar.api.crypto.ErasableKey;
|
import net.sf.briar.api.crypto.SecretKey;
|
||||||
import net.sf.briar.crypto.CryptoModule;
|
import net.sf.briar.crypto.CryptoModule;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -47,7 +47,7 @@ public class OutgoingEncryptionLayerTest extends BriarTestCase {
|
|||||||
byte[] iv = new byte[IV_LENGTH], aad = new byte[AAD_LENGTH];
|
byte[] iv = new byte[IV_LENGTH], aad = new byte[AAD_LENGTH];
|
||||||
byte[] plaintext = new byte[FRAME_LENGTH - MAC_LENGTH];
|
byte[] plaintext = new byte[FRAME_LENGTH - MAC_LENGTH];
|
||||||
byte[] ciphertext = new byte[FRAME_LENGTH];
|
byte[] ciphertext = new byte[FRAME_LENGTH];
|
||||||
ErasableKey frameKey = crypto.generateSecretKey();
|
SecretKey frameKey = crypto.generateSecretKey();
|
||||||
// Calculate the expected ciphertext
|
// Calculate the expected ciphertext
|
||||||
FrameEncoder.encodeIv(iv, 0);
|
FrameEncoder.encodeIv(iv, 0);
|
||||||
FrameEncoder.encodeAad(aad, 0, plaintext.length);
|
FrameEncoder.encodeAad(aad, 0, plaintext.length);
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import net.sf.briar.TestUtils;
|
|||||||
import net.sf.briar.api.ContactId;
|
import net.sf.briar.api.ContactId;
|
||||||
import net.sf.briar.api.TransportId;
|
import net.sf.briar.api.TransportId;
|
||||||
import net.sf.briar.api.crypto.CryptoComponent;
|
import net.sf.briar.api.crypto.CryptoComponent;
|
||||||
import net.sf.briar.api.crypto.ErasableKey;
|
import net.sf.briar.api.crypto.SecretKey;
|
||||||
import net.sf.briar.api.db.DatabaseComponent;
|
import net.sf.briar.api.db.DatabaseComponent;
|
||||||
import net.sf.briar.api.transport.ConnectionContext;
|
import net.sf.briar.api.transport.ConnectionContext;
|
||||||
import net.sf.briar.api.transport.TemporarySecret;
|
import net.sf.briar.api.transport.TemporarySecret;
|
||||||
@@ -36,7 +36,7 @@ public class TransportConnectionRecogniserTest extends BriarTestCase {
|
|||||||
final byte[] secret = new byte[32];
|
final byte[] secret = new byte[32];
|
||||||
new Random().nextBytes(secret);
|
new Random().nextBytes(secret);
|
||||||
final boolean alice = false;
|
final boolean alice = false;
|
||||||
final ErasableKey tagKey = context.mock(ErasableKey.class);
|
final SecretKey tagKey = context.mock(SecretKey.class);
|
||||||
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// Add secret
|
// Add secret
|
||||||
@@ -74,7 +74,7 @@ public class TransportConnectionRecogniserTest extends BriarTestCase {
|
|||||||
final byte[] secret = new byte[32];
|
final byte[] secret = new byte[32];
|
||||||
new Random().nextBytes(secret);
|
new Random().nextBytes(secret);
|
||||||
final boolean alice = false;
|
final boolean alice = false;
|
||||||
final ErasableKey tagKey = context.mock(ErasableKey.class);
|
final SecretKey tagKey = context.mock(SecretKey.class);
|
||||||
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// Add secret
|
// Add secret
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import net.sf.briar.api.ContactId;
|
|||||||
import net.sf.briar.api.TransportId;
|
import net.sf.briar.api.TransportId;
|
||||||
import net.sf.briar.api.crypto.AuthenticatedCipher;
|
import net.sf.briar.api.crypto.AuthenticatedCipher;
|
||||||
import net.sf.briar.api.crypto.CryptoComponent;
|
import net.sf.briar.api.crypto.CryptoComponent;
|
||||||
import net.sf.briar.api.crypto.ErasableKey;
|
import net.sf.briar.api.crypto.SecretKey;
|
||||||
import net.sf.briar.api.transport.ConnectionContext;
|
import net.sf.briar.api.transport.ConnectionContext;
|
||||||
import net.sf.briar.api.transport.ConnectionWriter;
|
import net.sf.briar.api.transport.ConnectionWriter;
|
||||||
import net.sf.briar.api.transport.ConnectionWriterFactory;
|
import net.sf.briar.api.transport.ConnectionWriterFactory;
|
||||||
@@ -42,7 +42,7 @@ public class TransportIntegrationTest extends BriarTestCase {
|
|||||||
private final AuthenticatedCipher frameCipher;
|
private final AuthenticatedCipher frameCipher;
|
||||||
private final Random random;
|
private final Random random;
|
||||||
private final byte[] secret;
|
private final byte[] secret;
|
||||||
private final ErasableKey frameKey;
|
private final SecretKey frameKey;
|
||||||
|
|
||||||
public TransportIntegrationTest() {
|
public TransportIntegrationTest() {
|
||||||
Module testModule = new AbstractModule() {
|
Module testModule = new AbstractModule() {
|
||||||
@@ -82,7 +82,7 @@ public class TransportIntegrationTest extends BriarTestCase {
|
|||||||
byte[] frame1 = new byte[321];
|
byte[] frame1 = new byte[321];
|
||||||
random.nextBytes(frame1);
|
random.nextBytes(frame1);
|
||||||
// Copy the frame key - the copy will be erased
|
// Copy the frame key - the copy will be erased
|
||||||
ErasableKey frameCopy = frameKey.copy();
|
SecretKey frameCopy = frameKey.copy();
|
||||||
// Write the frames
|
// Write the frames
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
FrameWriter encryptionOut = new OutgoingEncryptionLayer(out,
|
FrameWriter encryptionOut = new OutgoingEncryptionLayer(out,
|
||||||
|
|||||||
Reference in New Issue
Block a user