Envoyer la clé publique RSA sur le réseau de C à Java


J'essaie d'envoyer une clé publique RSA sur le réseau, d'un serveur écrit en c à un client écrit en Java. Lorsque le client reçoit le module, il doit recréer la clé RSA en utilisant le module et l'exposant public F4, que le serveur utilise également.

Voici comment le serveur génère et envoie la clé:

//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);

Voici comment la clé est recréée en Java. Gestion des exceptions omise.

//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));

Cependant, la clé RSA publique générée en Java n'est pas identique à celui en C. Vérifié en imprimant la version encodée en base64 des clés. J'imprime également le module et l'exposant aux deux extrémités et vérifie qu'ils sont identiques. Voici comment cela se fait:

//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));

Ils sont les mêmes.

Je ne peux pas comprendre pourquoi cela ne fonctionne pas. Ai-je raté quelque chose d'important ici. Les facteurs compliquant est que j'ai une version C du client, et il peut recréer correctement les informations qu'il reçoit du serveur. C'est peut être quelque chose avec BigInteger être signé en Java, mais j'ai également essayé d'insérer un 0x00 supplémentaire et d'étendre le bytearray à 129 octets, avec un résultat identique (même clé générée).

S'il vous plait, je suis complètement coincé. Merci

MISE À JOUR:

Voici un exemple de sortie du serveur C:

PubKeyExp 010001 
PubKeyMod A8CB09C2B84762A8C822F18C9CA48036E0D9988C9D8625BF5F2DF16FDEEC92D018863E129C0AE89EB0C344FD32DFF419548C39BB41A867293BC4BD84A1ECAEB0D723EEA97BD2651AF8BD56B2C97D38A39111A0C48894BC034371C2EDB96F1E2E9CDDA9B16DFBE80580ADFDA3853445120F7429AD60300E31254864041210B0BB 

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

Il est imprimé de cette manière:

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);

Où pubKey=rsa comme créé ci-dessus

Voici un exemple de sortie du serveur Java:

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

Il est imprimé de cette manière:

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);
Author: Andy, 2014-06-12

1 answers

Pour l'envoi de socket sur le réseau, Java utilise Big-Endian, tandis que C utilise little-Endian. Une fois que le client Java a reçu des données, essayez de les convertir de little-endian en big-endian. Vous pouvez utiliser ByteBuffer côté client.

Alors essayez ceci:

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

Vous pouvez également essayer:

ByteBuffer bbf = ByteBuffer.warp(Income_Data);

Veuillez vous référer à: Client C++ vers un serveur Java (TCP/IP)

 -1
Author: feohoTl, 2017-05-23 12:21:26