3
$\begingroup$

I have a case where to ensure the same encrypted string for the given input. Say for example If "Hello" is encrypted more than one time then same encrypted string should be i should get as an output (Like in hash algorithms). I have tried pure "ECIES" & "ElGamal" algorithms using bouncycastle but both returns different outputs each time for the same input.

I have tried with RSA by setting the "RSA/ECB/NoPadding" option and it works like charm. But RSA is both performance and memory consuming stuff so i choosen the Elliptic curve which will us both performance and efficient memory. So I choose ECIES initially and also "Elgamal".

What should i set for ECIES and ElGamal to produce same output each time for same input.?

public class AsymmetricElGamalCipher extends BaseAsymmetricCipher {

private final SecureRandom random;

public AsymmetricElGamalCipher(final Config config) throws AndesException {
    super(CryptAlgorithmType.ELGAMAL, config);
    this.random = KeyPairUtils.createFixedRandom();
}

/**
 * Encrypt the given bytes of data using the ECC public key
 *
 * @param value
 *            The data to be encoded or encrypted
 * @return The encrypted/encoded data
 * @throws AndesException
 *             if an error occurred during the operation
 */
public byte[] encrypt(byte[] value) throws AndesException {
    byte[] hexEncodedCipher = null;
     try {
         this.cipher.init(Cipher.ENCRYPT_MODE, this.publicKey, this.random);
        hexEncodedCipher = this.cipher.doFinal(value);
     } catch (InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
            throw new AndesException(e);
     }
     return hexEncodedCipher;
}

/**
 * Encrypt the given plain text using the Elgamal private key
 *
 * @param cipherText
 *            The data to be decoded/decrypted
 * @return The decrypted/decoded bytes of data
 * @throws AndesException
 *             if an error occurred during the operation
 */
public byte[] decrypt(byte[] value)  throws AndesException {
    byte[] hexEncodedCipher = null;
    try {
        this.cipher.init(Cipher.DECRYPT_MODE, this.privateKey, this.random);
        hexEncodedCipher = this.cipher.doFinal(value);
    } catch (InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
        throw new AndesException(e);
 }
    return hexEncodedCipher;
}

}

Here is the Ecc algorithm code,

public class AsymmetricEccCipher extends BaseAsymmetricCipher {

 //  generate derivation and encoding vectors
private final byte[]  d = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
private final byte[]  e = new byte[] { 8, 7, 6, 5, 4, 3, 2, 1 };
private final String initVector = "0000000000000000";
private final IESParameterSpec ALGORITHM_PARAMETER_SPEC;

public AsymmetricEccCipher(final Config config) throws AndesException {
    super(CryptAlgorithmType.ECIES, config);
    try {
        ALGORITHM_PARAMETER_SPEC = new IESParameterSpec(d, e, 128, 128, this.initVector.getBytes(IAndes.CHARACTER_TYPE_UTF_8), true);
    } catch (UnsupportedEncodingException e) {
        throw new AndesException("EC IES parameter spec creation error.");
    }
}

/**
 * Encrypt the given bytes of data using the ECC public key
 *
 * @param value
 *            The data to be encoded or encrypted
 * @return The encrypted/encoded data
 * @throws AndesException
 *             if an error occurred during the operation
 */
public byte[] encrypt(byte[] value) throws AndesException {
    byte[] hexEncodedCipher = null;
     try {
         this.cipher.init(Cipher.ENCRYPT_MODE, this.publicKey, this.ALGORITHM_PARAMETER_SPEC);
        hexEncodedCipher = this.cipher.doFinal(value);
     } catch (InvalidKeyException | IllegalBlockSizeException
                | BadPaddingException | InvalidAlgorithmParameterException e) {
            throw new AndesException(e);
     }
     return hexEncodedCipher;
}

/**
 * Encrypt the given plain text using the ECC private key
 *
 * @param cipherText
 *            The data to be decoded/decrypted
 * @return The decrypted/decoded bytes of data
 * @throws AndesException
 *             if an error occurred during the operation
 */
public byte[] decrypt(byte[] value)  throws AndesException {
    byte[] hexEncodedCipher = null;
    try {
        this.cipher.init(Cipher.DECRYPT_MODE, this.privateKey, this.ALGORITHM_PARAMETER_SPEC);
        hexEncodedCipher = this.cipher.doFinal(value);
    } catch (InvalidKeyException | IllegalBlockSizeException
            | BadPaddingException | InvalidAlgorithmParameterException e) {
        throw new AndesException(e);
    }
    return hexEncodedCipher;
}

}

