国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

smtp服務(wù)認(rèn)證過程

2019-11-11 04:12:28
字體:
供稿:網(wǎng)友

事先聲明,整個(gè)過程以LOGIN認(rèn)證方式為例,其他認(rèn)證方式大同小異。按照時(shí)間順序,主要分為22個(gè)步驟。

1、客戶端TCP連接服務(wù)器25端口;

2、三次握手以后,連接建立成功,服務(wù)器主動(dòng)推送服務(wù)就緒信息

網(wǎng)易郵箱一般都形如“220 163.com Anti-spam GT for Coremail System (163com[20111010])”;雅虎郵箱形如“220 smtp108.mail.gq1.yahoo.com ESMTP”;Google郵箱形如“220 mx.google.com ESMTP nw8sm917193igc.7”。其中220代表服務(wù)就緒,每一條服務(wù)就緒信息以“/r/n”為結(jié)尾標(biāo)示符。    

3、客戶端向服務(wù)器說明身份

交代自己認(rèn)證SMTP服務(wù)器的域名,例如雅虎郵箱的SMTP服務(wù)器為smtp.mail.yahoo.com,則發(fā)送“EHLO smtp.mail.yahoo.com/r/n”。

4、如果身份有效,則服務(wù)器進(jìn)入等待認(rèn)證狀態(tài),主動(dòng)推送自身支持的所有SMTP認(rèn)證方式

網(wǎng)易郵箱發(fā)送的內(nèi)容如下:

250-mail/r/n  250-PipELINING/r/n  250-AUTH LOGIN PLAIN/r/n  250-AUTH=LOGIN PLAIN/r/n  250-coremail/r/n 1Uxr2xKj7kG0xkI17xGrU7I0s8FY2U3Uj8Cz28x1UUUUU7Ic2I0Y2UFWNUp_UCa0xDrUUUUj  250-STARTTLS/r/n  250 8BITMIME/r/n  

表示其支持LOGIN、PLAIN兩種認(rèn)證方式;

雅虎郵箱發(fā)送的內(nèi)容如下:

250-smtp206.mail.ne1.yahoo.com/r/n  250-AUTH LOGIN PLAIN XYMCOOKIE/r/n  250-PIPELINING/r/n  250 8BITMIME/r/n  

表示其支持LOGIN、PLAIN、XYMCOOKIE三種認(rèn)證方式。

5、客戶端判斷自身是否支持服務(wù)器提供的SMTP認(rèn)證方式

如果認(rèn)證方式指定“auto”則采用服務(wù)端提供的第一個(gè)認(rèn)證方式,如果指定其他方式,則判斷服務(wù)端是否支持該方式,否則返回錯(cuò)誤。這一歩相當(dāng)關(guān)鍵,因?yàn)榭蛻舳顺绦蚩梢愿鶕?jù)具體的認(rèn)證方式加載相應(yīng)插件來完成認(rèn)證過程。

6、客戶端向服務(wù)器請(qǐng)求認(rèn)證

發(fā)送“AUTH LOGIN/r/n”。

7、如果認(rèn)證請(qǐng)求合理,服務(wù)器將進(jìn)入等待用戶輸入狀態(tài)

發(fā)送“334 VXNlcm5hbWU6/r/n”,334表示等待客戶端輸入,VXNlcm5hbWU6表示等待輸入用戶名。

8、客戶端向服務(wù)器發(fā)送轉(zhuǎn)碼后的用戶名

發(fā)送經(jīng)過Base64轉(zhuǎn)碼后的用戶名(taotown)”dGFvdG93bg==/r/n“。

9、服務(wù)器再次進(jìn)入等待用戶輸入狀態(tài)

發(fā)送“334 UGFzc3dvcmQ6/r/n”,334表示等待客戶端輸入,UGFzc3dvcmQ6表示等待輸入密碼。

10、客戶端向服務(wù)器發(fā)送轉(zhuǎn)碼后的密碼

發(fā)送經(jīng)過Base64轉(zhuǎn)碼后的密碼(Haier)“SGFpZXI=/r/n”。

11、如果用戶名或者密碼出錯(cuò),服務(wù)器將返回530錯(cuò)誤,發(fā)送“530 access denied/r/n”,表示認(rèn)證失敗。否則將返回235,發(fā)送“235 OK, Go ahead/r/n”,表示用戶認(rèn)證成功。

12、客戶端告訴服務(wù)器郵件來自何方

