diff options
Diffstat (limited to 'security.c')
| -rw-r--r-- | security.c | 161 |
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 |
