Deribit FIX API Logon

Following code doesn’t seem to work to Logon using FIX API. Getting “invalid credentials” from the exchange though same username and access key seem to work with REST API over websockets. Seems like issue with the definition of nonce. Here I am trying a basic example to try to Logon.

        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));

the functions used for base64 and sha256 encoding are:

string base64_encode(const std::string &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)&0x3F]);
            valb -= 6;
        }
    }
    if (valb>-6) out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[((val<<8)>>(valb+8))&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(&sha256);
    SHA256_Update(&sha256, str.c_str(), str.size());
    SHA256_Final(hash, &sha256);
    stringstream ss;
    for(int i = 0; i < SHA256_DIGEST_LENGTH; i++)
    {
        ss << hex << setw(2) << setfill('0') << (int)hash[i];
    }
    return ss.str();
}

I am following this documentation from Deribit https://docs.deribit.com/?shell#logon-a and quickfix as the fix engine.

enter image description here

Code follows from this description mentioned in the docs.

Answer

I was able to solve this problem and I am providing it’s solution so others can also benefit.

Method used for base64 encoding:

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] & 0xfc) >> 2;
      char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
      char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
      char_array_4[3] = char_array_3[2] & 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] & 0xfc) >> 2;
    char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
    char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
    char_array_4[3] = char_array_3[2] & 0x3f;

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

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

  }

  return ret;

} 

And how I calculated other fields :

        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(&sha256);
        SHA256_Update(&sha256, base_signature_string.c_str(), base_signature_string.size());
        SHA256_Final(hash, &sha256);

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

PS: RAND_bytes and SHA functions are pre defined function in openssl.