ECDH Curve 25519 Генерация ключей c реализацией в Libgcrypt

Я пытаюсь реализовать ECDH в libgcrypt. Я нашел в Интернете примеры вычисления общего секрета и знаю, как выполнять симметричное шифрование. Я просто не могу понять, как генерировать пары ключей.

Я хочу, чтобы ключи хранились как беззнаковые символы *. Вот как я сейчас пытаюсь это сделать, но на линии всегда возникают сбои gcry_mpi_ec_mul(mpi_public_key, mpi_private_key, NULL, ctx); Вот мой код: `

void generate_curve25519_keypair(unsigned char *public_key, unsigned char *private_key) {
    gcry_error_t error;
    gcry_mpi_t mpi_private_key;
    gcry_mpi_point_t mpi_public_key;
    gcry_ctx_t ctx;

    // Generate a random private key
    gcry_randomize(private_key, CURVE25519_KEY_SIZE, GCRY_STRONG_RANDOM);

    // Clamp the private key for Curve25519
    private_key[0] &= 248;
    private_key[31] &= 127;
    private_key[31] |= 64;

    // Initialize the context for Curve25519
    error = gcry_mpi_ec_new(&ctx, NULL, "Curve25519");
    if (error) {
        fprintf(stderr, "Failed to create context: %s\n", gpg_strerror(error));
        return;
    }

    // Convert the private key to an MPI
    error = gcry_mpi_scan(&mpi_private_key, GCRYMPI_FMT_USG, private_key, CURVE25519_KEY_SIZE, NULL);
    if (error) {
        fprintf(stderr, "Failed to convert private key to MPI: %s\n", gpg_strerror(error));
        gcry_ctx_release(ctx);
        return;
    }

    // Allocate memory for the resulting public key point
    mpi_public_key = gcry_mpi_point_new(0);

    // Multiply the base point with the private key MPI to get the public key point
    gcry_mpi_ec_mul(mpi_public_key, mpi_private_key, NULL, ctx); // Use NULL for the default base point G
    if (error) {
        fprintf(stderr, "Failed to multiply with base point: %s\n", gpg_strerror(error));
        gcry_mpi_release(mpi_private_key);
        gcry_mpi_point_release(mpi_public_key);
        gcry_ctx_release(ctx);
        return;
    }

    // Extract the x-coordinate of the public key point and convert it to a byte array
    gcry_mpi_t mpi_x = gcry_mpi_new(0);
    gcry_mpi_point_get(mpi_x, NULL, NULL, mpi_public_key);
    error = gcry_mpi_print(GCRYMPI_FMT_USG, public_key, CURVE25519_KEY_SIZE, NULL, mpi_x);
    if (error) {
        fprintf(stderr, "Failed to export public key: %s\n", gpg_strerror(error));
        gcry_mpi_release(mpi_x);
        gcry_mpi_release(mpi_private_key);
        gcry_mpi_point_release(mpi_public_key);
        gcry_ctx_release(ctx);
        return;
    }

    // Release resources
    gcry_mpi_release(mpi_x);
    gcry_mpi_release(mpi_private_key);
    gcry_mpi_point_release(mpi_public_key);
    gcry_ctx_release(ctx);
}
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
64
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вот рабочая реализация ECDH в libgcrypt на C, включая отдельные методы генерации ключей ECC и генерации общих ключей. Ключи хранятся в виде строк, а симметричное шифрование осуществляется в основном с помощью ECDH.

static gpg_error_t compute_master_secret (unsigned char *master, size_t masterlen,
                       const unsigned char *sk_a, size_t sk_a_len,
                       const unsigned char *pk_b, size_t pk_b_len)
{
  gpg_error_t err;
  gcry_sexp_t s_sk_a = NULL;
  gcry_sexp_t s_pk_b = NULL;
  gcry_sexp_t s_shared = NULL;
  gcry_sexp_t s_tmp;
  const char *s;
  size_t n;
  gcry_mpi_t pk_mpi, privk_mpi;

  //Convert public key string to MPI
  err = gcry_mpi_scan(&pk_mpi,GCRYMPI_FMT_USG,pk_b,pk_b_len, NULL);
  if (err){
    printf("pk_mpi failed\n");
  }

  //Convert private key string to MPI
  err = gcry_mpi_scan(&privk_mpi,GCRYMPI_FMT_USG,sk_a,sk_a_len, NULL);
  if (err){
    printf("privk_mpi failed\n");
  }
  
  //build a private key s expression
  err = gcry_sexp_build (&s_sk_a, NULL, "%m", privk_mpi);
  if (!err)
  //build a public key s expression
    err = gcry_sexp_build (&s_pk_b, NULL,
                           "(public-key(ecdh(curve Curve25519)"
                           "(q%m)))", pk_mpi);

  if (err){
      printf ("error building S-expression: %s\n", gpg_strerror (err));
      goto leave;
    }
    // show_sexp("ecdh secret key ",s_sk_a);
    // show_sexp("ecdh pub key ",s_pk_b);

  //Encrypt secret k with public key, this does ECDH under the hood
  //Ultimately uses ecc.encrypt_raw() in cipher/ecc.c
  err = gcry_pk_encrypt (&s_shared, s_sk_a, s_pk_b);

  if (err){
      printf ("error computing DH: %s\n", gpg_strerror (err));
      goto leave;
    }

  //temp s expression to just get shared key element
  s_tmp = gcry_sexp_find_token (s_shared, "s", 0);

  //s must be prefixed with 0x40
  if (!s_tmp || !(s = gcry_sexp_nth_data (s_tmp, 1, &n))
      || n != 33 || s[0] != 0x40)
    {
      err = gpg_error (GPG_ERR_INTERNAL);
      printf ("error computing DH: %s\n", gpg_strerror (err));
      goto leave;
    }

  //plus one because the first byte is always 0x40 which denotes that it is a compressed point
  memcpy (master, s+1, 32);


 leave:
  gcry_sexp_release (s_sk_a);
  gcry_sexp_release (s_pk_b);
  gcry_sexp_release (s_shared);
  return err;

}

void crypto_box_keypair(char *public_key, char *private_key){

    gcry_error_t error;
    gcry_sexp_t key_param_sexp, key_pair_sexp;
    size_t q_len, d_len;
    char *public_key_str, *private_key_str;
    gcry_mpi_t q_mpi, d_mpi;
    unsigned char raw_public_key[crypto_box_PUBLICKEYBYTES * 2];
    unsigned char raw_private_key[crypto_box_SECRETKEYBYTES * 2];

    // Initialize libgcrypt
    if (!gcry_check_version(GCRYPT_VERSION)) {
        fprintf(stderr, "libgcrypt version mismatch\n");
        exit(EXIT_FAILURE);
    }
    gcry_control(GCRYCTL_DISABLE_SECMEM, 0);
    gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);

    //build parameters s expression
    error = gcry_sexp_build(&key_param_sexp, NULL, "(genkey (ecc (curve Curve25519)))");

    if (error) {
        fprintf(stderr, "Failed to build S-expression for key generation: %s\n", gcry_strerror(error));
        exit(EXIT_FAILURE);
    }

    //generate ecc keys
    error = gcry_pk_genkey(&key_pair_sexp, key_param_sexp);
    if (error) {
        fprintf(stderr, "Failed to generate key pair: %s\n", gcry_strerror(error));
        gcry_sexp_release(key_param_sexp);
        exit(EXIT_FAILURE);
    }

    //get sub s expression for q and d (public and private)
    gcry_sexp_t q = gcry_sexp_find_token(key_pair_sexp, "q", 0);
    gcry_sexp_t d = gcry_sexp_find_token(key_pair_sexp, "d", 0);

    //convert s expression q and d to MPIs
    q_mpi = gcry_sexp_nth_mpi(q, 1, GCRYMPI_FMT_USG);
    d_mpi = gcry_sexp_nth_mpi(d, 1, GCRYMPI_FMT_USG);

    if (!q_mpi || !d_mpi) {
        fprintf(stderr, "Failed to extract MPIs from S-expression\n");
        gcry_sexp_release(key_pair_sexp);
        exit(EXIT_FAILURE);
    }

    // Convert the MPIs to binary format
    error = gcry_mpi_print(GCRYMPI_FMT_USG, raw_public_key, sizeof(raw_public_key), &q_len, q_mpi);
    if (error) {
        fprintf(stderr, "Failed to convert public key MPI to binary format: %s\n", gcry_strerror(error));
    }

    error = gcry_mpi_print(GCRYMPI_FMT_USG, raw_private_key, sizeof(raw_private_key), &d_len, d_mpi);
    if (error) {
        fprintf(stderr, "Failed to convert private key MPI to binary format: %s\n", gcry_strerror(error));
    }

    // Remove the 0x40 prefix from the public key, if present
    if (q_len == crypto_box_PUBLICKEYBYTES + 1 && raw_public_key[0] == 0x40) {
        printf("public key is 33 in length\n");
        memcpy(public_key, raw_public_key + 1, crypto_box_PUBLICKEYBYTES);
    } else {
        printf("public key is 32 in length\n");
        memcpy(public_key, raw_public_key, crypto_box_PUBLICKEYBYTES);
    }

    memcpy(private_key, raw_private_key, crypto_box_SECRETKEYBYTES);
}

int main(){
    unsigned char alice_publickey[crypto_box_PUBLICKEYBYTES];
    unsigned char alice_privatekey[crypto_box_SECRETKEYBYTES];
    
    unsigned char bob_publickey[crypto_box_PUBLICKEYBYTES];
    unsigned char bob_privatekey[crypto_box_SECRETKEYBYTES];

    char *msg = "test";
    unsigned long long msg_len = 4;
    unsigned char nonce[crypto_secretbox_NONCEBYTES];

    randombytes_buf(nonce, sizeof nonce);
    
    unsigned char ciphertext[msg_len + crypto_secretbox_MACBYTES];

    unsigned char decrypted[msg_len];
    

    crypto_box_keypair(alice_publickey, alice_privatekey);
    crypto_box_keypair(bob_publickey, bob_privatekey);

    //symmetric encryption function
    if (crypto_box_easy(ciphertext, msg, msg_len, nonce,
                        bob_publickey, alice_privatekey) != 0) {
        /* error */
    }

    //asymmetric encryption function
    if (crypto_box_open_easy(decrypted, ciphertext, CIPHERTEXT_LEN, nonce, alice_publickey, bob_privatekey) != 0){

    }
    printf("Decrypted  = %s\n", decrypted);

return 0;
}

Другие вопросы по теме