我可以在ZeroMQ中交换私钥和公钥

时间:2016-10-13 08:54:49

标签: c encryption zeromq

目前,我正在调查使用ZeroMQ和Curve来保护发布商和订阅者之间的流量的可能性。

我已经成功实现了一个使用CZMQ的pub子系统。

目前,我的发布商正在使用他的私钥加密他想要发送的数据,订阅者可以使用发布者的公钥解密这些数据。这更像是在验证'数据比加密'数据。因为当有一个中间人时,他仍然可以解密所有数据,因为出版商的公钥是公开的。

我使用最新版本的ZeroMQ和CZMQ在C编码。

我的publisher.c

zctx_t* zmq_context = zctx_new();

zauth_t* auth = zauth_new (zmq_context);
zauth_set_verbose (auth, true);
zauth_configure_curve (auth, "*", CURVE_ALLOW_ANY);

zcert_t* pub_cert = zcert_load("cert.key"); // private key of publisher
void* socket = zsocket_new(zmq_context, ZMQ_PUB);
zcert_apply(pub_cert, socket);
zsocket_set_curve_server(socket, true);

//start publishing from here

我的subscriber.c

zctx_t* zmq_context = zctx_new();

zcert_t* sub_cert = zcert_new();
zcert_t* pub_cert = zcert_load("cert.pub"); // public key of publisher
char* pub_key = zcert_public_txt(pub_cert);

void* zmq_s = zsocket_new(zmq_context, ZMQ_SUB);
zcert_apply(sub_cert, zmq_s);
zsocket_set_curve_serverkey(zmq_s, pub_key);

//start subscribing to topics and receiving messages from here

从这一点开始,发布者使用他的私钥加密所有数据,并且订阅正在使用发布者的公钥解密所有数据。我想交换这个系统。

因此,我想使用发布者的公钥加密所有数据,并使用发布者的私钥解密所有数据。

我已对其进行了测试,并将zcert_load("cert.key")更改为我的publisher.c中的zcert_load("cert.pub")

我还在subscriber.c中更改了此代码:

zcert_t* pub_cert = zcert_load("cert.pub"); // public key of publisher
char* pub_key = zcert_public_txt(pub_cert);

到此代码:

zcert_t* pub_cert = zcert_load("cert.key"); // private key of publisher
char* pub_key = zcert_secret_txt(pub_cert);

当我通过这些代码更改运行发布商和订阅者时,发布商会不断向我发送消息:CURVE I: cannot open client HELLO -- wrong server key?

我的问题:是否可以使用公钥加密数据(发布者套接字)和使用ZeroMQ和CZMQ架构解密数据(用户套接字)的私钥?

非常感谢提前,
罗伊

1 个答案:

答案 0 :(得分:1)

我认为您误解了ZeroMQ CURVE机制。 Pieter Hintjens撰写了两篇很棒的文章,one is theoretical,你可以在这里找到:

  

客户端和服务器具有长期永久密钥,并且对于每个连接,它们创建并安全地交换短期临时密钥。每个密钥都是公钥/密钥密钥对,遵循椭圆曲线安全模型。

     

要启动安全连接,客户端需要服务器永久公钥。然后,它会生成一个临时密钥对,并向包含其短期公钥的服务器发送HELLO命令。 HELLO命令对攻击者来说毫无价值;它没有识别客户。

     

当服务器获得HELLO时,它会生成自己的短期密钥对(一个连接总共使用四个密钥),并将这个新的私钥编码在" cookie"中,然后发回作为WELCOME命令到客户端。它还发送其加密的短期公钥,以便只有客户端才能读取它。然后丢弃这个短期密钥对。

     

在此阶段,服务器尚未存储客户端的任何状态。它生成了一个密钥对,以客户端可以读取的方式将其发送回客户端,并将其丢弃。

     

客户端返回INITIATE命令,该命令为服务器提供其cookie,以及客户端永久公钥,加密为"证实"所以只有服务器可以读取它。就客户端而言,服务器现在已经过身份验证,因此它也可以在命令中发回元数据。

     

服务器读取INITIATE,现在可以验证客户端永久公钥。它还解包了cookie并获得了用于连接的短期密钥对。就服务器而言,现在客户端已经过身份验证,因此服务器可以安全地发送其元数据。然后双方都可以发送消息和命令。

因此,您在此处生成的密钥不会直接用于加密数据,它们仅用于验证方。客户端和服务器之间的握手过程产生用于加密数据的真实加密(以及MAC中的认证)密钥。因此,如果您唯一担心的是MITM,那么您已经受到了保护。

但是你也可以关注流氓客户,你当前的方案允许任何人连接。这是Pieter Hintjens the second article可以帮助你解决的问题" The Ironhouse Pattern"。关键部分是禁用CURVE_ALLOW_ANY并告诉服务器在哪里查找客户端公共证书:

//  Tell authenticator to use the certificate store in .curve
zauth_configure_curve (auth, "*", ".curve");

然后在客户端上生成客户端密钥(一次!不为每个连接调用zcert_new()),将其公共部分转移到" .curve"服务器的目录并加载(在客户端上)该密钥而不是调用zcert_new()

如果您希望让生活更轻松(不需要为每个客户端将公钥从客户端传输到服务器),您可以创建一个" golden"客户密钥对,将其公共部分纳入" .curve"存储然后(当然是通过安全通道)在每个需要连接到您的发布者的客户端上复制密钥。