如何用C語言和windows api實現一個基本的ssl協議?(參考資料已備齊)

採用基本的C語言和windows api實現一個基本的ssl協議。
--------------------------------
感謝各位的回答,你們所有人的回答都讓我很受益。(2015-2-16 12:10)

SSL/STL協議越來越流行,SSL已成為了一個必學的技術點,下面是我找到的相關資料,以下資料看完應該可以完全解決這個問題了。
《SSL.and.TLS_Designing.and.Building.Secure.Systems》
RFC 2818 - HTTP Over TLS http://120.52.72.48/tools.ietf.org/c3pr90ntcsf0/rfc/rfc2818.txt
RFC 5246 - The Transport Layer Security (TLS) Protocol Version 1.2 http://tools.ietf.org/rfc/rfc5246.txt
《SSL與TLS》 Eric Rescorla 編著
《SSL TLS Essentials Securing the Web》


推薦 libcurl - the multiprotocol file transfer library


樓主請先看看這篇文章 https://blog.helong.info/blog/2015/09/06/tls-protocol-analysis-and-crypto-protocol-design/


WinHTTP Sessions Overview (Windows)
SSL in WinHTTP (Windows)

實在不懂就去看看GitHub - kimtg/WinHttpExample: WinHTTP example
這個例子已經是HTTPS的示例的
如果你還是不會用,這位朋友啊,我覺得你不適合編程

爬數據用啥C啊,這種事情都是啥簡單用啥,比如我都是PHP+JS,簡單粗暴


不會用openssl,於是想自己實現個類似的。
這是學不會開車於是想自己造一輛么
=======
我一直覺得想學東西起碼得有點鑽研的精神和研究的耐性,碰到困難了想辦法自己解決,這才是學習。
如果這個問題的題目是「編譯openssl庫後發現無法使用,xxxx現象,請大神指點」,這個叫鑽研,
如果是「想自己試著寫一個ssl庫練手,順便了解ssl的原理,請大神指點思路」,這個也叫鑽研。

你現在這個問題的描述則是:
1、「找相關資料編譯後的庫也無法正常使用」
現成的庫不會使
2、「現在想不如自己來親手寫一個」
覺得自己寫的省事,不用研究現成的庫那麼「費事」了
3、「功能簡單夠用就行了」,以及在我這答案里回復的:「造不了大奔但可是造個自行車用用唄」
對自己的標準放的很低,所以還是奔著省事來的。
4、還是在我這個答案里之前回復的「我相信這個東西的實現並不難,參考一下相關資料應該很快可以搞定的。」
到這那我就得不友善的下個結論了,題主是犯懶而且有點自大。

為什麼說自大?
因為openssl庫這樣成熟穩定的開源庫,只要學會怎麼編譯,怎麼調用就可以了,常見使用場景下的坑,別人已經碰到過不知道多少遍,早填過來了,有問題大部分是自己調用的問題,而且通常google就能解決,學會怎麼使碰到的坑要遠比自己實現一遍遇到的坑少的多,即使自己實現的玩意簡陋的不行,但凡是個寫過幾年代碼都知道這麼回事。

如果自己實現出現問題了,首先得排查是不是自己的設計有問題,之後要排查是不是自己代碼腦子不清、手誤寫出來的bug,有時候還不知道是設計問題還是自己的bug還是伺服器的協議版本不支持造成的問題。
這個過程中抓包、下斷點調試等等的過程非常麻煩,難度大了很多倍,你都不了解ssl的實現就說「相信這個東西的實現並不難」,只能說明你有點自大。

你要是直接問為了學習練手,自己實現個ssl庫碰到xx問題,大部分人都會支持你,可你前面一堆都是都是圖省事的理由,繞過簡單的辦法找了個麻煩的方法,然後理由寫的還是這個「簡單、不難、很快可以搞定」,這讓人看到有點呵呵了。


鞭炮都不會放,也不想學怎麼放,就想自己造核彈出來了?


不想用現成庫的話,你可以先試著實現一下求解:w = (x ^ y) mod z,其中:

x = 0x251efe513c7f8db2b395bde03767facda67109811619160e537b241d02ef639d;
y = 0x1e5a85b28c1a3ed0695bdb8ab15cfa5737933cc84f65cfee3f27956967216a49;
z = 0x22de8ed23bf3f2ddf3604e6a8dda60ad1a20486cddf9bf755bb9e8ccf7b7f05f;

