mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-03-01 17:10:42 +00:00
These functions only require 5 chars to encode 30 bits, and don't expect any padding. They will be used to encode dates in cookies. (cherry picked from commit a7e2b5fc4612994c7b13bcb103a4a2c3ecd6438a)
185 lines
4.8 KiB
C
185 lines
4.8 KiB
C
/*
|
|
* ASCII <-> Base64 conversion as described in RFC1421.
|
|
*
|
|
* Copyright 2006-2010 Willy Tarreau <w@1wt.eu>
|
|
* Copyright 2009-2010 Krzysztof Piotr Oledzki <ole@ans.pl>
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version
|
|
* 2 of the License, or (at your option) any later version.
|
|
*
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <common/base64.h>
|
|
#include <common/config.h>
|
|
|
|
#define B64BASE '#' /* arbitrary chosen base value */
|
|
#define B64CMIN '+'
|
|
#define B64CMAX 'z'
|
|
#define B64PADV 64 /* Base64 chosen special pad value */
|
|
|
|
const char base64tab[65]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
const char base64rev[]="b###cXYZ[\\]^_`a###d###$%&'()*+,-./0123456789:;<=######>?@ABCDEFGHIJKLMNOPQRSTUVW";
|
|
|
|
/* Encodes <ilen> bytes from <in> to <out> for at most <olen> chars (including
|
|
* the trailing zero). Returns the number of bytes written. No check is made
|
|
* for <in> or <out> to be NULL. Returns negative value if <olen> is too short
|
|
* to accept <ilen>. 4 output bytes are produced for 1 to 3 input bytes.
|
|
*/
|
|
int a2base64(char *in, int ilen, char *out, int olen)
|
|
{
|
|
int convlen;
|
|
|
|
convlen = ((ilen + 2) / 3) * 4;
|
|
|
|
if (convlen >= olen)
|
|
return -1;
|
|
|
|
/* we don't need to check olen anymore */
|
|
while (ilen >= 3) {
|
|
out[0] = base64tab[(((unsigned char)in[0]) >> 2)];
|
|
out[1] = base64tab[(((unsigned char)in[0] & 0x03) << 4) | (((unsigned char)in[1]) >> 4)];
|
|
out[2] = base64tab[(((unsigned char)in[1] & 0x0F) << 2) | (((unsigned char)in[2]) >> 6)];
|
|
out[3] = base64tab[(((unsigned char)in[2] & 0x3F))];
|
|
out += 4;
|
|
in += 3; ilen -= 3;
|
|
}
|
|
|
|
if (!ilen) {
|
|
out[0] = '\0';
|
|
} else {
|
|
out[0] = base64tab[((unsigned char)in[0]) >> 2];
|
|
if (ilen == 1) {
|
|
out[1] = base64tab[((unsigned char)in[0] & 0x03) << 4];
|
|
out[2] = '=';
|
|
} else {
|
|
out[1] = base64tab[(((unsigned char)in[0] & 0x03) << 4) |
|
|
(((unsigned char)in[1]) >> 4)];
|
|
out[2] = base64tab[((unsigned char)in[1] & 0x0F) << 2];
|
|
}
|
|
out[3] = '=';
|
|
out[4] = '\0';
|
|
}
|
|
|
|
return convlen;
|
|
}
|
|
|
|
/* Decodes <ilen> bytes from <in> to <out> for at most <olen> chars.
|
|
* Returns the number of bytes converted. No check is made for
|
|
* <in> or <out> to be NULL. Returns -1 if <in> is invalid or ilen
|
|
* has wrong size, -2 if <olen> is too short.
|
|
* 1 to 3 output bytes are produced for 4 input bytes.
|
|
*/
|
|
int base64dec(const char *in, size_t ilen, char *out, size_t olen) {
|
|
|
|
unsigned char t[4];
|
|
signed char b;
|
|
int convlen = 0, i = 0, pad = 0;
|
|
|
|
if (ilen % 4)
|
|
return -1;
|
|
|
|
if (olen < ilen / 4 * 3)
|
|
return -2;
|
|
|
|
while (ilen) {
|
|
|
|
/* if (*p < B64CMIN || *p > B64CMAX) */
|
|
b = (signed char)*in - B64CMIN;
|
|
if ((unsigned char)b > (B64CMAX-B64CMIN))
|
|
return -1;
|
|
|
|
b = base64rev[b] - B64BASE - 1;
|
|
|
|
/* b == -1: invalid character */
|
|
if (b < 0)
|
|
return -1;
|
|
|
|
/* padding has to be continous */
|
|
if (pad && b != B64PADV)
|
|
return -1;
|
|
|
|
/* valid padding: "XX==" or "XXX=", but never "X===" or "====" */
|
|
if (pad && i < 2)
|
|
return -1;
|
|
|
|
if (b == B64PADV)
|
|
pad++;
|
|
|
|
t[i++] = b;
|
|
|
|
if (i == 4) {
|
|
/*
|
|
* WARNING: we allow to write little more data than we
|
|
* should, but the checks from the beginning of the
|
|
* functions guarantee that we can safely do that.
|
|
*/
|
|
|
|
/* xx000000 xx001111 xx111122 xx222222 */
|
|
out[convlen] = ((t[0] << 2) + (t[1] >> 4));
|
|
out[convlen+1] = ((t[1] << 4) + (t[2] >> 2));
|
|
out[convlen+2] = ((t[2] << 6) + (t[3] >> 0));
|
|
|
|
convlen += 3-pad;
|
|
|
|
pad = i = 0;
|
|
}
|
|
|
|
in++;
|
|
ilen--;
|
|
}
|
|
|
|
return convlen;
|
|
}
|
|
|
|
|
|
/* Converts the lower 30 bits of an integer to a 5-char base64 string. The
|
|
* caller is responsible for ensuring that the output buffer can accept 6 bytes
|
|
* (5 + the trailing zero). The pointer to the string is returned. The
|
|
* conversion is performed with MSB first and in a format that can be
|
|
* decoded with b64tos30(). This format is not padded and thus is not
|
|
* compatible with usual base64 routines.
|
|
*/
|
|
const char *s30tob64(int in, char *out)
|
|
{
|
|
int i;
|
|
for (i = 0; i < 5; i++) {
|
|
out[i] = base64tab[(in >> 24) & 0x3F];
|
|
in <<= 6;
|
|
}
|
|
out[5] = '\0';
|
|
return out;
|
|
}
|
|
|
|
/* Converts a 5-char base64 string encoded by s30tob64() into a 30-bit integer.
|
|
* The caller is responsible for ensuring that the input contains at least 5
|
|
* chars. If any unexpected character is encountered, a negative value is
|
|
* returned. Otherwise the decoded value is returned.
|
|
*/
|
|
int b64tos30(const char *in)
|
|
{
|
|
int i, out;
|
|
signed char b;
|
|
|
|
out = 0;
|
|
for (i = 0; i < 5; i++) {
|
|
b = (signed char)in[i] - B64CMIN;
|
|
if ((unsigned char)b > (B64CMAX - B64CMIN))
|
|
return -1; /* input character out of range */
|
|
|
|
b = base64rev[b] - B64BASE - 1;
|
|
if (b < 0) /* invalid character */
|
|
return -1;
|
|
|
|
if (b == B64PADV) /* padding not allowed */
|
|
return -1;
|
|
|
|
out = (out << 6) + b;
|
|
}
|
|
return out;
|
|
}
|