Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 12.01.2013, 20:48   #1
Vadik(R)
Пользователь
 
Регистрация: 10.03.2008
Сообщений: 68
По умолчанию Работа с https без компонент

Добрый вечер, форумчане!

Есть у меня такой вопрос. Как на низком уровне работать с https?
Мои попытки вот:
Код:
program TestSSL;

{$APPTYPE CONSOLE}

uses
  Dialogs, SysUtils, Windows, WinSock;

procedure SendText(S: TSocket; Buffer: AnsiString);
begin
  send(S, Buffer[1], Length(Buffer), 0);
end;

procedure RecvText(S: TSocket; var Content: AnsiString);
var
  Buffer: AnsiString;
  Bytes: Integer;
begin
  Content := '';
  repeat
    SetLength(Buffer, 8192);
    Bytes := recv(S, Buffer[1], Length(Buffer), 0);
    SetLength(Buffer, Bytes);
    Content := Content + Buffer;
  until Bytes = 0;
end;

var
  Content: AnsiString;
  S: TSocket;
  SockAddr: TSockAddr;
  WSAData: TWSAData;

begin
  WSAStartup($202, WSAData);
  SockAddr.sin_family := AF_INET;
  SockAddr.sin_port := htons(443);
  SockAddr.sin_addr.S_addr := inet_addr('69.58.188.34');
  S := socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
  connect(S, SockAddr, SizeOf(TSockAddr));
  Content := '';
  Content := Content + 'GET / HTTP/1.1' + #13#10;
  Content := Content + 'Host: bitly.com' + #13#10;
  Content := Content + 'Connection: close' + #13#10;
  Content := Content + 'User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.52 Safari/537.17' + #13#10;
  Content := Content + 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' + #13#10;
  Content := Content + 'Accept-Encoding: gzip,deflate,sdch' + #13#10;
  Content := Content + 'Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4' + #13#10;
  Content := Content + 'Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.3' + #13#10;
  Content := Content + '' + #13#10;
  SendText(S, Content);
  RecvText(S, Content);
  closesocket(S);
  WSACleanup;
  ShowMessage(Content);
end.
Хочу получить код https://bit.ly.com/
Но сервер выдаёт такую ошибку: 400 The plain HTTP request was sent to HTTPS port
Предполагаю, что дело в том, что https-соединение защищено и прежде, чем делать запросы на получение кода, надо данные как-то зашифровать. И заранее об этом договориться с сервером, алгоритм шифрования, ключи...
Но я не знаю, какие именно надо прежде запросы делать.
Обычно смотрю, какие запросы надо делать через панель разработчика в Google Chrome. Но он ничего толкового в этот раз не подсказал, а с обычным http его всегда хватает.
Помогите, пожалуйста.
Vadik(R) вне форума Ответить с цитированием
Старый 12.01.2013, 21:06   #2
bakanaev
Форумчанин
 
Регистрация: 27.03.2012
Сообщений: 438
По умолчанию

А чем инди плох?
bakanaev вне форума Ответить с цитированием
Старый 12.01.2013, 21:09   #3
Vadik(R)
Пользователь
 
Регистрация: 10.03.2008
Сообщений: 68
По умолчанию

Интересно для себя, понять хочу.
Vadik(R) вне форума Ответить с цитированием
Старый 13.01.2013, 21:01   #4
Vadik(R)
Пользователь
 
Регистрация: 10.03.2008
Сообщений: 68
По умолчанию

Нашёл пример работы с https здесь http://synapse.ararat.cz/doku.php/download
Вроде бы можно было и его использовать, но ведь интерес!
Целый день дебажу прогу, но никак не могу понять, в каком моменте используется этот SSL
Вероятно из-за того, что пока происходит выполнение по шагам сервер уже успевает разрывать соединение из-за тайм аута.
Голова взрывается, а гугл не помогает. Неужели никто раньше этой проблемой не интересовался?

P.S. WireShark чтоль подключить?
Никак не пойму, то ли за защищённым соединением должна сама виндовс следить, а мне стоит просто передать в какую-нибудь WinAPI дополнительный параметр о защите...
Толи я просто никак не могу отследить тот момент, где получают/передают какие-либо ключи и шифруется информация.
Vadik(R) вне форума Ответить с цитированием
Старый 13.01.2013, 22:31   #5
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,426
По умолчанию

что для вас "низкий уровень работы"?
Человек_Борща вне форума Ответить с цитированием
Старый 14.01.2013, 11:35   #6
Vadik(R)
Пользователь
 
Регистрация: 10.03.2008
Сообщений: 68
По умолчанию

Подразумеваю то, что не будут использовать готовых компонент.
CryptoAPI использовать не против, алгоритмы создания ключей свои не думаю делать )

