Separated key agreement algorithm from signature algorithm.

This commit is contained in:
akwizgran
2012-04-28 18:02:28 +01:00
parent b01b17f2b1
commit 5814826573
8 changed files with 87 additions and 27 deletions

View File

@@ -23,9 +23,11 @@ public interface CryptoComponent {
byte[] deriveNextSecret(byte[] secret, int index, long connection); byte[] deriveNextSecret(byte[] secret, int index, long connection);
KeyPair generateKeyPair(); KeyPair generateAgreementKeyPair();
KeyParser getKeyParser(); KeyPair generateSignatureKeyPair();
KeyParser getSignatureKeyParser();
ErasableKey generateTestKey(); ErasableKey generateTestKey();

View File

@@ -30,14 +30,16 @@ import com.google.inject.Inject;
class CryptoComponentImpl implements CryptoComponent { class CryptoComponentImpl implements CryptoComponent {
private static final String PROVIDER = "BC"; private static final String PROVIDER = "BC";
private static final String KEY_PAIR_ALGO = "ECDSA"; private static final String AGREEMENT_KEY_PAIR_ALGO = "ECDH";
private static final int KEY_PAIR_BITS = 384; private static final int AGREEMENT_KEY_PAIR_BITS = 384;
private static final String KEY_AGREEMENT_ALGO = "ECDHC"; private static final String AGREEMENT_ALGO = "ECDHC";
private static final String SECRET_KEY_ALGO = "AES"; private static final String SECRET_KEY_ALGO = "AES";
private static final int SECRET_KEY_BYTES = 32; // 256 bits private static final int SECRET_KEY_BYTES = 32; // 256 bits
private static final int KEY_DERIVATION_IV_BYTES = 16; // 128 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 KEY_DERIVATION_ALGO = "AES/CTR/NoPadding";
private static final String DIGEST_ALGO = "SHA-384"; 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 SIGNATURE_ALGO = "ECDSA";
private static final String TAG_CIPHER_ALGO = "AES/ECB/NoPadding"; private static final String TAG_CIPHER_ALGO = "AES/ECB/NoPadding";
private static final String FRAME_CIPHER_ALGO = "AES/CTR/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 = private static final byte[] KEY_DERIVATION_INPUT =
new byte[SECRET_KEY_BYTES]; new byte[SECRET_KEY_BYTES];
private final KeyParser keyParser; private final KeyParser agreementKeyParser, signatureKeyParser;
private final KeyPairGenerator keyPairGenerator; private final KeyPairGenerator agreementKeyPairGenerator;
private final KeyPairGenerator signatureKeyPairGenerator;
private final SecureRandom secureRandom; private final SecureRandom secureRandom;
@Inject @Inject
CryptoComponentImpl() { CryptoComponentImpl() {
Security.addProvider(new BouncyCastleProvider()); Security.addProvider(new BouncyCastleProvider());
try { try {
keyParser = new KeyParserImpl(KEY_PAIR_ALGO, PROVIDER); agreementKeyParser = new KeyParserImpl(AGREEMENT_KEY_PAIR_ALGO,
keyPairGenerator = KeyPairGenerator.getInstance(KEY_PAIR_ALGO,
PROVIDER); 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) { } catch(GeneralSecurityException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@@ -130,7 +139,8 @@ class CryptoComponentImpl implements CryptoComponent {
byte[] theirPublicKey, PrivateKey ourPrivateKey, int invitationCode, byte[] theirPublicKey, PrivateKey ourPrivateKey, int invitationCode,
boolean initiator) { boolean initiator) {
try { try {
PublicKey theirPublic = keyParser.parsePublicKey(theirPublicKey); PublicKey theirPublic = agreementKeyParser.parsePublicKey(
theirPublicKey);
MessageDigest messageDigest = getMessageDigest(); MessageDigest messageDigest = getMessageDigest();
byte[] ourHash = messageDigest.digest(ourPublicKey); byte[] ourHash = messageDigest.digest(ourPublicKey);
byte[] theirHash = messageDigest.digest(theirPublicKey); byte[] theirHash = messageDigest.digest(theirPublicKey);
@@ -147,8 +157,8 @@ class CryptoComponentImpl implements CryptoComponent {
byte[] publicInfo = new byte[4]; byte[] publicInfo = new byte[4];
ByteUtils.writeUint32(invitationCode, publicInfo, 0); ByteUtils.writeUint32(invitationCode, publicInfo, 0);
// The raw secret comes from the key agreement algorithm // The raw secret comes from the key agreement algorithm
KeyAgreement keyAgreement = KeyAgreement.getInstance( KeyAgreement keyAgreement = KeyAgreement.getInstance(AGREEMENT_ALGO,
KEY_AGREEMENT_ALGO, PROVIDER); PROVIDER);
keyAgreement.init(ourPrivateKey); keyAgreement.init(ourPrivateKey);
keyAgreement.doPhase(theirPublic, true); keyAgreement.doPhase(theirPublic, true);
byte[] rawSecret = keyAgreement.generateSecret(); byte[] rawSecret = keyAgreement.generateSecret();
@@ -220,12 +230,16 @@ class CryptoComponentImpl implements CryptoComponent {
return code; return code;
} }
public KeyPair generateKeyPair() { public KeyPair generateAgreementKeyPair() {
return keyPairGenerator.generateKeyPair(); return agreementKeyPairGenerator.generateKeyPair();
} }
public KeyParser getKeyParser() { public KeyPair generateSignatureKeyPair() {
return keyParser; return signatureKeyPairGenerator.generateKeyPair();
}
public KeyParser getSignatureKeyParser() {
return signatureKeyParser;
} }
public ErasableKey generateTestKey() { public ErasableKey generateTestKey() {

View File

@@ -106,7 +106,7 @@ class InvitationStarterImpl implements InvitationStarter {
return; return;
} }
// Use an ephemeral key pair for key agreement // Use an ephemeral key pair for key agreement
KeyPair ourKeyPair = crypto.generateKeyPair(); KeyPair ourKeyPair = crypto.generateAgreementKeyPair();
MessageDigest messageDigest = crypto.getMessageDigest(); MessageDigest messageDigest = crypto.getMessageDigest();
byte[] ourKey = ourKeyPair.getPublic().getEncoded(); byte[] ourKey = ourKeyPair.getPublic().getEncoded();
byte[] ourHash = messageDigest.digest(ourKey); byte[] ourHash = messageDigest.digest(ourKey);

View File

@@ -57,7 +57,7 @@ class UnverifiedBatchImpl implements UnverifiedBatch {
// Verify the author's signature, if there is one // Verify the author's signature, if there is one
Author author = m.getAuthor(); Author author = m.getAuthor();
if(author != null) { if(author != null) {
if(keyParser == null) keyParser = crypto.getKeyParser(); if(keyParser == null) keyParser = crypto.getSignatureKeyParser();
PublicKey k = keyParser.parsePublicKey(author.getPublicKey()); PublicKey k = keyParser.parsePublicKey(author.getPublicKey());
if(signature == null) signature = crypto.getSignature(); if(signature == null) signature = crypto.getSignature();
signature.initVerify(k); signature.initVerify(k);
@@ -68,7 +68,7 @@ class UnverifiedBatchImpl implements UnverifiedBatch {
// Verify the group's signature, if there is one // Verify the group's signature, if there is one
Group group = m.getGroup(); Group group = m.getGroup();
if(group != null && group.getPublicKey() != null) { if(group != null && group.getPublicKey() != null) {
if(keyParser == null) keyParser = crypto.getKeyParser(); if(keyParser == null) keyParser = crypto.getSignatureKeyParser();
PublicKey k = keyParser.parsePublicKey(group.getPublicKey()); PublicKey k = keyParser.parsePublicKey(group.getPublicKey());
if(signature == null) signature = crypto.getSignature(); if(signature == null) signature = crypto.getSignature();
signature.initVerify(k); signature.initVerify(k);

View File

@@ -100,12 +100,12 @@ public class ProtocolIntegrationTest extends BriarTestCase {
// Create two groups: one restricted, one unrestricted // Create two groups: one restricted, one unrestricted
GroupFactory groupFactory = i.getInstance(GroupFactory.class); GroupFactory groupFactory = i.getInstance(GroupFactory.class);
group = groupFactory.createGroup("Unrestricted group", null); group = groupFactory.createGroup("Unrestricted group", null);
KeyPair groupKeyPair = crypto.generateKeyPair(); KeyPair groupKeyPair = crypto.generateSignatureKeyPair();
group1 = groupFactory.createGroup("Restricted group", group1 = groupFactory.createGroup("Restricted group",
groupKeyPair.getPublic().getEncoded()); groupKeyPair.getPublic().getEncoded());
// Create an author // Create an author
AuthorFactory authorFactory = i.getInstance(AuthorFactory.class); AuthorFactory authorFactory = i.getInstance(AuthorFactory.class);
KeyPair authorKeyPair = crypto.generateKeyPair(); KeyPair authorKeyPair = crypto.generateSignatureKeyPair();
author = authorFactory.createAuthor(authorName, author = authorFactory.createAuthor(authorName,
authorKeyPair.getPublic().getEncoded()); authorKeyPair.getPublic().getEncoded());
// Create two messages to each group: one anonymous, one pseudonymous // Create two messages to each group: one anonymous, one pseudonymous

View 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]);
}
}

View File

@@ -108,8 +108,8 @@ public class ConstantsTest extends BriarTestCase {
byte[] authorPublic = new byte[MAX_PUBLIC_KEY_LENGTH]; byte[] authorPublic = new byte[MAX_PUBLIC_KEY_LENGTH];
Author author = authorFactory.createAuthor(authorName, authorPublic); Author author = authorFactory.createAuthor(authorName, authorPublic);
// Create a maximum-length message // Create a maximum-length message
PrivateKey groupPrivate = crypto.generateKeyPair().getPrivate(); PrivateKey groupPrivate = crypto.generateSignatureKeyPair().getPrivate();
PrivateKey authorPrivate = crypto.generateKeyPair().getPrivate(); PrivateKey authorPrivate = crypto.generateSignatureKeyPair().getPrivate();
String subject = createRandomString(MAX_SUBJECT_LENGTH); String subject = createRandomString(MAX_SUBJECT_LENGTH);
byte[] body = new byte[MAX_BODY_LENGTH]; byte[] body = new byte[MAX_BODY_LENGTH];
Message message = messageFactory.createMessage(null, group, Message message = messageFactory.createMessage(null, group,

View File

@@ -122,8 +122,8 @@ public class UnverifiedBatchImplTest extends BriarTestCase {
@Test @Test
public void testSignatures() throws Exception { public void testSignatures() throws Exception {
final int signedByAuthor = 100, signedByGroup = 110; final int signedByAuthor = 100, signedByGroup = 110;
final KeyPair authorKeyPair = crypto.generateKeyPair(); final KeyPair authorKeyPair = crypto.generateSignatureKeyPair();
final KeyPair groupKeyPair = crypto.generateKeyPair(); final KeyPair groupKeyPair = crypto.generateSignatureKeyPair();
Signature signature = crypto.getSignature(); Signature signature = crypto.getSignature();
// Calculate the expected author and group signatures // Calculate the expected author and group signatures
signature.initSign(authorKeyPair.getPrivate()); signature.initSign(authorKeyPair.getPrivate());
@@ -202,7 +202,7 @@ public class UnverifiedBatchImplTest extends BriarTestCase {
@Test @Test
public void testExceptionThrownIfMessageIsModified() throws Exception { public void testExceptionThrownIfMessageIsModified() throws Exception {
final int signedByAuthor = 100; final int signedByAuthor = 100;
final KeyPair authorKeyPair = crypto.generateKeyPair(); final KeyPair authorKeyPair = crypto.generateSignatureKeyPair();
Signature signature = crypto.getSignature(); Signature signature = crypto.getSignature();
// Calculate the expected author signature // Calculate the expected author signature
signature.initSign(authorKeyPair.getPrivate()); signature.initSign(authorKeyPair.getPrivate());