sodiumTest

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

client3.c (6245B)


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