發(fā)送“MAIL FROM: <taotown@yahoo.com> /r/n”。

13、如果合理,服務(wù)端返回250表示成功

發(fā)送“250 OK , completed/r/n”。

14、客戶端告訴服務(wù)器郵件去往何地

發(fā)送“RCPT TO: <taotown@126.com> /r/n”。

15、如果合理,服務(wù)器返回250表示成功

發(fā)送“250 OK , completed/r/n”。

16、客戶端告訴服務(wù)器自己準(zhǔn)備發(fā)送郵件正文

發(fā)送“DATA/r/n”。

17、服務(wù)器返回354,表示自己已經(jīng)作好接受郵件的準(zhǔn)備

發(fā)送“354 Start Mail. End with CRLF.CRLF/r/n”,提醒客戶端開始發(fā)送郵件并以“.”結(jié)束。

18、客戶端發(fā)送郵件正文(如果正文過長(zhǎng),可以分多次發(fā)送)

發(fā)送

“To: taotown@126.com/r/n  Subject: Hello Trevor/r/n  My name is TaoZhen/r/n  ”。  

19、客戶端發(fā)送完正文以后,緊接著發(fā)送結(jié)束符

發(fā)送“.”。

20、如果合理,服務(wù)端返回250表示成功

發(fā)送“250 OK , completed/r/n”。

21、郵件發(fā)送結(jié)束,客戶端請(qǐng)求斷開連接

發(fā)送“QUIT/r/n”。

22、服務(wù)器返回211,提示斷開申請(qǐng)被采納,并主動(dòng)斷開連接,整個(gè)郵件發(fā)送過程結(jié)束。

發(fā)送“221 Service Closing transmission/r/n”。

附:如果服務(wù)端傳過來的錯(cuò)誤碼后面緊跟這”-“,則說明該次消息分了很多節(jié),直到最后一節(jié)沒有”-“為止。

資料二

在以前接觸的項(xiàng)目中,一直都是在做網(wǎng)站時(shí)用到了發(fā)送mail 的功能,在asp 和.net 中都有相關(guān)的發(fā)送mail 的類, 實(shí)現(xiàn)起來非常簡(jiǎn)單。最近這段時(shí)間因工作需要在C++ 中使用發(fā)送mail 的功能,上網(wǎng)搜了一大堆資料,終于得以實(shí)現(xiàn),總結(jié)自己開發(fā)過程中碰到的一些問題,希望對(duì)需的人有所幫助, 由于能力有限, 文中不免有些誤解之處,望大家能指正!!

其實(shí),使用C++ 發(fā)送mail 也是很簡(jiǎn)的事, 只需要了解一點(diǎn)SMTP 協(xié)議和socket 編程就OK 了, 網(wǎng)絡(luò)上也有很多高人寫好的mail 類源碼,有興趣的朋友可以下載看看.

 

1.     SMTP 常用命令簡(jiǎn)介

1). SMTP 常用命令

HELO/EHLO 向服務(wù)器標(biāo)識(shí)用戶身份

MAIL 初始化郵件傳輸

mail from:

RCPT 標(biāo)識(shí)單個(gè)的郵件接收人;常在MAIL 命令后面

可有多個(gè)rcpt to:

DATA 在單個(gè)或多個(gè)RCPT 命令后,表示所有的郵件接收人已標(biāo)識(shí),并初始化數(shù)據(jù)傳輸,以. 結(jié)束。

VRFY 用于驗(yàn)證指定的用戶/ 郵箱是否存在;由于安全方面的原因,服務(wù)器常禁止此命令

EXPN 驗(yàn)證給定的郵箱列表是否存在,擴(kuò)充郵箱列表,也常被禁用

HELP 查詢服務(wù)器支持什么命令

NOOP 無操作,服務(wù)器應(yīng)響應(yīng)OK

QUIT 結(jié)束會(huì)話

RSET 重置會(huì)話,當(dāng)前傳輸被取消

 

如你對(duì)SMTP 命令不了解,可以用telnet 命令登陸到smtp 服務(wù)器用help 命令進(jìn)行查看:

