c++ - 使用来自 OpenSSL 的 EC_POINT_mul 的奇怪结果

标签 c++ openssl diffie-hellman

我正在尝试实现基于 Diffie Hellman 协议(protocol)的专用集交集 (PSI) 协议(protocol)。

PSI 协议(protocol)是 [ Kiss et al. 2017 的第 2.2 节中提到的协议(protocol)。 ],, 这里已经有一个 Java 实现:

https://github.com/encryptogroup/MobilePSI/blob/master/PSIServer/src/PSIDH.java

想用C++实现,所以想到了用OpenSSL

我想做什么

大致的工作原理如下: 让 G 成为 diffie hellman 的生成器; alice 有一个 DH secret a 和一个元素 x, bob 有一个 DH secret b 和一个元素 yh 是一些函数,它接受任何(位串)元素并将其映射到 DH 标量。

  • alice 发送G*a*h(x)(称之为alice 的一边)
  • bob 回复(G*a*h(x))*b(称之为alice 的最后一面)
  • bob 发送G*b*h(y)(称之为bob 的一边)
  • alice 计算(G*b*h(y))*a

然后 Alice 比较两个最终值以了解是否 x == y

代码

(最小工作示例)

利用 G*a 是关于 Diffie-Hellman 的“Alice 的公钥”这一事实。

#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <iostream>

#include <openssl/obj_mac.h>
#include <openssl/ec.h>

// list of possible curve names here:
// https://git.openssl.org/gitweb/?p=openssl.git;a=blob;f=crypto/objects/obj_mac.h;h=b5ea7cdab4f84b90280f0a3aae1478a8d715c7a7;hb=46ebd9e3bb623d3c15ef2203038956f3f7213620#l385
// also here:
// https://github.com/openssl/openssl/blob/67e247fad12308e34817e60c9242113c285fb00c/include/openssl/obj_mac.h#L261
#define CURVE_NAME NID_X9_62_prime256v1

class PSIEntity {
  public:
    BN_CTX* bn_ctx;
    const EC_GROUP* ec_group;
    EC_KEY* key;

    PSIEntity(BN_CTX* c, const EC_GROUP* g){
      bn_ctx = c;

      ec_group = g;
      key = EC_KEY_new();
      EC_KEY_set_group(key, ec_group);
      EC_KEY_generate_key(key);
    }

    EC_POINT* encode_and_mask(const unsigned char* x_data){
      BIGNUM* x = BN_bin2bn(x_data, 28, NULL);

      const EC_POINT* pubkey = EC_KEY_get0_public_key(key);
      EC_POINT* result = EC_POINT_dup(pubkey, ec_group);

      EC_POINT_mul(ec_group, result, x, NULL, NULL, bn_ctx);

      return result;
    }

    EC_POINT* mask(EC_POINT* p){
      EC_POINT* result = EC_POINT_dup(p, ec_group);
      const BIGNUM *priv_key = EC_KEY_get0_private_key(key);
      EC_POINT_mul(ec_group, result, priv_key, NULL, NULL, bn_ctx);

      return result;
    }
};



int main(){
  EC_GROUP *ec_group = EC_GROUP_new_by_curve_name(CURVE_NAME);
  BN_CTX *bn_ctx = BN_CTX_new();

  PSIEntity alice(bn_ctx, ec_group);
  PSIEntity bob(bn_ctx, ec_group);

  // taken from "a_bin" in
  // https://wiki.openssl.org/index.php/Elliptic_Curve_Cryptography#Defining_Curves
  unsigned char x_data[28] =
          {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
           0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,
           0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE};

  EC_POINT* alice_side = alice.encode_and_mask(x_data);
  EC_POINT* alice_side_final = bob.mask(alice_side);

  EC_POINT* bob_side = bob.encode_and_mask(x_data);
  EC_POINT* bob_side_final = alice.mask(bob_side);

  int final_points_are_different = EC_POINT_cmp(ec_group,
                                                alice_side_final, bob_side_final,
                                                bn_ctx);
  if(final_points_are_different==-1){
    std::cout << "comparison of final points failed" << std::endl;
  }else if(final_points_are_different==1){
    std::cout << "final points are different" << std::endl;
  }else if(final_points_are_different==0){
    std::cout << "final points are equal" << std::endl;
  }

  int temp_points_are_different = EC_POINT_cmp(ec_group,
                                                alice_side, bob_side,
                                                bn_ctx);
  if(temp_points_are_different==-1){
    std::cout << "comparison of temp points failed" << std::endl;
  }else if(temp_points_are_different==1){
    std::cout << "temp points are different" << std::endl;
  }else if(temp_points_are_different==0){
    std::cout << "temp points are equal" << std::endl;
  }
  return 0;
}

代码结果和问题

结果是:

final points are different
temp points are equal

我希望相反: final points 应该相等,因为它在两边都是相同的 x

至于“温度点是相等的”,这是非常令人不安的: 这意味着我们有 G*a*x == G*b*x

如果将 G*aG*b(公钥)进行比较,答案是它们不同,所以似乎发生的情况是乘以 xEC_POINT_mul 只是“把事情搞砸了”。

知道发生了什么吗?

最佳答案

下面的代码应该可以完成这项工作。问题是将错误的参数传递给 EC_POINT_mul()。参见 here EC_POINT_mul() 的文档。

EC_POINT* encode_and_mask(const unsigned char* x_data){
    ...
    EC_POINT_mul(ec_group, result, NULL, result, x, bn_ctx);

    return result;
}

EC_POINT* mask(EC_POINT* p){
    ...
    EC_POINT_mul(ec_group, result, NULL, result, priv_key, bn_ctx);

    return result;
}

关于c++ - 使用来自 OpenSSL 的 EC_POINT_mul 的奇怪结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47221029/

相关文章:

c++ - sscanf 的精度问题

c++ - 插入链表创建循环

c++ - 按 STL - C++ 中的成绩对学生列表进行排序?

C++错误c2373重新定义不同的类型修饰符

php - Node.js aes128 加密/解密到 PHP 的端口

c - openssl/rsa.h : No such file or directory in C windows

openssl - 使用 openssl verify 验证证书链

security - 是否有可能通过知道素数和生成器参数来 "hack"Diffie-Hellman?

Java Diffie-Hellman key 交换

c - Diffie-Hellman 中参数的选择