$\endgroup$
3
  • $\begingroup$ Using ElGamal in a deterministic way means the assumptions in the security proof are not met... best case: you're lucky and nothing bad happens, worst case: as "secure" as sending the message in plaintext. Also, using RSA in ECB mode without padding is quite bad with respect to security. If you need a deterministic encryption scheme, then use one which is made for that kind of usage. $\endgroup$
    – tylo
    May 31, 2017 at 8:29
  • $\begingroup$ You should not do this since you are loosing semantic security... However, I think you can easily do it in your bouncy castle code by simply seeding the SecureRandom used by the cipher. If it doesn't work, please show us your code, that would make it easier to explain. $\endgroup$
    – Lery
    Jul 30, 2017 at 20:09
  • $\begingroup$ I have tried with SecureRandom (constant random number value) but got different encrypted values for same input multiple times. I have edited my post with sample code. $\endgroup$ Aug 2, 2017 at 6:29

2 Answers 2

2
$\begingroup$

These public key algorithms are designed with this sort of randomness as part of their security model, to stop leakage of information of the sort you seem to want as a feature.

$\endgroup$
2
  • $\begingroup$ Yes. I understood that one. But there are cases you wont need that randomness. $\endgroup$ Mar 1, 2017 at 21:13
  • $\begingroup$ See the answer and discussion at this question: crypto.stackexchange.com/questions/24328/… Maybe blinding on the second pair of keys where the second public key is kept secret may work. $\endgroup$
    – kodlu
    Mar 1, 2017 at 21:34
2
$\begingroup$

I have a case where to ensure the same encrypted string for the given input.

For symmetric encryption, that's actually a common case. It does leak if two different ciphertexts correspond to the same plaintext (the ciphertexts will be identical), however it need not leak anything more than that, assuming that we won't allow the attacker to suggest plaintexts for us to encrypt (and in many usage scenarios, the attacker cannot do that).

However, you want to do public key encryption; presumably Alice will generate and publish a public key; if Bob wants to send her a message, he'll encrypt it with the public key, and if Carol sends her the same message, she'll encrypt it into the same ciphertext.

That raises a possible security concern; if Eve sees a ciphertext and she guesses what the plaintext might be, she can encrypt her guess and see if the ciphertext matches what she saw. This means that this system is not secure unless the messages cannot be guessed (that is, they have high entropy).

The difference is between the symmetric case and the public key case is that, with symmetric crypto, Alice would have to cooperate to encrypt an attacker chosen plaintext (and she might refuse to); with public key crypto, the attacker has enough information to do so herself.

Now, if you do have high entropy plaintexts, this 'guess a plaintext and test it' might not be a concern, so it can possibly be secure. One method to do so would be to feed the plaintext as a seed to a cryptographically secure random number generator (aka DRBG), and use the output of that rng as the random coins that your standard public key encryption algorithm (be it ECDSA or ElGammal) would use.

Now, if you're looking at using Bouncy Castle, you might ask "how do you convince Bouncy Castle to do that?" Well, that might be difficult - for some odd reason, the Bouncy Castle developers have decided to not make it easy to misuse their product (and because of the nonstandard "high entropy plaintext" requirements, this would be considered a misuse), and so they likely don't give an easy way to change their internal 'random coin' logic with your own.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.