base64.c 4.12 KB
Newer Older
Dan Egnor's avatar
Dan Egnor committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/* base64.c
 *
 * Base64 "ASCII armor" codec.
 */

/* nettle, low-level cryptographics library
 *
 * Copyright (C) 2002 Niels Mller, Dan Egnor
 *  
 * The nettle library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version.
 * 
 * The nettle library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 * License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with the nettle library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 * MA 02111-1307, USA.
 */

#include "base64.h"

#include <assert.h>
29
#include <stdlib.h>
Dan Egnor's avatar
Dan Egnor committed
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

#define TABLE_INVALID -1
#define TABLE_SPACE -2
#define TABLE_END -3

static const uint8_t encode_table[64] =
  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  "abcdefghijklmnopqrstuvwxyz"
  "0123456789+/";

static const signed char decode_table[256] =
{
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -1, -1, -2, -1, -1, 
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
  52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -3, -1, -1,
  -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
  15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
  -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
  41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
};

60
61
#define ENCODE(x) (encode_table[0x3F & (x)])

Dan Egnor's avatar
Dan Egnor committed
62
63
64
65
66
unsigned 
base64_encode(uint8_t *dst,
              unsigned src_length,
              const uint8_t *src)
{
67
68
69
70
  unsigned dst_length = BASE64_ENCODE_LENGTH(src_length);
  const uint8_t *in = src + src_length;
  uint8_t *out = dst + dst_length;
  unsigned left_over = src_length % 3;
Dan Egnor's avatar
Dan Egnor committed
71

72
  if (left_over)
Dan Egnor's avatar
Dan Egnor committed
73
    {
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
      switch(left_over)
	{
	case 1:
	  in--;
	  *--out = '=';
	  *--out = '=';
	  *--out = ENCODE(in[0] << 4);
	  *--out = ENCODE(in[0] >> 2);
	  break;
	  
	case 2:
	  in-= 2;
	  *--out = '=';
	  *--out = ENCODE( in[1] << 2);
	  *--out = ENCODE((in[0] << 4) | (in[1] >> 4));
	  *--out = ENCODE( in[0] >> 2);
	  break;
Dan Egnor's avatar
Dan Egnor committed
91

92
93
94
95
96
97
	default:
	  abort();
	}
    }
  
  while (in > src)
Dan Egnor's avatar
Dan Egnor committed
98
    {
99
100
101
102
103
      in -= 3;
      *--out = ENCODE( in[2]);
      *--out = ENCODE((in[1] << 2) | (in[2] >> 6));
      *--out = ENCODE((in[0] << 4) | (in[1] >> 4));
      *--out = ENCODE( in[0] >> 2);
Dan Egnor's avatar
Dan Egnor committed
104
105
    }

106
107
108
  assert(out == dst);

  return dst_length;
Dan Egnor's avatar
Dan Egnor committed
109
110
}

111
112
113
114
115
116
117
void
base64_decode_init(struct base64_ctx *ctx)
{
  ctx->shift = 10;
  ctx->accum = 0;
}

Dan Egnor's avatar
Dan Egnor committed
118
unsigned
119
120
121
122
base64_decode_update(struct base64_ctx *ctx,
                     uint8_t *dst,
                     unsigned src_length,
                     const uint8_t *src)
Dan Egnor's avatar
Dan Egnor committed
123
124
125
{
  uint8_t *out = dst;

126
  for (;;) 
Dan Egnor's avatar
Dan Egnor committed
127
    {
128
129
130
      int data;
      if (src_length == 0) return out - dst;
      data = decode_table[*src];
Dan Egnor's avatar
Dan Egnor committed
131
132
133
      switch (data)
        {
        default:
134
135
136
          ctx->accum |= data << ctx->shift;
          ctx->shift -= 6;
          if (ctx->shift <= 2)
Dan Egnor's avatar
Dan Egnor committed
137
            {
138
139
140
              *out++ = ctx->accum >> 8;
              ctx->accum <<= 8;
              ctx->shift += 8;
Dan Egnor's avatar
Dan Egnor committed
141
            }
142
	  /* Fall through */
Dan Egnor's avatar
Dan Egnor committed
143
144
145
        case TABLE_INVALID:
        case TABLE_SPACE:
        case TABLE_END:
146
147
148
149
	  /* FIXME: Silently ignores any invalid characters.
	   * We need to detect and return errors, in some way. */
          ++src;
          --src_length;
Dan Egnor's avatar
Dan Egnor committed
150
151
152
        }
    }
}