The El Gamal Algorithm

http://www.bitpapers.com/2012/04/el-gamal-algorithm.html

The El Gamal Algorithm

El Gamal is a variant on Diffie-Hellman and derives its security from the same ideas. Although in some ways it is not as "neat" as the RSA algorithm, El Gamal is still very widely used—it is still the algorithm of choice for most keys used for encryption in Open PGP (RFC 2440).
In El Gamal, to send a message to another party whose public key is Gy mod P, you create a temporary public key, Gx mod P, encrypt the message by multiplying it by Gxy mod P, the multiplication also being modulo P, and send the temporary public key and the enciphered message as a single block. Although it works, as you will see, it does have the effect of making the ciphertext twice the size of the key.
Try It Out: El Gamal Encryption
Image from book
Following is an example of random key generation and encryption using El Gamal. You will find it runs a lot slower than the equivalent RSA example. You will read about the reasons for this a bit later, but if you run it first, you will get a much better idea of what is meant by "a lot slower."
package chapter4;

import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;

import javax.crypto.Cipher;

/**
 * El Gamal example with random key generation.
 */
public class RandomKeyElGamalExample
{
    public static void main(String[] args) throws Exception
    {
        byte[]           input = new byte[] { (byte)0xbe, (byte)0xef };
        Cipher           cipher = Cipher.getInstance(
                                                   "ElGamal/None/NoPadding", "BC");
        KeyPairGenerator generator = KeyPairGenerator.getInstance("ElGamal", "BC");
        SecureRandom     random = Utils.createFixedRandom();

        // create the keys

        generator.initialize(256, random);

        KeyPair          pair = generator.generateKeyPair();
        Key              pubKey = pair.getPublic();
        Key              privKey = pair.getPrivate();

        System.out.println("input : " + Utils.toHex(input));

        // encryption step

        cipher.init(Cipher.ENCRYPT_MODE, pubKey, random);

        byte[] cipherText = cipher.doFinal(input);

        System.out.println("cipher: " + Utils.toHex(cipherText));

        // decryption step

        cipher.init(Cipher.DECRYPT_MODE, privKey);

        byte[] plainText = cipher.doFinal(cipherText);

        System.out.println("plain : " + Utils.toHex(plainText));
    }
}
Running the program produces the following:
input : beef
cipher: 8c2e699772c14496bc82400d11decae4f662fe90864e8c553b78136679fcdfaa60c378b5
69083525c021fcf77e40f661525da56ed4133df92848aaba2459dff5
plain : beef
Image from book
 
How It Works
Overall, there is not much to say here about the use of the algorithm itself. As far as using the public key for encryption, El Gamal is pretty much like RSA; because it is based on math, you will have trouble with leading zeros if you do not use padding. The big difference you will notice when comparing the output to that of the RSA example is that the block of ciphertext produced is twice the size of the key—unlike RSA, where it is the same size as the key. Whether this is important to you really depends on the constraints of your application, but the larger cipher block size is one of the reasons El Gamal is not favored.
The biggest problem, at least in this case, is the speed of the key generation. As you saw previously, the generation of an El Gamal key pair requires Diffie-Hellman parameters, and calculating these values from scratch is very expensive. Internally, when initialized only with a key size, the KeyPairGenerator has to first generate the P and G values before it can generate the key pair. You will find, at least in the case of the Bouncy Castle provider, that this is a one-off cost—generating successive key pairs is much quicker because the P and G values calculated for the first key pair can be reused. Not surprisingly, you will also find that the Diffie-Hellman key pair generator exhibits the same behavior.
Can you pre-generate a DHParameterSpec so that you can pass in parameters like you did with Diffie-Hellman? As it turns out, you can; you just need to use an AlgorithmParametersGenerator object to create them.

The AlgorithmParameterGenerator Class

Like other classes in the JCA, java.security.AlgorithmParameterGenerator is created using the getInstance() factory pattern, and further, in keeping with classes like MessageDigest, it follows the same rules with regard to the precedence rules used if the Java runtime encounters more than one implementation for a given algorithm. The methods on AlgorithmParameterGenerator that are of most of interest to you are the init() methods, of which there are four, and the generateParameters() method, which is used to retrieve the generated AlgorithmParameters object.
AlgorithmParameter Generator.init()
The init() method comes in two flavors: two that just take a size value with an optional source of randomness and two that take AlgortihmParameterSpec objects for situations where it may be necessary to pass parameters other than the size to the generator. It depends on what you are generating as to what suits best. For something like Diffie-Hellman/ElGamal, the size attribute is enough to generate the prime P and the generator G that will provide the basic parameters. Then again, you want to create a parameters object for Diffie-Hellman that takes advantage of the ability to limit the size of the private value—in this case just the size will not be enough, and you will need an AlgorithmParameterSpec object to pass the necessary information in.
Take a look at examples of both over the next two sections.
AlgorithmParameter Generator.generate Parameters()
This returns the AlgorithmParameters that you want to generate. I already covered the AlgorithmParameters object in Chapter 2, so there's no need to go into too much detail here, other than to mention, as you have probably guessed, AlgorithmParameters is used everywhere.
Enough background though. You can now try using the class.
Try It Out: El Gamal Using AlgorithmParameterGenerator
Image from book
Have a look at the following example and compare it with the RandomKeyElGamalExample. Try running the example and then read on.
package chapter4;

import java.security.AlgorithmParameterGenerator;
import java.security.AlgorithmParameters;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;

import javax.crypto.Cipher;
import javax.crypto.spec.DHParameterSpec;

/**
 * El Gamal example with random key generation.
 */
public class AlgorithmParameterExample
{
    public static void main(String[] args) throws Exception
    {
        byte[]           input = new byte[] { (byte)0xbe, (byte)0xef };
        Cipher           cipher = Cipher.getInstance(
                                             "ElGamal/None/NoPadding", "BC");
        SecureRandom     random = Utils.createFixedRandom();

        // create the parameters
        AlgorithmParameterGenerator apg = AlgorithmParameterGenerator.getInstance(
                                                                 "ElGamal", "BC");

        apg.init(256, random);

        AlgorithmParameters     params = apg.generateParameters();
        AlgorithmParameterSpec  dhSpec = params.getParameterSpec(
                                                            DHParameterSpec.class);

        // create the keys
        KeyPairGenerator generator = KeyPairGenerator.getInstance("ElGamal", "BC");

        generator.initialize(dhSpec, random);

        KeyPair          pair = generator.generateKeyPair();
        Key              pubKey = pair.getPublic();
        Key              privKey = pair.getPrivate();

        System.out.println("input : " + Utils.toHex(input));

        // encryption step

        cipher.init(Cipher.ENCRYPT_MODE, pubKey, random);

        byte[] cipherText = cipher.doFinal(input);

        System.out.println("cipher: " + Utils.toHex(cipherText));

        // decryption step

        cipher.init(Cipher.DECRYPT_MODE, privKey);

        byte[] plainText = cipher.doFinal(cipherText);

        System.out.println("plain : " + Utils.toHex(plainText));
    }
}
Because of the fixed seed used in the "random" number generator, you should see that this prints the same results as the original RandomKeyElGamalExample. The reason is that the process that takes place internally to the provider, at least in Bouncy Castle's case, is exactly the same as the process you have made explicit in the code.
Image from book
 
How It Works
In the new example, you are generating the parameters for the P and G values and then passing them to the key pair generator class explicitly, rather than letting it create them based on the key size. This relieves the key pair generator of the need to generate its own set of parameters.
Although it is probably hard to tell the difference in speed just from running the examples, if you add some timing code around the key pair generation in RandomKeyElGamalExample and AlgorithmParameterExample, you will see that the time spent in KeyPairGenerator.generateKeyPair() is substantially less in the later case.
You read in earlier discussion that the AlgorithmParameterGenerator class can also take an AlgorithmParameterSpec object on its init() methods. As it happens, there is an AlgorithmParameterSpec class that is applicable to parameter generation for Diffie-Hellman type parameters—the DHGenParameterSpec class.
The DHGenParameterSpec Class
As you read earlier, an optimization to Diffie-Hellman is to limit the size of the private value associated with a public key. As you also learned, you can construct a DHParameterSpec that will limit the size of the private values it generates when used with a suitable KeyPairGenerator object. It would be useful to be able to incorporate this information into our generated parameters as well, so the JCE provides a class that allows us to configure an AlgorithmParameterGenerator object created for Diffie-Hellman algorithms— javax.crypto.spec.DHGenParameterSpec. So rather than simply specifying a size for the prime P, as you do on the line:
apg.init(256, random);
if you wanted to limit the private value to, say, 200 bits, you could have instead said
apg.init(new DHGenParameterSpec(256, 200), random);
where the arguments to the constructor of DHGenParameterSpec are the size of the prime P in bits and the maximum size in bits of the private value Y. This would then produce DHParameterSpec objects with the DHParameterSpec.getL() method returning 200 thus limiting the private values to 200 bits.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值