From d129186bab76d305c97c574805276b027c50c19b Mon Sep 17 00:00:00 2001 From: ameba23 Date: Tue, 30 Mar 2021 12:06:45 +0200 Subject: [PATCH] social backup exchange --- .../socialbackup/BackupPayloadEncoder.java | 2 +- .../BackupPayloadEncoderImpl.java | 4 +- .../briar/socialbackup/MessageEncoder.java | 2 +- .../socialbackup/MessageEncoderImpl.java | 2 +- .../briar/socialbackup/MessageParser.java | 2 +- .../briar/socialbackup/MessageParserImpl.java | 4 +- .../SocialBackupExchangeManagerImpl.java | 265 +++++++++--------- .../SocialBackupExchangeRecordTypes.java | 5 + .../socialbackup/SocialBackupManagerImpl.java | 1 + 9 files changed, 154 insertions(+), 133 deletions(-) diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/BackupPayloadEncoder.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/BackupPayloadEncoder.java index 45341fdc1..b65f027da 100644 --- a/briar-core/src/main/java/org/briarproject/briar/socialbackup/BackupPayloadEncoder.java +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/BackupPayloadEncoder.java @@ -9,6 +9,6 @@ import java.util.List; @NotNullByDefault interface BackupPayloadEncoder { - BackupPayload encodeBackupPayload(SecretKey secret, Identity identity, + org.briarproject.briar.api.socialbackup.BackupPayload encodeBackupPayload(SecretKey secret, Identity identity, List contactData, int version); } diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/BackupPayloadEncoderImpl.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/BackupPayloadEncoderImpl.java index c7953afc8..6ab55af71 100644 --- a/briar-core/src/main/java/org/briarproject/briar/socialbackup/BackupPayloadEncoderImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/BackupPayloadEncoderImpl.java @@ -44,7 +44,7 @@ class BackupPayloadEncoderImpl implements BackupPayloadEncoder { } @Override - public BackupPayload encodeBackupPayload(SecretKey secret, + public org.briarproject.briar.api.socialbackup.BackupPayload encodeBackupPayload(SecretKey secret, Identity identity, List contactData, int version) { // Encode the local identity BdfList bdfIdentity = new BdfList(); @@ -83,7 +83,7 @@ class BackupPayloadEncoderImpl implements BackupPayloadEncoder { int encrypted = cipher.process(plaintext, 0, plaintext.length, ciphertext, 0); if (encrypted != ciphertext.length) throw new AssertionError(); - return new BackupPayload(ciphertext); + return new org.briarproject.briar.api.socialbackup.BackupPayload(ciphertext); } catch (FormatException | GeneralSecurityException e) { throw new AssertionError(e); } diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/MessageEncoder.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/MessageEncoder.java index e2c8ce23a..b386b6174 100644 --- a/briar-core/src/main/java/org/briarproject/briar/socialbackup/MessageEncoder.java +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/MessageEncoder.java @@ -8,5 +8,5 @@ interface MessageEncoder { byte[] encodeShardMessage(Shard shard); - byte[] encodeBackupMessage(int version, BackupPayload payload); + byte[] encodeBackupMessage(int version, org.briarproject.briar.api.socialbackup.BackupPayload payload); } diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/MessageEncoderImpl.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/MessageEncoderImpl.java index 3214ee66c..e61ce8638 100644 --- a/briar-core/src/main/java/org/briarproject/briar/socialbackup/MessageEncoderImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/MessageEncoderImpl.java @@ -34,7 +34,7 @@ class MessageEncoderImpl implements MessageEncoder { } @Override - public byte[] encodeBackupMessage(int version, BackupPayload payload) { + public byte[] encodeBackupMessage(int version, org.briarproject.briar.api.socialbackup.BackupPayload payload) { BdfList body = BdfList.of( BACKUP.getValue(), version, diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/MessageParser.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/MessageParser.java index 36dbe6ea9..662e7ab77 100644 --- a/briar-core/src/main/java/org/briarproject/briar/socialbackup/MessageParser.java +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/MessageParser.java @@ -10,5 +10,5 @@ interface MessageParser { Shard parseShardMessage(BdfList body) throws FormatException; - BackupPayload parseBackupMessage(BdfList body) throws FormatException; + org.briarproject.briar.api.socialbackup.BackupPayload parseBackupMessage(BdfList body) throws FormatException; } diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/MessageParserImpl.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/MessageParserImpl.java index 962a12c07..e881da164 100644 --- a/briar-core/src/main/java/org/briarproject/briar/socialbackup/MessageParserImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/MessageParserImpl.java @@ -25,9 +25,9 @@ class MessageParserImpl implements MessageParser { } @Override - public BackupPayload parseBackupMessage(BdfList body) + public org.briarproject.briar.api.socialbackup.BackupPayload parseBackupMessage(BdfList body) throws FormatException { // Message type, backup payload - return new BackupPayload(body.getRaw(1)); + return new org.briarproject.briar.api.socialbackup.BackupPayload(body.getRaw(1)); } } diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/SocialBackupExchangeManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/SocialBackupExchangeManagerImpl.java index 44ea7a932..8f4f90619 100644 --- a/briar-core/src/main/java/org/briarproject/briar/socialbackup/SocialBackupExchangeManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/SocialBackupExchangeManagerImpl.java @@ -3,17 +3,16 @@ package org.briarproject.briar.socialbackup; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.Predicate; import org.briarproject.bramble.api.client.ClientHelper; -import org.briarproject.bramble.api.contact.Contact; +import org.briarproject.bramble.api.contact.ContactExchangeConstants; import org.briarproject.bramble.api.contact.ContactExchangeManager; +import org.briarproject.bramble.api.contact.ContactExchangeRecordTypes; import org.briarproject.bramble.api.contact.ContactManager; -import org.briarproject.bramble.api.contact.PendingContactId; import org.briarproject.bramble.api.crypto.PublicKey; import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.data.BdfDictionary; import org.briarproject.bramble.api.data.BdfList; import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DbException; -import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; @@ -30,7 +29,11 @@ import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.transport.StreamReaderFactory; import org.briarproject.bramble.api.transport.StreamWriter; import org.briarproject.bramble.api.transport.StreamWriterFactory; -import org.briarproject.bramble.contact.ContactExchangeCrypto; +import org.briarproject.bramble.api.contact.ContactExchangeCrypto; +import org.briarproject.briar.api.socialbackup.ReturnShardPayload; +import org.briarproject.briar.api.socialbackup.Shard; +import org.briarproject.briar.api.socialbackup.BackupPayload; +import org.briarproject.briar.api.socialbackup.SocialBackupExchangeManager; import java.io.EOFException; import java.io.IOException; @@ -43,28 +46,30 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; +import sun.java2d.xr.XRBackendNative; + import static java.util.logging.Logger.getLogger; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH; -import static org.briarproject.bramble.contact.ContactExchangeConstants.PROTOCOL_VERSION; -import static org.briarproject.bramble.contact.ContactExchangeRecordTypes.CONTACT_INFO; import static org.briarproject.bramble.util.ValidationUtils.checkLength; import static org.briarproject.bramble.util.ValidationUtils.checkSize; @Immutable @NotNullByDefault -class SocialBackupExchangeManagerImpl implements ContactExchangeManager { +class SocialBackupExchangeManagerImpl implements SocialBackupExchangeManager { private static final Logger LOG = getLogger(SocialBackupExchangeManagerImpl.class.getName()); // Accept records with current protocol version, known record type private static final Predicate ACCEPT = r -> - r.getProtocolVersion() == ContactExchangeConstants.PROTOCOL_VERSION && + r.getProtocolVersion() == + ContactExchangeConstants.PROTOCOL_VERSION && isKnownRecordType(r.getRecordType()); // Ignore records with current protocol version, unknown record type private static final Predicate IGNORE = r -> - r.getProtocolVersion() == ContactExchangeConstants.PROTOCOL_VERSION && + r.getProtocolVersion() == + ContactExchangeConstants.PROTOCOL_VERSION && !isKnownRecordType(r.getRecordType()); private static boolean isKnownRecordType(byte type) { @@ -77,17 +82,19 @@ class SocialBackupExchangeManagerImpl implements ContactExchangeManager { private final RecordWriterFactory recordWriterFactory; private final Clock clock; private final ContactManager contactManager; - private final IdentityManager identityManager; + // private final IdentityManager identityManager; private final TransportPropertyManager transportPropertyManager; private final ContactExchangeCrypto contactExchangeCrypto; private final StreamReaderFactory streamReaderFactory; private final StreamWriterFactory streamWriterFactory; @Inject - SocialBackupExchangeManagerImpl(DatabaseComponent db, ClientHelper clientHelper, + SocialBackupExchangeManagerImpl(DatabaseComponent db, + ClientHelper clientHelper, RecordReaderFactory recordReaderFactory, RecordWriterFactory recordWriterFactory, Clock clock, - ContactManager contactManager, IdentityManager identityManager, + ContactManager contactManager, +// IdentityManager identityManager, TransportPropertyManager transportPropertyManager, ContactExchangeCrypto contactExchangeCrypto, StreamReaderFactory streamReaderFactory, @@ -98,7 +105,7 @@ class SocialBackupExchangeManagerImpl implements ContactExchangeManager { this.recordWriterFactory = recordWriterFactory; this.clock = clock; this.contactManager = contactManager; - this.identityManager = identityManager; +// this.identityManager = identityManager; this.transportPropertyManager = transportPropertyManager; this.contactExchangeCrypto = contactExchangeCrypto; this.streamReaderFactory = streamReaderFactory; @@ -106,70 +113,16 @@ class SocialBackupExchangeManagerImpl implements ContactExchangeManager { } @Override - public void sendSocialBackup(DuplexTransportConnection conn, - SecretKey masterKey, boolean alice, - boolean verified) throws IOException, DbException { - return exchange(null, conn, masterKey, alice, verified); - } - - @Override - public ReturnShardPayload receiveSocialBackup(DuplexTransportConnection conn, - SecretKey masterKey, boolean verified) throws IOException, DbException { - boolean alice = false; - InputStream in = conn.getReader().getInputStream(); - - Map localProperties = - transportPropertyManager.getLocalProperties(); - - // Derive the header keys for the transport streams - SecretKey remoteHeaderKey = - contactExchangeCrypto.deriveHeaderKey(masterKey, !alice); - - // Create the readers - InputStream streamReader = streamReaderFactory - .createContactExchangeStreamReader(in, remoteHeaderKey); - RecordReader recordReader = - recordReaderFactory.createRecordReader(streamReader); - - long localTimestamp = clock.currentTimeMillis(); - ContactInfo remoteInfo; - remoteInfo = receiveContactInfo(recordReader); - - // Skip any remaining records from the incoming stream - recordReader.readRecord(r -> false, IGNORE); - - // Verify the contact's signature - PublicKey remotePublicKey = remoteInfo.author.getPublicKey(); - if (!contactExchangeCrypto.verify(remotePublicKey, - masterKey, !alice, remoteInfo.signature)) { - LOG.warning("Invalid signature"); - throw new FormatException(); - } - - // The agreed timestamp is the minimum of the peers' timestamps - long timestamp = Math.min(localTimestamp, remoteInfo.timestamp); - - // Contact exchange succeeded - LOG.info("Received social backup"); - return contact; - } - -// @Override -// public Contact exchangeContacts(PendingContactId p, -// DuplexTransportConnection conn, SecretKey masterKey, boolean alice, -// boolean verified) throws IOException, DbException { -// return exchange(p, conn, masterKey, alice, verified); -// } - - private Contact exchange(@Nullable PendingContactId p, - DuplexTransportConnection conn, SecretKey masterKey, boolean alice, + public void sendReturnShard(DuplexTransportConnection conn, + SecretKey masterKey, boolean verified) throws IOException, DbException { + boolean alice = true; // Get the transport connection's input and output streams InputStream in = conn.getReader().getInputStream(); OutputStream out = conn.getWriter().getOutputStream(); // Get the local author and transport properties - LocalAuthor localAuthor = identityManager.getLocalAuthor(); +// LocalAuthor localAuthor = identityManager.getLocalAuthor(); Map localProperties = transportPropertyManager.getLocalProperties(); @@ -192,21 +145,14 @@ class SocialBackupExchangeManagerImpl implements ContactExchangeManager { .createRecordWriter(streamWriter.getOutputStream()); // Create our signature - byte[] localSignature = contactExchangeCrypto - .sign(localAuthor.getPrivateKey(), masterKey, alice); +// byte[] localSignature = contactExchangeCrypto +// .sign(localAuthor.getPrivateKey(), masterKey, alice); // Exchange contact info long localTimestamp = clock.currentTimeMillis(); - ContactInfo remoteInfo; - if (alice) { - sendShardAndBackup(recordWriter, localAuthor, localProperties, - localSignature, localTimestamp); - remoteAcknowledgement = receiveRemoteAcknowledgement(recordReader); - } else { - remoteInfo = receiveContactInfo(recordReader); - sendContactInfo(recordWriter, localAuthor, localProperties, - localSignature, localTimestamp); - } + + sendShardPayload(recordWriter, localProperties, returnShardPayload, localTimestamp); + receiveAcknowledgement(recordReader); // Send EOF on the outgoing stream streamWriter.sendEndOfStream(); @@ -215,71 +161,140 @@ class SocialBackupExchangeManagerImpl implements ContactExchangeManager { recordReader.readRecord(r -> false, IGNORE); // Verify the contact's signature - PublicKey remotePublicKey = remoteInfo.author.getPublicKey(); - if (!contactExchangeCrypto.verify(remotePublicKey, - masterKey, !alice, remoteInfo.signature)) { - LOG.warning("Invalid signature"); - throw new FormatException(); - } +// PublicKey remotePublicKey = remoteInfo.author.getPublicKey(); +// if (!contactExchangeCrypto.verify(remotePublicKey, +// masterKey, !alice, remoteInfo.signature)) { +// LOG.warning("Invalid signature"); +// throw new FormatException(); +// } // The agreed timestamp is the minimum of the peers' timestamps - long timestamp = Math.min(localTimestamp, remoteInfo.timestamp); +// long timestamp = Math.min(localTimestamp, remoteInfo.timestamp); - // Add the contact - Contact contact = addContact(p, remoteInfo.author, localAuthor, - masterKey, timestamp, alice, verified, remoteInfo.properties); + LOG.info("Social backup sent"); + } + + @Override + public ReturnShardPayload receiveReturnShard(DuplexTransportConnection conn, + SecretKey masterKey, boolean verified) + throws IOException, DbException { + boolean alice = false; + // Get the transport connection's input and output streams + InputStream in = conn.getReader().getInputStream(); + OutputStream out = conn.getWriter().getOutputStream(); + + // Get the local author and transport properties +// LocalAuthor localAuthor = identityManager.getLocalAuthor(); + Map localProperties = + transportPropertyManager.getLocalProperties(); + + // Derive the header keys for the transport streams + SecretKey localHeaderKey = + contactExchangeCrypto.deriveHeaderKey(masterKey, alice); + SecretKey remoteHeaderKey = + contactExchangeCrypto.deriveHeaderKey(masterKey, !alice); + + // Create the readers + InputStream streamReader = streamReaderFactory + .createContactExchangeStreamReader(in, remoteHeaderKey); + RecordReader recordReader = + recordReaderFactory.createRecordReader(streamReader); + + // Create the writers + StreamWriter streamWriter = streamWriterFactory + .createContactExchangeStreamWriter(out, localHeaderKey); + RecordWriter recordWriter = recordWriterFactory + .createRecordWriter(streamWriter.getOutputStream()); + + // Create our signature +// byte[] localSignature = contactExchangeCrypto +// .sign(localAuthor.getPrivateKey(), masterKey, alice); + + // Exchange contact info + long localTimestamp = clock.currentTimeMillis(); + ReturnShardPayload returnShardPayload = + receiveShardPayload(recordReader); + sendAcknowledgement(recordWriter, localProperties, localTimestamp); + + // Send EOF on the outgoing stream + streamWriter.sendEndOfStream(); + + // Skip any remaining records from the incoming stream + recordReader.readRecord(r -> false, IGNORE); + + // Verify the contact's signature +// PublicKey remotePublicKey = remoteInfo.author.getPublicKey(); +// if (!contactExchangeCrypto.verify(remotePublicKey, +// masterKey, !alice, remoteInfo.signature)) { +// LOG.warning("Invalid signature"); +// throw new FormatException(); +// } + + // The agreed timestamp is the minimum of the peers' timestamps +// long timestamp = Math.min(localTimestamp, remoteInfo.timestamp); // Contact exchange succeeded - LOG.info("Contact exchange succeeded"); - return contact; + LOG.info("Received shard payload"); + return returnShardPayload; } - private void sendContactInfo(RecordWriter recordWriter, Author author, - Map properties, byte[] signature, + private void sendShardPayload(RecordWriter recordWriter, + Map properties, + ReturnShardPayload returnShardPayload, long timestamp) throws IOException { - BdfList authorList = clientHelper.toList(author); +// BdfList authorList = clientHelper.toList(author); BdfDictionary props = clientHelper.toDictionary(properties); - BdfList payload = BdfList.of(authorList, props, signature, timestamp); + Shard shard = returnShardPayload.getShard(); + BdfList shardList = BdfList.of(shard.getSecretId(), shard.getShard()); + BdfList payload = BdfList.of(shardList, + returnShardPayload.getBackupPayload().getBytes(), timestamp); recordWriter.writeRecord(new Record( - ContactExchangeConstants.PROTOCOL_VERSION, ContactExchangeRecordTypes.CONTACT_INFO, + ContactExchangeConstants.PROTOCOL_VERSION, + SocialBackupExchangeRecordTypes.RETURN_SHARD, clientHelper.toByteArray(payload))); recordWriter.flush(); - LOG.info("Sent contact info"); + LOG.info("Sent shard and encrypted backup"); } - private ContactInfo receiveContactInfo(RecordReader recordReader) + private ReturnShardPayload receiveShardPayload(RecordReader recordReader) throws IOException { Record record = recordReader.readRecord(ACCEPT, IGNORE); if (record == null) throw new EOFException(); - LOG.info("Received contact info"); + LOG.info("Received shard and encrypted backup"); BdfList payload = clientHelper.toList(record.getPayload()); - checkSize(payload, 4); - Author author = clientHelper.parseAndValidateAuthor(payload.getList(0)); - BdfDictionary props = payload.getDictionary(1); - Map properties = - clientHelper.parseAndValidateTransportPropertiesMap(props); - byte[] signature = payload.getRaw(2); - checkLength(signature, 1, MAX_SIGNATURE_LENGTH); - long timestamp = payload.getLong(3); + checkSize(payload, 3); + BdfList shardList = payload.getList(0); + Shard shard = new Shard(shardList.getRaw(0), shardList.getRaw(1)); + BackupPayload backupPayload = new BackupPayload(payload.getRaw(1)); +// Map properties = +// clientHelper.parseAndValidateTransportPropertiesMap(props); +// byte[] signature = payload.getRaw(2); +// checkLength(signature, 1, MAX_SIGNATURE_LENGTH); + long timestamp = payload.getLong(2); if (timestamp < 0) throw new FormatException(); - return new ContactInfo(author, properties, signature, timestamp); + return new ReturnShardPayload(shard, backupPayload); } + private void sendAcknowledgement(RecordWriter recordWriter, + Map properties, + long timestamp) throws IOException { - private static class ContactInfo { + BdfList payload = BdfList.of(timestamp); - private final Author author; - private final Map properties; - private final byte[] signature; - private final long timestamp; + recordWriter.writeRecord(new Record( + ContactExchangeConstants.PROTOCOL_VERSION, + SocialBackupExchangeRecordTypes.ACKNOWLEDGEMENT, + clientHelper.toByteArray(payload))); + recordWriter.flush(); + } - private ContactInfo(Author author, - Map properties, - byte[] signature, long timestamp) { - this.author = author; - this.properties = properties; - this.signature = signature; - this.timestamp = timestamp; - } + private void receiveAcknowledgement(RecordReader recordReader) + throws IOException { + Record record = recordReader.readRecord(ACCEPT, IGNORE); + if (record == null) throw new EOFException(); + BdfList payload = clientHelper.toList(record.getPayload()); + checkSize(payload, 1); + long timestamp = payload.getLong(0); + if (timestamp < 0) throw new FormatException(); } } diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/SocialBackupExchangeRecordTypes.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/SocialBackupExchangeRecordTypes.java index d83bf2193..ca12e1999 100644 --- a/briar-core/src/main/java/org/briarproject/briar/socialbackup/SocialBackupExchangeRecordTypes.java +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/SocialBackupExchangeRecordTypes.java @@ -1,4 +1,9 @@ package org.briarproject.briar.socialbackup; +/** + * Record types for the return shard protocol. + */ public interface SocialBackupExchangeRecordTypes { + byte RETURN_SHARD = 0; + byte ACKNOWLEDGEMENT = 1; } diff --git a/briar-core/src/main/java/org/briarproject/briar/socialbackup/SocialBackupManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/socialbackup/SocialBackupManagerImpl.java index fb971cee5..9786a7833 100644 --- a/briar-core/src/main/java/org/briarproject/briar/socialbackup/SocialBackupManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/socialbackup/SocialBackupManagerImpl.java @@ -46,6 +46,7 @@ import org.briarproject.briar.api.socialbackup.BackupExistsException; import org.briarproject.briar.api.socialbackup.BackupMetadata; import org.briarproject.briar.api.socialbackup.DarkCrystal; import org.briarproject.briar.api.socialbackup.Shard; +import org.briarproject.briar.api.socialbackup.BackupPayload; import org.briarproject.briar.api.socialbackup.ShardMessageHeader; import org.briarproject.briar.api.socialbackup.ShardReceivedEvent; import org.briarproject.briar.api.socialbackup.SocialBackupManager;