Working version of Batch messages on Server-Side

Bulletin-Board-Batch
Arbel Deutsch Peled 2015-12-27 11:21:17 +02:00
parent b5237d6c9f
commit 88b8f6d8ea
11 changed files with 468 additions and 104 deletions

View File

@ -79,6 +79,11 @@ test {
exclude '**/*IntegrationTest*'
}
task myTest(type: Test) {
include '**/*MySQL*Test*'
outputs.upToDateWhen { false }
}
task dbTest(type: Test) {
include '**/*H2*Test*'
include '**/*MySQL*Test*'

View File

@ -51,25 +51,87 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
*/
public static enum QueryType {
FIND_MSG_ID(new String[] {"MsgId"}),
INSERT_MSG(new String[] {"MsgId","Msg"}),
INSERT_NEW_TAG(new String[] {"Tag"}),
CONNECT_TAG(new String[] {"EntryNum","Tag"}),
ADD_SIGNATURE(new String[] {"EntryNum","SignerId","Signature"}),
GET_SIGNATURES(new String[] {"EntryNum"}),
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"}),
GET_BATCH_TAGS(new String[] {"SignerId", "BatchId"}),
MOVE_BATCH_TAGS(new String[] {"EntryNum", "SignerId", "BatchId"});
FIND_MSG_ID(
new String[] {"MsgId"},
new int[] {Types.BLOB}
),
FIND_TAG_ID(
new String[] {"Tag"},
new int[] {Types.VARCHAR}
),
INSERT_MSG(
new String[] {"MsgId","Msg"},
new int[] {Types.BLOB, Types.BLOB}
),
INSERT_NEW_TAG(
new String[] {"Tag"},
new int[] {Types.VARCHAR}
),
CONNECT_TAG(
new String[] {"EntryNum","Tag"},
new int[] {Types.INTEGER, Types.VARCHAR}
),
ADD_SIGNATURE(
new String[] {"EntryNum","SignerId","Signature"},
new int[] {Types.INTEGER, Types.BLOB, Types.BLOB}
),
GET_SIGNATURES(
new String[] {"EntryNum"},
new int[] {Types.INTEGER}
),
GET_MESSAGES(
new String[] {},
new int[] {}
),
GET_BATCH_MESSAGE_ENTRY(
new String[] {"SignerId", "BatchId"},
new int[] {Types.BLOB, Types.INTEGER}
),
CHECK_BATCH_LENGTH(
new String[] {"SignerId", "BatchId"},
new int[] {Types.BLOB, Types.INTEGER}
),
GET_BATCH_MESSAGE_DATA(
new String[] {"SignerId", "BatchId", "StartPosition"},
new int[] {Types.BLOB, Types.INTEGER, Types.INTEGER}
),
INSERT_BATCH_DATA(
new String[] {"SignerId", "BatchId", "SerialNum", "Data"},
new int[] {Types.BLOB, Types.INTEGER, Types.INTEGER, Types.BLOB}
),
CONNECT_BATCH_TAG(
new String[] {"SignerId", "BatchId", "Tag"},
new int[] {Types.BLOB, Types.INTEGER, Types.VARCHAR}
),
GET_BATCH_TAGS(
new String[] {"SignerId", "BatchId"},
new int[] {Types.BLOB, Types.INTEGER}
),
REMOVE_BATCH_TAGS(
new String[] {"SignerId", "BatchId"},
new int[] {Types.BLOB, Types.INTEGER}
);
private String[] paramNames;
private int[] paramTypes;
private QueryType(String[] paramNames) {
private QueryType(String[] paramNames, int[] paramTypes) {
this.paramNames = paramNames;
this.paramTypes = paramTypes;
}
public String[] getParamNames() {
@ -80,6 +142,14 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
return paramNames[num];
}
public int[] getParamTypes() {
return paramTypes;
}
public int getParamType(int num) {
return paramTypes[num];
}
}
/**
@ -316,10 +386,17 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
.build();
}
@Override
public BoolMsg postMessage(BulletinBoardMessage msg) throws CommunicationException {
if (!verifyMessage(msg)) {
/**
* This method posts a messages to the server
* @param msg is the message to post
* @param checkSignature decides whether ot not the method should check the signature before it posts the message
* @return TRUE if the post is successful and FALSE otherwise
* @throws CommunicationException
*/
public BoolMsg postMessage(BulletinBoardMessage msg, boolean checkSignature) throws CommunicationException{
if (checkSignature && !verifyMessage(msg)) {
return boolToBoolMsg(false);
}
@ -328,23 +405,23 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
byte[] msgID;
long entryNum;
ProtocolStringList tagList;
String[] tags;
List<Signature> signatureList;
Signature[] signatures;
// Calculate message ID (depending only on the the unsigned message)
digest.reset();
digest.update(msg.getMsg());
msgID = digest.digest();
// Add message to table if needed and store entry number of message.
sql = sqlQueryProvider.getSQLString(QueryType.FIND_MSG_ID);
Map namedParameters = new HashMap();
namedParameters.put(QueryType.FIND_MSG_ID.getParamName(0),msgID);
@ -366,21 +443,21 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
entryNum = keyHolder.getKey().longValue();
}
// Retrieve tags and store new ones in tag table.
try {
tagList = msg.getMsg().getTagList();
tags = new String[tagList.size()];
tags = tagList.toArray(tags);
insertNewTags(tags);
tagList = msg.getMsg().getTagList();
tags = new String[tagList.size()];
tags = tagList.toArray(tags);
insertNewTags(tags);
} catch (SQLException e) {
throw new CommunicationException(e.getMessage());
}
// Connect message to tags.
sql = sqlQueryProvider.getSQLString(QueryType.CONNECT_TAG);
@ -394,13 +471,13 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
}
jdbcTemplate.batchUpdate(sql, namedParameterArray);
// Retrieve signatures.
signatureList = msg.getSigList();
signatures = new Signature[signatureList.size()];
signatures = signatureList.toArray(signatures);
signatureList = msg.getSigList();
signatures = new Signature[signatureList.size()];
signatures = signatureList.toArray(signatures);
// Connect message to signatures.
sql = sqlQueryProvider.getSQLString(QueryType.ADD_SIGNATURE);
@ -417,6 +494,12 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
jdbcTemplate.batchUpdate(sql,namedParameterArray);
return boolToBoolMsg(true);
}
@Override
public BoolMsg postMessage(BulletinBoardMessage msg) throws CommunicationException {
return postMessage(msg, true); // Perform a post and check the signature for authenticity
}
@Override
@ -477,7 +560,8 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
// Run query
List<BulletinBoardMessage.Builder> msgBuilders = jdbcTemplate.query(sqlBuilder.toString(), namedParameters, messageMapper);
List<BulletinBoardMessage.Builder> msgBuilders =
jdbcTemplate.query(sqlBuilder.toString(), namedParameters, messageMapper);
// Compile list of messages
@ -507,23 +591,41 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
}
/**
* This method returns a string representation of the tag associated with a batch ID
* @param batchId is the given batch ID
* @return the String representation of the tag
*/
private String batchIdToTag(int batchId) {
return BATCH_ID_TAG_PREFIX + Integer.toString(batchId);
}
/**
* 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){
private boolean isBatchClosed(ByteString signerId, int batchId) throws CommunicationException {
String sql = sqlQueryProvider.getSQLString(QueryType.GET_BATCH_MESSAGE_ENTRY);
MessageFilterList filterList = MessageFilterList.newBuilder()
.addFilter(MessageFilter.newBuilder()
.setType(FilterType.SIGNER_ID)
.setId(signerId)
.build())
.addFilter(MessageFilter.newBuilder()
.setType(FilterType.TAG)
.setTag(BATCH_TAG)
.build())
.addFilter(MessageFilter.newBuilder()
.setType(FilterType.TAG)
.setTag(batchIdToTag(batchId))
.build())
.build();
MapSqlParameterSource namedParameters = new MapSqlParameterSource();
namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_ENTRY.getParamName(0), signerId);
namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_ENTRY.getParamName(1), batchId);
BulletinBoardMessageList messageList = readMessages(filterList);
List<Long> result = jdbcTemplate.query(sql,namedParameters,new LongMapper());
return (result.size() > 0);
return (messageList.getMessageList().size() > 0);
}
@ -562,7 +664,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
}
@Override
public BoolMsg postBatchMessage(BatchMessage batchMessage) {
public BoolMsg postBatchMessage(BatchMessage batchMessage) throws CommunicationException{
// Check if batch is closed
if (isBatchClosed(batchMessage.getSignerId(), batchMessage.getBatchId())) {
@ -576,7 +678,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
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());
namedParameters.addValue(QueryType.INSERT_BATCH_DATA.getParamName(3),batchMessage.getData().toByteArray());
jdbcTemplate.update(sql, namedParameters);
@ -641,11 +743,12 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
completeBatch.setSignature(message.getSig());
try {
signer.verify(completeBatch);
} catch (CertificateException | InvalidKeyException | SignatureException e) {
return BoolMsg.newBuilder().setValue(false).build();
}
// try {
// TODO: Actual verification
// //signer.verify(completeBatch);
// } catch (CertificateException | InvalidKeyException | SignatureException e) {
// return BoolMsg.newBuilder().setValue(false).build();
// }
// Batch verified: finalize it
@ -660,28 +763,25 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
.setMsg(UnsignedBulletinBoardMessage.newBuilder()
.addAllTag(tags)
.addTag(BATCH_TAG)
.addTag(batchIdToTag(batchId))
.setData(message.getSig().getSignerId())
.build())
.build();
sql = sqlQueryProvider.getSQLString(QueryType.INSERT_MSG);
// Post message without checking signature validity
postMessage(bulletinBoardMessage, false);
// Remove tags from temporary table
sql = sqlQueryProvider.getSQLString(QueryType.REMOVE_BATCH_TAGS);
namedParameters = new MapSqlParameterSource();
namedParameters.addValue(QueryType.INSERT_MSG.getParamName(0), msgID);
namedParameters.addValue(QueryType.INSERT_MSG.getParamName(1), bulletinBoardMessage);
namedParameters.addValue(QueryType.REMOVE_BATCH_TAGS.getParamName(0), signerId);
namedParameters.addValue(QueryType.REMOVE_BATCH_TAGS.getParamName(1), batchId);
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 TRUE
return BoolMsg.newBuilder().setValue(true).build();
}
@ -698,6 +798,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(0),message.getSignerId());
namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1),message.getBatchId());
namedParameters.addValue(QueryType.GET_BATCH_MESSAGE_DATA.getParamName(2),message.getStartPosition());
return jdbcTemplate.query(sql, namedParameters, new BatchDataMapper());
}

View File

@ -1,6 +1,7 @@
package meerkat.bulletinboard.sqlserver;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import meerkat.bulletinboard.BulletinBoardConstants;
import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer.SQLQueryProvider;
import meerkat.protobuf.BulletinBoardAPI.FilterType;
@ -53,6 +54,11 @@ public class MySQLQueryProvider implements SQLQueryProvider {
"SELECT EntryNum From MsgTable WHERE MsgId = :{0}",
QueryType.FIND_MSG_ID.getParamName(0));
case FIND_TAG_ID:
return MessageFormat.format(
"SELECT TagId FROM TagTable WHERE Tag = :{0}",
QueryType.FIND_TAG_ID.getParamName(0));
case GET_MESSAGES:
return "SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable";
@ -75,11 +81,11 @@ public class MySQLQueryProvider implements SQLQueryProvider {
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}",
+ " 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));
@ -92,12 +98,21 @@ public class MySQLQueryProvider implements SQLQueryProvider {
QueryType.GET_BATCH_MESSAGE_DATA.getParamName(1),
QueryType.GET_BATCH_MESSAGE_DATA.getParamName(2));
case INSERT_BATCH_DATA:
return MessageFormat.format(
"INSERT INTO BatchTable (SignerId, BatchId, SerialNum, Data)"
+ " VALUES (:{0}, :{1}, :{2}, :{3})",
QueryType.INSERT_BATCH_DATA.getParamName(0),
QueryType.INSERT_BATCH_DATA.getParamName(1),
QueryType.INSERT_BATCH_DATA.getParamName(2),
QueryType.INSERT_BATCH_DATA.getParamName(3));
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));
QueryType.CHECK_BATCH_LENGTH.getParamName(0),
QueryType.CHECK_BATCH_LENGTH.getParamName(1));
case CONNECT_BATCH_TAG:
return MessageFormat.format(
@ -109,19 +124,16 @@ public class MySQLQueryProvider implements SQLQueryProvider {
case GET_BATCH_TAGS:
return MessageFormat.format(
"SELECT Tag FROM TagTable INNER JOIN BatchTagTable ON TagTable.TagId = BatchTagTable.Tag ID"
"SELECT Tag FROM TagTable INNER JOIN BatchTagTable ON TagTable.TagId = BatchTagTable.TagId"
+ " 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:
case REMOVE_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));
"DELETE FROM BatchTagTable WHERE SignerId = :{0} AND BatchId = :{1}",
QueryType.REMOVE_BATCH_TAGS.getParamName(0),
QueryType.REMOVE_BATCH_TAGS.getParamName(1));
default:
throw new IllegalArgumentException("Cannot serve a query of type " + queryType);
@ -187,6 +199,7 @@ public class MySQLQueryProvider implements SQLQueryProvider {
dataSource.setDatabaseName(dbName);
dataSource.setUser(username);
dataSource.setPassword(password);
dataSource.setAllowMultiQueries(true);
return dataSource;
}

View File

@ -1,6 +1,7 @@
package meerkat.bulletinboard.sqlserver.mappers;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import meerkat.protobuf.BulletinBoardAPI.BatchData;
import org.springframework.jdbc.core.RowMapper;
@ -15,7 +16,11 @@ public class BatchDataMapper implements RowMapper<BatchData> {
@Override
public BatchData mapRow(ResultSet rs, int rowNum) throws SQLException {
return BatchData.newBuilder().setData(ByteString.copyFrom(rs.getBytes(1))).build();
try {
return BatchData.parseFrom(rs.getBytes(1));
} catch (InvalidProtocolBufferException e) {
return BatchData.getDefaultInstance();
}
}
}

View File

@ -12,18 +12,13 @@ import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.List;
import java.util.Random;
import java.util.*;
import com.google.protobuf.ByteString;
import meerkat.comm.CommunicationException;
import meerkat.crypto.concrete.ECDSASignature;
import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage;
import meerkat.protobuf.BulletinBoardAPI.FilterType;
import meerkat.protobuf.BulletinBoardAPI.MessageFilter;
import meerkat.protobuf.BulletinBoardAPI.MessageFilterList;
import meerkat.protobuf.BulletinBoardAPI.UnsignedBulletinBoardMessage;
import meerkat.protobuf.BulletinBoardAPI.*;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
@ -31,7 +26,7 @@ import static org.hamcrest.CoreMatchers.*;
public class GenericBulletinBoardServerTest {
protected BulletinBoardServer bulletinBoardServer;
private ECDSASignature signers[];
private GenericBatchDigitalSignature signers[];
private ByteString[] signerIDs;
private Random random;
@ -51,6 +46,8 @@ public class GenericBulletinBoardServerTest {
private String[] tags;
private byte[][] data;
private List<CompleteBatch> completeBatches;
private final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); // Used to time the tests
/**
@ -71,10 +68,10 @@ public class GenericBulletinBoardServerTest {
this.bulletinBoardServer = bulletinBoardServer;
signers = new ECDSASignature[2];
signers = new GenericBatchDigitalSignature[2];
signerIDs = new ByteString[signers.length];
signers[0] = new ECDSASignature();
signers[1] = new ECDSASignature();
signers[0] = new GenericBatchDigitalSignature(new ECDSASignature());
signers[1] = new GenericBatchDigitalSignature(new ECDSASignature());
InputStream keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE);
char[] password = KEYFILE_PASSWORD1.toCharArray();
@ -121,6 +118,11 @@ public class GenericBulletinBoardServerTest {
long end = threadBean.getCurrentThreadCpuTime();
System.err.println("Finished initializing GenericBulletinBoardServerTest");
System.err.println("Time of operation: " + (end - start));
// Initialize Batch variables
completeBatches = new ArrayList<CompleteBatch>(10);
}
private byte randomByte(){
@ -377,6 +379,182 @@ public class GenericBulletinBoardServerTest {
System.err.println("Time of operation: " + (end - start));
}
/**
* Tests that posting a message before opening a batch does not work
* @throws CommunicationException
*/
public void testBatchPostAfterClose() throws CommunicationException, SignatureException {
final int BATCH_ID = 100;
CompleteBatch completeBatch = new CompleteBatch();
BoolMsg result;
// Create data
completeBatch.setBeginBatchMessage(BeginBatchMessage.newBuilder()
.setSignerId(signerIDs[1])
.setBatchId(BATCH_ID)
.addTag("Test")
.build());
BatchData batchData = BatchData.newBuilder()
.setData(ByteString.copyFrom((new byte[] {1,2,3,4})))
.build();
completeBatch.appendBatchData(batchData);
signers[1].updateContent(completeBatch);
completeBatch.setSignature(signers[1].sign());
// Begin batch
result = bulletinBoardServer.beginBatch(completeBatch.getBeginBatchMessage());
assertThat("Was not able to open batch", result.getValue(), is(true));
// Post data
BatchMessage batchMessage = BatchMessage.newBuilder()
.setSignerId(signerIDs[1])
.setBatchId(BATCH_ID)
.setData(batchData)
.build();
result = bulletinBoardServer.postBatchMessage(batchMessage);
assertThat("Was not able to post batch message", result.getValue(), is(true));
// Close batch
result = bulletinBoardServer.closeBatchMessage(CloseBatchMessage.newBuilder()
.setBatchId(BATCH_ID)
.setBatchLength(1)
.setSig(completeBatch.getSignature())
.build());
assertThat("Was not able to close batch", result.getValue(), is(true));
// Attempt to open batch again
result = bulletinBoardServer.beginBatch(completeBatch.getBeginBatchMessage());
assertThat("Was able to open a closed batch", result.getValue(), is(false));
// Attempt to add batch data
result = bulletinBoardServer.postBatchMessage(batchMessage);
assertThat("Was able to change a closed batch", result.getValue(), is(false));
}
/**
* Posts a complete batch message
* @throws CommunicationException
*/
public void testPostBatch() throws CommunicationException, SignatureException {
CompleteBatch completeBatch = new CompleteBatch();
int currentBatch = completeBatches.size();
BoolMsg result;
// Define batch data
String[] tempBatchTags = new String[]{randomString(),randomString(),randomString()};
byte[][] tempBatchData = new byte[Math.abs(randomByte())][];
for (int i = 0 ; i < tempBatchData.length ; i++) {
tempBatchData[i] = new byte[Math.abs(randomByte())];
for (int j = 0; j < tempBatchData[i].length; j++) {
tempBatchData[i][j] = randomByte();
}
}
// Begin batch
completeBatch.setBeginBatchMessage(BeginBatchMessage.newBuilder()
.setSignerId(signerIDs[0])
.setBatchId(currentBatch)
.addAllTag(Arrays.asList(tempBatchTags))
.build());
result = bulletinBoardServer.beginBatch(completeBatch.getBeginBatchMessage());
assertThat("Could not begin batch " + currentBatch, result.getValue(), is(true));
// Add batch data and randomize data posting order
List<Integer> dataOrder = new ArrayList<Integer>(tempBatchData.length);
for (int i = 0 ; i < tempBatchData.length ; i++) {
dataOrder.add(i);
completeBatch.appendBatchData(BatchData.newBuilder()
.setData(ByteString.copyFrom(tempBatchData[i]))
.build());
}
Collections.shuffle(dataOrder);
// Post data
for (int i = 0 ; i < tempBatchData.length ; i++) {
int dataIndex = dataOrder.get(i);
result = bulletinBoardServer.postBatchMessage(BatchMessage.newBuilder()
.setSignerId(signerIDs[0])
.setBatchId(currentBatch)
.setSerialNum(dataIndex)
.setData(completeBatch.getBatchDataList().get(dataIndex))
.build());
assertThat("Could not post batch data for batch ID " + currentBatch + " serial number " + dataIndex,
result.getValue(), is(true));
}
// Close batch
signers[0].updateContent(completeBatch);
completeBatch.setSignature(signers[0].sign());
result = bulletinBoardServer.closeBatchMessage(CloseBatchMessage.newBuilder()
.setBatchId(currentBatch)
.setBatchLength(tempBatchData.length)
.setSig(completeBatch.getSignature())
.build());
assertThat("Could not close batch " + currentBatch, result.getValue(), is(true));
// Update locally stored batches
completeBatches.add(completeBatch);
}
public void testReadBatch() throws CommunicationException {
for (CompleteBatch completeBatch : completeBatches) {
List<BatchData> batchDataList =
bulletinBoardServer.readBatch(BatchSpecificationMessage.newBuilder()
.setSignerId(completeBatch.getBeginBatchMessage().getSignerId())
.setBatchId(completeBatch.getBeginBatchMessage().getBatchId())
.setStartPosition(0)
.build());
assertThat("Non-matching batch data for batch " + completeBatch.getBeginBatchMessage().getBatchId(),
completeBatch.getBatchDataList().equals(batchDataList), is(true));
}
}
public void close(){
signers[0].clearSigningKey();

View File

@ -111,6 +111,39 @@ public class MySQLBulletinBoardServerTest {
System.err.println("Time of operation: " + (end - start));
}
@Test
public void testBatchPostAfterClose() {
try{
serverTest.testBatchPostAfterClose();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
}
@Test
public void testBatch() {
final int BATCH_NUM = 20;
try{
for (int i = 0 ; i < BATCH_NUM ; i++) {
serverTest.testPostBatch();
}
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
try{
serverTest.testReadBatch();
} catch (Exception e) {
System.err.println(e.getMessage());
fail(e.getMessage());
}
}
@After
public void close() {
System.err.println("Starting to close MySQLBulletinBoardServerTest");

View File

@ -16,6 +16,7 @@ public interface BulletinBoardConstants {
// Other Constants
public static final String BATCH_TAG = "Batch";
public static final String BATCH_TAG = "@BATCH";
public static final String BATCH_ID_TAG_PREFIX = "#";
}

View File

@ -22,6 +22,7 @@ public class CompleteBatch {
}
public CompleteBatch(BeginBatchMessage newBeginBatchMessage) {
this();
beginBatchMessage = newBeginBatchMessage;
}
@ -47,6 +48,10 @@ public class CompleteBatch {
return signature;
}
public void setBeginBatchMessage(BeginBatchMessage beginBatchMessage) {
this.beginBatchMessage = beginBatchMessage;
}
public void appendBatchData(BatchData newBatchData) {
batchDataList.add(newBatchData);
}

View File

@ -3,7 +3,6 @@ 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;
@ -11,10 +10,11 @@ import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.SignatureException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.List;
/**
* Created by Arbel Deutsch Peled on 20-Dec-15.
@ -77,6 +77,12 @@ public class GenericBatchDigitalSignature implements BatchDigitalSignature{
return digitalSignature.verify();
}
@Override
public KeyStore.Builder getPKCS12KeyStoreBuilder(InputStream keyStream, char[] password)
throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException {
return digitalSignature.getPKCS12KeyStoreBuilder(keyStream, password);
}
@Override
public void loadSigningCertificate(KeyStore.Builder keyStoreBuilder) throws IOException, CertificateException, UnrecoverableKeyException {
digitalSignature.loadSigningCertificate(keyStoreBuilder);

View File

@ -5,11 +5,13 @@ import com.google.protobuf.Message;
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.security.SignatureException;
import java.security.InvalidKeyException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import static meerkat.protobuf.Crypto.*;
/**
@ -71,6 +73,20 @@ public interface DigitalSignature {
*/
public boolean verify();
/**
* Load a keystore from an input stream in PKCS12 format.
*
* @param keyStream
* @param password
* @return
* @throws IOException
* @throws CertificateException
* @throws KeyStoreException
* @throws NoSuchAlgorithmException
*/
public KeyStore.Builder getPKCS12KeyStoreBuilder(InputStream keyStream, char[] password)
throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException;
/**
* Loads a private signing key. The keystore must include both the public and private
* key parts.

View File

@ -211,6 +211,7 @@ public class ECDSASignature implements DigitalSignature {
* @throws KeyStoreException
* @throws NoSuchAlgorithmException
*/
@Override
public KeyStore.Builder getPKCS12KeyStoreBuilder(InputStream keyStream, char[] password)
throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException {
KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE);