bcgit / bc-java

Bouncy Castle Java Distribution (Mirror)
https://www.bouncycastle.org/java.html
MIT License
2.28k stars 1.13k forks source link

ElGamal homomorphic multiplication using Bouncy Castle #706

Open bojeckkk opened 4 years ago

bojeckkk commented 4 years ago

Long story short: I'm in need of using ElGamal encryption to perform multiplication on encoded numbers.

I'm currently using Kotlin with OpenJDK 1.8 and found nice provider for JCE called Bouncy Castle. It provides ElGamal encryption within standard JCE API. However, I have no idea at all how to perform multiplication on encrypted messages I get out of it.

eg. code in Kotlin:

Security.addProvider(BouncyCastleProvider())

val keys = KeyPairGenerator.getInstance("ElGamal", "BC").generateKeyPair()
val cipher = Cipher.getInstance("ElGamal/None/NoPadding", "BC")
cipher.init(Cipher.ENCRYPT_MODE, keys.public)
val eleven = BigInteger.valueOf(11)
val three = BigInteger.valueOf(3)
val eleven_e = cipher.doFinal(eleven.toByteArray())
val three_e = cipher.doFinal(three.toByteArray())
//Do three_e * eleven_e
bojeckkk commented 4 years ago

I've managed to investigate a little bit the source code of the Bouncy Castle. It seems that below code should be able to multiply two encoded numbers:

fun multiplyElGamal(num1: ByteArray, num2: ByteArray, p: BigInteger): ByteArray {
    val a1 = num1.copyOfRange(0, num1.size / 2)
    val b1 = num1.copyOfRange(num1.size / 2, num1.size)
    val a2 = num2.copyOfRange(0, num2.size / 2)
    val b2 = num2.copyOfRange(num2.size / 2, num2.size)
    return (BigInteger(1, a1) * BigInteger(1, a2) % p).toByteArray() + (BigInteger(1, b1) * BigInteger(1, b2) % p).toByteArray()
}

This might be only partial solution. The problem is that, part p of the key is 1025 bits, while parts a and b of the message got to be 1024 bit (resulting in a byte array of length 256). Modulus operation sometimes returns numbers larger than that which results in org.bouncycastle.crypto.DataLengthException: input too large for ElGamal cipher.