Дерибит ИСПРАВЛЯЕТ вход в API

#c #authentication #algorithmic-trading #quickfix #fix-protocol

Вопрос:

Следующий код, похоже, не работает для входа в систему с помощью FIX API. Получение «недействительных учетных данных» от exchange, хотя одно и то же имя пользователя и ключ доступа, похоже, работают с REST API через websockets. Похоже, проблема с определением nonce. Здесь я пытаюсь привести простой пример, чтобы попытаться войти в систему.

         string user = settings->get().getString("Username");
        message.setField(Username(user));
        string pass = settings->get().getString("Password");
        milliseconds ms = duration_cast< milliseconds >(
                system_clock::now().time_since_epoch()
        );
        long long millis = ms.count();
        string nonce = "abcdefghijkabcdefghijkabcdefghijkabcdefghijk";
        nonce = base64_encode(nonce);
        string raw = to_string(millis)   "."   nonce;

        message.setField(RawData(raw));
        string password = base64_encode(sha256(raw pass));

        message.setField(Password(password));
 

функции, используемые для кодирования base64 и sha256, следующие:

 string base64_encode(const std::string amp;in) {

    std::string out;

    int val = 0, valb = -6;
    for (unsigned char c : in) {
        val = (val << 8)   c;
        valb  = 8;
        while (valb >= 0) {
            out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 /"[(val>>valb)amp;0x3F]);
            valb -= 6;
        }
    }
    if (valb>-6) out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 /"[((val<<8)>>(valb 8))amp;0x3F]);
    while (out.size()%4) out.push_back('=');
    return out;
}

string sha256(const string str)
{
    unsigned char hash[SHA256_DIGEST_LENGTH];
    SHA256_CTX sha256;
    SHA256_Init(amp;sha256);
    SHA256_Update(amp;sha256, str.c_str(), str.size());
    SHA256_Final(hash, amp;sha256);
    stringstream ss;
    for(int i = 0; i < SHA256_DIGEST_LENGTH; i  )
    {
        ss << hex << setw(2) << setfill('0') << (int)hash[i];
    }
    return ss.str();
}
 

Я следую этой документации от Deribit https://docs.deribit.com/?shell#logon-a и quickfix в качестве механизма исправления.

введите описание изображения здесь

Код следует из этого описания, упомянутого в документах.

Комментарии:

1. Детали quickfix, на мой взгляд, выглядят нормально.

Ответ №1:

Я смог решить эту проблему и предоставляю ее решение, чтобы другие тоже могли извлечь выгоду.

Способ, используемый для кодирования base64:

 static const std::string base64_chars =
             "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
             "abcdefghijklmnopqrstuvwxyz"
             "0123456789 /";

std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
  std::string ret;
  int i = 0;
  int j = 0;
  unsigned char char_array_3[3];
  unsigned char char_array_4[4];

  while (in_len--) {
    char_array_3[i  ] = *(bytes_to_encode  );
    if (i == 3) {
      char_array_4[0] = (char_array_3[0] amp; 0xfc) >> 2;
      char_array_4[1] = ((char_array_3[0] amp; 0x03) << 4)   ((char_array_3[1] amp; 0xf0) >> 4);
      char_array_4[2] = ((char_array_3[1] amp; 0x0f) << 2)   ((char_array_3[2] amp; 0xc0) >> 6);
      char_array_4[3] = char_array_3[2] amp; 0x3f;

      for(i = 0; (i <4) ; i  )
        ret  = base64_chars[char_array_4[i]];
      i = 0;
    }
  }

  if (i)
  {
    for(j = i; j < 3; j  )
      char_array_3[j] = '';

    char_array_4[0] = (char_array_3[0] amp; 0xfc) >> 2;
    char_array_4[1] = ((char_array_3[0] amp; 0x03) << 4)   ((char_array_3[1] amp; 0xf0) >> 4);
    char_array_4[2] = ((char_array_3[1] amp; 0x0f) << 2)   ((char_array_3[2] amp; 0xc0) >> 6);
    char_array_4[3] = char_array_3[2] amp; 0x3f;

    for (j = 0; (j < i   1); j  )
      ret  = base64_chars[char_array_4[j]];

    while((i   < 3))
      ret  = '=';

  }

  return ret;

} 
 

И как я рассчитал другие поля :

         string user = settings->get().getString("Username");

        milliseconds ms = duration_cast< milliseconds >(system_clock::now().time_since_epoch());
        string timestamp_in_ms = std::to_string(ms.count());
        unsigned char nonce [32] = {};
        RAND_bytes(nonce, sizeof(nonce));
        string nonce64 = base64_encode(nonce, sizeof(nonce));
        string secret = settings->get().getString("Password");
        string raw_data = timestamp_in_ms   "."   nonce64;
        string base_signature_string = raw_data   secret;
        
        unsigned char hash[SHA256_DIGEST_LENGTH];
        SHA256_CTX sha256;
        SHA256_Init(amp;sha256);
        SHA256_Update(amp;sha256, base_signature_string.c_str(), base_signature_string.size());
        SHA256_Final(hash, amp;sha256);

        static string password_sha_base64 = base64_encode(hash, sizeof(hash));
 

PS: Функции RAND_bytes и SHA являются предварительно определенными функциями в openssl.