// dependency: libsodium #include #include // #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_public, 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, author_public, 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; }