libDwmCredence-0.0.20220501
DwmCredence Class Library

Introduction

This class library may be used for secure, authenticated network communication over TCP. The main three classes are Dwm::Credence::Peer, Dwm::Credence::KeyStash and Dwm::Credence::KnownKeys. Utilizing just these three classes, it is relatively easy to create secure TCP applications.

The library depends on libsodium, boost::asio and libDwm.

Since I'm using libsodium, I'm using XChaCha20Poly1305 for encryption. User and server authentication uses signatures produced and validated with Ed25519 keys.

No passwords are used, only key files (which aren't password protected). This is intentional since my main usage is in applications that are not launched interactively. I may later add password protected keys.

History

This library came about when I needed a replacement for Crypto++ (needed by libDwmAuth). In my own applications, libDwmAuth will be replaced by libDwmCredence. The new name is a hint that it's not the same as libDwmAuth under the hood, and allows me to migrate my applications as I have time.

Platforms

I only maintain support for 4 platforms: FreeBSD, macOS, desktop linux and Raspbian (now Raspberry Pi OS). FreeBSD is my operating system of choice for servers and macOS is my operating system of choice for desktops and laptops. I have several Raspberry Pis I utilize for various tasks, and Ubuntu VMs and Ubuntu workstations.

Examples

Assumptions

The examples assume that you have created your key files by running credence keygen, and that they are present in the default directory (~/.credence). They also assume that you have your own public key (from ~/.credence/id_ed25519.pub) in the default ~/.credence/known_keys file.

Simple echo

Simple echo client

1#include "DwmCredencePeer.hh"
2
3int main(int argc, char *argv[])
4{
5 using namespace std;
6 using namespace Dwm;
7
8 int rc = 1;
9
10 if (argc < 3) {
11 cerr << "Usage: " << argv[0] << " host port\n";
12 return 1;
13 }
14
15 Credence::Peer peer;
16 if (peer.Connect(argv[1], std::stoul(argv[2]))) {
17 Credence::KeyStash keyStash;
18 Credence::KnownKeys knownKeys;
19 if (peer.Authenticate(keyStash, knownKeys)) {
20 rc = 0;
21 string msg;
22 while (std::getline(cin, msg)) {
23 if (! peer.Send(msg)) { rc = 1; break; }
24 if (! peer.Receive(msg)) { rc = 1; break; }
25 cout << msg << '\n';
26 if (msg == "Goodbye") { break; }
27 }
28 }
29 else {
30 cerr << "Failed to authenticate to " << argv[1]
31 << " port " << argv[2] << '\n';
32 }
33 }
34 else {
35 cerr << "Failed to connect to " << argv[1]
36 << " port " << argv[2] << '\n';
37 }
38
39 return rc;
40}
Dwm::Credence::Peer class declaration.
Encapsulates storage of an Ed25519KeyPair in a filesystem.
Definition: DwmCredenceKeyStash.hh:56
Encapsulates the storage of a set of known public keys.
Definition: DwmCredenceKnownKeys.hh:60
Encapsulate a network peer.
Definition: DwmCredencePeer.hh:67
bool Send(const T &msg)
Sends the given msg to the peer.
Definition: DwmCredencePeer.hh:127
bool Connect(const std::string &host, uint16_t port)
Used by a client to connect to host at the given port.
bool Receive(T &msg)
Receives the given msg from the peer.
Definition: DwmCredencePeer.hh:159
bool Authenticate(const KeyStash &keyStash, const KnownKeys &knownKeys)
Using the given keyStash and knownKeys, authenticate our identity to the peer and verify the peer's i...

Simple echo server

Note that this server only accepts one client, and will exit after communicating with the client. In other words, it's not typical, but instead is a minimal illustration.

1#include "DwmCredencePeer.hh"
2
3using namespace std;
4using namespace boost::asio;
5using namespace Dwm;
6
7static bool AcceptPeer(io_context & ioContext, const string & addr,
8 const string & port, Credence::Peer & peer)
9{
10 bool rc = false;
11 boost::system::error_code ec;
12 ip::tcp::endpoint endPoint(ip::address::from_string(addr),
13 std::stoul(port));
14 ip::tcp::acceptor acc(ioContext, endPoint);
15 boost::asio::ip::tcp::acceptor::reuse_address option(true);
16 acc.set_option(option, ec);
17 if (! ec) {
18 acc.non_blocking(false, ec);
19 if (! ec) {
20 ip::tcp::socket sock(ioContext);
21 ip::tcp::endpoint client;
22 acc.accept(sock, client, ec);
23 if (! ec) {
24 sock.native_non_blocking(false, ec);
25 rc = peer.Accept(std::move(sock));
26 }
27 else { cerr << "accept() failed\n"; }
28 }
29 else { cerr << "Failed to set socket as blocking\n"; }
30 }
31 else { cerr << "Failed to set reuse_addr option\n"; }
32
33 return rc;
34}
35
36
37int main(int argc, char *argv[])
38{
39 if (argc < 3) {
40 cerr << "Usage: " << argv[0] << " addr port\n";
41 return 1;
42 }
43
44 int rc = 1;
45 io_context ioContext;
46 Credence::Peer peer;
47 if (AcceptPeer(ioContext, argv[1], argv[2], peer)) {
48 Credence::KeyStash keyStash;
49 Credence::KnownKeys knownKeys;
50 if (peer.Authenticate(keyStash, knownKeys)) {
51 string msg;
52 while (msg != "Goodbye") {
53 if (! peer.Receive(msg)) { break; }
54 if (! peer.Send(msg)) { break; }
55 }
56 peer.Send(msg);
57 rc = 0;
58 }
59 else {
60 cerr << "Authentication failed\n";
61 }
62 }
63 else {
64 cerr << "AcceptPeer failed\n";
65 }
66
67 return rc;
68}
bool Accept(boost::asio::ip::tcp::socket &&s)
Used by a server to accept a new connection.