220 tdcsw.maintek.corpnet.asus ESMTP Sendmail 8.13.8/8.13.8; Sat, 9 Jan 2010 10:45:09 +0800help214-2.0.0 This is sendmail214-2.0.0 Topics:214-2.0.0       HELO    EHLO    MAIL    RCPT    DATA214-2.0.0       RSET    NOOP    QUIT    HELP    VRFY214-2.0.0       EXPN    VERB    ETRN    DSN     AUTH214-2.0.0       STARTTLS214-2.0.0 For more info use “HELP <topic>”.214-2.0.0 To report bugs in the implementation see214-2.0.0       http://www.sendmail.org/email-addresses.html214-2.0.0 For local information send email to Postmaster at your site.214 2.0.0 End of HELP info

2).SMTP 返回碼含義

  *   郵件服務(wù)返回代碼含義 

  *   500   格式錯(cuò)誤,命令不可識(shí)別(此錯(cuò)誤也包括命令行過長(zhǎng)) 

  *   501   參數(shù)格式錯(cuò)誤 

  *   502   命令不可實(shí)現(xiàn) 

  *   503   錯(cuò)誤的命令序列 

  *   504   命令參數(shù)不可實(shí)現(xiàn) 

  *   211    系統(tǒng)狀態(tài)或系統(tǒng)幫助響應(yīng) 

  *   214   幫助信息 

  *   220     服務(wù)就緒 

  *   221     服務(wù)關(guān)閉傳輸信道 

  *   421     服務(wù)未就緒,關(guān)閉傳輸信道(當(dāng)必須關(guān)閉時(shí),此應(yīng)答可以作為對(duì)任何命令的響應(yīng)) 

  *   250   要求的郵件操作完成 

  *   251   用戶非本地,將轉(zhuǎn)發(fā)向 

  *   450   要求的郵件操作未完成,郵箱不可用(例如,郵箱忙) 

  *   550   要求的郵件操作未完成,郵箱不可用(例如,郵箱未找到,或不可訪問) 

  *   451   放棄要求的操作;處理過程中出錯(cuò) 

  *   551   用戶非本地,請(qǐng)嘗試 

  *   452   系統(tǒng)存儲(chǔ)不足,要求的操作未執(zhí)行 

  *   552   過量的存儲(chǔ)分配,要求的操作未執(zhí)行 

  *   553   郵箱名不可用,要求的操作未執(zhí)行(例如郵箱格式錯(cuò)誤) 

  *   354   開始郵件輸入,以. 結(jié)束 

  *   554   操作失敗 

  *   535   用戶驗(yàn)證失敗 

  *   235   用戶驗(yàn)證成功 

  *   334   等待用戶輸入驗(yàn)證信息 for next connection>;

 

3) SMTP 命令應(yīng)用

我們下需使用telnet 命令實(shí)現(xiàn)smtp 郵件的發(fā)送,具體操作如下:

220 tdcsw.com ESMTP Sendmail 8.13.8/8.13.8; Wed, 23 Dec 2009 18:18:18 +0800HELO tdcsw250 tdcsw.com Hello x-128-101-1-240.ahc.umn.edu [128.101.1.240], pleased to meet youMAIL FROM:lily@tdcsw.com250 2.1.0 lily@tdcsw.com… Sender okRCPR TO:sam@163.com250 2.1.5 carven@tdcsw.pegatroncorp.com… Recipient okDATA354 Enter mail, end with “.” on a line by itselfSUBJECT:HELLOHI:HAR are you?.250 2.0.0 nBNAIIG4000507 Message accepted for deliveryquit221 2.0.0 tdcsw.maintek.corpnet.asus closing connectionConnection to host lost.

 

2.     用C++ 實(shí)現(xiàn)Mail 發(fā)送

為了便于理解, 在此就不封裝Mail 類了, 而是以過程式函數(shù)方式給出.

1). 首先需要建立TCP 套接字, 連接端口依服務(wù)器而定,SMTP 服務(wù)默認(rèn)端口為25, 我們以 默認(rèn)端口為例

WSADATA wsaData;

int  SockFD;

WSAStartup(MAKEWord(2,2), &wsaData);

SockFD = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

ServAddr.sin_family = AF_INET;

ServAddr.sin_addr.s_addr = inet_addr (“192.168.1.1”);             //192.168.1.1 為服務(wù)器地址

ServAddr.sin_port = htons(25);

connect(SockFD, (struct sockaddr *)&ServAddr, sizeof(ServAddr));

2). 發(fā)送SMTP 命令及數(shù)據(jù)

