aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/tools/base64.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/base64.c')
-rw-r--r--src/tools/base64.c258
1 files changed, 52 insertions, 206 deletions
diff --git a/src/tools/base64.c b/src/tools/base64.c
index cf37464..48ac1be 100644
--- a/src/tools/base64.c
+++ b/src/tools/base64.c
@@ -1,220 +1,66 @@
-/*
- * Copyright (c) 1996, 1998 by Internet Software Consortium.
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
- * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
- * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- * SOFTWARE.
- *
- * Portions Copyright (c) 1995 by International Business Machines, Inc.
- *
- * International Business Machines, Inc. (hereinafter called IBM) grants
- * permission under its copyrights to use, copy, modify, and distribute this
- * Software with or without fee, provided that the above copyright notice and
- * all paragraphs of this notice appear in all copies, and that the name of IBM
- * not be used in connection with the marketing of any product incorporating
- * the Software or modifications thereof, without specific, written prior
- * permission.
- *
- * To the extent it has a right to do so, IBM grants an immunity from suit
- * under its patents, if any, for the use, sale or manufacture of products to
- * the extent that such products are used for performing Domain Name System
- * dynamic updates in TCP/IP networks by means of the Software. No immunity is
- * granted for any product per se or for any other function of any product.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
- * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
- * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
- * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ * This is a specialized constant-time base64 implementation that resists side-channel attacks.
*/
+#include <string.h>
#include "base64.h"
-#include <sys/types.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <ctype.h>
-
-#if defined(NEED_B64_NTOP) || defined(NEED_B64_PTON)
-static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-static const char pad64 = '=';
-#endif
-#ifdef NEED_B64_NTOP
-int b64_ntop(unsigned char const *src, size_t srclength, char *target, size_t targsize)
+static inline void encode(char dest[4], const uint8_t src[3])
{
- size_t datalength = 0;
- uint8_t input[3];
- uint8_t output[4];
- size_t i;
+ const uint8_t input[] = { (src[0] >> 2) & 63, ((src[0] << 4) | (src[1] >> 4)) & 63, ((src[1] << 2) | (src[2] >> 6)) & 63, src[2] & 63 };
+ for (unsigned int i = 0; i < 4; ++i)
+ dest[i] = input[i] + 'A'
+ + (((25 - input[i]) >> 8) & 6)
+ - (((51 - input[i]) >> 8) & 75)
+ - (((61 - input[i]) >> 8) & 15)
+ + (((62 - input[i]) >> 8) & 3);
- while (2 < srclength) {
- input[0] = *src++;
- input[1] = *src++;
- input[2] = *src++;
- srclength -= 3;
-
- output[0] = input[0] >> 2;
- output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
- output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
- output[3] = input[2] & 0x3f;
- assert(output[0] < 64);
- assert(output[1] < 64);
- assert(output[2] < 64);
- assert(output[3] < 64);
-
- if (datalength + 4 > targsize)
- return -1;
- target[datalength++] = base64[output[0]];
- target[datalength++] = base64[output[1]];
- target[datalength++] = base64[output[2]];
- target[datalength++] = base64[output[3]];
- }
- if (0 != srclength) {
- input[0] = input[1] = input[2] = '\0';
- for (i = 0; i < srclength; i++)
- input[i] = *src++;
- output[0] = input[0] >> 2;
- output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
- output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
- assert(output[0] < 64);
- assert(output[1] < 64);
- assert(output[2] < 64);
-
- if (datalength + 4 > targsize)
- return -1;
- target[datalength++] = base64[output[0]];
- target[datalength++] = base64[output[1]];
- if (srclength == 1)
- target[datalength++] = pad64;
- else
- target[datalength++] = base64[output[2]];
- target[datalength++] = pad64;
- }
- if (datalength >= targsize)
- return (-1);
- target[datalength] = '\0';
- return datalength;
}
-#endif
-#ifdef NEED_B64_PTON
-int b64_pton(char const *src, uint8_t *target, size_t targsize)
+void key_to_base64(char base64[static WG_KEY_LEN_BASE64], const uint8_t key[static WG_KEY_LEN])
{
- static int b64rmap_initialized = 0;
- static uint8_t b64rmap[256];
- static const uint8_t b64rmap_special = 0xf0;
- static const uint8_t b64rmap_end = 0xfd;
- static const uint8_t b64rmap_space = 0xfe;
- static const uint8_t b64rmap_invalid = 0xff;
- int tarindex, state, ch;
- uint8_t ofs;
-
- if (!b64rmap_initialized) {
- int i;
- char ch;
- b64rmap[0] = b64rmap_end;
- for (i = 1; i < 256; ++i) {
- ch = (char)i;
- if (isspace(ch))
- b64rmap[i] = b64rmap_space;
- else if (ch == pad64)
- b64rmap[i] = b64rmap_end;
- else
- b64rmap[i] = b64rmap_invalid;
- }
- for (i = 0; base64[i] != '\0'; ++i)
- b64rmap[(uint8_t)base64[i]] = i;
- b64rmap_initialized = 1;
- }
-
- state = 0;
- tarindex = 0;
-
- for (;;) {
- ch = *src++;
- ofs = b64rmap[ch];
-
- if (ofs >= b64rmap_special) {
- if (ofs == b64rmap_space)
- continue;
- if (ofs == b64rmap_end)
- break;
- return -1;
- }
-
- switch (state) {
- case 0:
- if ((size_t)tarindex >= targsize)
- return -1;
- target[tarindex] = ofs << 2;
- state = 1;
- break;
- case 1:
- if ((size_t)tarindex + 1 >= targsize)
- return -1;
- target[tarindex] |= ofs >> 4;
- target[tarindex+1] = (ofs & 0x0f) << 4 ;
- tarindex++;
- state = 2;
- break;
- case 2:
- if ((size_t)tarindex + 1 >= targsize)
- return -1;
- target[tarindex] |= ofs >> 2;
- target[tarindex+1] = (ofs & 0x03) << 6;
- tarindex++;
- state = 3;
- break;
- case 3:
- if ((size_t)tarindex >= targsize)
- return -1;
- target[tarindex] |= ofs;
- tarindex++;
- state = 0;
- break;
- default:
- abort();
- }
- }
+ unsigned int i;
+ for (i = 0; i < WG_KEY_LEN / 3; ++i)
+ encode(&base64[i * 4], &key[i * 3]);
+ encode(&base64[i * 4], (const uint8_t[]){ key[i * 3 + 0], key[i * 3 + 1], 0 });
+ base64[WG_KEY_LEN_BASE64 - 2] = '=';
+ base64[WG_KEY_LEN_BASE64 - 1] = '\0';
+}
- if (ch == pad64) {
- ch = *src++;
- switch (state) {
- case 0:
- case 1:
- return -1;
+static inline int decode(const char src[4])
+{
+ int val = 0;
+ for (unsigned int i = 0; i < 4; ++i)
+ val |= (-1
+ + ((((('A' - 1) - src[i]) & (src[i] - ('Z' + 1))) >> 8) & (src[i] - 64))
+ + ((((('a' - 1) - src[i]) & (src[i] - ('z' + 1))) >> 8) & (src[i] - 70))
+ + ((((('0' - 1) - src[i]) & (src[i] - ('9' + 1))) >> 8) & (src[i] + 5))
+ + ((((('+' - 1) - src[i]) & (src[i] - ('+' + 1))) >> 8) & 63)
+ + ((((('/' - 1) - src[i]) & (src[i] - ('/' + 1))) >> 8) & 64)
+ ) << (18 - 6 * i);
+ return val;
+}
- case 2:
- for (; ch; ch = *src++) {
- if (b64rmap[ch] != b64rmap_space)
- break;
- }
- if (ch != pad64)
- return -1;
- ch = *src++;
- case 3:
- for (; ch; ch = *src++) {
- if (b64rmap[ch] != b64rmap_space)
- return -1;
- }
- if (target[tarindex] != 0)
- return -1;
- }
- } else {
- if (state != 0)
- return -1;
+bool key_from_base64(uint8_t key[static WG_KEY_LEN], const char *base64)
+{
+ unsigned int i;
+ int val;
+ if (strlen(base64) != WG_KEY_LEN_BASE64 - 1 || base64[WG_KEY_LEN_BASE64 - 2] != '=')
+ return false;
+
+ for (i = 0; i < WG_KEY_LEN / 3; ++i) {
+ val = decode(&base64[i * 4]);
+ if (val < 0)
+ return false;
+ key[i * 3 + 0] = (val >> 16) & 0xff;
+ key[i * 3 + 1] = (val >> 8) & 0xff;
+ key[i * 3 + 2] = val & 0xff;
}
-
- return tarindex;
+ val = decode((const char[]){ base64[i * 4 + 0], base64[i * 4 + 1], base64[i * 4 + 2], 'A' });
+ if (val < 0 || val & 0xff)
+ return false;
+ key[i * 3 + 0] = (val >> 16) & 0xff;
+ key[i * 3 + 1] = (val >> 8) & 0xff;
+ return true;
}
-#endif