mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +01:00
Separated key agreement algorithm from signature algorithm.
This commit is contained in:
@@ -23,9 +23,11 @@ public interface CryptoComponent {
|
||||
|
||||
byte[] deriveNextSecret(byte[] secret, int index, long connection);
|
||||
|
||||
KeyPair generateKeyPair();
|
||||
KeyPair generateAgreementKeyPair();
|
||||
|
||||
KeyParser getKeyParser();
|
||||
KeyPair generateSignatureKeyPair();
|
||||
|
||||
KeyParser getSignatureKeyParser();
|
||||
|
||||
ErasableKey generateTestKey();
|
||||
|
||||
|
||||
@@ -30,14 +30,16 @@ import com.google.inject.Inject;
|
||||
class CryptoComponentImpl implements CryptoComponent {
|
||||
|
||||
private static final String PROVIDER = "BC";
|
||||
private static final String KEY_PAIR_ALGO = "ECDSA";
|
||||
private static final int KEY_PAIR_BITS = 384;
|
||||
private static final String KEY_AGREEMENT_ALGO = "ECDHC";
|
||||
private static final String AGREEMENT_KEY_PAIR_ALGO = "ECDH";
|
||||
private static final int AGREEMENT_KEY_PAIR_BITS = 384;
|
||||
private static final String AGREEMENT_ALGO = "ECDHC";
|
||||
private static final String SECRET_KEY_ALGO = "AES";
|
||||
private static final int SECRET_KEY_BYTES = 32; // 256 bits
|
||||
private static final int KEY_DERIVATION_IV_BYTES = 16; // 128 bits
|
||||
private static final String KEY_DERIVATION_ALGO = "AES/CTR/NoPadding";
|
||||
private static final String DIGEST_ALGO = "SHA-384";
|
||||
private static final String SIGNATURE_KEY_PAIR_ALGO = "ECDSA";
|
||||
private static final int SIGNATURE_KEY_PAIR_BITS = 384;
|
||||
private static final String SIGNATURE_ALGO = "ECDSA";
|
||||
private static final String TAG_CIPHER_ALGO = "AES/ECB/NoPadding";
|
||||
private static final String FRAME_CIPHER_ALGO = "AES/CTR/NoPadding";
|
||||
@@ -59,18 +61,25 @@ class CryptoComponentImpl implements CryptoComponent {
|
||||
private static final byte[] KEY_DERIVATION_INPUT =
|
||||
new byte[SECRET_KEY_BYTES];
|
||||
|
||||
private final KeyParser keyParser;
|
||||
private final KeyPairGenerator keyPairGenerator;
|
||||
private final KeyParser agreementKeyParser, signatureKeyParser;
|
||||
private final KeyPairGenerator agreementKeyPairGenerator;
|
||||
private final KeyPairGenerator signatureKeyPairGenerator;
|
||||
private final SecureRandom secureRandom;
|
||||
|
||||
@Inject
|
||||
CryptoComponentImpl() {
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
try {
|
||||
keyParser = new KeyParserImpl(KEY_PAIR_ALGO, PROVIDER);
|
||||
keyPairGenerator = KeyPairGenerator.getInstance(KEY_PAIR_ALGO,
|
||||
agreementKeyParser = new KeyParserImpl(AGREEMENT_KEY_PAIR_ALGO,
|
||||
PROVIDER);
|
||||
keyPairGenerator.initialize(KEY_PAIR_BITS);
|
||||
signatureKeyParser = new KeyParserImpl(SIGNATURE_KEY_PAIR_ALGO,
|
||||
PROVIDER);
|
||||
agreementKeyPairGenerator = KeyPairGenerator.getInstance(
|
||||
AGREEMENT_KEY_PAIR_ALGO, PROVIDER);
|
||||
agreementKeyPairGenerator.initialize(AGREEMENT_KEY_PAIR_BITS);
|
||||
signatureKeyPairGenerator = KeyPairGenerator.getInstance(
|
||||
SIGNATURE_KEY_PAIR_ALGO, PROVIDER);
|
||||
signatureKeyPairGenerator.initialize(SIGNATURE_KEY_PAIR_BITS);
|
||||
} catch(GeneralSecurityException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@@ -130,7 +139,8 @@ class CryptoComponentImpl implements CryptoComponent {
|
||||
byte[] theirPublicKey, PrivateKey ourPrivateKey, int invitationCode,
|
||||
boolean initiator) {
|
||||
try {
|
||||
PublicKey theirPublic = keyParser.parsePublicKey(theirPublicKey);
|
||||
PublicKey theirPublic = agreementKeyParser.parsePublicKey(
|
||||
theirPublicKey);
|
||||
MessageDigest messageDigest = getMessageDigest();
|
||||
byte[] ourHash = messageDigest.digest(ourPublicKey);
|
||||
byte[] theirHash = messageDigest.digest(theirPublicKey);
|
||||
@@ -147,8 +157,8 @@ class CryptoComponentImpl implements CryptoComponent {
|
||||
byte[] publicInfo = new byte[4];
|
||||
ByteUtils.writeUint32(invitationCode, publicInfo, 0);
|
||||
// The raw secret comes from the key agreement algorithm
|
||||
KeyAgreement keyAgreement = KeyAgreement.getInstance(
|
||||
KEY_AGREEMENT_ALGO, PROVIDER);
|
||||
KeyAgreement keyAgreement = KeyAgreement.getInstance(AGREEMENT_ALGO,
|
||||
PROVIDER);
|
||||
keyAgreement.init(ourPrivateKey);
|
||||
keyAgreement.doPhase(theirPublic, true);
|
||||
byte[] rawSecret = keyAgreement.generateSecret();
|
||||
@@ -220,12 +230,16 @@ class CryptoComponentImpl implements CryptoComponent {
|
||||
return code;
|
||||
}
|
||||
|
||||
public KeyPair generateKeyPair() {
|
||||
return keyPairGenerator.generateKeyPair();
|
||||
public KeyPair generateAgreementKeyPair() {
|
||||
return agreementKeyPairGenerator.generateKeyPair();
|
||||
}
|
||||
|
||||
public KeyParser getKeyParser() {
|
||||
return keyParser;
|
||||
public KeyPair generateSignatureKeyPair() {
|
||||
return signatureKeyPairGenerator.generateKeyPair();
|
||||
}
|
||||
|
||||
public KeyParser getSignatureKeyParser() {
|
||||
return signatureKeyParser;
|
||||
}
|
||||
|
||||
public ErasableKey generateTestKey() {
|
||||
|
||||
@@ -106,7 +106,7 @@ class InvitationStarterImpl implements InvitationStarter {
|
||||
return;
|
||||
}
|
||||
// Use an ephemeral key pair for key agreement
|
||||
KeyPair ourKeyPair = crypto.generateKeyPair();
|
||||
KeyPair ourKeyPair = crypto.generateAgreementKeyPair();
|
||||
MessageDigest messageDigest = crypto.getMessageDigest();
|
||||
byte[] ourKey = ourKeyPair.getPublic().getEncoded();
|
||||
byte[] ourHash = messageDigest.digest(ourKey);
|
||||
|
||||
@@ -57,7 +57,7 @@ class UnverifiedBatchImpl implements UnverifiedBatch {
|
||||
// Verify the author's signature, if there is one
|
||||
Author author = m.getAuthor();
|
||||
if(author != null) {
|
||||
if(keyParser == null) keyParser = crypto.getKeyParser();
|
||||
if(keyParser == null) keyParser = crypto.getSignatureKeyParser();
|
||||
PublicKey k = keyParser.parsePublicKey(author.getPublicKey());
|
||||
if(signature == null) signature = crypto.getSignature();
|
||||
signature.initVerify(k);
|
||||
@@ -68,7 +68,7 @@ class UnverifiedBatchImpl implements UnverifiedBatch {
|
||||
// Verify the group's signature, if there is one
|
||||
Group group = m.getGroup();
|
||||
if(group != null && group.getPublicKey() != null) {
|
||||
if(keyParser == null) keyParser = crypto.getKeyParser();
|
||||
if(keyParser == null) keyParser = crypto.getSignatureKeyParser();
|
||||
PublicKey k = keyParser.parsePublicKey(group.getPublicKey());
|
||||
if(signature == null) signature = crypto.getSignature();
|
||||
signature.initVerify(k);
|
||||
|
||||
@@ -100,12 +100,12 @@ public class ProtocolIntegrationTest extends BriarTestCase {
|
||||
// Create two groups: one restricted, one unrestricted
|
||||
GroupFactory groupFactory = i.getInstance(GroupFactory.class);
|
||||
group = groupFactory.createGroup("Unrestricted group", null);
|
||||
KeyPair groupKeyPair = crypto.generateKeyPair();
|
||||
KeyPair groupKeyPair = crypto.generateSignatureKeyPair();
|
||||
group1 = groupFactory.createGroup("Restricted group",
|
||||
groupKeyPair.getPublic().getEncoded());
|
||||
// Create an author
|
||||
AuthorFactory authorFactory = i.getInstance(AuthorFactory.class);
|
||||
KeyPair authorKeyPair = crypto.generateKeyPair();
|
||||
KeyPair authorKeyPair = crypto.generateSignatureKeyPair();
|
||||
author = authorFactory.createAuthor(authorName,
|
||||
authorKeyPair.getPublic().getEncoded());
|
||||
// Create two messages to each group: one anonymous, one pseudonymous
|
||||
|
||||
44
test/net/sf/briar/plugins/InvitationStarterImplTest.java
Normal file
44
test/net/sf/briar/plugins/InvitationStarterImplTest.java
Normal file
@@ -0,0 +1,44 @@
|
||||
package net.sf.briar.plugins;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
|
||||
import java.security.KeyPair;
|
||||
import java.security.PrivateKey;
|
||||
|
||||
import net.sf.briar.BriarTestCase;
|
||||
import net.sf.briar.api.crypto.CryptoComponent;
|
||||
import net.sf.briar.crypto.CryptoModule;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
|
||||
public class InvitationStarterImplTest extends BriarTestCase {
|
||||
|
||||
private final CryptoComponent crypto;
|
||||
|
||||
public InvitationStarterImplTest() {
|
||||
super();
|
||||
Injector i = Guice.createInjector(new CryptoModule());
|
||||
crypto = i.getInstance(CryptoComponent.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testKeyAgreement() {
|
||||
KeyPair a = crypto.generateAgreementKeyPair();
|
||||
byte[] aPub = a.getPublic().getEncoded();
|
||||
PrivateKey aPriv = a.getPrivate();
|
||||
KeyPair b = crypto.generateAgreementKeyPair();
|
||||
byte[] bPub = b.getPublic().getEncoded();
|
||||
PrivateKey bPriv = b.getPrivate();
|
||||
byte[][] aSecrets = crypto.deriveInitialSecrets(aPub, bPub, aPriv, 123,
|
||||
true);
|
||||
byte[][] bSecrets = crypto.deriveInitialSecrets(bPub, aPub, bPriv, 123,
|
||||
false);
|
||||
assertEquals(2, aSecrets.length);
|
||||
assertEquals(2, bSecrets.length);
|
||||
assertArrayEquals(aSecrets[0], bSecrets[0]);
|
||||
assertArrayEquals(aSecrets[1], bSecrets[1]);
|
||||
}
|
||||
}
|
||||
@@ -108,8 +108,8 @@ public class ConstantsTest extends BriarTestCase {
|
||||
byte[] authorPublic = new byte[MAX_PUBLIC_KEY_LENGTH];
|
||||
Author author = authorFactory.createAuthor(authorName, authorPublic);
|
||||
// Create a maximum-length message
|
||||
PrivateKey groupPrivate = crypto.generateKeyPair().getPrivate();
|
||||
PrivateKey authorPrivate = crypto.generateKeyPair().getPrivate();
|
||||
PrivateKey groupPrivate = crypto.generateSignatureKeyPair().getPrivate();
|
||||
PrivateKey authorPrivate = crypto.generateSignatureKeyPair().getPrivate();
|
||||
String subject = createRandomString(MAX_SUBJECT_LENGTH);
|
||||
byte[] body = new byte[MAX_BODY_LENGTH];
|
||||
Message message = messageFactory.createMessage(null, group,
|
||||
|
||||
@@ -122,8 +122,8 @@ public class UnverifiedBatchImplTest extends BriarTestCase {
|
||||
@Test
|
||||
public void testSignatures() throws Exception {
|
||||
final int signedByAuthor = 100, signedByGroup = 110;
|
||||
final KeyPair authorKeyPair = crypto.generateKeyPair();
|
||||
final KeyPair groupKeyPair = crypto.generateKeyPair();
|
||||
final KeyPair authorKeyPair = crypto.generateSignatureKeyPair();
|
||||
final KeyPair groupKeyPair = crypto.generateSignatureKeyPair();
|
||||
Signature signature = crypto.getSignature();
|
||||
// Calculate the expected author and group signatures
|
||||
signature.initSign(authorKeyPair.getPrivate());
|
||||
@@ -202,7 +202,7 @@ public class UnverifiedBatchImplTest extends BriarTestCase {
|
||||
@Test
|
||||
public void testExceptionThrownIfMessageIsModified() throws Exception {
|
||||
final int signedByAuthor = 100;
|
||||
final KeyPair authorKeyPair = crypto.generateKeyPair();
|
||||
final KeyPair authorKeyPair = crypto.generateSignatureKeyPair();
|
||||
Signature signature = crypto.getSignature();
|
||||
// Calculate the expected author signature
|
||||
signature.initSign(authorKeyPair.getPrivate());
|
||||
|
||||
Reference in New Issue
Block a user