mirror of
https://github.com/zeromq/libzmq.git
synced 2024-12-31 01:43:02 +08:00
7041770108
The use of binary for CURVE keys is painful; you cannot easily copy these in e.g. email, or use them directly in source code. There are various encoding possibilities. Base16 and Base64 are not optimal. Ascii85 is not safe for source (it generates quotes and escapes). So, I've designed a new Base85 encoding, Z85, which is safe to use in code and elsewhere, and I've modified libzmq to use this where it also uses binary keys (in get/setsockopt). Very simply, if you use a 32-byte value, it's Base256 (binary), and if you use a 40-byte value, it's Base85 (Z85). I've put the Z85 codec into z85_codec.hpp, it's not elegant C++ but it is minimal and it works. Feel free to rewrap as a real class if this annoys you.
109 lines
3.6 KiB
C
109 lines
3.6 KiB
C
/*
|
|
Copyright (c) 2007-2013 Contributors as noted in the AUTHORS file
|
|
|
|
This file is part of 0MQ.
|
|
|
|
0MQ 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 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
0MQ 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
// Z85 codec, taken from 0MQ RFC project, implements RFC32 Z85 encoding
|
|
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
|
|
// Maps base 256 to base 85
|
|
static char encoder [85 + 1] = {
|
|
"0123456789" "abcdefghij" "klmnopqrst" "uvwxyzABCD"
|
|
"EFGHIJKLMN" "OPQRSTUVWX" "YZ.-:+=^!/" "*?&<>()[]{"
|
|
"}@%$#"
|
|
};
|
|
|
|
// Maps base 85 to base 256
|
|
// We chop off lower 32 and higher 128 ranges
|
|
static uint8_t decoder [96] = {
|
|
0x00, 0x44, 0x00, 0x54, 0x53, 0x52, 0x48, 0x00,
|
|
0x4B, 0x4C, 0x46, 0x41, 0x00, 0x3F, 0x3E, 0x45,
|
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
|
0x08, 0x09, 0x40, 0x00, 0x49, 0x42, 0x4A, 0x47,
|
|
0x51, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A,
|
|
0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32,
|
|
0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A,
|
|
0x3B, 0x3C, 0x3D, 0x4D, 0x00, 0x4E, 0x43, 0x00,
|
|
0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
|
|
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
|
0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
|
|
0x21, 0x22, 0x23, 0x4F, 0x00, 0x50, 0x00, 0x00
|
|
};
|
|
|
|
// --------------------------------------------------------------------------
|
|
// Encode a binary frame as a string; destination string MUST be at least
|
|
// size * 5 / 4 bytes long. Returns dest. Size must be a multiple of 4.
|
|
|
|
char *
|
|
Z85_encode (char *dest, uint8_t *data, size_t size)
|
|
{
|
|
assert (size % 4 == 0);
|
|
uint char_nbr = 0;
|
|
uint byte_nbr = 0;
|
|
uint32_t value = 0;
|
|
while (byte_nbr < size) {
|
|
// Accumulate value in base 256 (binary)
|
|
value = value * 256 + data [byte_nbr++];
|
|
if (byte_nbr % 4 == 0) {
|
|
// Output value in base 85
|
|
uint divisor = 85 * 85 * 85 * 85;
|
|
while (divisor) {
|
|
dest [char_nbr++] = encoder [value / divisor % 85];
|
|
divisor /= 85;
|
|
}
|
|
value = 0;
|
|
}
|
|
}
|
|
assert (char_nbr == size * 5 / 4);
|
|
dest [char_nbr] = 0;
|
|
return dest;
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
// Decode an encoded string into a binary frame; dest must be at least
|
|
// strlen (string) * 4 / 5 bytes long. Returns dest. strlen (string)
|
|
// must be a multiple of 5.
|
|
|
|
uint8_t *
|
|
Z85_decode (uint8_t *dest, char *string)
|
|
{
|
|
assert (strlen (string) % 5 == 0);
|
|
uint byte_nbr = 0;
|
|
uint char_nbr = 0;
|
|
uint32_t value = 0;
|
|
while (char_nbr < strlen (string)) {
|
|
// Accumulate value in base 85
|
|
value = value * 85 + decoder [(uint8_t) string [char_nbr++] - 32];
|
|
if (char_nbr % 5 == 0) {
|
|
// Output value in base 256
|
|
uint divisor = 256 * 256 * 256;
|
|
while (divisor) {
|
|
dest [byte_nbr++] = value / divisor % 256;
|
|
divisor /= 256;
|
|
}
|
|
value = 0;
|
|
}
|
|
}
|
|
assert (byte_nbr == strlen (string) * 4 / 5);
|
|
return dest;
|
|
}
|