xref: /freebsd/crypto/krb5/src/util/support/base64.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* util/support/base64.c - base64 encoder and decoder */
3 /*
4  * Copyright (c) 1995-2001 Kungliga Tekniska Högskolan
5  * (Royal Institute of Technology, Stockholm, Sweden).
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * 3. Neither the name of the Institute nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include <k5-platform.h>
37 #include <k5-base64.h>
38 
39 static const char base64_chars[] =
40     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
41 
42 char *
k5_base64_encode(const void * data,size_t len)43 k5_base64_encode(const void *data, size_t len)
44 {
45     char *s, *p;
46     size_t i;
47     unsigned int c;
48     const unsigned char *q;
49 
50     if (len > SIZE_MAX / 4)
51         return NULL;
52 
53     p = s = malloc(len * 4 / 3 + 4);
54     if (p == NULL)
55         return NULL;
56     q = (const unsigned char *)data;
57 
58     for (i = 0; i < len;) {
59         c = q[i++];
60         c *= 256;
61         if (i < len)
62             c += q[i];
63         i++;
64         c *= 256;
65         if (i < len)
66             c += q[i];
67         i++;
68         p[0] = base64_chars[(c & 0x00fc0000) >> 18];
69         p[1] = base64_chars[(c & 0x0003f000) >> 12];
70         p[2] = base64_chars[(c & 0x00000fc0) >> 6];
71         p[3] = base64_chars[(c & 0x0000003f) >> 0];
72         if (i > len)
73             p[3] = '=';
74         if (i > len + 1)
75             p[2] = '=';
76         p += 4;
77     }
78     *p = '\0';
79     return s;
80 }
81 
82 #define DECODE_ERROR 0xffffffff
83 
84 /* Decode token, which must be four bytes long. */
85 static unsigned int
decode_token(const char * token)86 decode_token(const char *token)
87 {
88     int i, marker = 0;
89     unsigned int val = 0;
90     const char *p;
91 
92     for (i = 0; i < 4; i++) {
93         val *= 64;
94         if (token[i] == '=') {
95             marker++;
96         } else if (marker > 0) {
97             return DECODE_ERROR;
98         } else {
99             p = strchr(base64_chars, token[i]);
100             if (p == NULL)
101                 return DECODE_ERROR;
102             val += p - base64_chars;
103         }
104     }
105     if (marker > 2)
106         return DECODE_ERROR;
107     return (marker << 24) | val;
108 }
109 
110 void *
k5_base64_decode(const char * str,size_t * len_out)111 k5_base64_decode(const char *str, size_t *len_out)
112 {
113     unsigned char *data, *q;
114     unsigned int val, marker;
115     size_t len;
116 
117     *len_out = SIZE_MAX;
118 
119     /* Allocate the output buffer. */
120     len = strlen(str);
121     if (len % 4)
122         return NULL;
123     q = data = malloc(len / 4 * 3);
124     if (data == NULL) {
125         *len_out = 0;
126         return NULL;
127     }
128 
129     /* Decode the string. */
130     for (; *str != '\0'; str += 4) {
131         val = decode_token(str);
132         if (val == DECODE_ERROR) {
133             free(data);
134             return NULL;
135         }
136         marker = (val >> 24) & 0xff;
137         *q++ = (val >> 16) & 0xff;
138         if (marker < 2)
139             *q++ = (val >> 8) & 0xff;
140         if (marker < 1)
141             *q++ = val & 0xff;
142     }
143     *len_out = q - data;
144     return data;
145 }
146