Skip to content

Commit

Permalink
lib/crypto.c: add minisign ed25519 public-key cryptography api
Browse files Browse the repository at this point in the history
  • Loading branch information
Duncaen committed Feb 25, 2023
1 parent c78231f commit ffbefa2
Show file tree
Hide file tree
Showing 10 changed files with 1,346 additions and 1 deletion.
2 changes: 1 addition & 1 deletion include/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ all:
install:
install -d $(DESTDIR)$(INCLUDEDIR)/xbps
install -m 644 $(INCS) $(DESTDIR)$(INCLUDEDIR)
for f in array bool data dictionary number object string; do \
for f in array bool data dictionary number object string crypto; do \
install -m 644 xbps/xbps_$${f}.h $(DESTDIR)$(INCLUDEDIR)/xbps; \
done

Expand Down
346 changes: 346 additions & 0 deletions include/xbps/crypto.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,346 @@
#ifndef XBPS_CRYPTO_H
#define XBPS_CRYPTO_H

#include <sodium.h>

/** @addtogroup crypto */
/**@{*/

#define B64_ENCODED_LEN(BIN_LEN) \
sodium_base64_ENCODED_LEN(BIN_LEN, sodium_base64_VARIANT_ORIGINAL)

/**
*/
struct xbps_hash_state {
crypto_generichash_state hs;
};

/**
* @struct xbps_hash
* @brief BLAKE2b hash.
*/
struct xbps_hash {
unsigned char mem[crypto_generichash_BYTES_MAX];
};

/**
* @brief Initialize hash state.
*/
static inline int
xbps_hash_init(struct xbps_hash_state *state)
{
return crypto_generichash_init(&state->hs, NULL, 0U, crypto_generichash_BYTES_MAX);
}

/**
* @brief Update the hash state with new data.
*/
static inline int
xbps_hash_update(struct xbps_hash_state *state,
const unsigned char *in, unsigned long long inlen)
{
return crypto_generichash_update(&state->hs, in, inlen);
}

/**
* @brief Finalize the hash state and return the final hash.
*/
static inline int
xbps_hash_final(struct xbps_hash_state *state, struct xbps_hash *hash)
{
return crypto_generichash_final(&state->hs, hash->mem, sizeof(hash->mem));
}

/**
* @brief Hash a file.
*
* @param[out] hash ::xbps_hash struct to store the hash.
* @param[in] path Path of the file to hash.
*
* @return 0 on success or a negative \c errno from \c open(3) or \c read(3).
*/
int xbps_hash_file(struct xbps_hash *hash, const char *path);

/**
* @def SIGALG_HASHED
* @brief Ed25519 public-key signature of the BLAKE2b hash of the message.
*/
/**
* @def SIGALG
* @brief Ed25519 public-key signature of the message.
*/

/**
* @def KEYNUMBYTES
* @brief Number of bytes used for keynum.
*/
#define KEYNUMBYTES 8

/**
* @def COMMENTMAXBYTES
* @brief Maximum bytes of untristed comments including trailing `\0`.
*/
#define COMMENTMAXBYTES 1024

/**
* @def TRUSTEDCOMMENTMAXBYTES
* @brief Maximum bytes of trusted comments including trailing `\0`.
*/
#define TRUSTEDCOMMENTMAXBYTES 8192

/**
* @def SIGBYTES
* @brief Number of bytes of the Ed25519 public-key signature.
*/
#define SIGBYTES crypto_sign_BYTES

/**
* @def PUBLICKEYBYTES
* @brief Number of bytes of the Ed25519 public-key.
*/
#define PUBLICKEYBYTES crypto_sign_PUBLICKEYBYTES

/**
* @def SECRETKEYBYTES
* @brief Number of bytes of the Ed25519 secret-key.
*/
#define SECRETKEYBYTES crypto_sign_SECRETKEYBYTES

/**
* @def HASHBYTES
* @brief Number of bytes for the BLAKE2b hash.
*/
#define HASHBYTES crypto_generichash_BYTES

/**
* @struct xbps_pubkey
* @brief minisign public-key.
*
* Algorithm id, keynum and Ed25519 public-key.
*/
struct xbps_pubkey {
/**
* @var sig_alg
* @brief Algorithm identifier.
*/
unsigned char sig_alg[2];
/**
* @var keynum_pk
* @brief wtf
*/
struct {
/**
* @var keynum
* @brief key identifier
*/
unsigned char keynum[KEYNUMBYTES];
/**
* @var pk
* @brief Ed25519 public-key
*/
unsigned char pk[PUBLICKEYBYTES];
} keynum_pk;
};

#define PUBKEY_ENCODED_LEN (B64_ENCODED_LEN(sizeof(struct xbps_pubkey)))

/**
* @brief Decode a base64 encoded minisign public-key.
* @param[out] pubkey Structure to decode the public-key to.
* @param[in] pubkey_s Encoded public-key.
* @returns \c 0 on success or a negative \c errno.
* @retval -ENOTSUP Public-key specifies a signature algorithm that is not supported.
* @retval -EINVAL Public-key is invalid.
*/
int xbps_pubkey_decode(struct xbps_pubkey *pubkey, const char *pubkey_s);

/**
* @brief Encode a minising public-key using base64.
* @param[in] pubkey Public-key to encode.
* @param[out] pubkey_s Buffer to store the encoded public-key.
* @param[in] pubkey_s_len Size of the \p pubkey_s buffer.
* @returns \c 0 on success or a negative \c errno.
* @retval -ENOBUFS Encoded public-key would exceed the \p pubkey_s buffer.
*/
int xbps_pubkey_encode(const struct xbps_pubkey *pubkey, char *pubkey_s, size_t pubkey_s_len);

/**
* @brief Read a minisign public-key file
* @param[out] pubkey Structure to store the public-key to.
* @param[in] fd File descriptor to read from
* @returns \c 0 on success or a negative \c errno from ::xbps_pubkey_decode, \c open(3) or \c read(3).
* @retval -ENOBUFS Comment or the encoded public-key exceed the maximum size.
*/
int xbps_pubkey_read(struct xbps_pubkey *pubkey, int fd);

int xbps_pubkey_write(const struct xbps_pubkey *pubkey, const char *path);

/**
* @struct xbps_seckey
* @brief minisign secret-key.
*
* Ed25519 secret-key, algorithm id and encryption data.
*/
struct xbps_seckey {
unsigned char sig_alg[2];
unsigned char kdf_alg[2];
unsigned char chk_alg[2];
unsigned char kdf_salt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES];
unsigned char kdf_opslimit_le[8];
unsigned char kdf_memlimit_le[8];
struct {
unsigned char keynum[KEYNUMBYTES];
unsigned char sk[SECRETKEYBYTES];
/**
* @var chk
* @brief BLAKE2b hash of the secret-key.
*
* BLAKE2b hash of the secret-key used to check if the secret-key
* was successfully decrypted.
*/
unsigned char chk[HASHBYTES];
} keynum_sk;
};

/**
* @brief Read and decrypt a secret-key.
* @param[out] seckey Structure to store the read secret-key in.
* @param[in] passphrase Optional passphrase to encrypt the secret-key.
* @param[in] path File descriptor to read from.
* @returns \c 0 on success or a negative \c errno.
* @retval -ENOBUFS Comment or encoded secret-key exceed the maximum size.
* @retval -ENOTSUP Secret-key used an algorithm or encryption that is not supported.
* @retval -EINVAL Secret-key is invalid.
* @retval -ERANGE Secret-key is encrypted but no passphrase was supplied or decryption failed.
* @retval -ENOMEM Secret-key decryption failed due to resource limits.
*/
int xbps_seckey_read(struct xbps_seckey *seckey, const char *passphrase, const char *path);

/**
* @brief Write secret-key to file.
* @param[in] seckey Secret-key to write.
* @param[in] passphrase Optional passphrase to encrypt the secret-key with.
* @param[in] path Path to the file.
* @returns \c 0 on success or a negative \c errno from \c open(3) or \c write(3).
*/
int xbps_seckey_write(const struct xbps_seckey *seckey, const char *passphrase, const char *path);

/**
* @struct xbps_sig
* @brief Ed25519 signature.
*/
struct xbps_sig {
/**
* @var sig_alg
* @brief Signature algorithm.
*
* The signature algorithm, currently only ::SIGALG_HASHED.
*/
unsigned char sig_alg[2];
/**
* @var keynum
* @brief Key identifier.
*
* Cryptographically insecure. This should not be presented to users
* and is just used as a fastpath to check if a signature was signed
* by a different key.
*/
unsigned char keynum[KEYNUMBYTES];
/**
* @var sig
* @brief Ed25519 public-key signature.
*
* Detached Ed25519 pubkey-key signature.
*
* The signature depends on the used ::xbps_sig.sig_alg:
* - ::SIGALG_HASHED: Signed BLAKE2b hash of the message.
* - ::SIGALG: Signature of the message itself, not supported.
*/
unsigned char sig[SIGBYTES];
};

/**
* @struct xbps_minisig
* @brief minisig signature
*/
struct xbps_minisig {
/**
* @var comment
* @brief Untrusted comment in the .minisig file.
*/
char comment[COMMENTMAXBYTES];
/**
* @var sig
* @brief Algorithm, keynum and signature of the signed data.
*/
struct xbps_sig sig;
/**
* @var trusted_comment
* @brief Trusted comment in the .minisig file.
*/
char trusted_comment[TRUSTEDCOMMENTMAXBYTES];
/**
* @var global_sig
* @brief Signature of ::xbps_minisig.sig and ::xbps_minisig.trusted_comment.
*
* The global signature signs the signature and the trusted comment.
*/
unsigned char global_sig[SIGBYTES];
};

/**
* @brief Read a minisig file.
* @param[out] minisig ::xbps_minisig struct to store the read data.
* @param[in] path Path to the .minisig file.
* @returns \c 0 on success or a negative \c errno from \c open(3), \c read(3).
* @retval -ENOBUFS Comments or the encoded signature exceed the maximum size.
*/
int xbps_minisig_read(struct xbps_minisig *minisig, const char *path);

/**
* @brief Write a minisig file.
* @param[in] minisig The ::xbps_minisig structure that is written
* @param[in] path Path to write to
* @returns \c 0 on success or a negative \c errno from \c open(3), \c write(3).
*/
int xbps_minisig_write(const struct xbps_minisig *minisig, const char *path);

/**
* @brief Sign a minisig ::xbps_minisig.
* @param[out] minisig The ::xbps_minisig that is being signed and stores the signatures.
* @param[in] seckey Secret-key used to sign.
* @param[in] hash The hash of the message that is begin signed.
* @returns \c 0 on success or a negative \c errno.
* @retval -EINVAL Signing failed.
*/
int xbps_minisig_sign(struct xbps_minisig *minisig, const struct xbps_seckey *seckey,
const struct xbps_hash *hash);

/**
* @brief Verify a minisig ::xbps_minisig.
* @param[in] minisig The ::xbps_minisig that is being verified.
* @param[in] pubkey Public-key used to verify the ::xbps_minisig.
* @param[in] hash The hash of the message that is being verified.
* @returns \c 0 on success or a negative \c errno.
* @retval -EINVAL \c keynum of \p pubkey does not match signature.
* @retval -ERANGE Signature verification failed.
*/
int xbps_minisig_verify(const struct xbps_minisig *minisig, const struct xbps_pubkey *pubkey,
const struct xbps_hash *hash);

/**
* @brief Generate a new key pair.
*
* Generates a new public- and secret-key pair.
*
* @param[out] seckey ::xbps_seckey to store the generated secret-key.
* @param[out] pubkey ::xbps_pubkey to store the generated public-key.
*
* @return 0 on success or a negative \c errno.
* @retval -EINVAL Failure during keypair generation.
*/
int xbps_generate_keypair(struct xbps_seckey *seckey, struct xbps_pubkey *pubkey);

/**@}*/

#endif
1 change: 1 addition & 0 deletions lib/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ OBJS += repo.o repo_sync.o
OBJS += rpool.o cb_util.o proplib_wrapper.o
OBJS += package_alternatives.o
OBJS += conf.o log.o
OBJS += crypto.o
OBJS += $(EXTOBJS) $(COMPAT_OBJS)
# unnecessary unless pkgdb format changes
# OBJS += pkgdb_conversion.o
Expand Down
Loading

0 comments on commit ffbefa2

Please sign in to comment.