ElGamal

From Crypto++ Wiki
Jump to: navigation, search

ElGamal is a cryptosystem for public-key cryptography which is based on the Distrect Log problem similar to Diffie-hellman key exchange.

Saving and Loading Keys

You can save and load keys to and from disk as follows. While a PrivateKey and Decryptor are shown, the same applies to a PubicKey and Encryptor. See Keys and Formats for a detailed discussion.

ElGamalKeys::PrivateKey privateKey1;
privateKey1.GenerateRandomWithKeySize(prng, 2048);
privateKey1.Save(FileSink("elgamal.der", true /*binary*/).Ref());

ElGamalKeys::PrivateKey privateKey2;
privateKey2.Load(FileSource("elgamal.der", true /*pump*/).Ref());
privateKey2.Validate(prng, 3);

ElGamal::Decryptor decryptor(privateKey2);
// ...

Or, you can do it on a Decryptor rather than a PrivateKey because the decryptor provides access to the private key:

ElGamalKeys::PrivateKey privateKey1;
privateKey1.GenerateRandomWithKeySize(prng, 2048);
    
ElGamal::Decryptor decryptor1(privateKey1);
decryptor1.AccessKey().Save(FileSink("elgamal.der", true /*binary*/).Ref());

The keys are ASN.1 encoded, so you can dump them with something like Peter Gutmann's dumpasn1:

$ ./cryptopp-elgamal-keys.exe
Generating private key. This may take some time...
$ dumpasn1 elgamal.der 
  0 556: SEQUENCE {
  4 257:   INTEGER
       :     00 C0 8F 5A 29 88 82 8C 88 7D 00 AE 08 F0 37 AC
       :     FA F3 6B FC 4D B2 EF 5D 65 92 FD 39 98 04 C7 6D
       :     6D 74 F5 FA 84 8F 56 0C DD B4 96 B2 51 81 E3 A1
       :     75 F6 BE 82 46 67 92 F2 B3 EC 41 00 70 5C 45 BF
       :     40 A0 2C EC 15 49 AD 92 F1 3E 4D 06 E2 89 C6 5F
       :     0A 5A 88 32 3D BD 66 59 12 A1 CB 15 B1 72 FE F3
       :     2D 19 DD 07 DF A8 D6 4C B8 D0 AB 22 7C F2 79 4B
       :     6D 23 CE 40 EC FB DF B8 68 A4 8E 52 A9 9B 22 F1
       :             [ Another 129 bytes skipped ]
265   1:   INTEGER 3
268 257:   INTEGER
       :     00 BA 4D ED 20 E8 36 AC 01 F6 5C 9C DA 62 11 BB
       :     E9 71 D0 AB B7 E2 D3 61 37 E2 7B 5C B3 77 2C C9
       :     FC DE 43 70 AE AA 5A 3C 80 0A 2E B0 FA C9 18 E5
       :     1C 72 86 46 96 E9 9A 44 08 FF 43 62 95 BE D7 37
       :     F8 99 16 59 7D FA 3A 73 DD 0D C8 CA 19 B8 6D CA
       :     8D 8E 89 52 50 4E 3A 84 B3 17 BD 71 1A 1D 38 9E
       :     4A C4 04 F3 A2 1A F7 1F 34 F0 5A B9 CD B4 E2 7F
       :     8C 40 18 22 58 85 14 40 E0 BF 01 2D 52 B7 69 7B
       :             [ Another 129 bytes skipped ]
529  29:   INTEGER
       :     01 61 40 24 1F 48 00 4C 35 86 0B 9D 02 8C B8 90
       :     B1 56 CF BD A4 75 FE E2 8E 0B B3 66 08
       :   }

0 warnings, 0 errors.

Public Key Encryption

The following is a sample program that encrypts a secret under a ElGamal public key and then recovers the secret using an ElGamal private key.

////////////////////////////////////////////////
// Generate keys
AutoSeededRandomPool rng;

cout << "Generating private key. This may take some time..." << endl;

ElGamal::Decryptor decryptor;
decryptor.AccessKey().GenerateRandomWithKeySize(rng, 2048);
const ElGamalKeys::PrivateKey& privateKey = decryptor.AccessKey();

ElGamal::Encryptor encryptor(decryptor);
const PublicKey& publicKey = encryptor.AccessKey();

////////////////////////////////////////////////
// Secret to protect
static const int SECRET_SIZE = 16;
SecByteBlock plaintext( SECRET_SIZE );
memset( plaintext, 'A', SECRET_SIZE );

////////////////////////////////////////////////
// Encrypt

// Now that there is a concrete object, we can validate
assert( 0 != encryptor.FixedMaxPlaintextLength() );
assert( plaintext.size() <= encryptor.FixedMaxPlaintextLength() );

// Create cipher text space
size_t ecl = encryptor.CiphertextLength( plaintext.size() );
assert( 0 != ecl );
SecByteBlock ciphertext( ecl );

encryptor.Encrypt( rng, plaintext, plaintext.size(), ciphertext );

////////////////////////////////////////////////
// Decrypt

// Now that there is a concrete object, we can check sizes
assert( 0 != decryptor.FixedCiphertextLength() );
assert( ciphertext.size() <= decryptor.FixedCiphertextLength() );

// Create recovered text space
size_t dpl = decryptor.MaxPlaintextLength( ciphertext.size() );
assert( 0 != dpl );
SecByteBlock recovered( dpl );

DecodingResult result = decryptor.Decrypt( rng,
    ciphertext, ciphertext.size(), recovered );

// More sanity checks
assert( result.isValidCoding );
assert( result.messageLength <= decryptor.MaxPlaintextLength( ciphertext.size() ) );

// At this point, we can set the size of the recovered
//  data. Until decryption occurs (successfully), we
//  only know its maximum size
recovered.resize( result.messageLength );

// SecByteBlock is overloaded for proper results below
assert( plaintext == recovered );

// If the assert fires, we won't get this far.
if(plaintext == recovered)
    cout << "Recovered plain text" << endl;
else
    cout << "Failed to recover plain text" << endl;

Symmetric Encryption

Crypto++ ElGamal objects offer SymmetricEncrypt and SymmetricDecrypt. The functions will encrypt and decrypt arbitrary length text under a symmertic key, and then encrypt the symmetric key under the ElGamal public key.

You can find the source code for SymmetricEncrypt and SymmetricDecrypt in elgamal.h.

ElGamal Signatures

There is no implementation of ElGamal signatures as propoesd by Taher ElGamal. Rather, the Crypto++ library provides the modified ElGamal signature scheme as proposed by Nyberg and Rueppel and standardized in IEEE P1363. From the Readme.txt under the Crypto++ 3.0 changes:

Renamed ElGamalSignature to NR and changed it to track IEEE P1363

If you need the original ElGamal signature scheme, then you should download it from an archive.

Downloads

cryptopp-elgamal.zip - Demonstrates ElGamal public key encryption.

cryptopp-elgamal-keys.zip - Demonstrates loading and saving ElGamal private keys.