Вот ещё хорошую вещь нашёл по своему вопросу, пока что разбираюсь. Надеюсь, осилю...

http://archive.msdn.microsoft.com/em...x?ReleaseId=13
Vadik(R) вне форума Ответить с цитированием
Старый 16.01.2013, 23:31   #7
Vadik(R)
Пользователь
 
Регистрация: 10.03.2008
Сообщений: 68
По умолчанию

Прошу помощи. Вот полная версия кода из последней ссылки: http://www.everfall.com/paste/id.php?qhdubuy2o9id
(форум не даёт вставить код прямо сюда, говорит, слишком длинное сообщение)

Нужна помощь в этой части кода, что происходит до неё - понятно:
Код:
bool Handshake(SOCKET s, wchar_t * pwzHostname, PCredHandle phCredential, PCtxtHandle phContext)
{
	SecBufferDesc   InBufferDesc;
	SecBuffer	   InBuffers[2];
	InBufferDesc.cBuffers = _countof(InBuffers);
	InBufferDesc.pBuffers = InBuffers;
	InBufferDesc.ulVersion = SECBUFFER_VERSION;
	SecBufferDesc   OutBufferDesc;
	SecBuffer	   OutBuffers[1];
	OutBufferDesc.cBuffers = _countof(OutBuffers);
	OutBufferDesc.pBuffers = OutBuffers;
	OutBufferDesc.ulVersion = SECBUFFER_VERSION;
	char *		  InSecBuffer = NULL;
	char *		  OutSecBuffer = NULL;
	TimeStamp	   tsExpiry;
	ULONG m_byteOrder = SECURITY_NETWORK_DREP;
	ULONG requiredSecurity =
		ISC_REQ_SEQUENCE_DETECT   |
		ISC_REQ_REPLAY_DETECT	 |
		ISC_REQ_CONFIDENTIALITY   |
		ISC_RET_EXTENDED_ERROR	|
		ISC_REQ_STREAM;
	ULONG actualSecurity;
 
	SECURITY_STATUS scRet;
	bool			success = false;
 
	// Figure out how large of a buffer to allocate for a token.
	PSecPkgInfo pPackageInfo;
	scRet = QuerySecurityPackageInfo(SecurityPackage, &pPackageInfo);
	ULONG cbMaxTokenSize = pPackageInfo->cbMaxToken;
	FreeContextBuffer(pPackageInfo);
 
	// Allocate a buffer large enough to hold the largest token.
	InSecBuffer = (char *) LocalAlloc(LMEM_FIXED, cbMaxTokenSize);
	OutSecBuffer = (char *) LocalAlloc(LMEM_FIXED, cbMaxTokenSize);
	if (!InSecBuffer || !OutSecBuffer)
	{
		oom;
		goto cleanup;
	}
	ULONG& cbInSecBuffer = InBuffers[0].cbBuffer;
	ULONG& cbOutSecBuffer = OutBuffers[0].cbBuffer;
 
	//Do some one-time initialization of the buffers
	InBuffers[0].BufferType = SECBUFFER_TOKEN;
	InBuffers[0].pvBuffer = InSecBuffer;
	InBuffers[1].BufferType = SECBUFFER_EMPTY;
	InBuffers[1].pvBuffer = NULL;
	InBuffers[1].cbBuffer = 0;
   
	SecInvalidateHandle(phContext);
	do
	{
		cbInSecBuffer = 0;
		BOOL bFirstTime = !SecIsValidHandle(phContext);
		int cbData;
 
		do
		{
			if (InBuffers[1].BufferType == SECBUFFER_EXTRA)
			{
				// The server sent more to the token than could be processed in a single
				// call to InitializeSecurityContext.  We move this extra data into the token
				// buffer and prepare to call the function again.
				InBuffers[1].pvBuffer = (byte*)InBuffers[0].pvBuffer + cbData - InBuffers[1].cbBuffer;
				MoveMemory(InSecBuffer, InBuffers[1].pvBuffer, InBuffers[1].cbBuffer);
				InBuffers[0].pvBuffer = InSecBuffer;
				InBuffers[0].cbBuffer = InBuffers[1].cbBuffer;
				InBuffers[0].BufferType = SECBUFFER_TOKEN;
 
				InBuffers[1].BufferType = SECBUFFER_EMPTY;
				InBuffers[1].pvBuffer = NULL;
				InBuffers[1].cbBuffer = 0;
			}
			else // don't try to read more data from the server (yet) if there was data in the extra buffer
			{
				// Read in response from server if we already said something to it.
				if (!bFirstTime)
				{
					cbData = recv(s, InSecBuffer + cbInSecBuffer, cbMaxTokenSize - cbInSecBuffer, 0);
					if(cbData == SOCKET_ERROR || cbData == 0)
					{
						error("failure sending data to server 0x%x\n", WSAGetLastError());
						goto cleanup;
					}
					verbose("%5d bytes of handshake data received.\n", cbData);
					cbInSecBuffer += cbData;
 
					InBuffers[0].BufferType = SECBUFFER_TOKEN;
					InBuffers[0].pvBuffer = InSecBuffer;
				}
			}
 
			// Prepare client token.
			OutBuffers[0].BufferType = SECBUFFER_TOKEN;
			OutBuffers[0].pvBuffer = OutSecBuffer;
			OutBuffers[0].cbBuffer = cbMaxTokenSize;
 
			// Prepare client token.
			scRet = InitializeSecurityContextW(
				phCredential,
				bFirstTime ? NULL : phContext,
				bFirstTime ? pwzHostname : NULL,
				requiredSecurity,
				0,
				m_byteOrder,
				bFirstTime ? NULL : &InBufferDesc,
				0,
				bFirstTime ? phContext : NULL,
				&OutBufferDesc,
				&actualSecurity,
				&tsExpiry);
		} while (scRet == SEC_E_INCOMPLETE_MESSAGE);
 
		// Send token to server if there is a token.
		if(OutBuffers[0].cbBuffer != 0 && OutBuffers[0].pvBuffer != NULL)
		{
			cbData = send(s,
						  (const char*)OutBuffers[0].pvBuffer,
						  OutBuffers[0].cbBuffer,
						  0);
 
			if(cbData == SOCKET_ERROR || cbData == 0)
			{
				error("failure sending data to server 0x%x\n", WSAGetLastError());
				goto cleanup;
			}
 
			verbose("%5d bytes of handshake data sent.\n", cbData);
		}
	} while (scRet == SEC_I_CONTINUE_NEEDED);
 
	if (scRet != SEC_E_OK)
	{
		error("server handshake failed with error code 0x%x\n", scRet);
		goto cleanup;
	}
 
	success = true;
 
cleanup:
 
	if (InSecBuffer) LocalFree(InSecBuffer);
	if (OutSecBuffer) LocalFree(OutSecBuffer);
 
	if (!success)
	{
		if (SecIsValidHandle(phContext))
		{
			DeleteSecurityContext(phContext);
			SecInvalidateHandle(phContext);
		}
	}
 
	return success;
}
Vadik(R) вне форума Ответить с цитированием
Старый 16.01.2013, 23:32   #8
Vadik(R)
Пользователь
 
