sodiumTest

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

sodiumTest.c (12173B)


      1 #! /usr/bin/env sheepy
      2 /* or direct path to sheepy: #! /usr/local/bin/sheepy */
      3 
      4 /* Libsheepy documentation: https://spartatek.se/libsheepy/ */
      5 #include "libsheepyObject.h"
      6 #include "sodium.h"
      7 
      8 // detect entropy quality
      9 #include <fcntl.h>
     10 #include <unistd.h>
     11 #include <sys/ioctl.h>
     12 #include <linux/random.h>
     13 
     14 int urandomfd;
     15 
     16 /* void randombytes(u8 *buffer, size_t size) { */
     17 /* 	read(urandomfd, buffer, size); */
     18 /* } */
     19 
     20 typ struct {
     21 	u8 publicKey[crypto_box_PUBLICKEYBYTES];
     22 	u8 secretKey[crypto_box_SECRETKEYBYTES];
     23 } keyst;
     24 
     25 void newKeys(keyst *keys) {
     26 	crypto_box_keypair(keys->publicKey, keys->secretKey);
     27 }
     28 
     29 typ struct {
     30 	u8 publicKey[crypto_sign_PUBLICKEYBYTES];
     31 	u8 secretKey[crypto_sign_SECRETKEYBYTES];
     32 } signKeyst;
     33 
     34 void newSignKeys(signKeyst *keys) {
     35 	crypto_sign_keypair(keys->publicKey, keys->secretKey);
     36 }
     37 
     38 /* int isZero( const u8 *data, int len ) { */
     39 /* 	int r = 0; */
     40 /*  */
     41 /* 	range(i, len) { */
     42 /* 		r |= data[i]; */
     43 /* 	} */
     44 /*  */
     45 /* 	return r; */
     46 /* } */
     47 
     48 #define MAX_MSG_SIZE 1400
     49 
     50 /* int encrypts(u8 *encrypted, const u8 *pk, const u8 *sk, const u8 *nonce, const u8 *plain, size_t length) { */
     51 /* 	u8 temp_plain[MAX_MSG_SIZE]; */
     52 /* 	u8 temp_encrypted[MAX_MSG_SIZE]; */
     53 /* 	int rc; */
     54 /*  */
     55 /* 	logD("encrypt %zu", length); */
     56 /*  */
     57 /* 	if(length+crypto_box_ZEROBYTES >= MAX_MSG_SIZE) { */
     58 /* 		return -2; */
     59 /* 	} */
     60 /*  */
     61 /* 	memset(temp_plain, 0, crypto_box_ZEROBYTES); */
     62 /* 	memcpy(temp_plain + crypto_box_ZEROBYTES, plain, length); */
     63 /*  */
     64 /* 	rc = crypto_box(temp_encrypted, temp_plain, crypto_box_ZEROBYTES + length, nonce, pk, sk); */
     65 /*  */
     66 /* 	if( rc != 0 ) { */
     67 /* 		return -1; */
     68 /* 	} */
     69 /*  */
     70 /* 	if( isZero(temp_plain, crypto_box_BOXZEROBYTES) != 0 ) { */
     71 /* 		return -3; */
     72 /* 	} */
     73 /*  */
     74 /* 	memcpy(encrypted, temp_encrypted + crypto_box_BOXZEROBYTES, crypto_box_ZEROBYTES + length); */
     75 /*  */
     76 /* 	return crypto_box_ZEROBYTES + length - crypto_box_BOXZEROBYTES; */
     77 /* } */
     78 /*  */
     79 /* int decrypts(u8 plain[], const u8 pk[], const u8 sk[], const u8 nonce[], const u8 encrypted[], int length) { */
     80 /* 	u8 temp_encrypted[MAX_MSG_SIZE]; */
     81 /* 	u8 temp_plain[MAX_MSG_SIZE]; */
     82 /* 	int rc; */
     83 /*  */
     84 /* 	logD("decrypt\n"); */
     85 /*  */
     86 /* 	if(length+crypto_box_BOXZEROBYTES >= MAX_MSG_SIZE) { */
     87 /* 		return -2; */
     88 /* 	} */
     89 /*  */
     90 /* 	memset(temp_encrypted, '\0', crypto_box_BOXZEROBYTES); */
     91 /* 	memcpy(temp_encrypted + crypto_box_BOXZEROBYTES, encrypted, length); */
     92 /*  */
     93 /* 	rc = crypto_box_open(temp_plain, temp_encrypted, crypto_box_BOXZEROBYTES + length, nonce, pk, sk); */
     94 /*  */
     95 /* 	if( rc != 0 ) { */
     96 /* 		return -1; */
     97 /* 	} */
     98 /*  */
     99 /* 	if( isZero(temp_plain, crypto_box_ZEROBYTES) != 0 ) { */
    100 /* 		return -3; */
    101 /* 	} */
    102 /*  */
    103 /* 	memcpy(plain, temp_plain + crypto_box_ZEROBYTES, crypto_box_BOXZEROBYTES + length); */
    104 /*  */
    105 /* 	return crypto_box_BOXZEROBYTES + length - crypto_box_ZEROBYTES; */
    106 /* } */
    107 
    108 // return ciphertext (encrypted message) length
    109 int selPublicEncrypt(u8 *ciphertext/*result*/, size_t csize, const u8 *msg, size_t mlen, const u8 *nonce, const u8 *publicKey, const u8 *secretKey) {
    110 	// csize is ciphertext buffer size
    111   // check is there is enough space in ciphertext
    112 	if (csize < mlen + crypto_box_MACBYTES) ret 0;
    113   if (crypto_box_easy(ciphertext, msg, mlen, nonce, publicKey, secretKey) != 0) ret 0;
    114   ret mlen + crypto_box_MACBYTES;
    115 }
    116 
    117 // return message length
    118 int selPublicDecrypt(u8 *msg/*result*/, size_t msize, const u8 *ciphertext, size_t clen, const u8 *nonce, const u8 *publicKey, const u8 *secretKey) {
    119 	// msize is message buffer size
    120   // check ciphertext has minimal length, the message has to be at least one byte
    121   // check is there is enough space in message buffer
    122 	if (clen <= crypto_box_MACBYTES or msize < clen - crypto_box_MACBYTES) ret 0;
    123   if (crypto_box_open_easy(msg, ciphertext, clen, nonce, publicKey, secretKey) != 0) ret 0;
    124   ret clen - crypto_box_MACBYTES;
    125 }
    126 
    127 int main(int ARGC, char** ARGV) {
    128 
    129   initLibsheepy(ARGV[0]);
    130   setLogMode(LOG_VERBOSE);
    131 
    132   // detect entropy quality
    133   if ((urandomfd = open("/dev/urandom", O_RDONLY)) != -1) {
    134     int c;
    135     if (ioctl(urandomfd, RNDGETENTCNT, &c) == 0 && c < 160) {
    136       logN("This system doesn't provide enough entropy to quickly generate high-quality random numbers.\n"
    137           "Installing the rng-utils/rng-tools, jitterentropy or haveged packages may help.\n"
    138           "On virtualized Linux environments, also consider using virtio-rng.\n"
    139           "The service will not start until enough entropy has been collected.\n", stderr);
    140     }
    141     close(urandomfd);
    142   }
    143   if (sodium_init() == -1) {
    144     logC("Panic! libsodium couldn't be initialized; it is not safe to use");
    145     ret 1;
    146   }
    147 
    148 
    149   ///////////////////////////////////////////////////////////////////////////////////////////////
    150   // public key crypto
    151   keyst alice, bob;
    152 
    153   newKeys(&alice);
    154   newKeys(&bob);
    155 
    156 	u8 nonce[crypto_box_NONCEBYTES];
    157 	randombytes_buf(nonce, sizeof(nonce));
    158 
    159 	char *msg = "12345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568";
    160 
    161 	logI("message: %s\n", msg);
    162 
    163   int elen;
    164 	/* u8 encrypted[1000]; */
    165   /* //elen = encrypts(encrypted, bob.publicKey, alice.secretKey, nonce, msg, strlen(msg)); */
    166   /* elen = crypto_box_easy(encrypted, msg, strlen(msg), nonce, bob.publicKey, alice.secretKey); */
    167 	/* if (elen < 0) { */
    168   /*   logE("failed to encrypt"); */
    169 	/* 	ret 1; */
    170 	/* } */
    171   /* elen = crypto_box_MACBYTES + strlen(msg); */
    172   /*  */
    173 	/* uint8_t decrypted[1000]; */
    174   /* int r; */
    175 	/* //r = decrypts(decrypted, alice.publicKey, bob.secretKey, nonce, encrypted, elen); */
    176   /* r = crypto_box_open_easy(decrypted, encrypted, elen, nonce, alice.publicKey, bob.secretKey); */
    177 	/* if (r < 0) { */
    178   /*   logE("failed to decrypt"); */
    179 	/* 	ret 1; */
    180 	/* } */
    181   /* r = elen - crypto_box_MACBYTES; */
    182   /*  */
    183 	/* decrypted[r] = '\0'; */
    184 	/* logI("decrypted: %s", decrypted); */
    185   close(urandomfd);
    186 
    187 	u8 encrypted[1000];
    188 	u8 decrypted[1000];
    189   int r;
    190   stopwatchStart;
    191   loop(1000) {
    192   r = selPublicEncrypt(encrypted, sizeof(encrypted), msg, strlen(msg), nonce, bob.publicKey, alice.secretKey);
    193   if (!r) {
    194     logE("failed to encrypt");
    195 		ret 1;
    196   }
    197   }
    198   stopwatchLogMs;
    199 
    200   r = selPublicDecrypt(decrypted, sizeof(decrypted), encrypted, r, nonce, alice.publicKey, bob.secretKey);
    201   if (!r) {
    202     logE("failed to decrypt");
    203 		ret 1;
    204   }
    205 	decrypted[r] = '\0';
    206 	logI("decrypted: %s", decrypted);
    207 
    208 
    209   //////////////////////////////////////////////////////////////////////////////////////////////
    210   // public key signature
    211 
    212   signKeyst rob;
    213   newSignKeys(&rob);
    214 
    215 
    216   char *m = "bonjour";
    217 
    218   logD("crypto_sign_BYTES %d", crypto_sign_BYTES);
    219 
    220   u8 signed_message[crypto_sign_BYTES + 2000] = init0Var;
    221   unsigned long long signed_message_len = 0;
    222 
    223   logVarG(msg);
    224 
    225   logVarG(crypto_sign(signed_message, &signed_message_len, m, strlen(m), rob.secretKey));
    226 
    227   logVarG(crypto_sign_BYTES);
    228   logVarG((u64)signed_message_len);
    229 
    230   loghex(signed_message, sizeof signed_message);
    231   put
    232 
    233   logD("%s", signed_message);
    234 
    235   u8 unsigned_message[2000] = init0Var;
    236   unsigned long long unsigned_message_len;
    237   if (crypto_sign_open(unsigned_message, &unsigned_message_len, signed_message, signed_message_len, rob.publicKey) != 0) {
    238       logE("incorrect signature!");
    239   }
    240   else {
    241     logP("Correct signature");
    242   }
    243 
    244   //////////////////////////////////////////////////////////////////////////////////////////////
    245   // one shot encryption with secret key
    246   u8 k1[crypto_secretbox_KEYBYTES];
    247 
    248   crypto_secretbox_keygen(k1);
    249 
    250   // TODO generate nonce
    251 
    252   stopwatchStart;
    253   loop(1000) {
    254   elen = crypto_secretbox_easy(encrypted, msg, strlen(msg), nonce, k1);
    255   if (elen < 0) {
    256     logE("failed to encrypt");
    257 		ret 1;
    258   }
    259   elen = crypto_secretbox_MACBYTES + strlen(msg);
    260   }
    261   stopwatchLogMs;
    262 
    263   r = crypto_secretbox_open_easy(decrypted, encrypted, elen, nonce, k1);
    264 	if (r < 0) {
    265     logE("failed to decrypt");
    266 		return 1;
    267 	}
    268   r = elen - crypto_secretbox_MACBYTES;
    269 
    270 	decrypted[r] = '\0';
    271 	logI("decrypted: %s", decrypted);
    272 
    273 
    274   //////////////////////////////////////////////////////////////////////////////////////////////
    275   // password hash key derivation and one shot encryption
    276   // https://doc.libsodium.org/password_hashing/default_phf
    277   // Keep in mind that to produce the same key from the same password,
    278   // the same algorithm, the same salt, and the same values for opslimit
    279   // and memlimit must be used. Therefore, these parameters must be stored for each user.
    280 
    281   logD("crypto_pwhash_PASSWD_MIN %"PRIu64,crypto_pwhash_PASSWD_MIN);
    282   logD("crypto_pwhash_PASSWD_MAX %"PRIu64,crypto_pwhash_PASSWD_MAX);
    283   logD("crypto_pwhash_BYTES_MIN %"PRIu64,crypto_pwhash_BYTES_MIN);
    284   logD("crypto_pwhash_BYTES_MAX %"PRIu64,crypto_pwhash_BYTES_MAX);
    285   logD("crypto_pwhash_OPSLIMIT_MIN %"PRIu64,crypto_pwhash_OPSLIMIT_MIN);
    286   logD("crypto_pwhash_OPSLIMIT_MAX %"PRIu64,crypto_pwhash_OPSLIMIT_MAX);
    287   logD("crypto_pwhash_MEMLIMIT_MIN %"PRIu64,crypto_pwhash_MEMLIMIT_MIN);
    288   logD("crypto_pwhash_MEMLIMIT_MAX %"PRIu64,crypto_pwhash_MEMLIMIT_MAX);
    289 
    290   #define PASSWORDp "Correct Horse Battery Staple"
    291 
    292 	unsigned char saltp[crypto_pwhash_SALTBYTES]  = init0Var; // save the salt
    293 	unsigned char keyp[crypto_secretbox_KEYBYTES] = init0Var;
    294 
    295 	randombytes_buf(saltp, sizeof saltp);
    296 
    297   stopwatchStart;
    298 	if (crypto_pwhash
    299 	(keyp, sizeof keyp, PASSWORDp, strlen(PASSWORDp), saltp,
    300 	crypto_pwhash_OPSLIMIT_SENSITIVE, crypto_pwhash_MEMLIMIT_SENSITIVE,
    301 	crypto_pwhash_ALG_DEFAULT) != 0) {
    302 		logE("out of memory");
    303 	}
    304   stopwatchLogMs;
    305 
    306   loghex(keyp, sizeof keyp);put;
    307 
    308 	logD("encrypt/decrypt data with the generated key from password");
    309 
    310   elen = crypto_secretbox_easy(encrypted, msg, strlen(msg), nonce, keyp);
    311   if (elen < 0) {
    312     logE("failed to encrypt");
    313 		ret 1;
    314   }
    315   elen = crypto_secretbox_MACBYTES + strlen(msg);
    316 
    317 	logD("elen %d %d", elen, crypto_secretbox_MACBYTES);
    318 
    319   r = crypto_secretbox_open_easy(decrypted, encrypted, elen, nonce, keyp);
    320 	if (r < 0) {
    321     logE("failed to decrypt");
    322 		return 1;
    323 	}
    324   r = elen - crypto_secretbox_MACBYTES;
    325 
    326 	decrypted[r] = '\0';
    327 	logI("decrypted: %s", decrypted);
    328 
    329   //////////////////////////////////////////////////////////////////////////////////////////////
    330   // password hash password storage
    331 
    332   // key derivation
    333   #define PASSWORD "Correct Horse Battery Staple"
    334   #define KEY_LEN crypto_box_SEEDBYTES
    335 	u8 salt[crypto_pwhash_SALTBYTES];
    336 	u8 key[KEY_LEN];
    337 
    338   logVarG(KEY_LEN);
    339   logVarG(crypto_secretstream_xchacha20poly1305_KEYBYTES);
    340 
    341 	randombytes_buf(salt, sizeof salt);
    342 
    343 	if (crypto_pwhash(
    344        key, sizeof key, PASSWORD, strlen(PASSWORD), salt,
    345 			 crypto_pwhash_OPSLIMIT_INTERACTIVE, crypto_pwhash_MEMLIMIT_INTERACTIVE,
    346 			 crypto_pwhash_ALG_DEFAULT) != 0) {
    347 			logE("out of memory");
    348 	}
    349 
    350   // password hashing
    351   #define PASSWORD2 "Correct Horse Battery Staple"
    352   char hashed_PASSWORD2[crypto_pwhash_STRBYTES];
    353 
    354   logI("Hashing password");
    355   if (crypto_pwhash_str
    356           (hashed_PASSWORD2, PASSWORD2, strlen(PASSWORD2),
    357                 crypto_pwhash_OPSLIMIT_MODERATE, crypto_pwhash_MEMLIMIT_MODERATE) != 0) {
    358       logE("out of memory");
    359   }
    360 
    361   logI("Verifying password");
    362   //#define PASSWORD3 "Correct Horse Battery Stapl"
    363   #define PASSWORD3 PASSWORD2
    364   if (crypto_pwhash_str_verify
    365           (hashed_PASSWORD2, PASSWORD3, strlen(PASSWORD3)) != 0) {
    366       logE("wrong password");
    367   }
    368   else {
    369     logP("Password ok");
    370   }
    371   ret 0;
    372 }
    373 // vim: set expandtab ts=2 sw=2: