public final class ElGamalCipher
extends javax.crypto.CipherSpi
ElGamal is an asymmetric cipher that can be used to encipher/decipher data
using ElGamal (Diffie-Hellman) public/private key pairs. An instance of this
algorithm can be obtained using the Java Cryptography Architecture (JCA), by
requesting an 'ElGamal' cipher from the
Entrust cryptographic
service provider. This can be done using either of the following calls:
Cipher.getInstance("ElGamal", "Entrust");Cipher.getInstance("ElGamal/None/PKCS1Padding", "Entrust");
The ElGamal public-key cryptosystem was defined by Tahar ElGamal in his paper "A Public-Key Cryptosystem and a Signature Scheme Based on Discrete Logarithms" that was published in IEEE Transactions on Information Theory, v. IT-31, n. 4, 1985, pp469–472. The security of the algorithm is based on the intractability of the discrete logarithm problem, specifically the Diffie-Hellman problem. Elgamal simply provides a way to implement the public key distribution scheme introduced by Diffie and Hellman to encrypt and decrypt messages.
Because the ElGamal public-key cryptosystem is simply an extension of Diffie-Hellman algorithm, Diffie-Hellman keys are also used with ElGamal; ElGamal keys are in fact Diffie-Hellman keys. The keys used with ElGamal (a Diffie-Hellman key pair) are defined as follows:
p: the prime modulusg: the base generatory: the public valuep: the prime modulusg: the base generatorx: the private valueThe following is the description of the ElGamal public-key encryption algorithm from the Handbook of Applied Cryptography, Chapter 8, Section 8.18:
SUMMARY: B encrypts a message m for
A, which A decrypts.
B should do the following
A's authentic public key (p, g, y).m in the range
{0, 1, ..., p - 1}.k, such that
1 <= k <= p - 2.γ = gk mod p and
δ = m * (y)k mod p.c = (γ, δ) to A
.m from
c, A should do the following
(p, g, x) to compute
γ-x mod p.m by computing
(γ-x) * δ mod p.The problem of breaking the ElGamal encryption scheme (recovering the plaintext given the ciphertext and the public key) is equivalent to solving the Diffie-Hellman problem. In fact, the ElGamal encryption scheme can be viewed as simply comprising a Diffie-Hellman key exchange to determine a session key, and then encryption the message by multiplication with that session key. For this reason, the security of the ElGamal encryption scheme is said to be based on the discrete logarithm problem, although such equivalence has not been proven.
One disadvantage of ElGamal encryption is that the size of the ciphertext is
twice the size of the message; this property is called message expansion.
Another disadvantage is that the message being encrypted cannot be larger
than the prime modulus p. Also, because ElGamal requires modular
exponentiation and multiplication operations, the ElGamal public-key
cryptosystem is substantially slower at processing data than most symmetric
cipher algorithms. Because of these factors, ElGamal is typically used in
conjunction with a symmetric cipher algorithm. Usually, ElGamal is used to
protect a symmetric key, which in turn is used to protect the data.
When decrypting via the ElGamal public-key cryptosystem, it is impossible to
determine the length of the original message unless a padding mechanism is
employed. For this reason, this implementation of the ElGamal public-key
cryptosystem employs PKCS #1
padding with block type 02. The plaintext is automatically padded internally
prior to encryption and this padding is also automatically removed internally
following decryption. On restriction imposed by this padding mechanism is
that the padding must be at least 11 bytes in length. This means
that the plaintext can be no larger than k - 11 (where
k is the length of the prime modulus in bytes).
This cipher implementation only accepts ElGamal (Diffie-Hellman) keys (
javax.crypto.interfaces.DHKey). When encrypting, a
javax.crypto.interfaces.DHPublicKey is required; when decrypting
a javax.crypto.interfaces.DHPrivateKey is required. An Elgamal
(Diffie-Hellman) key-pair can be generated using the ElGamal (Diffie-Hellman)
key generation algorithm (KeyPairGenerator.getInstance("ElGamal, "Entrust")
) or manually created using an appropriate DHKey implementation.
This cipher implementation does not use any algorithm parameters; if any are
provided, an InvalidAlgorithmParameterException will result. It
supports the 'None' block mode and the 'PKCS1Padding' padding type.
For optimum security, the ElGamal (Diffie-Hellman) keys should be generated
so that the prime modulus has the following characteristic
p = 2q + 1, where q is also prime. This removes
some possible areas of attack on the algorithm. Generating ElGamal
(Diffie-Hellman) keys with this property is the default behaviour of the
Entrust key generation algorithm implementation and can be done as follows:
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("ElGamal, "Entrust");
keyGen.initialize(pSize);
or
SecureRandom secureRandom = Entrust.getDefaultSecureRandomInstance();
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("ElGamal, "Entrust");
keyGen.initialize(pSize, mySecureRandom);
This class SHOULD NOT be used directly; it should only be used through the JCA/JCE.
| Constructor and Description |
|---|
ElGamalCipher()
The constructor; creates a new instance of the ElGamal asymmetric cipher
algorithm.
|
| Modifier and Type | Method and Description |
|---|---|
protected byte[] |
engineDoFinal(byte[] input,
int inputOffset,
int inputLen)
Encrypts or decrypts data in a single-part operation, or finishes a
multiple-part operation.
|
protected int |
engineDoFinal(byte[] input,
int inputOffset,
int inputLen,
byte[] output,
int outputOffset)
Encrypts or decrypts data in a single-part operation, or finishes a
multiple-part operation.
|
protected int |
engineGetBlockSize()
Returns the block size (in bytes).
|
protected byte[] |
engineGetIV()
Returns the initialization vector (IV) in a new buffer.
|
protected int |
engineGetKeySize(java.security.Key key)
Returns the key size of the given key object in bits.
|
protected int |
engineGetOutputSize(int inputLen)
Returns the length in bytes that an output buffer would need to be in
order to hold the result of the next
update or
doFinal operation, given the input length
inputLen (in bytes). |
protected java.security.AlgorithmParameters |
engineGetParameters()
Returns the parameters used with this cipher.
|
protected void |
engineInit(int opmode,
java.security.Key key,
java.security.spec.AlgorithmParameterSpec params,
java.security.SecureRandom random)
Initializes this cipher with a key, a set of algorithm parameters, and a
source of randomness.
|
protected void |
engineInit(int opmode,
java.security.Key key,
java.security.AlgorithmParameters params,
java.security.SecureRandom random)
Initializes this cipher with a key, a set of algorithm parameters, and a
source of randomness.
|
protected void |
engineInit(int opmode,
java.security.Key key,
java.security.SecureRandom random)
Initializes this cipher with a key and a source of randomness.
|
protected void |
engineSetMode(java.lang.String mode)
Sets the block mode of this cipher.
|
protected void |
engineSetPadding(java.lang.String padding)
Sets the padding type of this cipher.
|
protected java.security.Key |
engineUnwrap(byte[] wrappedKey,
java.lang.String wrappedKeyAlgorithm,
int wrappedKeyType)
Unwrap a previously wrapped key.
|
protected byte[] |
engineUpdate(byte[] input,
int inputOffset,
int inputLen)
Continues a multiple-part encryption or decryption operation (depending
on how this cipher was initialized), processing another data part.
|
protected int |
engineUpdate(byte[] input,
int inputOffset,
int inputLen,
byte[] output,
int outputOffset)
Continues a multiple-part encryption or decryption operation (depending
on how this cipher was initialized), processing another data part.
|
protected byte[] |
engineWrap(java.security.Key key)
Wrap a key.
|
public ElGamalCipher()
Applications should never use this constructor, instead the symmetric
cipher algorithm should be requested from the appropriate JCA/JCE
cryptographic service provider as follows:
Cipher.getInstance("ElGamal", "Entrust").
protected void engineSetMode(java.lang.String mode)
throws java.security.NoSuchAlgorithmException
engineSetMode in class javax.crypto.CipherSpimode - [FIPS 140-2 control input] the cipher block modejava.security.NoSuchAlgorithmException - [FIPS 140-2 status output] if the requested cipher block mode
is not supportedprotected void engineSetPadding(java.lang.String padding)
throws javax.crypto.NoSuchPaddingException
engineSetPadding in class javax.crypto.CipherSpipadding - [FIPS 140-2 control input] the padding typejavax.crypto.NoSuchPaddingException - [FIPS 140-2 status output] if the requested padding type does
not existprotected java.security.AlgorithmParameters engineGetParameters()
The returned parameters may be the same that were used to initialize this cipher, or may contain a combination of default and random parameter values used by the underlying cipher implementation if this cipher requires algorithm parameters but was not initialized with any.
engineGetParameters in class javax.crypto.CipherSpiFips140ErrorStateException - [FIPS 140-2 status output] thrown if the Toolkit is not
allowed to perform cryptographic operationsprotected byte[] engineGetIV()
This is useful in the context of password-based encryption or decryption, where the IV is derived from a user-provided passphrase.
engineGetIV in class javax.crypto.CipherSpiFips140ErrorStateException - [FIPS 140-2 status output] thrown if the Toolkit is not
allowed to perform cryptographic operationsprotected int engineGetBlockSize()
engineGetBlockSize in class javax.crypto.CipherSpiFips140ErrorStateException - [FIPS 140-2 status output] thrown if the Toolkit is not
allowed to perform cryptographic operationsprotected int engineGetOutputSize(int inputLen)
update or
doFinal operation, given the input length
inputLen (in bytes).
This call takes into account any unprocessed (buffered) data from a
previous update call, and padding.
The actual output length of the next update or
doFinal call may be smaller than the length returned by this
method.
engineGetOutputSize in class javax.crypto.CipherSpiinputLen - [FIPS 140-2 data input] the input length (in bytes)Fips140ErrorStateException - [FIPS 140-2 status output] thrown if the Toolkit is not
allowed to perform cryptographic operationsprotected int engineGetKeySize(java.security.Key key)
throws java.security.InvalidKeyException
engineGetKeySize in class javax.crypto.CipherSpikey - [FIPS 140-2 data input] [FIPS 140-2 CSP] the key objectjava.security.InvalidKeyException - [FIPS 140-2 status output] if key is invalidFips140ErrorStateException - [FIPS 140-2 status output] thrown if the Toolkit is not
allowed to perform cryptographic operationsprotected void engineInit(int opmode,
java.security.Key key,
java.security.SecureRandom random)
throws java.security.InvalidKeyException
The cipher is initialized for one of the following four operations:
encryption, decryption, key wrapping or key unwrapping, depending on the
value of opmode.
If this cipher requires any algorithm parameters that cannot be derived
from the given key, the underlying cipher implementation is supposed to
generate the required parameters itself (using provider-specific default
or random values) if it is being initialized for encryption or key
wrapping, and raise an InvalidKeyException if it is being
initialized for decryption or key unwrapping. The generated parameters
can be retrieved using engineGetParameters() or
engineGetIV() (if the parameter is an IV).
If this cipher (including its underlying feedback or padding scheme)
requires any random bytes (e.g., for parameter generation), it will get
them from random.
Note that when a Cipher object is initialized, it loses all previously-acquired state. In other words, initializing a Cipher is equivalent to creating a new instance of that Cipher and initializing it.
engineInit in class javax.crypto.CipherSpiopmode - [FIPS 140-2 control input] the operation mode of this cipher
(this is one of the following: ENCRYPT_MODE,
DECRYPT_MODE, WRAP_MODE or
UNWRAP_MODE)key - [FIPS 140-2 data input] [FIPS 140-2 CSP] the encryption keyrandom - [FIPS 140-2 control input] the source of randomnessjava.security.InvalidKeyException - [FIPS 140-2 status output] if the given key is inappropriate
for initializing this cipher, or if this cipher is being
initialized for decryption and requires algorithm parameters
that cannot be determined from the given keyFips140ErrorStateException - [FIPS 140-2 status output] thrown if the Toolkit is not
allowed to perform cryptographic operationsprotected void engineInit(int opmode,
java.security.Key key,
java.security.AlgorithmParameters params,
java.security.SecureRandom random)
throws java.security.InvalidKeyException,
java.security.InvalidAlgorithmParameterException
The cipher is initialized for one of the following four operations:
encryption, decryption, key wrapping or key unwrapping, depending on the
value of opmode.
If this cipher requires any algorithm parameters and params
is null, the underlying cipher implementation is supposed to generate the
required parameters itself (using provider-specific default or random
values) if it is being initialized for encryption or key wrapping, and
raise an InvalidAlgorithmParameterException if it is being
initialized for decryption or key unwrapping. The generated parameters
can be retrieved using engineGetParameters() or
engineGetIV() (if the parameter is an IV).
If this cipher (including its underlying feedback or padding scheme)
requires any random bytes (e.g., for parameter generation), it will get
them from random.
Note that when a Cipher object is initialized, it loses all previously-acquired state. In other words, initializing a Cipher is equivalent to creating a new instance of that Cipher and initializing it.
engineInit in class javax.crypto.CipherSpiopmode - [FIPS 140-2 control input] the operation mode of this cipher
(this is one of the following: ENCRYPT_MODE,
DECRYPT_MODE, WRAP_MODE or
UNWRAP_MODE)key - [FIPS 140-2 data input] [FIPS 140-2 CSP] the encryption keyparams - [FIPS 140-2 data input] the algorithm parametersrandom - [FIPS 140-2 control input] the source of randomnessjava.security.InvalidKeyException - [FIPS 140-2 status output] if the given key is inappropriate
for initializing this cipherjava.security.InvalidAlgorithmParameterException - [FIPS 140-2 status output] if the given algorithm parameters
are inappropriate for this cipher, or if this cipher is being
initialized for decryption and requires algorithm parameters
and params is nullFips140ErrorStateException - [FIPS 140-2 status output] thrown if the Toolkit is not
allowed to perform cryptographic operationsprotected void engineInit(int opmode,
java.security.Key key,
java.security.spec.AlgorithmParameterSpec params,
java.security.SecureRandom random)
throws java.security.InvalidKeyException,
java.security.InvalidAlgorithmParameterException
The cipher is initialized for one of the following four operations:
encryption, decryption, key wrapping or key unwrapping, depending on the
value of opmode.
If this cipher requires any algorithm parameters and params
is null, the underlying cipher implementation is supposed to generate the
required parameters itself (using provider-specific default or random
values) if it is being initialized for encryption or key wrapping, and
raise an InvalidAlgorithmParameterException if it is being
initialized for decryption or key unwrapping. The generated parameters
can be retrieved using engineGetParameters() or
engineGetIV() (if the parameter is an IV).
If this cipher (including its underlying feedback or padding scheme)
requires any random bytes (e.g., for parameter generation), it will get
them from random.
Note that when a Cipher object is initialized, it loses all previously-acquired state. In other words, initializing a Cipher is equivalent to creating a new instance of that Cipher and initializing it.
engineInit in class javax.crypto.CipherSpiopmode - [FIPS 140-2 control input] the operation mode of this cipher
(this is one of the following: ENCRYPT_MODE,
DECRYPT_MODE, WRAP_MODE or
UNWRAP_MODE)key - [FIPS 140-2 data input] [FIPS 140-2 CSP] the encryption keyparams - [FIPS 140-2 data input] the algorithm parametersrandom - [FIPS 140-2 control input] the source of randomnessjava.security.InvalidKeyException - [FIPS 140-2 status output] if the given key is inappropriate
for initializing this cipherjava.security.InvalidAlgorithmParameterException - [FIPS 140-2 status output] if the given algorithm parameters
are inappropriate for this cipher, or if this cipher is being
initialized for decryption and requires algorithm parameters
and params is nullFips140ErrorStateException - [FIPS 140-2 status output] thrown if the Toolkit is not
allowed to perform cryptographic operationsprotected byte[] engineUpdate(byte[] input,
int inputOffset,
int inputLen)
The first inputLen bytes in the input buffer,
starting at inputOffset inclusive, are processed, and the
result is stored in a new buffer.
engineUpdate in class javax.crypto.CipherSpiinput - [FIPS 140-2 data input] the input bufferinputOffset - [FIPS 140-2 data input] the offset in input where the
input startsinputLen - [FIPS 140-2 data input] the input lengthFips140ErrorStateException - [FIPS 140-2 status output] thrown if the Toolkit is not
allowed to perform cryptographic operationsprotected int engineUpdate(byte[] input,
int inputOffset,
int inputLen,
byte[] output,
int outputOffset)
The first inputLen bytes in the input buffer,
starting at inputOffset inclusive, are processed, and the
result is stored in the output buffer, starting at
outputOffset inclusive.
If the output buffer is too small to hold the result, a
ShortBufferException is thrown.
engineUpdate in class javax.crypto.CipherSpiinput - [FIPS 140-2 data input] the input bufferinputOffset - [FIPS 140-2 data input] the offset in input where the
input startsinputLen - [FIPS 140-2 data input] the input lengthoutput - [FIPS 140-2 data output] the buffer for the resultoutputOffset - [FIPS 140-2 data input] the offset in output
where the result is storedoutputjavax.crypto.ShortBufferException - [FIPS 140-2 status output] if the given output buffer is too
small to hold the resultFips140ErrorStateException - [FIPS 140-2 status output] thrown if the Toolkit is not
allowed to perform cryptographic operationsprotected byte[] engineDoFinal(byte[] input,
int inputOffset,
int inputLen)
throws javax.crypto.BadPaddingException,
javax.crypto.IllegalBlockSizeException
The first inputLen bytes in the input buffer,
starting at inputOffset inclusive and any input bytes that
may have been buffered during a previous update operation, are processed,
with padding (if requested) being applied. The result is stored in a new
buffer.
Upon finishing, this method resets this cipher object to the state it was
in when previously initialized via a call to engineInit.
That is, the object is reset and available to encrypt or decrypt
(depending on the operation mode that was specified in the call to
engineInit) more data.
Note: if any exception is thrown, this cipher object may need to be reset before it can be used again.
engineDoFinal in class javax.crypto.CipherSpiinput - [FIPS 140-2 data input] the input bufferinputOffset - [FIPS 140-2 data input] the offset in input where the
input startsinputLen - [FIPS 140-2 data input] the input lengthjavax.crypto.IllegalBlockSizeException - [FIPS 140-2 status output] if this cipher is a block cipher,
no padding has been requested (only in encryption mode), and
the total input length of the data processed by this cipher
is not a multiple of block size; or if this encryption
algorithm is unable to process the input data providedjavax.crypto.BadPaddingException - [FIPS 140-2 status output] if this cipher is in decryption
mode, and (un)padding has been requested, but the decrypted
data is not bounded by the appropriate padding bytesFips140ErrorStateException - [FIPS 140-2 status output] thrown if the Toolkit is not
allowed to perform cryptographic operationsprotected int engineDoFinal(byte[] input,
int inputOffset,
int inputLen,
byte[] output,
int outputOffset)
throws javax.crypto.BadPaddingException,
javax.crypto.IllegalBlockSizeException,
javax.crypto.ShortBufferException
The first inputLen bytes in the input buffer,
starting at inputOffset inclusive, and any input bytes that
may have been buffered during a previous update operation, are processed,
with padding (if requested) being applied. The result is stored in the
output buffer, starting at outputOffset
inclusive.
If the output buffer is too small to hold the result, a
ShortBufferException is thrown.
Upon finishing, this method resets this cipher object to the state it was
in when previously initialized via a call to engineInit.
That is, the object is reset and available to encrypt or decrypt
(depending on the operation mode that was specified in the call to
engineInit) more data.
Note: if any exception is thrown, this cipher object may need to be reset before it can be used again.
engineDoFinal in class javax.crypto.CipherSpiinput - [FIPS 140-2 data input] the input bufferinputOffset - [FIPS 140-2 data input] the offset in input where the
input startsinputLen - [FIPS 140-2 data input] the input lengthoutput - [FIPS 140-2 data output] the buffer for the resultoutputOffset - [FIPS 140-2 data input] the offset in output
where the result is storedoutputjavax.crypto.IllegalBlockSizeException - [FIPS 140-2 status output] if this cipher is a block cipher,
no padding has been requested (only in encryption mode), and
the total input length of the data processed by this cipher
is not a multiple of block size; or if this encryption
algorithm is unable to process the input data providedjavax.crypto.ShortBufferException - [FIPS 140-2 status output] if the given output buffer is too
small to hold the resultjavax.crypto.BadPaddingException - [FIPS 140-2 status output] if this cipher is in decryption
mode, and (un)padding has been requested, but the decrypted
data is not bounded by the appropriate padding bytesFips140ErrorStateException - [FIPS 140-2 status output] thrown if the Toolkit is not
allowed to perform cryptographic operationsprotected byte[] engineWrap(java.security.Key key)
throws java.security.InvalidKeyException
engineWrap in class javax.crypto.CipherSpikey - [FIPS 140-2 data input] [FIPS 140-2 CSP] the key to be wrappedjavax.crypto.IllegalBlockSizeException - [FIPS 140-2 status output] if this cipher is a block cipher,
no padding has been requested, and the length of the encoding
of the key to be wrapped is not a multiple of the block sizejava.security.InvalidKeyException - [FIPS 140-2 status output] if it is impossible or unsafe to
wrap the key with this cipher (e.g., a hardware protected key
is being passed to a software-only cipher)Fips140ErrorStateException - [FIPS 140-2 status output] thrown if the Toolkit is not
allowed to perform cryptographic operationsprotected java.security.Key engineUnwrap(byte[] wrappedKey,
java.lang.String wrappedKeyAlgorithm,
int wrappedKeyType)
throws java.security.InvalidKeyException,
java.security.NoSuchAlgorithmException
engineUnwrap in class javax.crypto.CipherSpiwrappedKey - [FIPS 140-2 data input] [FIPS 140-2 CSP] the key to be
unwrappedwrappedKeyAlgorithm - [FIPS 140-2 control input] the algorithm associated with the
wrapped keywrappedKeyType - [FIPS 140-2 control input] the type of the wrapped key. This
is one of SECRET_KEY, PRIVATE_KEY,
or PUBLIC_KEY.java.security.NoSuchAlgorithmException - [FIPS 140-2 status output] if no installed providers can
create keys of type wrappedKeyType for the
wrappedKeyAlgorithmjava.security.InvalidKeyException - [FIPS 140-2 status output] if wrappedKey does
not represent a wrapped key of type
wrappedKeyType for the
wrappedKeyAlgorithmFips140ErrorStateException - [FIPS 140-2 status output] thrown if the Toolkit is not
allowed to perform cryptographic operations