-
Notifications
You must be signed in to change notification settings - Fork 124
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
lib/crypto.c: add minisign ed25519 public-key cryptography api
- Loading branch information
Showing
10 changed files
with
1,346 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.