【问题标题】:Send RSA public key over network from C to Java通过网络从 C 向 Java 发送 RSA 公钥
【发布时间】:2014-08-03 03:45:39
【问题描述】:

我正在尝试通过网络发送一个 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 并将字节数组扩展为 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);

【问题讨论】:

  • 当前是同一台机器?
  • 不,他们正在通过套接字进行通信。
  • 您忽略了recv() 返回的计数,并假设读取已填满缓冲区。它没有义务这样做。你必须循环直到你有你需要的一切。
  • 你说得对,我省略了那部分以便专注于真正的问题。它循环直到它接收到足够的字节来填充 public_key_mod 的整个字节数组。
  • 可能只是两个库为键打印了不同的结构。 Java 使用 PKCS#1 公钥格式作为getEncoded() 的结果。我不知道您如何检索二进制数据以在 C 中打印,因此我无法对此发表评论。能否将二进制数据打印为十六进制字符串并放入问题中?

标签: java c sockets networking rsa


【解决方案1】:

对于通过网络发送套接字,Java 使用 Big-Endian,而 C 使用 little-Endian。 Java客户端收到数据后,尝试将其从小端转换为大端。您可以在客户端使用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)

【讨论】:

  • C 使用平台使用的任何内容。默认情况下它不是小端,他没有提到他的平台。 -1
  • 正如我所提到的,我正确地收到了模数,并且在更新中你看到了这种情况,所以这个答案对这个特定问题没有帮助。在其他情况下,确实需要考虑字节顺序,尤其是对于整数等。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-21
  • 1970-01-01
  • 2015-02-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多