通过网络将RSA公钥从C发送到Java

时间:2014-06-12 17:49:54

标签: java c sockets networking rsa

我正在尝试通过网络发送RSA公钥,从用c编写的服务器发送到用Java编写的客户端。当客户端收到模数时,它应该使用模数和公共指数F4重新创建RSA密钥,服务器也在使用它。

以下是服务器生成和发送密钥的方式:

//Generate RSA key in C
RSA          *rsa;
int           bits = 1024;  
unsigned long exp  = RSA_F4;
BIGNUM       *bn;
BIGNUM       *MyModPubKey;

bn = BN_new();
BN_set_word(bn, exp);
rsa = RSA_new();
RSA_generate_key_ex(rsa, bits, bn, NULL);
MyModPubKey = rsa->n;

//Send RSA modulus in C
unsigned char public_key_Mod[128];
unsigned char *PubMod;
int PubModLen;


PubMod    = (unsigned char *)&public_key_Mod;
PubModLen = BN_bn2bin(MyModPubKey, PubMod);
assert(PubModLen == 128);
send(sd, public_key_Mod, 128, 0);

以下是如何在Java中重新创建密钥。省略了异常处理。

//Read the modulus
byte[] public_key_mod = new byte[128];
is.read(public_key_mod, 0, 128);


//Create BigInteger modulus and exponent
BigInteger RxPubKeyMod = new BigInteger(1, public_key_mod);             
BigInteger RxPubKeyExp = RSAKeyGenParameterSpec.F4;
PublicKey RxRsaPubKey = KeyFactory.getInstance("RSA").generatePublic(
                    new RSAPublicKeySpec(RxPubKeyMod, RxPubKeyExp));

但是,Java中生成的公共RSA密钥与C中的密钥不同。通过打印base64编码版本的密钥验证。 我还在两端打印模数和指数,并验证它们是否相同。这是怎么做到的:

//Java
System.out.println("RxPubKeyExp: " + RxPubKeyExp.toString(16));
System.out.println("RxPubKeyMod: " + RxPubKeyMod.toString(16));

//C
printf("PubKeyExp %s \n", BN_bn2hex(MyModPubKey->e));
printf("PubKeyMod %s \n", BN_bn2hex(MyModPubKey->n));

他们是一样的。

我无法弄清楚为什么这不起作用。我错过了一些重要的事情。复杂因素是我有一个C版本的客户端,它可以正确地重新创建从服务器收到的信息。它可能是BigInteger用Java签名的东西,但我也尝试插入额外的前导0x00并将bytearray扩展为129字节,结果相同(生成密钥相同)。

拜托,我完全卡住了。 感谢

更新:

以下是C服务器的示例输出:

PubKeyExp 010001 
PubKeyMod A8CB09C2B84762A8C822F18C9CA48036E0D9988C9D8625BF5F2DF16FDEEC92D018863E129C0AE89EB0C344FD32DFF419548C39BB41A867293BC4BD84A1ECAEB0D723EEA97BD2651AF8BD56B2C97D38A39111A0C48894BC034371C2EDB96F1E2E9CDDA9B16DFBE80580ADFDA3853445120F7429AD60300E31254864041210B0BB 

PublicKey -----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAKjLCcK4R2KoyCLxjJykgDbg2ZiMnYYlv18t8W/e7JLQGIY+EpwK6J6w
w0T9Mt/0GVSMObtBqGcpO8S9hKHsrrDXI+6pe9JlGvi9VrLJfTijkRGgxIiUvAND
ccLtuW8eLpzdqbFt++gFgK39o4U0RRIPdCmtYDAOMSVIZAQSELC7AgMBAAE=
-----END RSA PUBLIC KEY-----

以这种方式打印:

printf("PubKeyExp %s \n", BN_bn2hex(MyModPubKey->e));
printf("PubKeyMod %s \n", BN_bn2hex(MyModPubKey->n));
FILE *fp;
char *pubKeyString;
pubKeyString = calloc(1, 512);
if(!(fp = fmemopen(pubKeyString, 512, "w"))) {
   exit(1);
}
PEM_write_RSAPublicKey(fp, pubKey);
fflush(fp);
fclose(fp);
printf("PublicKey %s \n",pubKeyString);

其中pubKey = rsa如上所述

以下是Java服务器的示例输出:

RxPubKeyExp: 10001
RxPubKeyMod: a8cb09c2b84762a8c822f18c9ca48036e0d9988c9d8625bf5f2df16fdeec92d018863e129c0ae89eb0c344fd32dff419548c39bb41a867293bc4bd84a1ecaeb0d723eea97bd2651af8bd56b2c97d38a39111a0c48894bc034371c2edb96f1e2e9cdda9b16dfbe80580adfda3853445120f7429ad60300e31254864041210b0bb
RxRsaPubKey: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCoywnCuEdiqMgi8YycpIA24NmYjJ2GJb9fLfFv3uyS0BiGPhKcCuiesMNE/TLf9BlUjDm7QahnKTvEvYSh7K6w1yPuqXvSZRr4vVayyX04o5ERoMSIlLwDQ3HC7blvHi6c3amxbfvoBYCt/aOFNEUSD3QprWAwDjElSGQEEhCwuwIDAQAB

以这种方式打印:

System.out.println("RxPubKeyExp: " + RxPubKeyExp.toString(16));
System.out.println("RxPubKeyMod: " + RxPubKeyMod.toString(16));
String RxRsaPubKeyChar = Base64.encodeToString(RxRsaPubKey.getEncoded(), Base64.DEFAULT);
System.out.println("RxRsaPubKey: " + RxRsaPubKeyChar);

1 个答案:

答案 0 :(得分:-1)

对于通过网络发送套接字,Java使用Big-Endian,而C使用little-Endian。 Java客户端收到数据后,尝试将其从little-endian转换为big-endian。您可以在客户端使用ByteBuffer

所以试试这个:

ByteBuffer bbf = ByteBuffer.allocate(Income_Data.length);
bbf.put(Income_Data);
bbf.order(ByteOrder.BIG_ENDIAN);
byte[] goodData = bbf.array();

您也可以尝试:

ByteBuffer bbf = ByteBuffer.warp(Income_Data);

请参阅:C++ Client to a Java Server(TCP/IP)