const char HEADER[] = “HELO smtpSrv/r/n”

  “MAIL FROM: sender@126.com/r/n”

  “RCPT TO: recv@Gmail.com/r/n”

  “DATA/r/n”

  “FROM: sender@126.com/r/n”

  “TO: recv@gmail.com/r/n”

  “SUBJECT: this is a test/r/n”

  “Date: Fri, 8 Jan 2010 16:12:30/r/n”

“X-Mailer: shadowstar’s mailer/r/n”

  “MIME-Version: 1.0/r/n”

  “Content-type: text/plain/r/n/r/n”;

//send HEADER

send(SockFD, HEADER, strlen(HEADER), 0);

 

const char CONTENT[]=”this is content./r/n”;

//send CONTENT

send(SockFD, CONTENT, strlen(CONTENT), 0);

 

send(SockFD, “./r/n”, strlen(“./r/n”), 0);   //end

send(SockFD, “QUIT/r/n”, strlen(“QUIT/r/n”), 0); //quit

 

mail 發(fā)送的功能基本上就完成了, 當(dāng)然, 如果是應(yīng)用的話還是需要很多改動(dòng)的地方的, 比如說添加附件等.

3). 附件功能

要使用SMTP 發(fā)送附件, 需要對(duì)SMTP 頭信息進(jìn)行說明, 改變Content-type 及為每一段正文添加BOUNDARY名, 示例如下:

“DATA/r/n”

  “FROM: sender@126.com/r/n”

  “TO: recv@gmail.com/r/n”

  “SUBJECT: this is a test/r/n”

  “Date: Fri, 8 Jan 2010 16:12:30/r/n”

“X-Mailer: shadowstar’s mailer/r/n”

  “MIME-Version: 1.0/r/n”

  “Content-type: multipart/mixed; boundary=/”#BOUNDARY#/”/r/n/r/n”;

 

// 正文

“–#BOUNDARY#/r/n”

  “Content-Type: text/plain; charset=gb2312/r/n”

  “Content-Transfer-Encoding: quoted-printable/r/n”

郵件正文……….

 

// 附件

“/r/n–#BOUNDARY#/r/n”

  “Content-Type: application/octet-stream; name=att.txt/r/n”

  “Content-Disposition: attachment; filename=att.txt/r/n”

  “Content-Transfer-Encoding: base64/r/n”

  ”/r/n”

附件正信息(base64 編碼)…..

 

Base64 編碼函數(shù)在網(wǎng)絡(luò)上很容易找到, 這里就不給出源碼了, 如需要支持HTML 格式而又不知道如何寫這些頭信息, 可以用Outlook 或Foxmail 寫一封支持HTML 格式的mail, 查看其原文信息, 依照相同的格式發(fā)送就行了.

 

4). 實(shí)現(xiàn)抄送及密送

在SMTP 命令集中并沒有RCPT CC 或RCPT BCC 相關(guān)命令, 那要如何來實(shí)現(xiàn)抄送和密送功能呢?

在網(wǎng)絡(luò)上找到這樣一句話: “ 所有的接收者協(xié)商都通過RCPT TO 命令來實(shí)現(xiàn),如果是BCC ,則協(xié)商發(fā)送后在對(duì)方接收時(shí)被刪掉信封接收者”, 開始一直不明白這句話是什么意思? 后來通看查看foxmail 的郵件原文發(fā)現(xiàn):

Date: Wed, 6 Jan 2010 12:11:48 +0800

From: “carven_li” < carven_li @smtp.com>

To: “carven” <carven@smtp.com>

Cc: “sam” <sam@smtp.com>,

  “yoyo” <yoyo@smtp.com>

BCC: “clara” <clara@tsmtp.com>

Subject: t

X-mailer: Foxmail 5.0 [cn]

Mime-Version: 1.0

Content-Type: multipart/mixed;

    boundary=”=====001_Dragon237244850520_=====”

才恍然大悟, 所謂的” 協(xié)商” 應(yīng)該就是指發(fā)送方在Data 中指定哪些為CC, 哪些為BCC, 默認(rèn)情況下什么都不寫, 只發(fā)送第一個(gè)RCPT TO 的mail, 其他的都被過濾掉

