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