💾 Archived View for gmi.noulin.net › gitRepositories › sodiumTest › file › client3.c.gmi captured on 2023-07-10 at 18:14:38. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-01-29)
-=-=-=-=-=-=-
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: