package com.rau.evoting.ElGamal; import java.math.BigInteger; import java.security.SecureRandom; import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.params.ElGamalPublicKeyParameters; import com.rau.evoting.utils.Pair; public class EncryptEngine { private ElGamalPublicKeyParameters pubKey = null; private SecureRandom random; private int bitSize; private static final BigInteger ZERO = BigInteger.ZERO; //private static final BigInteger ONE = BigInteger.ONE; private static final BigInteger TWO = BigInteger.valueOf(2); private BigInteger r = null; public void initForEncrypt(ElGamalPublicKeyParameters key) { pubKey = key; bitSize = key.getParameters().getP().bitLength(); random = new SecureRandom(); } public int getInputBlockSize() { return (bitSize - 1) / 8; } public int getOutputBlockSize() { return 2 * ((bitSize + 7) / 8); } public byte[] encode(byte[] in, int inOff, int inLen) { if (pubKey == null) { throw new IllegalStateException("ElGamal engine notinitialised"); } int maxLength = (bitSize - 1 + 7) / 8; if (inLen > maxLength) { throw new DataLengthException( "input too large for ElGamal cipher.\n"); } BigInteger p = pubKey.getParameters().getP(); byte[] block; if (inOff != 0 || inLen != in.length) { block = new byte[inLen]; System.arraycopy(in, inOff, block, 0, inLen); } else { block = in; } BigInteger input = new BigInteger(1, block); if (input.bitLength() >= p.bitLength()) { throw new DataLengthException( "input too large for ElGamal cipher.\n"); } int pBitLength = p.bitLength(); r = new BigInteger(pBitLength, random); while (r.equals(ZERO) || (r.compareTo(p.subtract(TWO)) > 0)) { r = new BigInteger(pBitLength, random); } BigInteger g = pubKey.getParameters().getG(); BigInteger gamma = g.modPow(r, p); BigInteger phi = input.multiply(pubKey.getY().modPow(r, p)).mod(p); //System.out.println("enc_a:" + phi); //System.out.println("enc_b:" + gamma); byte[] out1 = gamma.toByteArray(); byte[] out2 = phi.toByteArray(); byte[] output = new byte[this.getOutputBlockSize()]; if (out1.length > output.length / 2) { System.arraycopy(out1, 1, output, output.length / 2 - (out1.length - 1), out1.length - 1); } else { System.arraycopy(out1, 0, output, output.length / 2 - out1.length, out1.length); } if (out2.length > output.length / 2) { System.arraycopy(out2, 1, output, output.length - (out2.length - 1), out2.length - 1); } else { System.arraycopy(out2, 0, output, output.length - out2.length, out2.length); } return output; } public byte[] reEncode(byte[] in, int inOff, int inLen) { if (pubKey == null) { throw new IllegalStateException("ElGamal engine notinitialised"); } int maxLength = (bitSize - 1 + 7) / 8; if (inLen/2 > maxLength) { // throw new DataLengthException( // "input1 too large for ElGamal cipher.\n"); } BigInteger p = pubKey.getParameters().getP(); byte[] block; if (inOff != 0 || inLen != in.length) { block = new byte[inLen]; System.arraycopy(in, inOff, block, 0, inLen); } else { block = in; } BigInteger input = new BigInteger(1, block); //System.out.println("input:" + input); Pair<BigInteger, BigInteger> enc = CryptoUtil.getBigIntEncodedA_B(input.toString()); BigInteger a = enc.getFirst(); BigInteger b = enc.getSecond(); //System.out.println("reenc_a:" + a); //System.out.println("reenc_b:" + b); if (a.bitLength() >= p.bitLength() || b.bitLength() >= p.bitLength()) { //throw new DataLengthException( // "input2 too large for ElGamal cipher.\n"); } int pBitLength = p.bitLength(); r = new BigInteger(pBitLength, random); while (r.equals(ZERO) || (r.compareTo(p.subtract(TWO)) > 0)) { r = new BigInteger(pBitLength, random); } BigInteger g = pubKey.getParameters().getG(); BigInteger gamma = a.multiply(g.modPow(r, p)).mod(p); BigInteger phi = b.multiply(pubKey.getY().modPow(r, p)).mod(p); byte[] out1 = gamma.toByteArray(); byte[] out2 = phi.toByteArray(); byte[] output = new byte[this.getOutputBlockSize()]; if (out1.length > output.length / 2) { System.arraycopy(out1, 1, output, output.length / 2 - (out1.length - 1), out1.length - 1); } else { System.arraycopy(out1, 0, output, output.length / 2 - out1.length, out1.length); } if (out2.length > output.length / 2) { System.arraycopy(out2, 1, output, output.length - (out2.length - 1), out2.length - 1); } else { System.arraycopy(out2, 0, output, output.length - out2.length, out2.length); } return output; } public BigInteger getR() { return r; } }