我尝试通过网络从用C编写的服务器向用Java编写的客户端发送RSA公钥。当客户端收到模数时,它应该使用模数和公共指数F4重新创建RSA密钥,服务器也在使用F4。
下面是服务器生成和发送密钥的过程:
//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版本的客户端,它可以正确地重新创建它从服务器接收的信息。这可能是与在Java中签名的BigInteger有关的东西,但我也尝试插入一个额外的前导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);
2条答案
按热度按时间5f0d552i1#
Java的输出是SubjectPublicKeyInfo(或SPKI)格式的RSA公钥,而C代码则是PKCS#1格式的RSA公钥。
我已经很多年没有使用openssl了,但是在看过openssl 3.0的文档后,我发现使用EVP_PKEY类型的函数是最好的选择,
i2d_PUBKEY
函数将返回一个SPKI编码的公钥。sigwle7e2#
通过网络发送套接字时,Java使用Big-Endian,而C使用Little-Endian。Java客户端收到数据后,尝试将其从小端转换为大端。您可以在客户端使用ByteBuffer。
所以试试这个:
您还可以尝试:
请参阅:C++ Client to a Java Server(TCP/IP)