sodiumTest

Libsodium examples, client/server system
git clone https://noulin.net/git/sodiumTest.git
Log | Files | Refs | README

client2.c (5872B)


      1 #! /usr/bin/env sheepy
      2 
      3 /*
      4 client2 and server2 are following request/response model.
      5 
      6 Steps in client
      7 - generate keys
      8 - connect to server
      9 - send signature, identity public key, session public key, write 0 for id key and signature if
     10   the client doesn't have an id
     11 - check server identity with signature, store nonce
     12 - store remote public key
     13 - send encrypted message
     14 - get encrypted response
     15 
     16 Steps in server
     17 - generate keys
     18 - start event loop
     19 - store remote session public key
     20 - check identity with signature
     21 - send signature, identity public key, session public key, nonce
     22 - get encrypted message
     23 - send encrypted response
     24 
     25 This version uses secret/symetric key encryption after the key exchange.
     26 
     27 For more nonce randomness, the server can provide the first nonce with the public keys when the session opens
     28 
     29 >> when sending large amount of data, use stream functions
     30 >> use aead functions only if there are metadata
     31 >> privelege separation: have a seperate process with the secrets
     32 >> to change id: sign id public key, sign id public key and signature and the new id public key with the new id key
     33 
     34 */
     35 
     36 #include "libsheepyObject.h"
     37 
     38 #include <sys/types.h>
     39 #include <sys/socket.h>
     40 #include <netdb.h>
     41 #include <netinet/in.h>
     42 
     43 #include "sel.h"
     44 
     45 int main(int ac, char **av) {
     46 
     47   setLogMode(LOG_FUNC);
     48 
     49   if (not selInit()) ret 1;
     50 
     51   // generate keys
     52   bool isKnownServer                      = no;
     53   const char* remoteIdFilename            = "remoteId.bin";
     54   bool sendClientIdToServer               = yes;
     55 
     56   newKeys();
     57   newSignKeys();
     58 
     59   // load server id if possible
     60   if (isPath(remoteIdFilename)) {
     61     logI("Server is known");
     62     pError0(bLReadFile(remoteIdFilename, remoteId, sizeof(remoteId)));
     63     isKnownServer = yes;
     64   }
     65 
     66 	char *msg = "Hello";
     67 
     68 	logI("message: %s\n", msg);
     69 
     70 
     71   // connect to server
     72   int sock;
     73   struct sockaddr_in server;
     74   struct hostent *hp;
     75   int mysock;
     76   char buf[128*1024];
     77   int rval;
     78 
     79   sock = socket(AF_INET, SOCK_STREAM, 0);
     80   if (sock < 0){
     81     perror("Failed to create socket");
     82   }
     83 
     84   server.sin_family = AF_INET;
     85 
     86   hp = gethostbyname(av[1]);
     87   if (hp==0) {
     88     perror("gethostbyname failed");
     89     close(sock);
     90     exit(1);
     91   }
     92 
     93   memcpy(&server.sin_addr, hp->h_addr, hp->h_length);
     94   server.sin_port = htons(5000);
     95 
     96   if (connect(sock,(struct sockaddr *) &server, sizeof(server))){
     97     perror("connect failed");
     98     close(sock);
     99     exit(1);
    100   }
    101 
    102   void snd(void *buf, size_t sz) {
    103     logVarG(sz);
    104     if(send(sock, buf, sz, 0) < 0){
    105       perror("send failed");
    106       close(sock);
    107       exit(1);
    108     }
    109   }
    110 
    111   void rcv(void *buf, size_t sz) {
    112     while (sz > 0) {
    113       rval = recv(sock, buf, sz, MSG_WAITALL);
    114       if (rval < 0) {
    115         perror("reading message");
    116         exit(1);
    117       }
    118       else if (rval == 0) {
    119         logI("Ending connection");
    120         close(sock);
    121         exit(0);
    122       }
    123       sz -= rval;
    124     }
    125     logVarG(rval);
    126   }
    127 
    128   // send public key
    129   // store remote public key
    130   void getServerPublicKey(void) {
    131     u8 exchange[crypto_sign_BYTES + crypto_sign_PUBLICKEYBYTES + sizeof(keys.publicKey)] = init0Var;
    132     memcpy(exchange+crypto_sign_BYTES+crypto_sign_PUBLICKEYBYTES, &keys.publicKey, sizeof(keys.publicKey));
    133     if (not sendClientIdToServer) {
    134       snd(exchange, sizeof(exchange));
    135     }
    136     else {
    137       // send client id
    138       // sign keys with id key
    139       memcpy(exchange+crypto_sign_BYTES, &identityKeys.publicKey, sizeof(identityKeys.publicKey));
    140       u8 signed_message[sizeof(exchange)] = init0Var;
    141       unsigned long long signed_message_len = 0;
    142       crypto_sign(signed_message, &signed_message_len, exchange+crypto_sign_BYTES, sizeof(exchange)-crypto_sign_BYTES, identityKeys.secretKey);
    143       snd(signed_message, sizeof(signed_message));
    144     }
    145 
    146     u8 serverInfo[crypto_sign_BYTES + crypto_sign_PUBLICKEYBYTES + sizeof(keys.remotePublicKey) + crypto_box_NONCEBYTES] = init0Var;
    147     rcv(serverInfo, sizeof(serverInfo));
    148 
    149     // check remote server
    150     u8 unsigned_message[crypto_sign_PUBLICKEYBYTES + sizeof(keys.remotePublicKey) + crypto_box_NONCEBYTES] = init0Var;
    151     unsigned long long unsigned_message_len;
    152     const u8 *idPublicKey = remoteId;
    153     if (not isKnownServer) {
    154       // TOFU - trust on first use
    155       idPublicKey = serverInfo + crypto_sign_BYTES;
    156     }
    157 
    158     if (crypto_sign_open(unsigned_message, &unsigned_message_len, serverInfo, sizeof(serverInfo), idPublicKey) != 0) {
    159       logE("Incorrect signature!");
    160     }
    161     else {
    162       logP("Correct signature");
    163     }
    164 
    165     memcpy(keys.remotePublicKey, unsigned_message + crypto_sign_PUBLICKEYBYTES, sizeof(keys.remotePublicKey));
    166     memcpy(sessionKeys.nonce, unsigned_message + crypto_sign_PUBLICKEYBYTES + sizeof(keys.remotePublicKey), crypto_box_NONCEBYTES);
    167 
    168     if (not isKnownServer) {
    169       // store server id key
    170       pError0(writeFile(remoteIdFilename, (u8*)idPublicKey, crypto_sign_PUBLICKEYBYTES));
    171       logI("Saved server id");
    172     }
    173 
    174     logD("Remote public key");
    175     loghex(keys.remotePublicKey, sizeof(keys.remotePublicKey));
    176     put;
    177 
    178     // key exchange
    179     if (not computeSharedKeys(CLIENT_SESSION_KEYS)) {
    180       logE("Invalid server key");
    181       exit(1);
    182     }
    183   }
    184 
    185   getServerPublicKey();
    186 
    187   // send encrypted message
    188   // *nonce is incremented by after sending or receiving a message
    189   // *nonce is allowed to wrap from the max value
    190   u64 *nonce = (u64*)sessionKeys.nonce;
    191   logVarG(*nonce);
    192   int len = selEncrypt(buf, sizeof(buf), msg, strlen(msg));
    193   inc *nonce;
    194 
    195   logVarG(len);
    196 
    197   snd(&len, sizeof(len));
    198   snd(buf, len);
    199 
    200   // get encrypted response
    201   rcv(&len, sizeof(len));
    202   rcv(buf, len);
    203 
    204 	u8 decrypted[1000];
    205   logVarG(*nonce);
    206   len = selDecrypt(decrypted, sizeof(decrypted), buf, len);
    207   inc *nonce;
    208 
    209   if (!len) {
    210     logE("failed to decrypt");
    211     ret 1;
    212   }
    213 
    214   decrypted[len] = 0;
    215 
    216   logI("decrypted: %s", decrypted);
    217 
    218   close(sock);
    219 }
    220 // vim: set expandtab ts=2 sw=2: