2 * Copyright (C) 2005-2011 Andre Noll <maan@systemlinux.org>
4 * Licensed under the GPL v2. For licencing details see COPYING.
7 /** \file crypt_common.c Crypto functions independent of the implementation. */
15 #include "crypt_backend.h"
18 #define KEY_TYPE_TXT "ssh-rsa"
21 * Check if given buffer starts with a ssh rsa key signature.
23 * \param data The buffer.
24 * \param size Number of data bytes.
26 * \return Number of header bytes to be skipped on success, zero if
27 * ssh rsa signature was not found.
29 size_t is_ssh_rsa_key(char *data, size_t size)
33 if (size < strlen(KEY_TYPE_TXT) + 2)
35 cp = memchr(data, ' ', size);
38 if (strncmp(KEY_TYPE_TXT, data, strlen(KEY_TYPE_TXT)))
41 if (cp >= data + size)
49 * This base64/uudecode stuff below is taken from openssh-5.2p1, Copyright (c)
50 * 1996 by Internet Software Consortium. Portions Copyright (c) 1995 by
51 * International Business Machines, Inc.
54 static const char Base64[] =
55 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
56 static const char Pad64 = '=';
58 * Skips all whitespace anywhere. Converts characters, four at a time, starting
59 * at (or after) src from base - 64 numbers into three 8 bit bytes in the
60 * target area. it returns the number of data bytes stored at the target, or -E_BASE64
63 int base64_decode(char const *src, unsigned char *target, size_t targsize)
65 unsigned int tarindex, state;
72 while ((ch = *src++) != '\0') {
73 if (para_isspace(ch)) /* Skip whitespace anywhere. */
79 pos = strchr(Base64, ch);
80 if (pos == 0) /* A non-base64 character. */
86 if (tarindex >= targsize)
88 target[tarindex] = (pos - Base64) << 2;
94 if (tarindex + 1 >= targsize)
96 target[tarindex] |= (pos - Base64) >> 4;
97 target[tarindex+1] = ((pos - Base64) & 0x0f)
105 if (tarindex + 1 >= targsize)
107 target[tarindex] |= (pos - Base64) >> 2;
108 target[tarindex+1] = ((pos - Base64) & 0x03)
116 if (tarindex >= targsize)
118 target[tarindex] |= (pos - Base64);
127 * We are done decoding Base-64 chars. Let's see if we ended
128 * on a byte boundary, and/or with erroneous trailing characters.
131 if (ch == Pad64) { /* We got a pad char. */
132 ch = *src++; /* Skip it, get next. */
134 case 0: /* Invalid = in first position */
135 case 1: /* Invalid = in second position */
138 case 2: /* Valid, means one byte of info */
139 /* Skip any number of spaces. */
140 for (; ch != '\0'; ch = *src++)
143 /* Make sure there is another trailing = sign. */
146 ch = *src++; /* Skip the = */
147 /* Fall through to "single trailing =" case. */
150 case 3: /* Valid, means two bytes of info */
152 * We know this char is an =. Is there anything but
153 * whitespace after it?
155 for (; ch != '\0'; ch = *src++)
160 * Now make sure for cases 2 and 3 that the "extra"
161 * bits that slopped past the last full byte were
162 * zeros. If we don't check them, they become a
163 * subliminal channel.
165 if (target && target[tarindex] != 0)
170 * We ended by seeing the end of the string. Make sure we
171 * have no partial bytes lying around.
180 int uudecode(const char *src, unsigned char *target, size_t targsize)
185 /* copy the 'readonly' source */
186 encoded = para_strdup(src);
187 /* skip whitespace and data */
188 for (p = encoded; *p == ' ' || *p == '\t'; p++)
190 for (; *p != '\0' && *p != ' ' && *p != '\t'; p++)
192 /* and remove trailing whitespace because base64_decode needs this */
194 len = base64_decode(encoded, target, targsize);
200 * Can not use the inline functions of portable_io.h here because the byte
201 * order is different.
203 uint32_t read_ssh_u32(const void *vp)
205 const unsigned char *p = (const unsigned char *)vp;
208 v = (uint32_t)p[0] << 24;
209 v |= (uint32_t)p[1] << 16;
210 v |= (uint32_t)p[2] << 8;
216 int check_ssh_key_header(const unsigned char *blob, int blen)
218 const unsigned char *p = blob, *end = blob + blen;
222 return -E_SSH_KEY_HEADER;
223 rlen = read_ssh_u32(p);
226 return -E_SSH_KEY_HEADER;
228 return -E_SSH_KEY_HEADER;
229 if (rlen < strlen(KEY_TYPE_TXT))
230 return -E_SSH_KEY_HEADER;
231 PARA_DEBUG_LOG("type: %s, rlen: %d\n", p, rlen);
232 if (strncmp((char *)p, KEY_TYPE_TXT, strlen(KEY_TYPE_TXT)))
233 return -E_SSH_KEY_HEADER;
237 int check_key_file(const char *file, bool private_key)
241 if (stat(file, &st) != 0)
242 return -ERRNO_TO_PARA_ERROR(errno);
245 if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0)
251 * Convert a hash value to ascii format.
253 * \param hash the hash value.
254 * \param asc Result pointer.
256 * \a asc must point to an area of at least 2 * \p HASH_SIZE + 1 bytes which
257 * will be filled by the function with the ascii representation of the hash
258 * value given by \a hash, and a terminating \p NULL byte.
260 void hash_to_asc(unsigned char *hash, char *asc)
263 const char hexchar[] = "0123456789abcdef";
265 for (i = 0; i < HASH_SIZE; i++) {
266 asc[2 * i] = hexchar[hash[i] >> 4];
267 asc[2 * i + 1] = hexchar[hash[i] & 0xf];
269 asc[2 * HASH_SIZE] = '\0';
273 * Compare two hashes.
275 * \param h1 Pointer to the first hash value.
276 * \param h2 Pointer to the second hash value.
278 * \return 1, -1, or zero, depending on whether \a h1 is greater than,
279 * less than or equal to h2, respectively.
281 int hash_compare(unsigned char *h1, unsigned char *h2)
285 for (i = 0; i < HASH_SIZE; i++) {
295 * Receive a buffer, decrypt it and write terminating NULL byte.
297 * \param scc The context.
298 * \param buf The buffer to write the decrypted data to.
299 * \param size The size of \a buf.
301 * Read at most \a size - 1 bytes from file descriptor given by \a scc, decrypt
302 * the received data and write a NULL byte at the end of the decrypted data.
304 * \return The return value of the underlying call to \ref
305 * sc_recv_bin_buffer().
307 int sc_recv_buffer(struct stream_cipher_context *scc, char *buf, size_t size)
312 n = sc_recv_bin_buffer(scc, buf, size - 1);
321 * Encrypt and send a \p NULL-terminated buffer.
323 * \param scc The context.
324 * \param buf The buffer to send.
326 * \return The return value of the underyling call to sc_send_bin_buffer().
328 int sc_send_buffer(struct stream_cipher_context *scc, char *buf)
330 return sc_send_bin_buffer(scc, buf, strlen(buf));
334 * Format, encrypt and send a buffer.
336 * \param scc The context.
337 * \param fmt A format string.
339 * \return The return value of the underyling call to sc_send_buffer().
341 __printf_2_3 int sc_send_va_buffer(struct stream_cipher_context *scc,
342 const char *fmt, ...)
347 PARA_VSPRINTF(fmt, msg);
348 ret = sc_send_buffer(scc, msg);