diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java index dd103c6..5953bde 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/ThreadedBulletinBoardClient.java @@ -117,6 +117,11 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple // TODO: Implement } + @Override + public void subscribe(MessageFilterList filterList, MessageHandler messageHandler) { + // TODO: Implement + } + @Override public void close() { super.close(); diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ClientFutureCallback.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ClientFutureCallback.java index 7c5b7b0..54cc63a 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ClientFutureCallback.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ClientFutureCallback.java @@ -1,14 +1,8 @@ package meerkat.bulletinboard.callbacks; import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListeningExecutorService; -import meerkat.bulletinboard.BulletinClientJob; import meerkat.bulletinboard.BulletinClientJobResult; -import meerkat.bulletinboard.BulletinClientWorker; -import meerkat.protobuf.BulletinBoardAPI; - -import java.util.List; /** * This is a future callback used to listen to workers and run on job finish diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/GetRedundancyFutureCallback.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/GetRedundancyFutureCallback.java index 518ed77..719428f 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/GetRedundancyFutureCallback.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/GetRedundancyFutureCallback.java @@ -1,7 +1,7 @@ package meerkat.bulletinboard.callbacks; import com.google.common.util.concurrent.ListeningExecutorService; -import meerkat.bulletinboard.BulletinBoardClient; +import meerkat.bulletinboard.AsyncBulletinBoardClient.*; import meerkat.bulletinboard.BulletinClientJobResult; import meerkat.protobuf.BulletinBoardAPI.*; @@ -13,10 +13,10 @@ import java.util.List; */ public class GetRedundancyFutureCallback extends ClientFutureCallback { - private BulletinBoardClient.ClientCallback callback; + private ClientCallback callback; public GetRedundancyFutureCallback(ListeningExecutorService listeningExecutor, - BulletinBoardClient.ClientCallback callback) { + ClientCallback callback) { super(listeningExecutor); this.callback = callback; } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/PostMessageFutureCallback.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/PostMessageFutureCallback.java index 221ae1a..abd4247 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/PostMessageFutureCallback.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/PostMessageFutureCallback.java @@ -2,13 +2,11 @@ package meerkat.bulletinboard.callbacks; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListeningExecutorService; -import meerkat.bulletinboard.BulletinBoardClient; +import meerkat.bulletinboard.AsyncBulletinBoardClient.*; import meerkat.bulletinboard.BulletinClientJob; import meerkat.bulletinboard.BulletinClientJobResult; import meerkat.bulletinboard.BulletinClientWorker; -import meerkat.protobuf.BulletinBoardAPI; -import java.util.List; /** * This is a future callback used to listen to workers and run on job finish @@ -16,10 +14,10 @@ import java.util.List; */ public class PostMessageFutureCallback extends ClientFutureCallback { - private BulletinBoardClient.ClientCallback callback; + private ClientCallback callback; public PostMessageFutureCallback(ListeningExecutorService listeningExecutor, - BulletinBoardClient.ClientCallback callback) { + ClientCallback callback) { super(listeningExecutor); this.callback = callback; } diff --git a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ReadMessagesFutureCallback.java b/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ReadMessagesFutureCallback.java index 4c43ba2..808b7a6 100644 --- a/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ReadMessagesFutureCallback.java +++ b/bulletin-board-client/src/main/java/meerkat/bulletinboard/callbacks/ReadMessagesFutureCallback.java @@ -1,11 +1,8 @@ package meerkat.bulletinboard.callbacks; -import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListeningExecutorService; -import meerkat.bulletinboard.BulletinBoardClient; -import meerkat.bulletinboard.BulletinClientJob; +import meerkat.bulletinboard.AsyncBulletinBoardClient.*; import meerkat.bulletinboard.BulletinClientJobResult; -import meerkat.bulletinboard.BulletinClientWorker; import meerkat.protobuf.BulletinBoardAPI; import java.util.List; @@ -16,10 +13,10 @@ import java.util.List; */ public class ReadMessagesFutureCallback extends ClientFutureCallback { - private BulletinBoardClient.ClientCallback> callback; + private ClientCallback> callback; public ReadMessagesFutureCallback(ListeningExecutorService listeningExecutor, - BulletinBoardClient.ClientCallback> callback) { + ClientCallback> callback) { super(listeningExecutor); this.callback = callback; } diff --git a/bulletin-board-client/src/test/java/BulletinBoardClientIntegrationTest.java b/bulletin-board-client/src/test/java/BulletinBoardClientIntegrationTest.java index 55f0343..d7ae69c 100644 --- a/bulletin-board-client/src/test/java/BulletinBoardClientIntegrationTest.java +++ b/bulletin-board-client/src/test/java/BulletinBoardClientIntegrationTest.java @@ -1,7 +1,6 @@ import com.google.protobuf.ByteString; import meerkat.bulletinboard.AsyncBulletinBoardClient; -import meerkat.bulletinboard.BulletinBoardClient; -import meerkat.bulletinboard.BulletinBoardClient.ClientCallback; +import meerkat.bulletinboard.AsyncBulletinBoardClient.ClientCallback; import meerkat.bulletinboard.ThreadedBulletinBoardClient; import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.Crypto; diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java index 52bf42b..5f9b461 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java @@ -1,20 +1,29 @@ package meerkat.bulletinboard.sqlserver; +import java.security.InvalidKeyException; +import java.security.cert.CertificateException; import java.sql.*; import java.util.*; +import com.google.protobuf.ByteString; import com.google.protobuf.ProtocolStringList; import meerkat.bulletinboard.BulletinBoardServer; -import meerkat.bulletinboard.sqlserver.mappers.EntryNumMapper; -import meerkat.bulletinboard.sqlserver.mappers.MessageMapper; -import meerkat.bulletinboard.sqlserver.mappers.SignatureMapper; +import meerkat.bulletinboard.sqlserver.mappers.*; + import meerkat.comm.CommunicationException; + +import meerkat.crypto.BatchDigest; +import meerkat.crypto.DigitalSignature; +import meerkat.crypto.concrete.ECDSASignature; +import meerkat.crypto.concrete.SHA256Digest; + import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.Crypto.Signature; import meerkat.protobuf.Crypto.SignatureVerificationKey; -import meerkat.crypto.Digest; -import meerkat.crypto.concrete.SHA256Digest; + + +import static meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer.SQLQueryProvider.*; import javax.sql.DataSource; @@ -23,6 +32,8 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.KeyHolder; + + /** * This is a generic SQL implementation of the BulletinBoardServer API. */ @@ -46,7 +57,12 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ CONNECT_TAG(new String[] {"EntryNum","Tag"}), ADD_SIGNATURE(new String[] {"EntryNum","SignerId","Signature"}), GET_SIGNATURES(new String[] {"EntryNum"}), - GET_MESSAGES(new String[] {}); + GET_MESSAGES(new String[] {}), + GET_BATCH_MESSAGE_ENTRY(new String[] {"SignerId", "BatchId"}), + CHECK_BATCH_LENGTH(new String[] {"SignerId", "BatchId"}), + GET_BATCH_MESSAGE_DATA(new String[] {"SignerId", "BatchId", "StartPosition"}), + INSERT_BATCH_DATA(new String[] {"SignerId", "BatchId", "SerialNum", "Data"}), + CONNECT_BATCH_TAG(new String[] {"SignerId", "BatchId", "Tag"}); private String[] paramNames; @@ -58,6 +74,10 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ return paramNames; } + public String getParamName(int num) { + return paramNames[num]; + } + } /** @@ -152,6 +172,11 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ } + /** + * This method returns the value of the parameter specified in a message filter + * @param messageFilter is the filter + * @return the object parameter for the SQL query embedded in the filter (this depends on the filter type) + */ private Object getParam(MessageFilter messageFilter) { switch (messageFilter.getType()) { @@ -170,7 +195,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ case MAX_MESSAGES: return messageFilter.getMaxMessages(); - default: + default: // Unsupported filter type return null; } @@ -193,7 +218,8 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ protected NamedParameterJdbcTemplate jdbcTemplate; - protected Digest digest; + protected BatchDigest digest; + protected DigitalSignature signer; protected List trusteeSignatureVerificationArray; protected int minTrusteeSignatures; @@ -232,6 +258,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ // TODO write signature reading part. digest = new SHA256Digest(); + signer = new ECDSASignature(); jdbcTemplate = new NamedParameterJdbcTemplate(sqlQueryProvider.getDataSource()); @@ -264,12 +291,12 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ String sql; - sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.INSERT_NEW_TAG); + sql = sqlQueryProvider.getSQLString(QueryType.INSERT_NEW_TAG); Map namedParameters[] = new HashMap[tags.length]; for (int i = 0 ; i < tags.length ; i++){ namedParameters[i] = new HashMap(); - namedParameters[i].put("Tag", tags[i]); + namedParameters[i].put(QueryType.INSERT_NEW_TAG.getParamName(0), tags[i]); } jdbcTemplate.batchUpdate(sql, namedParameters); @@ -316,11 +343,11 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ // Add message to table if needed and store entry number of message. - sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.FIND_MSG_ID); + sql = sqlQueryProvider.getSQLString(QueryType.FIND_MSG_ID); Map namedParameters = new HashMap(); - namedParameters.put("MsgId",msgID); + namedParameters.put(QueryType.FIND_MSG_ID.getParamName(0),msgID); - List entryNums = jdbcTemplate.query(sql, new MapSqlParameterSource(namedParameters), new EntryNumMapper()); + List entryNums = jdbcTemplate.query(sql, new MapSqlParameterSource(namedParameters), new LongMapper()); if (entryNums.size() > 0){ @@ -328,8 +355,8 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ } else{ - sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.INSERT_MSG); - namedParameters.put("Msg", msg.getMsg().toByteArray()); + sql = sqlQueryProvider.getSQLString(QueryType.INSERT_MSG); + namedParameters.put(QueryType.INSERT_MSG.getParamName(0), msg.getMsg().toByteArray()); KeyHolder keyHolder = new GeneratedKeyHolder(); jdbcTemplate.update(sql,new MapSqlParameterSource(namedParameters),keyHolder); @@ -354,14 +381,14 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ // Connect message to tags. - sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.CONNECT_TAG); + sql = sqlQueryProvider.getSQLString(QueryType.CONNECT_TAG); namedParameterArray = new HashMap[tags.length]; for (int i = 0 ; i < tags.length ; i++) { namedParameterArray[i] = new HashMap(); - namedParameterArray[i].put("EntryNum", entryNum); - namedParameterArray[i].put("Tag", tags[i]); + namedParameterArray[i].put(QueryType.CONNECT_TAG.getParamName(0), entryNum); + namedParameterArray[i].put(QueryType.CONNECT_TAG.getParamName(1), tags[i]); } jdbcTemplate.batchUpdate(sql, namedParameterArray); @@ -374,15 +401,15 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ // Connect message to signatures. - sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.ADD_SIGNATURE); + sql = sqlQueryProvider.getSQLString(QueryType.ADD_SIGNATURE); namedParameterArray = new HashMap[signatures.length]; for (int i = 0 ; i < signatures.length ; i++) { namedParameterArray[i] = new HashMap(); - namedParameterArray[i].put("EntryNum", entryNum); - namedParameterArray[i].put("SignerId", signatures[i].getSignerId().toByteArray()); - namedParameterArray[i].put("Signature", signatures[i].toByteArray()); + namedParameterArray[i].put(QueryType.ADD_SIGNATURE.getParamName(0), entryNum); + namedParameterArray[i].put(QueryType.ADD_SIGNATURE.getParamName(1), signatures[i].getSignerId().toByteArray()); + namedParameterArray[i].put(QueryType.ADD_SIGNATURE.getParamName(2), signatures[i].toByteArray()); } jdbcTemplate.batchUpdate(sql,namedParameterArray); @@ -412,7 +439,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ // Check if Tag/Signature tables are required for filtering purposes - sqlBuilder.append(sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.GET_MESSAGES)); + sqlBuilder.append(sqlQueryProvider.getSQLString(QueryType.GET_MESSAGES)); // Add conditions namedParameters = new MapSqlParameterSource(); @@ -434,7 +461,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ sqlBuilder.append(sqlQueryProvider.getCondition(filter.getType(), paramNum)); - SQLQueryProvider.FilterTypeParam filterTypeParam = SQLQueryProvider.FilterTypeParam.getFilterTypeParamName(filter.getType()); + FilterTypeParam filterTypeParam = FilterTypeParam.getFilterTypeParamName(filter.getType()); namedParameters.addValue( filterTypeParam.getParamName() + Integer.toString(paramNum), @@ -457,10 +484,10 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ // Retrieve signatures namedParameters = new MapSqlParameterSource(); - namedParameters.addValue("EntryNum", msgBuilder.getEntryNum()); + namedParameters.addValue(QueryType.GET_SIGNATURES.getParamName(0), msgBuilder.getEntryNum()); List signatures = jdbcTemplate.query( - sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.GET_SIGNATURES), + sqlQueryProvider.getSQLString(QueryType.GET_SIGNATURES), namedParameters, signatureMapper); @@ -478,6 +505,130 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{ } + /** + * This method checks if a specified batch exists and is already closed + * @param signerId is the ID of the publisher of the batch + * @param batchId is the unique (per signer) batch ID + * @return TRUE if the batch is closed and FALSE if it is still open or doesn't exist at all + */ + private boolean isBatchClosed(ByteString signerId, int batchId){ + + String sql = sqlQueryProvider.getSQLString(QueryType.GET_BATCH_MESSAGE_ENTRY); + + MapSqlParameterSource namedParameters = new MapSqlParameterSource(); + namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_ENTRY.getParamName(0), signerId); + namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_ENTRY.getParamName(1), batchId); + + List result = jdbcTemplate.query(sql,namedParameters,new LongMapper()); + + return (result.size() > 0); + + } + + @Override + public BoolMsg beginBatch(BeginBatchMessage message) throws CommunicationException { + + // Check if batch is closed + if (isBatchClosed(message.getSignerId(), message.getBatchId())) { + return BoolMsg.newBuilder().setValue(false).build(); + } + + // Add new tags to table + ProtocolStringList tagList = message.getTagList(); + String[] tags = new String[tagList.size()]; + tags = tagList.toArray(tags); + try { + insertNewTags(tags); + } catch (SQLException e) { + throw new CommunicationException(e.getMessage()); + } + + // Connect tags + String sql = sqlQueryProvider.getSQLString(QueryType.CONNECT_BATCH_TAG); + MapSqlParameterSource namedParameters[] = new MapSqlParameterSource[tags.length]; + + for (int i=0 ; i < tags.length ; i++) { + namedParameters[i] = new MapSqlParameterSource(); + namedParameters[i].addValue(QueryType.CONNECT_BATCH_TAG.getParamName(0),message.getSignerId()); + namedParameters[i].addValue(QueryType.CONNECT_BATCH_TAG.getParamName(1),message.getBatchId()); + namedParameters[i].addValue(QueryType.CONNECT_BATCH_TAG.getParamName(2),tags[i]); + } + + jdbcTemplate.batchUpdate(sql,namedParameters); + + return BoolMsg.newBuilder().setValue(true).build(); + } + + @Override + public BoolMsg postBatchMessage(BatchMessage batchMessage) { + + // Check if batch is closed + if (isBatchClosed(batchMessage.getSignerId(), batchMessage.getBatchId())) { + return BoolMsg.newBuilder().setValue(false).build(); + } + + // Add data + String sql = sqlQueryProvider.getSQLString(QueryType.INSERT_BATCH_DATA); + MapSqlParameterSource namedParameters = new MapSqlParameterSource(); + + namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(0),batchMessage.getSignerId()); + namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(1),batchMessage.getBatchId()); + namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(2),batchMessage.getSerialNum()); + namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(3),batchMessage.getData()); + + jdbcTemplate.update(sql, namedParameters); + + return BoolMsg.newBuilder().setValue(true).build(); + + } + + @Override + public BoolMsg closeBatchMessage(CloseBatchMessage message) throws CommunicationException { + + // Check batch size + + String sql = sqlQueryProvider.getSQLString(QueryType.CHECK_BATCH_LENGTH); + MapSqlParameterSource namedParameters = new MapSqlParameterSource(); + + namedParameters.addValue(QueryType.CHECK_BATCH_LENGTH.getParamName(0),message.getSig().getSignerId()); + namedParameters.addValue(QueryType.CHECK_BATCH_LENGTH.getParamName(1),message.getBatchId()); + + List lengthResult = jdbcTemplate.query(sql, namedParameters, new LongMapper()); + + if (lengthResult.get(0) != message.getBatchLength()) { + return BoolMsg.newBuilder().setValue(false).build(); + } + + // Check signature + + sql = sqlQueryProvider.getSQLString(QueryType.GET_BATCH_MESSAGE_DATA); + namedParameters = new MapSqlParameterSource(); + + namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(0),message.getSig().getSignerId()); + namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1),message.getBatchId()); + namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(2),0); // Read from the beginning + + List batchDataList = jdbcTemplate.query(sql, namedParameters, new BatchDataMapper()); + + try { + signer.initVerify(message.getSig()); + } catch (CertificateException | InvalidKeyException e) { + return BoolMsg.newBuilder().setValue(false).build(); + } + + //TODO: FInish this + + //signer.updateContent(msgStream); + //assertTrue("Signature did not verify!", signer.verify()); + + return null; + } + + @Override + public List readBatch(BatchSpecificationMessage message) { + return null; // TODO: Implement this + } + @Override public void close() {} diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java index c00c044..0093bd5 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java @@ -5,6 +5,7 @@ import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer.SQLQueryProvider; import meerkat.protobuf.BulletinBoardAPI.FilterType; import javax.sql.DataSource; +import java.text.MessageFormat; import java.util.LinkedList; import java.util.List; @@ -32,21 +33,72 @@ public class MySQLQueryProvider implements SQLQueryProvider { public String getSQLString(QueryType queryType) throws IllegalArgumentException{ switch(queryType) { + case ADD_SIGNATURE: - return "INSERT IGNORE INTO SignatureTable (EntryNum, SignerId, Signature) VALUES (:EntryNum, :SignerId, :Signature)"; + return MessageFormat.format( + "INSERT IGNORE INTO SignatureTable (EntryNum, SignerId, Signature) VALUES ({0}, {1}, {2})", + QueryType.ADD_SIGNATURE.getParamName(0), + QueryType.ADD_SIGNATURE.getParamName(1), + QueryType.ADD_SIGNATURE.getParamName(2)); + case CONNECT_TAG: - return "INSERT IGNORE INTO MsgTagTable (TagId, EntryNum)" - + " SELECT TagTable.TagId, :EntryNum AS EntryNum FROM TagTable WHERE Tag = :Tag"; + return MessageFormat.format( + "INSERT IGNORE INTO MsgTagTable (TagId, EntryNum)" + + " SELECT TagTable.TagId, {0} AS EntryNum FROM TagTable WHERE Tag = {1}", + QueryType.CONNECT_TAG.getParamName(0), + QueryType.CONNECT_TAG.getParamName(1)); + case FIND_MSG_ID: - return "SELECT EntryNum From MsgTable WHERE MsgId = :MsgId"; + return MessageFormat.format( + "SELECT EntryNum From MsgTable WHERE MsgId = {0}", + QueryType.FIND_MSG_ID.getParamName(0)); + case GET_MESSAGES: return "SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable"; + case GET_SIGNATURES: - return "SELECT Signature FROM SignatureTable WHERE EntryNum = :EntryNum"; + return MessageFormat.format( + "SELECT Signature FROM SignatureTable WHERE EntryNum = {0}", + QueryType.GET_SIGNATURES.getParamName(0)); + case INSERT_MSG: - return "INSERT INTO MsgTable (MsgId, Msg) VALUES(:MsgId, :Msg)"; + return MessageFormat.format( + "INSERT INTO MsgTable (MsgId, Msg) VALUES({0}, {1})", + QueryType.INSERT_MSG.getParamName(0), + QueryType.INSERT_MSG.getParamName(1)); + case INSERT_NEW_TAG: - return "INSERT IGNORE INTO TagTable(Tag) VALUES (:Tag)"; + return MessageFormat.format( + "INSERT IGNORE INTO TagTable(Tag) VALUES ({0})", + QueryType.INSERT_NEW_TAG.getParamName(0)); + + case GET_BATCH_MESSAGE_ENTRY: + return MessageFormat.format( + "SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable" + + "INNER JOIN SignatureTable ON MsgTable.EntryNum = SignatureTable.EntryNum" + + "INNER JOIN MsgTagTable ON MsgTable.EntryNum = MsgTagTable.EntryNum" + + "INNER JOIN TagTable ON MsgTagTable.TagId = TagTable.TagId" + + "WHERE SignatureTable.SignerId = {0}" + + "AND TagTable.Tag = {1}", + QueryType.GET_BATCH_MESSAGE_ENTRY.getParamName(0), + QueryType.GET_BATCH_MESSAGE_ENTRY.getParamName(1)); + + case GET_BATCH_MESSAGE_DATA: + return MessageFormat.format( + "SELECT Data FROM BatchTable" + + " WHERE SignerId = {0} AND BatchId = {1} AND SerialNum >= {2}" + + " ORDER BY SerialNum ASC", + QueryType.GET_BATCH_MESSAGE_DATA.getParamName(0), + QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1), + QueryType.GET_BATCH_MESSAGE_DATA.getParamName(2)); + + case CHECK_BATCH_LENGTH: + return MessageFormat.format( + "SELECT COUNT(Data) AS BatchLength FROM BatchTable" + + " WHERE SignerId = {0} AND BatchId = {1}", + QueryType.GET_BATCH_MESSAGE_DATA.getParamName(0), + QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1)); + default: throw new IllegalArgumentException("Cannot serve a query of type " + queryType); } @@ -119,7 +171,8 @@ public class MySQLQueryProvider implements SQLQueryProvider { public List getSchemaCreationCommands() { List list = new LinkedList(); - list.add("CREATE TABLE IF NOT EXISTS MsgTable (EntryNum INT NOT NULL AUTO_INCREMENT PRIMARY KEY, MsgId TINYBLOB, Msg BLOB, UNIQUE(MsgId(50)))"); + list.add("CREATE TABLE IF NOT EXISTS MsgTable (EntryNum INT NOT NULL AUTO_INCREMENT PRIMARY KEY," + + " MsgId TINYBLOB, Msg BLOB, UNIQUE(MsgId(50)))"); list.add("CREATE TABLE IF NOT EXISTS TagTable (TagId INT NOT NULL AUTO_INCREMENT PRIMARY KEY, Tag VARCHAR(50), UNIQUE(Tag))"); @@ -129,7 +182,14 @@ public class MySQLQueryProvider implements SQLQueryProvider { + " CONSTRAINT UNIQUE (EntryNum, TagID))"); list.add("CREATE TABLE IF NOT EXISTS SignatureTable (EntryNum INT, SignerId TINYBLOB, Signature TINYBLOB," - + " INDEX(SignerId(32)), CONSTRAINT Uni UNIQUE(SignerId(32), EntryNum), CONSTRAINT FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum))"); + + " INDEX(SignerId(32)), CONSTRAINT Unique_Signature UNIQUE(SignerId(32), EntryNum)," + + " CONSTRAINT FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum))"); + + list.add("CREATE TABLE IF NOT EXISTS BatchTable (SignerId TINYBLOB, BatchId INT, SerialNum INT, Data BLOB," + + " CONSTRAINT Unique_Batch UNIQUE(SignerId(32), BatchId, SerialNum))"); + + list.add("CREATE TABLE IF NOT EXISTS BatchTagTable (SignerId TINYBLOB, BatchId INT, TagId INT," + + " INDEX(SignerId, BatchId), CONSTRAINT FOREIGN KEY (TagId) REFERENCES TagTable(TagId))"); return list; } @@ -138,6 +198,8 @@ public class MySQLQueryProvider implements SQLQueryProvider { public List getSchemaDeletionCommands() { List list = new LinkedList(); + list.add("DROP TABLE IF EXISTS BatchTagTable"); + list.add("DROP TABLE IF EXISTS BatchTable"); list.add("DROP TABLE IF EXISTS MsgTagTable"); list.add("DROP TABLE IF EXISTS SignatureTable"); list.add("DROP TABLE IF EXISTS TagTable"); diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/BatchDataMapper.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/BatchDataMapper.java new file mode 100644 index 0000000..0189584 --- /dev/null +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/BatchDataMapper.java @@ -0,0 +1,21 @@ +package meerkat.bulletinboard.sqlserver.mappers; + +import com.google.protobuf.ByteString; +import meerkat.protobuf.BulletinBoardAPI.BatchData; +import org.springframework.jdbc.core.RowMapper; + +import java.sql.ResultSet; +import java.sql.SQLException; + +/** + * Created by Arbel Deutsch Peled on 19-Dec-15. + */ +public class BatchDataMapper implements RowMapper { + + @Override + public BatchData mapRow(ResultSet rs, int rowNum) throws SQLException { + + return BatchData.newBuilder().setData(ByteString.copyFrom(rs.getBytes(rowNum))).build(); + + } +} diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/EntryNumMapper.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/LongMapper.java similarity index 87% rename from bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/EntryNumMapper.java rename to bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/LongMapper.java index 478c39e..1ec0d98 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/EntryNumMapper.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/mappers/LongMapper.java @@ -9,7 +9,7 @@ import java.sql.SQLException; /** * Created by Arbel Deutsch Peled on 11-Dec-15. */ -public class EntryNumMapper implements RowMapper { +public class LongMapper implements RowMapper { @Override public Long mapRow(ResultSet rs, int rowNum) throws SQLException { diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java index b3fc03c..27d7bd5 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java @@ -17,12 +17,11 @@ import meerkat.bulletinboard.sqlserver.H2QueryProvider; import meerkat.bulletinboard.sqlserver.MySQLQueryProvider; import meerkat.bulletinboard.sqlserver.SQLiteQueryProvider; import meerkat.comm.CommunicationException; -import meerkat.protobuf.BulletinBoardAPI.BoolMsg; -import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage; -import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessageList; -import meerkat.protobuf.BulletinBoardAPI.MessageFilterList; +import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.rest.Constants; +import java.util.List; + @Path(Constants.BULLETIN_BOARD_SERVER_PATH) public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextListener{ @@ -99,6 +98,58 @@ public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextL return bulletinBoard.readMessages(filterList); } + @Path(Constants.BEGIN_BATCH_PATH) + @POST + @Consumes(Constants.MEDIATYPE_PROTOBUF) + @Produces(Constants.MEDIATYPE_PROTOBUF) + @Override + public BoolMsg beginBatch(BeginBatchMessage message) { + try { + return bulletinBoard.beginBatch(message); + } catch (CommunicationException e) { + System.err.println(e.getMessage()); + return null; + } + } + + @Path(Constants.POST_BATCH_PATH) + @POST + @Consumes(Constants.MEDIATYPE_PROTOBUF) + @Produces(Constants.MEDIATYPE_PROTOBUF) + @Override + public BoolMsg postBatchMessage(BatchMessage batchMessage) { + try { + return bulletinBoard.postBatchMessage(batchMessage); + } catch (CommunicationException e) { + System.err.println(e.getMessage()); + return null; + } + } + + @Path(Constants.CLOSE_BATCH_PATH) + @POST + @Consumes(Constants.MEDIATYPE_PROTOBUF) + @Produces(Constants.MEDIATYPE_PROTOBUF) + @Override + public BoolMsg closeBatchMessage(CloseBatchMessage message) { + try { + return bulletinBoard.closeBatchMessage(message); + } catch (CommunicationException e) { + System.err.println(e.getMessage()); + return null; + } + } + + @Override + public List readBatch(BatchSpecificationMessage message) { + try { + return bulletinBoard.readBatch(message); + } catch (CommunicationException | IllegalArgumentException e) { + System.err.println(e.getMessage()); + return null; + } + } + @Override public void close(){ try { diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java b/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java index 04b7a06..4d8075e 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/AsyncBulletinBoardClient.java @@ -9,13 +9,22 @@ import java.util.List; */ public interface AsyncBulletinBoardClient extends BulletinBoardClient { + public interface ClientCallback { + void handleCallback(T msg); + void handleFailure(Throwable t); + } + + public interface MessageHandler { + void handleNewMessages(List messageList); + } + /** * Post a message to the bulletin board in an asynchronous manner * @param msg is the message to be posted * @param callback is a class containing methods to handle the result of the operation * @return a unique message ID for the message, that can be later used to retrieve the batch */ - MessageID postMessage(BulletinBoardMessage msg, ClientCallback callback); + public MessageID postMessage(BulletinBoardMessage msg, ClientCallback callback); /** * This method allows for sending large messages as a batch to the bulletin board @@ -26,12 +35,12 @@ public interface AsyncBulletinBoardClient extends BulletinBoardClient { * @param callback is a callback function class for handling results of the operation * @return a unique message ID for the entire message, that can be later used to retrieve the batch */ - MessageID postBatch(byte[] signerId, int batchId, List batchDataList, int startPosition, ClientCallback callback); + public MessageID postBatch(byte[] signerId, int batchId, List batchDataList, int startPosition, ClientCallback callback); /** * Overloading of the postBatch method in which startPosition is set to the default value 0 */ - MessageID postBatch(byte[] signerId, int batchId, List batchDataList, ClientCallback callback); + public MessageID postBatch(byte[] signerId, int batchId, List batchDataList, ClientCallback callback); /** * Check how "safe" a given message is in an asynchronous manner @@ -39,7 +48,7 @@ public interface AsyncBulletinBoardClient extends BulletinBoardClient { * @param id is the unique message identifier for retrieval * @param callback is a callback function class for handling results of the operation */ - void getRedundancy(MessageID id, ClientCallback callback); + public void getRedundancy(MessageID id, ClientCallback callback); /** * Read all messages posted matching the given filter in an asynchronous manner @@ -49,7 +58,7 @@ public interface AsyncBulletinBoardClient extends BulletinBoardClient { * @param filterList return only messages that match the filters (null means no filtering). * @param callback is a callback function class for handling results of the operation */ - void readMessages(MessageFilterList filterList, ClientCallback> callback); + public void readMessages(MessageFilterList filterList, ClientCallback> callback); /** * Read a given batch message from the bulletin board @@ -57,6 +66,13 @@ public interface AsyncBulletinBoardClient extends BulletinBoardClient { * @param batchId is the unique (per signer) ID of the batch * @param callback is a callback class for handling the result of the operation */ - void readBatch(byte[] signerId, int batchId, ClientCallback callback); + public void readBatch(byte[] signerId, int batchId, ClientCallback callback); + + /** + * Subscribes to a notifier that will return any new messages on the server that match the given filters + * @param filterList defines the set of filters for message retrieval + * @param messageHandler defines the handler for new messages received + */ + public void subscribe(MessageFilterList filterList, MessageHandler messageHandler); } diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java index dcf6b15..2f5a3df 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardClient.java @@ -12,11 +12,6 @@ import java.util.List; */ public interface BulletinBoardClient { - interface ClientCallback { - void handleCallback(T msg); - void handleFailure(Throwable t); - } - /** * Initialize the client to use some specified servers * @param clientParams contains the parameters required for the client setup diff --git a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java index da53c1f..70721a7 100644 --- a/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java +++ b/meerkat-common/src/main/java/meerkat/bulletinboard/BulletinBoardServer.java @@ -3,40 +3,83 @@ package meerkat.bulletinboard; import meerkat.comm.CommunicationException; import meerkat.protobuf.BulletinBoardAPI.*; +import java.util.List; + /** * Created by Arbel on 07/11/15. * - * This interface refers to a single instance of a Bulletin Board. - * An implementation of this interface may use any DB and be hosted on any machine. + * This interface refers to a single instance of a Bulletin Board + * An implementation of this interface may use any DB and be hosted on any machine. */ public interface BulletinBoardServer{ /** - * This method initializes the server by reading the signature data and storing it. - * It also establishes the connection to the DB. - * @throws CommunicationException on DB connection error. + * This method initializes the server by reading the signature data and storing it + * It also establishes the connection to the DB + * @throws CommunicationException on DB connection error */ public void init(String meerkatDB) throws CommunicationException; /** * Post a message to bulletin board. * @param msg is the actual (signed) message - * @return TRUE if the message has been authenticated and FALSE otherwise (in ProtoBuf form). - * @throws CommunicationException on DB connection error. + * @return TRUE if the message has been authenticated and FALSE otherwise (in ProtoBuf form) + * @throws CommunicationException on DB connection error */ - public BoolMsg postMessage(BulletinBoardMessage msg) throws CommunicationException; + public BoolMsg postMessage(BulletinBoardMessage msg) throws CommunicationException; /** - * Read all messages posted matching the given filter. - * @param filter return only messages that match the filter (empty list means no filtering). + * Read all messages posted matching the given filter + * @param filterList return only messages that match the filters (empty list or null means no filtering) * @return + * @throws CommunicationException on DB connection error */ - BulletinBoardMessageList readMessages(MessageFilterList filterList) throws CommunicationException; - + public BulletinBoardMessageList readMessages(MessageFilterList filterList) throws CommunicationException; + + /** + * Informs server about a new batch message + * @param message contains the required data about the new batch + * @return TRUE if the batch request is accepted amd FALSE otherwise + * Specifically, if such a batch already exists and is not yet closed: the value returned will be TRUE + * However, if such a batch exists and is already closed: the value returned will be FALSE + * @throws CommunicationException on DB connection error + */ + public BoolMsg beginBatch(BeginBatchMessage message) throws CommunicationException; + + /** + * Posts a (part of a) batch message to the bulletin board + * Note that the existence and contents of a batch message are not available for reading before the batch is finalized + * @param batchMessage contains the (partial) data this message carries as well as meta-data required in order to place the data + * in the correct position inside the correct batch + * @return TRUE if the message is accepted and successfully saved and FALSE otherwise + * Specifically, if the batch is already closed: the value returned will be FALSE + * However, requiring to open a batch before insertion of messages is implementation-dependent + * @throws CommunicationException on DB connection error + */ + public BoolMsg postBatchMessage(BatchMessage batchMessage) throws CommunicationException; + + /** + * Attempts to close and finalize a batch message + * @param message contains the data necessary to close the batch; in particular: the signature for the batch + * @return TRUE if the batch was successfully closed, FALSE otherwise + * Specifically, if the signature is invalid or if some of the batch parts have not yet been submitted: the value returned will be FALSE + * @throws CommunicationException on DB connection error + */ + public BoolMsg closeBatchMessage(CloseBatchMessage message) throws CommunicationException; + + /** + * Reads a batch message from the server (starting with the supplied position) + * @param message specifies the signer ID and the batch ID to read as well as an (optional) start position + * @return an ordered list of batch messages starting from the specified start position (if given) or from the beginning (if omitted) + * @throws CommunicationException on DB connection error + * @throws IllegalArgumentException if message does not specify a batch + */ + public List readBatch(BatchSpecificationMessage message) throws CommunicationException, IllegalArgumentException; + /** - * This method closes the connection to the DB. - * @throws CommunicationException on DB connection error. + * This method closes the connection to the DB + * @throws CommunicationException on DB connection error */ - public void close() throws CommunicationException; + public void close() throws CommunicationException; } diff --git a/meerkat-common/src/main/java/meerkat/crypto/BatchDigest.java b/meerkat-common/src/main/java/meerkat/crypto/BatchDigest.java new file mode 100644 index 0000000..ff257b2 --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/crypto/BatchDigest.java @@ -0,0 +1,20 @@ +package meerkat.crypto; + +import meerkat.protobuf.BulletinBoardAPI.*; + +import java.util.List; + +/** + * Created by Arbel Deutsch Peled on 18-Dec-15. + * Extends the Digest interface with a method for digesting Batch messages + */ +public interface BatchDigest extends Digest{ + + /** + * Update the digest with the + * @param beginBatchMessage is the message that starts the batch + * @param batchDataList is the (ordered) list of data in the batch + */ + public void update(BeginBatchMessage beginBatchMessage, List batchDataList); + +} diff --git a/meerkat-common/src/main/java/meerkat/crypto/Digest.java b/meerkat-common/src/main/java/meerkat/crypto/Digest.java index 06b012c..c72206e 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/Digest.java +++ b/meerkat-common/src/main/java/meerkat/crypto/Digest.java @@ -13,7 +13,7 @@ public interface Digest { * (copied from {@link MessageDigest#digest()}) * @return */ - byte[] digest(); + public byte[] digest(); /** * Updates the digest using the specified message (in serialized wire form) @@ -22,12 +22,12 @@ public interface Digest { * @param msg * @return */ - void update(Message msg); + public void update(Message msg); /** * Resets the digest for further use. */ - void reset(); + public void reset(); /** * Clone the current digest state diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSASignature.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSASignature.java index 887b8e8..28e4600 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSASignature.java +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECDSASignature.java @@ -30,7 +30,10 @@ import javax.security.auth.callback.UnsupportedCallbackException; * * This class is not thread-safe (each thread should have its own instance). */ -public class ECDSASignature extends GlobalCryptoSetup implements DigitalSignature { +public class ECDSASignature implements DigitalSignature { + + private static GlobalCryptoSetup globalCryptoSetup = GlobalCryptoSetup.getInstance(); + final Logger logger = LoggerFactory.getLogger(getClass()); final public static String KEYSTORE_TYPE = "PKCS12"; diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java index f9936c7..98d32bf 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/ECElGamalEncryption.java @@ -31,7 +31,10 @@ import java.util.Random; /** * Created by talm on 17/11/15. */ -public class ECElGamalEncryption extends GlobalCryptoSetup implements Encryption { +public class ECElGamalEncryption implements Encryption { + + private static GlobalCryptoSetup globalCryptoSetup = GlobalCryptoSetup.getInstance(); + final Logger logger = LoggerFactory.getLogger(getClass()); public final static String KEY_ALGORITHM = "ECDH"; diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/GenericBatchDigest.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/GenericBatchDigest.java new file mode 100644 index 0000000..38b2192 --- /dev/null +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/GenericBatchDigest.java @@ -0,0 +1,27 @@ +package meerkat.crypto.concrete; + +import com.google.protobuf.Message; +import meerkat.crypto.BatchDigest; +import meerkat.protobuf.BulletinBoardAPI.*; + +import java.util.List; + +/** + * Created by Arbel Deutsch Peled on 19-Dec-15. + */ +public abstract class GenericBatchDigest implements BatchDigest{ + + + @Override + public void update(BeginBatchMessage beginBatchMessage, List batchDataList) { + update(beginBatchMessage); + for (BatchData batchData : batchDataList) { + update(batchData); + } + } + + @Override + // Repeated here to circumvent compiler error + public abstract BatchDigest clone() throws CloneNotSupportedException; + +} diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/GlobalCryptoSetup.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/GlobalCryptoSetup.java index 4f2e7a5..3d12701 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/concrete/GlobalCryptoSetup.java +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/GlobalCryptoSetup.java @@ -10,13 +10,26 @@ import java.security.Security; /** * A class that performs required crypto setup */ -public class GlobalCryptoSetup { +public final class GlobalCryptoSetup { + + private static GlobalCryptoSetup globalCryptoSetup; + final static Logger logger = LoggerFactory.getLogger(GlobalCryptoSetup.class); - static boolean loadedBouncyCastle = false; - static Provider bouncyCastleProvider; + private boolean loadedBouncyCastle = false; + private Provider bouncyCastleProvider; - public static boolean hasSecp256k1Curve() { + private GlobalCryptoSetup() { doSetup(); } + + public static GlobalCryptoSetup getInstance() { + if (globalCryptoSetup == null) { + globalCryptoSetup = new GlobalCryptoSetup(); + } + + return globalCryptoSetup; + } + + public boolean hasSecp256k1Curve() { // For now we just check if the java version is at least 8 String[] version = System.getProperty("java.version").split("\\."); int major = Integer.parseInt(version[0]); @@ -24,9 +37,11 @@ public class GlobalCryptoSetup { return ((major > 1) || ((major > 0) && (minor > 7))); } - public static Provider getBouncyCastleProvider() { doSetup(); return bouncyCastleProvider; } + public Provider getBouncyCastleProvider() { + return bouncyCastleProvider; + } - public static synchronized void doSetup() { + public void doSetup() { if (bouncyCastleProvider == null) { bouncyCastleProvider = new BouncyCastleProvider(); // Make bouncycastle our default provider if we're running on a JVM version < 8 @@ -39,5 +54,4 @@ public class GlobalCryptoSetup { } } - public GlobalCryptoSetup() { doSetup(); } } diff --git a/meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java b/meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java index 4f60af3..ac58f3a 100644 --- a/meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java +++ b/meerkat-common/src/main/java/meerkat/crypto/concrete/SHA256Digest.java @@ -2,6 +2,7 @@ package meerkat.crypto.concrete; import com.google.protobuf.ByteString; import com.google.protobuf.Message; +import meerkat.crypto.BatchDigest; import meerkat.crypto.Digest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -13,7 +14,7 @@ import java.security.NoSuchAlgorithmException; /** * Created by talm on 11/9/15. */ -public class SHA256Digest extends GlobalCryptoSetup implements Digest { +public class SHA256Digest extends GenericBatchDigest { final Logger logger = LoggerFactory.getLogger(getClass()); public static final String SHA256 = "SHA-256"; diff --git a/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto b/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto index 1a0bab1..2ae4068 100644 --- a/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto +++ b/meerkat-common/src/main/proto/meerkat/BulletinBoardAPI.proto @@ -104,4 +104,11 @@ message BatchMessage { int32 batchId = 2; // Unique identifier for the batch (unique per signer) int32 serialNum = 3; // Location of the message in the batch: starting from 0 BatchData data = 4; // Actual data +} + +// This message defines which batch to read and from which location to start reading +message BatchSpecificationMessage { + bytes signerId = 1; // Unique signer identifier + int32 batchId = 2; // Unique identifier for the batch (unique per signer) + int32 startPosition = 3; // Position in batch to start reading from } \ No newline at end of file diff --git a/meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalUtils.java b/meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalUtils.java index 66e1647..e57c817 100644 --- a/meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalUtils.java +++ b/meerkat-common/src/test/java/meerkat/crypto/concrete/ECElGamalUtils.java @@ -26,6 +26,9 @@ import java.security.spec.InvalidKeySpecException; * utilities for ECElgamal */ public class ECElGamalUtils { + + private static GlobalCryptoSetup globalCryptoSetup = GlobalCryptoSetup.getInstance(); + final static Logger logger = LoggerFactory.getLogger(ECElGamalUtils.class); public final static String ENCRYPTION_KEY_ALGORITHM = "ECDH"; @@ -43,7 +46,7 @@ public class ECElGamalUtils { try { KeyFactory fact = KeyFactory.getInstance(ENCRYPTION_KEY_ALGORITHM, - GlobalCryptoSetup.getBouncyCastleProvider()); + globalCryptoSetup.getBouncyCastleProvider()); PublicKey javaPk = fact.generatePublic(pubKeySpec); ConcreteCrypto.ElGamalPublicKey serializedPk = ConcreteCrypto.ElGamalPublicKey.newBuilder() .setSubjectPublicKeyInfo(ByteString.copyFrom(javaPk.getEncoded())).build(); diff --git a/restful-api-common/src/main/java/meerkat/rest/Constants.java b/restful-api-common/src/main/java/meerkat/rest/Constants.java index 73ed7d1..8215641 100644 --- a/restful-api-common/src/main/java/meerkat/rest/Constants.java +++ b/restful-api-common/src/main/java/meerkat/rest/Constants.java @@ -9,4 +9,8 @@ public interface Constants { public static final String BULLETIN_BOARD_SERVER_PATH = "/bbserver"; public static final String READ_MESSAGES_PATH = "/readmessages"; public static final String POST_MESSAGE_PATH = "/postmessage"; + public static final String BEGIN_BATCH_PATH = "/beginbatch"; + public static final String POST_BATCH_PATH = "/postbatch"; + public static final String CLOSE_BATCH_PATH = "/closebatch"; + }