f23115a9ff9bb8655ec2bef77232af847ced723c
[platform/upstream/nettle.git] / base64-encode.c
1 /* base64-encode.c
2
3    Copyright (C) 2002 Niels Möller
4
5    This file is part of GNU Nettle.
6
7    GNU Nettle is free software: you can redistribute it and/or
8    modify it under the terms of either:
9
10      * the GNU Lesser General Public License as published by the Free
11        Software Foundation; either version 3 of the License, or (at your
12        option) any later version.
13
14    or
15
16      * the GNU General Public License as published by the Free
17        Software Foundation; either version 2 of the License, or (at your
18        option) any later version.
19
20    or both in parallel, as here.
21
22    GNU Nettle is distributed in the hope that it will be useful,
23    but WITHOUT ANY WARRANTY; without even the implied warranty of
24    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25    General Public License for more details.
26
27    You should have received copies of the GNU General Public License and
28    the GNU Lesser General Public License along with this program.  If
29    not, see http://www.gnu.org/licenses/.
30 */
31
32 #if HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #include <assert.h>
37 #include <stdlib.h>
38
39 #include "base64.h"
40
41 #define ENCODE(alphabet,x) ((alphabet)[0x3F & (x)])
42
43 static void
44 encode_raw(const uint8_t *alphabet,
45            uint8_t *dst, size_t length, const uint8_t *src)
46 {
47   const uint8_t *in = src + length;
48   uint8_t *out = dst + BASE64_ENCODE_RAW_LENGTH(length);
49
50   unsigned left_over = length % 3;
51
52   if (left_over)
53     {
54       in -= left_over;
55       *--out = '=';
56       switch(left_over)
57         {
58         case 1:
59           *--out = '=';
60           *--out = ENCODE(alphabet, (in[0] << 4));
61           break;
62           
63         case 2:
64           *--out = ENCODE(alphabet, (in[1] << 2));
65           *--out = ENCODE(alphabet, ((in[0] << 4) | (in[1] >> 4)));
66           break;
67
68         default:
69           abort();
70         }
71       *--out = ENCODE(alphabet, (in[0] >> 2));
72     }
73   
74   while (in > src)
75     {
76       in -= 3;
77       *--out = ENCODE(alphabet, (in[2]));
78       *--out = ENCODE(alphabet, ((in[1] << 2) | (in[2] >> 6)));
79       *--out = ENCODE(alphabet, ((in[0] << 4) | (in[1] >> 4)));
80       *--out = ENCODE(alphabet, (in[0] >> 2));
81     }
82   assert(in == src);
83   assert(out == dst);
84 }
85
86 static const uint8_t base64_encode_table[64] =
87   "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
88   "abcdefghijklmnopqrstuvwxyz"
89   "0123456789+/";
90
91 void
92 base64_encode_raw(uint8_t *dst, size_t length, const uint8_t *src)
93 {
94   encode_raw(base64_encode_table, dst, length, src);
95 }
96
97 void
98 base64_encode_group(uint8_t *dst, uint32_t group)
99 {
100   *dst++ = ENCODE(base64_encode_table, (group >> 18));
101   *dst++ = ENCODE(base64_encode_table, (group >> 12));
102   *dst++ = ENCODE(base64_encode_table, (group >> 6));
103   *dst++ = ENCODE(base64_encode_table, group);
104 }
105
106 void
107 base64_encode_init(struct base64_encode_ctx *ctx)
108 {
109   ctx->word = ctx->bits = 0;
110   ctx->alphabet = base64_encode_table;
111 }
112
113 /* Encodes a single byte. */
114 size_t
115 base64_encode_single(struct base64_encode_ctx *ctx,
116                      uint8_t *dst,
117                      uint8_t src)
118 {
119   unsigned done = 0;
120   unsigned word = ctx->word << 8 | src;
121   unsigned bits = ctx->bits + 8;
122   
123   while (bits >= 6)
124     {
125       bits -= 6;
126       dst[done++] = ENCODE(ctx->alphabet, (word >> bits));
127     }
128
129   ctx->bits = bits;
130   ctx->word = word;
131
132   assert(done <= 2);
133   
134   return done;
135 }
136
137 /* Returns the number of output characters. DST should point to an
138  * area of size at least BASE64_ENCODE_LENGTH(length). */
139 size_t
140 base64_encode_update(struct base64_encode_ctx *ctx,
141                      uint8_t *dst,
142                      size_t length,
143                      const uint8_t *src)
144 {
145   size_t done = 0;
146   size_t left = length;
147   unsigned left_over;
148   size_t bulk;
149   
150   while (ctx->bits && left)
151     {
152       left--;
153       done += base64_encode_single(ctx, dst + done, *src++);
154     }
155   
156   left_over = left % 3;
157   bulk = left - left_over;
158   
159   if (bulk)
160     {
161       assert(!(bulk % 3));
162       
163       encode_raw(ctx->alphabet, dst + done, bulk, src);
164       done += BASE64_ENCODE_RAW_LENGTH(bulk);
165       src += bulk;
166       left = left_over;
167     }
168
169   while (left)
170     {
171       left--;
172       done += base64_encode_single(ctx, dst + done, *src++);
173     }
174
175   assert(done <= BASE64_ENCODE_LENGTH(length));
176
177   return done;
178 }
179
180 /* DST should point to an area of size at least
181  * BASE64_ENCODE_FINAL_SIZE */
182 size_t
183 base64_encode_final(struct base64_encode_ctx *ctx,
184                     uint8_t *dst)
185 {
186   unsigned done = 0;
187   unsigned bits = ctx->bits;
188   
189   if (bits)
190     {
191       dst[done++] = ENCODE(ctx->alphabet, (ctx->word << (6 - ctx->bits)));
192       for (; bits < 6; bits += 2)
193         dst[done++] = '=';
194
195       ctx->bits = 0;
196     }
197
198   assert(done <= BASE64_ENCODE_FINAL_LENGTH);
199   return done;
200 }