+ if(!c->outctx)
+ c->outctx = xmalloc(sizeof(*c->outctx));
+cp
+ /* Copy random data to the buffer */
+
+ RAND_bytes(c->outkey, len);
+
+ /* The message we send must be smaller than the modulus of the RSA key.
+ By definition, for a key of k bits, the following formula holds:
+
+ 2^(k-1) <= modulus < 2^(k)
+
+ Where ^ means "to the power of", not "xor".
+ This means that to be sure, we must choose our message < 2^(k-1).
+ This can be done by setting the most significant bit to zero.
+ */
+
+ c->outkey[0] &= 0x7F;
+
+ if(debug_lvl >= DEBUG_SCARY_THINGS)
+ {
+ bin2hex(c->outkey, buffer, len);
+ buffer[len*2] = '\0';
+ syslog(LOG_DEBUG, _("Generated random meta key (unencrypted): %s"), buffer);
+ }
+
+ /* Encrypt the random data
+
+ We do not use one of the PKCS padding schemes here.
+ This is allowed, because we encrypt a totally random string
+ with a length equal to that of the modulus of the RSA key.
+ */
+
+ if(RSA_public_encrypt(len, c->outkey, buffer, c->rsa_key, RSA_NO_PADDING) != len)
+ {
+ syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), c->name, c->hostname);
+ return -1;
+ }
+cp
+ /* Convert the encrypted random data to a hexadecimal formatted string */
+
+ bin2hex(buffer, buffer, len);
+ buffer[len*2] = '\0';
+
+ /* Send the meta key */
+
+ x = send_request(c, "%d %s", METAKEY, buffer);
+
+ /* Further outgoing requests are encrypted with the key we just generated */
+
+ EVP_EncryptInit(c->outctx, EVP_bf_cfb(),
+ c->outkey + len - EVP_bf_cfb()->key_len,
+ c->outkey + len - EVP_bf_cfb()->key_len - EVP_bf_cfb()->iv_len);
+
+ c->status.encryptout = 1;
+cp
+ return x;
+}
+
+int metakey_h(connection_t *c)
+{
+ char buffer[MAX_STRING_SIZE];
+ int len;
+cp
+ if(sscanf(c->buffer, "%*d "MAX_STRING, buffer) != 1)
+ {
+ syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "METAKEY", c->name, c->hostname);
+ return -1;
+ }
+cp
+ len = RSA_size(myself->connection->rsa_key);
+
+ /* Check if the length of the meta key is all right */
+
+ if(strlen(buffer) != len*2)
+ {
+ syslog(LOG_ERR, _("Possible intruder %s (%s): %s"), c->name, c->hostname, "wrong keylength");
+ return -1;
+ }
+
+ /* Allocate buffers for the meta key */
+cp
+ if(!c->inkey)
+ c->inkey = xmalloc(len);
+
+ if(!c->inctx)
+ c->inctx = xmalloc(sizeof(*c->inctx));
+
+ /* Convert the challenge from hexadecimal back to binary */
+cp
+ hex2bin(buffer,buffer,len);
+
+ /* Decrypt the meta key */
+cp
+ if(RSA_private_decrypt(len, buffer, c->inkey, myself->connection->rsa_key, RSA_NO_PADDING) != len) /* See challenge() */
+ {
+ syslog(LOG_ERR, _("Error during encryption of meta key for %s (%s)"), c->name, c->hostname);
+ return -1;
+ }
+
+ if(debug_lvl >= DEBUG_SCARY_THINGS)
+ {
+ bin2hex(c->inkey, buffer, len);
+ buffer[len*2] = '\0';
+ syslog(LOG_DEBUG, _("Received random meta key (unencrypted): %s"), buffer);
+ }
+
+ /* All incoming requests will now be encrypted. */
+cp
+ EVP_DecryptInit(c->inctx, EVP_bf_cfb(),
+ c->inkey + len - EVP_bf_cfb()->key_len,
+ c->inkey + len - EVP_bf_cfb()->key_len - EVP_bf_cfb()->iv_len);