package edu.princeton.bitcointwofactorauth.android;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.math.BigInteger;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLSocket;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.Transaction.SigHash;
import threshold.mr04.Util;
import threshold.mr04.data.PublicParameters;
import threshold.mr04.data.Round1Message;
import threshold.mr04.data.Round2Message;
import threshold.mr04.data.Round3Message;
import threshold.mr04.data.Round4Message;
import android.util.Log;
public class TFAConnection {
private static TFAConnection mMainConnection = null;
private static final String TAG = "TFAConnection";
private WalletData mWalletData;
private SSLSocket mSocket;
private ObjectInputStream ois;
private ObjectOutputStream oos;
public TransactionData mTransactionData;
public static TFAConnection getMainConnection() {
return mMainConnection;
}
public static void setMainConnection(TFAConnection mainConnection) {
mMainConnection = mainConnection;
}
// http://www.nealgroothuis.name/import-a-private-key-into-a-java-keystore/
public TFAConnection(SSLSocket socket) throws IOException {
Log.d(TAG, "Creating TFAConnection");
mSocket = socket;
oos = new ObjectOutputStream(new BufferedOutputStream(mSocket.getOutputStream()));
oos.flush();
ois = new ObjectInputStream(new BufferedInputStream(mSocket.getInputStream()));
Log.d(TAG, "Getting request");
int requestType = ois.readInt();
Log.d(TAG, "Got requestType + " + requestType);
oos.writeInt(4);
oos.flush();
Log.d(TAG, "Created TFAConnection");
}
public void tearDown() throws IOException {
mSocket.close();
}
public void setState(WalletData walletData, TransactionData txData) {
mWalletData = walletData;
mTransactionData = txData;
}
public InitializationParams initializeWallet(byte[] oneTimePass, X509Certificate cert) throws IOException {
InitializationParams params = null;
try {
Log.d(TAG, "Initializing wallet");
sendByteArray(oneTimePass);
Log.d(TAG, "Sent pass");
boolean passwordApproved = (Boolean) ois.readObject();
Log.d(TAG, "Got response");
if (passwordApproved) {
Log.d(TAG, "Password was approved");
sendObject(cert);
Log.d(TAG, "Sent cert");
Log.d(TAG, "Reading Initialization Params");
PublicParameters publicParams = (PublicParameters) ois.readObject();
BigInteger bobShare = (BigInteger) ois.readObject();
byte[] publicKey = readPublicKey();
Log.d(TAG, "Read Initialization Params");
params = new InitializationParams(publicParams, bobShare, publicKey);
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return params;
}
public void sendBoolean(Boolean bool) throws IOException {
sendObject(bool);
}
public byte[] readPublicKey() throws IOException {
Log.d(TAG, "Reading public key");
byte[] publicKey = receiveByteArray();
Log.d(TAG, "Read public key");
return publicKey;
}
public TransactionData readTransactionData() throws IOException {
try {
Log.d(TAG, "Reading Transaction Data");
boolean isTx = (Boolean) ois.readObject();
if (isTx) {
System.out.println("Getting actual transaction");
Transaction tx = (Transaction) ois.readObject();
int inputIndex = ois.readInt();
byte[] connectedPubKeyScript = receiveByteArray();
SigHash hashType = (SigHash) ois.readObject();
boolean anyoneCanPay = (Boolean) ois.readObject();
Log.d(TAG, "Read Transaction Data");
return new TransactionData(tx, inputIndex, connectedPubKeyScript, hashType, anyoneCanPay);
} else {
System.out.println("Producing fake transaction");
return new TransactionData(null, 0, null, SigHash.ALL, true);
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public boolean signTransaction(TransactionData txData) throws IOException {
try {
Round1Message round1Message = (Round1Message) ois.readObject();
if (txData.isTransaction()) {
BigInteger receivedMPrime = round1Message.getmPrime();
BigInteger calculatedMPrime = Util.calculateMPrime(mWalletData.mBob.q, txData.getSigningHash().getBytes());
if (!receivedMPrime.equals(calculatedMPrime)) {
Boolean response = false;
sendObject(response);
return false;
}
}
Boolean response = true;
sendObject(response);
Round2Message round2Message = mWalletData.mBob.bobToAliceRound2(round1Message);
sendObject(round2Message);
Round3Message round3Message = (Round3Message) ois.readObject();
Round4Message round4Message = mWalletData.mBob.bobToAliceRound4(round3Message);
sendObject(round4Message);
return true;
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return false;
}
private void sendObject(Object obj) throws IOException {
oos.writeObject(obj);
oos.flush();
}
private void sendByteArray(byte[] objArray) throws IOException {
oos.writeInt(objArray.length);
oos.write(objArray);
oos.flush();
}
private byte[] receiveByteArray() throws IOException {
int arrayLength = ois.readInt();
byte[] array = new byte[arrayLength];
ois.read(array);
return array;
}
}