/**
* Copyright (c) 2007-2009 Alysson Bessani, Eduardo Alchieri, Paulo Sousa, and the authors indicated in the @author tags
*
* This file is part of SMaRt.
*
* SMaRt is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SMaRt is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SMaRt. If not, see <http://www.gnu.org/licenses/>.
*/
package bftsmart.tom.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.util.Arrays;
import java.util.concurrent.locks.ReentrantLock;
import bftsmart.reconfiguration.ViewManager;
public class TOMUtil {
//private static final int BENCHMARK_PERIOD = 10000;
//some message types
public static final int RR_REQUEST = 0;
public static final int RR_REPLY = 1;
public static final int RR_DELIVERED = 2;
public static final int STOP = 3;
public static final int STOPDATA = 4;
public static final int SYNC = 5;
public static final int SM_REQUEST = 6;
public static final int SM_REPLY = 7;
public static final int TRIGGER_LC_LOCALLY = 8;
public static final int TRIGGER_SM_LOCALLY = 9;
//the signature engine used in the system and the signatureSize
private static Signature signatureEngine;
private static int signatureSize = -1;
//lock to make signMessage and verifySignature reentrant
private static ReentrantLock lock = new ReentrantLock();
//private static Semaphore sem = new Semaphore(10, true);
//private static Storage st = new Storage(BENCHMARK_PERIOD);
//private static int count=0;
public static int getSignatureSize(ViewManager manager) {
if (signatureSize > 0) {
return signatureSize;
}
byte[] signature = signMessage(manager.getStaticConf().getRSAPrivateKey(),
"a".getBytes());
if (signature != null) {
signatureSize = signature.length;
}
return signatureSize;
}
//******* EDUARDO BEGIN **************//
public static byte[] getBytes(Object o) {
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
ObjectOutputStream obOut = null;
try {
obOut = new ObjectOutputStream(bOut);
obOut.writeObject(o);
obOut.flush();
bOut.flush();
obOut.close();
bOut.close();
} catch (IOException ex) {
ex.printStackTrace();
return null;
}
return bOut.toByteArray();
}
public static Object getObject(byte[] b) {
if (b == null)
return null;
ByteArrayInputStream bInp = new ByteArrayInputStream(b);
try {
ObjectInputStream obInp = new ObjectInputStream(bInp);
Object ret = obInp.readObject();
obInp.close();
bInp.close();
return ret;
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
//******* EDUARDO END **************//
/**
* Sign a message.
*
* @param key the private key to be used to generate the signature
* @param message the message to be signed
* @return the signature
*/
public static byte[] signMessage(PrivateKey key, byte[] message) {
lock.lock();
byte[] result = null;
try {
if (signatureEngine == null) {
signatureEngine = Signature.getInstance("SHA1withRSA");
}
signatureEngine.initSign(key);
signatureEngine.update(message);
result = signatureEngine.sign();
} catch (Exception e) {
e.printStackTrace();
}
lock.unlock();
return result;
}
/**
* Verify the signature of a message.
*
* @param key the public key to be used to verify the signature
* @param message the signed message
* @param signature the signature to be verified
* @return true if the signature is valid, false otherwise
*/
public static boolean verifySignature(PublicKey key, byte[] message, byte[] signature) {
lock.lock();
boolean result = false;
//long startTime = System.nanoTime();
try {
if (signatureEngine == null) {
signatureEngine = Signature.getInstance("SHA1withRSA");
}
signatureEngine.initVerify(key);
result = verifySignature(signatureEngine, message, signature);
/*
st.store(System.nanoTime()-startTime);
//statistics about signature execution time
count++;
if (count%BENCHMARK_PERIOD==0){
System.out.println("#-- (TOMUtil) Signature verification benchmark:--");
System.out.println("#Average time for " + BENCHMARK_PERIOD + " signature verifications (-10%) = " + st.getAverage(true) / 1000 + " us ");
System.out.println("#Standard desviation for " + BENCHMARK_PERIOD + " signature verifications (-10%) = " + st.getDP(true) / 1000 + " us ");
System.out.println("#Average time for " + BENCHMARK_PERIOD + " signature verifications (all samples) = " + st.getAverage(false) / 1000 + " us ");
System.out.println("#Standard desviation for " + BENCHMARK_PERIOD + " signature verifications (all samples) = " + st.getDP(false) / 1000 + " us ");
System.out.println("#Maximum time for " + BENCHMARK_PERIOD + " signature verifications (-10%) = " + st.getMax(true) / 1000 + " us ");
System.out.println("#Maximum time for " + BENCHMARK_PERIOD + " signature verifications (all samples) = " + st.getMax(false) / 1000 + " us ");
count = 0;
st = new Storage(BENCHMARK_PERIOD);
}
*/
} catch (Exception e) {
e.printStackTrace();
}
lock.unlock();
return result;
}
/**
* Verify the signature of a message.
*
* @param initializedSignatureEngine a signature engine already initialized
* for verification
* @param message the signed message
* @param signature the signature to be verified
* @return true if the signature is valid, false otherwise
*/
public static boolean verifySignature(Signature initializedSignatureEngine, byte[] message, byte[] signature) throws SignatureException {
//TODO: limit the amount of parallelization we can do to save some cores for other tasks
//maybe we can use a semaphore here initialized with the maximum number of parallel verifications:
//sem.acquire()
initializedSignatureEngine.update(message);
return initializedSignatureEngine.verify(signature);
//sem.release()
}
public static String byteArrayToString(byte[] b) {
String s = "";
for (int i = 0; i < b.length; i++) {
s = s + b[i];
}
return s;
//Logger.println(s);
}
public static boolean equalsHash(byte[] h1, byte[] h2) {
return Arrays.equals(h2, h2);
}
}