要求 0.1ms以內完成計算,接著你再試著實現一個簡單的 RSA演算法,然後再說其他。
---
試著評估下,如果自己2-3周內能夠實現,自己也有時間和興趣就實現下去,沒時間的話果斷的用各種現成庫吧。


1、採用WINDOWS系統所擁有的API如何獲取HTTPS協議的網頁?
Windows的WinHTTP API簇支持HTTPS協議,所以你只需要使用WinHTTP API就可以實現靜態網頁下載。我兩三年前的練習(api demo代碼很短):win_net/mix_bak.cpp at master · cswuyg/win_net · GitHub 代碼可以用來下載文件、靜態網頁。如果是動態網頁,還需要熟悉一些ATL庫的使用,相當於寫一個簡單的瀏覽器。
2、不知哪位大神知道如何通過SSL協議連接HTTP伺服器並下載網頁,給個例子
沒寫過,如果是要不藉助系統API,完全從底層自己實現https的話,可以學習chromium的代碼,所有你想要的它都有。


我想往牆上釘個釘子,但是鎚子我不會用,於是我想乾脆就造個類似的吧,請問用螺絲刀怎麼比較容易把釘子敲進去。


你可以用curl庫或者另一答主林北提到的wininet和winhttp的api。


只是訪問https頁面的。
直接貼給你代碼 只能跑出個效果←_← 直接貼過去用肯定是不行的。

