Skip to content

Commit

Permalink
Added Z85 support
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
hintjens committed Jun 28, 2013
1 parent 76df045 commit 7041770
Show file tree
Hide file tree
Showing 13 changed files with 418 additions and 83 deletions.
6 changes: 3 additions & 3 deletions Makefile.am
Original file line number Diff line number Diff line change
@@ -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 \
Expand Down
12 changes: 8 additions & 4 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -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

36 changes: 29 additions & 7 deletions doc/zmq_curve.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
58 changes: 50 additions & 8 deletions doc/zmq_getsockopt.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -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]
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
32 changes: 20 additions & 12 deletions doc/zmq_setsockopt.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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

Expand All @@ -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

Expand Down
1 change: 1 addition & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ libzmq_la_SOURCES = \
xsub.hpp \
ypipe.hpp \
yqueue.hpp \
z85_codec.hpp \
address.cpp \
clock.cpp \
ctx.cpp \
Expand Down
39 changes: 37 additions & 2 deletions src/options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include "options.hpp"
#include "err.hpp"
#include "z85_codec.hpp"

zmq::options_t::options_t () :
sndhwm (1000),
Expand Down Expand Up @@ -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)) {
Expand All @@ -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:
Expand All @@ -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:
Expand All @@ -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
}
Expand Down Expand Up @@ -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) {
Expand All @@ -553,20 +573,35 @@ 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:
if (*optvallen_ == CURVE_KEYSIZE) {
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:
if (*optvallen_ == CURVE_KEYSIZE) {
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
}
Expand Down
5 changes: 4 additions & 1 deletion src/options.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
Loading

0 comments on commit 7041770

Please sign in to comment.