3. SMTP身份認(rèn)證 SMTP身份認(rèn)證方式有很多種, 每種認(rèn)證方式驗(yàn)證發(fā)送的信息都有點(diǎn)細(xì)微的差別, 這里我主要介紹下LOGIN,PLAIN及NTLM三種簡(jiǎn)單的認(rèn)證方式, 附帶CRAM-md5和DIGEST-MD5方式(驗(yàn)證沒通過, 不知道問題出在哪了? 有待高人幫忙解決!).要進(jìn)行身份認(rèn)證, 先要知道當(dāng)前SMTP服務(wù)器支持哪些認(rèn)證方式, 在ESMTP中有個(gè)與HELO命令相同功能的命令EHLO可以得到當(dāng)前服務(wù)器支持的認(rèn)證方式(有些服務(wù)器無返回信息, 可能服務(wù)器端作了限制). 1) LOGIN認(rèn)證方式LOGIN認(rèn)證方式是基于明文傳輸?shù)? 因此沒什么安全性可言, 如信息被截獲, 那么用戶名和密碼也就泄露了. 認(rèn)證過程如下:AUTH LOGIN334 VXNlcm5hbWU6                            //服務(wù)器返回信息, Base64編碼的Username:bXlOYW1l                                //輸入用戶名, 也需Base64編碼334 UGFzc3dvcmQ6                            //服務(wù)器返回信息, Base64編碼的Password::bXlQYXNzd29yZA==                            //輸入密碼, 也需Base64編碼235 2.0.0 OK Authenticated                        // 535 5.7.0 authentication failed2). NTLM認(rèn)證方式NTLM認(rèn)證方式過程與LOGIN認(rèn)證方式是一模一樣的, 只需將AUTH LOGN改成AUTH NTLM.就行了.3). PLAIN認(rèn)證方式PLAIN認(rèn)證方式消息過過程與LOGIN和NTLM有所不同, 其格式為: “NULL+UserName+NULL+Password”, 其中NULL為C語言中的’/0’, 不方便使用命令行測(cè)試, 因此下面給出C++代碼來實(shí)現(xiàn):char szSend[] = “userpwd”;size_t n = stlen(szSend);for(int i=0; i<n; i++)    if(szSend[i] == ‘$’) szSend[i] = ‘/0’;char szMsg[512]base64_encode(szSend, n, szMsg);send (skt, szMsg, strlen(szMsg), 0);4). CRAM-MD5認(rèn)證方式前面所介紹的三種方式, 都是將用戶名和密碼經(jīng)過BASE64編碼后直接發(fā)送到服務(wù)器端的, BASE64編碼并不是一種安全的加密算法, 其所有信息都可能通過反編碼, 沒有什么安全性可言. 而CRAM-MD5方式與前三種不同, 它是基于Challenge/Response的方式, 其中Challenge是由服務(wù)器產(chǎn)生的, 每次連接產(chǎn)生的Challenge都不同, 而Response是由用戶名,密碼,Challenge組合而成的, 具體格式如下:response=base64_encode(username : H_MAC(challenge, password))H_MAC是Keyed MD5算法(見http://www.faqs.org/rfcs/rfc2195.html), 先由challenge和password生成16位的散列碼, 將其轉(zhuǎn)換成16進(jìn)制32個(gè)字節(jié)的字符串?dāng)?shù)組digest(即以%02x輸出), 再對(duì)(username+空格+digest[32])進(jìn)行base64編碼,就是要發(fā)送的response了.另外, 在http://www.net-track.ch/opensource/cmd5/提供了SMTP CRAM-MD5認(rèn)證源碼, 可用于測(cè)試CRAM-MD5認(rèn)證, 但不知道是不是我這邊測(cè)試的SendMail服務(wù)器配置有問題, 測(cè)試時(shí)一直不能通過.

