1 /* Copyright (c) 2001, Matej Pfajfar.
2 * Copyright (c) 2001-2004, Roger Dingledine.
3 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
4 * Copyright (c) 2007-2020, The Tor Project, Inc. */
5 /* See LICENSE for licensing information */
8 * \file crypto_format.c
10 * \brief Formatting and parsing code for crypto-related data structures.
14 #ifdef HAVE_SYS_STAT_H
17 #include "lib/container/smartlist.h"
18 #include "lib/crypt_ops/crypto_curve25519.h"
19 #include "lib/crypt_ops/crypto_digest.h"
20 #include "lib/crypt_ops/crypto_ed25519.h"
21 #include "lib/crypt_ops/crypto_format.h"
22 #include "lib/crypt_ops/crypto_util.h"
23 #include "lib/string/compat_string.h"
24 #include "lib/string/util_string.h"
25 #include "lib/string/printf.h"
26 #include "lib/encoding/binascii.h"
27 #include "lib/log/log.h"
28 #include "lib/log/util_bug.h"
29 #include "lib/fs/files.h"
34 /** Write the <b>datalen</b> bytes from <b>data</b> to the file named
35 * <b>fname</b> in the tagged-data format. This format contains a
36 * 32-byte header, followed by the data itself. The header is the
37 * NUL-padded string "== <b>typestring</b>: <b>tag</b> ==". The length
38 * of <b>typestring</b> and <b>tag</b> must therefore be no more than
42 crypto_write_tagged_contents_to_file(const char *fname
,
43 const char *typestring
,
49 smartlist_t
*chunks
= smartlist_new();
50 sized_chunk_t ch0
, ch1
;
53 memset(header
, 0, sizeof(header
));
54 if (tor_snprintf(header
, sizeof(header
),
55 "== %s: %s ==", typestring
, tag
) < 0)
59 ch1
.bytes
= (const char*) data
;
61 smartlist_add(chunks
, &ch0
);
62 smartlist_add(chunks
, &ch1
);
64 r
= write_chunks_to_file(fname
, chunks
, 1, 0);
67 smartlist_free(chunks
);
71 /** Read a tagged-data file from <b>fname</b> into the
72 * <b>data_out_len</b>-byte buffer in <b>data_out</b>. Check that the
73 * typestring matches <b>typestring</b>; store the tag into a newly allocated
74 * string in <b>tag_out</b>. Return -1 on failure, and the number of bytes of
75 * data on success. Preserves the errno from reading the file. */
77 crypto_read_tagged_contents_from_file(const char *fname
,
78 const char *typestring
,
92 content
= read_file_to_str(fname
, RFTS_BIN
|RFTS_IGNORE_MISSING
, &st
);
97 if (st
.st_size
< 32 || st
.st_size
> 32 + data_out_len
) {
101 st_size
= (size_t)st
.st_size
;
103 memcpy(prefix
, content
, 32);
105 /* Check type, extract tag. */
106 if (strcmpstart(prefix
, "== ") || strcmpend(prefix
, " ==") ||
107 ! fast_mem_is_zero(prefix
+strlen(prefix
), 32-strlen(prefix
))) {
108 saved_errno
= EINVAL
;
112 if (strcmpstart(prefix
+3, typestring
) ||
113 3+strlen(typestring
) >= 32 ||
114 strcmpstart(prefix
+3+strlen(typestring
), ": ")) {
115 saved_errno
= EINVAL
;
119 *tag_out
= tor_strndup(prefix
+5+strlen(typestring
),
120 strlen(prefix
)-8-strlen(typestring
));
122 memcpy(data_out
, content
+32, st_size
-32);
127 memwipe(content
, 0, st_size
);
134 /** Encode <b>pkey</b> as a base64-encoded string in the buffer <b>output</b>.
135 * If <b>pad</b> is false do not include trailing "=" characters, otherwise
136 * include them. <b>output</b> must have at least
137 * CURVE25519_BASE64_PADDED_LEN+1 bytes available, even if <b>pad</b> is false.
140 * Careful! CURVE25519_BASE64_PADDED_LEN is one byte longer than
141 * ED25519_BASE64_LEN.
144 curve25519_public_to_base64(char *output
,
145 const curve25519_public_key_t
*pkey
, bool pad
)
149 n
= base64_encode(output
, CURVE25519_BASE64_PADDED_LEN
+1,
150 (const char*)pkey
->public_key
,
151 CURVE25519_PUBKEY_LEN
, 0);
152 expected_len
= CURVE25519_BASE64_PADDED_LEN
;
154 n
= base64_encode_nopad(output
, CURVE25519_BASE64_PADDED_LEN
+1,
155 (const uint8_t*)pkey
->public_key
,
156 CURVE25519_PUBKEY_LEN
);
157 expected_len
= CURVE25519_BASE64_LEN
;
160 /* These asserts should always succeed, unless there is a bug in
161 * base64_encode(). */
162 tor_assert(n
== expected_len
);
163 tor_assert(output
[expected_len
] == '\0');
166 /** Try to decode a base64-encoded curve25519 public key from <b>input</b>
167 * into the object at <b>pkey</b>. Return 0 on success, -1 on failure.
168 * Accepts keys with or without a trailing "=". */
170 curve25519_public_from_base64(curve25519_public_key_t
*pkey
,
173 size_t len
= strlen(input
);
174 if (len
== CURVE25519_BASE64_LEN
) {
176 return digest256_from_base64((char*)pkey
->public_key
, input
);
177 } else if (len
== CURVE25519_BASE64_PADDED_LEN
) {
178 char buf
[CURVE25519_BASE64_PADDED_LEN
+1];
179 if (base64_decode(buf
, sizeof(buf
), input
, len
) != CURVE25519_PUBKEY_LEN
)
181 memcpy(pkey
->public_key
, buf
, CURVE25519_PUBKEY_LEN
);
188 /** For logging convenience: Convert <b>pkey</b> to a statically allocated
189 * base64 string and return it. Not threadsafe. Format not meant to be
190 * computer-readable; it may change in the future. Subsequent calls invalidate
191 * previous returns. */
193 ed25519_fmt(const ed25519_public_key_t
*pkey
)
195 static char formatted
[ED25519_BASE64_LEN
+1];
197 if (ed25519_public_key_is_zero(pkey
)) {
198 strlcpy(formatted
, "<unset>", sizeof(formatted
));
200 ed25519_public_to_base64(formatted
, pkey
);
203 strlcpy(formatted
, "<null>", sizeof(formatted
));
208 /** Try to decode the string <b>input</b> into an ed25519 public key. On
209 * success, store the value in <b>pkey</b> and return 0. Otherwise return
212 ed25519_public_from_base64(ed25519_public_key_t
*pkey
,
215 return digest256_from_base64((char*)pkey
->pubkey
, input
);
218 /** Encode the public key <b>pkey</b> into the buffer at <b>output</b>,
219 * which must have space for ED25519_BASE64_LEN bytes of encoded key,
220 * plus one byte for a terminating NUL.
223 * Careful! ED25519_BASE64_LEN is one byte shorter than
224 * CURVE25519_BASE64_PADDED_LEN.
227 ed25519_public_to_base64(char *output
,
228 const ed25519_public_key_t
*pkey
)
230 digest256_to_base64(output
, (const char *)pkey
->pubkey
);
233 /** Encode the signature <b>sig</b> into the buffer at <b>output</b>,
234 * which must have space for ED25519_SIG_BASE64_LEN bytes of encoded signature,
235 * plus one byte for a terminating NUL.
239 ed25519_signature_to_base64(char *output
,
240 const ed25519_signature_t
*sig
)
243 int n
= base64_encode_nopad(buf
, sizeof(buf
), sig
->sig
, ED25519_SIG_LEN
);
244 /* These asserts should always succeed, unless there is a bug in
245 * base64_encode_nopad(). */
246 tor_assert(n
== ED25519_SIG_BASE64_LEN
);
247 tor_assert(buf
[ED25519_SIG_BASE64_LEN
] == '\0');
248 memcpy(output
, buf
, ED25519_SIG_BASE64_LEN
+1);
251 /** Try to decode the string <b>input</b> into an ed25519 signature. On
252 * success, store the value in <b>sig</b> and return 0. Otherwise return
255 ed25519_signature_from_base64(ed25519_signature_t
*sig
,
258 if (strlen(input
) != ED25519_SIG_BASE64_LEN
)
261 int n
= base64_decode(decoded
, sizeof(decoded
), input
,
262 ED25519_SIG_BASE64_LEN
);
263 if (n
< 0 || n
!= ED25519_SIG_LEN
)
265 memcpy(sig
->sig
, decoded
, ED25519_SIG_LEN
);
270 /** Base64 encode DIGEST_LEN bytes from <b>digest</b>, remove the trailing =
271 * characters, and store the nul-terminated result in the first
272 * BASE64_DIGEST_LEN+1 bytes of <b>d64</b>.
275 digest_to_base64(char *d64
, const char *digest
)
278 int n
= base64_encode_nopad(buf
, sizeof(buf
),
279 (const uint8_t *)digest
, DIGEST_LEN
);
280 /* These asserts should always succeed, unless there is a bug in
281 * base64_encode_nopad(). */
282 tor_assert(n
== BASE64_DIGEST_LEN
);
283 tor_assert(buf
[BASE64_DIGEST_LEN
] == '\0');
284 memcpy(d64
, buf
, BASE64_DIGEST_LEN
+1);
287 /** Given a base64 encoded, nul-terminated digest in <b>d64</b> (without
288 * trailing newline or = characters), decode it and store the result in the
289 * first DIGEST_LEN bytes at <b>digest</b>. */
291 digest_from_base64(char *digest
, const char *d64
)
293 if (base64_decode(digest
, DIGEST_LEN
, d64
, strlen(d64
)) == DIGEST_LEN
)
299 /** Base64 encode DIGEST256_LINE bytes from <b>digest</b>, remove the
300 * trailing = characters, and store the nul-terminated result in the first
301 * BASE64_DIGEST256_LEN+1 bytes of <b>d64</b>.
304 digest256_to_base64(char *d64
, const char *digest
)
307 int n
= base64_encode_nopad(buf
, sizeof(buf
),
308 (const uint8_t *)digest
, DIGEST256_LEN
);
309 /* These asserts should always succeed, unless there is a bug in
310 * base64_encode_nopad(). */
311 tor_assert(n
== BASE64_DIGEST256_LEN
);
312 tor_assert(buf
[BASE64_DIGEST256_LEN
] == '\0');
313 memcpy(d64
, buf
, BASE64_DIGEST256_LEN
+1);
316 /** Given a base64 encoded, nul-terminated digest in <b>d64</b> (without
317 * trailing newline or = characters), decode it and store the result in the
318 * first DIGEST256_LEN bytes at <b>digest</b>. */
320 digest256_from_base64(char *digest
, const char *d64
)
322 if (base64_decode(digest
, DIGEST256_LEN
, d64
, strlen(d64
)) == DIGEST256_LEN
)