Blob PrivateKey::decrypt(const Blob& cipher) const { if (!key) throw CryptoException("Can't decrypt data without private key !"); unsigned key_len = 0; int err = gnutls_privkey_get_pk_algorithm(key, &key_len); if (err < 0) throw CryptoException("Can't read public key length !"); if (err != GNUTLS_PK_RSA) throw CryptoException("Must be an RSA key"); unsigned cypher_block_sz = key_len / 8; if (cipher.size() % cypher_block_sz) throw CryptoException("Unexpected cipher length"); Blob ret; for (auto cb = cipher.cbegin(), ce = cipher.cend(); cb < ce; cb += cypher_block_sz) { const gnutls_datum_t dat {(uint8_t*)(&(*cb)), cypher_block_sz}; gnutls_datum_t out; int err = gnutls_privkey_decrypt_data(key, 0, &dat, &out); if (err != GNUTLS_E_SUCCESS) throw DhtException(std::string("Can't decrypt data: ") + gnutls_strerror(err)); ret.insert(ret.end(), out.data, out.data+out.size); gnutls_free(out.data); } return ret; }
DhtRunner::DhtRunner() { #ifdef _WIN32 WSADATA wsd; if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) throw DhtException("Can't initialize Winsock2"); #endif }
void DhtRunner::doRun(const sockaddr_in* sin4, const sockaddr_in6* sin6, SecureDht::Config config) { dht_.reset(); int s4 = -1, s6 = -1; if (sin4) { s4 = socket(PF_INET, SOCK_DGRAM, 0); if(s4 >= 0) { int rc = bind(s4, (sockaddr*)sin4, sizeof(sockaddr_in)); if(rc < 0) throw DhtException("Can't bind IPv4 socket on " + dht::print_addr((sockaddr*)sin4, sizeof(sockaddr_in))); } } #if 0 if (sin6) { s6 = socket(PF_INET6, SOCK_DGRAM, 0); if(s6 >= 0) { int val = 1; int rc = setsockopt(s6, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&val, sizeof(val)); if(rc < 0) throw DhtException("Can't set IPV6_V6ONLY"); rc = bind(s6, (sockaddr*)sin6, sizeof(sockaddr_in6)); if(rc < 0) throw DhtException("Can't bind IPv6 socket on " + dht::print_addr((sockaddr*)sin6, sizeof(sockaddr_in6))); } } #endif dht_ = std::unique_ptr<SecureDht>(new SecureDht {s4, s6, config}); rcv_thread = std::thread([this,s4,s6]() { try { while (true) { uint8_t buf[4096 * 64]; sockaddr_storage from; socklen_t fromlen; struct timeval tv {.tv_sec = 0, .tv_usec = 250000}; fd_set readfds; FD_ZERO(&readfds); if(s4 >= 0) FD_SET(s4, &readfds); if(s6 >= 0) FD_SET(s6, &readfds); int rc = select(s4 > s6 ? s4 + 1 : s6 + 1, &readfds, nullptr, nullptr, &tv); if(rc < 0) { if(errno != EINTR) { perror("select"); std::this_thread::sleep_for( std::chrono::seconds(1) ); } } if(!running) break; if(rc > 0) { fromlen = sizeof(from); if(s4 >= 0 && FD_ISSET(s4, &readfds)) rc = recvfrom(s4, (char*)buf, sizeof(buf) - 1, 0, (struct sockaddr*)&from, &fromlen); else if(s6 >= 0 && FD_ISSET(s6, &readfds)) rc = recvfrom(s6, (char*)buf, sizeof(buf) - 1, 0, (struct sockaddr*)&from, &fromlen); else break; if (rc > 0) { buf[rc] = 0; { std::lock_guard<std::mutex> lck(sock_mtx); rcv.emplace_back(Blob {buf, buf+rc+1}, std::make_pair(from, fromlen)); } cv.notify_all(); } } } } catch (const std::exception& e) { std::cerr << "Error int DHT networking thread: " << e.what() << std::endl; } if (s4 >= 0) close(s4); if (s6 >= 0) close(s6); });