commit cd1a6da42e8ba5dea2bf9109c01677206aca9e47
Author: Remy Noulin <loader2x@gmail.com>
Date: Thu, 29 Sep 2022 13:53:02 +0200
libsodium examples
.gitignore | 63 ++++++++++
README.md | 26 +++++
client.c | 172 +++++++++++++++++++++++++++
client2.c | 220 +++++++++++++++++++++++++++++++++++
package.yml | 13 +++
sel.c | 153 ++++++++++++++++++++++++
sel.h | 51 ++++++++
server.c | 147 +++++++++++++++++++++++
server2.c | 178 ++++++++++++++++++++++++++++
sodiumTest.c | 373 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
10 files changed, 1396 insertions(+)
Diffstat:
| A | .gitignore | | | 63 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | README.md | | | 26 | ++++++++++++++++++++++++++ |
| A | client.c | | | 172 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | client2.c | | | 220 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | package.yml | | | 13 | +++++++++++++ |
| A | sel.c | | | 153 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | sel.h | | | 51 | +++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | server.c | | | 147 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | server2.c | | | 178 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | sodiumTest.c | | | 373 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
10 files changed, 1396 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,63 @@
+# Vim
+*.sw*
+
+# Debug
+.gdb_history
+
+# Coverage
+*.gcov
+*.gcda
+*.gcno
+
+# Prerequisites
+*.d
+
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Linker output
+*.ilk
+*.map
+*.exp
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Libraries
+*.lib
+*.a
+*.la
+*.lo
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+
+# Debug files
+*.dSYM/
+*.su
+*.idb
+*.pdb
+
+# Kernel Module Compile Results
+*.mod*
+*.cmd
+.tmp_versions/
+modules.order
+Module.symvers
+Mkfile.old
+dkms.conf
diff --git a/README.md b/README.md
@@ -0,0 +1,26 @@
+# Libsodium
+The programs in this repos depend on [sheepy](https://spartatek.se/r/sheepy/file/README.md.html) and [libsodium](https://libsodium.org).
+
+## sodiumTest
+
+In `sodiumTest.c`, I implemented:
+- public key cryptograpy
+- public key signature, the message is signed the secret key and anyone can verify the signature with the public key
+- one shot encryption with secret key. Usage: encrypt a file on disk
+- derive key from password
+- password hashing for storing in a server database
+
+## client.c and server.c
+`client.c` and `server.c` are client and server using public key cryptograpy to exchange messages. This is a simple prototype which uses slow public key algorithms.
+
+`client.c` and `client2.c` have more detail description of how the system works at the file top.
+
+## client2.c and server2.c
+
+`client2.c` and `server2.c` implement a request-response system which supports anonymous clients. The clients don't have to be known in advance by the server.
+The system uses public keys for key exchange and secret keys are derived for symetric key cryptograpy. After the key exchange, the message are send and received using symetric key cryptograpy.
+For each session, the server changes public key to avoid reusing the same key pair and prevent replay attacks. For more nonce randomness, the server provides the first nonce for the client in the key exchange when the session opens.
+The server identity is verified in the client, the trust is established on first use (TOFU).
+The client can have identity keys which are verified by the server when provided during the key exchange. The server should store the client public identity key and link it to a user.
+
+I created `sel.c` to handle the various keys, there are functions that don't take keys as parameters, they use the keys stored in `sel.c` buffers.
diff --git a/client.c b/client.c
@@ -0,0 +1,172 @@
+#! /usr/bin/env sheepy
+
+/*
+client and server are following request/response model.
+
+Steps in client
+- generate keys
+- connect to server
+- send public key
+- store remote public key
+- send encrypted message
+- get encrypted response
+
+Steps in server
+- generate keys
+- start event loop
+- store remote public key
+- send public key
+- get encrypted message
+- send encrypted response
+
+It uses public key encryption which is slow compare to secret/symetric key encryption
+Secret key encryption is between 25 and 50 times faster than public key encryption depending on the CPU.
+With secret key encryption, my computer can encode 4GB/s which is enough (I have 1GB/s network).
+
+The client and server don't have identities, the client can't verify the server and the server can't verify the client
+
+The nonces are not verified, each nonce can be used multiple times, so replay attacks would be successful.
+*/
+
+#include "libsheepyObject.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+
+#include "sel.h"
+
+int main(int ac, char **av) {
+
+ setLogMode(LOG_FUNC);
+
+ if (not selInit()) ret 1;
+
+ // generate keys
+ keyst clientKeys = init0Var;
+
+ newKeys(&clientKeys);
+
+ char *msg = "Hello";
+
+ logI("message: %s\n", msg);
+
+
+ // connect to server
+ int sock;
+ struct sockaddr_in server;
+ struct hostent *hp;
+ int mysock;
+ char buf[128*1024];
+ int rval;
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock < 0){
+ perror("Failed to create socket");
+ }
+
+ server.sin_family = AF_INET;
+
+ hp = gethostbyname(av[1]);
+ if (hp==0) {
+ perror("gethostbyname failed");
+ close(sock);
+ exit(1);
+ }
+
+ memcpy(&server.sin_addr, hp->h_addr, hp->h_length);
+ server.sin_port = htons(5000);
+
+ if (connect(sock,(struct sockaddr *) &server, sizeof(server))){
+ perror("connect failed");
+ close(sock);
+ exit(1);
+ }
+
+ void snd(void *buf, size_t sz) {
+ logVarG(sz);
+ if(send(sock, buf, sz, 0) < 0){
+ perror("send failed");
+ close(sock);
+ exit(1);
+ }
+ }
+
+ void rcv(void *buf, size_t sz) {
+ rval = recv(sock, buf, sizeof(buf), 0);
+ if (rval < 0) {
+ perror("reading message");
+ exit(1);
+ }
+ else if (rval == 0) {
+ logI("Ending connection");
+ close(sock);
+ exit(0);
+ }
+ logVarG(rval);
+ }
+
+ // send public key
+ // store remote public key
+ void getServerPublicKey(void) {
+ snd(&clientKeys.publicKey, sizeof(clientKeys.publicKey));
+ rval = recv(sock, &clientKeys.remotePublicKey, sizeof(clientKeys.remotePublicKey), MSG_WAITALL);
+ if (rval < 0) {
+ perror("reading message");
+ exit(1);
+ }
+ else if (rval == 0) {
+ logI("Ending connection");
+ close(sock);
+ exit(0);
+ }
+ logVarG(rval);
+
+ logD("Remote public key");
+ loghex(clientKeys.remotePublicKey, sizeof(clientKeys.remotePublicKey));
+ put;
+ }
+
+ getServerPublicKey();
+
+ // send encrypted message
+ //randombytes_buf(clientKeys.nonce, sizeof(clientKeys.nonce));
+ int len = selPublicEncrypt(buf, sizeof(buf), msg, strlen(msg), &clientKeys);
+
+ logVarG(len);
+
+ snd(&len, sizeof(len));
+ snd(buf, len);
+
+ // get encrypted response
+ rcv(&len, sizeof(len));
+ rval = recv(sock, buf, len, MSG_WAITALL);
+ if (rval < 0) {
+ perror("reading message");
+ exit(1);
+ }
+ else if (rval == 0) {
+ logI("Ending connection");
+ close(sock);
+ exit(0);
+ }
+ logVarG(rval);
+
+ clientKeys.nonce[0] = 1;
+
+ u8 decrypted[1000];
+ len = selPublicDecrypt(decrypted, sizeof(decrypted), buf, rval, &clientKeys);
+
+ if (!len) {
+ logE("failed to decrypt");
+ ret 1;
+ }
+
+ decrypted[len] = 0;
+
+ logI("decrypted: %s", decrypted);
+
+ close(sock);
+}
+// vim: set expandtab ts=2 sw=2:
diff --git a/client2.c b/client2.c
@@ -0,0 +1,220 @@
+#! /usr/bin/env sheepy
+
+/*
+client2 and server2 are following request/response model.
+
+Steps in client
+- generate keys
+- connect to server
+- send signature, identity public key, session public key, write 0 for id key and signature if
+ the client doesn't have an id
+- check server identity with signature, store nonce
+- store remote public key
+- send encrypted message
+- get encrypted response
+
+Steps in server
+- generate keys
+- start event loop
+- store remote session public key
+- check identity with signature
+- send signature, identity public key, session public key, nonce
+- get encrypted message
+- send encrypted response
+
+This version uses secret/symetric key encryption after the key exchange.
+
+For more nonce randomness, the server can provide the first nonce with the public keys when the session opens
+
+>> when sending large amount of data, use stream functions
+>> use aead functions only if there are metadata
+>> privelege separation: have a seperate process with the secrets
+>> to change id: sign id public key, sign id public key and signature and the new id public key with the new id key
+
+*/
+
+#include "libsheepyObject.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+
+#include "sel.h"
+
+int main(int ac, char **av) {
+
+ setLogMode(LOG_FUNC);
+
+ if (not selInit()) ret 1;
+
+ // generate keys
+ bool isKnownServer = no;
+ const char* remoteIdFilename = "remoteId.bin";
+ bool sendClientIdToServer = yes;
+
+ newKeys();
+ newSignKeys();
+
+ // load server id if possible
+ if (isPath(remoteIdFilename)) {
+ logI("Server is known");
+ pError0(bLReadFile(remoteIdFilename, remoteId, sizeof(remoteId)));
+ isKnownServer = yes;
+ }
+
+ char *msg = "Hello";
+
+ logI("message: %s\n", msg);
+
+
+ // connect to server
+ int sock;
+ struct sockaddr_in server;
+ struct hostent *hp;
+ int mysock;
+ char buf[128*1024];
+ int rval;
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock < 0){
+ perror("Failed to create socket");
+ }
+
+ server.sin_family = AF_INET;
+
+ hp = gethostbyname(av[1]);
+ if (hp==0) {
+ perror("gethostbyname failed");
+ close(sock);
+ exit(1);
+ }
+
+ memcpy(&server.sin_addr, hp->h_addr, hp->h_length);
+ server.sin_port = htons(5000);
+
+ if (connect(sock,(struct sockaddr *) &server, sizeof(server))){
+ perror("connect failed");
+ close(sock);
+ exit(1);
+ }
+
+ void snd(void *buf, size_t sz) {
+ logVarG(sz);
+ if(send(sock, buf, sz, 0) < 0){
+ perror("send failed");
+ close(sock);
+ exit(1);
+ }
+ }
+
+ void rcv(void *buf, size_t sz) {
+ while (sz > 0) {
+ rval = recv(sock, buf, sz, MSG_WAITALL);
+ if (rval < 0) {
+ perror("reading message");
+ exit(1);
+ }
+ else if (rval == 0) {
+ logI("Ending connection");
+ close(sock);
+ exit(0);
+ }
+ sz -= rval;
+ }
+ logVarG(rval);
+ }
+
+ // send public key
+ // store remote public key
+ void getServerPublicKey(void) {
+ u8 exchange[crypto_sign_BYTES + crypto_sign_PUBLICKEYBYTES + sizeof(keys.publicKey)] = init0Var;
+ memcpy(exchange+crypto_sign_BYTES+crypto_sign_PUBLICKEYBYTES, &keys.publicKey, sizeof(keys.publicKey));
+ if (not sendClientIdToServer) {
+ snd(exchange, sizeof(exchange));
+ }
+ else {
+ // send client id
+ // sign keys with id key
+ memcpy(exchange+crypto_sign_BYTES, &identityKeys.publicKey, sizeof(identityKeys.publicKey));
+ u8 signed_message[sizeof(exchange)] = init0Var;
+ unsigned long long signed_message_len = 0;
+ crypto_sign(signed_message, &signed_message_len, exchange+crypto_sign_BYTES, sizeof(exchange)-crypto_sign_BYTES, identityKeys.secretKey);
+ snd(signed_message, sizeof(signed_message));
+ }
+
+ u8 serverInfo[crypto_sign_BYTES + crypto_sign_PUBLICKEYBYTES + sizeof(keys.remotePublicKey) + crypto_box_NONCEBYTES] = init0Var;
+ rcv(serverInfo, sizeof(serverInfo));
+
+ // check remote server
+ u8 unsigned_message[crypto_sign_PUBLICKEYBYTES + sizeof(keys.remotePublicKey) + crypto_box_NONCEBYTES] = init0Var;
+ unsigned long long unsigned_message_len;
+ const u8 *idPublicKey = remoteId;
+ if (not isKnownServer) {
+ // TOFU - trust on first use
+ idPublicKey = serverInfo + crypto_sign_BYTES;
+ }
+
+ if (crypto_sign_open(unsigned_message, &unsigned_message_len, serverInfo, sizeof(serverInfo), idPublicKey) != 0) {
+ logE("Incorrect signature!");
+ }
+ else {
+ logP("Correct signature");
+ }
+
+ memcpy(keys.remotePublicKey, unsigned_message + crypto_sign_PUBLICKEYBYTES, sizeof(keys.remotePublicKey));
+ memcpy(sessionKeys.nonce, unsigned_message + crypto_sign_PUBLICKEYBYTES + sizeof(keys.remotePublicKey), crypto_box_NONCEBYTES);
+
+ if (not isKnownServer) {
+ // store server id key
+ pError0(writeFile(remoteIdFilename, (u8*)idPublicKey, crypto_sign_PUBLICKEYBYTES));
+ logI("Saved server id");
+ }
+
+ logD("Remote public key");
+ loghex(keys.remotePublicKey, sizeof(keys.remotePublicKey));
+ put;
+
+ // key exchange
+ if (not computeSharedKeys(CLIENT_SESSION_KEYS)) {
+ logE("Invalid server key");
+ exit(1);
+ }
+ }
+
+ getServerPublicKey();
+
+ // send encrypted message
+ // *nonce is incremented by after sending or receiving a message
+ // *nonce is allowed to wrap from the max value
+ u64 *nonce = (u64*)sessionKeys.nonce;
+ logVarG(*nonce);
+ int len = selEncrypt(buf, sizeof(buf), msg, strlen(msg));
+ inc *nonce;
+
+ logVarG(len);
+
+ snd(&len, sizeof(len));
+ snd(buf, len);
+
+ // get encrypted response
+ rcv(&len, sizeof(len));
+ rcv(buf, len);
+
+ u8 decrypted[1000];
+ logVarG(*nonce);
+ len = selDecrypt(decrypted, sizeof(decrypted), buf, len);
+ inc *nonce;
+
+ if (!len) {
+ logE("failed to decrypt");
+ ret 1;
+ }
+
+ decrypted[len] = 0;
+
+ logI("decrypted: %s", decrypted);
+
+ close(sock);
+}
+// vim: set expandtab ts=2 sw=2:
diff --git a/package.yml b/package.yml
@@ -0,0 +1,13 @@
+---
+ name: sodiumTest
+ version: 0.0.1
+ description: "prototypes"
+ bin: ./sodiumTest.c
+ #cflags: -DA -g3 -std=gnu11 -fPIC -pipe
+ lflags: /usr/local/lib/libsodium.a
+ repository:
+ type: git
+ url: git+https://noulin.net/git/sodiumTest.git
+ author: Anonymous
+ license: MIT
+ homepage: https://noulin.net/sodiumTest
diff --git a/sel.c b/sel.c
@@ -0,0 +1,153 @@
+#include "sel.h"
+
+// detect entropy quality
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <linux/random.h>
+
+#include <iso646.h> /* and or not defines */
+
+signKeyst identityKeys = {0};
+u8 remoteId[crypto_sign_PUBLICKEYBYTES] = {0};
+sessionKeyst sessionKeys = {0};
+keyst keys = {0};
+
+int selInit(void) {
+ // detect entropy quality
+ int urandomfd;
+ if ((urandomfd = open("/dev/urandom", O_RDONLY)) != -1) {
+ int c;
+ if (ioctl(urandomfd, RNDGETENTCNT, &c) == 0 && c < 160) {
+ /* logN("This system doesn't provide enough entropy to quickly generate high-quality random numbers.\n" */
+ /* "Installing the rng-utils/rng-tools, jitterentropy or haveged packages may help.\n" */
+ /* "On virtualized Linux environments, also consider using virtio-rng.\n" */
+ /* "The service will not start until enough entropy has been collected.\n", stderr); */
+ close(urandomfd);
+ return 0;
+ }
+ }
+ close(urandomfd);
+ if (sodium_init() == -1) {
+ /* logC("Panic! libsodium couldn't be initialized; it is not safe to use"); */
+ return 0;
+ }
+ return 1;
+}
+
+void newKeys(void) {
+ crypto_box_keypair(keys.publicKey, keys.secretKey);
+}
+
+void newKeysBuf(keyst *keys) {
+ crypto_box_keypair(keys->publicKey, keys->secretKey);
+ /* logD("Public key"); */
+ /* loghex(keys->publicKey, sizeof(keys->publicKey)); */
+ /* put; */
+ /* logD("Secret key"); */
+ /* loghex(keys->secretKey, sizeof(keys->secretKey)); */
+ /* put; */
+}
+
+void newSignKeys(void) {
+ crypto_sign_keypair(identityKeys.publicKey, identityKeys.secretKey);
+}
+
+void newSignKeysBuf(signKeyst *keys) {
+ crypto_sign_keypair(keys->publicKey, keys->secretKey);
+}
+
+// return ciphertext (encrypted message) length
+int selPublicEncrypt(u8 *ciphertext/*result*/, size_t csize, const u8 *msg, size_t mlen, keyst *keys) {
+ // csize is ciphertext buffer size
+ // check is there is enough space in ciphertext
+ if (csize < mlen + crypto_box_MACBYTES) return 0;
+ if (crypto_box_easy(ciphertext, msg, mlen, keys->nonce, keys->remotePublicKey, keys->secretKey) != 0) return 0;
+ return mlen + crypto_box_MACBYTES;
+}
+
+// return message length
+int selPublicDecrypt(u8 *msg/*result*/, size_t msize, const u8 *ciphertext, size_t clen, keyst *keys) {
+ // msize is message buffer size
+ // check ciphertext has minimal length, the message has to be at least one byte
+ // check is there is enough space in message buffer
+ if (clen <= crypto_box_MACBYTES or msize < clen - crypto_box_MACBYTES) return 0;
+ if (crypto_box_open_easy(msg, ciphertext, clen, keys->nonce, keys->remotePublicKey, keys->secretKey) != 0) return 0;
+ return clen - crypto_box_MACBYTES;
+}
+
+int computeSharedKeys(int clientOrServer) {
+ switch (clientOrServer) {
+ case CLIENT_SESSION_KEYS:
+ if (crypto_kx_client_session_keys(sessionKeys.rx, sessionKeys.tx, keys.publicKey, keys.secretKey, keys.remotePublicKey) != 0) {
+ // Suspicious server public key, bail out
+ return 0;
+ }
+ break;
+ case SERVER_SESSION_KEYS:
+ if (crypto_kx_server_session_keys(sessionKeys.rx, sessionKeys.tx, keys.publicKey, keys.secretKey, keys.remotePublicKey) != 0) {
+ // Suspicious server public key, bail out
+ return 0;
+ }
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+int computeSharedKeysBuf(int clientOrServer, sessionKeyst *sessionKeys, keyst *keys) {
+ switch (clientOrServer) {
+ case CLIENT_SESSION_KEYS:
+ if (crypto_kx_client_session_keys(sessionKeys->rx, sessionKeys->tx, keys->publicKey, keys->secretKey, keys->remotePublicKey) != 0) {
+ // Suspicious server public key, bail out
+ return 0;
+ }
+ break;
+ case SERVER_SESSION_KEYS:
+ if (crypto_kx_server_session_keys(sessionKeys->rx, sessionKeys->tx, keys->publicKey, keys->secretKey, keys->remotePublicKey) != 0) {
+ // Suspicious server public key, bail out
+ return 0;
+ }
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+int selEncrypt(u8 *ciphertext/*result*/, size_t csize, const u8 *msg, size_t mlen) {
+ // csize is ciphertext buffer size
+ // check is there is enough space in ciphertext
+ if (csize < mlen + crypto_secretbox_MACBYTES) return 0;
+ if (crypto_secretbox_easy(ciphertext, msg, mlen, sessionKeys.nonce, sessionKeys.tx) != 0) return 0;
+ return mlen + crypto_secretbox_MACBYTES;
+}
+
+int selEncryptBuf(u8 *ciphertext/*result*/, size_t csize, const u8 *msg, size_t mlen, const u8 *nonce, const u8 *k) {
+ // csize is ciphertext buffer size
+ // check is there is enough space in ciphertext
+ if (csize < mlen + crypto_secretbox_MACBYTES) return 0;
+ if (crypto_secretbox_easy(ciphertext, msg, mlen, nonce, k) != 0) return 0;
+ return mlen + crypto_secretbox_MACBYTES;
+}
+
+int selDecrypt(u8 *msg/*result*/, size_t msize, const u8 *ciphertext, size_t clen) {
+ // msize is message buffer size
+ // check ciphertext has minimal length, the message has to be at least one byte
+ // check is there is enough space in message buffer
+ if (clen <= crypto_secretbox_MACBYTES or msize < clen - crypto_secretbox_MACBYTES) return 0;
+ if (crypto_secretbox_open_easy(msg, ciphertext, clen, sessionKeys.nonce, sessionKeys.rx) != 0) return 0;
+ return clen - crypto_secretbox_MACBYTES;
+}
+
+int selDecryptBuf(u8 *msg/*result*/, size_t msize, const u8 *ciphertext, size_t clen, const u8 *nonce, const u8 *k) {
+ // msize is message buffer size
+ // check ciphertext has minimal length, the message has to be at least one byte
+ // check is there is enough space in message buffer
+ if (clen <= crypto_secretbox_MACBYTES or msize < clen - crypto_secretbox_MACBYTES) return 0;
+ if (crypto_secretbox_open_easy(msg, ciphertext, clen, nonce, k) != 0) return 0;
+ return clen - crypto_secretbox_MACBYTES;
+}
+
+// vim: set expandtab ts=2 sw=2:
diff --git a/sel.h b/sel.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#include "sodium.h"
+
+#ifndef u8
+#define u8 uint8_t
+#endif
+
+typedef struct {
+ u8 publicKey[crypto_box_PUBLICKEYBYTES];
+ u8 secretKey[crypto_box_SECRETKEYBYTES];
+ u8 remotePublicKey[crypto_box_PUBLICKEYBYTES];
+ u8 nonce[crypto_box_NONCEBYTES];
+} keyst;
+
+typedef struct {
+ u8 rx[crypto_kx_SESSIONKEYBYTES];
+ u8 tx[crypto_kx_SESSIONKEYBYTES];
+ u8 nonce[crypto_box_NONCEBYTES];
+} sessionKeyst;
+
+#define CLIENT_SESSION_KEYS 0
+#define SERVER_SESSION_KEYS 1
+
+typedef struct {
+ u8 publicKey[crypto_sign_PUBLICKEYBYTES];
+ u8 secretKey[crypto_sign_SECRETKEYBYTES];
+} signKeyst;
+
+extern signKeyst identityKeys;
+extern u8 remoteId[crypto_sign_PUBLICKEYBYTES];
+extern sessionKeyst sessionKeys;
+extern keyst keys;
+/*
+These functions return 0 when they fail.
+*/
+
+int selInit(void);
+void newKeys(void);
+void newKeysBuf(keyst *keys);
+void newSignKeys(void);
+void newSignKeysBuf(signKeyst *keys);
+int selPublicEncrypt(u8 *ciphertext/*result*/, size_t csize, const u8 *msg, size_t mlen, keyst *keys);
+int selPublicDecrypt(u8 *msg/*result*/, size_t msize, const u8 *ciphertext, size_t clen, keyst *keys);
+int computeSharedKeys(int clientOrServer);
+int computeSharedKeysBuf(int clientOrServer, sessionKeyst *sessionKeys, keyst *clientKeys);
+// secret/symetric key encryption
+int selEncrypt(u8 *ciphertext/*result*/, size_t csize, const u8 *msg, size_t mlen);
+int selEncryptBuf(u8 *ciphertext/*result*/, size_t csize, const u8 *msg, size_t mlen, const u8 *nonce, const u8 *k);
+int selDecrypt(u8 *msg/*result*/, size_t msize, const u8 *ciphertext, size_t clen);
+int selDecryptBuf(u8 *msg/*result*/, size_t msize, const u8 *ciphertext, size_t clen, const u8 *nonce, const u8 *k);
diff --git a/server.c b/server.c
@@ -0,0 +1,147 @@
+#! /usr/bin/env sheepy
+
+#include "libsheepyObject.h"
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include "sel.h"
+
+int main(int ac, char **av){
+
+ setLogMode(LOG_FUNC);
+
+ if (not selInit()) ret 1;
+
+ // generate keys
+ keyst serverKeys = init0Var;
+
+ newKeys(&serverKeys);
+
+
+ // start event loop
+ int sock;
+ struct sockaddr_in server;
+ int mysock;
+ char buf[128*1024];
+ int rval;
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock < 0){
+ perror("Failed to create socket");
+ ret 1;
+ }
+
+ server.sin_family = AF_INET;
+ server.sin_addr.s_addr = INADDR_ANY;
+ server.sin_port = htons(5000);
+
+ if (bind(sock, (struct sockaddr *) &server, sizeof(server))){
+ perror("bind failed");
+ ret 1;
+ }
+
+ listen(sock, 5);
+
+ forever {
+ mysock = accept(sock, (struct sockaddr *)0, 0);
+ if (mysock == -1)
+ perror("accept failed");
+ else {
+
+ bool snd(void *buf, size_t sz) {
+ logVarG(sz);
+ if(send(mysock, buf, sz, 0) < 0){
+ perror("send failed");
+ close(mysock);
+ ret no;
+ }
+ ret yes;
+ }
+
+ bool rcv(void *buf, size_t sz) {
+ rval = recv(mysock, buf, sizeof(buf), 0);
+ if (rval < 0) {
+ perror("reading message");
+ ret no;
+ }
+ else if (rval == 0) {
+ logI("Ending connection");
+ close(mysock);
+ ret no;
+ }
+ logVarG(rval);
+ ret yes;
+ }
+
+ /* memset(buf, 0, sizeof(buf)); */
+ /* if ((rval = recv(mysock, buf, sizeof(buf), 0)) < 0) { */
+
+ // store remote public key
+ if ((rval = recv(mysock, &serverKeys.remotePublicKey, sizeof(serverKeys.remotePublicKey), MSG_WAITALL)) < 0) {
+ perror("reading message");
+ close(mysock);
+ continue;
+ }
+ else if (rval == 0) {
+ logI("Ending connection");
+ close(mysock);
+ continue;
+ }
+ if (rval != sizeof(serverKeys.remotePublicKey)) {
+ logW("Didn't get complete client public key");
+ }
+
+ logD("Remote public key");
+ loghex(serverKeys.remotePublicKey, sizeof(serverKeys.remotePublicKey));
+ put;
+
+ // send public key
+ if (!snd(&serverKeys.publicKey, sizeof(serverKeys.publicKey))) continue;
+
+ // get encrypted message
+ int len;
+ if (!rcv(&len, sizeof(len))) continue;
+ rval = recv(mysock, buf, len, MSG_WAITALL);
+ if (rval < 0) {
+ perror("reading message");
+ close(mysock);
+ continue;
+ }
+ else if (rval == 0) {
+ logI("Ending connection");
+ close(mysock);
+ continue;
+ }
+ logVarG(rval);
+
+ u8 decrypted[1000];
+ len = selPublicDecrypt(decrypted, sizeof(decrypted), buf, rval, &serverKeys);
+
+ if (!len) {
+ logE("failed to decrypt");
+ close(mysock);
+ continue;
+ }
+
+ decrypted[len] = 0;
+
+ logI("decrypted: %s", decrypted);
+
+ // send encrypted response
+ serverKeys.nonce[0] = 1;
+
+ char *msg = "OK";
+
+ len = selPublicEncrypt(buf, sizeof(buf), msg, strlen(msg), &serverKeys);
+
+ logVarG(len);
+
+ snd(&len, sizeof(len));
+ snd(buf, len);
+
+ close(mysock);
+ }
+ }
+}
+// vim: set expandtab ts=2 sw=2:
diff --git a/server2.c b/server2.c
@@ -0,0 +1,178 @@
+#! /usr/bin/env sheepy
+
+#include "libsheepyObject.h"
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include "sel.h"
+
+int main(int ac, char **av){
+
+ setLogMode(LOG_FUNC);
+
+ if (not selInit()) ret 1;
+
+ // generate id keys
+ newSignKeys();
+
+
+ // start event loop
+ int sock;
+ struct sockaddr_in server;
+ int mysock;
+ char buf[128*1024];
+ int rval;
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock < 0){
+ perror("Failed to create socket");
+ ret 1;
+ }
+
+ server.sin_family = AF_INET;
+ server.sin_addr.s_addr = INADDR_ANY;
+ server.sin_port = htons(5000);
+
+ if (bind(sock, (struct sockaddr *) &server, sizeof(server))){
+ perror("bind failed");
+ ret 1;
+ }
+
+ listen(sock, 5);
+
+ logI("Server started");
+ forever {
+ mysock = accept(sock, (struct sockaddr *)0, 0);
+ if (mysock == -1)
+ perror("accept failed");
+ else {
+
+ bool snd(void *buf, size_t sz) {
+ logVarG(sz);
+ if(send(mysock, buf, sz, 0) < 0){
+ perror("send failed");
+ close(mysock);
+ ret no;
+ }
+ ret yes;
+ }
+
+ bool rcv(void *buf, size_t sz) {
+ while (sz > 0) {
+ // TODO add timeout
+ rval = recv(mysock, buf, sz, MSG_WAITALL);
+ if (rval < 0) {
+ perror("reading message");
+ ret no;
+ }
+ else if (rval == 0) {
+ logI("Ending connection");
+ close(mysock);
+ ret no;
+ }
+ sz -= rval;
+ }
+ ret yes;
+ }
+
+ // public key for session
+ newKeys();
+ randombytes_buf(sessionKeys.nonce, sizeof(sessionKeys.nonce));
+
+ // store remote public key
+ u8 clientInfo[crypto_sign_BYTES + crypto_sign_PUBLICKEYBYTES + sizeof(keys.remotePublicKey)] = init0Var;
+ rcv(clientInfo, sizeof(clientInfo));
+
+ // check if the clientInfo is signed
+ bool is0 = yes;
+ range(i, crypto_sign_BYTES + crypto_sign_PUBLICKEYBYTES) {
+ if (clientInfo[i]) {
+ is0 = no;
+ break;
+ }
+ }
+
+ if (is0) {
+ logN("Client id not checked");
+ }
+ else {
+ // check client
+ // id key should already be known
+ u8 unsigned_message[crypto_sign_PUBLICKEYBYTES + sizeof(keys.remotePublicKey)] = init0Var;
+ unsigned long long unsigned_message_len;
+
+ if (crypto_sign_open(unsigned_message, &unsigned_message_len, clientInfo, sizeof(clientInfo), clientInfo + crypto_sign_BYTES) != 0) {
+ logE("Incorrect signature!");
+ }
+ else {
+ logP("Correct client signature");
+ }
+ }
+
+ memcpy(keys.remotePublicKey, clientInfo + crypto_sign_BYTES + crypto_sign_PUBLICKEYBYTES, sizeof(keys.remotePublicKey));
+
+ logD("Remote public key");
+ loghex(keys.remotePublicKey, sizeof(keys.remotePublicKey));
+ put;
+
+ // send public key
+ u8 exchange[crypto_sign_PUBLICKEYBYTES + sizeof(keys.publicKey) + crypto_box_NONCEBYTES] = init0Var;
+ u8 signed_message[crypto_sign_BYTES + sizeof(exchange)] = init0Var;
+ unsigned long long signed_message_len = 0;
+
+ memcpy(exchange, identityKeys.publicKey, crypto_sign_PUBLICKEYBYTES);
+ memcpy(exchange + crypto_sign_PUBLICKEYBYTES, keys.publicKey, sizeof(keys.publicKey));
+ memcpy(exchange + crypto_sign_PUBLICKEYBYTES + sizeof(keys.publicKey), sessionKeys.nonce, sizeof(sessionKeys.nonce));
+
+ crypto_sign(signed_message, &signed_message_len, exchange, sizeof(exchange), identityKeys.secretKey);
+
+ if (!snd(signed_message, sizeof(signed_message))) continue;
+
+ // key exchange
+ if (not computeSharedKeys(SERVER_SESSION_KEYS)) {
+ logE("Invalid client key");
+ exit(1);
+ }
+
+ // get encrypted message
+ int len;
+ // *nonce is incremented by after sending or receiving a message
+ // *nonce is allowed to wrap from the max value
+ u64 *nonce = (u64*)sessionKeys.nonce;
+ if (!rcv(&len, sizeof(len))) continue;
+ rcv(buf, len);
+
+ u8 decrypted[1000];
+ logVarG(*nonce);
+ len = selDecrypt(decrypted, sizeof(decrypted), buf, len);
+ inc *nonce;
+
+ if (!len) {
+ logE("failed to decrypt");
+ close(mysock);
+ continue;
+ }
+
+ decrypted[len] = 0;
+
+ logI("decrypted: %s", decrypted);
+
+ // send encrypted response
+
+ char *msg = "OK";
+
+ logVarG(*nonce);
+ len = selEncrypt(buf, sizeof(buf), msg, strlen(msg));
+ inc *nonce;
+
+ logVarG(len);
+
+ snd(&len, sizeof(len));
+ snd(buf, len);
+
+ close(mysock);
+ }
+ }
+}
+// vim: set expandtab ts=2 sw=2:
diff --git a/sodiumTest.c b/sodiumTest.c
@@ -0,0 +1,373 @@
+#! /usr/bin/env sheepy
+/* or direct path to sheepy: #! /usr/local/bin/sheepy */
+
+/* Libsheepy documentation: https://spartatek.se/libsheepy/ */
+#include "libsheepyObject.h"
+#include "sodium.h"
+
+// detect entropy quality
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <linux/random.h>
+
+int urandomfd;
+
+/* void randombytes(u8 *buffer, size_t size) { */
+/* read(urandomfd, buffer, size); */
+/* } */
+
+typ struct {
+ u8 publicKey[crypto_box_PUBLICKEYBYTES];
+ u8 secretKey[crypto_box_SECRETKEYBYTES];
+} keyst;
+
+void newKeys(keyst *keys) {
+ crypto_box_keypair(keys->publicKey, keys->secretKey);
+}
+
+typ struct {
+ u8 publicKey[crypto_sign_PUBLICKEYBYTES];
+ u8 secretKey[crypto_sign_SECRETKEYBYTES];
+} signKeyst;
+
+void newSignKeys(signKeyst *keys) {
+ crypto_sign_keypair(keys->publicKey, keys->secretKey);
+}
+
+/* int isZero( const u8 *data, int len ) { */
+/* int r = 0; */
+/* */
+/* range(i, len) { */
+/* r |= data[i]; */
+/* } */
+/* */
+/* return r; */
+/* } */
+
+#define MAX_MSG_SIZE 1400
+
+/* int encrypts(u8 *encrypted, const u8 *pk, const u8 *sk, const u8 *nonce, const u8 *plain, size_t length) { */
+/* u8 temp_plain[MAX_MSG_SIZE]; */
+/* u8 temp_encrypted[MAX_MSG_SIZE]; */
+/* int rc; */
+/* */
+/* logD("encrypt %zu", length); */
+/* */
+/* if(length+crypto_box_ZEROBYTES >= MAX_MSG_SIZE) { */
+/* return -2; */
+/* } */
+/* */
+/* memset(temp_plain, 0, crypto_box_ZEROBYTES); */
+/* memcpy(temp_plain + crypto_box_ZEROBYTES, plain, length); */
+/* */
+/* rc = crypto_box(temp_encrypted, temp_plain, crypto_box_ZEROBYTES + length, nonce, pk, sk); */
+/* */
+/* if( rc != 0 ) { */
+/* return -1; */
+/* } */
+/* */
+/* if( isZero(temp_plain, crypto_box_BOXZEROBYTES) != 0 ) { */
+/* return -3; */
+/* } */
+/* */
+/* memcpy(encrypted, temp_encrypted + crypto_box_BOXZEROBYTES, crypto_box_ZEROBYTES + length); */
+/* */
+/* return crypto_box_ZEROBYTES + length - crypto_box_BOXZEROBYTES; */
+/* } */
+/* */
+/* int decrypts(u8 plain[], const u8 pk[], const u8 sk[], const u8 nonce[], const u8 encrypted[], int length) { */
+/* u8 temp_encrypted[MAX_MSG_SIZE]; */
+/* u8 temp_plain[MAX_MSG_SIZE]; */
+/* int rc; */
+/* */
+/* logD("decrypt\n"); */
+/* */
+/* if(length+crypto_box_BOXZEROBYTES >= MAX_MSG_SIZE) { */
+/* return -2; */
+/* } */
+/* */
+/* memset(temp_encrypted, '\0', crypto_box_BOXZEROBYTES); */
+/* memcpy(temp_encrypted + crypto_box_BOXZEROBYTES, encrypted, length); */
+/* */
+/* rc = crypto_box_open(temp_plain, temp_encrypted, crypto_box_BOXZEROBYTES + length, nonce, pk, sk); */
+/* */
+/* if( rc != 0 ) { */
+/* return -1; */
+/* } */
+/* */
+/* if( isZero(temp_plain, crypto_box_ZEROBYTES) != 0 ) { */
+/* return -3; */
+/* } */
+/* */
+/* memcpy(plain, temp_plain + crypto_box_ZEROBYTES, crypto_box_BOXZEROBYTES + length); */
+/* */
+/* return crypto_box_BOXZEROBYTES + length - crypto_box_ZEROBYTES; */
+/* } */
+
+// return ciphertext (encrypted message) length
+int selPublicEncrypt(u8 *ciphertext/*result*/, size_t csize, const u8 *msg, size_t mlen, const u8 *nonce, const u8 *publicKey, const u8 *secretKey) {
+ // csize is ciphertext buffer size
+ // check is there is enough space in ciphertext
+ if (csize < mlen + crypto_box_MACBYTES) ret 0;
+ if (crypto_box_easy(ciphertext, msg, mlen, nonce, publicKey, secretKey) != 0) ret 0;
+ ret mlen + crypto_box_MACBYTES;
+}
+
+// return message length
+int selPublicDecrypt(u8 *msg/*result*/, size_t msize, const u8 *ciphertext, size_t clen, const u8 *nonce, const u8 *publicKey, const u8 *secretKey) {
+ // msize is message buffer size
+ // check ciphertext has minimal length, the message has to be at least one byte
+ // check is there is enough space in message buffer
+ if (clen <= crypto_box_MACBYTES or msize < clen - crypto_box_MACBYTES) ret 0;
+ if (crypto_box_open_easy(msg, ciphertext, clen, nonce, publicKey, secretKey) != 0) ret 0;
+ ret clen - crypto_box_MACBYTES;
+}
+
+int main(int ARGC, char** ARGV) {
+
+ initLibsheepy(ARGV[0]);
+ setLogMode(LOG_VERBOSE);
+
+ // detect entropy quality
+ if ((urandomfd = open("/dev/urandom", O_RDONLY)) != -1) {
+ int c;
+ if (ioctl(urandomfd, RNDGETENTCNT, &c) == 0 && c < 160) {
+ logN("This system doesn't provide enough entropy to quickly generate high-quality random numbers.\n"
+ "Installing the rng-utils/rng-tools, jitterentropy or haveged packages may help.\n"
+ "On virtualized Linux environments, also consider using virtio-rng.\n"
+ "The service will not start until enough entropy has been collected.\n", stderr);
+ }
+ close(urandomfd);
+ }
+ if (sodium_init() == -1) {
+ logC("Panic! libsodium couldn't be initialized; it is not safe to use");
+ ret 1;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // public key crypto
+ keyst alice, bob;
+
+ newKeys(&alice);
+ newKeys(&bob);
+
+ u8 nonce[crypto_box_NONCEBYTES];
+ randombytes_buf(nonce, sizeof(nonce));
+
+ char *msg = "12345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568123456812345681234568";
+
+ logI("message: %s\n", msg);
+
+ int elen;
+ /* u8 encrypted[1000]; */
+ /* //elen = encrypts(encrypted, bob.publicKey, alice.secretKey, nonce, msg, strlen(msg)); */
+ /* elen = crypto_box_easy(encrypted, msg, strlen(msg), nonce, bob.publicKey, alice.secretKey); */
+ /* if (elen < 0) { */
+ /* logE("failed to encrypt"); */
+ /* ret 1; */
+ /* } */
+ /* elen = crypto_box_MACBYTES + strlen(msg); */
+ /* */
+ /* uint8_t decrypted[1000]; */
+ /* int r; */
+ /* //r = decrypts(decrypted, alice.publicKey, bob.secretKey, nonce, encrypted, elen); */
+ /* r = crypto_box_open_easy(decrypted, encrypted, elen, nonce, alice.publicKey, bob.secretKey); */
+ /* if (r < 0) { */
+ /* logE("failed to decrypt"); */
+ /* ret 1; */
+ /* } */
+ /* r = elen - crypto_box_MACBYTES; */
+ /* */
+ /* decrypted[r] = '\0'; */
+ /* logI("decrypted: %s", decrypted); */
+ close(urandomfd);
+
+ u8 encrypted[1000];
+ u8 decrypted[1000];
+ int r;
+ stopwatchStart;
+ loop(1000) {
+ r = selPublicEncrypt(encrypted, sizeof(encrypted), msg, strlen(msg), nonce, bob.publicKey, alice.secretKey);
+ if (!r) {
+ logE("failed to encrypt");
+ ret 1;
+ }
+ }
+ stopwatchLogMs;
+
+ r = selPublicDecrypt(decrypted, sizeof(decrypted), encrypted, r, nonce, alice.publicKey, bob.secretKey);
+ if (!r) {
+ logE("failed to decrypt");
+ ret 1;
+ }
+ decrypted[r] = '\0';
+ logI("decrypted: %s", decrypted);
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ // public key signature
+
+ signKeyst rob;
+ newSignKeys(&rob);
+
+
+ char *m = "bonjour";
+
+ logD("crypto_sign_BYTES %d", crypto_sign_BYTES);
+
+ u8 signed_message[crypto_sign_BYTES + 2000] = init0Var;
+ unsigned long long signed_message_len = 0;
+
+ logVarG(msg);
+
+ logVarG(crypto_sign(signed_message, &signed_message_len, m, strlen(m), rob.secretKey));
+
+ logVarG(crypto_sign_BYTES);
+ logVarG((u64)signed_message_len);
+
+ loghex(signed_message, sizeof signed_message);
+ put
+
+ logD("%s", signed_message);
+
+ u8 unsigned_message[2000] = init0Var;
+ unsigned long long unsigned_message_len;
+ if (crypto_sign_open(unsigned_message, &unsigned_message_len, signed_message, signed_message_len, rob.publicKey) != 0) {
+ logE("incorrect signature!");
+ }
+ else {
+ logP("Correct signature");
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ // one shot encryption with secret key
+ u8 k1[crypto_secretbox_KEYBYTES];
+
+ crypto_secretbox_keygen(k1);
+
+ // TODO generate nonce
+
+ stopwatchStart;
+ loop(1000) {
+ elen = crypto_secretbox_easy(encrypted, msg, strlen(msg), nonce, k1);
+ if (elen < 0) {
+ logE("failed to encrypt");
+ ret 1;
+ }
+ elen = crypto_secretbox_MACBYTES + strlen(msg);
+ }
+ stopwatchLogMs;
+
+ r = crypto_secretbox_open_easy(decrypted, encrypted, elen, nonce, k1);
+ if (r < 0) {
+ logE("failed to decrypt");
+ return 1;
+ }
+ r = elen - crypto_secretbox_MACBYTES;
+
+ decrypted[r] = '\0';
+ logI("decrypted: %s", decrypted);
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ // password hash key derivation and one shot encryption
+ // https://doc.libsodium.org/password_hashing/default_phf
+ // Keep in mind that to produce the same key from the same password,
+ // the same algorithm, the same salt, and the same values for opslimit
+ // and memlimit must be used. Therefore, these parameters must be stored for each user.
+
+ logD("crypto_pwhash_PASSWD_MIN %"PRIu64,crypto_pwhash_PASSWD_MIN);
+ logD("crypto_pwhash_PASSWD_MAX %"PRIu64,crypto_pwhash_PASSWD_MAX);
+ logD("crypto_pwhash_BYTES_MIN %"PRIu64,crypto_pwhash_BYTES_MIN);
+ logD("crypto_pwhash_BYTES_MAX %"PRIu64,crypto_pwhash_BYTES_MAX);
+ logD("crypto_pwhash_OPSLIMIT_MIN %"PRIu64,crypto_pwhash_OPSLIMIT_MIN);
+ logD("crypto_pwhash_OPSLIMIT_MAX %"PRIu64,crypto_pwhash_OPSLIMIT_MAX);
+ logD("crypto_pwhash_MEMLIMIT_MIN %"PRIu64,crypto_pwhash_MEMLIMIT_MIN);
+ logD("crypto_pwhash_MEMLIMIT_MAX %"PRIu64,crypto_pwhash_MEMLIMIT_MAX);
+
+ #define PASSWORDp "Correct Horse Battery Staple"
+
+ unsigned char saltp[crypto_pwhash_SALTBYTES] = init0Var; // save the salt
+ unsigned char keyp[crypto_secretbox_KEYBYTES] = init0Var;
+
+ randombytes_buf(saltp, sizeof saltp);
+
+ stopwatchStart;
+ if (crypto_pwhash
+ (keyp, sizeof keyp, PASSWORDp, strlen(PASSWORDp), saltp,
+ crypto_pwhash_OPSLIMIT_SENSITIVE, crypto_pwhash_MEMLIMIT_SENSITIVE,
+ crypto_pwhash_ALG_DEFAULT) != 0) {
+ logE("out of memory");
+ }
+ stopwatchLogMs;
+
+ loghex(keyp, sizeof keyp);put;
+
+ logD("encrypt/decrypt data with the generated key from password");
+
+ elen = crypto_secretbox_easy(encrypted, msg, strlen(msg), nonce, keyp);
+ if (elen < 0) {
+ logE("failed to encrypt");
+ ret 1;
+ }
+ elen = crypto_secretbox_MACBYTES + strlen(msg);
+
+ logD("elen %d %d", elen, crypto_secretbox_MACBYTES);
+
+ r = crypto_secretbox_open_easy(decrypted, encrypted, elen, nonce, keyp);
+ if (r < 0) {
+ logE("failed to decrypt");
+ return 1;
+ }
+ r = elen - crypto_secretbox_MACBYTES;
+
+ decrypted[r] = '\0';
+ logI("decrypted: %s", decrypted);
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ // password hash password storage
+
+ // key derivation
+ #define PASSWORD "Correct Horse Battery Staple"
+ #define KEY_LEN crypto_box_SEEDBYTES
+ u8 salt[crypto_pwhash_SALTBYTES];
+ u8 key[KEY_LEN];
+
+ logVarG(KEY_LEN);
+ logVarG(crypto_secretstream_xchacha20poly1305_KEYBYTES);
+
+ randombytes_buf(salt, sizeof salt);
+
+ if (crypto_pwhash(
+ key, sizeof key, PASSWORD, strlen(PASSWORD), salt,
+ crypto_pwhash_OPSLIMIT_INTERACTIVE, crypto_pwhash_MEMLIMIT_INTERACTIVE,
+ crypto_pwhash_ALG_DEFAULT) != 0) {
+ logE("out of memory");
+ }
+
+ // password hashing
+ #define PASSWORD2 "Correct Horse Battery Staple"
+ char hashed_PASSWORD2[crypto_pwhash_STRBYTES];
+
+ logI("Hashing password");
+ if (crypto_pwhash_str
+ (hashed_PASSWORD2, PASSWORD2, strlen(PASSWORD2),
+ crypto_pwhash_OPSLIMIT_MODERATE, crypto_pwhash_MEMLIMIT_MODERATE) != 0) {
+ logE("out of memory");
+ }
+
+ logI("Verifying password");
+ //#define PASSWORD3 "Correct Horse Battery Stapl"
+ #define PASSWORD3 PASSWORD2
+ if (crypto_pwhash_str_verify
+ (hashed_PASSWORD2, PASSWORD3, strlen(PASSWORD3)) != 0) {
+ logE("wrong password");
+ }
+ else {
+ logP("Password ok");
+ }
+ ret 0;
+}
+// vim: set expandtab ts=2 sw=2: