Tor  0.4.7.0-alpha-dev
crypto_format.c
Go to the documentation of this file.
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-2021, The Tor Project, Inc. */
5 /* See LICENSE for licensing information */
6 
7 /**
8  * \file crypto_format.c
9  *
10  * \brief Formatting and parsing code for crypto-related data structures.
11  */
12 
13 #include "orconfig.h"
14 #ifdef HAVE_SYS_STAT_H
15 #include <sys/stat.h>
16 #endif
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"
30 
31 #include <string.h>
32 #include <errno.h>
33 
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
39  * 24.
40  **/
41 int
43  const char *typestring,
44  const char *tag,
45  const uint8_t *data,
46  size_t datalen)
47 {
48  char header[32];
49  smartlist_t *chunks = smartlist_new();
50  sized_chunk_t ch0, ch1;
51  int r = -1;
52 
53  memset(header, 0, sizeof(header));
54  if (tor_snprintf(header, sizeof(header),
55  "== %s: %s ==", typestring, tag) < 0)
56  goto end;
57  ch0.bytes = header;
58  ch0.len = 32;
59  ch1.bytes = (const char*) data;
60  ch1.len = datalen;
61  smartlist_add(chunks, &ch0);
62  smartlist_add(chunks, &ch1);
63 
64  r = write_chunks_to_file(fname, chunks, 1, 0);
65 
66  end:
67  smartlist_free(chunks);
68  return r;
69 }
70 
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. */
76 ssize_t
78  const char *typestring,
79  char **tag_out,
80  uint8_t *data_out,
81  ssize_t data_out_len)
82 {
83  char prefix[33];
84  char *content = NULL;
85  struct stat st;
86  ssize_t r = -1;
87  size_t st_size = 0;
88  int saved_errno = 0;
89 
90  *tag_out = NULL;
91  st.st_size = 0;
92  content = read_file_to_str(fname, RFTS_BIN|RFTS_IGNORE_MISSING, &st);
93  if (! content) {
94  saved_errno = errno;
95  goto end;
96  }
97  if (st.st_size < 32 || st.st_size > 32 + data_out_len) {
98  saved_errno = EINVAL;
99  goto end;
100  }
101  st_size = (size_t)st.st_size;
102 
103  memcpy(prefix, content, 32);
104  prefix[32] = 0;
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;
109  goto end;
110  }
111 
112  if (strcmpstart(prefix+3, typestring) ||
113  3+strlen(typestring) >= 32 ||
114  strcmpstart(prefix+3+strlen(typestring), ": ")) {
115  saved_errno = EINVAL;
116  goto end;
117  }
118 
119  *tag_out = tor_strndup(prefix+5+strlen(typestring),
120  strlen(prefix)-8-strlen(typestring));
121 
122  memcpy(data_out, content+32, st_size-32);
123  r = st_size - 32;
124 
125  end:
126  if (content)
127  memwipe(content, 0, st_size);
128  tor_free(content);
129  if (saved_errno)
130  errno = saved_errno;
131  return r;
132 }
133 
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.
138  * Can not fail.
139  *
140  * Careful! CURVE25519_BASE64_PADDED_LEN is one byte longer than
141  * ED25519_BASE64_LEN.
142  */
143 void
145  const curve25519_public_key_t *pkey, bool pad)
146 {
147  int n, expected_len;
148  if (pad) {
150  (const char*)pkey->public_key,
152  expected_len = CURVE25519_BASE64_PADDED_LEN;
153  } else {
155  (const uint8_t*)pkey->public_key,
157  expected_len = CURVE25519_BASE64_LEN;
158  }
159 
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');
164 }
165 
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 "=". */
169 int
171  const char *input)
172 {
173  size_t len = strlen(input);
174  if (len == CURVE25519_BASE64_LEN) {
175  /* not padded */
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)
180  return -1;
181  memcpy(pkey->public_key, buf, CURVE25519_PUBKEY_LEN);
182  return 0;
183  } else {
184  return -1;
185  }
186 }
187 
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. */
192 const char *
194 {
195  static char formatted[ED25519_BASE64_LEN+1];
196  if (pkey) {
197  if (ed25519_public_key_is_zero(pkey)) {
198  strlcpy(formatted, "<unset>", sizeof(formatted));
199  } else {
200  ed25519_public_to_base64(formatted, pkey);
201  }
202  } else {
203  strlcpy(formatted, "<null>", sizeof(formatted));
204  }
205  return formatted;
206 }
207 
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
210  * -1. */
211 int
213  const char *input)
214 {
215  return digest256_from_base64((char*)pkey->pubkey, input);
216 }
217 
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.
221  * Can not fail.
222  *
223  * Careful! ED25519_BASE64_LEN is one byte shorter than
224  * CURVE25519_BASE64_PADDED_LEN.
225  */
226 void
228  const ed25519_public_key_t *pkey)
229 {
230  digest256_to_base64(output, (const char *)pkey->pubkey);
231 }
232 
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.
236  * Can not fail.
237  */
238 void
240  const ed25519_signature_t *sig)
241 {
242  char buf[256];
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(). */
247  tor_assert(buf[ED25519_SIG_BASE64_LEN] == '\0');
248  memcpy(output, buf, ED25519_SIG_BASE64_LEN+1);
249 }
250 
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
253  * -1. */
254 int
256  const char *input)
257 {
258  if (strlen(input) != ED25519_SIG_BASE64_LEN)
259  return -1;
260  char decoded[128];
261  int n = base64_decode(decoded, sizeof(decoded), input,
263  if (n < 0 || n != ED25519_SIG_LEN)
264  return -1;
265  memcpy(sig->sig, decoded, ED25519_SIG_LEN);
266 
267  return 0;
268 }
269 
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>.
273  * Can not fail. */
274 void
275 digest_to_base64(char *d64, const char *digest)
276 {
277  char buf[256];
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(). */
283  tor_assert(buf[BASE64_DIGEST_LEN] == '\0');
284  memcpy(d64, buf, BASE64_DIGEST_LEN+1);
285 }
286 
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>. */
290 int
291 digest_from_base64(char *digest, const char *d64)
292 {
293  if (base64_decode(digest, DIGEST_LEN, d64, strlen(d64)) == DIGEST_LEN)
294  return 0;
295  else
296  return -1;
297 }
298 
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>.
302  * Can not fail. */
303 void
304 digest256_to_base64(char *d64, const char *digest)
305 {
306  char buf[256];
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(). */
312  tor_assert(buf[BASE64_DIGEST256_LEN] == '\0');
313  memcpy(d64, buf, BASE64_DIGEST256_LEN+1);
314 }
315 
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>. */
319 int
320 digest256_from_base64(char *digest, const char *d64)
321 {
322  if (base64_decode(digest, DIGEST256_LEN, d64, strlen(d64)) == DIGEST256_LEN)
323  return 0;
324  else
325  return -1;
326 }
int base64_decode(char *dest, size_t destlen, const char *src, size_t srclen)
Definition: binascii.c:396
int base64_encode(char *dest, size_t destlen, const char *src, size_t srclen, int flags)
Definition: binascii.c:215
int base64_encode_nopad(char *dest, size_t destlen, const uint8_t *src, size_t srclen)
Definition: binascii.c:329
Header for binascii.c.
Header for compat_string.c.
Header for crypto_curve25519.c.
Headers for crypto_digest.c.
#define BASE64_DIGEST256_LEN
Definition: crypto_digest.h:29
#define BASE64_DIGEST_LEN
Definition: crypto_digest.h:26
int ed25519_public_key_is_zero(const ed25519_public_key_t *pubkey)
Header for crypto_ed25519.c.
void digest256_to_base64(char *d64, const char *digest)
int ed25519_signature_from_base64(ed25519_signature_t *sig, const char *input)
void ed25519_signature_to_base64(char *output, const ed25519_signature_t *sig)
int curve25519_public_from_base64(curve25519_public_key_t *pkey, const char *input)
void ed25519_public_to_base64(char *output, const ed25519_public_key_t *pkey)
ssize_t crypto_read_tagged_contents_from_file(const char *fname, const char *typestring, char **tag_out, uint8_t *data_out, ssize_t data_out_len)
Definition: crypto_format.c:77
const char * ed25519_fmt(const ed25519_public_key_t *pkey)
int crypto_write_tagged_contents_to_file(const char *fname, const char *typestring, const char *tag, const uint8_t *data, size_t datalen)
Definition: crypto_format.c:42
int ed25519_public_from_base64(ed25519_public_key_t *pkey, const char *input)
void curve25519_public_to_base64(char *output, const curve25519_public_key_t *pkey, bool pad)
int digest256_from_base64(char *digest, const char *d64)
void digest_to_base64(char *d64, const char *digest)
int digest_from_base64(char *digest, const char *d64)
Header for crypto_format.c.
void memwipe(void *mem, uint8_t byte, size_t sz)
Definition: crypto_util.c:55
Common functions for cryptographic routines.
#define DIGEST_LEN
Definition: digest_sizes.h:20
#define DIGEST256_LEN
Definition: digest_sizes.h:23
Wrappers for reading and writing data to files on disk.
#define RFTS_IGNORE_MISSING
Definition: files.h:101
#define RFTS_BIN
Definition: files.h:99
Headers for log.c.
#define tor_free(p)
Definition: malloc.h:52
int tor_snprintf(char *str, size_t size, const char *format,...)
Definition: printf.c:27
Header for printf.c.
Header for smartlist.c.
smartlist_t * smartlist_new(void)
void smartlist_add(smartlist_t *sl, void *element)
Macros to manage assertions, fatal and non-fatal.
#define tor_assert(expr)
Definition: util_bug.h:102
int strcmpstart(const char *s1, const char *s2)
Definition: util_string.c:215
int strcmpend(const char *s1, const char *s2)
Definition: util_string.c:251
int fast_mem_is_zero(const char *mem, size_t len)
Definition: util_string.c:74
Header for util_string.c.
#define ED25519_SIG_LEN
Definition: x25519_sizes.h:34
#define CURVE25519_BASE64_PADDED_LEN
Definition: x25519_sizes.h:37
#define ED25519_BASE64_LEN
Definition: x25519_sizes.h:43
#define ED25519_SIG_BASE64_LEN
Definition: x25519_sizes.h:45
#define CURVE25519_PUBKEY_LEN
Definition: x25519_sizes.h:20
#define CURVE25519_BASE64_LEN
Definition: x25519_sizes.h:40