I have a project to test various algorithms about their running time for big byte arrays (>10MB) and i can't find a way to encrypt/decrypt those data with the paillier algorithm. This is my code which obviously doesn't work for data bigger than the key size
public class PaillierKeyPair implements Serializable{
public PaillierPublicKey PublicKey;
public PaillierPrivateKey PrivateKey;
public PaillierKeyPair(int bitLengthVal) {
// TODO Auto-generated constructor stub
KeyGeneration(bitLengthVal, 100);
}
public PaillierKeyPair() {
//null constructor
}
private void KeyGeneration(int bitLengthVal, int certainty) {
int bitLength = bitLengthVal;
/*Constructs two randomly generated positive BigIntegers that are probably prime, with the specified bitLength and certainty.*/
BigInteger p = new BigInteger(bitLength / 2, certainty, new SecureRandom());
BigInteger q = new BigInteger(bitLength / 2, certainty, new SecureRandom());
BigInteger n = p.multiply(q);
BigInteger nsquare = n.multiply(n);
BigInteger g, lambda;
while(true){
g = new BigInteger(bitLength, new SecureRandom());
lambda = p.subtract(BigInteger.ONE).multiply(q.subtract(BigInteger.ONE)).divide(
p.subtract(BigInteger.ONE).gcd(q.subtract(BigInteger.ONE)));
/* check whether g is good.*/
if (g.modPow(lambda, nsquare).subtract(BigInteger.ONE).divide(n).gcd(n).intValue() != 1) {
System.out.println("g is not good. Choose g again.");
//System.exit(1);
}else{
break;
}
}
PublicKey = new PaillierPublicKey();
PublicKey.bitLength = bitLength;
PublicKey.n = n;
PublicKey.nsquare = nsquare;
PublicKey.g = g;
PrivateKey = new PaillierPrivateKey();
PrivateKey.bitLength = bitLength;
PrivateKey.n = n;
PrivateKey.nsquare = nsquare;
PrivateKey.lambda = lambda;
PrivateKey.u = g.modPow(lambda, nsquare).subtract(BigInteger.ONE).divide(n).modInverse(n);
}
//public static void main() throws IOException {
public static void main(String[] str) throws IOException, IllegalBlockSizeException, BadPaddingException {
PaillierKeyPair pkp = new PaillierKeyPair(1024);
int data_size = 256; //256*8(bits)>1024(bits)
byte[] data = new byte[data_size];
new Random().nextBytes(data);
/* instantiating two plaintext msgs*/
BigInteger m1 = new BigInteger(data);
BigInteger m2 = BigInteger.valueOf(1);
/* encryption*/
System.out.println("start paillier encryption ");
long enc_time = System.nanoTime();
BigInteger em1 = pkp.PublicKey.Encryption(m1);
byte[] encrypted = blockCipher(data, 0, pkp);
long endTime_encr = System.nanoTime();
System.out.println("Encryption : "+(endTime_encr - enc_time)/1000 + " us");
BigInteger em2 = pkp.PublicKey.Encryption(m2);
System.out.println("start paillier decryption ");
long decr_time = System.nanoTime();
BigInteger dm1 = pkp.PrivateKey.Decryption(em1);
byte[] decrypted = blockCipher(encrypted, 1, pkp);
long endTime_decr = System.nanoTime();
System.out.println("Decryption : "+(endTime_decr - decr_time)/1000 + " us");
byte[] array_d = dm1.toByteArray();
/* test homomorphic properties -> D(E(m1)*E(m2) mod n^2) = (m1 + m2) mod n */
BigInteger product_em1em2 = em1.multiply(em2).mod(pkp.PublicKey.nsquare);
}
public class PaillierPrivateKey implements Serializable {
/**
* number of bits of modulus
*/
public int bitLength;
/**
* n = p*q, where p and q are two large primes.
*/
public BigInteger n;
/**
* nsquare = n*n
*/
public BigInteger nsquare;
/**
* p and q are two large primes.
* lambda = lcm(p-1, q-1) = (p-1)*(q-1)/gcd(p-1, q-1).
*/
public BigInteger lambda;
/**
* u = (L(g^lambda mod n^2))^(-1) mod n
*/
public BigInteger u;
public PaillierPrivateKey() {
// TODO Auto-generated constructor stub
}
/**
* Decrypts ciphertext c. plaintext m = L(c^lambda mod n^2) * u mod n, where u = (L(g^lambda mod n^2))^(-1) mod n.
* @param c ciphertext as a BigInteger
* @return plaintext as a BigInteger
*/
public BigInteger Decryption(BigInteger c) {
return c.modPow(lambda, nsquare).subtract(BigInteger.ONE).divide(n).multiply(u).mod(n);
}
public class PaillierPublicKey implements Serializable {
/**
* number of bits of modulus
*/
public int bitLength;
/**
* n = p*q, where p and q are two large primes.
*/
public BigInteger n;
/**
* nsquare = n*n
*/
public BigInteger nsquare;
/**
* a random integer in Z*_{n^2} where gcd (L(g^lambda mod n^2), n) = 1.
*/
public BigInteger g;
public PaillierPublicKey() {
// TODO Auto-generated constructor stub
}
/**
* Encrypts plaintext m. ciphertext c = g^m * r^n mod n^2. This function automatically generates random input r (to help with encryption).
* @param m plaintext as a BigInteger
* @return ciphertext as a BigInteger
*/
public BigInteger Encryption(BigInteger m) {
BigInteger r = new BigInteger(bitLength, new SecureRandom());
return g.modPow(m, nsquare).multiply(r.modPow(n, nsquare)).mod(nsquare);
}
public boolean equals(Object arg0){
PaillierPublicKey pk = (PaillierPublicKey)arg0;
if(this.bitLength == pk.bitLength && this.n.equals(pk.n) && this.nsquare.equals(pk.nsquare) && this.g.equals(pk.g)) return true;
else return false;
}
I tried to make smaller data blocks of the byte array (data), then made those smaller arrays BigInteger and then encrypt them but it didn't work at all. Is there a way to make that possible ?