Defined semi-final versions of the batch interfaces.

Implemented in part extended BB Server interface.
Added Digest support for Batch messages.
Made GlobalCryptoSetup a final singleton.
Bulletin-Board-Batch
Arbel Deutsch Peled 2015-12-19 19:54:50 +02:00
parent 37fdc0bb83
commit 37f962d520
24 changed files with 516 additions and 102 deletions

View File

@ -117,6 +117,11 @@ public class ThreadedBulletinBoardClient extends SimpleBulletinBoardClient imple
// TODO: Implement // TODO: Implement
} }
@Override
public void subscribe(MessageFilterList filterList, MessageHandler messageHandler) {
// TODO: Implement
}
@Override @Override
public void close() { public void close() {
super.close(); super.close();

View File

@ -1,14 +1,8 @@
package meerkat.bulletinboard.callbacks; package meerkat.bulletinboard.callbacks;
import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.ListeningExecutorService;
import meerkat.bulletinboard.BulletinClientJob;
import meerkat.bulletinboard.BulletinClientJobResult; 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 * This is a future callback used to listen to workers and run on job finish

View File

@ -1,7 +1,7 @@
package meerkat.bulletinboard.callbacks; package meerkat.bulletinboard.callbacks;
import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.ListeningExecutorService;
import meerkat.bulletinboard.BulletinBoardClient; import meerkat.bulletinboard.AsyncBulletinBoardClient.*;
import meerkat.bulletinboard.BulletinClientJobResult; import meerkat.bulletinboard.BulletinClientJobResult;
import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.BulletinBoardAPI.*;
@ -13,10 +13,10 @@ import java.util.List;
*/ */
public class GetRedundancyFutureCallback extends ClientFutureCallback { public class GetRedundancyFutureCallback extends ClientFutureCallback {
private BulletinBoardClient.ClientCallback<Float> callback; private ClientCallback<Float> callback;
public GetRedundancyFutureCallback(ListeningExecutorService listeningExecutor, public GetRedundancyFutureCallback(ListeningExecutorService listeningExecutor,
BulletinBoardClient.ClientCallback<Float> callback) { ClientCallback<Float> callback) {
super(listeningExecutor); super(listeningExecutor);
this.callback = callback; this.callback = callback;
} }

View File

@ -2,13 +2,11 @@ package meerkat.bulletinboard.callbacks;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.ListeningExecutorService;
import meerkat.bulletinboard.BulletinBoardClient; import meerkat.bulletinboard.AsyncBulletinBoardClient.*;
import meerkat.bulletinboard.BulletinClientJob; import meerkat.bulletinboard.BulletinClientJob;
import meerkat.bulletinboard.BulletinClientJobResult; import meerkat.bulletinboard.BulletinClientJobResult;
import meerkat.bulletinboard.BulletinClientWorker; 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 * 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 { public class PostMessageFutureCallback extends ClientFutureCallback {
private BulletinBoardClient.ClientCallback<?> callback; private ClientCallback<?> callback;
public PostMessageFutureCallback(ListeningExecutorService listeningExecutor, public PostMessageFutureCallback(ListeningExecutorService listeningExecutor,
BulletinBoardClient.ClientCallback<?> callback) { ClientCallback<?> callback) {
super(listeningExecutor); super(listeningExecutor);
this.callback = callback; this.callback = callback;
} }

View File

@ -1,11 +1,8 @@
package meerkat.bulletinboard.callbacks; package meerkat.bulletinboard.callbacks;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListeningExecutorService; 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.BulletinClientJobResult;
import meerkat.bulletinboard.BulletinClientWorker;
import meerkat.protobuf.BulletinBoardAPI; import meerkat.protobuf.BulletinBoardAPI;
import java.util.List; import java.util.List;
@ -16,10 +13,10 @@ import java.util.List;
*/ */
public class ReadMessagesFutureCallback extends ClientFutureCallback { public class ReadMessagesFutureCallback extends ClientFutureCallback {
private BulletinBoardClient.ClientCallback<List<BulletinBoardAPI.BulletinBoardMessage>> callback; private ClientCallback<List<BulletinBoardAPI.BulletinBoardMessage>> callback;
public ReadMessagesFutureCallback(ListeningExecutorService listeningExecutor, public ReadMessagesFutureCallback(ListeningExecutorService listeningExecutor,
BulletinBoardClient.ClientCallback<List<BulletinBoardAPI.BulletinBoardMessage>> callback) { ClientCallback<List<BulletinBoardAPI.BulletinBoardMessage>> callback) {
super(listeningExecutor); super(listeningExecutor);
this.callback = callback; this.callback = callback;
} }

View File

@ -1,7 +1,6 @@
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import meerkat.bulletinboard.AsyncBulletinBoardClient; import meerkat.bulletinboard.AsyncBulletinBoardClient;
import meerkat.bulletinboard.BulletinBoardClient; import meerkat.bulletinboard.AsyncBulletinBoardClient.ClientCallback;
import meerkat.bulletinboard.BulletinBoardClient.ClientCallback;
import meerkat.bulletinboard.ThreadedBulletinBoardClient; import meerkat.bulletinboard.ThreadedBulletinBoardClient;
import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.BulletinBoardAPI.*;
import meerkat.protobuf.Crypto; import meerkat.protobuf.Crypto;

View File

@ -1,20 +1,29 @@
package meerkat.bulletinboard.sqlserver; package meerkat.bulletinboard.sqlserver;
import java.security.InvalidKeyException;
import java.security.cert.CertificateException;
import java.sql.*; import java.sql.*;
import java.util.*; import java.util.*;
import com.google.protobuf.ByteString;
import com.google.protobuf.ProtocolStringList; import com.google.protobuf.ProtocolStringList;
import meerkat.bulletinboard.BulletinBoardServer; import meerkat.bulletinboard.BulletinBoardServer;
import meerkat.bulletinboard.sqlserver.mappers.EntryNumMapper; import meerkat.bulletinboard.sqlserver.mappers.*;
import meerkat.bulletinboard.sqlserver.mappers.MessageMapper;
import meerkat.bulletinboard.sqlserver.mappers.SignatureMapper;
import meerkat.comm.CommunicationException; 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.BulletinBoardAPI.*;
import meerkat.protobuf.Crypto.Signature; import meerkat.protobuf.Crypto.Signature;
import meerkat.protobuf.Crypto.SignatureVerificationKey; 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; 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.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder; import org.springframework.jdbc.support.KeyHolder;
/** /**
* This is a generic SQL implementation of the BulletinBoardServer API. * 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"}), CONNECT_TAG(new String[] {"EntryNum","Tag"}),
ADD_SIGNATURE(new String[] {"EntryNum","SignerId","Signature"}), ADD_SIGNATURE(new String[] {"EntryNum","SignerId","Signature"}),
GET_SIGNATURES(new String[] {"EntryNum"}), 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; private String[] paramNames;
@ -58,6 +74,10 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
return paramNames; 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) { private Object getParam(MessageFilter messageFilter) {
switch (messageFilter.getType()) { switch (messageFilter.getType()) {
@ -170,7 +195,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
case MAX_MESSAGES: case MAX_MESSAGES:
return messageFilter.getMaxMessages(); return messageFilter.getMaxMessages();
default: default: // Unsupported filter type
return null; return null;
} }
@ -193,7 +218,8 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
protected NamedParameterJdbcTemplate jdbcTemplate; protected NamedParameterJdbcTemplate jdbcTemplate;
protected Digest digest; protected BatchDigest digest;
protected DigitalSignature signer;
protected List<SignatureVerificationKey> trusteeSignatureVerificationArray; protected List<SignatureVerificationKey> trusteeSignatureVerificationArray;
protected int minTrusteeSignatures; protected int minTrusteeSignatures;
@ -232,6 +258,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
// TODO write signature reading part. // TODO write signature reading part.
digest = new SHA256Digest(); digest = new SHA256Digest();
signer = new ECDSASignature();
jdbcTemplate = new NamedParameterJdbcTemplate(sqlQueryProvider.getDataSource()); jdbcTemplate = new NamedParameterJdbcTemplate(sqlQueryProvider.getDataSource());
@ -264,12 +291,12 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
String sql; String sql;
sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.INSERT_NEW_TAG); sql = sqlQueryProvider.getSQLString(QueryType.INSERT_NEW_TAG);
Map namedParameters[] = new HashMap[tags.length]; Map namedParameters[] = new HashMap[tags.length];
for (int i = 0 ; i < tags.length ; i++){ for (int i = 0 ; i < tags.length ; i++){
namedParameters[i] = new HashMap(); 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); 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. // 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(); Map namedParameters = new HashMap();
namedParameters.put("MsgId",msgID); namedParameters.put(QueryType.FIND_MSG_ID.getParamName(0),msgID);
List<Long> entryNums = jdbcTemplate.query(sql, new MapSqlParameterSource(namedParameters), new EntryNumMapper()); List<Long> entryNums = jdbcTemplate.query(sql, new MapSqlParameterSource(namedParameters), new LongMapper());
if (entryNums.size() > 0){ if (entryNums.size() > 0){
@ -328,8 +355,8 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
} else{ } else{
sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.INSERT_MSG); sql = sqlQueryProvider.getSQLString(QueryType.INSERT_MSG);
namedParameters.put("Msg", msg.getMsg().toByteArray()); namedParameters.put(QueryType.INSERT_MSG.getParamName(0), msg.getMsg().toByteArray());
KeyHolder keyHolder = new GeneratedKeyHolder(); KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(sql,new MapSqlParameterSource(namedParameters),keyHolder); jdbcTemplate.update(sql,new MapSqlParameterSource(namedParameters),keyHolder);
@ -354,14 +381,14 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
// Connect message to tags. // Connect message to tags.
sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.CONNECT_TAG); sql = sqlQueryProvider.getSQLString(QueryType.CONNECT_TAG);
namedParameterArray = new HashMap[tags.length]; namedParameterArray = new HashMap[tags.length];
for (int i = 0 ; i < tags.length ; i++) { for (int i = 0 ; i < tags.length ; i++) {
namedParameterArray[i] = new HashMap(); namedParameterArray[i] = new HashMap();
namedParameterArray[i].put("EntryNum", entryNum); namedParameterArray[i].put(QueryType.CONNECT_TAG.getParamName(0), entryNum);
namedParameterArray[i].put("Tag", tags[i]); namedParameterArray[i].put(QueryType.CONNECT_TAG.getParamName(1), tags[i]);
} }
jdbcTemplate.batchUpdate(sql, namedParameterArray); jdbcTemplate.batchUpdate(sql, namedParameterArray);
@ -374,15 +401,15 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
// Connect message to signatures. // Connect message to signatures.
sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.ADD_SIGNATURE); sql = sqlQueryProvider.getSQLString(QueryType.ADD_SIGNATURE);
namedParameterArray = new HashMap[signatures.length]; namedParameterArray = new HashMap[signatures.length];
for (int i = 0 ; i < signatures.length ; i++) { for (int i = 0 ; i < signatures.length ; i++) {
namedParameterArray[i] = new HashMap(); namedParameterArray[i] = new HashMap();
namedParameterArray[i].put("EntryNum", entryNum); namedParameterArray[i].put(QueryType.ADD_SIGNATURE.getParamName(0), entryNum);
namedParameterArray[i].put("SignerId", signatures[i].getSignerId().toByteArray()); namedParameterArray[i].put(QueryType.ADD_SIGNATURE.getParamName(1), signatures[i].getSignerId().toByteArray());
namedParameterArray[i].put("Signature", signatures[i].toByteArray()); namedParameterArray[i].put(QueryType.ADD_SIGNATURE.getParamName(2), signatures[i].toByteArray());
} }
jdbcTemplate.batchUpdate(sql,namedParameterArray); jdbcTemplate.batchUpdate(sql,namedParameterArray);
@ -412,7 +439,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
// Check if Tag/Signature tables are required for filtering purposes // 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 // Add conditions
namedParameters = new MapSqlParameterSource(); namedParameters = new MapSqlParameterSource();
@ -434,7 +461,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
sqlBuilder.append(sqlQueryProvider.getCondition(filter.getType(), paramNum)); sqlBuilder.append(sqlQueryProvider.getCondition(filter.getType(), paramNum));
SQLQueryProvider.FilterTypeParam filterTypeParam = SQLQueryProvider.FilterTypeParam.getFilterTypeParamName(filter.getType()); FilterTypeParam filterTypeParam = FilterTypeParam.getFilterTypeParamName(filter.getType());
namedParameters.addValue( namedParameters.addValue(
filterTypeParam.getParamName() + Integer.toString(paramNum), filterTypeParam.getParamName() + Integer.toString(paramNum),
@ -457,10 +484,10 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
// Retrieve signatures // Retrieve signatures
namedParameters = new MapSqlParameterSource(); namedParameters = new MapSqlParameterSource();
namedParameters.addValue("EntryNum", msgBuilder.getEntryNum()); namedParameters.addValue(QueryType.GET_SIGNATURES.getParamName(0), msgBuilder.getEntryNum());
List<Signature> signatures = jdbcTemplate.query( List<Signature> signatures = jdbcTemplate.query(
sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.GET_SIGNATURES), sqlQueryProvider.getSQLString(QueryType.GET_SIGNATURES),
namedParameters, namedParameters,
signatureMapper); 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<Long> 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<Long> 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<BatchData> 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<BatchData> readBatch(BatchSpecificationMessage message) {
return null; // TODO: Implement this
}
@Override @Override
public void close() {} public void close() {}

View File

@ -5,6 +5,7 @@ import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer.SQLQueryProvider;
import meerkat.protobuf.BulletinBoardAPI.FilterType; import meerkat.protobuf.BulletinBoardAPI.FilterType;
import javax.sql.DataSource; import javax.sql.DataSource;
import java.text.MessageFormat;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -32,21 +33,72 @@ public class MySQLQueryProvider implements SQLQueryProvider {
public String getSQLString(QueryType queryType) throws IllegalArgumentException{ public String getSQLString(QueryType queryType) throws IllegalArgumentException{
switch(queryType) { switch(queryType) {
case ADD_SIGNATURE: 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: case CONNECT_TAG:
return "INSERT IGNORE INTO MsgTagTable (TagId, EntryNum)" return MessageFormat.format(
+ " SELECT TagTable.TagId, :EntryNum AS EntryNum FROM TagTable WHERE Tag = :Tag"; "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: 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: case GET_MESSAGES:
return "SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable"; return "SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable";
case GET_SIGNATURES: 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: 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: 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: default:
throw new IllegalArgumentException("Cannot serve a query of type " + queryType); throw new IllegalArgumentException("Cannot serve a query of type " + queryType);
} }
@ -119,7 +171,8 @@ public class MySQLQueryProvider implements SQLQueryProvider {
public List<String> getSchemaCreationCommands() { public List<String> getSchemaCreationCommands() {
List<String> list = new LinkedList<String>(); List<String> list = new LinkedList<String>();
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))"); 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))"); + " CONSTRAINT UNIQUE (EntryNum, TagID))");
list.add("CREATE TABLE IF NOT EXISTS SignatureTable (EntryNum INT, SignerId TINYBLOB, Signature TINYBLOB," 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; return list;
} }
@ -138,6 +198,8 @@ public class MySQLQueryProvider implements SQLQueryProvider {
public List<String> getSchemaDeletionCommands() { public List<String> getSchemaDeletionCommands() {
List<String> list = new LinkedList<String>(); List<String> list = new LinkedList<String>();
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 MsgTagTable");
list.add("DROP TABLE IF EXISTS SignatureTable"); list.add("DROP TABLE IF EXISTS SignatureTable");
list.add("DROP TABLE IF EXISTS TagTable"); list.add("DROP TABLE IF EXISTS TagTable");

View File

@ -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<BatchData> {
@Override
public BatchData mapRow(ResultSet rs, int rowNum) throws SQLException {
return BatchData.newBuilder().setData(ByteString.copyFrom(rs.getBytes(rowNum))).build();
}
}

View File

@ -9,7 +9,7 @@ import java.sql.SQLException;
/** /**
* Created by Arbel Deutsch Peled on 11-Dec-15. * Created by Arbel Deutsch Peled on 11-Dec-15.
*/ */
public class EntryNumMapper implements RowMapper<Long> { public class LongMapper implements RowMapper<Long> {
@Override @Override
public Long mapRow(ResultSet rs, int rowNum) throws SQLException { public Long mapRow(ResultSet rs, int rowNum) throws SQLException {

View File

@ -17,12 +17,11 @@ import meerkat.bulletinboard.sqlserver.H2QueryProvider;
import meerkat.bulletinboard.sqlserver.MySQLQueryProvider; import meerkat.bulletinboard.sqlserver.MySQLQueryProvider;
import meerkat.bulletinboard.sqlserver.SQLiteQueryProvider; import meerkat.bulletinboard.sqlserver.SQLiteQueryProvider;
import meerkat.comm.CommunicationException; import meerkat.comm.CommunicationException;
import meerkat.protobuf.BulletinBoardAPI.BoolMsg; import meerkat.protobuf.BulletinBoardAPI.*;
import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage;
import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessageList;
import meerkat.protobuf.BulletinBoardAPI.MessageFilterList;
import meerkat.rest.Constants; import meerkat.rest.Constants;
import java.util.List;
@Path(Constants.BULLETIN_BOARD_SERVER_PATH) @Path(Constants.BULLETIN_BOARD_SERVER_PATH)
public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextListener{ public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextListener{
@ -99,6 +98,58 @@ public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextL
return bulletinBoard.readMessages(filterList); 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<BatchData> readBatch(BatchSpecificationMessage message) {
try {
return bulletinBoard.readBatch(message);
} catch (CommunicationException | IllegalArgumentException e) {
System.err.println(e.getMessage());
return null;
}
}
@Override @Override
public void close(){ public void close(){
try { try {

View File

@ -9,13 +9,22 @@ import java.util.List;
*/ */
public interface AsyncBulletinBoardClient extends BulletinBoardClient { public interface AsyncBulletinBoardClient extends BulletinBoardClient {
public interface ClientCallback<T> {
void handleCallback(T msg);
void handleFailure(Throwable t);
}
public interface MessageHandler {
void handleNewMessages(List<BulletinBoardMessage> messageList);
}
/** /**
* Post a message to the bulletin board in an asynchronous manner * Post a message to the bulletin board in an asynchronous manner
* @param msg is the message to be posted * @param msg is the message to be posted
* @param callback is a class containing methods to handle the result of the operation * @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 * @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 * 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 * @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 * @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<BatchData> batchDataList, int startPosition, ClientCallback<?> callback); public MessageID postBatch(byte[] signerId, int batchId, List<BatchData> batchDataList, int startPosition, ClientCallback<?> callback);
/** /**
* Overloading of the postBatch method in which startPosition is set to the default value 0 * Overloading of the postBatch method in which startPosition is set to the default value 0
*/ */
MessageID postBatch(byte[] signerId, int batchId, List<BatchData> batchDataList, ClientCallback<?> callback); public MessageID postBatch(byte[] signerId, int batchId, List<BatchData> batchDataList, ClientCallback<?> callback);
/** /**
* Check how "safe" a given message is in an asynchronous manner * 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 id is the unique message identifier for retrieval
* @param callback is a callback function class for handling results of the operation * @param callback is a callback function class for handling results of the operation
*/ */
void getRedundancy(MessageID id, ClientCallback<Float> callback); public void getRedundancy(MessageID id, ClientCallback<Float> callback);
/** /**
* Read all messages posted matching the given filter in an asynchronous manner * 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 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 * @param callback is a callback function class for handling results of the operation
*/ */
void readMessages(MessageFilterList filterList, ClientCallback<List<BulletinBoardMessage>> callback); public void readMessages(MessageFilterList filterList, ClientCallback<List<BulletinBoardMessage>> callback);
/** /**
* Read a given batch message from the bulletin board * 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 batchId is the unique (per signer) ID of the batch
* @param callback is a callback class for handling the result of the operation * @param callback is a callback class for handling the result of the operation
*/ */
void readBatch(byte[] signerId, int batchId, ClientCallback<SignedBatch> callback); public void readBatch(byte[] signerId, int batchId, ClientCallback<SignedBatch> 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);
} }

View File

@ -12,11 +12,6 @@ import java.util.List;
*/ */
public interface BulletinBoardClient { public interface BulletinBoardClient {
interface ClientCallback<T> {
void handleCallback(T msg);
void handleFailure(Throwable t);
}
/** /**
* Initialize the client to use some specified servers * Initialize the client to use some specified servers
* @param clientParams contains the parameters required for the client setup * @param clientParams contains the parameters required for the client setup

View File

@ -3,40 +3,83 @@ package meerkat.bulletinboard;
import meerkat.comm.CommunicationException; import meerkat.comm.CommunicationException;
import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.BulletinBoardAPI.*;
import java.util.List;
/** /**
* Created by Arbel on 07/11/15. * Created by Arbel on 07/11/15.
* *
* This interface refers to a single instance of a Bulletin Board. * 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. * An implementation of this interface may use any DB and be hosted on any machine.
*/ */
public interface BulletinBoardServer{ public interface BulletinBoardServer{
/** /**
* This method initializes the server by reading the signature data and storing it. * This method initializes the server by reading the signature data and storing it
* It also establishes the connection to the DB. * It also establishes the connection to the DB
* @throws CommunicationException on DB connection error. * @throws CommunicationException on DB connection error
*/ */
public void init(String meerkatDB) throws CommunicationException; public void init(String meerkatDB) throws CommunicationException;
/** /**
* Post a message to bulletin board. * Post a message to bulletin board.
* @param msg is the actual (signed) message * @param msg is the actual (signed) message
* @return TRUE if the message has been authenticated and FALSE otherwise (in ProtoBuf form). * @return TRUE if the message has been authenticated and FALSE otherwise (in ProtoBuf form)
* @throws CommunicationException on DB connection error. * @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. * Read all messages posted matching the given filter
* @param filter return only messages that match the filter (empty list means no filtering). * @param filterList return only messages that match the filters (empty list or null means no filtering)
* @return * @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<BatchData> readBatch(BatchSpecificationMessage message) throws CommunicationException, IllegalArgumentException;
/** /**
* This method closes the connection to the DB. * This method closes the connection to the DB
* @throws CommunicationException on DB connection error. * @throws CommunicationException on DB connection error
*/ */
public void close() throws CommunicationException; public void close() throws CommunicationException;
} }

View File

@ -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<BatchData> batchDataList);
}

View File

@ -13,7 +13,7 @@ public interface Digest {
* (copied from {@link MessageDigest#digest()}) * (copied from {@link MessageDigest#digest()})
* @return * @return
*/ */
byte[] digest(); public byte[] digest();
/** /**
* Updates the digest using the specified message (in serialized wire form) * Updates the digest using the specified message (in serialized wire form)
@ -22,12 +22,12 @@ public interface Digest {
* @param msg * @param msg
* @return * @return
*/ */
void update(Message msg); public void update(Message msg);
/** /**
* Resets the digest for further use. * Resets the digest for further use.
*/ */
void reset(); public void reset();
/** /**
* Clone the current digest state * Clone the current digest state

View File

@ -30,7 +30,10 @@ import javax.security.auth.callback.UnsupportedCallbackException;
* *
* This class is not thread-safe (each thread should have its own instance). * 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 Logger logger = LoggerFactory.getLogger(getClass());
final public static String KEYSTORE_TYPE = "PKCS12"; final public static String KEYSTORE_TYPE = "PKCS12";

View File

@ -31,7 +31,10 @@ import java.util.Random;
/** /**
* Created by talm on 17/11/15. * 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()); final Logger logger = LoggerFactory.getLogger(getClass());
public final static String KEY_ALGORITHM = "ECDH"; public final static String KEY_ALGORITHM = "ECDH";

View File

@ -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<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

@ -10,13 +10,26 @@ import java.security.Security;
/** /**
* A class that performs required crypto setup * 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); final static Logger logger = LoggerFactory.getLogger(GlobalCryptoSetup.class);
static boolean loadedBouncyCastle = false; private boolean loadedBouncyCastle = false;
static Provider bouncyCastleProvider; 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 // For now we just check if the java version is at least 8
String[] version = System.getProperty("java.version").split("\\."); String[] version = System.getProperty("java.version").split("\\.");
int major = Integer.parseInt(version[0]); int major = Integer.parseInt(version[0]);
@ -24,9 +37,11 @@ public class GlobalCryptoSetup {
return ((major > 1) || ((major > 0) && (minor > 7))); 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) { if (bouncyCastleProvider == null) {
bouncyCastleProvider = new BouncyCastleProvider(); bouncyCastleProvider = new BouncyCastleProvider();
// Make bouncycastle our default provider if we're running on a JVM version < 8 // Make bouncycastle our default provider if we're running on a JVM version < 8
@ -39,5 +54,4 @@ public class GlobalCryptoSetup {
} }
} }
public GlobalCryptoSetup() { doSetup(); }
} }

View File

@ -2,6 +2,7 @@ package meerkat.crypto.concrete;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import com.google.protobuf.Message; import com.google.protobuf.Message;
import meerkat.crypto.BatchDigest;
import meerkat.crypto.Digest; import meerkat.crypto.Digest;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -13,7 +14,7 @@ import java.security.NoSuchAlgorithmException;
/** /**
* Created by talm on 11/9/15. * 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()); final Logger logger = LoggerFactory.getLogger(getClass());
public static final String SHA256 = "SHA-256"; public static final String SHA256 = "SHA-256";

View File

@ -105,3 +105,10 @@ message BatchMessage {
int32 serialNum = 3; // Location of the message in the batch: starting from 0 int32 serialNum = 3; // Location of the message in the batch: starting from 0
BatchData data = 4; // Actual data 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
}

View File

@ -26,6 +26,9 @@ import java.security.spec.InvalidKeySpecException;
* utilities for ECElgamal * utilities for ECElgamal
*/ */
public class ECElGamalUtils { public class ECElGamalUtils {
private static GlobalCryptoSetup globalCryptoSetup = GlobalCryptoSetup.getInstance();
final static Logger logger = LoggerFactory.getLogger(ECElGamalUtils.class); final static Logger logger = LoggerFactory.getLogger(ECElGamalUtils.class);
public final static String ENCRYPTION_KEY_ALGORITHM = "ECDH"; public final static String ENCRYPTION_KEY_ALGORITHM = "ECDH";
@ -43,7 +46,7 @@ public class ECElGamalUtils {
try { try {
KeyFactory fact = KeyFactory.getInstance(ENCRYPTION_KEY_ALGORITHM, KeyFactory fact = KeyFactory.getInstance(ENCRYPTION_KEY_ALGORITHM,
GlobalCryptoSetup.getBouncyCastleProvider()); globalCryptoSetup.getBouncyCastleProvider());
PublicKey javaPk = fact.generatePublic(pubKeySpec); PublicKey javaPk = fact.generatePublic(pubKeySpec);
ConcreteCrypto.ElGamalPublicKey serializedPk = ConcreteCrypto.ElGamalPublicKey.newBuilder() ConcreteCrypto.ElGamalPublicKey serializedPk = ConcreteCrypto.ElGamalPublicKey.newBuilder()
.setSubjectPublicKeyInfo(ByteString.copyFrom(javaPk.getEncoded())).build(); .setSubjectPublicKeyInfo(ByteString.copyFrom(javaPk.getEncoded())).build();

View File

@ -9,4 +9,8 @@ public interface Constants {
public static final String BULLETIN_BOARD_SERVER_PATH = "/bbserver"; public static final String BULLETIN_BOARD_SERVER_PATH = "/bbserver";
public static final String READ_MESSAGES_PATH = "/readmessages"; public static final String READ_MESSAGES_PATH = "/readmessages";
public static final String POST_MESSAGE_PATH = "/postmessage"; 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";
} }