int Test(TCHAR *Url){
int HTTPS = 1;
int AccessMethod = 1; //訪問方式
TCHAR *DomainName = GetDomainNameForUrl(Url), *PageAddress = GetPathForUrl(Url); //域名, 頁面地址
int Port = GetPortForUrl(Url); //埠
_tprintf(TEXT("DomainName:%s
PageAddress:%s
Port:%d
"), DomainName, PageAddress, Port);
TCHAR *ProxyAddress = NULL, *ProxyUserName = NULL, *PagePassword = NULL; //代理地址, 代理的用戶名, 代理的密碼
TCHAR *AdditionalProtocolHeader = TEXT(""), *CommitProtocolHeader = NULL; //附加協議頭, 提交協議頭
char *SubmittedData = ""; //提交的數據(POST使用)
int SubmittedDataLength = strlen(SubmittedData); //提交數據長度
TCHAR *Cookie = NULL, *SubmittedCookie = NULL; //Cookie
int CookieLength = 0;
char ReceiveBuffer[512] = {0};
DWORD Number = 0;
char *GetData = NULL;
int GetLength = 0;
TCHAR *Request = NULL;
DWORD HALEN = 4096;
TCHAR BrowserVersion[] = TEXT("Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.2)");
TCHAR Headers_A[] = TEXT("Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
");
HINTERNET hOpen = NULL, hConnect = NULL, hRequest = NULL;
hOpen = InternetOpen(BrowserVersion, (ProxyAddress != NULL ? 3 : 1), ProxyAddress, NULL, 0);
if (hOpen == NULL)
return -1;
hConnect = InternetConnect(hOpen, DomainName, Port, ProxyUserName, PagePassword, INTERNET_SERVICE_HTTP, 0, 0);
if (hConnect == NULL){
InternetCloseHandle(hOpen);
return -2;
}
if (Cookie == NULL)
hRequest = HttpOpenRequest(hConnect, (AccessMethod == 0 ? TEXT("GET") : TEXT("POST")), PageAddress, TEXT("HTTP/1.1"), NULL, NULL, (HTTPS == 1 ? 524288 | INTERNET_FLAG_SECURE : 524288), 0);//INTERNET_FLAG_SECURE
else
hRequest = HttpOpenRequest(hConnect, (AccessMethod == 0 ? TEXT("GET") : TEXT("POST")), PageAddress, TEXT("HTTP/1.1"), NULL, NULL, (HTTPS == 1 ? 2147483648 | INTERNET_FLAG_SECURE : 2147483648), 0);
if (hRequest == NULL){
InternetCloseHandle(hConnect);
InternetCloseHandle(hOpen);
return -3;
}
if (AdditionalProtocolHeader != NULL){
CommitProtocolHeader = calloc(1, sizeof(TCHAR) * 4096 * 2 + _tcslen(AdditionalProtocolHeader));
memcpy(CommitProtocolHeader, AdditionalProtocolHeader, _tcslen(AdditionalProtocolHeader));
}else
CommitProtocolHeader = calloc(1, sizeof(TCHAR) * 4096 * 2);
if (_tcsstr(CommitProtocolHeader, TEXT("Accept: ")) == NULL)
_stprintf(CommitProtocolHeader, TEXT("%s%s"), CommitProtocolHeader, Headers_A);
if (_tcsstr(CommitProtocolHeader, TEXT("Referer: ")) == NULL)
_stprintf(CommitProtocolHeader, TEXT("%sReferer: %s
"), CommitProtocolHeader, Url);
if (_tcsstr(CommitProtocolHeader, TEXT("Accept-Language: ")) == NULL)
_stprintf(CommitProtocolHeader, TEXT("%sAccept-Language: zh-cn
"), CommitProtocolHeader);
if (Cookie != NULL){
CookieLength = _tcslen(Cookie);
SubmittedCookie = calloc(1, sizeof(TCHAR) * CookieLength + 16);
_stprintf(SubmittedCookie, TEXT("Cookie: %s"), Cookie);
HttpAddRequestHeaders(hRequest, SubmittedCookie, CookieLength, 0);
free(SubmittedCookie);
}
if (AccessMethod == 0)
HttpSendRequest(hRequest, CommitProtocolHeader, _tcslen(CommitProtocolHeader), NULL, 0);
else{
if (SubmittedData != NULL){
if (_tcsstr(CommitProtocolHeader, TEXT("Content-Type: ")) == NULL)
_stprintf(CommitProtocolHeader, TEXT("%sContent-Type: application/x-www-form-urlencoded
"), CommitProtocolHeader);
_stprintf(CommitProtocolHeader, TEXT("%sContent-Length: %d
"), CommitProtocolHeader, SubmittedDataLength);
}
HttpSendRequest(hRequest, CommitProtocolHeader, _tcslen(CommitProtocolHeader), SubmittedData, SubmittedDataLength);
}
free(CommitProtocolHeader);
do{
InternetReadFile(hRequest, ReceiveBuffer, sizeof(ReceiveBuffer), Number);
if (Number == 0)
break;
GetData = realloc(GetData, GetLength + sizeof(ReceiveBuffer));
memcpy(GetData + GetLength, ReceiveBuffer, Number);
GetLength = GetLength + Number;
}while(Number != 0);
Request = calloc(1, sizeof(TCHAR) * HALEN);
HttpQueryInfo(hRequest, 22, Request, HALEN, 0);
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hOpen);
//Test
FILE *fp = NULL;
fp = _tfopen(TEXT("1.html"), TEXT("wb+"));
fwrite(GetData, 1, GetLength, fp);
fclose(fp);
return 0;
}


大一狗,確認無誤


好,開發一個CloseSSL庫


https://msdn.microsoft.com/en-us/library/windows/desktop/aa380123(v=vs.85).aspx


理由不成立。

openssl在Windows上的替代品是有的,但是他們解決的問題是一致的,也就是說包含的東西是同一類,僅僅是換個口味而已。


爬網頁和openssl沒半毛錢關係,openssl用於ssl握手,爬網頁爬的是http內容;

不知道windows下面有沒有wget,好像可以裝cygwin吧,有的話直接使用wget就好了,例如
wget https://www.taobao.com


學下go語言吧


你先了解下wget/curl/libcurl


WININET和WINHTTP都是win32的API貌似都支持https。
(第一次見到用c寫爬蟲的)


推薦閱讀:

全面普及 HTTPS 有意義嗎?
自2013 年 7 月大量 Apple ID 被盜用來在中國區 App Store 進行刷榜,誰的嫌疑最大?
本人小白準備學習網路攻防,想知道這門技術十幾年後會被淘汰嗎?如果感覺回答很麻煩直接回答會或不會就好了?
公司是否能夠亦或是否有權截獲員工在公司電腦使用https訪問網站的內容?如何實現?
SSL根證書里的公鑰為什麼是密文?

TAG:網路安全 | 爬蟲計算機網路 | 網路編程 |