Skip to content

Commit ffbefa2

Browse files
committed
lib/crypto.c: add minisign ed25519 public-key cryptography api
1 parent c78231f commit ffbefa2

File tree

10 files changed

+1346
-1
lines changed

10 files changed

+1346
-1
lines changed

include/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ all:
1010
install:
1111
install -d $(DESTDIR)$(INCLUDEDIR)/xbps
1212
install -m 644 $(INCS) $(DESTDIR)$(INCLUDEDIR)
13-
for f in array bool data dictionary number object string; do \
13+
for f in array bool data dictionary number object string crypto; do \
1414
install -m 644 xbps/xbps_$${f}.h $(DESTDIR)$(INCLUDEDIR)/xbps; \
1515
done
1616

include/xbps/crypto.h

Lines changed: 346 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,346 @@
1+
#ifndef XBPS_CRYPTO_H
2+
#define XBPS_CRYPTO_H
3+
4+
#include <sodium.h>
5+
6+
/** @addtogroup crypto */
7+
/**@{*/
8+
9+
#define B64_ENCODED_LEN(BIN_LEN) \
10+
sodium_base64_ENCODED_LEN(BIN_LEN, sodium_base64_VARIANT_ORIGINAL)
11+
12+
/**
13+
*/
14+
struct xbps_hash_state {
15+
crypto_generichash_state hs;
16+
};
17+
18+
/**
19+
* @struct xbps_hash
20+
* @brief BLAKE2b hash.
21+
*/
22+
struct xbps_hash {
23+
unsigned char mem[crypto_generichash_BYTES_MAX];
24+
};
25+
26+
/**
27+
* @brief Initialize hash state.
28+
*/
29+
static inline int
30+
xbps_hash_init(struct xbps_hash_state *state)
31+
{
32+
return crypto_generichash_init(&state->hs, NULL, 0U, crypto_generichash_BYTES_MAX);
33+
}
34+
35+
/**
36+
* @brief Update the hash state with new data.
37+
*/
38+
static inline int
39+
xbps_hash_update(struct xbps_hash_state *state,
40+
const unsigned char *in, unsigned long long inlen)
41+
{
42+
return crypto_generichash_update(&state->hs, in, inlen);
43+
}
44+
45+
/**
46+
* @brief Finalize the hash state and return the final hash.
47+
*/
48+
static inline int
49+
xbps_hash_final(struct xbps_hash_state *state, struct xbps_hash *hash)
50+
{
51+
return crypto_generichash_final(&state->hs, hash->mem, sizeof(hash->mem));
52+
}
53+
54+
/**
55+
* @brief Hash a file.
56+
*
57+
* @param[out] hash ::xbps_hash struct to store the hash.
58+
* @param[in] path Path of the file to hash.
59+
*
60+
* @return 0 on success or a negative \c errno from \c open(3) or \c read(3).
61+
*/
62+
int xbps_hash_file(struct xbps_hash *hash, const char *path);
63+
64+
/**
65+
* @def SIGALG_HASHED
66+
* @brief Ed25519 public-key signature of the BLAKE2b hash of the message.
67+
*/
68+
/**
69+
* @def SIGALG
70+
* @brief Ed25519 public-key signature of the message.
71+
*/
72+
73+
/**
74+
* @def KEYNUMBYTES
75+
* @brief Number of bytes used for keynum.
76+
*/
77+
#define KEYNUMBYTES 8
78+
79+
/**
80+
* @def COMMENTMAXBYTES
81+
* @brief Maximum bytes of untristed comments including trailing `\0`.
82+
*/
83+
#define COMMENTMAXBYTES 1024
84+
85+
/**
86+
* @def TRUSTEDCOMMENTMAXBYTES
87+
* @brief Maximum bytes of trusted comments including trailing `\0`.
88+
*/
89+
#define TRUSTEDCOMMENTMAXBYTES 8192
90+
91+
/**
92+
* @def SIGBYTES
93+
* @brief Number of bytes of the Ed25519 public-key signature.
94+
*/
95+
#define SIGBYTES crypto_sign_BYTES
96+
97+
/**
98+
* @def PUBLICKEYBYTES
99+
* @brief Number of bytes of the Ed25519 public-key.
100+
*/
101+
#define PUBLICKEYBYTES crypto_sign_PUBLICKEYBYTES
102+
103+
/**
104+
* @def SECRETKEYBYTES
105+
* @brief Number of bytes of the Ed25519 secret-key.
106+
*/
107+
#define SECRETKEYBYTES crypto_sign_SECRETKEYBYTES
108+
109+
/**
110+
* @def HASHBYTES
111+
* @brief Number of bytes for the BLAKE2b hash.
112+
*/
113+
#define HASHBYTES crypto_generichash_BYTES
114+
115+
/**
116+
* @struct xbps_pubkey
117+
* @brief minisign public-key.
118+
*
119+
* Algorithm id, keynum and Ed25519 public-key.
120+
*/
121+
struct xbps_pubkey {
122+
/**
123+
* @var sig_alg
124+
* @brief Algorithm identifier.
125+
*/
126+
unsigned char sig_alg[2];
127+
/**
128+
* @var keynum_pk
129+
* @brief wtf
130+
*/
131+
struct {
132+
/**
133+
* @var keynum
134+
* @brief key identifier
135+
*/
136+
unsigned char keynum[KEYNUMBYTES];
137+
/**
138+
* @var pk
139+
* @brief Ed25519 public-key
140+
*/
141+
unsigned char pk[PUBLICKEYBYTES];
142+
} keynum_pk;
143+
};
144+
145+
#define PUBKEY_ENCODED_LEN (B64_ENCODED_LEN(sizeof(struct xbps_pubkey)))
146+
147+
/**
148+
* @brief Decode a base64 encoded minisign public-key.
149+
* @param[out] pubkey Structure to decode the public-key to.
150+
* @param[in] pubkey_s Encoded public-key.
151+
* @returns \c 0 on success or a negative \c errno.
152+
* @retval -ENOTSUP Public-key specifies a signature algorithm that is not supported.
153+
* @retval -EINVAL Public-key is invalid.
154+
*/
155+
int xbps_pubkey_decode(struct xbps_pubkey *pubkey, const char *pubkey_s);
156+
157+
/**
158+
* @brief Encode a minising public-key using base64.
159+
* @param[in] pubkey Public-key to encode.
160+
* @param[out] pubkey_s Buffer to store the encoded public-key.
161+
* @param[in] pubkey_s_len Size of the \p pubkey_s buffer.
162+
* @returns \c 0 on success or a negative \c errno.
163+
* @retval -ENOBUFS Encoded public-key would exceed the \p pubkey_s buffer.
164+
*/
165+
int xbps_pubkey_encode(const struct xbps_pubkey *pubkey, char *pubkey_s, size_t pubkey_s_len);
166+
167+
/**
168+
* @brief Read a minisign public-key file
169+
* @param[out] pubkey Structure to store the public-key to.
170+
* @param[in] fd File descriptor to read from
171+
* @returns \c 0 on success or a negative \c errno from ::xbps_pubkey_decode, \c open(3) or \c read(3).
172+
* @retval -ENOBUFS Comment or the encoded public-key exceed the maximum size.
173+
*/
174+
int xbps_pubkey_read(struct xbps_pubkey *pubkey, int fd);
175+
176+
int xbps_pubkey_write(const struct xbps_pubkey *pubkey, const char *path);
177+
178+
/**
179+
* @struct xbps_seckey
180+
* @brief minisign secret-key.
181+
*
182+
* Ed25519 secret-key, algorithm id and encryption data.
183+
*/
184+
struct xbps_seckey {
185+
unsigned char sig_alg[2];
186+
unsigned char kdf_alg[2];
187+
unsigned char chk_alg[2];
188+
unsigned char kdf_salt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES];
189+
unsigned char kdf_opslimit_le[8];
190+
unsigned char kdf_memlimit_le[8];
191+
struct {
192+
unsigned char keynum[KEYNUMBYTES];
193+
unsigned char sk[SECRETKEYBYTES];
194+
/**
195+
* @var chk
196+
* @brief BLAKE2b hash of the secret-key.
197+
*
198+
* BLAKE2b hash of the secret-key used to check if the secret-key
199+
* was successfully decrypted.
200+
*/
201+
unsigned char chk[HASHBYTES];
202+
} keynum_sk;
203+
};
204+
205+
/**
206+
* @brief Read and decrypt a secret-key.
207+
* @param[out] seckey Structure to store the read secret-key in.
208+
* @param[in] passphrase Optional passphrase to encrypt the secret-key.
209+
* @param[in] path File descriptor to read from.
210+
* @returns \c 0 on success or a negative \c errno.
211+
* @retval -ENOBUFS Comment or encoded secret-key exceed the maximum size.
212+
* @retval -ENOTSUP Secret-key used an algorithm or encryption that is not supported.
213+
* @retval -EINVAL Secret-key is invalid.
214+
* @retval -ERANGE Secret-key is encrypted but no passphrase was supplied or decryption failed.
215+
* @retval -ENOMEM Secret-key decryption failed due to resource limits.
216+
*/
217+
int xbps_seckey_read(struct xbps_seckey *seckey, const char *passphrase, const char *path);
218+
219+
/**
220+
* @brief Write secret-key to file.
221+
* @param[in] seckey Secret-key to write.
222+
* @param[in] passphrase Optional passphrase to encrypt the secret-key with.
223+
* @param[in] path Path to the file.
224+
* @returns \c 0 on success or a negative \c errno from \c open(3) or \c write(3).
225+
*/
226+
int xbps_seckey_write(const struct xbps_seckey *seckey, const char *passphrase, const char *path);
227+
228+
/**
229+
* @struct xbps_sig
230+
* @brief Ed25519 signature.
231+
*/
232+
struct xbps_sig {
233+
/**
234+
* @var sig_alg
235+
* @brief Signature algorithm.
236+
*
237+
* The signature algorithm, currently only ::SIGALG_HASHED.
238+
*/
239+
unsigned char sig_alg[2];
240+
/**
241+
* @var keynum
242+
* @brief Key identifier.
243+
*
244+
* Cryptographically insecure. This should not be presented to users
245+
* and is just used as a fastpath to check if a signature was signed
246+
* by a different key.
247+
*/
248+
unsigned char keynum[KEYNUMBYTES];
249+
/**
250+
* @var sig
251+
* @brief Ed25519 public-key signature.
252+
*
253+
* Detached Ed25519 pubkey-key signature.
254+
*
255+
* The signature depends on the used ::xbps_sig.sig_alg:
256+
* - ::SIGALG_HASHED: Signed BLAKE2b hash of the message.
257+
* - ::SIGALG: Signature of the message itself, not supported.
258+
*/
259+
unsigned char sig[SIGBYTES];
260+
};
261+
262+
/**
263+
* @struct xbps_minisig
264+
* @brief minisig signature
265+
*/
266+
struct xbps_minisig {
267+
/**
268+
* @var comment
269+
* @brief Untrusted comment in the .minisig file.
270+
*/
271+
char comment[COMMENTMAXBYTES];
272+
/**
273+
* @var sig
274+
* @brief Algorithm, keynum and signature of the signed data.
275+
*/
276+
struct xbps_sig sig;
277+
/**
278+
* @var trusted_comment
279+
* @brief Trusted comment in the .minisig file.
280+
*/
281+
char trusted_comment[TRUSTEDCOMMENTMAXBYTES];
282+
/**
283+
* @var global_sig
284+
* @brief Signature of ::xbps_minisig.sig and ::xbps_minisig.trusted_comment.
285+
*
286+
* The global signature signs the signature and the trusted comment.
287+
*/
288+
unsigned char global_sig[SIGBYTES];
289+
};
290+
291+
/**
292+
* @brief Read a minisig file.
293+
* @param[out] minisig ::xbps_minisig struct to store the read data.
294+
* @param[in] path Path to the .minisig file.
295+
* @returns \c 0 on success or a negative \c errno from \c open(3), \c read(3).
296+
* @retval -ENOBUFS Comments or the encoded signature exceed the maximum size.
297+
*/
298+
int xbps_minisig_read(struct xbps_minisig *minisig, const char *path);
299+
300+
/**
301+
* @brief Write a minisig file.
302+
* @param[in] minisig The ::xbps_minisig structure that is written
303+
* @param[in] path Path to write to
304+
* @returns \c 0 on success or a negative \c errno from \c open(3), \c write(3).
305+
*/
306+
int xbps_minisig_write(const struct xbps_minisig *minisig, const char *path);
307+
308+
/**
309+
* @brief Sign a minisig ::xbps_minisig.
310+
* @param[out] minisig The ::xbps_minisig that is being signed and stores the signatures.
311+
* @param[in] seckey Secret-key used to sign.
312+
* @param[in] hash The hash of the message that is begin signed.
313+
* @returns \c 0 on success or a negative \c errno.
314+
* @retval -EINVAL Signing failed.
315+
*/
316+
int xbps_minisig_sign(struct xbps_minisig *minisig, const struct xbps_seckey *seckey,
317+
const struct xbps_hash *hash);
318+
319+
/**
320+
* @brief Verify a minisig ::xbps_minisig.
321+
* @param[in] minisig The ::xbps_minisig that is being verified.
322+
* @param[in] pubkey Public-key used to verify the ::xbps_minisig.
323+
* @param[in] hash The hash of the message that is being verified.
324+
* @returns \c 0 on success or a negative \c errno.
325+
* @retval -EINVAL \c keynum of \p pubkey does not match signature.
326+
* @retval -ERANGE Signature verification failed.
327+
*/
328+
int xbps_minisig_verify(const struct xbps_minisig *minisig, const struct xbps_pubkey *pubkey,
329+
const struct xbps_hash *hash);
330+
331+
/**
332+
* @brief Generate a new key pair.
333+
*
334+
* Generates a new public- and secret-key pair.
335+
*
336+
* @param[out] seckey ::xbps_seckey to store the generated secret-key.
337+
* @param[out] pubkey ::xbps_pubkey to store the generated public-key.
338+
*
339+
* @return 0 on success or a negative \c errno.
340+
* @retval -EINVAL Failure during keypair generation.
341+
*/
342+
int xbps_generate_keypair(struct xbps_seckey *seckey, struct xbps_pubkey *pubkey);
343+
344+
/**@}*/
345+
346+
#endif

lib/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ OBJS += repo.o repo_sync.o
5252
OBJS += rpool.o cb_util.o proplib_wrapper.o
5353
OBJS += package_alternatives.o
5454
OBJS += conf.o log.o
55+
OBJS += crypto.o
5556
OBJS += $(EXTOBJS) $(COMPAT_OBJS)
5657
# unnecessary unless pkgdb format changes
5758
# OBJS += pkgdb_conversion.o

0 commit comments

Comments
 (0)