stop
parent
3e1f59ec2b
commit
d0951f8644
|
@ -2,8 +2,8 @@ package meerkat.bulletinboard;
|
|||
|
||||
import com.google.protobuf.Message;
|
||||
import meerkat.comm.CommunicationException;
|
||||
import meerkat.crypto.Digest;
|
||||
import meerkat.crypto.concrete.SHA256Digest;
|
||||
import meerkat.destributed_key_generation.Digest;
|
||||
import meerkat.destributed_key_generation.concrete.SHA256Digest;
|
||||
import meerkat.protobuf.BulletinBoardAPI.*;
|
||||
import meerkat.rest.Constants;
|
||||
import meerkat.rest.ProtobufMessageBodyReader;
|
||||
|
|
|
@ -2,8 +2,8 @@ package meerkat.bulletinboard;
|
|||
|
||||
import com.google.protobuf.ByteString;
|
||||
import meerkat.comm.CommunicationException;
|
||||
import meerkat.crypto.Digest;
|
||||
import meerkat.crypto.concrete.SHA256Digest;
|
||||
import meerkat.destributed_key_generation.Digest;
|
||||
import meerkat.destributed_key_generation.concrete.SHA256Digest;
|
||||
import meerkat.protobuf.BulletinBoardAPI.*;
|
||||
import meerkat.protobuf.Voting;
|
||||
import meerkat.protobuf.Voting.BulletinBoardClientParams;
|
||||
|
|
|
@ -6,8 +6,8 @@ import meerkat.bulletinboard.callbacks.GetRedundancyFutureCallback;
|
|||
import meerkat.bulletinboard.callbacks.PostMessageFutureCallback;
|
||||
import meerkat.bulletinboard.callbacks.ReadMessagesFutureCallback;
|
||||
import meerkat.comm.CommunicationException;
|
||||
import meerkat.crypto.Digest;
|
||||
import meerkat.crypto.concrete.SHA256Digest;
|
||||
import meerkat.destributed_key_generation.Digest;
|
||||
import meerkat.destributed_key_generation.concrete.SHA256Digest;
|
||||
import meerkat.protobuf.BulletinBoardAPI.*;
|
||||
import meerkat.protobuf.Voting;
|
||||
|
||||
|
|
|
@ -13,8 +13,8 @@ import meerkat.comm.CommunicationException;
|
|||
import meerkat.protobuf.BulletinBoardAPI.*;
|
||||
import meerkat.protobuf.Crypto.Signature;
|
||||
import meerkat.protobuf.Crypto.SignatureVerificationKey;
|
||||
import meerkat.crypto.Digest;
|
||||
import meerkat.crypto.concrete.SHA256Digest;
|
||||
import meerkat.destributed_key_generation.Digest;
|
||||
import meerkat.destributed_key_generation.concrete.SHA256Digest;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ import java.util.Random;
|
|||
import com.google.protobuf.ByteString;
|
||||
|
||||
import meerkat.comm.CommunicationException;
|
||||
import meerkat.crypto.concrete.ECDSASignature;
|
||||
import meerkat.destributed_key_generation.concrete.ECDSASignature;
|
||||
import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage;
|
||||
import meerkat.protobuf.BulletinBoardAPI.FilterType;
|
||||
import meerkat.protobuf.BulletinBoardAPI.MessageFilter;
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
package meerkat.crypto;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Created by Tzlil on 4/8/2016.
|
||||
*/
|
||||
public interface KeyGeneration<T> {
|
||||
|
||||
T generateKey(Random random);
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
package meerkat.crypto;
|
||||
|
||||
/**
|
||||
* Created by Tzlil on 4/8/2016.
|
||||
*/
|
||||
public class SecretSharing {
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package meerkat.crypto.utilitis;
|
||||
|
||||
/**
|
||||
* Created by Tzlil on 3/17/2016.
|
||||
*/
|
||||
public interface Arithmetic<T> {
|
||||
/**
|
||||
*
|
||||
* @param a
|
||||
* @param b
|
||||
* @return
|
||||
*/
|
||||
T add(T a, T b);
|
||||
T sub(T a, T b);
|
||||
T mul(T a, T b);
|
||||
T div(T a, T b);
|
||||
|
||||
}
|
|
@ -1,36 +1,59 @@
|
|||
package meerkat.crypto.concrete.distributed_key_generation.communication;
|
||||
package meerkat.destributed_key_generation.concrete.distributed_key_generation.communication;
|
||||
|
||||
import com.google.protobuf.Message;
|
||||
import meerkat.crypto.utilitis.Channel;
|
||||
import meerkat.destributed_key_generation.utilitis.Channel;
|
||||
import meerkat.protobuf.DKGMessages;
|
||||
|
||||
/**
|
||||
* Created by Tzlil on 2/14/2016.
|
||||
*
|
||||
* an implementation of ReceiverCallback
|
||||
*/
|
||||
public abstract class MailHandler implements Channel.ReceiverCallback{
|
||||
|
||||
/**
|
||||
* fixed value for broadcasting
|
||||
*/
|
||||
public static final int BROADCAST = 0;
|
||||
|
||||
/**
|
||||
* message handler
|
||||
*/
|
||||
private MessageHandler messageHandler;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
* @param messageHandler
|
||||
*/
|
||||
public MailHandler(MessageHandler messageHandler){
|
||||
this.messageHandler = messageHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* extract message from mail
|
||||
* @param mail
|
||||
* @return
|
||||
*/
|
||||
public abstract Message extractMessage(DKGMessages.Mail mail);
|
||||
|
||||
/**
|
||||
* is this mail was received by broadcast channel
|
||||
* @param mail
|
||||
* @return mail user destination == BROADCAST
|
||||
*/
|
||||
public boolean isBroadcast(DKGMessages.Mail mail){
|
||||
return mail.getDestination() == BROADCAST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveMail(DKGMessages.Mail mail){
|
||||
|
||||
Message message = extractMessage(mail);
|
||||
if (message == null)
|
||||
return;
|
||||
|
||||
switch (mail.getType()) {
|
||||
case SHARE:
|
||||
messageHandler.handleSecretMessage(mail.getSender(), isBroadcast(mail),message);
|
||||
messageHandler.handleShareMessage(mail.getSender(), isBroadcast(mail),message);
|
||||
break;
|
||||
case COMMITMENT:
|
||||
messageHandler.handleCommitmentMessage(mail.getSender(), isBroadcast(mail),message);
|
|
@ -1,15 +1,39 @@
|
|||
package meerkat.crypto.concrete.distributed_key_generation.communication;
|
||||
package meerkat.destributed_key_generation.concrete.distributed_key_generation.communication;
|
||||
|
||||
import com.google.protobuf.Message;
|
||||
|
||||
/**
|
||||
* Created by Tzlil on 2/14/2016.
|
||||
* an interface for handling received messages
|
||||
*/
|
||||
public interface MessageHandler {
|
||||
void handleSecretMessage(int sender, boolean isBroadcast, Message message);
|
||||
/**
|
||||
* handle share message
|
||||
*/
|
||||
void handleShareMessage(int sender, boolean isBroadcast, Message message);
|
||||
|
||||
/**
|
||||
* handle commitment message
|
||||
*/
|
||||
void handleCommitmentMessage(int sender, boolean isBroadcast, Message message);
|
||||
|
||||
/**
|
||||
* handle complaint message
|
||||
*/
|
||||
void handleComplaintMessage(int sender, boolean isBroadcast, Message message);
|
||||
|
||||
/**
|
||||
* handle done message
|
||||
*/
|
||||
void handleDoneMessage(int sender, boolean isBroadcast, Message message);
|
||||
|
||||
/**
|
||||
* handle answer message
|
||||
*/
|
||||
void handleAnswerMessage(int sender, boolean isBroadcast, Message message);
|
||||
|
||||
/**
|
||||
* handle abort message
|
||||
*/
|
||||
void handleAbortMessage(int sender, boolean isBroadcast, Message message);
|
||||
}
|
|
@ -1,17 +1,26 @@
|
|||
package meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol;
|
||||
package meerkat.destributed_key_generation.concrete.distributed_key_generation.gjkr_secure_protocol;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.google.protobuf.Message;
|
||||
import meerkat.crypto.concrete.distributed_key_generation.communication.MessageHandler;
|
||||
import meerkat.destributed_key_generation.concrete.distributed_key_generation.communication.MessageHandler;
|
||||
import meerkat.protobuf.DKGMessages;
|
||||
|
||||
/**
|
||||
* Created by Tzlil on 2/29/2016.
|
||||
* an extension of MailHandler matching gjkr protocl
|
||||
*/
|
||||
public class MailHandler extends meerkat.crypto.concrete.distributed_key_generation.communication.MailHandler {
|
||||
public class MailHandler extends meerkat.destributed_key_generation.concrete.distributed_key_generation.communication.MailHandler {
|
||||
|
||||
/**
|
||||
* flag that indicants whether the
|
||||
* current run achieved stage 4 of the protocol or not
|
||||
*/
|
||||
private boolean isStage4;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
* @param messageHandler
|
||||
*/
|
||||
public MailHandler(MessageHandler messageHandler) {
|
||||
super(messageHandler);
|
||||
this.isStage4 = false;
|
||||
|
@ -52,10 +61,10 @@ public class MailHandler extends meerkat.crypto.concrete.distributed_key_generat
|
|||
}
|
||||
}
|
||||
|
||||
public boolean isStage4() {
|
||||
return isStage4;
|
||||
}
|
||||
|
||||
/**
|
||||
* setter
|
||||
* @param stage4
|
||||
*/
|
||||
public void setStage4(boolean stage4) {
|
||||
isStage4 = stage4;
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol;
|
||||
package meerkat.destributed_key_generation.concrete.distributed_key_generation.gjkr_secure_protocol;
|
||||
|
||||
import meerkat.crypto.concrete.secret_shring.shamir.Polynomial;
|
||||
import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
|
@ -13,7 +13,7 @@ import java.util.Set;
|
|||
* contains all relevant information on specific party during
|
||||
* the run of the safe protocol
|
||||
*/
|
||||
public class Party<T> extends meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.Party<T> {
|
||||
public class Party<T> extends meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol.Party<T> {
|
||||
public Polynomial.Point shareT;
|
||||
public boolean ysDoneFlag;
|
||||
public ArrayList<T> verifiableValues;
|
|
@ -1,7 +1,7 @@
|
|||
package meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol;
|
||||
package meerkat.destributed_key_generation.concrete.distributed_key_generation.gjkr_secure_protocol;
|
||||
|
||||
import meerkat.crypto.concrete.secret_shring.feldman_verifiable.VerifiableSecretSharing;
|
||||
import meerkat.crypto.concrete.secret_shring.shamir.Polynomial;
|
||||
import meerkat.destributed_key_generation.concrete.secret_shring.feldman_verifiable.VerifiableSecretSharing;
|
||||
import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial;
|
||||
import com.google.protobuf.ByteString;
|
||||
import meerkat.protobuf.DKGMessages;
|
||||
import org.factcenter.qilin.primitives.Group;
|
||||
|
@ -17,7 +17,7 @@ import java.util.Set;
|
|||
* TODO: comments
|
||||
* TODO: put Channel (ChannelImpl) in constructor
|
||||
*/
|
||||
public class Protocol<T> extends meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.Protocol<T> {
|
||||
public class Protocol<T> extends meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol.Protocol<T> {
|
||||
|
||||
private VerifiableSecretSharing<T> maskingShares;
|
||||
private final T h;
|
|
@ -1,10 +1,10 @@
|
|||
package meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol;
|
||||
package meerkat.destributed_key_generation.concrete.distributed_key_generation.gjkr_secure_protocol;
|
||||
|
||||
import meerkat.crypto.utilitis.Arithmetic;
|
||||
import meerkat.crypto.utilitis.concrete.Fp;
|
||||
import meerkat.crypto.utilitis.Channel;
|
||||
import meerkat.crypto.concrete.secret_shring.shamir.Polynomial;
|
||||
import meerkat.crypto.concrete.secret_shring.shamir.SecretSharing;
|
||||
import meerkat.destributed_key_generation.utilitis.Arithmetic;
|
||||
import meerkat.destributed_key_generation.utilitis.concrete.Fp;
|
||||
import meerkat.destributed_key_generation.utilitis.Channel;
|
||||
import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial;
|
||||
import meerkat.destributed_key_generation.concrete.secret_shring.shamir.SecretSharing;
|
||||
import com.google.protobuf.Message;
|
||||
import meerkat.protobuf.DKGMessages;
|
||||
|
||||
|
@ -13,25 +13,48 @@ import java.util.ArrayList;
|
|||
|
||||
/**
|
||||
* Created by Tzlil on 3/16/2016.
|
||||
*
|
||||
* implementation of gjkr protocol user.
|
||||
*
|
||||
* this protocol extends joint feldman protocol by splitting the protocol to commitment stage (stages 1,2,3)
|
||||
* and reviling stage (stage 4).
|
||||
*
|
||||
* as in joint feldman, each party in QUAL has his own share of the generated random key.
|
||||
* this key can be recover by any subset of QUAL of size at least t + 1.
|
||||
*/
|
||||
public class User<T> extends meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.User<T> {
|
||||
public class User<T> extends meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol.User<T> {
|
||||
|
||||
/**
|
||||
* All parties participating in key generation.
|
||||
* parties[id-1] has my info.
|
||||
*/
|
||||
protected Party<T>[] parties;
|
||||
protected final Protocol<T> sdkg;
|
||||
private Arithmetic<BigInteger> arithmetic;
|
||||
private boolean isStage4;
|
||||
|
||||
/**
|
||||
* gjkr secure protocol object
|
||||
*/
|
||||
protected final Protocol<T> sdkg;
|
||||
|
||||
/**
|
||||
* message handler
|
||||
*/
|
||||
private MessageHandler messageHandler;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
* @param sdkg gjkr protocol object
|
||||
* @param channel channel object
|
||||
*/
|
||||
public User(Protocol<T> sdkg, Channel channel) {
|
||||
super(sdkg, channel);
|
||||
this.sdkg = sdkg;
|
||||
this.parties = sdkg.getParties();
|
||||
this.arithmetic = new Fp(sdkg.getQ());
|
||||
this.isStage4 = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerReceiverCallback(){
|
||||
this.mailHandler = new MailHandler(new MessageHandler());
|
||||
this.messageHandler = new MessageHandler();
|
||||
this.mailHandler = new MailHandler(messageHandler);
|
||||
this.channel.registerReceiverCallback(mailHandler);
|
||||
}
|
||||
/**
|
||||
|
@ -84,7 +107,7 @@ public class User<T> extends meerkat.crypto.concrete.distributed_key_generation.
|
|||
try {
|
||||
parties[i - 1].wait();
|
||||
} catch (InterruptedException e) {
|
||||
//do nothing
|
||||
if (stop) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -102,7 +125,7 @@ public class User<T> extends meerkat.crypto.concrete.distributed_key_generation.
|
|||
try {
|
||||
parties[i - 1].wait();
|
||||
} catch (InterruptedException e) {
|
||||
//do nothing
|
||||
if (stop) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -122,13 +145,13 @@ public class User<T> extends meerkat.crypto.concrete.distributed_key_generation.
|
|||
try {
|
||||
parties[i - 1].wait();
|
||||
} catch (InterruptedException e) {
|
||||
//do nothing
|
||||
if (stop) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Arithmetic<BigInteger> arithmetic = new Fp(sdkg.getQ());
|
||||
// restore necessary information
|
||||
for (int i = 0; i < n ; i++) {
|
||||
if(parties[i].recoverSharesSet.isEmpty()){
|
||||
|
@ -152,10 +175,10 @@ public class User<T> extends meerkat.crypto.concrete.distributed_key_generation.
|
|||
}
|
||||
|
||||
/**
|
||||
* notifies mail handler that stage 4 was started
|
||||
* notifies mail handler and message handler that stage 4 was started
|
||||
*/
|
||||
protected void setStage4(){
|
||||
this.isStage4 = true;
|
||||
this.messageHandler.isStage4 = true;
|
||||
((MailHandler)this.mailHandler).setStage4(true);
|
||||
}
|
||||
|
||||
|
@ -163,11 +186,13 @@ public class User<T> extends meerkat.crypto.concrete.distributed_key_generation.
|
|||
protected void stage4() {
|
||||
setStage4();
|
||||
resolveQualifyingPublicKey();
|
||||
if (stop) return;
|
||||
super.stage4();
|
||||
}
|
||||
|
||||
private class MessageHandler extends meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.User.MessageHandler {
|
||||
private class MessageHandler extends meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol.User.MessageHandler {
|
||||
|
||||
boolean isStage4;
|
||||
/**
|
||||
* as in super, with extension to double secret message
|
||||
*/
|
||||
|
@ -184,7 +209,7 @@ public class User<T> extends meerkat.crypto.concrete.distributed_key_generation.
|
|||
* as in super, with extension to double secret message
|
||||
*/
|
||||
@Override
|
||||
public void handleSecretMessage(int sender, boolean isBroadcast, Message message) {
|
||||
public void handleShareMessage(int sender, boolean isBroadcast, Message message) {
|
||||
DKGMessages.DoubleShareMessage doubleSecretMessage = (DKGMessages.DoubleShareMessage)message;
|
||||
if (isValidSecretMessage(sender,isBroadcast,doubleSecretMessage)) {
|
||||
int i = doubleSecretMessage.getI();
|
||||
|
@ -234,10 +259,10 @@ public class User<T> extends meerkat.crypto.concrete.distributed_key_generation.
|
|||
synchronized (parties[i - 1]) {
|
||||
if (!isStage4) {
|
||||
if (sdkg.isValidShare(secret, secretT, parties[j - 1].verifiableValues, i)) {
|
||||
parties[i - 1].complaints[j - 1] = meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.Protocol.ComplaintState.NonDisqualified;
|
||||
parties[i - 1].complaints[j - 1] = meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol.Protocol.ComplaintState.NonDisqualified;
|
||||
|
||||
} else {
|
||||
parties[i - 1].complaints[j - 1] = meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.Protocol.ComplaintState.Disqualified;
|
||||
parties[i - 1].complaints[j - 1] = meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol.Protocol.ComplaintState.Disqualified;
|
||||
}
|
||||
if (j == id) {
|
||||
parties[i - 1].share = secret;
|
|
@ -1,15 +1,20 @@
|
|||
package meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol;
|
||||
package meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.google.protobuf.Message;
|
||||
import meerkat.crypto.concrete.distributed_key_generation.communication.MessageHandler;
|
||||
import meerkat.destributed_key_generation.concrete.distributed_key_generation.communication.MessageHandler;
|
||||
import meerkat.protobuf.DKGMessages;
|
||||
|
||||
/**
|
||||
* Created by Tzlil on 2/29/2016.
|
||||
* an extension of MailHandler matching joint feldman protocol
|
||||
*/
|
||||
public class MailHandler extends meerkat.crypto.concrete.distributed_key_generation.communication.MailHandler {
|
||||
public class MailHandler extends meerkat.destributed_key_generation.concrete.distributed_key_generation.communication.MailHandler {
|
||||
|
||||
/**
|
||||
* constructor
|
||||
* @param messageHandler
|
||||
*/
|
||||
public MailHandler(MessageHandler messageHandler) {
|
||||
super(messageHandler);
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol;
|
||||
package meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol;
|
||||
|
||||
import meerkat.crypto.concrete.secret_shring.shamir.Polynomial;
|
||||
import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -19,6 +19,12 @@ public class Party<T> {
|
|||
public Protocol.ComplaintState[] complaints;
|
||||
public boolean aborted;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param id party identifier - 1 <= id <= n
|
||||
* @param n number of parties in current run protocol
|
||||
* @param t protocol's threshold
|
||||
*/
|
||||
public Party(int id, int n, int t) {
|
||||
this.id = id;
|
||||
this.share = null;
|
|
@ -1,8 +1,8 @@
|
|||
package meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol;
|
||||
package meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol;
|
||||
|
||||
import meerkat.crypto.utilitis.Channel;
|
||||
import meerkat.crypto.concrete.secret_shring.feldman_verifiable.VerifiableSecretSharing;
|
||||
import meerkat.crypto.concrete.secret_shring.shamir.Polynomial;
|
||||
import meerkat.destributed_key_generation.utilitis.Channel;
|
||||
import meerkat.destributed_key_generation.concrete.secret_shring.feldman_verifiable.VerifiableSecretSharing;
|
||||
import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial;
|
||||
import com.google.protobuf.ByteString;
|
||||
import meerkat.protobuf.DKGMessages;
|
||||
import org.factcenter.qilin.primitives.Group;
|
||||
|
@ -57,7 +57,6 @@ public class Protocol<T> extends VerifiableSecretSharing<T> {
|
|||
*/
|
||||
protected Channel channel;
|
||||
|
||||
|
||||
/**
|
||||
* Encode/Decode group elements
|
||||
*/
|
||||
|
@ -76,9 +75,10 @@ public class Protocol<T> extends VerifiableSecretSharing<T> {
|
|||
* @param g a generator of cyclic group of order q.
|
||||
* the generated group is a subgroup of the given group.
|
||||
* it must be chosen such that computing discrete logarithms is hard in this group.
|
||||
* @param encoder Encode/Decode group elements (of type T) to/from byte array
|
||||
*/
|
||||
public Protocol(int t, int n, BigInteger zi, Random random, BigInteger q, T g
|
||||
, Group<T> group, int id, ByteEncoder<T> byteEncoder) {
|
||||
, Group<T> group, int id, ByteEncoder<T> encoder) {
|
||||
super(t, n, zi, random, q, g,group);
|
||||
this.id = id;
|
||||
this.parties = new Party[n];
|
||||
|
@ -86,7 +86,7 @@ public class Protocol<T> extends VerifiableSecretSharing<T> {
|
|||
this.parties[i - 1] = new Party(i,n,t);
|
||||
}
|
||||
this.parties[id - 1].share = getShare(id);
|
||||
this.encoder = byteEncoder;
|
||||
this.encoder = encoder;
|
||||
}
|
||||
|
||||
/**
|
|
@ -1,7 +1,7 @@
|
|||
package meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol;
|
||||
package meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol;
|
||||
|
||||
import meerkat.crypto.utilitis.Channel;
|
||||
import meerkat.crypto.concrete.secret_shring.shamir.Polynomial;
|
||||
import meerkat.destributed_key_generation.utilitis.Channel;
|
||||
import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial;
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.Message;
|
||||
import meerkat.protobuf.DKGMessages;
|
||||
|
@ -13,27 +13,91 @@ import java.util.Set;
|
|||
|
||||
/**
|
||||
* Created by Tzlil on 3/14/2016.
|
||||
* TODO: Comments
|
||||
* TODO: Replace polling with monitors/wait/notify (remember synchronization)
|
||||
*
|
||||
* implementation of joint feldman protocol user.
|
||||
*
|
||||
* according to the protocol, each user run feldman verifiable secret sharing
|
||||
* as a dealer.
|
||||
*
|
||||
* by the end of run(), each party in QUAL has his own share of the generated random key.
|
||||
* this key can be recover by any subset of QUAL of size at least t + 1.
|
||||
*/
|
||||
public class User<T> implements Runnable{
|
||||
|
||||
/**
|
||||
* joint feldman protocol object
|
||||
*/
|
||||
protected final Protocol<T> dkg;
|
||||
|
||||
/**
|
||||
* a generator of cyclic group of order q.
|
||||
* the generated group is a subgroup of the given group.
|
||||
* it must be chosen such that computing discrete logarithms is hard in this group.
|
||||
*/
|
||||
protected final T g;
|
||||
|
||||
/**
|
||||
* cyclic group contains g.
|
||||
*/
|
||||
protected final Group<T> group;
|
||||
protected final int n;
|
||||
protected final int t;
|
||||
|
||||
/**
|
||||
* user id
|
||||
*/
|
||||
protected final int id;
|
||||
protected meerkat.crypto.concrete.distributed_key_generation.communication.MailHandler mailHandler;
|
||||
|
||||
protected final Channel channel;
|
||||
/**
|
||||
* threshold
|
||||
*/
|
||||
protected final int t;
|
||||
|
||||
/**
|
||||
* number of shares
|
||||
*/
|
||||
protected final int n;
|
||||
|
||||
/**
|
||||
* mail handler registered to channel as ReceiverCallback
|
||||
*/
|
||||
protected meerkat.destributed_key_generation.concrete.distributed_key_generation.communication.MailHandler mailHandler;
|
||||
|
||||
/**
|
||||
* channel object
|
||||
*/
|
||||
protected final Channel channel; //
|
||||
|
||||
/**
|
||||
* All parties participating in key generation.
|
||||
* parties[id-1] has my info.
|
||||
*/
|
||||
protected final Party[] parties;
|
||||
protected Set<Integer> QUAL; // set of all non-disqualified parties
|
||||
protected Polynomial.Point share; // final share of the secrete
|
||||
protected ArrayList<T> commitments; // public verification values
|
||||
protected T y; // final public value
|
||||
|
||||
/**
|
||||
* set of all non-disqualified parties
|
||||
*/
|
||||
protected Set<Integer> QUAL;
|
||||
|
||||
/**
|
||||
* my own share of the generated random key.
|
||||
*/
|
||||
protected Polynomial.Point share;
|
||||
|
||||
/**
|
||||
* public verification values
|
||||
*/
|
||||
protected ArrayList<T> commitments;
|
||||
|
||||
/**
|
||||
* public value,
|
||||
* y = g ^ key
|
||||
*/
|
||||
protected T y;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
* @param dkg joint feldman protocol object
|
||||
* @param channel channel object
|
||||
*/
|
||||
public User(Protocol<T> dkg, Channel channel) {
|
||||
this.dkg = dkg;
|
||||
|
||||
|
@ -74,20 +138,23 @@ public class User<T> implements Runnable{
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* wait for all shares and commitments will arrive from other parties
|
||||
*/
|
||||
protected void waitUntilStageOneCompleted(){
|
||||
// all parties send their share or aborted
|
||||
// wait for parties' share
|
||||
for (int i = 0 ; i < n ; i++){
|
||||
synchronized (parties[i]) {
|
||||
while (parties[i].share == null && !parties[i].aborted) {
|
||||
try {
|
||||
parties[i].wait();
|
||||
} catch (InterruptedException e) {
|
||||
//do nothing
|
||||
if (stop) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// all parties broadcast their commitments or aborted
|
||||
// wait for parties' commitments
|
||||
for (int i = 0 ; i < n ; i++){
|
||||
for (int k = 0 ; k <= t ; k++) {
|
||||
synchronized (parties[i]) {
|
||||
|
@ -95,7 +162,7 @@ public class User<T> implements Runnable{
|
|||
try {
|
||||
parties[i].wait();
|
||||
} catch (InterruptedException e) {
|
||||
//do nothing
|
||||
if (stop) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -117,15 +184,17 @@ public class User<T> implements Runnable{
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* wait until all other parties done complaining by receiving done message
|
||||
*/
|
||||
protected void waitUntilStageTwoCompleted(){
|
||||
// all parties done or aborted
|
||||
for (int i = 0 ; i < n ; i++){
|
||||
synchronized (parties[i]) {
|
||||
while (!parties[i].doneFlag && !parties[i].aborted) {
|
||||
try {
|
||||
parties[i].wait();
|
||||
} catch (InterruptedException e) {
|
||||
//do nothing
|
||||
if (stop) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -150,7 +219,7 @@ public class User<T> implements Runnable{
|
|||
try {
|
||||
parties[i].wait();
|
||||
} catch (InterruptedException e) {
|
||||
//do nothing
|
||||
if (stop) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -173,18 +242,38 @@ public class User<T> implements Runnable{
|
|||
|
||||
@Override
|
||||
public void run() {
|
||||
this.runThread = Thread.currentThread();
|
||||
stage1();
|
||||
waitUntilStageOneCompleted();
|
||||
if (stop) return;
|
||||
stage2();
|
||||
waitUntilStageTwoCompleted();
|
||||
if (stop) return;
|
||||
stage3();
|
||||
if (stop) return;
|
||||
stage4();
|
||||
}
|
||||
|
||||
/**
|
||||
* current thread in the main loop
|
||||
*/
|
||||
protected Thread runThread;
|
||||
|
||||
/**
|
||||
* flag indicates if there was request to stop the current run of the protocol
|
||||
*/
|
||||
protected boolean stop = false;
|
||||
|
||||
/**
|
||||
* Request the current run loop to exit gracefully
|
||||
*/
|
||||
public void stop() {
|
||||
try {
|
||||
stop = true;
|
||||
runThread.interrupt();
|
||||
}catch (Exception e){
|
||||
//do nothing
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -260,12 +349,19 @@ public class User<T> implements Runnable{
|
|||
return QUAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* getter
|
||||
* @return channel
|
||||
*/
|
||||
public Channel getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
public class MessageHandler implements meerkat.crypto.concrete.distributed_key_generation.communication.MessageHandler{
|
||||
/**
|
||||
* an implementation of MessageHandler
|
||||
*/
|
||||
public class MessageHandler implements meerkat.destributed_key_generation.concrete.distributed_key_generation.communication.MessageHandler{
|
||||
|
||||
public MessageHandler(){
|
||||
|
||||
}
|
||||
/**
|
||||
* commitment message is valid if:
|
||||
* 1. it was received in broadcast chanel
|
||||
|
@ -314,7 +410,7 @@ public class User<T> implements Runnable{
|
|||
* saves the secret
|
||||
*/
|
||||
@Override
|
||||
public void handleSecretMessage(int sender, boolean isBroadcast, Message message) {
|
||||
public void handleShareMessage(int sender, boolean isBroadcast, Message message) {
|
||||
DKGMessages.ShareMessage secretMessage = (DKGMessages.ShareMessage) message;
|
||||
if(isValidSecretMessage(sender,isBroadcast,secretMessage)) {
|
||||
int i = secretMessage.getI();
|
|
@ -1,7 +1,7 @@
|
|||
package meerkat.crypto.concrete.secret_shring.feldman_verifiable;
|
||||
package meerkat.destributed_key_generation.concrete.secret_shring.feldman_verifiable;
|
||||
|
||||
import meerkat.crypto.concrete.secret_shring.shamir.Polynomial;
|
||||
import meerkat.crypto.concrete.secret_shring.shamir.SecretSharing;
|
||||
import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial;
|
||||
import meerkat.destributed_key_generation.concrete.secret_shring.shamir.SecretSharing;
|
||||
import org.factcenter.qilin.primitives.Group;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -17,12 +17,22 @@ import java.util.Random;
|
|||
*
|
||||
*/
|
||||
public class VerifiableSecretSharing<T> extends SecretSharing {
|
||||
/**
|
||||
* cyclic group contains g.
|
||||
*/
|
||||
protected final Group<T> group;
|
||||
protected final T g; // public generator of group
|
||||
/**
|
||||
* a generator of cyclic group of order q.
|
||||
* the generated group is a subgroup of the given group.
|
||||
* it must be chosen such that computing discrete logarithms is hard in this group.
|
||||
*/
|
||||
protected final T g;
|
||||
/**
|
||||
* commitments to polynomial coefficients.
|
||||
* commitments[k] = g ^ coefficients[k] (group operation)
|
||||
*/
|
||||
protected final ArrayList<T> commitmentsArrayList;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* constructor
|
||||
* @param q a large prime.
|
|
@ -1,6 +1,6 @@
|
|||
package meerkat.crypto.concrete.secret_shring.shamir;
|
||||
package meerkat.destributed_key_generation.concrete.secret_shring.shamir;
|
||||
|
||||
import meerkat.crypto.utilitis.Arithmetic;
|
||||
import meerkat.destributed_key_generation.utilitis.Arithmetic;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package meerkat.crypto.concrete.secret_shring.shamir;
|
||||
package meerkat.destributed_key_generation.concrete.secret_shring.shamir;
|
||||
|
||||
import meerkat.crypto.utilitis.Arithmetic;
|
||||
import meerkat.destributed_key_generation.utilitis.Arithmetic;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Arrays;
|
||||
|
@ -100,7 +100,7 @@ public class Polynomial implements Comparable<Polynomial> {
|
|||
|
||||
/**
|
||||
* @param other
|
||||
* @return new meerkat.crypto.concrete.secret_shring.shamir.Polynomial of degree max(this degree,other degree) s.t for all x
|
||||
* @return new meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial of degree max(this degree,other degree) s.t for all x
|
||||
* new.evaluate(x) = this.evaluate(x) + other.evaluate(x)
|
||||
*/
|
||||
public Polynomial add(Polynomial other){
|
|
@ -1,7 +1,7 @@
|
|||
package meerkat.crypto.concrete.secret_shring.shamir;
|
||||
package meerkat.destributed_key_generation.concrete.secret_shring.shamir;
|
||||
|
||||
import meerkat.crypto.utilitis.Arithmetic;
|
||||
import meerkat.crypto.utilitis.concrete.Fp;
|
||||
import meerkat.destributed_key_generation.utilitis.Arithmetic;
|
||||
import meerkat.destributed_key_generation.utilitis.concrete.Fp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Random;
|
||||
|
@ -11,9 +11,21 @@ import java.util.Random;
|
|||
* an implementation of Shamire's secret sharing scheme
|
||||
*/
|
||||
public class SecretSharing{
|
||||
/**
|
||||
* threshold
|
||||
*/
|
||||
protected final int t;
|
||||
/**
|
||||
* number of shares
|
||||
*/
|
||||
protected final int n;
|
||||
/**
|
||||
* a large prime
|
||||
*/
|
||||
protected final BigInteger q;
|
||||
/**
|
||||
* random polynomial of degree s.t polynomial.evaluate(0) = secret
|
||||
*/
|
||||
protected final Polynomial polynomial;
|
||||
|
||||
/**
|
|
@ -0,0 +1,38 @@
|
|||
package meerkat.destributed_key_generation.utilitis;
|
||||
|
||||
/**
|
||||
* Created by Tzlil on 3/17/2016.
|
||||
* defines the properties of the traditional operations : add,sub,mul,div
|
||||
* between two objects of type T
|
||||
*/
|
||||
public interface Arithmetic<T> {
|
||||
/**
|
||||
* addition
|
||||
* @param a
|
||||
* @param b
|
||||
* @return a + b
|
||||
*/
|
||||
T add(T a, T b);
|
||||
/**
|
||||
* subtraction
|
||||
* @param a
|
||||
* @param b
|
||||
* @return a - b
|
||||
*/
|
||||
T sub(T a, T b);
|
||||
/**
|
||||
* multiplication
|
||||
* @param a
|
||||
* @param b
|
||||
* @return a * b
|
||||
*/
|
||||
T mul(T a, T b);
|
||||
/**
|
||||
* division
|
||||
* @param a
|
||||
* @param b
|
||||
* @return a / b
|
||||
*/
|
||||
T div(T a, T b);
|
||||
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
package meerkat.crypto.utilitis;
|
||||
package meerkat.destributed_key_generation.utilitis;
|
||||
|
||||
import com.google.protobuf.Message;
|
||||
import meerkat.protobuf.DKGMessages;
|
||||
|
||||
/**
|
||||
* A generic commmunication channel that supports point-to-point and broadcast operation
|
||||
* A generic communication channel that supports point-to-point and broadcast operation
|
||||
*/
|
||||
|
||||
public interface Channel {
|
||||
|
@ -12,8 +12,20 @@ public interface Channel {
|
|||
public void receiveMail(DKGMessages.Mail mail);
|
||||
}
|
||||
|
||||
/**
|
||||
* sends a private message
|
||||
* @param destUser destination user's identifier
|
||||
* @param type message type
|
||||
* @param msg message
|
||||
*/
|
||||
public void sendMessage(int destUser, DKGMessages.Mail.Type type, Message msg);
|
||||
|
||||
|
||||
/**
|
||||
* broadcasts a message to all parties (including the sender)
|
||||
* @param type message type
|
||||
* @param msg message
|
||||
*/
|
||||
public void broadcastMessage(DKGMessages.Mail.Type type, Message msg);
|
||||
|
||||
/**
|
|
@ -1,17 +1,22 @@
|
|||
package meerkat.crypto.utilitis.concrete;
|
||||
package meerkat.destributed_key_generation.utilitis.concrete;
|
||||
|
||||
import meerkat.crypto.utilitis.Arithmetic;
|
||||
import meerkat.destributed_key_generation.utilitis.Arithmetic;
|
||||
import org.factcenter.qilin.primitives.concrete.Zpstar;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* Created by Tzlil on 3/17/2016.
|
||||
* an implementation of Arithmetic<BigInteger> over prime fields: integers modulo p
|
||||
*/
|
||||
public class Fp implements Arithmetic<BigInteger> {
|
||||
public final BigInteger p;
|
||||
private final Zpstar zp;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
* @param p prime
|
||||
*/
|
||||
public Fp(BigInteger p) {
|
||||
this.p = p;
|
||||
this.zp = new Zpstar(p);
|
|
@ -1,7 +1,6 @@
|
|||
package meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol;
|
||||
package meerkat.destributed_key_generation.concrete.distributed_key_generation.gjkr_secure_protocol;
|
||||
|
||||
import meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol.*;
|
||||
import meerkat.crypto.utilitis.Channel;
|
||||
import meerkat.destributed_key_generation.utilitis.Channel;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Random;
|
|
@ -1,15 +1,15 @@
|
|||
package meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol;
|
||||
package meerkat.destributed_key_generation.concrete.distributed_key_generation.gjkr_secure_protocol;
|
||||
|
||||
import Utils.ChannelImpl;
|
||||
import meerkat.crypto.utilitis.Arithmetic;
|
||||
import meerkat.crypto.utilitis.concrete.Fp;
|
||||
import meerkat.crypto.utilitis.Channel;
|
||||
import meerkat.crypto.concrete.secret_shring.feldman_verifiable.VerifiableSecretSharing;
|
||||
import meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.DKGMaliciousUser;
|
||||
import meerkat.crypto.concrete.secret_shring.shamir.Polynomial;
|
||||
import meerkat.crypto.concrete.secret_shring.shamir.SecretSharing;
|
||||
import Utils.BigIntegerByteEncoder;
|
||||
import Utils.GenerateRandomPrime;
|
||||
import meerkat.destributed_key_generation.utilitis.ChannelImpl;
|
||||
import meerkat.destributed_key_generation.utilitis.Arithmetic;
|
||||
import meerkat.destributed_key_generation.utilitis.concrete.Fp;
|
||||
import meerkat.destributed_key_generation.utilitis.Channel;
|
||||
import meerkat.destributed_key_generation.concrete.secret_shring.feldman_verifiable.VerifiableSecretSharing;
|
||||
import meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol.DKGMaliciousUser;
|
||||
import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial;
|
||||
import meerkat.destributed_key_generation.concrete.secret_shring.shamir.SecretSharing;
|
||||
import meerkat.destributed_key_generation.utilitis.BigIntegerByteEncoder;
|
||||
import meerkat.destributed_key_generation.utilitis.GenerateRandomPrime;
|
||||
import org.factcenter.qilin.primitives.Group;
|
||||
import org.factcenter.qilin.primitives.concrete.Zpstar;
|
||||
import org.factcenter.qilin.util.ByteEncoder;
|
||||
|
@ -27,25 +27,16 @@ import java.util.Set;
|
|||
*/
|
||||
public class SDKGTest {
|
||||
|
||||
int tests = 1;
|
||||
int tests = 10;
|
||||
BigInteger p = GenerateRandomPrime.SafePrime100Bits;
|
||||
BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2));
|
||||
Group<BigInteger> group = new Zpstar(p);
|
||||
Arithmetic<BigInteger> arithmetic = new Fp(q);
|
||||
int t = 9;
|
||||
int n = 20;
|
||||
Testable[] testables;
|
||||
|
||||
@Before
|
||||
public void settings(){
|
||||
testables = new Testable[tests];
|
||||
for (int i = 0; i < tests; i++){
|
||||
testables[i] = new Testable(new Random());
|
||||
}
|
||||
}
|
||||
|
||||
public void oneTest(int test) throws Exception {
|
||||
Testable testable = testables[test];
|
||||
public void oneTest(Testable testable) throws Exception {
|
||||
for (int i = 0; i < testable.threads.length ; i++){
|
||||
testable.threads[i].start();
|
||||
}
|
||||
|
@ -83,13 +74,23 @@ public class SDKGTest {
|
|||
assert (calculatedSecret.equals(testable.secret));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
for (int i = 0; i < tests; i++){
|
||||
oneTest(i);
|
||||
public void stopReceivers(Testable testable){
|
||||
ChannelImpl channel;
|
||||
for (int i = 0 ; i < testable.sdkgs.length ; i++){
|
||||
channel = (ChannelImpl)testable.sdkgs[i].getChannel();
|
||||
channel.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
Testable testable;
|
||||
for (int i = 0; i < tests; i++) {
|
||||
testable = new Testable(new Random());
|
||||
oneTest(testable);
|
||||
stopReceivers(testable);
|
||||
}
|
||||
}
|
||||
class Testable{
|
||||
Set<Integer> valids;
|
||||
Set<Integer> QUAL;
|
|
@ -1,6 +1,6 @@
|
|||
package meerkat.crypto.concrete.distributed_key_generation.gjkr_secure_protocol;
|
||||
package meerkat.destributed_key_generation.concrete.distributed_key_generation.gjkr_secure_protocol;
|
||||
|
||||
import meerkat.crypto.utilitis.Channel;
|
||||
import meerkat.destributed_key_generation.utilitis.Channel;
|
||||
import meerkat.protobuf.DKGMessages;
|
||||
|
||||
/**
|
|
@ -1,6 +1,6 @@
|
|||
package meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol;
|
||||
package meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol;
|
||||
|
||||
import meerkat.crypto.utilitis.Channel;
|
||||
import meerkat.destributed_key_generation.utilitis.Channel;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.*;
|
|
@ -1,15 +1,14 @@
|
|||
package meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol;
|
||||
package meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol;
|
||||
|
||||
import Utils.ChannelImpl;
|
||||
import meerkat.crypto.utilitis.Arithmetic;
|
||||
import meerkat.crypto.utilitis.concrete.Fp;
|
||||
import meerkat.crypto.utilitis.Channel;
|
||||
import meerkat.crypto.concrete.secret_shring.feldman_verifiable.VerifiableSecretSharing;
|
||||
import meerkat.crypto.concrete.secret_shring.shamir.Polynomial;
|
||||
import meerkat.crypto.concrete.secret_shring.shamir.SecretSharing;
|
||||
import Utils.BigIntegerByteEncoder;
|
||||
import Utils.GenerateRandomPrime;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.destributed_key_generation.utilitis.ChannelImpl;
|
||||
import meerkat.destributed_key_generation.utilitis.Arithmetic;
|
||||
import meerkat.destributed_key_generation.utilitis.concrete.Fp;
|
||||
import meerkat.destributed_key_generation.utilitis.Channel;
|
||||
import meerkat.destributed_key_generation.concrete.secret_shring.feldman_verifiable.VerifiableSecretSharing;
|
||||
import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial;
|
||||
import meerkat.destributed_key_generation.concrete.secret_shring.shamir.SecretSharing;
|
||||
import meerkat.destributed_key_generation.utilitis.BigIntegerByteEncoder;
|
||||
import meerkat.destributed_key_generation.utilitis.GenerateRandomPrime;
|
||||
import org.factcenter.qilin.primitives.Group;
|
||||
import org.factcenter.qilin.primitives.concrete.Zpstar;
|
||||
import org.factcenter.qilin.util.ByteEncoder;
|
||||
|
@ -27,7 +26,7 @@ import java.util.Set;
|
|||
*/
|
||||
public class DKGTest {
|
||||
|
||||
int tests = 1;
|
||||
int tests = 10;
|
||||
BigInteger p = GenerateRandomPrime.SafePrime100Bits;
|
||||
BigInteger q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2));
|
||||
Group<BigInteger> group = new Zpstar(p);
|
||||
|
@ -35,18 +34,7 @@ public class DKGTest {
|
|||
int t = 9;
|
||||
int n = 20;
|
||||
|
||||
Testable[] testables;
|
||||
|
||||
@Before
|
||||
public void settings(){
|
||||
testables = new Testable[tests];
|
||||
for (int i = 0; i < tests; i++){
|
||||
testables[i] = new Testable(new Random());
|
||||
}
|
||||
}
|
||||
|
||||
public void oneTest(int test) throws Exception {
|
||||
Testable testable = testables[test];
|
||||
public void oneTest(Testable testable) throws Exception {
|
||||
for (int i = 0; i < testable.threads.length ; i++){
|
||||
testable.threads[i].start();
|
||||
}
|
||||
|
@ -84,10 +72,21 @@ public class DKGTest {
|
|||
assert (calculatedSecret.equals(testable.secret));
|
||||
}
|
||||
|
||||
public void stopReceivers(Testable testable){
|
||||
ChannelImpl channel;
|
||||
for (int i = 0 ; i < testable.dkgs.length ; i++){
|
||||
channel = (ChannelImpl)testable.dkgs[i].getChannel();
|
||||
channel.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
Testable testable;
|
||||
for (int i = 0; i < tests; i++){
|
||||
oneTest(i);
|
||||
testable = new Testable(new Random());
|
||||
oneTest(testable);
|
||||
stopReceivers(testable);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,13 +116,13 @@ public class DKGTest {
|
|||
BigInteger s;
|
||||
Protocol<BigInteger> dkg;
|
||||
this.secret = BigInteger.ZERO;
|
||||
Channel channel;
|
||||
ChannelImpl channel;
|
||||
ByteEncoder<BigInteger> byteEncoder = new BigIntegerByteEncoder();
|
||||
while (!ids.isEmpty()) {
|
||||
id = ids.remove(random.nextInt(ids.size()));
|
||||
channel = new ChannelImpl(id,n);
|
||||
s = randomIntModQ(random);
|
||||
dkg = new meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol.Protocol<BigInteger>(t, n, s, random, q, g, group, id,byteEncoder);
|
||||
dkg = new meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol.Protocol<BigInteger>(t, n, s, random, q, g, group, id,byteEncoder);
|
||||
dkgs[id - 1] = randomDKGUser(id,channel,dkg,random);
|
||||
threads[id - 1] = new Thread(dkgs[id - 1]);
|
||||
if(QUAL.contains(id)){
|
|
@ -1,6 +1,6 @@
|
|||
package meerkat.crypto.concrete.distributed_key_generation.joint_feldman_protocol;
|
||||
package meerkat.destributed_key_generation.concrete.distributed_key_generation.joint_feldman_protocol;
|
||||
|
||||
import meerkat.crypto.utilitis.Channel;
|
||||
import meerkat.destributed_key_generation.utilitis.Channel;
|
||||
import meerkat.protobuf.DKGMessages;
|
||||
|
||||
/**
|
|
@ -1,6 +1,6 @@
|
|||
package meerkat.crypto.concrete.secret_shring.feldman_verifiable;
|
||||
package meerkat.destributed_key_generation.concrete.secret_shring.feldman_verifiable;
|
||||
|
||||
import meerkat.crypto.concrete.secret_shring.shamir.Polynomial;
|
||||
import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial;
|
||||
import org.factcenter.qilin.primitives.Group;
|
||||
import org.factcenter.qilin.primitives.concrete.Zpstar;
|
||||
import org.junit.Before;
|
|
@ -1,7 +1,7 @@
|
|||
package meerkat.crypto.concrete.secret_shring.shamir.PolynomialTests;
|
||||
import Utils.GenerateRandomPolynomial;
|
||||
import Utils.Z;
|
||||
import meerkat.crypto.concrete.secret_shring.shamir.Polynomial;
|
||||
package meerkat.destributed_key_generation.concrete.secret_shring.shamir.PolynomialTests;
|
||||
import meerkat.destributed_key_generation.utilitis.GenerateRandomPolynomial;
|
||||
import meerkat.destributed_key_generation.utilitis.Z;
|
||||
import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
package meerkat.crypto.concrete.secret_shring.shamir.PolynomialTests;
|
||||
package meerkat.destributed_key_generation.concrete.secret_shring.shamir.PolynomialTests;
|
||||
|
||||
import meerkat.crypto.utilitis.Arithmetic;
|
||||
import meerkat.crypto.utilitis.concrete.Fp;
|
||||
import Utils.GenerateRandomPolynomial;
|
||||
import meerkat.crypto.concrete.secret_shring.shamir.Polynomial;
|
||||
import Utils.GenerateRandomPrime;
|
||||
import meerkat.destributed_key_generation.utilitis.Arithmetic;
|
||||
import meerkat.destributed_key_generation.utilitis.concrete.Fp;
|
||||
import meerkat.destributed_key_generation.utilitis.GenerateRandomPolynomial;
|
||||
import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial;
|
||||
import meerkat.destributed_key_generation.utilitis.GenerateRandomPrime;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
package meerkat.crypto.concrete.secret_shring.shamir.PolynomialTests;
|
||||
package meerkat.destributed_key_generation.concrete.secret_shring.shamir.PolynomialTests;
|
||||
|
||||
import Utils.GenerateRandomPolynomial;
|
||||
import Utils.Z;
|
||||
import meerkat.crypto.concrete.secret_shring.shamir.Polynomial;
|
||||
import meerkat.destributed_key_generation.utilitis.GenerateRandomPolynomial;
|
||||
import meerkat.destributed_key_generation.utilitis.Z;
|
||||
import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
package meerkat.crypto.concrete.secret_shring.shamir.PolynomialTests;
|
||||
package meerkat.destributed_key_generation.concrete.secret_shring.shamir.PolynomialTests;
|
||||
|
||||
import Utils.GenerateRandomPolynomial;
|
||||
import Utils.Z;
|
||||
import meerkat.crypto.concrete.secret_shring.shamir.Polynomial;
|
||||
import meerkat.destributed_key_generation.utilitis.GenerateRandomPolynomial;
|
||||
import meerkat.destributed_key_generation.utilitis.Z;
|
||||
import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package meerkat.crypto.concrete.secret_shring.shamir;
|
||||
package meerkat.destributed_key_generation.concrete.secret_shring.shamir;
|
||||
|
||||
import meerkat.crypto.utilitis.concrete.Fp;
|
||||
import Utils.GenerateRandomPrime;
|
||||
import meerkat.destributed_key_generation.utilitis.concrete.Fp;
|
||||
import meerkat.destributed_key_generation.utilitis.GenerateRandomPrime;
|
||||
import org.factcenter.qilin.primitives.CyclicGroup;
|
||||
import org.factcenter.qilin.primitives.concrete.Zn;
|
||||
import org.junit.Before;
|
|
@ -1,4 +1,4 @@
|
|||
package Utils;
|
||||
package meerkat.destributed_key_generation.utilitis;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package Utils;
|
||||
package meerkat.destributed_key_generation.utilitis;
|
||||
|
||||
import com.google.protobuf.Message;
|
||||
import meerkat.crypto.utilitis.Channel;
|
||||
import meerkat.protobuf.DKGMessages;
|
||||
|
||||
import java.util.Queue;
|
||||
|
@ -76,13 +75,17 @@ public class ChannelImpl implements Channel {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerReceiverCallback(final ReceiverCallback callback) {
|
||||
public void stop(){
|
||||
try{
|
||||
receiverThread.interrupt();
|
||||
}catch (Exception e){
|
||||
//do nothing
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerReceiverCallback(final ReceiverCallback callback) {
|
||||
stop();
|
||||
receiverThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
|
@ -1,31 +1,30 @@
|
|||
package Utils;
|
||||
|
||||
import meerkat.crypto.concrete.secret_shring.shamir.Polynomial;
|
||||
import meerkat.crypto.utilitis.Arithmetic;
|
||||
import meerkat.crypto.utilitis.concrete.Fp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Created by Tzlil on 1/27/2016.
|
||||
*/
|
||||
public class GenerateRandomPolynomial {
|
||||
|
||||
public static Polynomial generateRandomPolynomial(int degree, int bits, Random random, Arithmetic<BigInteger> arithmetic) {
|
||||
BigInteger[] coefficients = new BigInteger[degree + 1];
|
||||
|
||||
for (int i = 0 ; i <= degree; i++ ){
|
||||
coefficients[i] = new BigInteger(bits,random); // sample from Zp [0,... q-1]
|
||||
}
|
||||
return new Polynomial(coefficients,arithmetic);
|
||||
}
|
||||
|
||||
public static Polynomial generateRandomPolynomial(int degree,int bits,Random random,BigInteger p) {
|
||||
BigInteger[] coefficients = generateRandomPolynomial(degree,bits,random,new Fp(p)).getCoefficients();
|
||||
for (int i = 0; i<coefficients.length;i++){
|
||||
coefficients[i] = coefficients[i].mod(p);
|
||||
}
|
||||
return new Polynomial(coefficients,new Fp(p));
|
||||
}
|
||||
}
|
||||
package meerkat.destributed_key_generation.utilitis;
|
||||
|
||||
import meerkat.destributed_key_generation.concrete.secret_shring.shamir.Polynomial;
|
||||
import meerkat.destributed_key_generation.utilitis.concrete.Fp;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Created by Tzlil on 1/27/2016.
|
||||
*/
|
||||
public class GenerateRandomPolynomial {
|
||||
|
||||
public static Polynomial generateRandomPolynomial(int degree, int bits, Random random, Arithmetic<BigInteger> arithmetic) {
|
||||
BigInteger[] coefficients = new BigInteger[degree + 1];
|
||||
|
||||
for (int i = 0 ; i <= degree; i++ ){
|
||||
coefficients[i] = new BigInteger(bits,random); // sample from Zp [0,... q-1]
|
||||
}
|
||||
return new Polynomial(coefficients,arithmetic);
|
||||
}
|
||||
|
||||
public static Polynomial generateRandomPolynomial(int degree,int bits,Random random,BigInteger p) {
|
||||
BigInteger[] coefficients = generateRandomPolynomial(degree,bits,random,new Fp(p)).getCoefficients();
|
||||
for (int i = 0; i<coefficients.length;i++){
|
||||
coefficients[i] = coefficients[i].mod(p);
|
||||
}
|
||||
return new Polynomial(coefficients,new Fp(p));
|
||||
}
|
||||
}
|
|
@ -1,32 +1,30 @@
|
|||
package Utils;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Created by Tzlil on 3/28/2016.
|
||||
*/
|
||||
public class GenerateRandomPrime {
|
||||
private final static int Certainty = 10000;
|
||||
public final static BigInteger SafePrime100Bits = new BigInteger("146407324427772525685319783363");
|
||||
|
||||
public static BigInteger generateRandomPrime(int bits, Random random) {
|
||||
BigInteger p;
|
||||
do {
|
||||
p = new BigInteger(bits, random);
|
||||
} while (!p.isProbablePrime(Certainty));
|
||||
return p;
|
||||
}
|
||||
|
||||
public static BigInteger generateRandomSafePrime(int bits, Random random) {
|
||||
BigInteger p;
|
||||
BigInteger q;
|
||||
do {
|
||||
p = generateRandomPrime(bits, random);
|
||||
q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2));
|
||||
} while (!q.isProbablePrime(Certainty));
|
||||
return q;
|
||||
}
|
||||
}
|
||||
package meerkat.destributed_key_generation.utilitis;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Created by Tzlil on 3/28/2016.
|
||||
*/
|
||||
public class GenerateRandomPrime {
|
||||
private final static int Certainty = 10000;
|
||||
public final static BigInteger SafePrime100Bits = new BigInteger("146407324427772525685319783363");
|
||||
|
||||
public static BigInteger generateRandomPrime(int bits, Random random) {
|
||||
BigInteger p;
|
||||
do {
|
||||
p = new BigInteger(bits, random);
|
||||
} while (!p.isProbablePrime(Certainty));
|
||||
return p;
|
||||
}
|
||||
|
||||
public static BigInteger generateRandomSafePrime(int bits, Random random) {
|
||||
BigInteger p;
|
||||
BigInteger q;
|
||||
do {
|
||||
p = generateRandomPrime(bits, random);
|
||||
q = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2));
|
||||
} while (!q.isProbablePrime(Certainty));
|
||||
return q;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,4 @@
|
|||
package Utils;
|
||||
|
||||
import meerkat.crypto.utilitis.Arithmetic;
|
||||
package meerkat.destributed_key_generation.utilitis;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
|
@ -1,38 +1,38 @@
|
|||
package meerkat.crypto;
|
||||
|
||||
import com.google.protobuf.Message;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
|
||||
/**
|
||||
* Created by talm on 11/9/15.
|
||||
*/
|
||||
public interface Digest {
|
||||
/**
|
||||
* Completes the hash computation by performing final operations such as padding.
|
||||
* (copied from {@link MessageDigest#digest()})
|
||||
* @return
|
||||
*/
|
||||
byte[] digest();
|
||||
|
||||
/**
|
||||
* Updates the digest using the specified message (in serialized wire form)
|
||||
*
|
||||
* Each message is (automatically) prepended with its length as a 32-bit big-endian unsigned integer.
|
||||
* @param msg
|
||||
* @return
|
||||
*/
|
||||
void update(Message msg);
|
||||
|
||||
/**
|
||||
* Resets the digest for further use.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* Clone the current digest state
|
||||
* @return
|
||||
*/
|
||||
public Digest clone() throws CloneNotSupportedException;
|
||||
|
||||
}
|
||||
package meerkat.destributed_key_generation;
|
||||
|
||||
import com.google.protobuf.Message;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
|
||||
/**
|
||||
* Created by talm on 11/9/15.
|
||||
*/
|
||||
public interface Digest {
|
||||
/**
|
||||
* Completes the hash computation by performing final operations such as padding.
|
||||
* (copied from {@link MessageDigest#digest()})
|
||||
* @return
|
||||
*/
|
||||
byte[] digest();
|
||||
|
||||
/**
|
||||
* Updates the digest using the specified message (in serialized wire form)
|
||||
*
|
||||
* Each message is (automatically) prepended with its length as a 32-bit big-endian unsigned integer.
|
||||
* @param msg
|
||||
* @return
|
||||
*/
|
||||
void update(Message msg);
|
||||
|
||||
/**
|
||||
* Resets the digest for further use.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* Clone the current digest state
|
||||
* @return
|
||||
*/
|
||||
public Digest clone() throws CloneNotSupportedException;
|
||||
|
||||
}
|
|
@ -1,96 +1,96 @@
|
|||
package meerkat.crypto;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
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 static meerkat.protobuf.Crypto.*;
|
||||
|
||||
/**
|
||||
* Created by talm on 25/10/15.
|
||||
*
|
||||
* Sign and verify arrays of messages
|
||||
*/
|
||||
public interface DigitalSignature {
|
||||
final public static String CERTIFICATE_ENCODING_X509 = "X.509";
|
||||
|
||||
/**
|
||||
* Load a set of certificates from an input stream.
|
||||
* This will consume the entire stream.
|
||||
* Certificates can be either DER-encoded (binary) or PEM (base64) encoded.
|
||||
* This may be called multiple times to load several different certificates.
|
||||
* It must be called before calling {@link #verify()}.
|
||||
* @param certStream source from which certificates are loaded
|
||||
* @throws CertificateException on parsing errors
|
||||
*/
|
||||
public void loadVerificationCertificates(InputStream certStream)
|
||||
throws CertificateException;
|
||||
|
||||
/**
|
||||
* Clear the loaded verification certificates.
|
||||
*/
|
||||
public void clearVerificationCertificates();
|
||||
|
||||
|
||||
/**
|
||||
* Add msg to the content stream to be verified / signed. Each message is (automatically)
|
||||
* prepended with its length as a 32-bit big-endian unsigned integer.
|
||||
*
|
||||
* @param msg
|
||||
* @throws SignatureException
|
||||
*/
|
||||
public void updateContent(Message msg) throws SignatureException;
|
||||
|
||||
|
||||
/**
|
||||
* Sign the content that was added using {@link #updateContent(Message)}.
|
||||
* Reset the DigitalSignature and make it available to sign a new message using the same key.
|
||||
* @return
|
||||
* @throws SignatureException
|
||||
*/
|
||||
Signature sign() throws SignatureException;
|
||||
|
||||
/**
|
||||
* Initialize the verifier with the certificate whose Id is in sig.
|
||||
* @param sig
|
||||
* @throws CertificateException
|
||||
* @throws InvalidKeyException
|
||||
*/
|
||||
void initVerify(Signature sig)
|
||||
throws CertificateException, InvalidKeyException;
|
||||
|
||||
/**
|
||||
* Verify the updated content using the initialized signature.
|
||||
* @return
|
||||
*/
|
||||
public boolean verify();
|
||||
|
||||
/**
|
||||
* Loads a private signing key. The keystore must include both the public and private
|
||||
* key parts.
|
||||
* This method must be called before calling {@link #sign()} or {@link #updateContent(Message)}
|
||||
* Calling this method again will replace the key.
|
||||
*
|
||||
* @param keyStoreBuilder A keystore builder that can be used to load a keystore.
|
||||
*/
|
||||
public void loadSigningCertificate(KeyStore.Builder keyStoreBuilder)
|
||||
throws IOException, CertificateException, UnrecoverableKeyException;
|
||||
|
||||
|
||||
/**
|
||||
* @return the signer ID if it exists; null otherwise.
|
||||
*/
|
||||
public ByteString getSignerID();
|
||||
|
||||
/**
|
||||
* Clear the signing key (will require authentication to use again).
|
||||
*/
|
||||
public void clearSigningKey();
|
||||
|
||||
}
|
||||
package meerkat.destributed_key_generation;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
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 static meerkat.protobuf.Crypto.*;
|
||||
|
||||
/**
|
||||
* Created by talm on 25/10/15.
|
||||
*
|
||||
* Sign and verify arrays of messages
|
||||
*/
|
||||
public interface DigitalSignature {
|
||||
final public static String CERTIFICATE_ENCODING_X509 = "X.509";
|
||||
|
||||
/**
|
||||
* Load a set of certificates from an input stream.
|
||||
* This will consume the entire stream.
|
||||
* Certificates can be either DER-encoded (binary) or PEM (base64) encoded.
|
||||
* This may be called multiple times to load several different certificates.
|
||||
* It must be called before calling {@link #verify()}.
|
||||
* @param certStream source from which certificates are loaded
|
||||
* @throws CertificateException on parsing errors
|
||||
*/
|
||||
public void loadVerificationCertificates(InputStream certStream)
|
||||
throws CertificateException;
|
||||
|
||||
/**
|
||||
* Clear the loaded verification certificates.
|
||||
*/
|
||||
public void clearVerificationCertificates();
|
||||
|
||||
|
||||
/**
|
||||
* Add msg to the content stream to be verified / signed. Each message is (automatically)
|
||||
* prepended with its length as a 32-bit big-endian unsigned integer.
|
||||
*
|
||||
* @param msg
|
||||
* @throws SignatureException
|
||||
*/
|
||||
public void updateContent(Message msg) throws SignatureException;
|
||||
|
||||
|
||||
/**
|
||||
* Sign the content that was added using {@link #updateContent(Message)}.
|
||||
* Reset the DigitalSignature and make it available to sign a new message using the same key.
|
||||
* @return
|
||||
* @throws SignatureException
|
||||
*/
|
||||
Signature sign() throws SignatureException;
|
||||
|
||||
/**
|
||||
* Initialize the verifier with the certificate whose Id is in sig.
|
||||
* @param sig
|
||||
* @throws CertificateException
|
||||
* @throws InvalidKeyException
|
||||
*/
|
||||
void initVerify(Signature sig)
|
||||
throws CertificateException, InvalidKeyException;
|
||||
|
||||
/**
|
||||
* Verify the updated content using the initialized signature.
|
||||
* @return
|
||||
*/
|
||||
public boolean verify();
|
||||
|
||||
/**
|
||||
* Loads a private signing key. The keystore must include both the public and private
|
||||
* key parts.
|
||||
* This method must be called before calling {@link #sign()} or {@link #updateContent(Message)}
|
||||
* Calling this method again will replace the key.
|
||||
*
|
||||
* @param keyStoreBuilder A keystore builder that can be used to load a keystore.
|
||||
*/
|
||||
public void loadSigningCertificate(KeyStore.Builder keyStoreBuilder)
|
||||
throws IOException, CertificateException, UnrecoverableKeyException;
|
||||
|
||||
|
||||
/**
|
||||
* @return the signer ID if it exists; null otherwise.
|
||||
*/
|
||||
public ByteString getSignerID();
|
||||
|
||||
/**
|
||||
* Clear the signing key (will require authentication to use again).
|
||||
*/
|
||||
public void clearSigningKey();
|
||||
|
||||
}
|
|
@ -1,40 +1,40 @@
|
|||
package meerkat.crypto;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.google.protobuf.Message;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Random;
|
||||
|
||||
import static meerkat.protobuf.Crypto.*;
|
||||
|
||||
/**
|
||||
* Created by talm on 11/2/15.
|
||||
*/
|
||||
public interface Encryption {
|
||||
/**
|
||||
* Encrypt the serialized form of a message plaintext.
|
||||
* @param plaintext
|
||||
* @param rnd
|
||||
* @return
|
||||
*/
|
||||
RerandomizableEncryptedMessage encrypt(Message plaintext, EncryptionRandomness rnd) throws IOException; // TODO: type of exception; throws
|
||||
|
||||
|
||||
/**
|
||||
* Rerandomize a ciphertext using the supplied randomness.
|
||||
* @param msg
|
||||
* @param rnd
|
||||
* @return
|
||||
* @throws InvalidProtocolBufferException
|
||||
*/
|
||||
RerandomizableEncryptedMessage rerandomize(RerandomizableEncryptedMessage msg, EncryptionRandomness rnd) throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Generate randomness compatible with {@link #encrypt(Message, EncryptionRandomness) and
|
||||
* {@link #rerandomize(RerandomizableEncryptedMessage, EncryptionRandomness)}}.
|
||||
* @param rand
|
||||
* @return
|
||||
*/
|
||||
EncryptionRandomness generateRandomness(Random rand);
|
||||
}
|
||||
package meerkat.destributed_key_generation;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.google.protobuf.Message;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Random;
|
||||
|
||||
import static meerkat.protobuf.Crypto.*;
|
||||
|
||||
/**
|
||||
* Created by talm on 11/2/15.
|
||||
*/
|
||||
public interface Encryption {
|
||||
/**
|
||||
* Encrypt the serialized form of a message plaintext.
|
||||
* @param plaintext
|
||||
* @param rnd
|
||||
* @return
|
||||
*/
|
||||
RerandomizableEncryptedMessage encrypt(Message plaintext, EncryptionRandomness rnd) throws IOException; // TODO: type of exception; throws
|
||||
|
||||
|
||||
/**
|
||||
* Rerandomize a ciphertext using the supplied randomness.
|
||||
* @param msg
|
||||
* @param rnd
|
||||
* @return
|
||||
* @throws InvalidProtocolBufferException
|
||||
*/
|
||||
RerandomizableEncryptedMessage rerandomize(RerandomizableEncryptedMessage msg, EncryptionRandomness rnd) throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Generate randomness compatible with {@link #encrypt(Message, EncryptionRandomness) and
|
||||
* {@link #rerandomize(RerandomizableEncryptedMessage, EncryptionRandomness)}}.
|
||||
* @param rand
|
||||
* @return
|
||||
*/
|
||||
EncryptionRandomness generateRandomness(Random rand);
|
||||
}
|
|
@ -1,134 +1,134 @@
|
|||
package meerkat.crypto.concrete;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.Message;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.protobuf.Crypto.Signature;
|
||||
import org.bouncycastle.asn1.ASN1Integer;
|
||||
import org.bouncycastle.asn1.DERSequence;
|
||||
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
|
||||
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
|
||||
import org.bouncycastle.crypto.signers.DSAKCalculator;
|
||||
import org.bouncycastle.crypto.signers.ECDSASigner;
|
||||
import org.bouncycastle.crypto.signers.HMacDSAKCalculator;
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.security.*;
|
||||
import java.security.cert.*;
|
||||
import java.security.interfaces.ECPrivateKey;
|
||||
|
||||
|
||||
/**
|
||||
* Sign and verify digital signatures.
|
||||
*
|
||||
* Uses deterministic ECDSA signatures as per RFC 6979
|
||||
*
|
||||
* This class uses BouncyCastle directly, so will not work with arbitrary PKCS11 providers.
|
||||
*
|
||||
* This class is not thread-safe (each thread should have its own instance).
|
||||
*/
|
||||
public class ECDSADeterministicSignature extends ECDSASignature {
|
||||
final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
/**
|
||||
* Digest of message contents for deterministic signing.
|
||||
*/
|
||||
SHA256Digest msgDigest = new SHA256Digest();
|
||||
|
||||
/**
|
||||
* The actual signing implementation. (used only signing -- superclass is used for verification)
|
||||
*/
|
||||
ECDSASigner deterministicSigner;
|
||||
|
||||
/**
|
||||
* Output the DER encoding of the ASN.1 sequence r,s
|
||||
* @param r
|
||||
* @param s
|
||||
* @return
|
||||
*/
|
||||
public static byte[] derEncodeSignature(BigInteger r, BigInteger s) {
|
||||
ASN1Integer[] rs = {new ASN1Integer(r), new ASN1Integer(s)};
|
||||
DERSequence seq = new DERSequence(rs);
|
||||
|
||||
try {
|
||||
return seq.getEncoded();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Should never happen! DER Encoding exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
public ECDSADeterministicSignature() {
|
||||
DSAKCalculator kCalk = new HMacDSAKCalculator(new org.bouncycastle.crypto.digests.SHA256Digest());
|
||||
deterministicSigner = new ECDSASigner(kCalk);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSigningCertificate(KeyStore.Builder keyStoreBuilder)
|
||||
throws CertificateException, UnrecoverableKeyException, IOException {
|
||||
super.loadSigningCertificate(keyStoreBuilder);
|
||||
|
||||
if (!(loadedSigningKey instanceof ECPrivateKey)) {
|
||||
logger.error("Wrong private key type (expected ECPrivateKey, got {})", loadedSigningKey.getClass());
|
||||
throw new CertificateException("Wrong signing key type!");
|
||||
}
|
||||
ECPrivateKey key = (ECPrivateKey) loadedSigningKey;
|
||||
|
||||
AsymmetricKeyParameter baseParams;
|
||||
try {
|
||||
baseParams = ECUtil.generatePrivateKeyParameter(key);
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new UnrecoverableKeyException("Couldn't convert private key");
|
||||
}
|
||||
|
||||
if (!(baseParams instanceof ECPrivateKeyParameters)) {
|
||||
logger.error("Error converting to bouncycastle type! (got {})", baseParams.getClass());
|
||||
throw new UnrecoverableKeyException("Wrong signing key type!");
|
||||
}
|
||||
|
||||
ECPrivateKeyParameters params = (ECPrivateKeyParameters) baseParams;
|
||||
|
||||
deterministicSigner.init(true, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the list of messages to the stream that is being verified/signed.
|
||||
* Messages are prepended with their length in 32-bit big-endian format.
|
||||
*
|
||||
* @param msg
|
||||
* @throws SignatureException
|
||||
*/
|
||||
@Override
|
||||
public void updateContent(Message msg) throws SignatureException {
|
||||
assert msg != null;
|
||||
|
||||
// We're doing twice the digest work so that we also support verification with the same update.
|
||||
// If this becomes a problem, we can decide which way to update based on which init was called.
|
||||
super.updateContent(msg);
|
||||
msgDigest.update(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateContent(InputStream in) throws IOException, SignatureException {
|
||||
ByteString inStr = ByteString.readFrom(in);
|
||||
signer.update(inStr.asReadOnlyByteBuffer());
|
||||
msgDigest.update(inStr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Signature sign() throws SignatureException {
|
||||
Signature.Builder sig = Signature.newBuilder();
|
||||
sig.setType(Crypto.SignatureType.ECDSA);
|
||||
|
||||
BigInteger[] rawSig = deterministicSigner.generateSignature(msgDigest.digest());
|
||||
|
||||
sig.setData(ByteString.copyFrom(derEncodeSignature(rawSig[0], rawSig[1])));
|
||||
|
||||
sig.setSignerId(loadedSigningKeyId);
|
||||
return sig.build();
|
||||
}
|
||||
}
|
||||
package meerkat.destributed_key_generation.concrete;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.Message;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.protobuf.Crypto.Signature;
|
||||
import org.bouncycastle.asn1.ASN1Integer;
|
||||
import org.bouncycastle.asn1.DERSequence;
|
||||
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
|
||||
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
|
||||
import org.bouncycastle.crypto.signers.DSAKCalculator;
|
||||
import org.bouncycastle.crypto.signers.ECDSASigner;
|
||||
import org.bouncycastle.crypto.signers.HMacDSAKCalculator;
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.security.*;
|
||||
import java.security.cert.*;
|
||||
import java.security.interfaces.ECPrivateKey;
|
||||
|
||||
|
||||
/**
|
||||
* Sign and verify digital signatures.
|
||||
*
|
||||
* Uses deterministic ECDSA signatures as per RFC 6979
|
||||
*
|
||||
* This class uses BouncyCastle directly, so will not work with arbitrary PKCS11 providers.
|
||||
*
|
||||
* This class is not thread-safe (each thread should have its own instance).
|
||||
*/
|
||||
public class ECDSADeterministicSignature extends ECDSASignature {
|
||||
final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
/**
|
||||
* Digest of message contents for deterministic signing.
|
||||
*/
|
||||
SHA256Digest msgDigest = new SHA256Digest();
|
||||
|
||||
/**
|
||||
* The actual signing implementation. (used only signing -- superclass is used for verification)
|
||||
*/
|
||||
ECDSASigner deterministicSigner;
|
||||
|
||||
/**
|
||||
* Output the DER encoding of the ASN.1 sequence r,s
|
||||
* @param r
|
||||
* @param s
|
||||
* @return
|
||||
*/
|
||||
public static byte[] derEncodeSignature(BigInteger r, BigInteger s) {
|
||||
ASN1Integer[] rs = {new ASN1Integer(r), new ASN1Integer(s)};
|
||||
DERSequence seq = new DERSequence(rs);
|
||||
|
||||
try {
|
||||
return seq.getEncoded();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Should never happen! DER Encoding exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
public ECDSADeterministicSignature() {
|
||||
DSAKCalculator kCalk = new HMacDSAKCalculator(new org.bouncycastle.crypto.digests.SHA256Digest());
|
||||
deterministicSigner = new ECDSASigner(kCalk);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSigningCertificate(KeyStore.Builder keyStoreBuilder)
|
||||
throws CertificateException, UnrecoverableKeyException, IOException {
|
||||
super.loadSigningCertificate(keyStoreBuilder);
|
||||
|
||||
if (!(loadedSigningKey instanceof ECPrivateKey)) {
|
||||
logger.error("Wrong private key type (expected ECPrivateKey, got {})", loadedSigningKey.getClass());
|
||||
throw new CertificateException("Wrong signing key type!");
|
||||
}
|
||||
ECPrivateKey key = (ECPrivateKey) loadedSigningKey;
|
||||
|
||||
AsymmetricKeyParameter baseParams;
|
||||
try {
|
||||
baseParams = ECUtil.generatePrivateKeyParameter(key);
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new UnrecoverableKeyException("Couldn't convert private key");
|
||||
}
|
||||
|
||||
if (!(baseParams instanceof ECPrivateKeyParameters)) {
|
||||
logger.error("Error converting to bouncycastle type! (got {})", baseParams.getClass());
|
||||
throw new UnrecoverableKeyException("Wrong signing key type!");
|
||||
}
|
||||
|
||||
ECPrivateKeyParameters params = (ECPrivateKeyParameters) baseParams;
|
||||
|
||||
deterministicSigner.init(true, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the list of messages to the stream that is being verified/signed.
|
||||
* Messages are prepended with their length in 32-bit big-endian format.
|
||||
*
|
||||
* @param msg
|
||||
* @throws SignatureException
|
||||
*/
|
||||
@Override
|
||||
public void updateContent(Message msg) throws SignatureException {
|
||||
assert msg != null;
|
||||
|
||||
// We're doing twice the digest work so that we also support verification with the same update.
|
||||
// If this becomes a problem, we can decide which way to update based on which init was called.
|
||||
super.updateContent(msg);
|
||||
msgDigest.update(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateContent(InputStream in) throws IOException, SignatureException {
|
||||
ByteString inStr = ByteString.readFrom(in);
|
||||
signer.update(inStr.asReadOnlyByteBuffer());
|
||||
msgDigest.update(inStr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Signature sign() throws SignatureException {
|
||||
Signature.Builder sig = Signature.newBuilder();
|
||||
sig.setType(Crypto.SignatureType.ECDSA);
|
||||
|
||||
BigInteger[] rawSig = deterministicSigner.generateSignature(msgDigest.digest());
|
||||
|
||||
sig.setData(ByteString.copyFrom(derEncodeSignature(rawSig[0], rawSig[1])));
|
||||
|
||||
sig.setSignerId(loadedSigningKeyId);
|
||||
return sig.build();
|
||||
}
|
||||
}
|
|
@ -1,322 +1,322 @@
|
|||
package meerkat.crypto.concrete;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.*;
|
||||
import java.security.cert.*;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.*;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.util.Hex;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.protobuf.Message;
|
||||
|
||||
import meerkat.crypto.DigitalSignature;
|
||||
import meerkat.protobuf.Crypto.Signature;
|
||||
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.security.auth.callback.PasswordCallback;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
|
||||
|
||||
/**
|
||||
* Sign and verify digital signatures.
|
||||
*
|
||||
* This class is not thread-safe (each thread should have its own instance).
|
||||
*/
|
||||
public class ECDSASignature extends GlobalCryptoSetup implements DigitalSignature {
|
||||
final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
final public static String KEYSTORE_TYPE = "PKCS12";
|
||||
final public static String DEFAULT_SIGNATURE_ALGORITHM = "SHA256withECDSA";
|
||||
|
||||
SHA256Digest certDigest = new SHA256Digest();
|
||||
|
||||
/**
|
||||
* Buffer used to hold length in for hash update
|
||||
*/
|
||||
ByteBuffer lenBuf = ByteBuffer.allocate(4);
|
||||
|
||||
|
||||
Map<ByteString, Certificate> loadedCertificates = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Signature currently loaded (will be used in calls to {@link #verify()}).
|
||||
*/
|
||||
ByteString loadedSignature = null;
|
||||
|
||||
ByteString loadedSigningKeyId = null;
|
||||
|
||||
/**
|
||||
* The actual signing implementation. (used for both signing and verifying)
|
||||
*/
|
||||
java.security.Signature signer;
|
||||
|
||||
/**
|
||||
* The currently loaded signing key.
|
||||
*/
|
||||
PrivateKey loadedSigningKey;
|
||||
|
||||
|
||||
/**
|
||||
* Compute a fingerprint of a cert as a SHA256 hash.
|
||||
*
|
||||
* @param cert
|
||||
* @return
|
||||
*/
|
||||
public ByteString computeCertificateFingerprint(Certificate cert) {
|
||||
try {
|
||||
certDigest.reset();
|
||||
byte[] data = cert.getEncoded();
|
||||
certDigest.update(data);
|
||||
return ByteString.copyFrom(certDigest.digest());
|
||||
} catch (CertificateEncodingException e) {
|
||||
// Shouldn't happen
|
||||
logger.error("Certificate encoding error", e);
|
||||
throw new RuntimeException("Certificate encoding error", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public ECDSASignature(java.security.Signature signer) {
|
||||
this.signer = signer;
|
||||
}
|
||||
|
||||
public ECDSASignature() {
|
||||
try {
|
||||
this.signer = java.security.Signature.getInstance(DEFAULT_SIGNATURE_ALGORITHM);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// Should never happen
|
||||
logger.error("Couldn't find implementation for " + DEFAULT_SIGNATURE_ALGORITHM + " signatures", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadVerificationCertificates(InputStream certStream)
|
||||
throws CertificateException {
|
||||
CertificateFactory certificateFactory = CertificateFactory.getInstance(CERTIFICATE_ENCODING_X509);
|
||||
Collection<? extends Certificate> certs = certificateFactory.generateCertificates(certStream);
|
||||
for (Certificate cert : certs) {
|
||||
// Just checking
|
||||
if (!(cert instanceof X509Certificate)) {
|
||||
logger.error("Certificate must be in X509 format; got {} instead!", cert.getClass().getCanonicalName());
|
||||
continue;
|
||||
}
|
||||
ByteString keyId = computeCertificateFingerprint(cert);
|
||||
loadedCertificates.put(keyId, cert);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearVerificationCertificates() {
|
||||
loadedCertificates.clear();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add the list of messages to the stream that is being verified/signed.
|
||||
* Messages are prepended with their length in 32-bit big-endian format.
|
||||
*
|
||||
* @param msg
|
||||
* @throws SignatureException
|
||||
*/
|
||||
@Override
|
||||
public void updateContent(Message msg) throws SignatureException {
|
||||
assert msg != null;
|
||||
|
||||
lenBuf.clear();
|
||||
lenBuf.putInt(msg.getSerializedSize());
|
||||
lenBuf.flip();
|
||||
signer.update(lenBuf);
|
||||
signer.update(msg.toByteString().asReadOnlyByteBuffer());
|
||||
}
|
||||
|
||||
public void updateContent(InputStream in) throws IOException, SignatureException {
|
||||
ByteString inStr = ByteString.readFrom(in);
|
||||
signer.update(inStr.asReadOnlyByteBuffer());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Signature sign() throws SignatureException {
|
||||
Signature.Builder sig = Signature.newBuilder();
|
||||
sig.setType(Crypto.SignatureType.ECDSA);
|
||||
sig.setData(ByteString.copyFrom(signer.sign()));
|
||||
sig.setSignerId(loadedSigningKeyId);
|
||||
return sig.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initVerify(Signature sig)
|
||||
throws CertificateException, InvalidKeyException {
|
||||
Certificate cert = loadedCertificates.get(sig.getSignerId());
|
||||
if (cert == null) {
|
||||
logger.warn("No certificate loaded for ID {}!", sig.getSignerId());
|
||||
throw new CertificateException("No certificate loaded for " + sig.getSignerId());
|
||||
}
|
||||
signer.initVerify(cert.getPublicKey());
|
||||
loadedSignature = sig.getData();
|
||||
loadedSigningKeyId = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify() {
|
||||
try {
|
||||
return signer.verify(loadedSignature.toByteArray());
|
||||
} catch (SignatureException e) {
|
||||
// Happens only if signature is invalid!
|
||||
logger.error("Signature exception", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to more easily deal with simple password-protected files.
|
||||
*
|
||||
* @param password
|
||||
* @return
|
||||
*/
|
||||
public CallbackHandler getFixedPasswordHandler(final char[] password) {
|
||||
return new CallbackHandler() {
|
||||
@Override
|
||||
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
|
||||
for (Callback callback : callbacks) {
|
||||
if (callback instanceof PasswordCallback) {
|
||||
PasswordCallback passwordCallback = (PasswordCallback) callback;
|
||||
logger.debug("Requested password ({})", passwordCallback.getPrompt());
|
||||
passwordCallback.setPassword(password);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE);
|
||||
keyStore.load(keyStream, password);
|
||||
return KeyStore.Builder.newInstance(keyStore, new KeyStore.CallbackHandlerProtection(getFixedPasswordHandler(password)));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* For now we only support PKCS12.
|
||||
* TODO: Support for PKCS11 as well.
|
||||
*
|
||||
* @param keyStoreBuilder
|
||||
* @throws IOException
|
||||
* @throws CertificateException
|
||||
* @throws UnrecoverableKeyException
|
||||
*/
|
||||
@Override
|
||||
public void loadSigningCertificate(KeyStore.Builder keyStoreBuilder)
|
||||
throws IOException, CertificateException, UnrecoverableKeyException {
|
||||
try {
|
||||
|
||||
KeyStore keyStore = keyStoreBuilder.getKeyStore();
|
||||
|
||||
// Iterate through all aliases until we find the first privatekey
|
||||
Enumeration<String> aliases = keyStore.aliases();
|
||||
while (aliases.hasMoreElements()) {
|
||||
String alias = aliases.nextElement();
|
||||
logger.trace("Testing keystore entry {}", alias);
|
||||
|
||||
|
||||
try {
|
||||
Certificate cert = keyStore.getCertificate(alias);
|
||||
logger.trace("keystore entry {}, has cert type {}", alias, cert.getClass());
|
||||
|
||||
Key key;
|
||||
|
||||
try {
|
||||
key = keyStore.getKey(alias, null);
|
||||
} catch (UnrecoverableKeyException e) {
|
||||
// This might be a keystore that doesn't support callback handlers
|
||||
// (e.g., Java 8 PKCS12)
|
||||
// Manually extract password using callback handler
|
||||
char[] password = null;
|
||||
KeyStore.ProtectionParameter prot = keyStoreBuilder.getProtectionParameter(alias);
|
||||
|
||||
if (prot instanceof KeyStore.PasswordProtection) {
|
||||
password = ((KeyStore.PasswordProtection) prot).getPassword();
|
||||
} else if (prot instanceof KeyStore.CallbackHandlerProtection) {
|
||||
PasswordCallback callback = new PasswordCallback("Password for " + alias + "?", false);
|
||||
Callback[] callbacks = { callback };
|
||||
try {
|
||||
((KeyStore.CallbackHandlerProtection) prot).getCallbackHandler().handle(callbacks);
|
||||
password = callback.getPassword();
|
||||
} catch (UnsupportedCallbackException e1) {
|
||||
logger.error("PasswordCallback fallback not supported!", e1);
|
||||
throw new UnrecoverableKeyException("Couldn't use password callback to get key");
|
||||
}
|
||||
} else {
|
||||
logger.error("Unrecognized protection handler for keystore: {}", prot.getClass());
|
||||
throw new UnrecoverableKeyException("Unrecognized protection handler for keystore");
|
||||
}
|
||||
key = keyStore.getKey(alias, password);
|
||||
}
|
||||
logger.trace("keystore entry {}, has key type {}", alias, key.getClass());
|
||||
if (key instanceof PrivateKey) {
|
||||
loadedSigningKey = (PrivateKey) key;
|
||||
loadedSigningKeyId = computeCertificateFingerprint(cert);
|
||||
signer.initSign(loadedSigningKey);
|
||||
logger.debug("Loaded signing key with ID {}", Hex.encode(loadedSigningKeyId));
|
||||
|
||||
return;
|
||||
} else {
|
||||
logger.info("Certificate {} in keystore does not have a private key", cert.toString());
|
||||
}
|
||||
} catch(InvalidKeyException e) {
|
||||
logger.info("Read invalid key", e);
|
||||
} catch(UnrecoverableEntryException e) {
|
||||
logger.info("Read unrecoverable entry", e);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (KeyStoreException e) {
|
||||
logger.error("Keystore exception", e);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
logger.error("NoSuchAlgorithmException exception", e);
|
||||
throw new CertificateException(e);
|
||||
}
|
||||
logger.error("Didn't find valid private key entry in keystore");
|
||||
throw new UnrecoverableKeyException("Didn't find valid private key entry in keystore!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteString getSignerID() {
|
||||
return loadedSigningKeyId;
|
||||
}
|
||||
|
||||
public void clearSigningKey() {
|
||||
try {
|
||||
// TODO: Check if this really clears the key from memory
|
||||
if (loadedSigningKeyId != null)
|
||||
signer.initSign(null);
|
||||
loadedSigningKeyId = null;
|
||||
loadedSigningKey = null;
|
||||
// Start garbage collection?
|
||||
} catch (InvalidKeyException e) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
package meerkat.destributed_key_generation.concrete;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.*;
|
||||
import java.security.cert.*;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.*;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.util.Hex;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.protobuf.Message;
|
||||
|
||||
import meerkat.destributed_key_generation.DigitalSignature;
|
||||
import meerkat.protobuf.Crypto.Signature;
|
||||
|
||||
import javax.security.auth.callback.Callback;
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.security.auth.callback.PasswordCallback;
|
||||
import javax.security.auth.callback.UnsupportedCallbackException;
|
||||
|
||||
|
||||
/**
|
||||
* Sign and verify digital signatures.
|
||||
*
|
||||
* This class is not thread-safe (each thread should have its own instance).
|
||||
*/
|
||||
public class ECDSASignature extends GlobalCryptoSetup implements DigitalSignature {
|
||||
final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
final public static String KEYSTORE_TYPE = "PKCS12";
|
||||
final public static String DEFAULT_SIGNATURE_ALGORITHM = "SHA256withECDSA";
|
||||
|
||||
SHA256Digest certDigest = new SHA256Digest();
|
||||
|
||||
/**
|
||||
* Buffer used to hold length in for hash update
|
||||
*/
|
||||
ByteBuffer lenBuf = ByteBuffer.allocate(4);
|
||||
|
||||
|
||||
Map<ByteString, Certificate> loadedCertificates = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Signature currently loaded (will be used in calls to {@link #verify()}).
|
||||
*/
|
||||
ByteString loadedSignature = null;
|
||||
|
||||
ByteString loadedSigningKeyId = null;
|
||||
|
||||
/**
|
||||
* The actual signing implementation. (used for both signing and verifying)
|
||||
*/
|
||||
java.security.Signature signer;
|
||||
|
||||
/**
|
||||
* The currently loaded signing key.
|
||||
*/
|
||||
PrivateKey loadedSigningKey;
|
||||
|
||||
|
||||
/**
|
||||
* Compute a fingerprint of a cert as a SHA256 hash.
|
||||
*
|
||||
* @param cert
|
||||
* @return
|
||||
*/
|
||||
public ByteString computeCertificateFingerprint(Certificate cert) {
|
||||
try {
|
||||
certDigest.reset();
|
||||
byte[] data = cert.getEncoded();
|
||||
certDigest.update(data);
|
||||
return ByteString.copyFrom(certDigest.digest());
|
||||
} catch (CertificateEncodingException e) {
|
||||
// Shouldn't happen
|
||||
logger.error("Certificate encoding error", e);
|
||||
throw new RuntimeException("Certificate encoding error", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public ECDSASignature(java.security.Signature signer) {
|
||||
this.signer = signer;
|
||||
}
|
||||
|
||||
public ECDSASignature() {
|
||||
try {
|
||||
this.signer = java.security.Signature.getInstance(DEFAULT_SIGNATURE_ALGORITHM);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// Should never happen
|
||||
logger.error("Couldn't find implementation for " + DEFAULT_SIGNATURE_ALGORITHM + " signatures", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadVerificationCertificates(InputStream certStream)
|
||||
throws CertificateException {
|
||||
CertificateFactory certificateFactory = CertificateFactory.getInstance(CERTIFICATE_ENCODING_X509);
|
||||
Collection<? extends Certificate> certs = certificateFactory.generateCertificates(certStream);
|
||||
for (Certificate cert : certs) {
|
||||
// Just checking
|
||||
if (!(cert instanceof X509Certificate)) {
|
||||
logger.error("Certificate must be in X509 format; got {} instead!", cert.getClass().getCanonicalName());
|
||||
continue;
|
||||
}
|
||||
ByteString keyId = computeCertificateFingerprint(cert);
|
||||
loadedCertificates.put(keyId, cert);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearVerificationCertificates() {
|
||||
loadedCertificates.clear();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add the list of messages to the stream that is being verified/signed.
|
||||
* Messages are prepended with their length in 32-bit big-endian format.
|
||||
*
|
||||
* @param msg
|
||||
* @throws SignatureException
|
||||
*/
|
||||
@Override
|
||||
public void updateContent(Message msg) throws SignatureException {
|
||||
assert msg != null;
|
||||
|
||||
lenBuf.clear();
|
||||
lenBuf.putInt(msg.getSerializedSize());
|
||||
lenBuf.flip();
|
||||
signer.update(lenBuf);
|
||||
signer.update(msg.toByteString().asReadOnlyByteBuffer());
|
||||
}
|
||||
|
||||
public void updateContent(InputStream in) throws IOException, SignatureException {
|
||||
ByteString inStr = ByteString.readFrom(in);
|
||||
signer.update(inStr.asReadOnlyByteBuffer());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Signature sign() throws SignatureException {
|
||||
Signature.Builder sig = Signature.newBuilder();
|
||||
sig.setType(Crypto.SignatureType.ECDSA);
|
||||
sig.setData(ByteString.copyFrom(signer.sign()));
|
||||
sig.setSignerId(loadedSigningKeyId);
|
||||
return sig.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initVerify(Signature sig)
|
||||
throws CertificateException, InvalidKeyException {
|
||||
Certificate cert = loadedCertificates.get(sig.getSignerId());
|
||||
if (cert == null) {
|
||||
logger.warn("No certificate loaded for ID {}!", sig.getSignerId());
|
||||
throw new CertificateException("No certificate loaded for " + sig.getSignerId());
|
||||
}
|
||||
signer.initVerify(cert.getPublicKey());
|
||||
loadedSignature = sig.getData();
|
||||
loadedSigningKeyId = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify() {
|
||||
try {
|
||||
return signer.verify(loadedSignature.toByteArray());
|
||||
} catch (SignatureException e) {
|
||||
// Happens only if signature is invalid!
|
||||
logger.error("Signature exception", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to more easily deal with simple password-protected files.
|
||||
*
|
||||
* @param password
|
||||
* @return
|
||||
*/
|
||||
public CallbackHandler getFixedPasswordHandler(final char[] password) {
|
||||
return new CallbackHandler() {
|
||||
@Override
|
||||
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
|
||||
for (Callback callback : callbacks) {
|
||||
if (callback instanceof PasswordCallback) {
|
||||
PasswordCallback passwordCallback = (PasswordCallback) callback;
|
||||
logger.debug("Requested password ({})", passwordCallback.getPrompt());
|
||||
passwordCallback.setPassword(password);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
KeyStore keyStore = KeyStore.getInstance(KEYSTORE_TYPE);
|
||||
keyStore.load(keyStream, password);
|
||||
return KeyStore.Builder.newInstance(keyStore, new KeyStore.CallbackHandlerProtection(getFixedPasswordHandler(password)));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* For now we only support PKCS12.
|
||||
* TODO: Support for PKCS11 as well.
|
||||
*
|
||||
* @param keyStoreBuilder
|
||||
* @throws IOException
|
||||
* @throws CertificateException
|
||||
* @throws UnrecoverableKeyException
|
||||
*/
|
||||
@Override
|
||||
public void loadSigningCertificate(KeyStore.Builder keyStoreBuilder)
|
||||
throws IOException, CertificateException, UnrecoverableKeyException {
|
||||
try {
|
||||
|
||||
KeyStore keyStore = keyStoreBuilder.getKeyStore();
|
||||
|
||||
// Iterate through all aliases until we find the first privatekey
|
||||
Enumeration<String> aliases = keyStore.aliases();
|
||||
while (aliases.hasMoreElements()) {
|
||||
String alias = aliases.nextElement();
|
||||
logger.trace("Testing keystore entry {}", alias);
|
||||
|
||||
|
||||
try {
|
||||
Certificate cert = keyStore.getCertificate(alias);
|
||||
logger.trace("keystore entry {}, has cert type {}", alias, cert.getClass());
|
||||
|
||||
Key key;
|
||||
|
||||
try {
|
||||
key = keyStore.getKey(alias, null);
|
||||
} catch (UnrecoverableKeyException e) {
|
||||
// This might be a keystore that doesn't support callback handlers
|
||||
// (e.g., Java 8 PKCS12)
|
||||
// Manually extract password using callback handler
|
||||
char[] password = null;
|
||||
KeyStore.ProtectionParameter prot = keyStoreBuilder.getProtectionParameter(alias);
|
||||
|
||||
if (prot instanceof KeyStore.PasswordProtection) {
|
||||
password = ((KeyStore.PasswordProtection) prot).getPassword();
|
||||
} else if (prot instanceof KeyStore.CallbackHandlerProtection) {
|
||||
PasswordCallback callback = new PasswordCallback("Password for " + alias + "?", false);
|
||||
Callback[] callbacks = { callback };
|
||||
try {
|
||||
((KeyStore.CallbackHandlerProtection) prot).getCallbackHandler().handle(callbacks);
|
||||
password = callback.getPassword();
|
||||
} catch (UnsupportedCallbackException e1) {
|
||||
logger.error("PasswordCallback fallback not supported!", e1);
|
||||
throw new UnrecoverableKeyException("Couldn't use password callback to get key");
|
||||
}
|
||||
} else {
|
||||
logger.error("Unrecognized protection handler for keystore: {}", prot.getClass());
|
||||
throw new UnrecoverableKeyException("Unrecognized protection handler for keystore");
|
||||
}
|
||||
key = keyStore.getKey(alias, password);
|
||||
}
|
||||
logger.trace("keystore entry {}, has key type {}", alias, key.getClass());
|
||||
if (key instanceof PrivateKey) {
|
||||
loadedSigningKey = (PrivateKey) key;
|
||||
loadedSigningKeyId = computeCertificateFingerprint(cert);
|
||||
signer.initSign(loadedSigningKey);
|
||||
logger.debug("Loaded signing key with ID {}", Hex.encode(loadedSigningKeyId));
|
||||
|
||||
return;
|
||||
} else {
|
||||
logger.info("Certificate {} in keystore does not have a private key", cert.toString());
|
||||
}
|
||||
} catch(InvalidKeyException e) {
|
||||
logger.info("Read invalid key", e);
|
||||
} catch(UnrecoverableEntryException e) {
|
||||
logger.info("Read unrecoverable entry", e);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (KeyStoreException e) {
|
||||
logger.error("Keystore exception", e);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
logger.error("NoSuchAlgorithmException exception", e);
|
||||
throw new CertificateException(e);
|
||||
}
|
||||
logger.error("Didn't find valid private key entry in keystore");
|
||||
throw new UnrecoverableKeyException("Didn't find valid private key entry in keystore!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteString getSignerID() {
|
||||
return loadedSigningKeyId;
|
||||
}
|
||||
|
||||
public void clearSigningKey() {
|
||||
try {
|
||||
// TODO: Check if this really clears the key from memory
|
||||
if (loadedSigningKeyId != null)
|
||||
signer.initSign(null);
|
||||
loadedSigningKeyId = null;
|
||||
loadedSigningKey = null;
|
||||
// Start garbage collection?
|
||||
} catch (InvalidKeyException e) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,135 +1,135 @@
|
|||
package meerkat.crypto.concrete;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.google.protobuf.Message;
|
||||
import meerkat.crypto.Encryption;
|
||||
import meerkat.protobuf.ConcreteCrypto;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
|
||||
import org.bouncycastle.crypto.params.ECDomainParameters;
|
||||
import org.bouncycastle.crypto.params.ECKeyParameters;
|
||||
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
||||
import org.bouncycastle.crypto.util.PublicKeyFactory;
|
||||
import org.bouncycastle.jce.spec.ECParameterSpec;
|
||||
import org.bouncycastle.math.ec.ECCurve;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.bouncycastle.util.BigIntegers;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.factcenter.qilin.primitives.concrete.ECElGamal;
|
||||
import org.factcenter.qilin.primitives.concrete.ECGroup;
|
||||
import org.factcenter.qilin.util.PRGRandom;
|
||||
import org.factcenter.qilin.util.Pair;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.spec.*;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Created by talm on 17/11/15.
|
||||
*/
|
||||
public class ECElGamalEncryption extends GlobalCryptoSetup implements Encryption {
|
||||
final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
public final static String KEY_ALGORITHM = "ECDH";
|
||||
|
||||
/**
|
||||
* The Qilin format El-Gamal public key
|
||||
*/
|
||||
ECElGamal.PK elGamalPK;
|
||||
|
||||
ECCurve curve;
|
||||
|
||||
ECGroup group;
|
||||
|
||||
public ECGroup getGroup() { return group; }
|
||||
|
||||
public ECElGamal.PK getElGamalPK() {
|
||||
return elGamalPK;
|
||||
}
|
||||
|
||||
public void init(ConcreteCrypto.ElGamalPublicKey serializedPk) throws InvalidKeySpecException {
|
||||
AsymmetricKeyParameter keyParam;
|
||||
|
||||
try {
|
||||
keyParam = PublicKeyFactory.createKey(serializedPk.getSubjectPublicKeyInfo().toByteArray());
|
||||
} catch (IOException e) {
|
||||
// Shouldn't every happen
|
||||
logger.error("Invalid Public Key Encoding", e);
|
||||
throw new InvalidKeySpecException("Invalid Public Key Encoding", e);
|
||||
}
|
||||
|
||||
if (!(keyParam instanceof ECPublicKeyParameters)) {
|
||||
logger.error("Public key is a {}, not a valid public EC Key!", keyParam.getClass());
|
||||
throw new InvalidKeySpecException("Not a valid EC public key!");
|
||||
}
|
||||
|
||||
ECDomainParameters params = ((ECKeyParameters) keyParam).getParameters();
|
||||
ECParameterSpec ecParams = new ECParameterSpec(params.getCurve(), params.getG(), params.getN(), params.getH(),
|
||||
params.getSeed());
|
||||
|
||||
curve = params.getCurve();
|
||||
group = new ECGroup(ecParams);
|
||||
|
||||
elGamalPK = new ECElGamal.PK(group, ((ECPublicKeyParameters) keyParam).getQ());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Crypto.RerandomizableEncryptedMessage encrypt(Message plaintext, Crypto.EncryptionRandomness rnd) {
|
||||
|
||||
// We write the message using writeDelimited to so the length gets prepended.
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
try {
|
||||
plaintext.writeDelimitedTo(out);
|
||||
} catch (IOException e) {
|
||||
logger.error("Should never happen!", e);
|
||||
throw new RuntimeException("Error in ByteArrayOutputStream!", e);
|
||||
}
|
||||
byte[] msg = out.toByteArray();
|
||||
ECPoint encodedMsg = group.injectiveEncode(msg, new PRGRandom(msg));
|
||||
|
||||
BigInteger rndInt = BigIntegers.fromUnsignedByteArray(rnd.getData().toByteArray());
|
||||
Pair<ECPoint,ECPoint> cipherText = elGamalPK.encrypt(encodedMsg, rndInt);
|
||||
ConcreteCrypto.ElGamalCiphertext encodedCipherText = ConcreteCrypto.ElGamalCiphertext.newBuilder()
|
||||
.setC1(ByteString.copyFrom(cipherText.a.getEncoded(true)))
|
||||
.setC2(ByteString.copyFrom(cipherText.b.getEncoded(true)))
|
||||
.build();
|
||||
|
||||
return Crypto.RerandomizableEncryptedMessage.newBuilder()
|
||||
.setData(encodedCipherText.toByteString())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Crypto.RerandomizableEncryptedMessage rerandomize(Crypto.RerandomizableEncryptedMessage msg, Crypto.EncryptionRandomness rnd) throws InvalidProtocolBufferException {
|
||||
BigInteger rndInt = BigIntegers.fromUnsignedByteArray(rnd.getData().toByteArray());
|
||||
Pair<ECPoint,ECPoint> randomizer = elGamalPK.encrypt(curve.getInfinity(), rndInt);
|
||||
ConcreteCrypto.ElGamalCiphertext originalEncodedCipher= ConcreteCrypto.ElGamalCiphertext.parseFrom(msg.getData());
|
||||
|
||||
Pair<ECPoint,ECPoint> originalCipher = new Pair<ECPoint, ECPoint>(
|
||||
curve.decodePoint(originalEncodedCipher.getC1().toByteArray()),
|
||||
curve.decodePoint(originalEncodedCipher.getC2().toByteArray()));
|
||||
Pair<ECPoint,ECPoint> newCipher = elGamalPK.add(originalCipher, randomizer);
|
||||
|
||||
return Crypto.RerandomizableEncryptedMessage.newBuilder()
|
||||
.setData(
|
||||
ConcreteCrypto.ElGamalCiphertext.newBuilder()
|
||||
.setC1(ByteString.copyFrom(newCipher.a.getEncoded(true)))
|
||||
.setC2(ByteString.copyFrom(newCipher.b.getEncoded(true)))
|
||||
.build().toByteString()
|
||||
).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Crypto.EncryptionRandomness generateRandomness(Random rand) {
|
||||
BigInteger randomInt = new BigInteger(group.getCurveParams().getN().bitLength() - 1, rand);
|
||||
Crypto.EncryptionRandomness retval = Crypto.EncryptionRandomness.newBuilder()
|
||||
.setData(ByteString.copyFrom(BigIntegers.asUnsignedByteArray(randomInt))).build();
|
||||
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
package meerkat.destributed_key_generation.concrete;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.google.protobuf.Message;
|
||||
import meerkat.destributed_key_generation.Encryption;
|
||||
import meerkat.protobuf.ConcreteCrypto;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
|
||||
import org.bouncycastle.crypto.params.ECDomainParameters;
|
||||
import org.bouncycastle.crypto.params.ECKeyParameters;
|
||||
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
||||
import org.bouncycastle.crypto.util.PublicKeyFactory;
|
||||
import org.bouncycastle.jce.spec.ECParameterSpec;
|
||||
import org.bouncycastle.math.ec.ECCurve;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.bouncycastle.util.BigIntegers;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.factcenter.qilin.primitives.concrete.ECElGamal;
|
||||
import org.factcenter.qilin.primitives.concrete.ECGroup;
|
||||
import org.factcenter.qilin.util.PRGRandom;
|
||||
import org.factcenter.qilin.util.Pair;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.spec.*;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Created by talm on 17/11/15.
|
||||
*/
|
||||
public class ECElGamalEncryption extends GlobalCryptoSetup implements Encryption {
|
||||
final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
public final static String KEY_ALGORITHM = "ECDH";
|
||||
|
||||
/**
|
||||
* The Qilin format El-Gamal public key
|
||||
*/
|
||||
ECElGamal.PK elGamalPK;
|
||||
|
||||
ECCurve curve;
|
||||
|
||||
ECGroup group;
|
||||
|
||||
public ECGroup getGroup() { return group; }
|
||||
|
||||
public ECElGamal.PK getElGamalPK() {
|
||||
return elGamalPK;
|
||||
}
|
||||
|
||||
public void init(ConcreteCrypto.ElGamalPublicKey serializedPk) throws InvalidKeySpecException {
|
||||
AsymmetricKeyParameter keyParam;
|
||||
|
||||
try {
|
||||
keyParam = PublicKeyFactory.createKey(serializedPk.getSubjectPublicKeyInfo().toByteArray());
|
||||
} catch (IOException e) {
|
||||
// Shouldn't every happen
|
||||
logger.error("Invalid Public Key Encoding", e);
|
||||
throw new InvalidKeySpecException("Invalid Public Key Encoding", e);
|
||||
}
|
||||
|
||||
if (!(keyParam instanceof ECPublicKeyParameters)) {
|
||||
logger.error("Public key is a {}, not a valid public EC Key!", keyParam.getClass());
|
||||
throw new InvalidKeySpecException("Not a valid EC public key!");
|
||||
}
|
||||
|
||||
ECDomainParameters params = ((ECKeyParameters) keyParam).getParameters();
|
||||
ECParameterSpec ecParams = new ECParameterSpec(params.getCurve(), params.getG(), params.getN(), params.getH(),
|
||||
params.getSeed());
|
||||
|
||||
curve = params.getCurve();
|
||||
group = new ECGroup(ecParams);
|
||||
|
||||
elGamalPK = new ECElGamal.PK(group, ((ECPublicKeyParameters) keyParam).getQ());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Crypto.RerandomizableEncryptedMessage encrypt(Message plaintext, Crypto.EncryptionRandomness rnd) {
|
||||
|
||||
// We write the message using writeDelimited to so the length gets prepended.
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
try {
|
||||
plaintext.writeDelimitedTo(out);
|
||||
} catch (IOException e) {
|
||||
logger.error("Should never happen!", e);
|
||||
throw new RuntimeException("Error in ByteArrayOutputStream!", e);
|
||||
}
|
||||
byte[] msg = out.toByteArray();
|
||||
ECPoint encodedMsg = group.injectiveEncode(msg, new PRGRandom(msg));
|
||||
|
||||
BigInteger rndInt = BigIntegers.fromUnsignedByteArray(rnd.getData().toByteArray());
|
||||
Pair<ECPoint,ECPoint> cipherText = elGamalPK.encrypt(encodedMsg, rndInt);
|
||||
ConcreteCrypto.ElGamalCiphertext encodedCipherText = ConcreteCrypto.ElGamalCiphertext.newBuilder()
|
||||
.setC1(ByteString.copyFrom(cipherText.a.getEncoded(true)))
|
||||
.setC2(ByteString.copyFrom(cipherText.b.getEncoded(true)))
|
||||
.build();
|
||||
|
||||
return Crypto.RerandomizableEncryptedMessage.newBuilder()
|
||||
.setData(encodedCipherText.toByteString())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Crypto.RerandomizableEncryptedMessage rerandomize(Crypto.RerandomizableEncryptedMessage msg, Crypto.EncryptionRandomness rnd) throws InvalidProtocolBufferException {
|
||||
BigInteger rndInt = BigIntegers.fromUnsignedByteArray(rnd.getData().toByteArray());
|
||||
Pair<ECPoint,ECPoint> randomizer = elGamalPK.encrypt(curve.getInfinity(), rndInt);
|
||||
ConcreteCrypto.ElGamalCiphertext originalEncodedCipher= ConcreteCrypto.ElGamalCiphertext.parseFrom(msg.getData());
|
||||
|
||||
Pair<ECPoint,ECPoint> originalCipher = new Pair<ECPoint, ECPoint>(
|
||||
curve.decodePoint(originalEncodedCipher.getC1().toByteArray()),
|
||||
curve.decodePoint(originalEncodedCipher.getC2().toByteArray()));
|
||||
Pair<ECPoint,ECPoint> newCipher = elGamalPK.add(originalCipher, randomizer);
|
||||
|
||||
return Crypto.RerandomizableEncryptedMessage.newBuilder()
|
||||
.setData(
|
||||
ConcreteCrypto.ElGamalCiphertext.newBuilder()
|
||||
.setC1(ByteString.copyFrom(newCipher.a.getEncoded(true)))
|
||||
.setC2(ByteString.copyFrom(newCipher.b.getEncoded(true)))
|
||||
.build().toByteString()
|
||||
).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Crypto.EncryptionRandomness generateRandomness(Random rand) {
|
||||
BigInteger randomInt = new BigInteger(group.getCurveParams().getN().bitLength() - 1, rand);
|
||||
Crypto.EncryptionRandomness retval = Crypto.EncryptionRandomness.newBuilder()
|
||||
.setData(ByteString.copyFrom(BigIntegers.asUnsignedByteArray(randomInt))).build();
|
||||
|
||||
return retval;
|
||||
}
|
||||
}
|
|
@ -1,43 +1,43 @@
|
|||
package meerkat.crypto.concrete;
|
||||
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.security.Provider;
|
||||
import java.security.Security;
|
||||
|
||||
/**
|
||||
* A class that performs required crypto setup
|
||||
*/
|
||||
public class GlobalCryptoSetup {
|
||||
final static Logger logger = LoggerFactory.getLogger(GlobalCryptoSetup.class);
|
||||
|
||||
static boolean loadedBouncyCastle = false;
|
||||
static Provider bouncyCastleProvider;
|
||||
|
||||
public static boolean hasSecp256k1Curve() {
|
||||
// For now we just check if the java version is at least 8
|
||||
String[] version = System.getProperty("java.version").split("\\.");
|
||||
int major = Integer.parseInt(version[0]);
|
||||
int minor = Integer.parseInt(version[1]);
|
||||
return ((major > 1) || ((major > 0) && (minor > 7)));
|
||||
}
|
||||
|
||||
public static Provider getBouncyCastleProvider() { doSetup(); return bouncyCastleProvider; }
|
||||
|
||||
public static synchronized void doSetup() {
|
||||
if (bouncyCastleProvider == null) {
|
||||
bouncyCastleProvider = new BouncyCastleProvider();
|
||||
// Make bouncycastle our default provider if we're running on a JVM version < 8
|
||||
// (earlier version don't support the EC curve we use for signatures)
|
||||
if (!hasSecp256k1Curve() && !loadedBouncyCastle) {
|
||||
loadedBouncyCastle = true;
|
||||
Security.insertProviderAt(bouncyCastleProvider, 1);
|
||||
logger.info("Using BouncyCastle instead of native provider to support secp256k1 named curve");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public GlobalCryptoSetup() { doSetup(); }
|
||||
}
|
||||
package meerkat.destributed_key_generation.concrete;
|
||||
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.security.Provider;
|
||||
import java.security.Security;
|
||||
|
||||
/**
|
||||
* A class that performs required destributed_key_generation setup
|
||||
*/
|
||||
public class GlobalCryptoSetup {
|
||||
final static Logger logger = LoggerFactory.getLogger(GlobalCryptoSetup.class);
|
||||
|
||||
static boolean loadedBouncyCastle = false;
|
||||
static Provider bouncyCastleProvider;
|
||||
|
||||
public static boolean hasSecp256k1Curve() {
|
||||
// For now we just check if the java version is at least 8
|
||||
String[] version = System.getProperty("java.version").split("\\.");
|
||||
int major = Integer.parseInt(version[0]);
|
||||
int minor = Integer.parseInt(version[1]);
|
||||
return ((major > 1) || ((major > 0) && (minor > 7)));
|
||||
}
|
||||
|
||||
public static Provider getBouncyCastleProvider() { doSetup(); return bouncyCastleProvider; }
|
||||
|
||||
public static synchronized void doSetup() {
|
||||
if (bouncyCastleProvider == null) {
|
||||
bouncyCastleProvider = new BouncyCastleProvider();
|
||||
// Make bouncycastle our default provider if we're running on a JVM version < 8
|
||||
// (earlier version don't support the EC curve we use for signatures)
|
||||
if (!hasSecp256k1Curve() && !loadedBouncyCastle) {
|
||||
loadedBouncyCastle = true;
|
||||
Security.insertProviderAt(bouncyCastleProvider, 1);
|
||||
logger.info("Using BouncyCastle instead of native provider to support secp256k1 named curve");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public GlobalCryptoSetup() { doSetup(); }
|
||||
}
|
|
@ -1,96 +1,96 @@
|
|||
package meerkat.crypto.concrete;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.Message;
|
||||
import meerkat.crypto.Digest;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* Created by talm on 11/9/15.
|
||||
*/
|
||||
public class SHA256Digest extends GlobalCryptoSetup implements Digest {
|
||||
final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
public static final String SHA256 = "SHA-256";
|
||||
|
||||
MessageDigest hash;
|
||||
|
||||
/**
|
||||
* Used to convert length to bytes in proper order.
|
||||
*/
|
||||
ByteBuffer lenBuf = ByteBuffer.allocate(4);
|
||||
|
||||
/**
|
||||
* Instantiate with a specified algorithm.
|
||||
* @param algorithm
|
||||
* @throws NoSuchAlgorithmException
|
||||
*/
|
||||
public SHA256Digest(String algorithm) throws NoSuchAlgorithmException {
|
||||
hash = MessageDigest.getInstance(algorithm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate with the default (SHA-256) algorithm
|
||||
*/
|
||||
public SHA256Digest() { this(true); }
|
||||
|
||||
|
||||
/**SHA
|
||||
* Instantiate with the default (SHA-256) algorithm,
|
||||
* or create an empty class (for cloning)
|
||||
*/
|
||||
private SHA256Digest(boolean initHash) {
|
||||
if (initHash) {
|
||||
try {
|
||||
hash = MessageDigest.getInstance(SHA256);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// Should never happen!
|
||||
logger.error("Couldn't find default {} algorhtm: {}", SHA256, e);
|
||||
assert false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] digest() {
|
||||
return hash.digest();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Message msg) {
|
||||
|
||||
lenBuf.clear();
|
||||
lenBuf.putInt(msg.getSerializedSize());
|
||||
lenBuf.flip();
|
||||
hash.update(lenBuf);
|
||||
hash.update(msg.toByteString().asReadOnlyByteBuffer());
|
||||
}
|
||||
|
||||
final public void update(ByteString msg) {
|
||||
hash.update(msg.asReadOnlyByteBuffer());
|
||||
}
|
||||
|
||||
final public void update(byte[] msg) {
|
||||
hash.update(msg);
|
||||
}
|
||||
|
||||
final public void update(ByteBuffer msg) {
|
||||
hash.update(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
hash.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SHA256Digest clone() throws CloneNotSupportedException {
|
||||
SHA256Digest copy = new SHA256Digest(false);
|
||||
copy.hash = (MessageDigest) hash.clone();
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
package meerkat.destributed_key_generation.concrete;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.Message;
|
||||
import meerkat.destributed_key_generation.Digest;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* Created by talm on 11/9/15.
|
||||
*/
|
||||
public class SHA256Digest extends GlobalCryptoSetup implements Digest {
|
||||
final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
public static final String SHA256 = "SHA-256";
|
||||
|
||||
MessageDigest hash;
|
||||
|
||||
/**
|
||||
* Used to convert length to bytes in proper order.
|
||||
*/
|
||||
ByteBuffer lenBuf = ByteBuffer.allocate(4);
|
||||
|
||||
/**
|
||||
* Instantiate with a specified algorithm.
|
||||
* @param algorithm
|
||||
* @throws NoSuchAlgorithmException
|
||||
*/
|
||||
public SHA256Digest(String algorithm) throws NoSuchAlgorithmException {
|
||||
hash = MessageDigest.getInstance(algorithm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate with the default (SHA-256) algorithm
|
||||
*/
|
||||
public SHA256Digest() { this(true); }
|
||||
|
||||
|
||||
/**SHA
|
||||
* Instantiate with the default (SHA-256) algorithm,
|
||||
* or create an empty class (for cloning)
|
||||
*/
|
||||
private SHA256Digest(boolean initHash) {
|
||||
if (initHash) {
|
||||
try {
|
||||
hash = MessageDigest.getInstance(SHA256);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// Should never happen!
|
||||
logger.error("Couldn't find default {} algorhtm: {}", SHA256, e);
|
||||
assert false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] digest() {
|
||||
return hash.digest();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Message msg) {
|
||||
|
||||
lenBuf.clear();
|
||||
lenBuf.putInt(msg.getSerializedSize());
|
||||
lenBuf.flip();
|
||||
hash.update(lenBuf);
|
||||
hash.update(msg.toByteString().asReadOnlyByteBuffer());
|
||||
}
|
||||
|
||||
final public void update(ByteString msg) {
|
||||
hash.update(msg.asReadOnlyByteBuffer());
|
||||
}
|
||||
|
||||
final public void update(byte[] msg) {
|
||||
hash.update(msg);
|
||||
}
|
||||
|
||||
final public void update(ByteBuffer msg) {
|
||||
hash.update(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
hash.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SHA256Digest clone() throws CloneNotSupportedException {
|
||||
SHA256Digest copy = new SHA256Digest(false);
|
||||
copy.hash = (MessageDigest) hash.clone();
|
||||
return copy;
|
||||
}
|
||||
}
|
|
@ -1,18 +1,18 @@
|
|||
package meerkat.crypto.mixnet;
|
||||
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.protobuf.Mixing;
|
||||
|
||||
/**
|
||||
* Prove in zero knowledge that two ciphertexts are a mix of two original ciphertexts.
|
||||
*/
|
||||
public interface Mix2ZeroKnowledgeProver {
|
||||
public Mixing.ZeroKnowledgeProof prove(Crypto.RerandomizableEncryptedMessage in1,
|
||||
Crypto.RerandomizableEncryptedMessage in2,
|
||||
Crypto.RerandomizableEncryptedMessage out1,
|
||||
Crypto.RerandomizableEncryptedMessage out2,
|
||||
boolean switched,
|
||||
Crypto.EncryptionRandomness r1,
|
||||
Crypto.EncryptionRandomness r2);
|
||||
|
||||
}
|
||||
package meerkat.destributed_key_generation.mixnet;
|
||||
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.protobuf.Mixing;
|
||||
|
||||
/**
|
||||
* Prove in zero knowledge that two ciphertexts are a mix of two original ciphertexts.
|
||||
*/
|
||||
public interface Mix2ZeroKnowledgeProver {
|
||||
public Mixing.ZeroKnowledgeProof prove(Crypto.RerandomizableEncryptedMessage in1,
|
||||
Crypto.RerandomizableEncryptedMessage in2,
|
||||
Crypto.RerandomizableEncryptedMessage out1,
|
||||
Crypto.RerandomizableEncryptedMessage out2,
|
||||
boolean switched,
|
||||
Crypto.EncryptionRandomness r1,
|
||||
Crypto.EncryptionRandomness r2);
|
||||
|
||||
}
|
|
@ -1,23 +1,23 @@
|
|||
package meerkat.crypto.mixnet;
|
||||
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.protobuf.Mixing;
|
||||
|
||||
/**
|
||||
* Verify the two-ciphertext mix proof
|
||||
*/
|
||||
public interface Mix2ZeroKnowledgeVerifier {
|
||||
/**
|
||||
* Return true iff the proof is valid.
|
||||
* @param in1
|
||||
* @param in2
|
||||
* @param out1
|
||||
* @param out2
|
||||
* @return
|
||||
*/
|
||||
boolean verify(Crypto.RerandomizableEncryptedMessage in1,
|
||||
Crypto.RerandomizableEncryptedMessage in2,
|
||||
Crypto.RerandomizableEncryptedMessage out1,
|
||||
Crypto.RerandomizableEncryptedMessage out2,
|
||||
Mixing.ZeroKnowledgeProof proof);
|
||||
}
|
||||
package meerkat.destributed_key_generation.mixnet;
|
||||
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.protobuf.Mixing;
|
||||
|
||||
/**
|
||||
* Verify the two-ciphertext mix proof
|
||||
*/
|
||||
public interface Mix2ZeroKnowledgeVerifier {
|
||||
/**
|
||||
* Return true iff the proof is valid.
|
||||
* @param in1
|
||||
* @param in2
|
||||
* @param out1
|
||||
* @param out2
|
||||
* @return
|
||||
*/
|
||||
boolean verify(Crypto.RerandomizableEncryptedMessage in1,
|
||||
Crypto.RerandomizableEncryptedMessage in2,
|
||||
Crypto.RerandomizableEncryptedMessage out1,
|
||||
Crypto.RerandomizableEncryptedMessage out2,
|
||||
Mixing.ZeroKnowledgeProof proof);
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
package meerkat.crypto.mixnet;
|
||||
|
||||
import java.util.List;
|
||||
import static meerkat.protobuf.Voting.*;
|
||||
|
||||
/**
|
||||
* Created by talm on 25/10/15.
|
||||
*/
|
||||
public interface Mixer {
|
||||
public List<EncryptedBallot> mix(List<EncryptedBallot> ballots);
|
||||
}
|
||||
package meerkat.destributed_key_generation.mixnet;
|
||||
|
||||
import java.util.List;
|
||||
import static meerkat.protobuf.Voting.*;
|
||||
|
||||
/**
|
||||
* Created by talm on 25/10/15.
|
||||
*/
|
||||
public interface Mixer {
|
||||
public List<EncryptedBallot> mix(List<EncryptedBallot> ballots);
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package meerkat.crypto.mixnet;
|
||||
|
||||
/**
|
||||
* Created by talm on 25/10/15.
|
||||
*/
|
||||
public class Trustee {
|
||||
}
|
||||
package meerkat.destributed_key_generation.mixnet;
|
||||
|
||||
/**
|
||||
* Created by talm on 25/10/15.
|
||||
*/
|
||||
public class Trustee {
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package meerkat.crypto.mixnet;
|
||||
|
||||
/**
|
||||
* Created by talm on 25/10/15.
|
||||
*/
|
||||
public class Verifier {
|
||||
}
|
||||
package meerkat.destributed_key_generation.mixnet;
|
||||
|
||||
/**
|
||||
* Created by talm on 25/10/15.
|
||||
*/
|
||||
public class Verifier {
|
||||
}
|
|
@ -1,50 +1,49 @@
|
|||
package meerkat.crypto.concrete;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.Message;
|
||||
|
||||
import meerkat.crypto.concrete.ECDSASignature;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Created by talm on 12/11/15.
|
||||
*/
|
||||
public class ECDSADeterministicSignatureTest extends ECDSASignatureTest {
|
||||
|
||||
@Override
|
||||
protected ECDSASignature getSigner() { return new ECDSADeterministicSignature(); }
|
||||
|
||||
|
||||
/**
|
||||
* Make sure signatures don't vary
|
||||
*/
|
||||
@Test
|
||||
public void testDeterministicSigning() throws Exception {
|
||||
loadSigningKeys();
|
||||
|
||||
|
||||
for (int i = 0; i < REPEAT_COUNT; ++i) {
|
||||
BigInteger rawMsg = new BigInteger(50, rand);
|
||||
Message msg = Crypto.BigInteger.newBuilder()
|
||||
.setData(ByteString.copyFrom(rawMsg.toByteArray())).build();
|
||||
Crypto.Signature[] sigs = new Crypto.Signature[REPEAT_COUNT];
|
||||
|
||||
signer.updateContent(msg);
|
||||
sigs[0] = signer.sign();
|
||||
byte[] canonicalSig = sigs[0].toByteArray();
|
||||
|
||||
for (int j = 1; j < sigs.length; ++j) {
|
||||
signer.updateContent(msg);
|
||||
sigs[j] = signer.sign();
|
||||
|
||||
byte[] newSig = sigs[j].toByteArray();
|
||||
|
||||
assertArrayEquals("Signatures on same message differ (i="+i+",j="+j+")", canonicalSig, newSig);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
package meerkat.destributed_key_generation.concrete;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.Message;
|
||||
|
||||
import meerkat.protobuf.Crypto;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Created by talm on 12/11/15.
|
||||
*/
|
||||
public class ECDSADeterministicSignatureTest extends ECDSASignatureTest {
|
||||
|
||||
@Override
|
||||
protected ECDSASignature getSigner() { return new ECDSADeterministicSignature(); }
|
||||
|
||||
|
||||
/**
|
||||
* Make sure signatures don't vary
|
||||
*/
|
||||
@Test
|
||||
public void testDeterministicSigning() throws Exception {
|
||||
loadSigningKeys();
|
||||
|
||||
|
||||
for (int i = 0; i < REPEAT_COUNT; ++i) {
|
||||
BigInteger rawMsg = new BigInteger(50, rand);
|
||||
Message msg = Crypto.BigInteger.newBuilder()
|
||||
.setData(ByteString.copyFrom(rawMsg.toByteArray())).build();
|
||||
Crypto.Signature[] sigs = new Crypto.Signature[REPEAT_COUNT];
|
||||
|
||||
signer.updateContent(msg);
|
||||
sigs[0] = signer.sign();
|
||||
byte[] canonicalSig = sigs[0].toByteArray();
|
||||
|
||||
for (int j = 1; j < sigs.length; ++j) {
|
||||
signer.updateContent(msg);
|
||||
sigs[j] = signer.sign();
|
||||
|
||||
byte[] newSig = sigs[j].toByteArray();
|
||||
|
||||
assertArrayEquals("Signatures on same message differ (i="+i+",j="+j+")", canonicalSig, newSig);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,220 +1,219 @@
|
|||
package meerkat.crypto.concrete;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.Message;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.crypto.concrete.ECDSASignature;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.security.KeyStore;
|
||||
import java.util.Random;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Created by talm on 12/11/15.
|
||||
*/
|
||||
public class ECDSASignatureTest {
|
||||
public static String KEYFILE_EXAMPLE = "/certs/enduser-certs/user1-key-with-password-secret.p12";
|
||||
public static String KEYFILE_PASSWORD = "secret";
|
||||
|
||||
public static String CERT1_PEM_EXAMPLE = "/certs/enduser-certs/user1.crt";
|
||||
public static String CERT2_DER_EXAMPLE = "/certs/enduser-certs/user2.der";
|
||||
|
||||
public static String MSG_PLAINTEXT_EXAMPLE = "/certs/signed-messages/helloworld.txt";
|
||||
public static String MSG_SIG_EXAMPLE = "/certs/signed-messages/helloworld.txt.sha256sig";
|
||||
|
||||
public static String HELLO_WORLD = "hello world!";
|
||||
|
||||
public final static int REPEAT_COUNT = 10;
|
||||
|
||||
Random rand = new Random(0);
|
||||
|
||||
protected ECDSASignature signer;
|
||||
|
||||
protected ECDSASignature getSigner() { return new ECDSASignature(); }
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
signer = getSigner();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadSignatureKey() throws Exception {
|
||||
InputStream keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE);
|
||||
char[] password = KEYFILE_PASSWORD.toCharArray();
|
||||
|
||||
KeyStore.Builder keyStore = signer.getPKCS12KeyStoreBuilder(keyStream, password);
|
||||
signer.loadSigningCertificate(keyStore);
|
||||
keyStream.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadPEMVerificationKey() throws Exception {
|
||||
InputStream certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE);
|
||||
|
||||
signer.loadVerificationCertificates(certStream);
|
||||
certStream.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadDERVerificationKey() throws Exception {
|
||||
InputStream certStream = getClass().getResourceAsStream(CERT2_DER_EXAMPLE);
|
||||
|
||||
signer.loadVerificationCertificates(certStream);
|
||||
certStream.close();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void verifyValidSig() throws Exception {
|
||||
InputStream certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE);
|
||||
InputStream msgStream = getClass().getResourceAsStream(MSG_PLAINTEXT_EXAMPLE);
|
||||
InputStream sigStream = getClass().getResourceAsStream(MSG_SIG_EXAMPLE);
|
||||
|
||||
signer.loadVerificationCertificates(certStream);
|
||||
certStream.close();
|
||||
|
||||
Crypto.Signature.Builder sig = Crypto.Signature.newBuilder();
|
||||
sig.setType(Crypto.SignatureType.ECDSA);
|
||||
sig.setSignerId(signer.loadedCertificates.entrySet().iterator().next().getKey());
|
||||
sig.setData(ByteString.readFrom(sigStream));
|
||||
|
||||
Crypto.Signature builtSig = sig.build();
|
||||
signer.initVerify(builtSig);
|
||||
signer.updateContent(msgStream);
|
||||
assertTrue("Signature did not verify!", signer.verify());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyInvalidSig() throws Exception {
|
||||
InputStream certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE);
|
||||
InputStream msgStream = getClass().getResourceAsStream(MSG_PLAINTEXT_EXAMPLE);
|
||||
InputStream sigStream = getClass().getResourceAsStream(MSG_SIG_EXAMPLE);
|
||||
|
||||
signer.loadVerificationCertificates(certStream);
|
||||
certStream.close();
|
||||
|
||||
Crypto.Signature.Builder sig = Crypto.Signature.newBuilder();
|
||||
sig.setType(Crypto.SignatureType.ECDSA);
|
||||
sig.setSignerId(signer.loadedCertificates.entrySet().iterator().next().getKey());
|
||||
byte[] sigData = ByteString.readFrom(sigStream).toByteArray();
|
||||
++sigData[0];
|
||||
|
||||
sig.setData(ByteString.copyFrom(sigData));
|
||||
|
||||
|
||||
Crypto.Signature builtSig = sig.build();
|
||||
signer.initVerify(builtSig);
|
||||
signer.updateContent(msgStream);
|
||||
assertFalse("Bad Signature passed verification!", signer.verify());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void verifyInvalidMsg() throws Exception {
|
||||
InputStream certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE);
|
||||
InputStream msgStream = getClass().getResourceAsStream(MSG_PLAINTEXT_EXAMPLE);
|
||||
InputStream sigStream = getClass().getResourceAsStream(MSG_SIG_EXAMPLE);
|
||||
|
||||
signer.loadVerificationCertificates(certStream);
|
||||
certStream.close();
|
||||
|
||||
Crypto.Signature.Builder sig = Crypto.Signature.newBuilder();
|
||||
sig.setType(Crypto.SignatureType.ECDSA);
|
||||
sig.setSignerId(signer.loadedCertificates.entrySet().iterator().next().getKey());
|
||||
sig.setData(ByteString.readFrom(sigStream));
|
||||
byte[] msgData = ByteString.readFrom(msgStream).toByteArray();
|
||||
++msgData[0];
|
||||
|
||||
Crypto.Signature builtSig = sig.build();
|
||||
signer.initVerify(builtSig);
|
||||
signer.updateContent(msgStream);
|
||||
assertFalse("Signature doesn't match message but passed verification!", signer.verify());
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected void loadSigningKeys() throws Exception {
|
||||
InputStream keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE);
|
||||
char[] password = KEYFILE_PASSWORD.toCharArray();
|
||||
|
||||
KeyStore.Builder keyStore = signer.getPKCS12KeyStoreBuilder(keyStream, password);
|
||||
signer.loadSigningCertificate(keyStore);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void signAndVerify() throws Exception {
|
||||
loadSigningKeys();
|
||||
|
||||
BigInteger rawMsg = new BigInteger(50, rand);
|
||||
Crypto.BigInteger usMsg = Crypto.BigInteger.newBuilder()
|
||||
.setData(ByteString.copyFrom(rawMsg.toByteArray())).build();
|
||||
|
||||
signer.updateContent(usMsg);
|
||||
Crypto.Signature sig = signer.sign();
|
||||
|
||||
signer.loadVerificationCertificates(getClass().getResourceAsStream(CERT1_PEM_EXAMPLE));
|
||||
|
||||
signer.initVerify(sig);
|
||||
signer.updateContent(usMsg);
|
||||
assertTrue("Couldn't verify signature on ", signer.verify());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void signMultipleAndVerify() throws Exception {
|
||||
loadSigningKeys();
|
||||
|
||||
Message[] msgs = new Message[REPEAT_COUNT];
|
||||
for (int i = 0; i < msgs.length; ++i) {
|
||||
|
||||
BigInteger rawMsg = new BigInteger(50, rand);
|
||||
msgs[i] = Crypto.BigInteger.newBuilder()
|
||||
.setData(ByteString.copyFrom(rawMsg.toByteArray())).build();
|
||||
signer.updateContent(msgs[i]);
|
||||
}
|
||||
|
||||
Crypto.Signature sig = signer.sign();
|
||||
|
||||
signer.loadVerificationCertificates(getClass().getResourceAsStream(CERT1_PEM_EXAMPLE));
|
||||
|
||||
signer.initVerify(sig);
|
||||
for (int i = 0; i < msgs.length; ++i) {
|
||||
signer.updateContent(msgs[i]);
|
||||
}
|
||||
assertTrue("Couldn't verify signature on ", signer.verify());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleSignAndVerify() throws Exception {
|
||||
loadSigningKeys();
|
||||
|
||||
Message[] msgs = new Message[REPEAT_COUNT];
|
||||
Crypto.Signature[] sigs = new Crypto.Signature[REPEAT_COUNT];
|
||||
for (int i = 0; i < msgs.length; ++i) {
|
||||
BigInteger rawMsg = new BigInteger(50, rand);
|
||||
msgs[i] = Crypto.BigInteger.newBuilder()
|
||||
.setData(ByteString.copyFrom(rawMsg.toByteArray())).build();
|
||||
signer.updateContent(msgs[i]);
|
||||
sigs[i] = signer.sign();
|
||||
}
|
||||
|
||||
signer.loadVerificationCertificates(getClass().getResourceAsStream(CERT1_PEM_EXAMPLE));
|
||||
|
||||
|
||||
for (int i = 0; i < msgs.length; ++i) {
|
||||
signer.initVerify(sigs[i]);
|
||||
signer.updateContent(msgs[i]);
|
||||
assertTrue("Couldn't verify signature on ", signer.verify());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
package meerkat.destributed_key_generation.concrete;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.Message;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.security.KeyStore;
|
||||
import java.util.Random;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Created by talm on 12/11/15.
|
||||
*/
|
||||
public class ECDSASignatureTest {
|
||||
public static String KEYFILE_EXAMPLE = "/certs/enduser-certs/user1-key-with-password-secret.p12";
|
||||
public static String KEYFILE_PASSWORD = "secret";
|
||||
|
||||
public static String CERT1_PEM_EXAMPLE = "/certs/enduser-certs/user1.crt";
|
||||
public static String CERT2_DER_EXAMPLE = "/certs/enduser-certs/user2.der";
|
||||
|
||||
public static String MSG_PLAINTEXT_EXAMPLE = "/certs/signed-messages/helloworld.txt";
|
||||
public static String MSG_SIG_EXAMPLE = "/certs/signed-messages/helloworld.txt.sha256sig";
|
||||
|
||||
public static String HELLO_WORLD = "hello world!";
|
||||
|
||||
public final static int REPEAT_COUNT = 10;
|
||||
|
||||
Random rand = new Random(0);
|
||||
|
||||
protected ECDSASignature signer;
|
||||
|
||||
protected ECDSASignature getSigner() { return new ECDSASignature(); }
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
signer = getSigner();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadSignatureKey() throws Exception {
|
||||
InputStream keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE);
|
||||
char[] password = KEYFILE_PASSWORD.toCharArray();
|
||||
|
||||
KeyStore.Builder keyStore = signer.getPKCS12KeyStoreBuilder(keyStream, password);
|
||||
signer.loadSigningCertificate(keyStore);
|
||||
keyStream.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadPEMVerificationKey() throws Exception {
|
||||
InputStream certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE);
|
||||
|
||||
signer.loadVerificationCertificates(certStream);
|
||||
certStream.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadDERVerificationKey() throws Exception {
|
||||
InputStream certStream = getClass().getResourceAsStream(CERT2_DER_EXAMPLE);
|
||||
|
||||
signer.loadVerificationCertificates(certStream);
|
||||
certStream.close();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void verifyValidSig() throws Exception {
|
||||
InputStream certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE);
|
||||
InputStream msgStream = getClass().getResourceAsStream(MSG_PLAINTEXT_EXAMPLE);
|
||||
InputStream sigStream = getClass().getResourceAsStream(MSG_SIG_EXAMPLE);
|
||||
|
||||
signer.loadVerificationCertificates(certStream);
|
||||
certStream.close();
|
||||
|
||||
Crypto.Signature.Builder sig = Crypto.Signature.newBuilder();
|
||||
sig.setType(Crypto.SignatureType.ECDSA);
|
||||
sig.setSignerId(signer.loadedCertificates.entrySet().iterator().next().getKey());
|
||||
sig.setData(ByteString.readFrom(sigStream));
|
||||
|
||||
Crypto.Signature builtSig = sig.build();
|
||||
signer.initVerify(builtSig);
|
||||
signer.updateContent(msgStream);
|
||||
assertTrue("Signature did not verify!", signer.verify());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void verifyInvalidSig() throws Exception {
|
||||
InputStream certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE);
|
||||
InputStream msgStream = getClass().getResourceAsStream(MSG_PLAINTEXT_EXAMPLE);
|
||||
InputStream sigStream = getClass().getResourceAsStream(MSG_SIG_EXAMPLE);
|
||||
|
||||
signer.loadVerificationCertificates(certStream);
|
||||
certStream.close();
|
||||
|
||||
Crypto.Signature.Builder sig = Crypto.Signature.newBuilder();
|
||||
sig.setType(Crypto.SignatureType.ECDSA);
|
||||
sig.setSignerId(signer.loadedCertificates.entrySet().iterator().next().getKey());
|
||||
byte[] sigData = ByteString.readFrom(sigStream).toByteArray();
|
||||
++sigData[0];
|
||||
|
||||
sig.setData(ByteString.copyFrom(sigData));
|
||||
|
||||
|
||||
Crypto.Signature builtSig = sig.build();
|
||||
signer.initVerify(builtSig);
|
||||
signer.updateContent(msgStream);
|
||||
assertFalse("Bad Signature passed verification!", signer.verify());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void verifyInvalidMsg() throws Exception {
|
||||
InputStream certStream = getClass().getResourceAsStream(CERT1_PEM_EXAMPLE);
|
||||
InputStream msgStream = getClass().getResourceAsStream(MSG_PLAINTEXT_EXAMPLE);
|
||||
InputStream sigStream = getClass().getResourceAsStream(MSG_SIG_EXAMPLE);
|
||||
|
||||
signer.loadVerificationCertificates(certStream);
|
||||
certStream.close();
|
||||
|
||||
Crypto.Signature.Builder sig = Crypto.Signature.newBuilder();
|
||||
sig.setType(Crypto.SignatureType.ECDSA);
|
||||
sig.setSignerId(signer.loadedCertificates.entrySet().iterator().next().getKey());
|
||||
sig.setData(ByteString.readFrom(sigStream));
|
||||
byte[] msgData = ByteString.readFrom(msgStream).toByteArray();
|
||||
++msgData[0];
|
||||
|
||||
Crypto.Signature builtSig = sig.build();
|
||||
signer.initVerify(builtSig);
|
||||
signer.updateContent(msgStream);
|
||||
assertFalse("Signature doesn't match message but passed verification!", signer.verify());
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected void loadSigningKeys() throws Exception {
|
||||
InputStream keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE);
|
||||
char[] password = KEYFILE_PASSWORD.toCharArray();
|
||||
|
||||
KeyStore.Builder keyStore = signer.getPKCS12KeyStoreBuilder(keyStream, password);
|
||||
signer.loadSigningCertificate(keyStore);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void signAndVerify() throws Exception {
|
||||
loadSigningKeys();
|
||||
|
||||
BigInteger rawMsg = new BigInteger(50, rand);
|
||||
Crypto.BigInteger usMsg = Crypto.BigInteger.newBuilder()
|
||||
.setData(ByteString.copyFrom(rawMsg.toByteArray())).build();
|
||||
|
||||
signer.updateContent(usMsg);
|
||||
Crypto.Signature sig = signer.sign();
|
||||
|
||||
signer.loadVerificationCertificates(getClass().getResourceAsStream(CERT1_PEM_EXAMPLE));
|
||||
|
||||
signer.initVerify(sig);
|
||||
signer.updateContent(usMsg);
|
||||
assertTrue("Couldn't verify signature on ", signer.verify());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void signMultipleAndVerify() throws Exception {
|
||||
loadSigningKeys();
|
||||
|
||||
Message[] msgs = new Message[REPEAT_COUNT];
|
||||
for (int i = 0; i < msgs.length; ++i) {
|
||||
|
||||
BigInteger rawMsg = new BigInteger(50, rand);
|
||||
msgs[i] = Crypto.BigInteger.newBuilder()
|
||||
.setData(ByteString.copyFrom(rawMsg.toByteArray())).build();
|
||||
signer.updateContent(msgs[i]);
|
||||
}
|
||||
|
||||
Crypto.Signature sig = signer.sign();
|
||||
|
||||
signer.loadVerificationCertificates(getClass().getResourceAsStream(CERT1_PEM_EXAMPLE));
|
||||
|
||||
signer.initVerify(sig);
|
||||
for (int i = 0; i < msgs.length; ++i) {
|
||||
signer.updateContent(msgs[i]);
|
||||
}
|
||||
assertTrue("Couldn't verify signature on ", signer.verify());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleSignAndVerify() throws Exception {
|
||||
loadSigningKeys();
|
||||
|
||||
Message[] msgs = new Message[REPEAT_COUNT];
|
||||
Crypto.Signature[] sigs = new Crypto.Signature[REPEAT_COUNT];
|
||||
for (int i = 0; i < msgs.length; ++i) {
|
||||
BigInteger rawMsg = new BigInteger(50, rand);
|
||||
msgs[i] = Crypto.BigInteger.newBuilder()
|
||||
.setData(ByteString.copyFrom(rawMsg.toByteArray())).build();
|
||||
signer.updateContent(msgs[i]);
|
||||
sigs[i] = signer.sign();
|
||||
}
|
||||
|
||||
signer.loadVerificationCertificates(getClass().getResourceAsStream(CERT1_PEM_EXAMPLE));
|
||||
|
||||
|
||||
for (int i = 0; i < msgs.length; ++i) {
|
||||
signer.initVerify(sigs[i]);
|
||||
signer.updateContent(msgs[i]);
|
||||
assertTrue("Couldn't verify signature on ", signer.verify());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -1,122 +1,122 @@
|
|||
package meerkat.crypto.concrete;
|
||||
|
||||
import meerkat.protobuf.ConcreteCrypto;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.protobuf.Voting;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.factcenter.qilin.primitives.concrete.ECElGamal;
|
||||
import org.factcenter.qilin.primitives.concrete.ECGroup;
|
||||
import org.factcenter.qilin.util.Pair;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Random;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Test class for {@link ECElGamalEncryption}
|
||||
*/
|
||||
public class ECElGamalEncryptionTest {
|
||||
final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
/**
|
||||
* Number of times to repeat probabilistic tests.
|
||||
*/
|
||||
public final static int CONFIDENCE = 10;
|
||||
|
||||
Random rand = new Random(0); // Insecure deterministic random for testing.
|
||||
|
||||
ECElGamal.SK key;
|
||||
ECGroup group;
|
||||
ECElGamalEncryption enc;
|
||||
ConcreteCrypto.ElGamalPublicKey serializedPk;
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
group = new ECGroup("secp256k1");
|
||||
BigInteger sk = ECElGamal.generateSecretKey(group, rand);
|
||||
key = new ECElGamal.SK(group, sk);
|
||||
serializedPk = ECElGamalUtils.serializePk(group, key);
|
||||
|
||||
|
||||
enc = new ECElGamalEncryption();
|
||||
|
||||
enc.init(serializedPk);
|
||||
}
|
||||
|
||||
|
||||
Voting.PlaintextBallot genRandomBallot(int numQuestions, int numAnswers, int maxAnswer) {
|
||||
Voting.PlaintextBallot.Builder ballot = Voting.PlaintextBallot.newBuilder();
|
||||
ballot.setSerialNumber(rand.nextInt(1000000));
|
||||
for (int i = 0; i < numQuestions; ++i) {
|
||||
Voting.BallotAnswer.Builder answers = ballot.addAnswersBuilder();
|
||||
for (int j = 0; j < numAnswers; ++j) {
|
||||
answers.addAnswer(rand.nextInt(maxAnswer));
|
||||
}
|
||||
}
|
||||
return ballot.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Testing just the key management
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testPkSerialization() throws Exception {
|
||||
ECElGamal.PK pk = enc.getElGamalPK();
|
||||
|
||||
ECPoint point = enc.getGroup().sample(rand);
|
||||
Pair<ECPoint, ECPoint> cipher = pk.encrypt(point, pk.getRandom(rand));
|
||||
|
||||
ECPoint decrypted = key.decrypt(cipher);
|
||||
|
||||
assertEquals("Decrypted value not equal to encrypted value!", point, decrypted);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncryption() throws Exception {
|
||||
for (int i = 0; i < CONFIDENCE; ++i) {
|
||||
Voting.PlaintextBallot msg = genRandomBallot(2,3,16); // 2 questions with 3 answers each, in range 0-15.
|
||||
if (msg.getSerializedSize() > enc.getGroup().getInjectiveEncodeMsgLength()) {
|
||||
logger.error("Test Message too big (|msg|={} > max={}), expect failure.",
|
||||
msg.getSerializedSize(), enc.getGroup().getInjectiveEncodeMsgLength());
|
||||
}
|
||||
|
||||
Crypto.RerandomizableEncryptedMessage cipherText = enc.encrypt(msg, enc.generateRandomness(rand));
|
||||
|
||||
Voting.PlaintextBallot decrypted = ECElGamalUtils.decrypt(Voting.PlaintextBallot.class, key, group, cipherText);
|
||||
|
||||
assertEquals("Decrypted value differs from encrypted value (i="+i+")!", msg, decrypted);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRerandomizeModifiesCiphertext() throws Exception {
|
||||
Voting.PlaintextBallot msg = genRandomBallot(2,3,16); // 2 questions with 3 answers each, in range 0-15.
|
||||
Crypto.RerandomizableEncryptedMessage cipher1 = enc.encrypt(msg, enc.generateRandomness(rand));
|
||||
Crypto.RerandomizableEncryptedMessage cipher2 = enc.rerandomize(cipher1, enc.generateRandomness(rand));
|
||||
assertNotEquals("Rerandomized cipher identical to original!", cipher1, cipher2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRerandomizePreservesPlaintext() throws Exception {
|
||||
for (int i = 0; i < CONFIDENCE; ++i) {
|
||||
Voting.PlaintextBallot msg = genRandomBallot(2,3,16); // 2 questions with 3 answers each, in range 0-15.
|
||||
|
||||
Crypto.RerandomizableEncryptedMessage cipher = enc.encrypt(msg, enc.generateRandomness(rand));
|
||||
Crypto.RerandomizableEncryptedMessage cipher2 = cipher;
|
||||
for (int j = 0; j < CONFIDENCE; ++j)
|
||||
cipher2 = enc.rerandomize(cipher2, enc.generateRandomness(rand));
|
||||
|
||||
Voting.PlaintextBallot decrypted = ECElGamalUtils.decrypt(Voting.PlaintextBallot.class, key, group,
|
||||
cipher2);
|
||||
|
||||
assertEquals("Decrypted value differs from original encrypted value (i="+i+")!", msg, decrypted);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
package meerkat.destributed_key_generation.concrete;
|
||||
|
||||
import meerkat.protobuf.ConcreteCrypto;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import meerkat.protobuf.Voting;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.factcenter.qilin.primitives.concrete.ECElGamal;
|
||||
import org.factcenter.qilin.primitives.concrete.ECGroup;
|
||||
import org.factcenter.qilin.util.Pair;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Random;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Test class for {@link ECElGamalEncryption}
|
||||
*/
|
||||
public class ECElGamalEncryptionTest {
|
||||
final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
/**
|
||||
* Number of times to repeat probabilistic tests.
|
||||
*/
|
||||
public final static int CONFIDENCE = 10;
|
||||
|
||||
Random rand = new Random(0); // Insecure deterministic random for testing.
|
||||
|
||||
ECElGamal.SK key;
|
||||
ECGroup group;
|
||||
ECElGamalEncryption enc;
|
||||
ConcreteCrypto.ElGamalPublicKey serializedPk;
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
group = new ECGroup("secp256k1");
|
||||
BigInteger sk = ECElGamal.generateSecretKey(group, rand);
|
||||
key = new ECElGamal.SK(group, sk);
|
||||
serializedPk = ECElGamalUtils.serializePk(group, key);
|
||||
|
||||
|
||||
enc = new ECElGamalEncryption();
|
||||
|
||||
enc.init(serializedPk);
|
||||
}
|
||||
|
||||
|
||||
Voting.PlaintextBallot genRandomBallot(int numQuestions, int numAnswers, int maxAnswer) {
|
||||
Voting.PlaintextBallot.Builder ballot = Voting.PlaintextBallot.newBuilder();
|
||||
ballot.setSerialNumber(rand.nextInt(1000000));
|
||||
for (int i = 0; i < numQuestions; ++i) {
|
||||
Voting.BallotAnswer.Builder answers = ballot.addAnswersBuilder();
|
||||
for (int j = 0; j < numAnswers; ++j) {
|
||||
answers.addAnswer(rand.nextInt(maxAnswer));
|
||||
}
|
||||
}
|
||||
return ballot.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Testing just the key management
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testPkSerialization() throws Exception {
|
||||
ECElGamal.PK pk = enc.getElGamalPK();
|
||||
|
||||
ECPoint point = enc.getGroup().sample(rand);
|
||||
Pair<ECPoint, ECPoint> cipher = pk.encrypt(point, pk.getRandom(rand));
|
||||
|
||||
ECPoint decrypted = key.decrypt(cipher);
|
||||
|
||||
assertEquals("Decrypted value not equal to encrypted value!", point, decrypted);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncryption() throws Exception {
|
||||
for (int i = 0; i < CONFIDENCE; ++i) {
|
||||
Voting.PlaintextBallot msg = genRandomBallot(2,3,16); // 2 questions with 3 answers each, in range 0-15.
|
||||
if (msg.getSerializedSize() > enc.getGroup().getInjectiveEncodeMsgLength()) {
|
||||
logger.error("Test Message too big (|msg|={} > max={}), expect failure.",
|
||||
msg.getSerializedSize(), enc.getGroup().getInjectiveEncodeMsgLength());
|
||||
}
|
||||
|
||||
Crypto.RerandomizableEncryptedMessage cipherText = enc.encrypt(msg, enc.generateRandomness(rand));
|
||||
|
||||
Voting.PlaintextBallot decrypted = ECElGamalUtils.decrypt(Voting.PlaintextBallot.class, key, group, cipherText);
|
||||
|
||||
assertEquals("Decrypted value differs from encrypted value (i="+i+")!", msg, decrypted);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRerandomizeModifiesCiphertext() throws Exception {
|
||||
Voting.PlaintextBallot msg = genRandomBallot(2,3,16); // 2 questions with 3 answers each, in range 0-15.
|
||||
Crypto.RerandomizableEncryptedMessage cipher1 = enc.encrypt(msg, enc.generateRandomness(rand));
|
||||
Crypto.RerandomizableEncryptedMessage cipher2 = enc.rerandomize(cipher1, enc.generateRandomness(rand));
|
||||
assertNotEquals("Rerandomized cipher identical to original!", cipher1, cipher2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRerandomizePreservesPlaintext() throws Exception {
|
||||
for (int i = 0; i < CONFIDENCE; ++i) {
|
||||
Voting.PlaintextBallot msg = genRandomBallot(2,3,16); // 2 questions with 3 answers each, in range 0-15.
|
||||
|
||||
Crypto.RerandomizableEncryptedMessage cipher = enc.encrypt(msg, enc.generateRandomness(rand));
|
||||
Crypto.RerandomizableEncryptedMessage cipher2 = cipher;
|
||||
for (int j = 0; j < CONFIDENCE; ++j)
|
||||
cipher2 = enc.rerandomize(cipher2, enc.generateRandomness(rand));
|
||||
|
||||
Voting.PlaintextBallot decrypted = ECElGamalUtils.decrypt(Voting.PlaintextBallot.class, key, group,
|
||||
cipher2);
|
||||
|
||||
assertEquals("Decrypted value differs from original encrypted value (i="+i+")!", msg, decrypted);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,89 +1,89 @@
|
|||
package meerkat.crypto.concrete;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.GeneratedMessage;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.google.protobuf.Message;
|
||||
import meerkat.protobuf.ConcreteCrypto;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import org.bouncycastle.jce.spec.ECParameterSpec;
|
||||
import org.bouncycastle.jce.spec.ECPublicKeySpec;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.factcenter.qilin.primitives.concrete.ECElGamal;
|
||||
import org.factcenter.qilin.primitives.concrete.ECGroup;
|
||||
import org.factcenter.qilin.primitives.generic.ElGamal;
|
||||
import org.factcenter.qilin.util.Pair;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PublicKey;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
|
||||
/**
|
||||
* utilities for ECElgamal
|
||||
*/
|
||||
public class ECElGamalUtils {
|
||||
final static Logger logger = LoggerFactory.getLogger(ECElGamalUtils.class);
|
||||
|
||||
public final static String ENCRYPTION_KEY_ALGORITHM = "ECDH";
|
||||
|
||||
/**
|
||||
* Serialize an El-Gamal public key into a form acceptable by {@link ECElGamalEncryption}
|
||||
* @param pk
|
||||
* @return
|
||||
*/
|
||||
public static ConcreteCrypto.ElGamalPublicKey serializePk(ECGroup group, ElGamal.PK<ECPoint> pk) {
|
||||
ECPoint pkPoint = pk.getPK();
|
||||
ECParameterSpec params = group.getCurveParams();
|
||||
|
||||
ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(pkPoint, params);
|
||||
|
||||
try {
|
||||
KeyFactory fact = KeyFactory.getInstance(ENCRYPTION_KEY_ALGORITHM,
|
||||
GlobalCryptoSetup.getBouncyCastleProvider());
|
||||
PublicKey javaPk = fact.generatePublic(pubKeySpec);
|
||||
ConcreteCrypto.ElGamalPublicKey serializedPk = ConcreteCrypto.ElGamalPublicKey.newBuilder()
|
||||
.setSubjectPublicKeyInfo(ByteString.copyFrom(javaPk.getEncoded())).build();
|
||||
|
||||
return serializedPk;
|
||||
} catch (NoSuchAlgorithmException|InvalidKeySpecException e) {
|
||||
logger.error("Should never happen!", e);
|
||||
throw new RuntimeException("Error converting public key!", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard (non-threshold) decryption for testing purposes.
|
||||
* @param secretKey
|
||||
* @return
|
||||
*/
|
||||
public static <T extends Message> T decrypt(Class<T> plaintextMessageType, ECElGamal.SK secretKey, ECGroup group, Crypto.RerandomizableEncryptedMessage opaqueCipher)
|
||||
throws InvalidProtocolBufferException {
|
||||
ConcreteCrypto.ElGamalCiphertext cipherText = ConcreteCrypto.ElGamalCiphertext.parseFrom(opaqueCipher.getData());
|
||||
ByteString c1encoded = cipherText.getC1();
|
||||
ByteString c2encoded = cipherText.getC2();
|
||||
|
||||
ECPoint c1 = group.decode(c1encoded.toByteArray());
|
||||
ECPoint c2 = group.decode(c2encoded.toByteArray());
|
||||
|
||||
ECPoint plaintextEncoded = secretKey.decrypt(new Pair<ECPoint, ECPoint>(c1, c2));
|
||||
|
||||
byte[] plaintext = group.injectiveDecode(plaintextEncoded);
|
||||
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(plaintext);
|
||||
|
||||
try {
|
||||
java.lang.reflect.Method newBuilder = plaintextMessageType.getMethod("newBuilder");
|
||||
GeneratedMessage.Builder<?> builder = (GeneratedMessage.Builder<?>) newBuilder.invoke(plaintextMessageType);
|
||||
builder.mergeDelimitedFrom(in);
|
||||
return plaintextMessageType.cast(builder.build());
|
||||
} catch (Exception e) {
|
||||
logger.error("Error parsing incoming message", e);
|
||||
throw new InvalidProtocolBufferException("Plaintext protobuf error");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package meerkat.destributed_key_generation.concrete;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.GeneratedMessage;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.google.protobuf.Message;
|
||||
import meerkat.protobuf.ConcreteCrypto;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import org.bouncycastle.jce.spec.ECParameterSpec;
|
||||
import org.bouncycastle.jce.spec.ECPublicKeySpec;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.factcenter.qilin.primitives.concrete.ECElGamal;
|
||||
import org.factcenter.qilin.primitives.concrete.ECGroup;
|
||||
import org.factcenter.qilin.primitives.generic.ElGamal;
|
||||
import org.factcenter.qilin.util.Pair;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PublicKey;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
|
||||
/**
|
||||
* utilities for ECElgamal
|
||||
*/
|
||||
public class ECElGamalUtils {
|
||||
final static Logger logger = LoggerFactory.getLogger(ECElGamalUtils.class);
|
||||
|
||||
public final static String ENCRYPTION_KEY_ALGORITHM = "ECDH";
|
||||
|
||||
/**
|
||||
* Serialize an El-Gamal public key into a form acceptable by {@link ECElGamalEncryption}
|
||||
* @param pk
|
||||
* @return
|
||||
*/
|
||||
public static ConcreteCrypto.ElGamalPublicKey serializePk(ECGroup group, ElGamal.PK<ECPoint> pk) {
|
||||
ECPoint pkPoint = pk.getPK();
|
||||
ECParameterSpec params = group.getCurveParams();
|
||||
|
||||
ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(pkPoint, params);
|
||||
|
||||
try {
|
||||
KeyFactory fact = KeyFactory.getInstance(ENCRYPTION_KEY_ALGORITHM,
|
||||
GlobalCryptoSetup.getBouncyCastleProvider());
|
||||
PublicKey javaPk = fact.generatePublic(pubKeySpec);
|
||||
ConcreteCrypto.ElGamalPublicKey serializedPk = ConcreteCrypto.ElGamalPublicKey.newBuilder()
|
||||
.setSubjectPublicKeyInfo(ByteString.copyFrom(javaPk.getEncoded())).build();
|
||||
|
||||
return serializedPk;
|
||||
} catch (NoSuchAlgorithmException|InvalidKeySpecException e) {
|
||||
logger.error("Should never happen!", e);
|
||||
throw new RuntimeException("Error converting public key!", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard (non-threshold) decryption for testing purposes.
|
||||
* @param secretKey
|
||||
* @return
|
||||
*/
|
||||
public static <T extends Message> T decrypt(Class<T> plaintextMessageType, ECElGamal.SK secretKey, ECGroup group, Crypto.RerandomizableEncryptedMessage opaqueCipher)
|
||||
throws InvalidProtocolBufferException {
|
||||
ConcreteCrypto.ElGamalCiphertext cipherText = ConcreteCrypto.ElGamalCiphertext.parseFrom(opaqueCipher.getData());
|
||||
ByteString c1encoded = cipherText.getC1();
|
||||
ByteString c2encoded = cipherText.getC2();
|
||||
|
||||
ECPoint c1 = group.decode(c1encoded.toByteArray());
|
||||
ECPoint c2 = group.decode(c2encoded.toByteArray());
|
||||
|
||||
ECPoint plaintextEncoded = secretKey.decrypt(new Pair<ECPoint, ECPoint>(c1, c2));
|
||||
|
||||
byte[] plaintext = group.injectiveDecode(plaintextEncoded);
|
||||
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(plaintext);
|
||||
|
||||
try {
|
||||
java.lang.reflect.Method newBuilder = plaintextMessageType.getMethod("newBuilder");
|
||||
GeneratedMessage.Builder<?> builder = (GeneratedMessage.Builder<?>) newBuilder.invoke(plaintextMessageType);
|
||||
builder.mergeDelimitedFrom(in);
|
||||
return plaintextMessageType.cast(builder.build());
|
||||
} catch (Exception e) {
|
||||
logger.error("Error parsing incoming message", e);
|
||||
throw new InvalidProtocolBufferException("Plaintext protobuf error");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue