2

我想加密 C++ 客户端和 Java 服务器之间的一些数据。在网上搜索我发现crypto++可以在客户端和java端使用Java类内置的KeyAgreement(顺便说一句,我的项目中已经有bouncycastle jar,如果它比内置的更好,我可以使用它) .

以自身为例,我能够在每一侧执行 DH,但由于密钥大小,我无法让他们就密钥达成一致。

我的 C++ 代码:

// g++ -g3 -ggdb -O0 -I. -I/usr/include/cryptopp dh-agree.cpp -o dh-agree.exe -lcryptopp -lpthread
// g++ -g -O2 -I. -I/usr/include/cryptopp dh-agree.cpp -o dh-agree.exe -lcryptopp -lpthread

#include <iostream>
using std::cout;
using std::cerr;
using std::endl;

#include <sys/socket.h>
#include <sys/types.h>
#include <stdio.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <string>
using std::string;

#include <stdexcept>
using std::runtime_error;

#include "osrng.h"
using CryptoPP::AutoSeededRandomPool;

#include "integer.h"
using CryptoPP::Integer;

#include "nbtheory.h"
using CryptoPP::ModularExponentiation;

#include "dh.h"
using CryptoPP::DH;

#include "secblock.h"
using CryptoPP::SecByteBlock;

#include <hex.h>
using CryptoPP::HexEncoder;

#include <filters.h>
using CryptoPP::StringSink;
int main(int argc, char** argv)
{
    try
    {
        // RFC 5114, 1024-bit MODP Group with 160-bit Prime Order Subgroup
        // http://tools.ietf.org/html/rfc5114#section-2.1
        Integer p("0xB10B8F96A080E01DDE92DE5EAE5D54EC52C99FBCFB06A3C6"
            "9A6A9DCA52D23B616073E28675A23D189838EF1E2EE652C0"
            "13ECB4AEA906112324975C3CD49B83BFACCBDD7D90C4BD70"
            "98488E9C219A73724EFFD6FAE5644738FAA31A4FF55BCCC0"
            "A151AF5F0DC8B4BD45BF37DF365C1A65E68CFDA76D4DA708"
            "DF1FB2BC2E4A4371");

        Integer g("0xA4D1CBD5C3FD34126765A442EFB99905F8104DD258AC507F"
            "D6406CFF14266D31266FEA1E5C41564B777E690F5504F213"
            "160217B4B01B886A5E91547F9E2749F4D7FBD7D3B9A92EE1"
            "909D0D2263F80A76A6A24C087A091F531DBF0A0169B6A28A"
            "D662A4D18E73AFA32D779D5918D08BC8858F4DCEF97C2A24"
            "855E6EEB22B3B2E5");

        Integer q("0xF518AA8781A8DF278ABA4E7D64B7CB9D49462353");        

        // Schnorr Group primes are of the form p = rq + 1, p and q prime. They
        // provide a subgroup order. In the case of 1024-bit MODP Group, the
        // security level is 80 bits (based on the 160-bit prime order subgroup).       

        // For a compare/contrast of using the maximum security level, see
        // dh-agree.zip. Also see http://www.cryptopp.com/wiki/Diffie-Hellman
        // and http://www.cryptopp.com/wiki/Security_level .

        DH dh;
        AutoSeededRandomPool rnd;

        dh.AccessGroupParameters().Initialize(p, q, g);

        if(!dh.GetGroupParameters().ValidateGroup(rnd, 3)) 
            throw runtime_error("Failed to validate prime and generator");

        size_t count = 0;

        p = dh.GetGroupParameters().GetModulus();
        q = dh.GetGroupParameters().GetSubgroupOrder();
        g = dh.GetGroupParameters().GetGenerator();

        // http://groups.google.com/group/sci.crypt/browse_thread/thread/7dc7eeb04a09f0ce
        Integer v = ModularExponentiation(g, q, p);
        if(v != Integer::One())
            throw runtime_error("Failed to verify order of the subgroup");

        //////////////////////////////////////////////////////////////

        SecByteBlock priv(dh.PrivateKeyLength());
        SecByteBlock pub(dh.PublicKeyLength());
        dh.GenerateKeyPair(rnd, priv, pub);
        printf("lengths: %d %d\n",dh.PrivateKeyLength(),dh.PublicKeyLength());
        byte* pubData = pub.data();     
        for(int j = 0; j < pub.size()-1; j++)
            printf("%02X:", pubData[j]);    
        printf("%02X\n", pubData[pub.size()-1]);    
        // Send pub to Java
        sendData(pub.data(),pub.size());
        // Read pubB from Java
        byte pubBbytes[10000];
        int n = readData(pubBbytes,sizeof(pubBbytes));
        SecByteBlock pubB(pubBbytes,n);
        //////////////////////////////////////////////////////////////

        SecByteBlock sharedA(dh.AgreedValueLength());

        if(!dh.Agree(sharedA, priv, pubB))
            throw runtime_error("Failed to reach shared secret (1A)");


        //////////////////////////////////////////////////////////////

        Integer a;

        a.Decode(sharedA.BytePtr(), sharedA.SizeInBytes());
        cout << "Shared secret (A): " << std::hex << a << endl;
    }

    catch(const CryptoPP::Exception& e)
    {
        cerr << e.what() << endl;
        return -2;
    }

    catch(const std::exception& e)
    {
        cerr << e.what() << endl;
        return -1;
    }

    return 0;
}

Java中的服务器代码:

package test;
/*
 * Copyright (c) 1997, 2001, Oracle and/or its affiliates. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Oracle nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.KeyAgreement;
import javax.crypto.spec.DHParameterSpec;

/**
 * This program executes the Diffie-Hellman key agreement protocol
 * between 2 parties: Alice and Bob.
 *
 * By default, preconfigured parameters (1024-bit prime modulus and base
 * generator used by SKIP) are used.
 * If this program is called with the "-gen" option, a new set of
 * parameters is created.
 */

public class DHKeyAgreement2 {

    private DHKeyAgreement2() {}

    public final static String sP = "B10B8F96A080E01DDE92DE5EAE5D54EC52C99FBCFB06A3C6" +
            "9A6A9DCA52D23B616073E28675A23D189838EF1E2EE652C0" +
            "13ECB4AEA906112324975C3CD49B83BFACCBDD7D90C4BD70" +
            "98488E9C219A73724EFFD6FAE5644738FAA31A4FF55BCCC0" +
            "A151AF5F0DC8B4BD45BF37DF365C1A65E68CFDA76D4DA708" +
            "DF1FB2BC2E4A4371";

    public final static String sG = "A4D1CBD5C3FD34126765A442EFB99905F8104DD258AC507F" +
            "D6406CFF14266D31266FEA1E5C41564B777E690F5504F213" +
            "160217B4B01B886A5E91547F9E2749F4D7FBD7D3B9A92EE1" +
            "909D0D2263F80A76A6A24C087A091F531DBF0A0169B6A28A" +
            "D662A4D18E73AFA32D779D5918D08BC8858F4DCEF97C2A24" +
            "855E6EEB22B3B2E5";


    public static void main(String argv[]) {
        try {
            DHKeyAgreement2 keyAgree = new DHKeyAgreement2();
            keyAgree.run();
        } catch (Exception e) {
            System.err.println("Error: " + e);
            System.exit(1);
        }
    }

    private void run() throws Exception {

        DHParameterSpec dhSkipParamSpec;

        // use some pre-generated, default DH parameters
        System.out.println("Using SKIP Diffie-Hellman parameters");
        BigInteger p = new BigInteger(sP,16);
        BigInteger g = new BigInteger(sG,16);
        System.out.println("P " + sP.length() + " is: " + toHexString(p.toByteArray()));
        System.out.println("G " + sG.length() + " is: " + toHexString(g.toByteArray()));
        dhSkipParamSpec = new DHParameterSpec(p,g);
        /*
         * Alice creates her own DH key pair, using the DH parameters from
         * above
         */
        System.out.println("ALICE: Generate DH keypair ...");
        KeyPairGenerator aliceKpairGen = KeyPairGenerator.getInstance("DH");
        aliceKpairGen.initialize(dhSkipParamSpec);
        KeyPair aliceKpair = aliceKpairGen.generateKeyPair();

        // Alice creates and initializes her DH KeyAgreement object
        System.out.println("ALICE: Initialization ...");
        KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH");
        aliceKeyAgree.init(aliceKpair.getPrivate());

        // Alice encodes her public key, and sends it over to Bob.
        byte[] alicePubKeyEnc = aliceKpair.getPublic().getEncoded();
        byte[] alicePrivKeyEnc = aliceKpair.getPrivate().getEncoded();
        System.out.println("Alice pub key size: " + alicePubKeyEnc.length);
        System.out.println("Alice pub key: " + toHexString(alicePubKeyEnc));
        System.out.println("Alice priv key size: " + alicePrivKeyEnc.length);
        System.out.println("Alice priv key: " + toHexString(alicePrivKeyEnc));
        ServerSocket ss = new ServerSocket(5454);
        Socket accept = ss.accept();
        byte[] bobPubKeyEnc = readByteArrayFromSocket(accept);
        System.out.println("Read bob's pubkey: " + toHexString(bobPubKeyEnc));
        sendByteArrayToBob(alicePubKeyEnc);
        System.out.println("Sent Alice's pubkey");

        /*
         * Alice uses Bob's public key for the first (and only) phase
         * of her version of the DH
         * protocol.
         * Before she can do so, she has to instantiate a DH public key
         * from Bob's encoded key material.
         */
        KeyFactory aliceKeyFac = KeyFactory.getInstance("DH");
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(bobPubKeyEnc);
        PublicKey bobPubKey = aliceKeyFac.generatePublic(x509KeySpec);
        System.out.println("ALICE: Execute PHASE1 ...");
        aliceKeyAgree.doPhase(bobPubKey, true);

        /*
         * At this stage, both Alice and Bob have completed the DH key
         * agreement protocol.
         * Both generate the (same) shared secret.
         */
        byte[] aliceSharedSecret = aliceKeyAgree.generateSecret();
        int aliceLen = aliceSharedSecret.length;

        System.out.println("Alice secret: " +
          toHexString(aliceSharedSecret));
    }
}

我的 C++ 输出:

lengths: 20 128
77:61:FD:93:D9:23:38:41:6D:B0:9B:F8:7A:FB:CE:CA:0E:DF:7D:0A:95:F6:B4:55:FF:64:32:03:2C:B5:9C:47:05:06:FF:1B:72:F3:C6:8A:91:68:13:98:DE:56:0C:D6:02:30:C2:4B:DB:AD:0A:B3:7D:2A:7E:DD:13:A8:7C:97:4A:46:79:6A:85:C7:5B:79:29:D8:E5:2B:F4:59:21:B3:29:EA:6A:2F:FB:70:A1:C8:FD:5C:31:E1:92:A9:B0:67:74:65:3D:C1:1B:33:4B:DE:1C:EB:1E:A1:3A:36:29:0F:DF:A2:FA:5D:DA:69:DC:6D:00:D7:76:95:3A:FD:7D:76
sent 128 bytes, remaining 0
Failed to reach shared secret (1A)

并从 Java 输出:

Using SKIP Diffie-Hellman parameters
P 256 is: 00:B1:0B:8F:96:A0:80:E0:1D:DE:92:DE:5E:AE:5D:54:EC:52:C9:9F:BC:FB:06:A3:C6:9A:6A:9D:CA:52:D2:3B:61:60:73:E2:86:75:A2:3D:18:98:38:EF:1E:2E:E6:52:C0:13:EC:B4:AE:A9:06:11:23:24:97:5C:3C:D4:9B:83:BF:AC:CB:DD:7D:90:C4:BD:70:98:48:8E:9C:21:9A:73:72:4E:FF:D6:FA:E5:64:47:38:FA:A3:1A:4F:F5:5B:CC:C0:A1:51:AF:5F:0D:C8:B4:BD:45:BF:37:DF:36:5C:1A:65:E6:8C:FD:A7:6D:4D:A7:08:DF:1F:B2:BC:2E:4A:43:71
G 256 is: 00:A4:D1:CB:D5:C3:FD:34:12:67:65:A4:42:EF:B9:99:05:F8:10:4D:D2:58:AC:50:7F:D6:40:6C:FF:14:26:6D:31:26:6F:EA:1E:5C:41:56:4B:77:7E:69:0F:55:04:F2:13:16:02:17:B4:B0:1B:88:6A:5E:91:54:7F:9E:27:49:F4:D7:FB:D7:D3:B9:A9:2E:E1:90:9D:0D:22:63:F8:0A:76:A6:A2:4C:08:7A:09:1F:53:1D:BF:0A:01:69:B6:A2:8A:D6:62:A4:D1:8E:73:AF:A3:2D:77:9D:59:18:D0:8B:C8:85:8F:4D:CE:F9:7C:2A:24:85:5E:6E:EB:22:B3:B2:E5
ALICE: Generate DH keypair ...
ALICE: Initialization ...
Alice pub key size: 426
Alice pub key: 30:82:01:A6:30:82:01:1B:06:09:2A:86:48:86:F7:0D:01:03:01:30:82:01:0C:02:81:81:00:B1:0B:8F:96:A0:80:E0:1D:DE:92:DE:5E:AE:5D:54:EC:52:C9:9F:BC:FB:06:A3:C6:9A:6A:9D:CA:52:D2:3B:61:60:73:E2:86:75:A2:3D:18:98:38:EF:1E:2E:E6:52:C0:13:EC:B4:AE:A9:06:11:23:24:97:5C:3C:D4:9B:83:BF:AC:CB:DD:7D:90:C4:BD:70:98:48:8E:9C:21:9A:73:72:4E:FF:D6:FA:E5:64:47:38:FA:A3:1A:4F:F5:5B:CC:C0:A1:51:AF:5F:0D:C8:B4:BD:45:BF:37:DF:36:5C:1A:65:E6:8C:FD:A7:6D:4D:A7:08:DF:1F:B2:BC:2E:4A:43:71:02:81:81:00:A4:D1:CB:D5:C3:FD:34:12:67:65:A4:42:EF:B9:99:05:F8:10:4D:D2:58:AC:50:7F:D6:40:6C:FF:14:26:6D:31:26:6F:EA:1E:5C:41:56:4B:77:7E:69:0F:55:04:F2:13:16:02:17:B4:B0:1B:88:6A:5E:91:54:7F:9E:27:49:F4:D7:FB:D7:D3:B9:A9:2E:E1:90:9D:0D:22:63:F8:0A:76:A6:A2:4C:08:7A:09:1F:53:1D:BF:0A:01:69:B6:A2:8A:D6:62:A4:D1:8E:73:AF:A3:2D:77:9D:59:18:D0:8B:C8:85:8F:4D:CE:F9:7C:2A:24:85:5E:6E:EB:22:B3:B2:E5:02:02:02:00:03:81:84:00:02:81:80:25:E7:BD:24:57:C9:59:EE:E0:EC:7A:F3:D6:22:1C:84:68:52:D9:19:40:5F:1B:C6:CB:A9:3A:42:BF:AB:3C:C2:EC:6F:BC:F9:F9:B2:70:AC:A2:E5:CE:36:FC:06:4F:2D:B3:4F:B5:25:D9:59:AD:D6:AD:B6:17:FA:09:76:AE:89:99:91:52:9B:E0:10:1D:9F:AC:50:AF:02:6D:25:F6:E8:DD:B8:6C:51:17:44:59:98:52:4B:E9:75:E1:D1:26:FE:EA:73:EF:C7:89:7F:70:A8:ED:6F:57:28:A4:0F:1B:F8:21:7D:A5:A2:59:B9:74:42:42:45:BA:EC:E2:53:B3:C4
Alice priv key size: 362
Alice priv key: 30:82:01:66:02:01:00:30:82:01:1B:06:09:2A:86:48:86:F7:0D:01:03:01:30:82:01:0C:02:81:81:00:B1:0B:8F:96:A0:80:E0:1D:DE:92:DE:5E:AE:5D:54:EC:52:C9:9F:BC:FB:06:A3:C6:9A:6A:9D:CA:52:D2:3B:61:60:73:E2:86:75:A2:3D:18:98:38:EF:1E:2E:E6:52:C0:13:EC:B4:AE:A9:06:11:23:24:97:5C:3C:D4:9B:83:BF:AC:CB:DD:7D:90:C4:BD:70:98:48:8E:9C:21:9A:73:72:4E:FF:D6:FA:E5:64:47:38:FA:A3:1A:4F:F5:5B:CC:C0:A1:51:AF:5F:0D:C8:B4:BD:45:BF:37:DF:36:5C:1A:65:E6:8C:FD:A7:6D:4D:A7:08:DF:1F:B2:BC:2E:4A:43:71:02:81:81:00:A4:D1:CB:D5:C3:FD:34:12:67:65:A4:42:EF:B9:99:05:F8:10:4D:D2:58:AC:50:7F:D6:40:6C:FF:14:26:6D:31:26:6F:EA:1E:5C:41:56:4B:77:7E:69:0F:55:04:F2:13:16:02:17:B4:B0:1B:88:6A:5E:91:54:7F:9E:27:49:F4:D7:FB:D7:D3:B9:A9:2E:E1:90:9D:0D:22:63:F8:0A:76:A6:A2:4C:08:7A:09:1F:53:1D:BF:0A:01:69:B6:A2:8A:D6:62:A4:D1:8E:73:AF:A3:2D:77:9D:59:18:D0:8B:C8:85:8F:4D:CE:F9:7C:2A:24:85:5E:6E:EB:22:B3:B2:E5:02:02:02:00:04:42:02:40:3C:16:B6:8F:73:CD:9D:0F:19:D5:A7:54:61:FC:A9:AF:3E:79:78:B8:5E:3E:3D:58:52:2F:95:5E:0D:3F:E0:19:92:17:22:B4:06:9A:E4:ED:9D:55:54:3F:1F:DE:20:36:31:5A:AC:58:FB:A3:C2:7E:65:31:A4:F0:43:37:A2:37
Read 128 bytes
Read bob's pubkey: 77:61:FD:93:D9:23:38:41:6D:B0:9B:F8:7A:FB:CE:CA:0E:DF:7D:0A:95:F6:B4:55:FF:64:32:03:2C:B5:9C:47:05:06:FF:1B:72:F3:C6:8A:91:68:13:98:DE:56:0C:D6:02:30:C2:4B:DB:AD:0A:B3:7D:2A:7E:DD:13:A8:7C:97:4A:46:79:6A:85:C7:5B:79:29:D8:E5:2B:F4:59:21:B3:29:EA:6A:2F:FB:70:A1:C8:FD:5C:31:E1:92:A9:B0:67:74:65:3D:C1:1B:33:4B:DE:1C:EB:1E:A1:3A:36:29:0F:DF:A2:FA:5D:DA:69:DC:6D:00:D7:76:95:3A:FD:7D:76
Sent Alice's pubkey
Error: java.security.spec.InvalidKeySpecException: Inappropriate key specification

似乎尽管我在两个程序中都使用了相同的 G 和 P,但在 C++ 中生成的密钥是 128\20 字节长(公共\私有),而在 java 中它们是 426\362 字节长。我想知道在哪里可以在 crypto++ 中设置所需的密钥长度,但还没有发现。我还从上面的代码中删除了一些辅助函数,所以我猜复制粘贴并尝试编译它们是行不通的。如果有人真的想这样做,我将提交我的完整代码。

谢谢

4

0 回答 0