5). DIGEST-MD5認(rèn)證方式DIGEST-MD5認(rèn)證也是Challenge/Response的方式, 與CRAM-MD5相比, 它的Challenge信息更多, 其Response計(jì)算方式也非常復(fù)雜, 我在測(cè)試時(shí)也是以認(rèn)證失敗而告終, 只是將在網(wǎng)上找到的資料整理于此, 能為后來研究的人多提供點(diǎn)資料, 或者有興趣的朋友們可以和我一起討論下.我們先看下DIGEST-MD5認(rèn)證發(fā)送響應(yīng)信息:DIGEST-MD5服務(wù)器格式說明(見RFC 2831 Digest SASL Mechanism Mai 2000):   digest-challenge =         1 # (Reich | Nonce | qop-Optionen | schal | MAXBUF | charset               Algorithmus | Chiffre-opts | auth-param)        realm = “Reich” “=” < “> Reich-Wert <”>        Reich-Wert = qdstr-val        Nonce = “Nonce” “=” < “> Nonce-Wert <”>        Nonce-Wert = qdstr-val        qop-options = “qop” “=” < “> qop-Liste <”>        qop-list = 1 # qop-Wert        qop-Wert = “auth” | “auth-int” | “auth-conf” |                             Token        stale = “veraltete” “=” “true”        MAXBUF = “MAXBUF” “=” MAXBUF-Wert        MAXBUF-Wert = 1 * DIGIT        charset = “charset” = “” UTF-8 “        algorithm = “Algorithmus” “=” “md5-sess”        Chiffre-opts = “Chiffre” “=” < “> 1 # Null-Wert <”>        Chiffre-value = “3des” | “des” | “RC4-40” | “RC4” |                            “RC4-56” | Token        auth-param = Token “=” (token | quoted-string)DIGEST-MD5客戶端響應(yīng)格式說明(見RFC 2831 Digest SASL Mechanism Mai 2000):   digest-response = 1 # (Benutzername | Reich | Nonce | cnonce |                          Nonce-count | qop | digest-uri | Antwort |                          MAXBUF | charset | Chiffre | authzid |                          auth-param)       username = “username” = “<”> username-Wert < “>       Benutzernamen-Wert = qdstr-val       cnonce = “cnonce” “=” < “> cnonce-Wert <”>       cnonce-Wert = qdstr-val       Nonce-count = “nc” “=” nc-Wert       nc-Wert = 8LHEX       qop = “qop” “=” qop-Wert       digest-uri = “digest-uri” = “<”> digest-uri-value < “>       digest-uri-value = serv-type “/” host [ “/” serv-name]   //eg: smtp/mail3.example.com/example.com       serv-type = 1 * ALPHA            //www for web-service, ftp for ftp-dienst, SMTP for mail-versand-service …       host = 1 * (ALPHA | DIGIT | “-” | “.”)       serv-name = host       response = “Antwort” “=” Response-Wert       response-value = 32LHEX       LHEX = “0” | “1” | “2” | “3” |                          “4” | “5” | “6” | “7” |                          “8” | “9” | “a” | “b” |                          “c” | “d” | “e” | “f”       cipher = “Chiffre” “=” Null-Wert       authzid = “authzid” “=” < “> authzid-Wert <”>       authzid-Wert = qdstr-val其各字段具體含義見相關(guān)文檔, 這里只介始幾個(gè)需要用到的字段是如何產(chǎn)生的, C/S響應(yīng)示例如下:    S: realm=”elwood.innosoft.com”,nonce=”O(jiān)A6MG9tEQGm2hh”,qop=”auth”,       algorithm=md5-sess,charset=utf-8    C: charset=utf-8,username=”chris”,realm=”elwood.innosoft.com”,       nonce=”O(jiān)A6MG9tEQGm2hh”,nc=00000001,cnonce=”O(jiān)A6MHXh6VqTrRk”,       digest-uri=”imap/elwood.innosoft.com”,       response=d388dad90d4bbd760a152321f2143af7,qop=auth    S: rspauth=ea40f60335c427b5527b84dbabcdfffd    The password in this example was “secret”.從這個(gè)示例可以看出, 客戶端返回的信息比服務(wù)器端發(fā)送過來的多了以下幾個(gè):username, nc, cnonce, digest-uri和responeusername就不用說了, nc是8位長(zhǎng)的16進(jìn)制數(shù)字符串,統(tǒng)計(jì)客戶端使用nonce發(fā)出請(qǐng)求的次數(shù)(包含當(dāng)前請(qǐng)求),例示我們可以設(shè)為”00000001”, cnonce是是用了4個(gè)隨機(jī)數(shù)組成一個(gè)8位長(zhǎng)16進(jìn)制的字符串,digest-uri是由在realm前加上請(qǐng)求類型(如http, smtp等), response是一個(gè)32位長(zhǎng)的16進(jìn)制數(shù)組, 計(jì)算公式如下:If the “qop” value is “auth” or “auth-int”:      request-digest  = <”> < KD ( H(A1),     unq(nonce-value)                                          “:” nc-value                                          “:” unq(cnonce-value)                                          “:” unq(qop-value)                                          “:” H(A2)                                  ) <”>   If the “qop” directive is not present (this construction is for   compatibility with RFC 2069):      request-digest  =                 <”> < KD ( H(A1), unq(nonce-value) “:” H(A2) ) >   <”>   See below for the definitions for A1 and A2.Read more: http://www.faqs.org/rfcs/rfc2617.html#ixzz0c4s8ck3FKD(secret,data)表示分類算法,其中data指數(shù)據(jù),secret表示采用的方法.如果表示校驗(yàn)和算法時(shí),data要寫成H(data);而unq(X)表示將帶引號(hào)字符串的引號(hào)去掉。                  對(duì)于”MD5” 和”MD5-sess” 算法: H(data) = MD5(data)和 KD(secret, data) = H(concat(secret, “:”, data))如果”algorithm”指定為”MD5”或沒有指定,A1計(jì)算方式如下:A1  =  unq(username-value) “:” unq(realm-value) “:” passwd//Password為用戶密碼如果”algorithm”指定為”MD5-sess”, 則需要nonce和cnonce的參與:A1       = H(unq(username-value) “:” unq(realm-value) “:” passwd )                     “:” unq(nonce-value) “:” unq(cnonce-value)如果”qop”沒有指定或指定為”auth”, A2計(jì)算方式如下:A2  = Method “:” digest-uri-value如果”qop”沒有指定或指定為”auth int”, A2計(jì)算方式如下:A2 = Method “:” digest-uri-value “:” H(entity-body)Method是http請(qǐng)求時(shí)的方法(post,get), 由于英文水平比較差, 很多都看不明白, 有興趣的朋友可以自己去看看原文(http://www.faqs.org/rfcs/rfc2617.html), 這里還提供了DIGEST驗(yàn)證的代碼:   File “digcalc.h”:#define HASHLEN 16typedef char HASH[HASHLEN];#define HASHHEXLEN 32typedef char HASHHEX[HASHHEXLEN+1];#define IN#define OUT/* calculate H(A1) as per HTTP Digest spec */void DigestCalcHA1(    IN char * pszAlg,    IN char * pszUserName,    IN char * pszRealm,    IN char * pszPassword,    IN char * pszNonce,    IN char * pszCNonce,    OUT HASHHEX sessionKey    );/* calculate request-digest/response-digest as per HTTP Digest spec */void DigestCalcResponse(    IN HASHHEX HA1,           /* H(A1) */    IN char * pszNonce,       /* nonce from server */    IN char * pszNonceCount,  /* 8 hex digits */    IN char * pszCNonce,      /* client nonce */    IN char * pszQop,         /* qop-value: “”, “auth”, “auth-int” */    IN char * pszMethod,      /* method from the request */    IN char * pszDigestUri,   /* requested URL */    IN HASHHEX HEntity,       /* H(entity body) if qop=”auth-int” */    OUT HASHHEX Response      /* request-digest or response-digest */    );File “digcalc.c”:#include <global.h>#include <md5.h>#include <string.h>#include “digcalc.h”void CvtHex(    IN HASH Bin,    OUT HASHHEX Hex    ){    unsigned short i;    unsigned char j;    for (i = 0; i < HASHLEN; i++) {        j = (Bin[i] >> 4) & 0xf;        if (j <= 9)            Hex[i*2] = (j + ‘0’);         else            Hex[i*2] = (j + ‘a(chǎn)’ - 10);        j = Bin[i] & 0xf;        if (j <= 9)            Hex[i*2+1] = (j + ‘0’);         else            Hex[i*2+1] = (j + ‘a(chǎn)’ - 10);    };    Hex[HASHHEXLEN] = ‘/0’;};/* calculate H(A1) as per spec */void DigestCalcHA1(    IN char * pszAlg,    IN char * pszUserName,    IN char * pszRealm,    IN char * pszPassword,    IN char * pszNonce,    IN char * pszCNonce,    OUT HASHHEX SessionKey    ){      MD5_CTX Md5Ctx;      HASH HA1;      MD5Init(&Md5Ctx);      MD5Update(&Md5Ctx, pszUserName, strlen(pszUserName));      MD5Update(&Md5Ctx, “:”, 1);      MD5Update(&Md5Ctx, pszRealm, strlen(pszRealm));      MD5Update(&Md5Ctx, “:”, 1);      MD5Update(&Md5Ctx, pszPassword, strlen(pszPassword));      MD5Final(HA1, &Md5Ctx);      if (stricmp(pszAlg, “md5-sess”) == 0) {            MD5Init(&Md5Ctx);            MD5Update(&Md5Ctx, HA1, HASHLEN);            MD5Update(&Md5Ctx, “:”, 1);            MD5Update(&Md5Ctx, pszNonce, strlen(pszNonce));            MD5Update(&Md5Ctx, “:”, 1);            MD5Update(&Md5Ctx, pszCNonce, strlen(pszCNonce));            MD5Final(HA1, &Md5Ctx);      };      CvtHex(HA1, SessionKey);};/* calculate request-digest/response-digest as per HTTP Digest spec */void DigestCalcResponse(    IN HASHHEX HA1,           /* H(A1) */    IN char * pszNonce,       /* nonce from server */    IN char * pszNonceCount,  /* 8 hex digits */    IN char * pszCNonce,      /* client nonce */    IN char * pszQop,         /* qop-value: “”, “auth”, “auth-int” */    IN char * pszMethod,      /* method from the request */    IN char * pszDigestUri,   /* requested URL */    IN HASHHEX HEntity,       /* H(entity body) if qop=”auth-int” */    OUT HASHHEX Response      /* request-digest or response-digest */    ){      MD5_CTX Md5Ctx;      HASH HA2;      HASH RespHash;       HASHHEX HA2Hex;      // calculate H(A2)      MD5Init(&Md5Ctx);      MD5Update(&Md5Ctx, pszMethod, strlen(pszMethod));      MD5Update(&Md5Ctx, “:”, 1);      MD5Update(&Md5Ctx, pszDigestUri, strlen(pszDigestUri));      if (stricmp(pszQop, “auth-int”) == 0) {            MD5Update(&Md5Ctx, “:”, 1);            MD5Update(&Md5Ctx, HEntity, HASHHEXLEN);      };      MD5Final(HA2, &Md5Ctx);       CvtHex(HA2, HA2Hex);      // calculate response      MD5Init(&Md5Ctx);      MD5Update(&Md5Ctx, HA1, HASHHEXLEN);      MD5Update(&Md5Ctx, “:”, 1);      MD5Update(&Md5Ctx, pszNonce, strlen(pszNonce));      MD5Update(&Md5Ctx, “:”, 1);      if (*pszQop) {          MD5Update(&Md5Ctx, pszNonceCount, strlen(pszNonceCount));          MD5Update(&Md5Ctx, “:”, 1);          MD5Update(&Md5Ctx, pszCNonce, strlen(pszCNonce));          MD5Update(&Md5Ctx, “:”, 1);          MD5Update(&Md5Ctx, pszQop, strlen(pszQop));          MD5Update(&Md5Ctx, “:”, 1);      };      MD5Update(&Md5Ctx, HA2Hex, HASHHEXLEN);      MD5Final(RespHash, &Md5Ctx);      CvtHex(RespHash, Response);};File “digtest.c”:#include <stdio.h>#include “digcalc.h”void main(int argc, char ** argv) {      char * pszNonce = “dcd98b7102dd2f0e8b11d0f600bfb0c093”;      char * pszCNonce = “0a4f113b”;      char * pszUser = “Mufasa”;      char * pszRealm = “testrealm@host.com”;      char * pszPass = “Circle Of Life”;      char * pszAlg = “md5”;      char szNonceCount[9] = “00000001”;      char * pszMethod = “GET”;      char * pszQop = “auth”;      char * pszURI = “/dir/index.html”;      HASHHEX HA1;      HASHHEX HA2 = “”;      HASHHEX Response;      DigestCalcHA1(pszAlg, pszUser, pszRealm, pszPass, pszNonce,pszCNonce, HA1);      DigestCalcResponse(HA1, pszNonce, szNonceCount, pszCNonce, pszQop,       pszMethod, pszURI, HA2, Response);      printf(“Response = %s/n”, Response);};到這里,關(guān)于使用SMTP發(fā)送mail就結(jié)束了, 由于水平有限, 有很多地方可能講不夠透徹!!!


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 米易县| 禹州市| 崇义县| 衡阳县| 琼结县| 宜君县| 博客| 大余县| 北辰区| 科技| 运城市| 叙永县| 中宁县| 通许县| 泰兴市| 五华县| 基隆市| 固镇县| 饶河县| 揭东县| 宣恩县| 鄯善县| 分宜县| 吴桥县| 天镇县| 安顺市| 和政县| 南郑县| 台江县| 衡南县| 泰安市| 静乐县| 泌阳县| 辛集市| 长葛市| 弥渡县| 永宁县| 三穗县| 信阳市| 郑州市| 封丘县|