Implemented (untested) batch messages in Bulletin Board Server (MySQL implementation only).

Implemented generic batch message signatures and digests.
Created new interface for Bulletin Board constants.
Bulletin-Board-Batch
Arbel Deutsch Peled 2015-12-21 23:16:06 +02:00
parent 37f962d520
commit b5237d6c9f
20 changed files with 428 additions and 128 deletions

View File

@ -8,6 +8,7 @@ import meerkat.protobuf.BulletinBoardAPI.*;
import meerkat.rest.Constants;
import meerkat.rest.ProtobufMessageBodyReader;
import meerkat.rest.ProtobufMessageBodyWriter;
import static meerkat.bulletinboard.BulletinBoardConstants.*;
import javax.ws.rs.ProcessingException;
import javax.ws.rs.client.Client;
@ -101,7 +102,7 @@ public class BulletinClientWorker implements Callable<BulletinClientJobResult> {
}
msg = payload;
requestPath = Constants.POST_MESSAGE_PATH;
requestPath = POST_MESSAGE_PATH;
break;
case READ_MESSAGES:
@ -111,7 +112,7 @@ public class BulletinClientWorker implements Callable<BulletinClientJobResult> {
}
msg = payload;
requestPath = Constants.READ_MESSAGES_PATH;
requestPath = READ_MESSAGES_PATH;
break;
case GET_REDUNDANCY:
@ -120,7 +121,7 @@ public class BulletinClientWorker implements Callable<BulletinClientJobResult> {
throw new IllegalArgumentException("Cannot search for an object that is not an instance of MessageID");
}
requestPath = Constants.READ_MESSAGES_PATH;
requestPath = READ_MESSAGES_PATH;
msg = MessageFilterList.newBuilder()
.addFilter(MessageFilter.newBuilder()
@ -144,7 +145,7 @@ public class BulletinClientWorker implements Callable<BulletinClientJobResult> {
// Send request to Server
String address = addressIterator.next();
webTarget = client.target(address).path(Constants.BULLETIN_BOARD_SERVER_PATH).path(requestPath);
webTarget = client.target(address).path(BULLETIN_BOARD_SERVER_PATH).path(requestPath);
response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(msg, Constants.MEDIATYPE_PROTOBUF));
// Retrieve answer

View File

@ -16,6 +16,8 @@ import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;
import static meerkat.bulletinboard.BulletinBoardConstants.*;
/**
* Created by Arbel Deutsch Peled on 05-Dec-15.
* Implements BulletinBoardClient interface in a simple, straightforward manner
@ -61,7 +63,7 @@ public class SimpleBulletinBoardClient implements BulletinBoardClient{
// Post message to all databases
try {
for (String db : meerkatDBs) {
webTarget = client.target(db).path(Constants.BULLETIN_BOARD_SERVER_PATH).path(Constants.POST_MESSAGE_PATH);
webTarget = client.target(db).path(BULLETIN_BOARD_SERVER_PATH).path(POST_MESSAGE_PATH);
response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(msg, Constants.MEDIATYPE_PROTOBUF));
// Only consider valid responses
@ -104,7 +106,7 @@ public class SimpleBulletinBoardClient implements BulletinBoardClient{
for (String db : meerkatDBs) {
try {
webTarget = client.target(db).path(Constants.BULLETIN_BOARD_SERVER_PATH).path(Constants.READ_MESSAGES_PATH);
webTarget = client.target(db).path(BULLETIN_BOARD_SERVER_PATH).path(READ_MESSAGES_PATH);
response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(filterList, Constants.MEDIATYPE_PROTOBUF));
@ -138,7 +140,7 @@ public class SimpleBulletinBoardClient implements BulletinBoardClient{
for (String db : meerkatDBs) {
try {
webTarget = client.target(db).path(Constants.BULLETIN_BOARD_SERVER_PATH).path(Constants.READ_MESSAGES_PATH);
webTarget = client.target(db).path(BULLETIN_BOARD_SERVER_PATH).path(READ_MESSAGES_PATH);
response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(filterList, Constants.MEDIATYPE_PROTOBUF));

View File

@ -113,7 +113,7 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple
}
@Override
public void readBatch(byte[] signerId, int batchId, ClientCallback<SignedBatch> callback) {
public void readBatch(byte[] signerId, int batchId, ClientCallback<CompleteBatch> callback) {
// TODO: Implement
}

View File

@ -1,6 +1,7 @@
package meerkat.bulletinboard.sqlserver;
import java.security.InvalidKeyException;
import java.security.SignatureException;
import java.security.cert.CertificateException;
import java.sql.*;
import java.util.*;
@ -8,13 +9,12 @@ import java.util.*;
import com.google.protobuf.ByteString;
import com.google.protobuf.ProtocolStringList;
import meerkat.bulletinboard.BulletinBoardServer;
import meerkat.bulletinboard.*;
import meerkat.bulletinboard.sqlserver.mappers.*;
import static meerkat.bulletinboard.BulletinBoardConstants.*;
import meerkat.comm.CommunicationException;
import meerkat.crypto.BatchDigest;
import meerkat.crypto.DigitalSignature;
import meerkat.crypto.concrete.ECDSASignature;
import meerkat.crypto.concrete.SHA256Digest;
@ -62,7 +62,9 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
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"});
CONNECT_BATCH_TAG(new String[] {"SignerId", "BatchId", "Tag"}),
GET_BATCH_TAGS(new String[] {"SignerId", "BatchId"}),
MOVE_BATCH_TAGS(new String[] {"EntryNum", "SignerId", "BatchId"});
private String[] paramNames;
@ -219,7 +221,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
protected NamedParameterJdbcTemplate jdbcTemplate;
protected BatchDigest digest;
protected DigitalSignature signer;
protected BatchDigitalSignature signer;
protected List<SignatureVerificationKey> trusteeSignatureVerificationArray;
protected int minTrusteeSignatures;
@ -257,8 +259,8 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
public void init(String meerkatDB) throws CommunicationException {
// TODO write signature reading part.
digest = new SHA256Digest();
signer = new ECDSASignature();
digest = new GenericBatchDigest(new SHA256Digest());
signer = new GenericBatchDigitalSignature(new ECDSASignature());
jdbcTemplate = new NamedParameterJdbcTemplate(sqlQueryProvider.getDataSource());
@ -356,7 +358,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
} else{
sql = sqlQueryProvider.getSQLString(QueryType.INSERT_MSG);
namedParameters.put(QueryType.INSERT_MSG.getParamName(0), msg.getMsg().toByteArray());
namedParameters.put(QueryType.INSERT_MSG.getParamName(1), msg.getMsg().toByteArray());
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(sql,new MapSqlParameterSource(namedParameters),keyHolder);
@ -585,13 +587,19 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
@Override
public BoolMsg closeBatchMessage(CloseBatchMessage message) throws CommunicationException {
ByteString signerId = message.getSig().getSignerId();
int batchId = message.getBatchId();
KeyHolder keyHolder = new GeneratedKeyHolder();
// 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());
namedParameters.addValue(QueryType.CHECK_BATCH_LENGTH.getParamName(0),signerId);
namedParameters.addValue(QueryType.CHECK_BATCH_LENGTH.getParamName(1),batchId);
List<Long> lengthResult = jdbcTemplate.query(sql, namedParameters, new LongMapper());
@ -599,34 +607,99 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
return BoolMsg.newBuilder().setValue(false).build();
}
// Check signature
// Get Tags and add them to CompleteBatch
sql = sqlQueryProvider.getSQLString(QueryType.GET_BATCH_TAGS);
namedParameters = new MapSqlParameterSource();
namedParameters.addValue(QueryType.GET_BATCH_TAGS.getParamName(0),signerId);
namedParameters.addValue(QueryType.GET_BATCH_TAGS.getParamName(1),batchId);
List<String> tags = jdbcTemplate.query(sql, namedParameters, new StringMapper());
CompleteBatch completeBatch = new CompleteBatch(
BeginBatchMessage.newBuilder()
.setSignerId(signerId)
.setBatchId(batchId)
.addAllTag(tags)
.build()
);
// Add actual batch data to CompleteBatch
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(0),signerId);
namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1),batchId);
namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(2),0); // Read from the beginning
List<BatchData> batchDataList = jdbcTemplate.query(sql, namedParameters, new BatchDataMapper());
completeBatch.appendBatchData(jdbcTemplate.query(sql, namedParameters, new BatchDataMapper()));
// Verify signature
completeBatch.setSignature(message.getSig());
try {
signer.initVerify(message.getSig());
} catch (CertificateException | InvalidKeyException e) {
signer.verify(completeBatch);
} catch (CertificateException | InvalidKeyException | SignatureException e) {
return BoolMsg.newBuilder().setValue(false).build();
}
//TODO: FInish this
// Batch verified: finalize it
//signer.updateContent(msgStream);
//assertTrue("Signature did not verify!", signer.verify());
// Calculate message ID
digest.reset();
digest.update(completeBatch);
MessageID msgID = MessageID.newBuilder().setID(ByteString.copyFrom(digest.digest())).build();
return null;
// Create Bulletin Board message
BulletinBoardMessage bulletinBoardMessage = BulletinBoardMessage.newBuilder()
.addSig(message.getSig())
.setMsg(UnsignedBulletinBoardMessage.newBuilder()
.addAllTag(tags)
.addTag(BATCH_TAG)
.setData(message.getSig().getSignerId())
.build())
.build();
sql = sqlQueryProvider.getSQLString(QueryType.INSERT_MSG);
namedParameters = new MapSqlParameterSource();
namedParameters.addValue(QueryType.INSERT_MSG.getParamName(0), msgID);
namedParameters.addValue(QueryType.INSERT_MSG.getParamName(1), bulletinBoardMessage);
jdbcTemplate.update(sql, namedParameters, keyHolder);
long entryNum = keyHolder.getKey().longValue();
sql = sqlQueryProvider.getSQLString(QueryType.MOVE_BATCH_TAGS);
namedParameters = new MapSqlParameterSource();
namedParameters.addValue(QueryType.MOVE_BATCH_TAGS.getParamName(0), entryNum);
namedParameters.addValue(QueryType.MOVE_BATCH_TAGS.getParamName(1), signerId);
namedParameters.addValue(QueryType.MOVE_BATCH_TAGS.getParamName(2), batchId);
jdbcTemplate.update(sql, namedParameters);
return BoolMsg.newBuilder().setValue(true).build();
}
@Override
public List<BatchData> readBatch(BatchSpecificationMessage message) {
return null; // TODO: Implement this
public List<BatchData> readBatch(BatchSpecificationMessage message) throws CommunicationException, IllegalArgumentException{
// Check that batch is closed
if (!isBatchClosed(message.getSignerId(), message.getBatchId())) {
throw new IllegalArgumentException("No such batch");
}
String sql = sqlQueryProvider.getSQLString(QueryType.GET_BATCH_MESSAGE_DATA);
MapSqlParameterSource namedParameters = new MapSqlParameterSource();
namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(0),message.getSignerId());
namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1),message.getBatchId());
return jdbcTemplate.query(sql, namedParameters, new BatchDataMapper());
}
@Override

View File

@ -36,7 +36,7 @@ public class MySQLQueryProvider implements SQLQueryProvider {
case ADD_SIGNATURE:
return MessageFormat.format(
"INSERT IGNORE INTO SignatureTable (EntryNum, SignerId, Signature) VALUES ({0}, {1}, {2})",
"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));
@ -44,13 +44,13 @@ public class MySQLQueryProvider implements SQLQueryProvider {
case CONNECT_TAG:
return MessageFormat.format(
"INSERT IGNORE INTO MsgTagTable (TagId, EntryNum)"
+ " SELECT TagTable.TagId, {0} AS EntryNum FROM TagTable WHERE Tag = {1}",
+ " 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 MessageFormat.format(
"SELECT EntryNum From MsgTable WHERE MsgId = {0}",
"SELECT EntryNum From MsgTable WHERE MsgId = :{0}",
QueryType.FIND_MSG_ID.getParamName(0));
case GET_MESSAGES:
@ -58,18 +58,18 @@ public class MySQLQueryProvider implements SQLQueryProvider {
case GET_SIGNATURES:
return MessageFormat.format(
"SELECT Signature FROM SignatureTable WHERE EntryNum = {0}",
"SELECT Signature FROM SignatureTable WHERE EntryNum = :{0}",
QueryType.GET_SIGNATURES.getParamName(0));
case INSERT_MSG:
return MessageFormat.format(
"INSERT INTO MsgTable (MsgId, Msg) VALUES({0}, {1})",
"INSERT INTO MsgTable (MsgId, Msg) VALUES(:{0}, :{1})",
QueryType.INSERT_MSG.getParamName(0),
QueryType.INSERT_MSG.getParamName(1));
case INSERT_NEW_TAG:
return MessageFormat.format(
"INSERT IGNORE INTO TagTable(Tag) VALUES ({0})",
"INSERT IGNORE INTO TagTable(Tag) VALUES (:{0})",
QueryType.INSERT_NEW_TAG.getParamName(0));
case GET_BATCH_MESSAGE_ENTRY:
@ -78,15 +78,15 @@ public class MySQLQueryProvider implements SQLQueryProvider {
+ "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}",
+ "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}"
+ " 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),
@ -95,10 +95,34 @@ public class MySQLQueryProvider implements SQLQueryProvider {
case CHECK_BATCH_LENGTH:
return MessageFormat.format(
"SELECT COUNT(Data) AS BatchLength FROM BatchTable"
+ " WHERE SignerId = {0} AND BatchId = {1}",
+ " WHERE SignerId = :{0} AND BatchId = :{1}",
QueryType.GET_BATCH_MESSAGE_DATA.getParamName(0),
QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1));
case CONNECT_BATCH_TAG:
return MessageFormat.format(
"INSERT INTO BatchTagTable (SignerId, BatchId, TagId) SELECT :{0}, :{1}, TagId FROM TagTable"
+ " WHERE Tag = :{2}",
QueryType.CONNECT_BATCH_TAG.getParamName(0),
QueryType.CONNECT_BATCH_TAG.getParamName(1),
QueryType.CONNECT_BATCH_TAG.getParamName(2));
case GET_BATCH_TAGS:
return MessageFormat.format(
"SELECT Tag FROM TagTable INNER JOIN BatchTagTable ON TagTable.TagId = BatchTagTable.Tag ID"
+ " WHERE SignerId = :{0} AND BatchId = :{1} ORDER BY Tag ASC",
QueryType.GET_BATCH_TAGS.getParamName(0),
QueryType.GET_BATCH_TAGS.getParamName(1));
case MOVE_BATCH_TAGS:
return MessageFormat.format(
"INSERT INTO MsgTagTable (EntryNum, TagId) "
+ " SELECT {0}, TagId FROM BatchTagTable WHERE SignerId = {1} AND BatchId = {2};"
+ " DELETE FROM BatchTagTable WHERE SignerId = {1} AND BatchId = {2}",
QueryType.GET_BATCH_TAGS.getParamName(0),
QueryType.GET_BATCH_TAGS.getParamName(1),
QueryType.GET_BATCH_TAGS.getParamName(2));
default:
throw new IllegalArgumentException("Cannot serve a query of type " + queryType);
}
@ -189,7 +213,7 @@ public class MySQLQueryProvider implements SQLQueryProvider {
+ " 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))");
+ " INDEX(SignerId(32), BatchId), CONSTRAINT FOREIGN KEY (TagId) REFERENCES TagTable(TagId))");
return list;
}

View File

@ -15,7 +15,7 @@ public class BatchDataMapper implements RowMapper<BatchData> {
@Override
public BatchData mapRow(ResultSet rs, int rowNum) throws SQLException {
return BatchData.newBuilder().setData(ByteString.copyFrom(rs.getBytes(rowNum))).build();
return BatchData.newBuilder().setData(ByteString.copyFrom(rs.getBytes(1))).build();
}
}

View File

@ -0,0 +1,18 @@
package meerkat.bulletinboard.sqlserver.mappers;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* Created by Arbel Deutsch Peled on 20-Dec-15.
*/
public class StringMapper implements RowMapper<String> {
@Override
public String mapRow(ResultSet rs, int rowNum) throws SQLException {
return rs.getString(1);
}
}

View File

@ -18,11 +18,12 @@ import meerkat.bulletinboard.sqlserver.MySQLQueryProvider;
import meerkat.bulletinboard.sqlserver.SQLiteQueryProvider;
import meerkat.comm.CommunicationException;
import meerkat.protobuf.BulletinBoardAPI.*;
import meerkat.rest.Constants;
import static meerkat.bulletinboard.BulletinBoardConstants.*;
import static meerkat.rest.Constants.*;
import java.util.List;
@Path(Constants.BULLETIN_BOARD_SERVER_PATH)
@Path(BULLETIN_BOARD_SERVER_PATH)
public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextListener{
private static final String BULLETIN_BOARD_ATTRIBUTE_NAME = "bulletinBoard";
@ -78,30 +79,30 @@ public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextL
}
}
@Path(Constants.POST_MESSAGE_PATH)
@Path(POST_MESSAGE_PATH)
@POST
@Consumes(Constants.MEDIATYPE_PROTOBUF)
@Produces(Constants.MEDIATYPE_PROTOBUF)
@Consumes(MEDIATYPE_PROTOBUF)
@Produces(MEDIATYPE_PROTOBUF)
@Override
public BoolMsg postMessage(BulletinBoardMessage msg) throws CommunicationException {
init();
return bulletinBoard.postMessage(msg);
}
@Path(Constants.READ_MESSAGES_PATH)
@Path(READ_MESSAGES_PATH)
@POST
@Consumes(Constants.MEDIATYPE_PROTOBUF)
@Produces(Constants.MEDIATYPE_PROTOBUF)
@Consumes(MEDIATYPE_PROTOBUF)
@Produces(MEDIATYPE_PROTOBUF)
@Override
public BulletinBoardMessageList readMessages(MessageFilterList filterList) throws CommunicationException {
init();
return bulletinBoard.readMessages(filterList);
}
@Path(Constants.BEGIN_BATCH_PATH)
@Path(BEGIN_BATCH_PATH)
@POST
@Consumes(Constants.MEDIATYPE_PROTOBUF)
@Produces(Constants.MEDIATYPE_PROTOBUF)
@Consumes(MEDIATYPE_PROTOBUF)
@Produces(MEDIATYPE_PROTOBUF)
@Override
public BoolMsg beginBatch(BeginBatchMessage message) {
try {
@ -112,10 +113,10 @@ public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextL
}
}
@Path(Constants.POST_BATCH_PATH)
@Path(POST_BATCH_PATH)
@POST
@Consumes(Constants.MEDIATYPE_PROTOBUF)
@Produces(Constants.MEDIATYPE_PROTOBUF)
@Consumes(MEDIATYPE_PROTOBUF)
@Produces(MEDIATYPE_PROTOBUF)
@Override
public BoolMsg postBatchMessage(BatchMessage batchMessage) {
try {
@ -126,10 +127,10 @@ public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextL
}
}
@Path(Constants.CLOSE_BATCH_PATH)
@Path(CLOSE_BATCH_PATH)
@POST
@Consumes(Constants.MEDIATYPE_PROTOBUF)
@Produces(Constants.MEDIATYPE_PROTOBUF)
@Consumes(MEDIATYPE_PROTOBUF)
@Produces(MEDIATYPE_PROTOBUF)
@Override
public BoolMsg closeBatchMessage(CloseBatchMessage message) {
try {

View File

@ -6,6 +6,7 @@ import com.google.protobuf.TextFormat;
import meerkat.protobuf.Crypto.*;
import meerkat.protobuf.BulletinBoardAPI.*;
import static meerkat.bulletinboard.BulletinBoardConstants.*;
import meerkat.rest.Constants;
import meerkat.rest.ProtobufMessageBodyReader;
import meerkat.rest.ProtobufMessageBodyWriter;
@ -54,8 +55,8 @@ public class BulletinBoardSQLServerIntegrationTest {
// Test writing mechanism
System.err.println("******** Testing: " + Constants.POST_MESSAGE_PATH);
webTarget = client.target(BASE_URL).path(Constants.BULLETIN_BOARD_SERVER_PATH).path(Constants.POST_MESSAGE_PATH);
System.err.println("******** Testing: " + POST_MESSAGE_PATH);
webTarget = client.target(BASE_URL).path(BULLETIN_BOARD_SERVER_PATH).path(POST_MESSAGE_PATH);
System.err.println(webTarget.getUri());
msg = BulletinBoardMessage.newBuilder()
@ -101,8 +102,8 @@ public class BulletinBoardSQLServerIntegrationTest {
// Test reading mechanism
System.err.println("******** Testing: " + Constants.READ_MESSAGES_PATH);
webTarget = client.target(BASE_URL).path(Constants.BULLETIN_BOARD_SERVER_PATH).path(Constants.READ_MESSAGES_PATH);
System.err.println("******** Testing: " + READ_MESSAGES_PATH);
webTarget = client.target(BASE_URL).path(BULLETIN_BOARD_SERVER_PATH).path(READ_MESSAGES_PATH);
filterList = MessageFilterList.newBuilder()
.addFilter(
MessageFilter.newBuilder()

View File

@ -66,7 +66,7 @@ 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
*/
public void readBatch(byte[] signerId, int batchId, ClientCallback<SignedBatch> callback);
public void readBatch(byte[] signerId, int batchId, ClientCallback<CompleteBatch> callback);
/**
* Subscribes to a notifier that will return any new messages on the server that match the given filters

View File

@ -0,0 +1,20 @@
package meerkat.bulletinboard;
import meerkat.crypto.Digest;
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 batch message data (ignore the signature)
* @param completeBatch is the batch message that needs to be digested
*/
public void update(CompleteBatch completeBatch);
}

View File

@ -0,0 +1,34 @@
package meerkat.bulletinboard;
import meerkat.crypto.DigitalSignature;
import meerkat.protobuf.BulletinBoardAPI.BeginBatchMessage;
import meerkat.protobuf.BulletinBoardAPI.BatchData;
import meerkat.protobuf.Crypto.Signature;
import java.security.InvalidKeyException;
import java.security.SignatureException;
import java.security.cert.CertificateException;
import java.util.List;
/**
* Created by Arbel Deutsch Peled on 20-Dec-15.
* Extends the DigitalSignature interface with methods for signing and authenticating Batch messages
*/
public interface BatchDigitalSignature extends DigitalSignature {
/**
* Appends the batch data to the signed content (ignoring the signature)
* @param completeBatch contains all the data about the batch
* @throws SignatureException
*/
public void updateContent(CompleteBatch completeBatch) throws SignatureException;
/**
* Performs a complete verification process on the given batch message
* @param completeBatch contains the batch data as well as the signature
* @return TRUE if the batch is verified and FALSE otherwise
* @throws SignatureException | SignatureException | InvalidKeyException when underlying methods do so
*/
public boolean verify(CompleteBatch completeBatch) throws SignatureException, CertificateException, InvalidKeyException;
}

View File

@ -0,0 +1,21 @@
package meerkat.bulletinboard;
/**
* Created by Arbel Deutsch Peled on 21-Dec-15.
*/
public interface BulletinBoardConstants {
// Relative addresses for Bulletin Board operations
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";
// Other Constants
public static final String BATCH_TAG = "Batch";
}

View File

@ -9,27 +9,36 @@ import java.util.List;
/**
* Created by Arbel Deutsch Peled on 14-Dec-15.
*
* A data structure for holding both a batch message and its signature
* A data structure for holding a complete batch message along with its signature
*/
public class SignedBatch {
public class CompleteBatch {
private BeginBatchMessage beginBatchMessage;
private List<BatchData> batchDataList;
private Signature signature;
public SignedBatch() {
public CompleteBatch() {
batchDataList = new LinkedList<BatchData>();
}
public SignedBatch(List<BatchData> newDataList) {
this();
public CompleteBatch(BeginBatchMessage newBeginBatchMessage) {
beginBatchMessage = newBeginBatchMessage;
}
public CompleteBatch(BeginBatchMessage newBeginBatchMessage, List<BatchData> newDataList) {
this(newBeginBatchMessage);
appendBatchData(newDataList);
}
public SignedBatch(List<BatchData> newDataList, Signature newSignature) {
this(newDataList);
public CompleteBatch(BeginBatchMessage newBeginBatchMessage, List<BatchData> newDataList, Signature newSignature) {
this(newBeginBatchMessage, newDataList);
signature = newSignature;
}
public BeginBatchMessage getBeginBatchMessage() {
return beginBatchMessage;
}
public List<BatchData> getBatchDataList() {
return batchDataList;
}
@ -46,5 +55,8 @@ public class SignedBatch {
batchDataList.addAll(newBatchDataList);
}
public void setSignature(Signature newSignature) {
signature = newSignature;
}
}

View File

@ -0,0 +1,54 @@
package meerkat.bulletinboard;
import com.google.protobuf.Message;
import meerkat.crypto.Digest;
import meerkat.protobuf.BulletinBoardAPI.BeginBatchMessage;
import meerkat.protobuf.BulletinBoardAPI.BatchData;
import java.util.List;
/**
* Created by Arbel Deutsch Peled on 19-Dec-15.
* Wrapper class for digesting Batches in a standardized way
*/
public class GenericBatchDigest implements BatchDigest{
private Digest digest;
public GenericBatchDigest(Digest digest) {
this.digest = digest;
}
@Override
public void update(CompleteBatch completeBatch) {
update(completeBatch.getBeginBatchMessage());
for (BatchData batchData : completeBatch.getBatchDataList()) {
update(batchData);
}
}
@Override
public byte[] digest() {
return digest.digest();
}
@Override
public void update(Message msg) {
digest.update(msg);
}
@Override
public void reset() {
digest.reset();
}
@Override
public GenericBatchDigest clone() throws CloneNotSupportedException{
return new GenericBatchDigest(digest.clone());
}
}

View File

@ -0,0 +1,95 @@
package meerkat.bulletinboard;
import com.google.protobuf.ByteString;
import com.google.protobuf.Message;
import meerkat.crypto.DigitalSignature;
import meerkat.protobuf.BulletinBoardAPI.BeginBatchMessage;
import meerkat.protobuf.BulletinBoardAPI.BatchData;
import meerkat.protobuf.Crypto;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.SignatureException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.List;
/**
* Created by Arbel Deutsch Peled on 20-Dec-15.
* Wrapper class for signing and verifying Batch signatures in a standardized way
*/
public class GenericBatchDigitalSignature implements BatchDigitalSignature{
private DigitalSignature digitalSignature;
public GenericBatchDigitalSignature(DigitalSignature digitalSignature) {
this.digitalSignature = digitalSignature;
}
@Override
public void updateContent(CompleteBatch completeBatch) throws SignatureException {
digitalSignature.updateContent(completeBatch.getBeginBatchMessage());
for (BatchData batchData : completeBatch.getBatchDataList()) {
digitalSignature.updateContent(batchData);
}
}
@Override
public boolean verify(CompleteBatch completeBatch) throws SignatureException, CertificateException, InvalidKeyException {
digitalSignature.initVerify(completeBatch.getSignature());
updateContent(completeBatch);
return digitalSignature.verify();
}
@Override
public void loadVerificationCertificates(InputStream certStream) throws CertificateException {
digitalSignature.loadVerificationCertificates(certStream);
}
@Override
public void clearVerificationCertificates() {
digitalSignature.clearVerificationCertificates();
}
@Override
public void updateContent(Message msg) throws SignatureException {
digitalSignature.updateContent(msg);
}
@Override
public Crypto.Signature sign() throws SignatureException {
return digitalSignature.sign();
}
@Override
public void initVerify(Crypto.Signature sig) throws CertificateException, InvalidKeyException {
digitalSignature.initVerify(sig);
}
@Override
public boolean verify() {
return digitalSignature.verify();
}
@Override
public void loadSigningCertificate(KeyStore.Builder keyStoreBuilder) throws IOException, CertificateException, UnrecoverableKeyException {
digitalSignature.loadSigningCertificate(keyStoreBuilder);
}
@Override
public ByteString getSignerID() {
return digitalSignature.getSignerID();
}
@Override
public void clearSigningKey() {
digitalSignature.clearSigningKey();
}
}

View File

@ -1,20 +0,0 @@
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<BatchData> batchDataList);
}

View File

@ -1,27 +0,0 @@
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<BatchData> batchDataList) {
update(beginBatchMessage);
for (BatchData batchData : batchDataList) {
update(batchData);
}
}
@Override
// Repeated here to circumvent compiler error
public abstract BatchDigest clone() throws CloneNotSupportedException;
}

View File

@ -2,7 +2,6 @@ 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;
@ -14,7 +13,7 @@ import java.security.NoSuchAlgorithmException;
/**
* Created by talm on 11/9/15.
*/
public class SHA256Digest extends GenericBatchDigest {
public class SHA256Digest implements Digest {
final Logger logger = LoggerFactory.getLogger(getClass());
public static final String SHA256 = "SHA-256";

View File

@ -5,12 +5,4 @@ package meerkat.rest;
*/
public interface Constants {
public static final String MEDIATYPE_PROTOBUF = "application/x-protobuf";
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";
}