summaryrefslogtreecommitdiff
path: root/security.c
diff options
context:
space:
mode:
Diffstat (limited to 'security.c')
-rw-r--r--security.c161
1 files changed, 161 insertions, 0 deletions
diff --git a/security.c b/security.c
new file mode 100644
index 0000000..79dd2c2
--- /dev/null
+++ b/security.c
@@ -0,0 +1,161 @@
+// dependency: libsodium
+#include <sodium.h>
+#include <string.h>
+//
+#include "common.c"
+
+#if crypto_box_PUBLICKEYBYTES != 32 || crypto_box_SECRETKEYBYTES != 32
+ #error currently, moonpaste requires 32 bytes length for public key and private key each.
+#endif
+
+#if crypto_sign_BYTES != 64
+ #error moonpaste needs 64 bytes length for signature.
+#endif
+
+#ifndef SIGN_PUBLICKEYBYTES
+ #define SIGN_PUBLICKEYBYTES crypto_sign_PUBLICKEYBYTES
+#endif
+#ifndef SIGN_SECRETKEYBYTES
+ #define SIGN_SECRETKEYBYTES crypto_sign_SECRETKEYBYTES
+#endif
+
+typedef unsigned char sign_public_key[ SIGN_PUBLICKEYBYTES ];
+typedef unsigned char sign_secret_key[ SIGN_SECRETKEYBYTES ];
+
+typedef struct {
+ public_key encryption_pub;
+ private_key encryption_priv;
+ sign_public_key signing_pub;
+ sign_secret_key signing_priv;
+} keypair;
+
+typedef struct {
+ bool is_valid;
+ byte data[ 65536 - crypto_box_MACBYTES - crypto_box_NONCEBYTES ];
+} plain_payload;
+
+typedef struct {
+ byte nonce[ crypto_box_NONCEBYTES ];
+ byte encrypted_data[ 65536 - crypto_box_NONCEBYTES ];
+ byte signature[ crypto_sign_BYTES ];
+} secure_payload;
+
+bool has_called_sodium_init = false;
+
+void init_sec() {
+ if (unlikely(!has_called_sodium_init)) {
+ if (sodium_init() == -1) {
+ fprintf(stderr, "sodium init failed\n");
+ exit(1);
+ }
+ has_called_sodium_init = true;
+ }
+}
+
+keypair generate_keypair() {
+ init_sec();
+ keypair new;
+ crypto_box_keypair(new.encryption_pub, new.encryption_priv);
+ crypto_sign_keypair(new.signing_pub, new.signing_priv);
+ return new;
+}
+
+secure_payload
+encrypt_and_sign(plain_payload input, keypair author_keys, public_key target_encryption_public) {
+ init_sec();
+
+ secure_payload output;
+ randombytes_buf(output.nonce, crypto_box_NONCEBYTES);
+
+ if (crypto_box_easy(
+ output.encrypted_data,
+ input.data,
+ sizeof(input.data),
+ output.nonce,
+ target_encryption_public,
+ author_keys.encryption_priv)
+ != 0) {
+ fprintf(stderr, "sodium encryption failed\n");
+ exit(1);
+ }
+
+ byte message_to_sign[ crypto_box_NONCEBYTES + sizeof(output.encrypted_data) ];
+ memcpy(message_to_sign, output.nonce, crypto_box_NONCEBYTES);
+ memcpy(
+ message_to_sign + crypto_box_NONCEBYTES,
+ output.encrypted_data,
+ sizeof(output.encrypted_data));
+
+ if (crypto_sign_detached(
+ output.signature,
+ NULL,
+ message_to_sign,
+ sizeof(message_to_sign),
+ author_keys.signing_priv)
+ != 0) {
+ fprintf(stderr, "sodium signing failed\n");
+ exit(1);
+ }
+
+ return output;
+}
+
+plain_payload decrypt(secure_payload input, keypair target_keys, public_key author_signing_public) {
+ init_sec();
+
+ plain_payload output;
+ output.is_valid = true;
+
+ byte message_to_verify[ crypto_box_NONCEBYTES + sizeof(input.encrypted_data) ];
+ memcpy(message_to_verify, input.nonce, crypto_box_NONCEBYTES);
+ memcpy(
+ message_to_verify + crypto_box_NONCEBYTES,
+ input.encrypted_data,
+ sizeof(input.encrypted_data));
+
+ if (crypto_sign_verify_detached(
+ input.signature, message_to_verify, sizeof(message_to_verify), author_signing_public)
+ != 0) {
+ output.is_valid = false;
+ return output;
+ }
+
+ if (crypto_box_open_easy(
+ output.data,
+ input.encrypted_data,
+ sizeof(input.encrypted_data),
+ input.nonce,
+ target_keys.encryption_pub,
+ target_keys.encryption_priv)
+ != 0) {
+ fprintf(stderr, "sodium decryption failed\n");
+ exit(1);
+ }
+
+ return output;
+}
+
+bool verify_signature(secure_payload input, public_key author_signing_public) {
+ init_sec();
+
+ byte message_to_verify[ crypto_box_NONCEBYTES + sizeof(input.encrypted_data) ];
+ memcpy(message_to_verify, input.nonce, crypto_box_NONCEBYTES);
+ memcpy(
+ message_to_verify + crypto_box_NONCEBYTES,
+ input.encrypted_data,
+ sizeof(input.encrypted_data));
+
+ return crypto_sign_verify_detached(
+ input.signature, message_to_verify, sizeof(message_to_verify), author_signing_public)
+ == 0;
+}
+
+bool verify_raw_signature(
+ const byte* msg,
+ size_t msg_len,
+ const signature signature,
+ const sign_public_key author_signing_public) {
+ init_sec();
+ if (msg == NULL || signature == NULL || author_signing_public == NULL) return false;
+ return crypto_sign_verify_detached(signature, msg, msg_len, author_signing_public) == 0;
+} \ No newline at end of file