我想加密 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++ 中设置所需的密钥长度,但还没有发现。我还从上面的代码中删除了一些辅助函数,所以我猜复制粘贴并尝试编译它们是行不通的。如果有人真的想这样做,我将提交我的完整代码。
谢谢