【问题标题】:ElGamal encryption example?ElGamal 加密示例?
【发布时间】:2013-11-27 06:53:40
【问题描述】:

对于提出这个问题的不礼貌,我提前道歉,但我已经被困了很长时间,我正在努力弄清楚下一步该做什么。本质上,我正在尝试对某些数据执行 ElGamal 加密。我已经获得了一个临时密钥对和第二个静态密钥的公共部分,以及一些数据。如果我的理解是正确的,这就是我执行加密所需的全部内容,但我正在努力弄清楚如何使用 Crypto++。

我无休止地寻找示例,但在 Google 上几乎可以找到零。 Ohloh 并没有什么帮助,因为我刚刚找回了无数页的 cryptopp ElGamal 源文件,我似乎无法弄清楚(我对使用 Crypto++ 比较陌生,直到大约 3 天前甚至还没有听说过 ElGamal)。

我能找到的最接近的例子来自 CryptoPP 包本身,如下所示:

bool ValidateElGamal()
{
    cout << "\nElGamal validation suite running...\n\n";
    bool pass = true;
    {
        FileSource fc("TestData/elgc1024.dat", true, new HexDecoder);
        ElGamalDecryptor privC(fc);
        ElGamalEncryptor pubC(privC);
        privC.AccessKey().Precompute();
        ByteQueue queue;
        privC.AccessKey().SavePrecomputation(queue);
        privC.AccessKey().LoadPrecomputation(queue);

        pass = CryptoSystemValidate(privC, pubC) && pass;
    }
    return pass;
}

但是,这似乎对我没有多大帮助,因为我不知道如何插入我已经计算的值。我不确定我是否在努力理解 Elgamal 的工作原理(完全可能),或者在使用 CryptoPP 所拥有的东西时我是否只是个白痴。谁能帮我指出正确的方向?

【问题讨论】:

    标签: c++ crypto++ elgamal


    【解决方案1】:

    我获得了一个临时密钥对的公共部分和第二个静态密钥,以及一些数据。

    我们在这里无法真正帮助您,因为我们对应该做什么一无所知。

    临时密钥对可能是用于模拟密钥交换,而静态密钥是长期用于签署临时交换。除此之外,任何人都可以猜测发生了什么。

    你会碰巧知道钥匙是什么吗?临时密钥是 Diffie-Hellman 密钥,静态密钥是 ElGamal 签名密钥吗?


    如果我的理解是正确的,这就是我执行加密所需的全部内容,但我正在努力弄清楚如何使用 Crypto++。

    对于加密示例,我将作弊并使用RSA encryption example 并将其移植到ElGamal。这与复制和粘贴一样困难,因为 RSA 加密和ElGamal encryption 都遵循PK_EncryptorPK_Decryptor 接口。有关详细信息,请参阅 PK_EncryptorPK_Decryptor 类。 (请记住,您可能需要 ElGamal 或 Nyberg-Rueppel (NR) 签名示例)。

    Crypto++ 有一个基于 ElGamal 的密码系统。密码系统将在对称密钥下加密一大块纯文本,然后在 ElGamal 密钥下加密对称密钥。不过,我不确定它遵循什么标准(可能是 IEEE 的 P1363)。请参阅elgamal.h 中的SymmetricEncryptSymmetricDecrypt

    密钥大小人为地变小,因此程序运行得很快。 ElGamal 是一个离散对数问题,因此它的密钥大小在实践中应该是 2048 位或更高。 2048 位得到 ECRYPT(亚洲)、ISO/IEC(全球)、NESSIE(欧洲)和 NIST(美国)的祝福。

    如果您需要保存/保留/加载您生成的密钥,请参阅 Crypto++ wiki 上的 Keys and Formats。简短的回答是致电decryptor.Save()decryptor.Load();并远离{BER|DER} 编码。

    如果需要,您可以使用标准的string 而不是SecByteBlock。如果您有兴趣通过cout 和朋友将内容打印到终端,string 会更容易。

    最后,Crypto++ Wiki 上现在有一个页面涵盖了该主题以及下面程序的源代码。请参阅 Crypto++ 的 ElGamal Encryption

    #include <iostream>
    using std::cout;
    using std::cerr;
    using std::endl;
    
    #include <cryptopp/osrng.h>
    using CryptoPP::AutoSeededRandomPool;
    
    #include <cryptopp/secblock.h>
    using CryptoPP::SecByteBlock;
    
    #include <cryptopp/elgamal.h>
    using CryptoPP::ElGamal;
    using CryptoPP::ElGamalKeys;
    
    #include <cryptopp/cryptlib.h>
    using CryptoPP::DecodingResult;
    
    int main(int argc, char* argv[])
    {
        ////////////////////////////////////////////////
        // Generate keys
        AutoSeededRandomPool rng;
    
        cout << "Generating private key. This may take some time..." << endl;
    
        ElGamal::Decryptor decryptor;
        decryptor.AccessKey().GenerateRandomWithKeySize(rng, 512);
        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;
    
        return !(plaintext == recovered);
    }
    

    您也可以像这样从PrivateKey 创建Decryptor

    ElGamalKeys::PrivateKey k;
    k.GenerateRandomWithKeySize(rng, 512);
    ElGamal::Decryptor d(k);
    ...
    

    还有来自PublicKeyEncryptor

    ElGamalKeys::PublicKey pk;
    privateKey.MakePublicKey(pk);
    ElGamal::Encryptor e(pk);
    

    您可以按如下方式在磁盘中保存和加载密钥:

    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);
    // ...
    

    密钥采用 ASN.1 编码,因此您可以使用 Peter Gutmann 的 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.
    

    【讨论】:

    • 嗨!感谢您的回复,我非常感谢您在那里付出的努力(我非常感谢维基条目,我认为这对每个人都很好)。事实证明,我们客户的要求发生了变化(或者更确切地说,当他们说“Elgamel”时,他们的实际意思是“Diffie-Helman”,并且不知何故在大约 15 个不同的地方犯了同样的错误,并引用了各种 ElGamel 规范和所有内容。 )。无论如何,这可以解释为什么我所说的完全没有意义。我把它留了下来,因为我相信它对许多人来说会是一个有用的帖子,而且我最终可能会需要它。
    猜你喜欢
    • 2022-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多