Вести с полей

Привет всем.

Медленно и печально продираюсь сквозь терни подключения к FB3 минуя fbclient.dll. Добрался до настройки шифрования подключения (op_crypt). Разобравшись что к чему, я даже немного оживился — если делать по уму, то конструкция получается достаточно красивой.

Изначально объект порта отправлял и получал пакеты напрямую через объект сокета. С внедрением шифрования пришлось спрятать сокет за интерфейсом RemoteFB__PortStream:

class RemoteFB__PortStream:public RemoteFB__SmartInterface
{
 public:
  virtual void Write(size_t      cb,
                     const void* pv)=0;

  virtual void FlushWriteBuf()=0;

  virtual void Read(size_t  cb,
                    void*   pv)=0;
};//class RemoteFB__PortStream

Для этого интерфейса соорудил класс, который реализует алгоритм шифрования «Arc4» и читает/пишет данные через нижележащий объект с интерфейсом RemoteFB__PortStream:

void RemoteFB__PortStream__Crypt_Arc4::Write(size_t      const cb,
                                             const void* const pv)
{
 CHECK_READ_PTR(pv,cb);

 assert(m_spBaseStream);

 const byte_type* p=reinterpret_cast<const byte_type*>(pv);

 const byte_type* const e=(p+cb);

 for(;;)
 {
  assert(m_write_buf_beg<=m_write_buf_cur);
  assert(m_write_buf_cur<=m_write_buf_end);

  for(;;++p,++m_write_buf_cur)
  {
   if(p==e)
    return;

   if(m_write_buf_cur==m_write_buf_end)
    break;

   (*m_write_buf_cur)=m_Encoder.transform(*p);
  }//for[ever]

  assert(m_write_buf_cur==m_write_buf_end);

  m_spBaseStream->Write(m_write_buf_end-m_write_buf_beg,
                        m_write_buf_beg); //throw
 
  m_write_buf_cur=m_write_buf_beg;
 }//for[ever]
}//Write

//------------------------------------------------------------------------
void RemoteFB__PortStream__Crypt_Arc4::FlushWriteBuf()
{
 assert(m_write_buf_beg<=m_write_buf_cur);
 assert(m_write_buf_cur<=m_write_buf_end);

 assert(m_spBaseStream);

 //1. сброс буферизированных данных
 if(m_write_buf_cur!=m_write_buf_beg)
 {
  m_spBaseStream->Write(m_write_buf_cur-m_write_buf_beg,
                        m_write_buf_beg);
 
  m_write_buf_cur=m_write_buf_beg;
 }//if

 assert(m_write_buf_cur==m_write_buf_beg);

 //2. сброс буфера на нижнем уровне
 m_spBaseStream->FlushWriteBuf(); //throw
}//FlushWriteBuf

//------------------------------------------------------------------------
void RemoteFB__PortStream__Crypt_Arc4::Read(size_t const cb,
                                            void*  const pv)
{
 CHECK_READ_WRITE_PTR(pv,cb);

 assert(m_spBaseStream);

 m_spBaseStream->Read(cb,pv); //throw

 byte_type* p=reinterpret_cast<byte_type*>(pv);

 const byte_type* const e=(p+cb);

 for(;p!=e;++p)
 {
  (*p)=m_Decoder.transform(*p);
 }//for p
}//Read

Сам процесс «инициализации» шифрования выглядит просто:

1. Отправляем серверу пакет op_crypt с именем типа ключа шифрования (Symmetric) и названием алгоритма (плагина) шифрования (Arc4).

2. Замещаем объект сокета на объект зашифрованного потока:

m_spSocket.swap(spCryptStream);

3. Читаем (зашифрованный!) ответ сервера. Прочитали — все ок (хотя статус вектор, все таки, стоит проверить).

Не смогли прочитать (сервер оборвал подключение) — можно залезть в лог сервера и посмотреть, что он там написал:

HOME3	Wed Aug 17 12:20:11 2016
	start_crypt:
	Client attempted to start wire encryption using unsupported plugin QUQU

HOME3	Wed Aug 17 12:34:53 2016
	start_crypt:
	Client attempted to start wire encryption using unsupported plugin QUQU+++

Нормальную нотификацию клиента (вместо обрыва) о проблеме разработчики сервера неасилили. Главное ошибку о некорректном логине/пароле — сервер присылает, а тут тупо закрывает подключение. Жаль.

В тройке еще компрессор к потоку данных прикрутили. По сути, думаю, это то же шифрование. Посмотрим. Потом.

Leave a Comment