mirror of
https://github.com/zeromq/libzmq.git
synced 2024-12-12 10:33:52 +01:00
Added Z85 support
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.
This commit is contained in:
parent
76df045950
commit
7041770108
@ -1,12 +1,12 @@
|
||||
ACLOCAL_AMFLAGS = -I config
|
||||
|
||||
if BUILD_PGM
|
||||
SUBDIRS = foreign/openpgm src doc perf tests
|
||||
SUBDIRS = foreign/openpgm src doc perf tests tools
|
||||
else
|
||||
SUBDIRS = src doc perf tests
|
||||
SUBDIRS = src doc perf tests tools
|
||||
endif
|
||||
|
||||
DIST_SUBDIRS = foreign/openpgm src doc perf tests builds/msvc
|
||||
DIST_SUBDIRS = foreign/openpgm src doc perf tests tools builds/msvc
|
||||
|
||||
EXTRA_DIST = \
|
||||
autogen.sh \
|
||||
|
12
configure.ac
12
configure.ac
@ -428,10 +428,14 @@ AC_SUBST(LIBZMQ_EXTRA_CFLAGS)
|
||||
AC_SUBST(LIBZMQ_EXTRA_CXXFLAGS)
|
||||
AC_SUBST(LIBZMQ_EXTRA_LDFLAGS)
|
||||
|
||||
AC_CONFIG_FILES([Makefile src/Makefile doc/Makefile
|
||||
perf/Makefile src/libzmq.pc \
|
||||
builds/msvc/Makefile tests/Makefile \
|
||||
AC_CONFIG_FILES([Makefile \
|
||||
src/Makefile \
|
||||
src/libzmq.pc \
|
||||
doc/Makefile \
|
||||
perf/Makefile \
|
||||
tests/Makefile \
|
||||
tools/Makefile \
|
||||
builds/msvc/Makefile \
|
||||
foreign/openpgm/Makefile \
|
||||
builds/redhat/zeromq.spec])
|
||||
AC_OUTPUT
|
||||
|
||||
|
@ -37,21 +37,43 @@ long-term key pair.
|
||||
If the server does authentication it will be based on the client's long
|
||||
term public key.
|
||||
|
||||
KEY ENCODING
|
||||
------------
|
||||
The standard representation for keys in source code is either 32 bytes of
|
||||
base 256 (binary) data, or 40 characters of base 85 data encoded using the
|
||||
Z85 algorithm defined by http://rfc.zeromq.org/spec:32.
|
||||
|
||||
The Z85 algorithm is designed to produce printable key strings for use in
|
||||
configuration files, the command line, and code. There is a reference
|
||||
implementation in C at https://github.com/zeromq/rfc/tree/master/src.
|
||||
|
||||
|
||||
TEST KEY VALUES
|
||||
---------------
|
||||
|
||||
For test cases, the client shall use this long-term key pair:
|
||||
For test cases, the client shall use this long-term key pair (specified
|
||||
as hexadecimal and in Z85):
|
||||
|
||||
----
|
||||
public: BB88471D65E2659B30C55A5321CEBB5AAB2B70A398645C26DCA2B2FCB43FC518
|
||||
secret: 7BB864B489AFA3671FBE69101F94B38972F24816DFB01B51656B3FEC8DFD0888
|
||||
public:
|
||||
BB88471D65E2659B30C55A5321CEBB5AAB2B70A398645C26DCA2B2FCB43FC518
|
||||
Yne@$w-vo<fVvi]a<NY6T1ed:M$fCG*[IaLV{hID
|
||||
|
||||
secret:
|
||||
7BB864B489AFA3671FBE69101F94B38972F24816DFB01B51656B3FEC8DFD0888
|
||||
D:)Q[IlAW!ahhC2ac:9*A}h:p?([4%wOTJ%JR%cs
|
||||
----
|
||||
|
||||
And the server shall use this long-term key pair:
|
||||
And the server shall use this long-term key pair (specified as hexadecimal
|
||||
and in Z85):
|
||||
|
||||
----
|
||||
public: 54FCBA24E93249969316FB617C872BB0C1D1FF14800427C594CBFACF1BC2D652
|
||||
secret: 8E0BDD697628B91D8F245587EE95C5B04D48963F79259877B49CD9063AEAD3B7
|
||||
public:
|
||||
54FCBA24E93249969316FB617C872BB0C1D1FF14800427C594CBFACF1BC2D652
|
||||
rq:rM>}U?@Lns47E1%kR.o@n%FcmmsL/@{H8]yf7
|
||||
|
||||
secret:
|
||||
8E0BDD697628B91D8F245587EE95C5B04D48963F79259877B49CD9063AEAD3B7
|
||||
JTKVSB%%)wK0E.X)V>+}o?pNmC{O&4W4b!Ni{Lh6
|
||||
----
|
||||
|
||||
SEE ALSO
|
||||
|
@ -486,8 +486,8 @@ Default value:: -1 (leave to OS default)
|
||||
Applicable socket types:: all, when using TCP transports.
|
||||
|
||||
|
||||
ZMQ_MECHANISM: Retrieve the current security mechanism
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
ZMQ_MECHANISM: Retrieve current security mechanism
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The 'ZMQ_MECHANISM' option shall retrieve the current security mechanism
|
||||
for the socket.
|
||||
|
||||
@ -498,8 +498,8 @@ Default value:: ZMQ_NULL
|
||||
Applicable socket types:: all, when using TCP or IPC transports
|
||||
|
||||
|
||||
ZMQ_PLAIN_SERVER: Retrieve the PLAIN server role
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
ZMQ_PLAIN_SERVER: Retrieve current PLAIN server role
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Returns the 'ZMQ_PLAIN_SERVER' option, if any, previously set on the socket.
|
||||
|
||||
[horizontal]
|
||||
@ -509,8 +509,8 @@ Default value:: int
|
||||
Applicable socket types:: all, when using TCP or IPC transports
|
||||
|
||||
|
||||
ZMQ_PLAIN_USERNAME: Retrieve the last username set
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
ZMQ_PLAIN_USERNAME: Retrieve current PLAIN username
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The 'ZMQ_PLAIN_USERNAME' option shall retrieve the last username set for
|
||||
the PLAIN security mechanism. The returned value shall be a NULL-terminated
|
||||
string and MAY be empty. The returned size SHALL include the terminating
|
||||
@ -523,8 +523,8 @@ Default value:: null string
|
||||
Applicable socket types:: all, when using TCP or IPC transports
|
||||
|
||||
|
||||
ZMQ_PLAIN_PASSWORD: Retrieve the last password set
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
ZMQ_PLAIN_PASSWORD: Retrieve current password
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The 'ZMQ_PLAIN_PASSWORD' option shall retrieve the last password set for
|
||||
the PLAIN security mechanism. The returned value shall be a NULL-terminated
|
||||
string and MAY be empty. The returned size SHALL include the terminating
|
||||
@ -537,6 +537,48 @@ Default value:: null string
|
||||
Applicable socket types:: all, when using TCP or IPC transports
|
||||
|
||||
|
||||
ZMQ_CURVE_PUBLICKEY: Retrieve current CURVE public key
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Retrieves the current long term public key for the socket. You can
|
||||
provide either a 32 byte buffer, to retrieve the binary key value, or
|
||||
a 40 byte buffer, to retrieve the key in a printable Z85 format.
|
||||
|
||||
[horizontal]
|
||||
Option value type:: binary data or Z85 text string
|
||||
Option value size:: 32 or 40
|
||||
Default value:: null
|
||||
Applicable socket types:: all, when using TCP transport
|
||||
|
||||
|
||||
ZMQ_CURVE_SECRETKEY: Retrieve current CURVE secret key
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Retrieves the current long term secret key for the socket. You can
|
||||
provide either a 32 byte buffer, to retrieve the binary key value, or
|
||||
a 40 byte buffer, to retrieve the key in a printable Z85 format.
|
||||
|
||||
[horizontal]
|
||||
Option value type:: binary data or Z85 text string
|
||||
Option value size:: 32 or 40
|
||||
Default value:: null
|
||||
Applicable socket types:: all, when using TCP transport
|
||||
|
||||
|
||||
ZMQ_CURVE_SERVERKEY: Retrieve current CURVE server key
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Retrieves the current server key for the client socket. You can
|
||||
provide either a 32 byte buffer, to retrieve the binary key value, or
|
||||
a 40 byte buffer, to retrieve the key in a printable Z85 format.
|
||||
|
||||
[horizontal]
|
||||
Option value type:: binary data or Z85 text string
|
||||
Option value size:: 32 or 40
|
||||
Default value:: null
|
||||
Applicable socket types:: all, when using TCP transport
|
||||
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
The _zmq_getsockopt()_ function shall return zero if successful. Otherwise it
|
||||
|
@ -596,13 +596,17 @@ ZMQ_CURVE_PUBLICKEY: Set CURVE public key
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Sets the socket's long term public key. You must set this on a CURVE
|
||||
client or server socket, see linkzmq:zmq_curve[7]. The key is 32 bytes.
|
||||
For servers, it must be persisted and shared through some unspecified
|
||||
secure mechanism to clients.
|
||||
client or server socket, see linkzmq:zmq_curve[7]. You can provide the
|
||||
key as 32 binary bytes, or as a 40-character string encoded in the Z85
|
||||
encoding format. For servers, the public key must be persisted and
|
||||
shared through some unspecified but secure mechanism to clients. The
|
||||
public key must always be used with the matching secret key generated
|
||||
at the same time. To generate a public/secret key pair, use the
|
||||
tools/curve_keygen tool.
|
||||
|
||||
[horizontal]
|
||||
Option value type:: binary data
|
||||
Option value size:: 32
|
||||
Option value type:: binary data or Z85 text string
|
||||
Option value size:: 32 or 40
|
||||
Default value:: NULL
|
||||
Applicable socket types:: all, when using TCP transport
|
||||
|
||||
@ -611,11 +615,13 @@ ZMQ_CURVE_SECRETKEY: Set CURVE secret key
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Sets the socket's long term secret key. You must set this on a CURVE
|
||||
client socket, see linkzmq:zmq_curve[7]. The key is 32 bytes.
|
||||
client socket, see linkzmq:zmq_curve[7]. You can provide the key as
|
||||
32 binary bytes, or as a 40-character string encoded in the Z85 encoding
|
||||
format.
|
||||
|
||||
[horizontal]
|
||||
Option value type:: binary data
|
||||
Option value size:: 32
|
||||
Option value type:: binary data or Z85 text string
|
||||
Option value size:: 32 or 40
|
||||
Default value:: NULL
|
||||
Applicable socket types:: all, when using TCP transport
|
||||
|
||||
@ -624,12 +630,14 @@ ZMQ_CURVE_SERVERKEY: Set CURVE server key
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Sets the socket's long term server key. You must set this on a CURVE
|
||||
client socket, see linkzmq:zmq_curve[7]. The key is 32 bytes. This
|
||||
key must be the same as the public key set on the server socket.
|
||||
client socket, see linkzmq:zmq_curve[7]. You can provide the key as
|
||||
32 binary bytes, or as a 40-character string encoded in the Z85 encoding
|
||||
format. This key must be the same as the public key set on the server
|
||||
socket.
|
||||
|
||||
[horizontal]
|
||||
Option value type:: binary data
|
||||
Option value size:: 32
|
||||
Option value type:: binary data or Z85 text string
|
||||
Option value size:: 32 or 40
|
||||
Default value:: NULL
|
||||
Applicable socket types:: all, when using TCP transport
|
||||
|
||||
|
@ -89,6 +89,7 @@ libzmq_la_SOURCES = \
|
||||
xsub.hpp \
|
||||
ypipe.hpp \
|
||||
yqueue.hpp \
|
||||
z85_codec.hpp \
|
||||
address.cpp \
|
||||
clock.cpp \
|
||||
ctx.cpp \
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include "options.hpp"
|
||||
#include "err.hpp"
|
||||
#include "z85_codec.hpp"
|
||||
|
||||
zmq::options_t::options_t () :
|
||||
sndhwm (1000),
|
||||
@ -285,7 +286,7 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
|
||||
}
|
||||
break;
|
||||
|
||||
// If libsodium isn't installed, these options provoke EINVAL
|
||||
// If libsodium isn't installed, these options provoke EINVAL
|
||||
# ifdef HAVE_LIBSODIUM
|
||||
case ZMQ_CURVE_SERVER:
|
||||
if (is_int && (value == 0 || value == 1)) {
|
||||
@ -301,6 +302,12 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
|
||||
mechanism = ZMQ_CURVE;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
if (optvallen_ == CURVE_KEYSIZE_Z85) {
|
||||
Z85_decode (curve_public_key, (char *) optval_);
|
||||
mechanism = ZMQ_CURVE;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case ZMQ_CURVE_SECRETKEY:
|
||||
@ -309,6 +316,12 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
|
||||
mechanism = ZMQ_CURVE;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
if (optvallen_ == CURVE_KEYSIZE_Z85) {
|
||||
Z85_decode (curve_secret_key, (char *) optval_);
|
||||
mechanism = ZMQ_CURVE;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case ZMQ_CURVE_SERVERKEY:
|
||||
@ -318,6 +331,13 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
|
||||
mechanism = ZMQ_CURVE;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
if (optvallen_ == CURVE_KEYSIZE_Z85) {
|
||||
Z85_decode (curve_server_key, (char *) optval_);
|
||||
as_server = 0;
|
||||
mechanism = ZMQ_CURVE;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
# endif
|
||||
}
|
||||
@ -539,7 +559,7 @@ int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_)
|
||||
}
|
||||
break;
|
||||
|
||||
// If libsodium isn't installed, these options provoke EINVAL
|
||||
// If libsodium isn't installed, these options provoke EINVAL
|
||||
# ifdef HAVE_LIBSODIUM
|
||||
case ZMQ_CURVE_SERVER:
|
||||
if (is_int) {
|
||||
@ -553,6 +573,11 @@ int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_)
|
||||
memcpy (optval_, curve_public_key, CURVE_KEYSIZE);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
if (*optvallen_ == CURVE_KEYSIZE_Z85) {
|
||||
Z85_encode ((char *) optval_, curve_public_key, CURVE_KEYSIZE);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case ZMQ_CURVE_SECRETKEY:
|
||||
@ -560,6 +585,11 @@ int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_)
|
||||
memcpy (optval_, curve_secret_key, CURVE_KEYSIZE);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
if (*optvallen_ == CURVE_KEYSIZE_Z85) {
|
||||
Z85_encode ((char *) optval_, curve_secret_key, CURVE_KEYSIZE);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case ZMQ_CURVE_SERVERKEY:
|
||||
@ -567,6 +597,11 @@ int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_)
|
||||
memcpy (optval_, curve_server_key, CURVE_KEYSIZE);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
if (*optvallen_ == CURVE_KEYSIZE_Z85) {
|
||||
Z85_encode ((char *) optval_, curve_server_key, CURVE_KEYSIZE);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
# endif
|
||||
}
|
||||
|
@ -28,7 +28,10 @@
|
||||
#include "tcp_address.hpp"
|
||||
#include "../include/zmq.h"
|
||||
|
||||
#define CURVE_KEYSIZE 32
|
||||
// Normal base 256 key is 32 bytes
|
||||
#define CURVE_KEYSIZE 32
|
||||
// Key encoded using Z85 is 40 bytes
|
||||
#define CURVE_KEYSIZE_Z85 40
|
||||
|
||||
namespace zmq
|
||||
{
|
||||
|
108
src/z85_codec.hpp
Normal file
108
src/z85_codec.hpp
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
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
|
||||
|
||||
#ifndef __ZMQ_Z85_CODEC_HPP_INCLUDED__
|
||||
#define __ZMQ_Z85_CODEC_HPP_INCLUDED__
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
#endif
|
@ -56,7 +56,7 @@ zap_handler (void *zap)
|
||||
int main (void)
|
||||
{
|
||||
#ifndef HAVE_LIBSODIUM
|
||||
printf("libsodium not installed, skipping CURVE test\n");
|
||||
printf ("libsodium not installed, skipping CURVE test\n");
|
||||
return 0;
|
||||
#endif
|
||||
int rc;
|
||||
@ -75,43 +75,24 @@ int main (void)
|
||||
void *client = zmq_socket (ctx, ZMQ_DEALER);
|
||||
assert (client);
|
||||
|
||||
// Test keys from the zmq_curve man page
|
||||
char client_public [] = "Yne@$w-vo<fVvi]a<NY6T1ed:M$fCG*[IaLV{hID";
|
||||
char client_secret [] = "D:)Q[IlAW!ahhC2ac:9*A}h:p?([4%wOTJ%JR%cs";
|
||||
char server_public [] = "rq:rM>}U?@Lns47E1%kR.o@n%FcmmsL/@{H8]yf7";
|
||||
char server_secret [] = "JTKVSB%%)wK0E.X)V>+}o?pNmC{O&4W4b!Ni{Lh6";
|
||||
|
||||
as_server = 1;
|
||||
rc = zmq_setsockopt(server, ZMQ_CURVE_SERVER, &as_server, sizeof(int));
|
||||
// Test key from the zmq_curve man page.
|
||||
uint8_t server_secret[32] = {
|
||||
0x8E, 0x0B, 0xDD, 0x69, 0x76, 0x28, 0xB9, 0x1D, 0x8F, 0x24,
|
||||
0x55, 0x87, 0xEE, 0x95, 0xC5, 0xB0, 0x4D, 0x48, 0x96, 0x3F,
|
||||
0x79, 0x25, 0x98, 0x77, 0xB4, 0x9C, 0xD9, 0x06, 0x3A, 0xEA,
|
||||
0xD3, 0xB7
|
||||
};
|
||||
rc = zmq_setsockopt(server, ZMQ_CURVE_SECRETKEY, server_secret, sizeof(server_secret));
|
||||
assert(rc == 0);
|
||||
rc = zmq_setsockopt (server, ZMQ_CURVE_SERVER, &as_server, sizeof (int));
|
||||
assert (rc == 0);
|
||||
rc = zmq_setsockopt (server, ZMQ_CURVE_SECRETKEY, server_secret, 40);
|
||||
assert (rc == 0);
|
||||
|
||||
// Test client keys from the zmq_curve man page.
|
||||
uint8_t server_public[32] = {
|
||||
0x54, 0xFC, 0xBA, 0x24, 0xE9, 0x32, 0x49, 0x96, 0x93, 0x16,
|
||||
0xFB, 0x61, 0x7C, 0x87, 0x2B, 0xB0, 0xC1, 0xD1, 0xFF, 0x14,
|
||||
0x80, 0x04, 0x27, 0xC5, 0x94, 0xCB, 0xFA, 0xCF, 0x1B, 0xC2,
|
||||
0xD6, 0x52
|
||||
};
|
||||
rc = zmq_setsockopt(client, ZMQ_CURVE_SERVERKEY, server_public, sizeof(server_public));
|
||||
assert(rc == 0);
|
||||
uint8_t client_public[32] = {
|
||||
0xBB, 0x88, 0x47, 0x1D, 0x65, 0xE2, 0x65, 0x9B, 0x30, 0xC5,
|
||||
0x5A, 0x53, 0x21, 0xCE, 0xBB, 0x5A, 0xAB, 0x2B, 0x70, 0xA3,
|
||||
0x98, 0x64, 0x5C, 0x26, 0xDC, 0xA2, 0xB2, 0xFC, 0xB4, 0x3F,
|
||||
0xC5, 0x18
|
||||
};
|
||||
rc = zmq_setsockopt(client, ZMQ_CURVE_PUBLICKEY, client_public, sizeof(client_public));
|
||||
assert(rc == 0);
|
||||
uint8_t client_secret[32] = {
|
||||
0x7B, 0xB8, 0x64, 0xB4, 0x89, 0xAF, 0xA3, 0x67, 0x1F, 0xBE,
|
||||
0x69, 0x10, 0x1F, 0x94, 0xB3, 0x89, 0x72, 0xF2, 0x48, 0x16,
|
||||
0xDF, 0xB0, 0x1B, 0x51, 0x65, 0x6B, 0x3F, 0xEC, 0x8D, 0xFD,
|
||||
0x08, 0x88
|
||||
};
|
||||
rc = zmq_setsockopt(client, ZMQ_CURVE_SECRETKEY, client_secret, sizeof(client_secret));
|
||||
assert(rc == 0);
|
||||
rc = zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, server_public, 40);
|
||||
assert (rc == 0);
|
||||
rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, client_public, 40);
|
||||
assert (rc == 0);
|
||||
rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, client_secret, 40);
|
||||
assert (rc == 0);
|
||||
|
||||
// Test the client and server both have the right mechanism.
|
||||
optsize = sizeof (int);
|
||||
|
1
tools/Makefile.am
Normal file
1
tools/Makefile.am
Normal file
@ -0,0 +1 @@
|
||||
EXTRA_DIST = curve_keygen.c z85_codec.h
|
@ -3,6 +3,16 @@
|
||||
|
||||
This file is part of 0MQ.
|
||||
|
||||
This tool generates a keypair for the libzmq CURVE security mechanism,
|
||||
and encodes the keypair to give two printable strings that you can use
|
||||
in configuration files or source code. The encoding uses Z85, which is
|
||||
a base-85 format that is described in 0MQ RFC 32, and which has an
|
||||
implementation in the Z85.c source used by this tool. The keypair
|
||||
always works with the secret key held by one party and the public key
|
||||
distributed (securely!) to peers wishing to connect to it. CURVE is
|
||||
defined by http://rfc.zeromq.org/spec:25. Z85 is defined by
|
||||
http://rfc.zeromq.org/spec:32.
|
||||
|
||||
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
|
||||
@ -21,6 +31,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <sodium.h>
|
||||
#include "z85_codec.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
@ -28,20 +39,31 @@ int main (void)
|
||||
|| crypto_box_SECRETKEYBYTES != 32
|
||||
# error "libsodium not built correctly"
|
||||
# endif
|
||||
|
||||
puts ("This tool generates a keypair for the libzmq CURVE security mechanism,");
|
||||
puts ("and encodes the keypair to give two printable strings that you can use");
|
||||
puts ("in configuration files or source code. The encoding uses Z85, which is");
|
||||
puts ("a base-85 format that is described in 0MQ RFC 32, and which has an");
|
||||
puts ("implementation in the Z85.c source used by this tool. The keypair");
|
||||
puts ("always works with the secret key held by one party and the public key");
|
||||
puts ("distributed (securely!) to peers wishing to connect to it. CURVE is");
|
||||
puts ("defined by http://rfc.zeromq.org/spec:25. Z85 is defined by");
|
||||
puts ("http://rfc.zeromq.org/spec:32.");
|
||||
|
||||
uint8_t public_key [32];
|
||||
uint8_t secret_key [32];
|
||||
|
||||
int rc = crypto_box_keypair (public_key, secret_key);
|
||||
assert (rc == 0);
|
||||
int byte_nbr;
|
||||
printf ("public: ");
|
||||
for (byte_nbr = 0; byte_nbr < 32; byte_nbr++)
|
||||
printf ("%02X", public_key [byte_nbr]);
|
||||
printf ("\n");
|
||||
printf ("secret: ");
|
||||
for (byte_nbr = 0; byte_nbr < 32; byte_nbr++)
|
||||
printf ("%02X", secret_key [byte_nbr]);
|
||||
printf ("\n");
|
||||
|
||||
char encoded [40];
|
||||
Z85_encode (encoded, public_key, 32);
|
||||
puts ("\n== CURVE PUBLIC KEY ==");
|
||||
puts (encoded);
|
||||
|
||||
Z85_encode (encoded, secret_key, 32);
|
||||
puts ("\n== CURVE SECRET KEY ==");
|
||||
puts (encoded);
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
108
tools/z85_codec.h
Normal file
108
tools/z85_codec.h
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user