Регистрация: 10.03.2008
Сообщений: 68
По умолчанию

Из названия понятно, что здесь происходит рукопожатие. Причём двойное.
Но в целом, тут мало что понятно. Куча каких-то непонятных структур безопасности, которые я смотрел на MSDN, но запутался. Не понятно, почему структуры заполняются именно такими параметрами, а не какими-либо другими.
Хотелось бы найти объяснение этого участка кода в следующем виде:
Цитата:
Для установки https-соединения необходим процесс рукопожатия. Вначале мы должны отправить серверу такие-то данные о себе (поддерживаемую версию SSL и поддерживаемые алгоритмы шифрования? (источник - http://www.securitylab.ru/analytics/216405.php)). Для того, чтобы получить эти данные, необходимо вызвать такую-то функцию. Эта функция принимает дофига параметров:
Первый параметр такой-то, он отвечает за то-то, поэтому мы присваиваем ему такое-то значение...
К сожалению, подобного разбора в интернете нигде не находил. Сам бы написал хорошую статью на эту тему, да вот пока не понимаю, как это всё работает... Кто-нибудь может помочь, кто силён в этой теме?
Заранее спасибо!

Последний раз редактировалось Vadik(R); 16.01.2013 в 23:38.
Vadik(R) вне форума Ответить с цитированием
Старый 17.01.2013, 06:33   #9
Slym
Участник клуба
 
Регистрация: 07.12.2011
Сообщений: 1,025
По умолчанию

Чем WinInet не угодил?
Не стесняемся, плюсуем!
Slym вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Работа с https. Tip.the.besT Работа с сетью в Delphi 0 10.03.2012 23:29
Компонент без исходников lisiserg Общие вопросы Delphi 7 09.09.2010 09:20
есть ли компонент,чтобы иметь прямой доступ к пикселям jpeg без конвертирования в bmp? Dima_Dima Свободное общение 1 26.05.2010 19:00
есть ли компонент,чтобы иметь прямой доступ к пикселям jpeg без конвертирования в bmp? Dima_Dima Компоненты Delphi 14 26.05.2010 18:30
работа с БД без vcl компонент Jager-ntr БД в Delphi 1 17.05.2008 21:20