diff --git a/briar-android-tests/src/test/java/org/briarproject/PrivateGroupManagerTest.java b/briar-android-tests/src/test/java/org/briarproject/PrivateGroupManagerTest.java index d7c9c051dceeaf287d8c8e916892998f37448b90..ab8fa52cc1bbc23b0ff5a70d52bdf6e3723c6195 100644 --- a/briar-android-tests/src/test/java/org/briarproject/PrivateGroupManagerTest.java +++ b/briar-android-tests/src/test/java/org/briarproject/PrivateGroupManagerTest.java @@ -5,6 +5,7 @@ import net.jodah.concurrentunit.Waiter; import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.clients.ContactGroupFactory; import org.briarproject.api.clients.MessageTracker.GroupCount; +import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactManager; import org.briarproject.api.crypto.CryptoComponent; @@ -29,7 +30,7 @@ import org.briarproject.api.privategroup.JoinMessageHeader; import org.briarproject.api.privategroup.PrivateGroup; import org.briarproject.api.privategroup.PrivateGroupFactory; import org.briarproject.api.privategroup.PrivateGroupManager; -import org.briarproject.api.sync.Group; +import org.briarproject.api.privategroup.invitation.GroupInvitationFactory; import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; import org.briarproject.api.sync.SyncSession; @@ -65,7 +66,7 @@ import static org.briarproject.api.privategroup.Visibility.INVISIBLE; import static org.briarproject.api.privategroup.Visibility.REVEALED_BY_CONTACT; import static org.briarproject.api.privategroup.Visibility.REVEALED_BY_US; import static org.briarproject.api.privategroup.Visibility.VISIBLE; -import static org.briarproject.api.privategroup.invitation.GroupInvitationManager.CLIENT_ID; +import static org.briarproject.api.privategroup.invitation.GroupInvitationFactory.SIGNING_LABEL_INVITE; import static org.briarproject.api.sync.Group.Visibility.SHARED; import static org.briarproject.api.sync.ValidationManager.State.DELIVERED; import static org.briarproject.api.sync.ValidationManager.State.INVALID; @@ -103,6 +104,8 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest { PrivateGroupFactory privateGroupFactory; @Inject GroupMessageFactory groupMessageFactory; + @Inject + GroupInvitationFactory groupInvitationFactory; // objects accessed from background threads need to be volatile private volatile Waiter validationWaiter; @@ -358,13 +361,10 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest { // author1 joins privateGroup0 with wrong timestamp joinTime = clock.currentTimeMillis(); long inviteTime = joinTime; - Group invitationGroup = contactGroupFactory - .createContactGroup(CLIENT_ID, author0.getId(), - author1.getId()); - BdfList toSign = BdfList.of(0, inviteTime, invitationGroup.getId(), - privateGroup0.getId()); - byte[] creatorSignature = - clientHelper.sign(toSign, author0.getPrivateKey()); + Contact c1 = contactManager0.getContact(contactId1); + byte[] creatorSignature = groupInvitationFactory + .signInvitation(c1, privateGroup0.getId(), inviteTime, + author0.getPrivateKey()); GroupMessage joinMsg1 = groupMessageFactory .createJoinMessage(privateGroup0.getId(), joinTime, author1, inviteTime, creatorSignature); @@ -402,13 +402,11 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest { // author0 joins privateGroup0 with wrong member's join message long joinTime = clock.currentTimeMillis(); long inviteTime = joinTime - 1; - Group invitationGroup = contactGroupFactory - .createContactGroup(CLIENT_ID, author0.getId(), - author0.getId()); - BdfList toSign = BdfList.of(0, inviteTime, invitationGroup.getId(), - privateGroup0.getId()); - byte[] creatorSignature = - clientHelper.sign(toSign, author0.getPrivateKey()); + BdfList toSign = groupInvitationFactory + .createInviteToken(author0.getId(), author0.getId(), + privateGroup0.getId(), inviteTime); + byte[] creatorSignature = clientHelper + .sign(SIGNING_LABEL_INVITE, toSign, author0.getPrivateKey()); // join message should not include invite time and creator's signature GroupMessage joinMsg0 = groupMessageFactory .createJoinMessage(privateGroup0.getId(), joinTime, author0, @@ -426,13 +424,11 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest { // author1 joins privateGroup0 with wrong signature in join message joinTime = clock.currentTimeMillis(); inviteTime = joinTime - 1; - invitationGroup = contactGroupFactory - .createContactGroup(CLIENT_ID, author0.getId(), - author1.getId()); - toSign = BdfList.of(0, inviteTime, invitationGroup.getId(), - privateGroup0.getId()); // signature uses joiner's key, not creator's key - creatorSignature = clientHelper.sign(toSign, author1.getPrivateKey()); + Contact c1 = contactManager0.getContact(contactId1); + creatorSignature = groupInvitationFactory + .signInvitation(c1, privateGroup0.getId(), inviteTime, + author1.getPrivateKey()); GroupMessage joinMsg1 = groupMessageFactory .createJoinMessage(privateGroup0.getId(), joinTime, author1, inviteTime, creatorSignature); @@ -529,13 +525,10 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest { // author2 joins privateGroup0 long joinTime = clock.currentTimeMillis(); long inviteTime = joinTime - 1; - Group invitationGroup = contactGroupFactory - .createContactGroup(CLIENT_ID, author0.getId(), - author2.getId()); - BdfList toSign = BdfList.of(0, inviteTime, invitationGroup.getId(), - privateGroup0.getId()); - byte[] creatorSignature = - clientHelper.sign(toSign, author0.getPrivateKey()); + Contact c2 = contactManager0.getContact(contactId2); + byte[] creatorSignature = groupInvitationFactory + .signInvitation(c2, privateGroup0.getId(), inviteTime, + author0.getPrivateKey()); GroupMessage joinMsg2 = groupMessageFactory .createJoinMessage(privateGroup0.getId(), joinTime, author2, inviteTime, creatorSignature); @@ -753,13 +746,10 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest { // author1 joins privateGroup0 joinTime = clock.currentTimeMillis(); long inviteTime = joinTime - 1; - Group invitationGroup = contactGroupFactory - .createContactGroup(CLIENT_ID, author0.getId(), - author1.getId()); - BdfList toSign = BdfList.of(0, inviteTime, invitationGroup.getId(), - privateGroup0.getId()); - byte[] creatorSignature = - clientHelper.sign(toSign, author0.getPrivateKey()); + Contact c1 = contactManager0.getContact(contactId1); + byte[] creatorSignature = groupInvitationFactory + .signInvitation(c1, privateGroup0.getId(), inviteTime, + author0.getPrivateKey()); GroupMessage joinMsg1 = groupMessageFactory .createJoinMessage(privateGroup0.getId(), joinTime, author1, inviteTime, creatorSignature); diff --git a/briar-android-tests/src/test/java/org/briarproject/introduction/IntroductionIntegrationTest.java b/briar-android-tests/src/test/java/org/briarproject/introduction/IntroductionIntegrationTest.java index 86ed51afb12f38f345522aa389ba7aa7970a846b..826524cc18ae7f9a0d86ca37befe6bd924827e5d 100644 --- a/briar-android-tests/src/test/java/org/briarproject/introduction/IntroductionIntegrationTest.java +++ b/briar-android-tests/src/test/java/org/briarproject/introduction/IntroductionIntegrationTest.java @@ -17,7 +17,6 @@ import org.briarproject.api.contact.ContactManager; import org.briarproject.api.crypto.CryptoComponent; import org.briarproject.api.crypto.KeyPair; import org.briarproject.api.crypto.SecretKey; -import org.briarproject.api.crypto.Signature; import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.data.BdfEntry; import org.briarproject.api.data.BdfList; @@ -95,6 +94,7 @@ import static org.briarproject.api.introduction.IntroductionConstants.TYPE_REQUE import static org.briarproject.api.introduction.IntroductionConstants.TYPE_RESPONSE; import static org.briarproject.api.sync.ValidationManager.State.DELIVERED; import static org.briarproject.api.sync.ValidationManager.State.INVALID; +import static org.briarproject.introduction.IntroduceeManager.SIGNING_LABEL_RESPONSE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -922,10 +922,8 @@ public class IntroductionIntegrationTest extends BriarIntegrationTest { byte[] nonce1 = crypto.deriveSignatureNonce(secretKey, true); // Signature 1 - Signature signature = crypto.getSignature(); - signature.initSign(keyPair1.getPrivate()); - signature.update(nonce1); - byte[] sig1 = signature.sign(); + byte[] sig1 = crypto.sign(SIGNING_LABEL_RESPONSE, nonce1, + keyPair1.getPrivate().getEncoded()); // MAC 1 SecretKey macKey1 = crypto.deriveMacKey(secretKey, true); diff --git a/briar-api/src/org/briarproject/api/blogs/BlogPostFactory.java b/briar-api/src/org/briarproject/api/blogs/BlogPostFactory.java index 7b05c0078ec5d5ba84e86412e5291020b1c196a1..4f8292720ad203b1f87af6afcedb190ac5c4591d 100644 --- a/briar-api/src/org/briarproject/api/blogs/BlogPostFactory.java +++ b/briar-api/src/org/briarproject/api/blogs/BlogPostFactory.java @@ -11,8 +11,13 @@ import org.jetbrains.annotations.Nullable; import java.security.GeneralSecurityException; +import static org.briarproject.api.blogs.BlogManager.CLIENT_ID; + public interface BlogPostFactory { + String SIGNING_LABEL_POST = CLIENT_ID + "/POST"; + String SIGNING_LABEL_COMMENT = CLIENT_ID + "/COMMENT"; + BlogPost createBlogPost(@NotNull GroupId groupId, long timestamp, @Nullable MessageId parent, @NotNull LocalAuthor author, @NotNull String body) diff --git a/briar-api/src/org/briarproject/api/clients/ClientHelper.java b/briar-api/src/org/briarproject/api/clients/ClientHelper.java index 7743f3ba5eb052e9474c2ee8a05384511c17b140..32af81f627d94021792f0451cd5bf90857142fa2 100644 --- a/briar-api/src/org/briarproject/api/clients/ClientHelper.java +++ b/briar-api/src/org/briarproject/api/clients/ClientHelper.java @@ -92,10 +92,10 @@ public interface ClientHelper { BdfList toList(Message m) throws FormatException; - byte[] sign(BdfList toSign, byte[] privateKey) + byte[] sign(String label, BdfList toSign, byte[] privateKey) throws FormatException, GeneralSecurityException; - void verifySignature(byte[] sig, byte[] publicKey, BdfList signed) - throws FormatException, GeneralSecurityException; + void verifySignature(String label, byte[] sig, byte[] publicKey, + BdfList signed) throws FormatException, GeneralSecurityException; } diff --git a/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java b/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java index 50a9c94d565d612f645fc5b5f8cbba561d937f18..60a606889a14f1ab846f0c512c467eb96b924561 100644 --- a/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java +++ b/briar-api/src/org/briarproject/api/crypto/CryptoComponent.java @@ -16,8 +16,6 @@ public interface CryptoComponent { SecureRandom getSecureRandom(); - Signature getSignature(); - KeyPair generateAgreementKeyPair(); KeyParser getAgreementKeyParser(); @@ -143,6 +141,26 @@ public interface CryptoComponent { /** Encodes the pseudo-random tag that is used to recognise a stream. */ void encodeTag(byte[] tag, SecretKey tagKey, long streamNumber); + /** + * Signs the given byte[] with the given PrivateKey. + * + * @param label A label specific to this signature + * to ensure that the signature cannot be repurposed + */ + byte[] sign(String label, byte[] toSign, byte[] privateKey) + throws GeneralSecurityException; + + /** + * Verifies that the given signature is valid for the signedData + * and the given publicKey. + * + * @param label A label that was specific to this signature + * to ensure that the signature cannot be repurposed + * @return true if the signature was valid, false otherwise. + */ + boolean verify(String label, byte[] signedData, byte[] publicKey, + byte[] signature) throws GeneralSecurityException; + /** * Returns the hash of the given inputs. The inputs are unambiguously * combined by prefixing each input with its length. diff --git a/briar-api/src/org/briarproject/api/forum/ForumPostFactory.java b/briar-api/src/org/briarproject/api/forum/ForumPostFactory.java index 820a11acc25f5682f17dca3f36c210c366afe0c8..d5b8d9b35614555678a7c67848cad529e3606fee 100644 --- a/briar-api/src/org/briarproject/api/forum/ForumPostFactory.java +++ b/briar-api/src/org/briarproject/api/forum/ForumPostFactory.java @@ -8,8 +8,12 @@ import org.briarproject.api.sync.MessageId; import java.security.GeneralSecurityException; +import static org.briarproject.api.forum.ForumManager.CLIENT_ID; + public interface ForumPostFactory { + String SIGNING_LABEL_POST = CLIENT_ID + "/POST"; + @CryptoExecutor ForumPost createPost(GroupId groupId, long timestamp, MessageId parent, LocalAuthor author, String body) diff --git a/briar-api/src/org/briarproject/api/privategroup/GroupMessageFactory.java b/briar-api/src/org/briarproject/api/privategroup/GroupMessageFactory.java index ff1b72e84f482a70274718e37428a11b6025c472..220e958fc07f3339e2a13c804a0f3daa794e65d5 100644 --- a/briar-api/src/org/briarproject/api/privategroup/GroupMessageFactory.java +++ b/briar-api/src/org/briarproject/api/privategroup/GroupMessageFactory.java @@ -1,16 +1,20 @@ package org.briarproject.api.privategroup; import org.briarproject.api.crypto.CryptoExecutor; -import org.briarproject.api.identity.Author; import org.briarproject.api.identity.LocalAuthor; import org.briarproject.api.nullsafety.NotNullByDefault; import org.briarproject.api.sync.GroupId; import org.briarproject.api.sync.MessageId; import org.jetbrains.annotations.Nullable; +import static org.briarproject.api.privategroup.PrivateGroupManager.CLIENT_ID; + @NotNullByDefault public interface GroupMessageFactory { + String SIGNING_LABEL_JOIN = CLIENT_ID + "/JOIN"; + String SIGNING_LABEL_POST = CLIENT_ID + "/POST"; + /** * Creates a join announcement message for the creator of a group. * diff --git a/briar-api/src/org/briarproject/api/privategroup/invitation/GroupInvitationFactory.java b/briar-api/src/org/briarproject/api/privategroup/invitation/GroupInvitationFactory.java index e5cf41adf714a6e73ee0a36bdac94e3305a2b596..fdde77abe33e8c6003b60e14790d659cdbd28fe1 100644 --- a/briar-api/src/org/briarproject/api/privategroup/invitation/GroupInvitationFactory.java +++ b/briar-api/src/org/briarproject/api/privategroup/invitation/GroupInvitationFactory.java @@ -6,8 +6,12 @@ import org.briarproject.api.data.BdfList; import org.briarproject.api.identity.AuthorId; import org.briarproject.api.sync.GroupId; +import static org.briarproject.api.privategroup.invitation.GroupInvitationManager.CLIENT_ID; + public interface GroupInvitationFactory { + String SIGNING_LABEL_INVITE = CLIENT_ID + "/INVITE"; + /** * Returns a signature to include when inviting a member to join a private * group. If the member accepts the invitation, the signature will be @@ -24,4 +28,5 @@ public interface GroupInvitationFactory { */ BdfList createInviteToken(AuthorId creatorId, AuthorId memberId, GroupId privateGroupId, long timestamp); + } diff --git a/briar-core/src/org/briarproject/blogs/BlogPostFactoryImpl.java b/briar-core/src/org/briarproject/blogs/BlogPostFactoryImpl.java index fdab87cac682357641e27d1b1f92674b197b85c3..52cbc72a76e3e6db71ed4471c24bf7626f408734 100644 --- a/briar-core/src/org/briarproject/blogs/BlogPostFactoryImpl.java +++ b/briar-core/src/org/briarproject/blogs/BlogPostFactoryImpl.java @@ -52,7 +52,8 @@ class BlogPostFactoryImpl implements BlogPostFactory { BdfList signed = BdfList.of(groupId, timestamp, body); // Generate the signature - byte[] sig = clientHelper.sign(signed, author.getPrivateKey()); + byte[] sig = clientHelper + .sign(SIGNING_LABEL_POST, signed, author.getPrivateKey()); // Serialise the signed message BdfList message = BdfList.of(POST.getInt(), body, sig); @@ -77,7 +78,8 @@ class BlogPostFactoryImpl implements BlogPostFactory { // Generate the signature BdfList signed = BdfList.of(groupId, timestamp, comment, pOriginalId, parentId); - byte[] sig = clientHelper.sign(signed, author.getPrivateKey()); + byte[] sig = clientHelper + .sign(SIGNING_LABEL_COMMENT, signed, author.getPrivateKey()); // Serialise the signed message BdfList message = diff --git a/briar-core/src/org/briarproject/blogs/BlogPostValidator.java b/briar-core/src/org/briarproject/blogs/BlogPostValidator.java index 088354fc1697caa67d714f2eb554fc4a332e42e5..4b7dd148e39197e64f86a63084075895896dc19c 100644 --- a/briar-core/src/org/briarproject/blogs/BlogPostValidator.java +++ b/briar-core/src/org/briarproject/blogs/BlogPostValidator.java @@ -39,6 +39,8 @@ import static org.briarproject.api.blogs.BlogConstants.KEY_TIME_RECEIVED; import static org.briarproject.api.blogs.BlogConstants.KEY_TYPE; import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_COMMENT_LENGTH; import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_POST_BODY_LENGTH; +import static org.briarproject.api.blogs.BlogPostFactory.SIGNING_LABEL_COMMENT; +import static org.briarproject.api.blogs.BlogPostFactory.SIGNING_LABEL_POST; import static org.briarproject.api.blogs.MessageType.COMMENT; import static org.briarproject.api.blogs.MessageType.POST; import static org.briarproject.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH; @@ -105,7 +107,9 @@ class BlogPostValidator extends BdfMessageValidator { Blog b = blogFactory.parseBlog(g); Author a = b.getAuthor(); try { - clientHelper.verifySignature(sig, a.getPublicKey(), signed); + clientHelper + .verifySignature(SIGNING_LABEL_POST, sig, a.getPublicKey(), + signed); } catch (GeneralSecurityException e) { throw new InvalidMessageException(e); } @@ -150,7 +154,8 @@ class BlogPostValidator extends BdfMessageValidator { Blog b = blogFactory.parseBlog(g); Author a = b.getAuthor(); try { - clientHelper.verifySignature(sig, a.getPublicKey(), signed); + clientHelper.verifySignature(SIGNING_LABEL_COMMENT, sig, + a.getPublicKey(), signed); } catch (GeneralSecurityException e) { throw new InvalidMessageException(e); } diff --git a/briar-core/src/org/briarproject/clients/ClientHelperImpl.java b/briar-core/src/org/briarproject/clients/ClientHelperImpl.java index 7356ca1d1cd164b42d2f71b2e124a6af8b2ac561..bca3812f35a16366c1b570c58df898c8c0adc16d 100644 --- a/briar-core/src/org/briarproject/clients/ClientHelperImpl.java +++ b/briar-core/src/org/briarproject/clients/ClientHelperImpl.java @@ -3,10 +3,6 @@ package org.briarproject.clients; import org.briarproject.api.FormatException; import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.crypto.CryptoComponent; -import org.briarproject.api.crypto.KeyParser; -import org.briarproject.api.crypto.PrivateKey; -import org.briarproject.api.crypto.PublicKey; -import org.briarproject.api.crypto.Signature; import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.data.BdfList; import org.briarproject.api.data.BdfReader; @@ -346,27 +342,15 @@ class ClientHelperImpl implements ClientHelper { } @Override - public byte[] sign(BdfList toSign, byte[] privateKey) + public byte[] sign(String label, BdfList toSign, byte[] privateKey) throws FormatException, GeneralSecurityException { - Signature signature = crypto.getSignature(); - KeyParser keyParser = crypto.getSignatureKeyParser(); - PrivateKey key = keyParser.parsePrivateKey(privateKey); - signature.initSign(key); - signature.update(toByteArray(toSign)); - return signature.sign(); + return crypto.sign(label, toByteArray(toSign), privateKey); } @Override - public void verifySignature(byte[] sig, byte[] publicKey, BdfList signed) - throws FormatException, GeneralSecurityException { - // Parse the public key - KeyParser keyParser = crypto.getSignatureKeyParser(); - PublicKey key = keyParser.parsePublicKey(publicKey); - // Verify the signature - Signature signature = crypto.getSignature(); - signature.initVerify(key); - signature.update(toByteArray(signed)); - if (!signature.verify(sig)) { + public void verifySignature(String label, byte[] sig, byte[] publicKey, + BdfList signed) throws FormatException, GeneralSecurityException { + if (!crypto.verify(label, toByteArray(signed), publicKey, sig)) { throw new GeneralSecurityException("Invalid signature"); } } diff --git a/briar-core/src/org/briarproject/contact/ContactExchangeTaskImpl.java b/briar-core/src/org/briarproject/contact/ContactExchangeTaskImpl.java index 85eb36f9a63ea7900a38fff294d81f5d7fabc0e4..ec825052cc7643795930e40ab89d55b73c205484 100644 --- a/briar-core/src/org/briarproject/contact/ContactExchangeTaskImpl.java +++ b/briar-core/src/org/briarproject/contact/ContactExchangeTaskImpl.java @@ -7,9 +7,7 @@ import org.briarproject.api.contact.ContactExchangeTask; import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactManager; import org.briarproject.api.crypto.CryptoComponent; -import org.briarproject.api.crypto.KeyParser; import org.briarproject.api.crypto.SecretKey; -import org.briarproject.api.crypto.Signature; import org.briarproject.api.data.BdfList; import org.briarproject.api.data.BdfReader; import org.briarproject.api.data.BdfReaderFactory; @@ -55,6 +53,8 @@ public class ContactExchangeTaskImpl extends Thread private static final Logger LOG = Logger.getLogger(ContactExchangeTaskImpl.class.getName()); + private static final String SIGNING_LABEL_EXCHANGE = + "org.briarproject.briar.contact/EXCHANGE"; private final DatabaseComponent db; private final AuthorFactory authorFactory; @@ -219,12 +219,9 @@ public class ContactExchangeTaskImpl extends Thread private void sendPseudonym(BdfWriter w, byte[] nonce) throws GeneralSecurityException, IOException { // Sign the nonce - Signature signature = crypto.getSignature(); - KeyParser keyParser = crypto.getSignatureKeyParser(); byte[] privateKey = localAuthor.getPrivateKey(); - signature.initSign(keyParser.parsePrivateKey(privateKey)); - signature.update(nonce); - byte[] sig = signature.sign(); + byte[] sig = crypto.sign(SIGNING_LABEL_EXCHANGE, nonce, privateKey); + // Write the name, public key and signature w.writeListStart(); w.writeString(localAuthor.getName()); @@ -244,11 +241,7 @@ public class ContactExchangeTaskImpl extends Thread r.readListEnd(); LOG.info("Received pseudonym"); // Verify the signature - Signature signature = crypto.getSignature(); - KeyParser keyParser = crypto.getSignatureKeyParser(); - signature.initVerify(keyParser.parsePublicKey(publicKey)); - signature.update(nonce); - if (!signature.verify(sig)) { + if (!crypto.verify(SIGNING_LABEL_EXCHANGE, nonce, publicKey, sig)) { if (LOG.isLoggable(INFO)) LOG.info("Invalid signature"); throw new GeneralSecurityException(); diff --git a/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java b/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java index 22698a22ff70aac5087158a3f17684aab0c87686..eb98217947a30dc7a464033d3a94f5881557003a 100644 --- a/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java +++ b/briar-core/src/org/briarproject/crypto/CryptoComponentImpl.java @@ -164,11 +164,6 @@ class CryptoComponentImpl implements CryptoComponent { return secret; } - @Override - public Signature getSignature() { - return new SignatureImpl(secureRandom); - } - @Override public KeyPair generateAgreementKeyPair() { AsymmetricCipherKeyPair keyPair = @@ -399,6 +394,40 @@ class CryptoComponentImpl implements CryptoComponent { System.arraycopy(mac, 0, tag, 0, TAG_LENGTH); } + @Override + public byte[] sign(String label, byte[] toSign, byte[] privateKey) + throws GeneralSecurityException { + Signature signature = new SignatureImpl(secureRandom); + KeyParser keyParser = getSignatureKeyParser(); + PrivateKey key = keyParser.parsePrivateKey(privateKey); + signature.initSign(key); + updateSignature(signature, label, toSign); + return signature.sign(); + } + + @Override + public boolean verify(String label, byte[] signedData, byte[] publicKey, + byte[] signature) throws GeneralSecurityException { + Signature sig = new SignatureImpl(secureRandom); + KeyParser keyParser = getSignatureKeyParser(); + PublicKey key = keyParser.parsePublicKey(publicKey); + sig.initVerify(key); + updateSignature(sig, label, signedData); + return sig.verify(signature); + } + + private void updateSignature(Signature signature, String label, + byte[] toSign) { + byte[] labelBytes = StringUtils.toUtf8(label); + byte[] length = new byte[INT_32_BYTES]; + ByteUtils.writeUint32(labelBytes.length, length, 0); + signature.update(length); + signature.update(labelBytes); + ByteUtils.writeUint32(toSign.length, length, 0); + signature.update(length); + signature.update(toSign); + } + @Override public byte[] hash(byte[]... inputs) { MessageDigest digest = getMessageDigest(); diff --git a/briar-core/src/org/briarproject/forum/ForumPostFactoryImpl.java b/briar-core/src/org/briarproject/forum/ForumPostFactoryImpl.java index f4ddfad0f0463d321e87bdcea4a67143fbece460..70a545e1f9f6d80c3729ad026aa100ed56d55516 100644 --- a/briar-core/src/org/briarproject/forum/ForumPostFactoryImpl.java +++ b/briar-core/src/org/briarproject/forum/ForumPostFactoryImpl.java @@ -39,7 +39,8 @@ class ForumPostFactoryImpl implements ForumPostFactory { BdfList signed = BdfList.of(groupId, timestamp, parent, authorList, body); // Sign the data - byte[] sig = clientHelper.sign(signed, author.getPrivateKey()); + byte[] sig = clientHelper + .sign(SIGNING_LABEL_POST, signed, author.getPrivateKey()); // Serialise the signed message BdfList message = BdfList.of(parent, authorList, body, sig); Message m = clientHelper.createMessage(groupId, timestamp, message); diff --git a/briar-core/src/org/briarproject/forum/ForumPostValidator.java b/briar-core/src/org/briarproject/forum/ForumPostValidator.java index 19e62584c84227c35d35b1b54a53c740e36da380..b7d2f70660889b0094038f99015ebc6468ec866c 100644 --- a/briar-core/src/org/briarproject/forum/ForumPostValidator.java +++ b/briar-core/src/org/briarproject/forum/ForumPostValidator.java @@ -22,6 +22,7 @@ import java.util.Collection; import java.util.Collections; import static org.briarproject.api.forum.ForumConstants.MAX_FORUM_POST_BODY_LENGTH; +import static org.briarproject.api.forum.ForumPostFactory.SIGNING_LABEL_POST; import static org.briarproject.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; import static org.briarproject.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH; @@ -68,7 +69,8 @@ class ForumPostValidator extends BdfMessageValidator { BdfList signed = BdfList.of(g.getId(), m.getTimestamp(), parent, authorList, forumPostBody); try { - clientHelper.verifySignature(sig, author.getPublicKey(), signed); + clientHelper.verifySignature(SIGNING_LABEL_POST, sig, + author.getPublicKey(), signed); } catch (GeneralSecurityException e) { throw new InvalidMessageException(e); } diff --git a/briar-core/src/org/briarproject/introduction/IntroduceeManager.java b/briar-core/src/org/briarproject/introduction/IntroduceeManager.java index 450fc023a39a017b21354abeabb101b2d082e181..e0227b6bc4f436820bd75407aa8169b2fd0a9bd6 100644 --- a/briar-core/src/org/briarproject/introduction/IntroduceeManager.java +++ b/briar-core/src/org/briarproject/introduction/IntroduceeManager.java @@ -13,7 +13,6 @@ import org.briarproject.api.crypto.KeyParser; import org.briarproject.api.crypto.PrivateKey; import org.briarproject.api.crypto.PublicKey; import org.briarproject.api.crypto.SecretKey; -import org.briarproject.api.crypto.Signature; import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.data.BdfList; import org.briarproject.api.db.DatabaseComponent; @@ -88,11 +87,13 @@ import static org.briarproject.api.introduction.IntroductionConstants.TYPE; import static org.briarproject.api.introduction.IntroductionConstants.TYPE_ABORT; import static org.briarproject.api.introduction.IntroductionConstants.TYPE_ACK; import static org.briarproject.api.introduction.IntroductionConstants.TYPE_RESPONSE; +import static org.briarproject.api.introduction.IntroductionManager.CLIENT_ID; class IntroduceeManager { private static final Logger LOG = Logger.getLogger(IntroduceeManager.class.getName()); + static final String SIGNING_LABEL_RESPONSE = CLIENT_ID + "/RESPONSE"; private final MessageSender messageSender; private final DatabaseComponent db; @@ -453,12 +454,8 @@ class IntroduceeManager { localState.put(MAC_KEY, theirMacKey.getBytes()); // Sign our nonce with our long-term identity public key - Signature signature = cryptoComponent.getSignature(); - KeyParser sigParser = cryptoComponent.getSignatureKeyParser(); - PrivateKey privKey = sigParser.parsePrivateKey(author.getPrivateKey()); - signature.initSign(privKey); - signature.update(ourNonce); - byte[] sig = signature.sign(); + byte[] sig = cryptoComponent + .sign(SIGNING_LABEL_RESPONSE, ourNonce, author.getPrivateKey()); // Calculate a MAC over identity public key, ephemeral public key, // transport properties and timestamp. @@ -479,16 +476,10 @@ class IntroduceeManager { throws FormatException, GeneralSecurityException { byte[] nonce = localState.getRaw(NONCE); byte[] sig = localState.getRaw(SIGNATURE); - byte[] keyBytes = localState.getRaw(PUBLIC_KEY); + byte[] key = localState.getRaw(PUBLIC_KEY); - // Parse the public key - KeyParser keyParser = cryptoComponent.getSignatureKeyParser(); - PublicKey key = keyParser.parsePublicKey(keyBytes); // Verify the signature - Signature signature = cryptoComponent.getSignature(); - signature.initVerify(key); - signature.update(nonce); - if (!signature.verify(sig)) { + if (!cryptoComponent.verify(SIGNING_LABEL_RESPONSE, nonce, key, sig)) { LOG.warning("Invalid nonce signature in ACK"); throw new GeneralSecurityException(); } diff --git a/briar-core/src/org/briarproject/privategroup/GroupMessageFactoryImpl.java b/briar-core/src/org/briarproject/privategroup/GroupMessageFactoryImpl.java index aeb478001b91dc4fe04aaaacc3da460664082f33..71d6ebbeefad49bef35ae9b46d8305983a027f3d 100644 --- a/briar-core/src/org/briarproject/privategroup/GroupMessageFactoryImpl.java +++ b/briar-core/src/org/briarproject/privategroup/GroupMessageFactoryImpl.java @@ -51,8 +51,8 @@ class GroupMessageFactoryImpl implements GroupMessageFactory { int type = JOIN.getInt(); BdfList toSign = BdfList.of(groupId, timestamp, type, member.getName(), member.getPublicKey(), invite); - byte[] memberSignature = - clientHelper.sign(toSign, member.getPrivateKey()); + byte[] memberSignature = clientHelper + .sign(SIGNING_LABEL_JOIN, toSign, member.getPrivateKey()); // Compose the message BdfList body = @@ -78,8 +78,8 @@ class GroupMessageFactoryImpl implements GroupMessageFactory { BdfList toSign = BdfList.of(groupId, timestamp, type, author.getName(), author.getPublicKey(), parentId, previousMsgId, content); - byte[] signature = - clientHelper.sign(toSign, author.getPrivateKey()); + byte[] signature = clientHelper + .sign(SIGNING_LABEL_POST, toSign, author.getPrivateKey()); // Compose the message BdfList body = diff --git a/briar-core/src/org/briarproject/privategroup/GroupMessageValidator.java b/briar-core/src/org/briarproject/privategroup/GroupMessageValidator.java index a80f1ce4b58db6e0cc03ff7a1f17bd3adeab9547..7e27d74685bdf55eb9fb23d27981b029d97796ad 100644 --- a/briar-core/src/org/briarproject/privategroup/GroupMessageValidator.java +++ b/briar-core/src/org/briarproject/privategroup/GroupMessageValidator.java @@ -27,9 +27,12 @@ import java.util.Collection; import static org.briarproject.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; import static org.briarproject.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH; +import static org.briarproject.api.privategroup.GroupMessageFactory.SIGNING_LABEL_JOIN; +import static org.briarproject.api.privategroup.GroupMessageFactory.SIGNING_LABEL_POST; import static org.briarproject.api.privategroup.MessageType.JOIN; import static org.briarproject.api.privategroup.MessageType.POST; import static org.briarproject.api.privategroup.PrivateGroupConstants.MAX_GROUP_POST_BODY_LENGTH; +import static org.briarproject.api.privategroup.invitation.GroupInvitationFactory.SIGNING_LABEL_INVITE; import static org.briarproject.privategroup.GroupConstants.KEY_INITIAL_JOIN_MSG; import static org.briarproject.privategroup.GroupConstants.KEY_MEMBER_ID; import static org.briarproject.privategroup.GroupConstants.KEY_MEMBER_NAME; @@ -130,7 +133,7 @@ class GroupMessageValidator extends BdfMessageValidator { .createInviteToken(creator.getId(), member.getId(), pg.getId(), inviteTimestamp); try { - clientHelper.verifySignature(creatorSignature, + clientHelper.verifySignature(SIGNING_LABEL_INVITE, creatorSignature, creator.getPublicKey(), token); } catch (GeneralSecurityException e) { throw new InvalidMessageException(e); @@ -146,8 +149,8 @@ class GroupMessageValidator extends BdfMessageValidator { BdfList signed = BdfList.of(g.getId(), m.getTimestamp(), JOIN.getInt(), member.getName(), member.getPublicKey(), invite); try { - clientHelper.verifySignature(memberSignature, member.getPublicKey(), - signed); + clientHelper.verifySignature(SIGNING_LABEL_JOIN, memberSignature, + member.getPublicKey(), signed); } catch (GeneralSecurityException e) { throw new InvalidMessageException(e); } @@ -189,8 +192,8 @@ class GroupMessageValidator extends BdfMessageValidator { member.getName(), member.getPublicKey(), parentId, previousMessageId, content); try { - clientHelper - .verifySignature(signature, member.getPublicKey(), signed); + clientHelper.verifySignature(SIGNING_LABEL_POST, signature, + member.getPublicKey(), signed); } catch (GeneralSecurityException e) { throw new InvalidMessageException(e); } diff --git a/briar-core/src/org/briarproject/privategroup/invitation/GroupInvitationFactoryImpl.java b/briar-core/src/org/briarproject/privategroup/invitation/GroupInvitationFactoryImpl.java index 3e9b8c88c67aaab47b7d9ab8c56e491c4ae93109..502d4f0761aa8ecff8f9b83d7d64ec2a652b0ec0 100644 --- a/briar-core/src/org/briarproject/privategroup/invitation/GroupInvitationFactoryImpl.java +++ b/briar-core/src/org/briarproject/privategroup/invitation/GroupInvitationFactoryImpl.java @@ -36,7 +36,7 @@ class GroupInvitationFactoryImpl implements GroupInvitationFactory { BdfList token = createInviteToken(creatorId, memberId, privateGroupId, timestamp); try { - return clientHelper.sign(token, privateKey); + return clientHelper.sign(SIGNING_LABEL_INVITE, token, privateKey); } catch (GeneralSecurityException e) { throw new IllegalArgumentException(e); } catch (FormatException e) { @@ -50,7 +50,6 @@ class GroupInvitationFactoryImpl implements GroupInvitationFactory { Group contactGroup = contactGroupFactory.createContactGroup(CLIENT_ID, creatorId, memberId); return BdfList.of( - 0, // TODO: Replace with a namespaced string timestamp, contactGroup.getId(), privateGroupId diff --git a/briar-core/src/org/briarproject/privategroup/invitation/GroupInvitationValidator.java b/briar-core/src/org/briarproject/privategroup/invitation/GroupInvitationValidator.java index 15de431499b54f4c3abd969a6626ccf348d392cb..175a593c49903013cadde62cedfbb37433e37489 100644 --- a/briar-core/src/org/briarproject/privategroup/invitation/GroupInvitationValidator.java +++ b/briar-core/src/org/briarproject/privategroup/invitation/GroupInvitationValidator.java @@ -31,6 +31,7 @@ import static org.briarproject.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH import static org.briarproject.api.privategroup.PrivateGroupConstants.GROUP_SALT_LENGTH; import static org.briarproject.api.privategroup.PrivateGroupConstants.MAX_GROUP_INVITATION_MSG_LENGTH; import static org.briarproject.api.privategroup.PrivateGroupConstants.MAX_GROUP_NAME_LENGTH; +import static org.briarproject.api.privategroup.invitation.GroupInvitationFactory.SIGNING_LABEL_INVITE; import static org.briarproject.privategroup.invitation.MessageType.ABORT; import static org.briarproject.privategroup.invitation.MessageType.INVITE; import static org.briarproject.privategroup.invitation.MessageType.JOIN; @@ -96,13 +97,13 @@ class GroupInvitationValidator extends BdfMessageValidator { groupName, creator, salt); // Verify the signature BdfList signed = BdfList.of( - INVITE.getValue(), m.getTimestamp(), m.getGroupId(), privateGroup.getId() ); try { - clientHelper.verifySignature(signature, creatorPublicKey, signed); + clientHelper.verifySignature(SIGNING_LABEL_INVITE, signature, + creatorPublicKey, signed); } catch (GeneralSecurityException e) { throw new FormatException(); } diff --git a/briar-tests/src/org/briarproject/blogs/BlogPostValidatorTest.java b/briar-tests/src/org/briarproject/blogs/BlogPostValidatorTest.java index 08943fc9f163aff322f79df52869069711be0b4c..306b082a6bf55333d6345140a161f0fa76c6a438 100644 --- a/briar-tests/src/org/briarproject/blogs/BlogPostValidatorTest.java +++ b/briar-tests/src/org/briarproject/blogs/BlogPostValidatorTest.java @@ -38,6 +38,8 @@ import static org.briarproject.api.blogs.BlogConstants.KEY_ORIGINAL_PARENT_MSG_I import static org.briarproject.api.blogs.BlogConstants.KEY_PARENT_MSG_ID; import static org.briarproject.api.blogs.BlogConstants.KEY_PUBLIC_KEY; import static org.briarproject.api.blogs.BlogConstants.KEY_READ; +import static org.briarproject.api.blogs.BlogPostFactory.SIGNING_LABEL_COMMENT; +import static org.briarproject.api.blogs.BlogPostFactory.SIGNING_LABEL_POST; import static org.briarproject.api.blogs.MessageType.COMMENT; import static org.briarproject.api.blogs.MessageType.POST; import static org.briarproject.api.blogs.MessageType.WRAPPED_COMMENT; @@ -101,7 +103,7 @@ public class BlogPostValidatorTest extends BriarTestCase { BdfList signed = BdfList.of(blog.getId(), message.getTimestamp(), body); - expectCrypto(signed, sigBytes); + expectCrypto(SIGNING_LABEL_POST, signed, sigBytes); final BdfDictionary result = validator.validateMessage(message, group, m).getDictionary(); @@ -143,7 +145,7 @@ public class BlogPostValidatorTest extends BriarTestCase { BdfList signed = BdfList.of(blog.getId(), message.getTimestamp(), comment, pOriginalId, currentId); - expectCrypto(signed, sigBytes); + expectCrypto(SIGNING_LABEL_COMMENT, signed, sigBytes); final BdfDictionary result = validator.validateMessage(message, group, m).getDictionary(); @@ -170,7 +172,7 @@ public class BlogPostValidatorTest extends BriarTestCase { BdfList signed = BdfList.of(blog.getId(), message.getTimestamp(), null, originalId, currentId); - expectCrypto(signed, sigBytes); + expectCrypto(SIGNING_LABEL_COMMENT, signed, sigBytes); final BdfDictionary result = validator.validateMessage(message, group, m).getDictionary(); @@ -189,7 +191,7 @@ public class BlogPostValidatorTest extends BriarTestCase { BdfList signed = BdfList.of(blog.getId(), message.getTimestamp(), body); - expectCrypto(signed, sigBytes); + expectCrypto(SIGNING_LABEL_POST, signed, sigBytes); final BdfList originalList = BdfList.of(POST.getInt(), body, sigBytes); final byte[] originalBody = TestUtils.getRandomBytes(42); @@ -228,7 +230,7 @@ public class BlogPostValidatorTest extends BriarTestCase { BdfList signed = BdfList.of(blog.getId(), message.getTimestamp(), comment, originalId, oldId); - expectCrypto(signed, sigBytes); + expectCrypto(SIGNING_LABEL_COMMENT, signed, sigBytes); final BdfList originalList = BdfList.of(COMMENT.getInt(), comment, originalId, oldId, sigBytes); @@ -256,13 +258,13 @@ public class BlogPostValidatorTest extends BriarTestCase { context.assertIsSatisfied(); } - private void expectCrypto(final BdfList signed, final byte[] sig) - throws IOException, GeneralSecurityException { + private void expectCrypto(final String label, final BdfList signed, + final byte[] sig) throws IOException, GeneralSecurityException { context.checking(new Expectations() {{ oneOf(blogFactory).parseBlog(group); will(returnValue(blog)); oneOf(clientHelper) - .verifySignature(sig, author.getPublicKey(), signed); + .verifySignature(label, sig, author.getPublicKey(), signed); }}); } diff --git a/briar-tests/src/org/briarproject/clients/ClientHelperImplTest.java b/briar-tests/src/org/briarproject/clients/ClientHelperImplTest.java index 73e17616a1f842d4cd64d30e290bc2e8df957a09..ccea806ff2037885b5580e02eb341da66816fb71 100644 --- a/briar-tests/src/org/briarproject/clients/ClientHelperImplTest.java +++ b/briar-tests/src/org/briarproject/clients/ClientHelperImplTest.java @@ -1,13 +1,10 @@ package org.briarproject.clients; import org.briarproject.BriarTestCase; +import org.briarproject.TestUtils; import org.briarproject.api.FormatException; import org.briarproject.api.clients.ClientHelper; import org.briarproject.api.crypto.CryptoComponent; -import org.briarproject.api.crypto.KeyParser; -import org.briarproject.api.crypto.PrivateKey; -import org.briarproject.api.crypto.PublicKey; -import org.briarproject.api.crypto.Signature; import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.data.BdfEntry; import org.briarproject.api.data.BdfList; @@ -57,8 +54,6 @@ public class ClientHelperImplTest extends BriarTestCase { context.mock(MetadataEncoder.class); private final CryptoComponent cryptoComponent = context.mock(CryptoComponent.class); - private final KeyParser keyParser = context.mock(KeyParser.class); - private final Signature signature = context.mock(Signature.class); private final ClientHelper clientHelper; private final GroupId groupId = new GroupId(getRandomId()); @@ -70,6 +65,7 @@ public class ClientHelperImplTest extends BriarTestCase { new Message(messageId, groupId, timestamp, rawMessage); private final Metadata metadata = new Metadata(); private final BdfList list = BdfList.of("Sign this!", getRandomBytes(42)); + private final String label = TestUtils.getRandomString(5); public ClientHelperImplTest() { clientHelper = @@ -284,72 +280,46 @@ public class ClientHelperImplTest extends BriarTestCase { @Test public void testSign() throws Exception { - final byte[] privateKeyBytes = getRandomBytes(42); - final PrivateKey privateKey = context.mock(PrivateKey.class); + final byte[] privateKey = getRandomBytes(42); final byte[] signed = getRandomBytes(42); final byte[] bytes = expectToByteArray(list); context.checking(new Expectations() {{ - oneOf(cryptoComponent).getSignature(); - will(returnValue(signature)); - oneOf(cryptoComponent).getSignatureKeyParser(); - will(returnValue(keyParser)); - oneOf(keyParser).parsePrivateKey(privateKeyBytes); - will(returnValue(privateKey)); - oneOf(signature).initSign(privateKey); - oneOf(signature).update(bytes); - oneOf(signature).sign(); + oneOf(cryptoComponent).sign(label, bytes, privateKey); will(returnValue(signed)); }}); - assertArrayEquals(signed, clientHelper.sign(list, privateKeyBytes)); + assertArrayEquals(signed, clientHelper.sign(label, list, privateKey)); context.assertIsSatisfied(); } @Test public void testVerifySignature() throws Exception { - final PublicKey publicKey = context.mock(PublicKey.class); - final byte[] publicKeyBytes = getRandomBytes(42); - + final byte[] publicKey = getRandomBytes(42); final byte[] bytes = expectToByteArray(list); + context.checking(new Expectations() {{ - oneOf(cryptoComponent).getSignatureKeyParser(); - will(returnValue(keyParser)); - oneOf(keyParser).parsePublicKey(publicKeyBytes); - will(returnValue(publicKey)); - oneOf(cryptoComponent).getSignature(); - will(returnValue(signature)); - oneOf(signature).initVerify(publicKey); - oneOf(signature).update(bytes); - oneOf(signature).verify(rawMessage); + oneOf(cryptoComponent).verify(label, bytes, publicKey, rawMessage); will(returnValue(true)); }}); - clientHelper.verifySignature(rawMessage, publicKeyBytes, list); + clientHelper.verifySignature(label, rawMessage, publicKey, list); context.assertIsSatisfied(); } @Test public void testVerifyWrongSignature() throws Exception { - final PublicKey publicKey = context.mock(PublicKey.class); - final byte[] publicKeyBytes = getRandomBytes(42); - + final byte[] publicKey = getRandomBytes(42); final byte[] bytes = expectToByteArray(list); + context.checking(new Expectations() {{ - oneOf(cryptoComponent).getSignatureKeyParser(); - will(returnValue(keyParser)); - oneOf(keyParser).parsePublicKey(publicKeyBytes); - will(returnValue(publicKey)); - oneOf(cryptoComponent).getSignature(); - will(returnValue(signature)); - oneOf(signature).initVerify(publicKey); - oneOf(signature).update(bytes); - oneOf(signature).verify(rawMessage); + oneOf(cryptoComponent).verify(label, bytes, publicKey, rawMessage); will(returnValue(false)); }}); try { - clientHelper.verifySignature(rawMessage, publicKeyBytes, list); + clientHelper + .verifySignature(label, rawMessage, publicKey, list); fail(); } catch (GeneralSecurityException e) { // expected diff --git a/briar-tests/src/org/briarproject/crypto/KeyEncodingAndParsingTest.java b/briar-tests/src/org/briarproject/crypto/KeyEncodingAndParsingTest.java index d35da2762e08cc1f24e735a486d236162f2abc8b..b7abf54fb45abfe18a4d6648a2dd0e4301a3c551 100644 --- a/briar-tests/src/org/briarproject/crypto/KeyEncodingAndParsingTest.java +++ b/briar-tests/src/org/briarproject/crypto/KeyEncodingAndParsingTest.java @@ -7,7 +7,6 @@ import org.briarproject.api.crypto.KeyPair; import org.briarproject.api.crypto.KeyParser; import org.briarproject.api.crypto.PrivateKey; import org.briarproject.api.crypto.PublicKey; -import org.briarproject.api.crypto.Signature; import org.junit.Test; import java.security.GeneralSecurityException; @@ -102,15 +101,13 @@ public class KeyEncodingAndParsingTest extends BriarTestCase { @Test public void testSignatureLength() throws Exception { - Signature sig = crypto.getSignature(); // Generate 10 signature key pairs for (int i = 0; i < 10; i++) { KeyPair keyPair = crypto.generateSignatureKeyPair(); + byte[] key = keyPair.getPrivate().getEncoded(); // Sign some random data and check the length of the signature byte[] toBeSigned = TestUtils.getRandomBytes(1234); - sig.initSign(keyPair.getPrivate()); - sig.update(toBeSigned); - byte[] signature = sig.sign(); + byte[] signature = crypto.sign("label", toBeSigned, key); assertTrue(signature.length <= MAX_SIGNATURE_LENGTH); } } diff --git a/briar-tests/src/org/briarproject/crypto/MacTest.java b/briar-tests/src/org/briarproject/crypto/MacTest.java index 336d90952ca4c5dd990a72dddcb67862b902e630..c63fa66c299d864df7d875d051dfbfbe6dc9956a 100644 --- a/briar-tests/src/org/briarproject/crypto/MacTest.java +++ b/briar-tests/src/org/briarproject/crypto/MacTest.java @@ -16,18 +16,17 @@ public class MacTest extends BriarTestCase { private final CryptoComponent crypto; + private final SecretKey k = TestUtils.getSecretKey(); + private final byte[] inputBytes = TestUtils.getRandomBytes(123); + private final byte[] inputBytes1 = TestUtils.getRandomBytes(234); + private final byte[] inputBytes2 = new byte[0]; + public MacTest() { crypto = new CryptoComponentImpl(new TestSeedProvider()); } @Test public void testIdenticalKeysAndInputsProduceIdenticalMacs() { - // Generate a random key and some random input - byte[] keyBytes = TestUtils.getRandomBytes(SecretKey.LENGTH); - SecretKey k = new SecretKey(keyBytes); - byte[] inputBytes = TestUtils.getRandomBytes(123); - byte[] inputBytes1 = TestUtils.getRandomBytes(234); - byte[] inputBytes2 = new byte[0]; // Calculate the MAC twice - the results should be identical byte[] mac = crypto.mac(k, inputBytes, inputBytes1, inputBytes2); byte[] mac1 = crypto.mac(k, inputBytes, inputBytes1, inputBytes2); @@ -36,14 +35,8 @@ public class MacTest extends BriarTestCase { @Test public void testDifferentKeysProduceDifferentMacs() { - // Generate two random keys and some random input - byte[] keyBytes = TestUtils.getRandomBytes(SecretKey.LENGTH); - SecretKey k = new SecretKey(keyBytes); - byte[] keyBytes1 = TestUtils.getRandomBytes(SecretKey.LENGTH); - SecretKey k1 = new SecretKey(keyBytes1); - byte[] inputBytes = TestUtils.getRandomBytes(123); - byte[] inputBytes1 = TestUtils.getRandomBytes(234); - byte[] inputBytes2 = new byte[0]; + // Generate second random key + SecretKey k1 = TestUtils.getSecretKey(); // Calculate the MAC with each key - the results should be different byte[] mac = crypto.mac(k, inputBytes, inputBytes1, inputBytes2); byte[] mac1 = crypto.mac(k1, inputBytes, inputBytes1, inputBytes2); @@ -52,16 +45,11 @@ public class MacTest extends BriarTestCase { @Test public void testDifferentInputsProduceDifferentMacs() { - // Generate a random key and some random input - byte[] keyBytes = TestUtils.getRandomBytes(SecretKey.LENGTH); - SecretKey k = new SecretKey(keyBytes); - byte[] inputBytes = TestUtils.getRandomBytes(123); - byte[] inputBytes1 = TestUtils.getRandomBytes(234); - byte[] inputBytes2 = new byte[0]; // Calculate the MAC with the inputs in different orders - the results // should be different byte[] mac = crypto.mac(k, inputBytes, inputBytes1, inputBytes2); byte[] mac1 = crypto.mac(k, inputBytes2, inputBytes1, inputBytes); assertFalse(Arrays.equals(mac, mac1)); } + } diff --git a/briar-tests/src/org/briarproject/crypto/SignatureTest.java b/briar-tests/src/org/briarproject/crypto/SignatureTest.java new file mode 100644 index 0000000000000000000000000000000000000000..36d718540867bfe7eeec612db75605eef8c81861 --- /dev/null +++ b/briar-tests/src/org/briarproject/crypto/SignatureTest.java @@ -0,0 +1,109 @@ +package org.briarproject.crypto; + +import org.briarproject.BriarTestCase; +import org.briarproject.TestSeedProvider; +import org.briarproject.TestUtils; +import org.briarproject.api.crypto.CryptoComponent; +import org.briarproject.api.crypto.KeyPair; +import org.junit.Test; + +import java.util.Arrays; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class SignatureTest extends BriarTestCase { + + private final CryptoComponent crypto; + + private final byte[] publicKey, privateKey; + private final String label = TestUtils.getRandomString(42); + private final byte[] inputBytes = TestUtils.getRandomBytes(123); + + public SignatureTest() { + crypto = new CryptoComponentImpl(new TestSeedProvider()); + KeyPair k = crypto.generateSignatureKeyPair(); + publicKey = k.getPublic().getEncoded(); + privateKey = k.getPrivate().getEncoded(); + } + + @Test + public void testIdenticalKeysAndInputsProduceIdenticalSignatures() + throws Exception { + // Calculate the Signature twice - the results should be identical + byte[] sig1 = crypto.sign(label, inputBytes, privateKey); + byte[] sig2 = crypto.sign(label, inputBytes, privateKey); + assertArrayEquals(sig1, sig2); + } + + @Test + public void testDifferentKeysProduceDifferentSignatures() throws Exception { + // Generate second private key + KeyPair k2 = crypto.generateSignatureKeyPair(); + byte[] privateKey2 = k2.getPrivate().getEncoded(); + // Calculate the signature with each key + byte[] sig1 = crypto.sign(label, inputBytes, privateKey); + byte[] sig2 = crypto.sign(label, inputBytes, privateKey2); + assertFalse(Arrays.equals(sig1, sig2)); + } + + @Test + public void testDifferentInputsProduceDifferentSignatures() + throws Exception { + // Generate a second input + byte[] inputBytes2 = TestUtils.getRandomBytes(123); + // Calculate the signature with different inputs + // the results should be different + byte[] sig1 = crypto.sign(label, inputBytes, privateKey); + byte[] sig2 = crypto.sign(label, inputBytes2, privateKey); + assertFalse(Arrays.equals(sig1, sig2)); + } + + @Test + public void testDifferentLabelsProduceDifferentSignatures() + throws Exception { + // Generate a second label + String label2 = TestUtils.getRandomString(42); + // Calculate the signature with different inputs + // the results should be different + byte[] sig1 = crypto.sign(label, inputBytes, privateKey); + byte[] sig2 = crypto.sign(label2, inputBytes, privateKey); + assertFalse(Arrays.equals(sig1, sig2)); + } + + @Test + public void testSignatureVerification() throws Exception { + byte[] sig = crypto.sign(label, inputBytes, privateKey); + assertTrue(crypto.verify(label, inputBytes, publicKey, sig)); + } + + @Test + public void testDifferentKeyFailsVerification() throws Exception { + // Generate second private key + KeyPair k2 = crypto.generateSignatureKeyPair(); + byte[] privateKey2 = k2.getPrivate().getEncoded(); + // calculate the signature with different key, should fail to verify + byte[] sig = crypto.sign(label, inputBytes, privateKey2); + assertFalse(crypto.verify(label, inputBytes, publicKey, sig)); + } + + @Test + public void testDifferentInputFailsVerification() throws Exception { + // Generate a second input + byte[] inputBytes2 = TestUtils.getRandomBytes(123); + // calculate the signature with different input, should fail to verify + byte[] sig = crypto.sign(label, inputBytes, privateKey); + assertFalse(crypto.verify(label, inputBytes2, publicKey, sig)); + } + + @Test + public void testDifferentLabelFailsVerification() throws Exception { + // Generate a second label + String label2 = TestUtils.getRandomString(42); + // calculate the signature with different label, should fail to verify + byte[] sig = crypto.sign(label, inputBytes, privateKey); + assertFalse(crypto.verify(label2, inputBytes, publicKey, sig)); + } + +} diff --git a/briar-tests/src/org/briarproject/forum/ForumPostValidatorTest.java b/briar-tests/src/org/briarproject/forum/ForumPostValidatorTest.java index 17e5c1266dca74739f381392f5deb9815fa34dfb..af048f6f1a7e68d14d7fb9d07f7fb489bd4179fd 100644 --- a/briar-tests/src/org/briarproject/forum/ForumPostValidatorTest.java +++ b/briar-tests/src/org/briarproject/forum/ForumPostValidatorTest.java @@ -19,6 +19,7 @@ import java.security.GeneralSecurityException; import java.util.Collection; import static org.briarproject.api.forum.ForumConstants.MAX_FORUM_POST_BODY_LENGTH; +import static org.briarproject.api.forum.ForumPostFactory.SIGNING_LABEL_POST; import static org.briarproject.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; import static org.briarproject.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH; @@ -70,8 +71,8 @@ public class ForumPostValidatorTest extends ValidatorTestCase { context.checking(new Expectations() {{ oneOf(authorFactory).createAuthor(authorName, authorPublicKey); will(returnValue(author)); - oneOf(clientHelper).verifySignature(signature, authorPublicKey, - signedWithoutParent); + oneOf(clientHelper).verifySignature(SIGNING_LABEL_POST, signature, + authorPublicKey, signedWithoutParent); }}); ForumPostValidator v = new ForumPostValidator(authorFactory, @@ -179,8 +180,8 @@ public class ForumPostValidatorTest extends ValidatorTestCase { context.checking(new Expectations() {{ oneOf(authorFactory).createAuthor(shortAuthorName, authorPublicKey); will(returnValue(shortNameAuthor)); - oneOf(clientHelper).verifySignature(signature, authorPublicKey, - signedWithShortNameAuthor); + oneOf(clientHelper).verifySignature(SIGNING_LABEL_POST, signature, + authorPublicKey, signedWithShortNameAuthor); }}); ForumPostValidator v = new ForumPostValidator(authorFactory, @@ -267,8 +268,8 @@ public class ForumPostValidatorTest extends ValidatorTestCase { context.checking(new Expectations() {{ oneOf(authorFactory).createAuthor(authorName, authorPublicKey); will(returnValue(author)); - oneOf(clientHelper).verifySignature(signature, authorPublicKey, - signedWithShortContent); + oneOf(clientHelper).verifySignature(SIGNING_LABEL_POST, signature, + authorPublicKey, signedWithShortContent); }}); ForumPostValidator v = new ForumPostValidator(authorFactory, @@ -342,8 +343,8 @@ public class ForumPostValidatorTest extends ValidatorTestCase { context.checking(new Expectations() {{ oneOf(authorFactory).createAuthor(authorName, authorPublicKey); will(returnValue(author)); - oneOf(clientHelper).verifySignature(signature, authorPublicKey, - signedWithParent); + oneOf(clientHelper).verifySignature(SIGNING_LABEL_POST, signature, + authorPublicKey, signedWithParent); will(throwException(new FormatException())); }}); @@ -359,8 +360,8 @@ public class ForumPostValidatorTest extends ValidatorTestCase { context.checking(new Expectations() {{ oneOf(authorFactory).createAuthor(authorName, authorPublicKey); will(returnValue(author)); - oneOf(clientHelper).verifySignature(signature, authorPublicKey, - signedWithParent); + oneOf(clientHelper).verifySignature(SIGNING_LABEL_POST, signature, + authorPublicKey, signedWithParent); will(throwException(new GeneralSecurityException())); }}); diff --git a/briar-tests/src/org/briarproject/introduction/IntroduceeManagerTest.java b/briar-tests/src/org/briarproject/introduction/IntroduceeManagerTest.java index 2ac86ea65f61ba6fc18d0404f953d7706416808f..c33b308c665e0f5e9156f5277eb893607d15b300 100644 --- a/briar-tests/src/org/briarproject/introduction/IntroduceeManagerTest.java +++ b/briar-tests/src/org/briarproject/introduction/IntroduceeManagerTest.java @@ -10,10 +10,7 @@ import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactManager; import org.briarproject.api.crypto.CryptoComponent; -import org.briarproject.api.crypto.KeyParser; -import org.briarproject.api.crypto.PublicKey; import org.briarproject.api.crypto.SecretKey; -import org.briarproject.api.crypto.Signature; import org.briarproject.api.data.BdfDictionary; import org.briarproject.api.data.BdfEntry; import org.briarproject.api.data.BdfList; @@ -77,6 +74,7 @@ import static org.briarproject.api.introduction.IntroductionConstants.TYPE_ACK; import static org.briarproject.api.introduction.IntroductionConstants.TYPE_REQUEST; import static org.briarproject.api.introduction.IntroductionConstants.TYPE_RESPONSE; import static org.briarproject.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH; +import static org.briarproject.introduction.IntroduceeManager.SIGNING_LABEL_RESPONSE; import static org.hamcrest.Matchers.array; import static org.hamcrest.Matchers.samePropertyValuesAs; import static org.junit.Assert.assertFalse; @@ -91,11 +89,8 @@ public class IntroduceeManagerTest extends BriarTestCase { private final CryptoComponent cryptoComponent; private final ClientHelper clientHelper; private final IntroductionGroupFactory introductionGroupFactory; - private final MessageSender messageSender; - private final TransportPropertyManager transportPropertyManager; private final AuthorFactory authorFactory; private final ContactManager contactManager; - private final IdentityManager identityManager; private final Clock clock; private final Contact introducer; private final Contact introducee1; @@ -105,24 +100,24 @@ public class IntroduceeManagerTest extends BriarTestCase { private final Transaction txn; private final long time = 42L; private final Message localStateMessage; - private final ClientId clientId; private final SessionId sessionId; private final Message message1; public IntroduceeManagerTest() { context = new Mockery(); context.setImposteriser(ClassImposteriser.INSTANCE); - messageSender = context.mock(MessageSender.class); + MessageSender messageSender = context.mock(MessageSender.class); db = context.mock(DatabaseComponent.class); cryptoComponent = context.mock(CryptoComponent.class); clientHelper = context.mock(ClientHelper.class); clock = context.mock(Clock.class); introductionGroupFactory = context.mock(IntroductionGroupFactory.class); - transportPropertyManager = context.mock(TransportPropertyManager.class); + TransportPropertyManager transportPropertyManager = + context.mock(TransportPropertyManager.class); authorFactory = context.mock(AuthorFactory.class); contactManager = context.mock(ContactManager.class); - identityManager = context.mock(IdentityManager.class); + IdentityManager identityManager = context.mock(IdentityManager.class); introduceeManager = new IntroduceeManager(messageSender, db, clientHelper, clock, cryptoComponent, transportPropertyManager, @@ -152,7 +147,7 @@ public class IntroduceeManagerTest extends BriarTestCase { introducee2 = new Contact(contactId2, author2, localAuthorId, true, true); - clientId = IntroductionManagerImpl.CLIENT_ID; + ClientId clientId = IntroductionManagerImpl.CLIENT_ID; localGroup1 = new Group(new GroupId(TestUtils.getRandomId()), clientId, new byte[0]); introductionGroup1 = new Group(new GroupId(TestUtils.getRandomId()), @@ -270,20 +265,9 @@ public class IntroduceeManagerTest extends BriarTestCase { new BdfEntry(SIGNATURE, sig) ); - final KeyParser keyParser = context.mock(KeyParser.class); - final PublicKey publicKey = context.mock(PublicKey.class); - final Signature signature = context.mock(Signature.class); context.checking(new Expectations() {{ - oneOf(cryptoComponent).getSignatureKeyParser(); - will(returnValue(keyParser)); - oneOf(keyParser) - .parsePublicKey(introducee2.getAuthor().getPublicKey()); - will(returnValue(publicKey)); - oneOf(cryptoComponent).getSignature(); - will(returnValue(signature)); - oneOf(signature).initVerify(publicKey); - oneOf(signature).update(nonce); - oneOf(signature).verify(sig); + oneOf(cryptoComponent).verify(SIGNING_LABEL_RESPONSE, nonce, + introducee2.getAuthor().getPublicKey(), sig); will(returnValue(false)); }}); @@ -311,19 +295,9 @@ public class IntroduceeManagerTest extends BriarTestCase { state.put(NONCE, nonce); state.put(SIGNATURE, sig); - final KeyParser keyParser = context.mock(KeyParser.class); - final Signature signature = context.mock(Signature.class); - final PublicKey publicKey = context.mock(PublicKey.class); context.checking(new Expectations() {{ - oneOf(cryptoComponent).getSignatureKeyParser(); - will(returnValue(keyParser)); - oneOf(keyParser).parsePublicKey(publicKeyBytes); - will(returnValue(publicKey)); - oneOf(cryptoComponent).getSignature(); - will(returnValue(signature)); - oneOf(signature).initVerify(publicKey); - oneOf(signature).update(nonce); - oneOf(signature).verify(sig); + oneOf(cryptoComponent).verify(SIGNING_LABEL_RESPONSE, nonce, + publicKeyBytes, sig); will(returnValue(true)); }}); introduceeManager.verifySignature(state);