有关smtp/esmtp协议(用sniffer捕获了263的esmtp服务器的返回应答,已搞定)中的base64编码规则。

时间:2021-05-29 18:13:46
那天我用自己的sniffer捕获了一个发往263的一份邮件,内容是:

======================================================
Source: 202.96.44.20  --->  Dest: 192.168.0.9 
Protocal type: TCP 
Length: 24 
Context: 
220 smtp.263.net ESMTP

======================================================


======================================================
Source: 192.168.0.9  --->  Dest: 202.96.44.20 
Protocal type: TCP 
Length: 9 
Context: 
HELO vc

======================================================

======================================================
Source: 202.96.44.20  --->  Dest: 192.168.0.9 
Protocal type: TCP 
Length: 18 
Context: 
250 smtp.263.net

======================================================


======================================================
Source: 192.168.0.9  --->  Dest: 202.96.44.20 
Protocal type: TCP 
Length: 32 
Context: 
VRFY "zc1949" <zc1949@263.net>

======================================================


======================================================
Source: 202.96.44.20  --->  Dest: 192.168.0.9 
Protocal type: TCP 
Length: 27 
Context: 
252 Send mail to find out

======================================================


======================================================
Source: 192.168.0.9  --->  Dest: 202.96.44.20 
Protocal type: TCP 
Length: 12 
Context: 
auth LOGIN

======================================================


======================================================
Source: 202.96.44.20  --->  Dest: 192.168.0.9 
Protocal type: TCP 
Length: 18 
Context: 
334 VXNlcm5hbWU6

======================================================


======================================================
Source: 192.168.0.9  --->  Dest: 202.96.44.20 
Protocal type: TCP 
Length: 10 
Context: 
aDdAaOTQ5

======================================================


======================================================
Source: 202.96.44.20  --->  Dest: 192.168.0.9 
Protocal type: TCP 
Length: 18 
Context: 
334 UGFav34acmQ6

======================================================


======================================================
Source: 192.168.0.9  --->  Dest: 202.96.44.20 
Protocal type: TCP 
Length: 14 
Context: 
yMadfaNveQ==

======================================================


======================================================
Source: 202.96.44.20  --->  Dest: 192.168.0.9 
Protocal type: TCP 
Length: 31 
Context: 
235 Authentication successful

======================================================


======================================================
Source: 192.168.0.9  --->  Dest: 202.96.44.20 
Protocal type: TCP 
Length: 28 
Context: 
MAIL FROM:<zc1949@263.net>

======================================================


======================================================
Source: 202.96.44.20  --->  Dest: 192.168.0.9 
Protocal type: TCP 
Length: 8 
Context: 
250 Ok

======================================================


======================================================
Source: 192.168.0.9  --->  Dest: 202.96.44.20 
Protocal type: TCP 
Length: 27 
Context: 
RCPT TO:<iamhxh@sina.com>

======================================================


======================================================
Source: 202.96.44.20  --->  Dest: 192.168.0.9 
Protocal type: TCP 
Length: 8 
Context: 
250 Ok

======================================================


======================================================
Source: 192.168.0.9  --->  Dest: 202.96.44.20 
Protocal type: TCP 
Length: 6 
Context: 
DATA

======================================================

======================================================
Source: 202.96.44.20  --->  Dest: 192.168.0.9 
Protocal type: TCP 
Length: 37 
Context: 
354 End data with <CR><LF>.<CR><LF>

======================================================


======================================================
Source: 192.168.0.9  --->  Dest: 202.96.44.20 
Protocal type: TCP 
Length: 60 
Context: 
Message-Id: <263WingBox.2001.10.30.blsjttafhspkcren@a.b.c>

======================================================

======================================================
Source: 192.168.0.9  --->  Dest: 202.96.44.20 
Protocal type: TCP 
Length: 442 
Context: 
Date: Tue, 30 Oct 2001 10:47:52 +0800
X-Priority: 3
From: "zc1949" <zc1949@263.net>
X-Mailer: 263WingBoxBeta2
To: iamhxh@sina.com
MIME-Version: 1.0
Subject: =?gb2312?B?xOO/tLW9ztK4+MTjtcRFX21haWzBy8Lwo78=?=
Content-Type: text/plain; charset=gb2312
Content-Transfer-Encoding: base64

aHhoOg0KICAgICAgICAgv7S1vcHLwvCjv7K70qrTw3dwc6Os08N3b3Jkv8nS1MLwo78NCiAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbW9uDQo=

.

======================================================


======================================================
Source: 202.96.44.20  --->  Dest: 192.168.0.9 
Protocal type: TCP 
Length: 33 
Context: 
250 Ok: queued as 747341CCCFE63

======================================================


======================================================
Source: 192.168.0.9  --->  Dest: 202.96.44.20 
Protocal type: TCP 
Length: 6 
Context: 
RSET

======================================================


======================================================
Source: 202.96.44.20  --->  Dest: 192.168.0.9 
Protocal type: TCP 
Length: 8 
Context: 
250 Ok

======================================================


但在邮件头出现了:
Subject: =?gb2312?B?xOO/tLW9ztK4+MTjtcRFX21haWzBy8Lwo78=?=
Content-Type: text/plain; charset=gb2312
Content-Transfer-Encoding: base64

题目是中文的,但编了码过后就成了别的了,它的编码规则是base64。我想问以下哪位同事知道。向大家透露一个事:263的smtp要先经过授权后你才可以发送邮件,这一点我也搞不清楚,害的我看了好久的rfc821,结果后来才晓得它用的是esmtp,然后自己又修改了sendmail源程序,提供了auth LOGIN命令(授权),而且取消了一些久的命令,HELP命令就是被delete了。

6 个解决方案

#1


CString CBase64::m_sBase64Alphabet = 
_T( "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" );

int CBase64::m_nMask[] = { 0, 1, 3, 7, 15, 31, 63, 127, 255 };
int CBase64::Decode(LPTSTR szDecoding, LPTSTR szOutput)
{
    int c, lp =0;
int nDigit;
    int nDecode[ 256 ];
int nLen = strlen(szDecoding);

ASSERT( szDecoding != NULL );
ASSERT( szOutput != NULL );
if( szOutput == NULL )
return 0;
if( szDecoding == NULL )
return 0;
if(  nLen == 0 )
return 0;

m_nBitsRemaining = 0;
// 
//建立解码表
for( int i = 0; i < 256; i++ ) 
nDecode[i] = -2; // 无效数字
for( i=0; i < 64; i++ )
{
nDecode[ m_sBase64Alphabet[ i ] ] = i;
nDecode[ m_sBase64Alphabet[ i ] | 0x80 ] = i; // 忽略每八个字节
nDecode[ '=' ] = -1; 
nDecode[ '=' | 0x80 ] = -1; // 忽略MIME填充字符
    }

// 清除输出缓存
memset( szOutput, 0, nLen + 1 );

// 对输入缓存解码
//
for( lp = 0, i = 0; lp < nLen; lp++ )
{
c = szDecoding[ lp ];
nDigit = nDecode[ c & 0x7F ];
if( nDigit < -1 ) 
{
return 0;

else if( nDigit >= 0 ) 
// i (输出索引) 由write_bits()添加
write_bits( nDigit & 0x3F, 6, szOutput, i );
    }
return i;
}

UINT CBase64::read_bits(int nNumBits, int * pBitsRead, int& lp)
{
    ULONG lScratch;
    while( ( m_nBitsRemaining < nNumBits ) && 
   ( lp < m_nInputSize ) ) 
{
int c = m_szInput[ lp++ ];
        m_lBitStorage <<= 8;
        m_lBitStorage |= (c & 0xff);
m_nBitsRemaining += 8;
    }
    if( m_nBitsRemaining < nNumBits ) 
{
lScratch = m_lBitStorage << ( nNumBits - m_nBitsRemaining );
*pBitsRead = m_nBitsRemaining;
m_nBitsRemaining = 0;
    } 
else 
{
lScratch = m_lBitStorage >> ( m_nBitsRemaining - nNumBits );
*pBitsRead = nNumBits;
m_nBitsRemaining -= nNumBits;
    }
    return (UINT)lScratch & m_nMask[nNumBits];
}


void CBase64::write_bits(UINT nBits,
 int nNumBits,
 LPTSTR szOutput,
 int& i)
{
UINT nScratch;

m_lBitStorage = (m_lBitStorage << nNumBits) | nBits;
m_nBitsRemaining += nNumBits;

while( m_nBitsRemaining > 7 ) 
{
nScratch = m_lBitStorage >> (m_nBitsRemaining - 8);
szOutput[ i++ ] = nScratch & 0xFF;
m_nBitsRemaining -= 8;
}
}

#2


to sunhang(悟空):
你是在什么地方看见的相关资料?

#3


曾经编写一个支持POP3下载并解析邮件的COM组件,其中一小段代码是从CodeGuru弄来的,正是你所问的BASE64编码这一段。

#4


我已经搞出来了,谢谢。
BOOL CEDCoder::EncodeBase64(const char *pszIn, int nInLen, char *pszOut, int nOutSize, int *nOutLen) 

    ASSERT(pszIn); 
    ASSERT(pszOut); 
    ASSERT(nOutSize); 
    ASSERT(nOutSize >= Base64BufferSize(nInLen)); 

    #ifndef _DEBUG 
        nOutSize; 
    #endif 

    //初始化编码过程中的循环变量 
        int nInPos = 0; 
        int nOutPos = 0; 
        int nLineLen = 0; 
    //一次从源串中取得三个字符并编码 
        for( int i=0 ; i<nInLen/3 ; i++) 
        { 
            //取得三个字符 
            int c1 = pszIn[nInPos++]&0xFF; 
            int c2 = pszIn[nInPos++]&0xFF; 
            int c3 = pszIn[nInPos++]&0xFF; 
            //将三个字符进行Base64编码 
            pszOut[nOutPos++] = m_base64tab[(c1&0xFC)>>2]; 
            pszOut[nOutPos++] = m_base64tab[((c1&0x03)<<4)|((c2&0xF0)>>4)]; 
            pszOut[nOutPos++] = m_base64tab[((c2&0x0F)<<2)|((c3&0xC0)>>6)]; 
            pszOut[nOutPos++] = m_base64tab[c3&0x3F]; 
            nLineLen += 4; 
            //处理行数越界的情况 
            if(nLineLen >= BASE64_MAXLINE-3) 
            { 
                char* cp = EOL; 
                pszOut[nOutPos++] = *cp++; 
                if(*cp) 
                    pszOut[nOutPos++] = *cp; 
                nLineLen = 0; 
            } 
        } 
        //处理剩余的1或2个字符 
        char* cp; 
        switch(nInLen%3) 
        { 
        case 0: 
            { 
                cp = EOL; 
                pszOut[nOutPos++] = *cp++; 
                if(*cp) 
                    pszOut[nOutPos] = *cp; 
                break; 
            } 
        case 1: 
            { 
                int c1 = pszIn[nInPos]&0xFF; 
                pszOut[nOutPos++] = m_base64tab[(c1&0xFC)>>2]; 
                pszOut[nOutPos++] = m_base64tab[(c1&0x03)<<4]; 
                pszOut[nOutPos++] = '='; 
                pszOut[nOutPos++] = '='; 
                cp = EOL; 
                pszOut[nOutPos++] = *cp++; 
                if(*cp) 
                    pszOut[nOutPos++] = *cp; 
                break; 
            } 
        case 2: 
            { 
                int c1 = pszIn[nInPos++]&0xFF; 
                int c2 = pszIn[nInPos]&0xFF; 
                pszOut[nOutPos++] = m_base64tab[(c1&0xFC)>>2]; 
                pszOut[nOutPos++] = m_base64tab[((c1&0x03)<<4)|((c2&0xF0)>>4)]; 
                pszOut[nOutPos++] = m_base64tab[(c2&0x0F)<<2]; 
                pszOut[nOutPos++] = '='; 
                cp = EOL; 
                pszOut[nOutPos++] = *cp++; 
                if(*cp) 
                    pszOut[nOutPos++] = *cp; 
                break; 
            } 
        default: 
            { 
                //出错了!! 
                ASSERT(FALSE); 
                break; 
            } 
        } 

        pszOut[nOutPos] = 0; 
        *nOutLen = nOutPos; 

    return TRUE; 

#5


你的编码风格不错

#6


呵呵,常来看看啊!

#1


CString CBase64::m_sBase64Alphabet = 
_T( "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" );

int CBase64::m_nMask[] = { 0, 1, 3, 7, 15, 31, 63, 127, 255 };
int CBase64::Decode(LPTSTR szDecoding, LPTSTR szOutput)
{
    int c, lp =0;
int nDigit;
    int nDecode[ 256 ];
int nLen = strlen(szDecoding);

ASSERT( szDecoding != NULL );
ASSERT( szOutput != NULL );
if( szOutput == NULL )
return 0;
if( szDecoding == NULL )
return 0;
if(  nLen == 0 )
return 0;

m_nBitsRemaining = 0;
// 
//建立解码表
for( int i = 0; i < 256; i++ ) 
nDecode[i] = -2; // 无效数字
for( i=0; i < 64; i++ )
{
nDecode[ m_sBase64Alphabet[ i ] ] = i;
nDecode[ m_sBase64Alphabet[ i ] | 0x80 ] = i; // 忽略每八个字节
nDecode[ '=' ] = -1; 
nDecode[ '=' | 0x80 ] = -1; // 忽略MIME填充字符
    }

// 清除输出缓存
memset( szOutput, 0, nLen + 1 );

// 对输入缓存解码
//
for( lp = 0, i = 0; lp < nLen; lp++ )
{
c = szDecoding[ lp ];
nDigit = nDecode[ c & 0x7F ];
if( nDigit < -1 ) 
{
return 0;

else if( nDigit >= 0 ) 
// i (输出索引) 由write_bits()添加
write_bits( nDigit & 0x3F, 6, szOutput, i );
    }
return i;
}

UINT CBase64::read_bits(int nNumBits, int * pBitsRead, int& lp)
{
    ULONG lScratch;
    while( ( m_nBitsRemaining < nNumBits ) && 
   ( lp < m_nInputSize ) ) 
{
int c = m_szInput[ lp++ ];
        m_lBitStorage <<= 8;
        m_lBitStorage |= (c & 0xff);
m_nBitsRemaining += 8;
    }
    if( m_nBitsRemaining < nNumBits ) 
{
lScratch = m_lBitStorage << ( nNumBits - m_nBitsRemaining );
*pBitsRead = m_nBitsRemaining;
m_nBitsRemaining = 0;
    } 
else 
{
lScratch = m_lBitStorage >> ( m_nBitsRemaining - nNumBits );
*pBitsRead = nNumBits;
m_nBitsRemaining -= nNumBits;
    }
    return (UINT)lScratch & m_nMask[nNumBits];
}


void CBase64::write_bits(UINT nBits,
 int nNumBits,
 LPTSTR szOutput,
 int& i)
{
UINT nScratch;

m_lBitStorage = (m_lBitStorage << nNumBits) | nBits;
m_nBitsRemaining += nNumBits;

while( m_nBitsRemaining > 7 ) 
{
nScratch = m_lBitStorage >> (m_nBitsRemaining - 8);
szOutput[ i++ ] = nScratch & 0xFF;
m_nBitsRemaining -= 8;
}
}

#2


to sunhang(悟空):
你是在什么地方看见的相关资料?

#3


曾经编写一个支持POP3下载并解析邮件的COM组件,其中一小段代码是从CodeGuru弄来的,正是你所问的BASE64编码这一段。

#4


我已经搞出来了,谢谢。
BOOL CEDCoder::EncodeBase64(const char *pszIn, int nInLen, char *pszOut, int nOutSize, int *nOutLen) 

    ASSERT(pszIn); 
    ASSERT(pszOut); 
    ASSERT(nOutSize); 
    ASSERT(nOutSize >= Base64BufferSize(nInLen)); 

    #ifndef _DEBUG 
        nOutSize; 
    #endif 

    //初始化编码过程中的循环变量 
        int nInPos = 0; 
        int nOutPos = 0; 
        int nLineLen = 0; 
    //一次从源串中取得三个字符并编码 
        for( int i=0 ; i<nInLen/3 ; i++) 
        { 
            //取得三个字符 
            int c1 = pszIn[nInPos++]&0xFF; 
            int c2 = pszIn[nInPos++]&0xFF; 
            int c3 = pszIn[nInPos++]&0xFF; 
            //将三个字符进行Base64编码 
            pszOut[nOutPos++] = m_base64tab[(c1&0xFC)>>2]; 
            pszOut[nOutPos++] = m_base64tab[((c1&0x03)<<4)|((c2&0xF0)>>4)]; 
            pszOut[nOutPos++] = m_base64tab[((c2&0x0F)<<2)|((c3&0xC0)>>6)]; 
            pszOut[nOutPos++] = m_base64tab[c3&0x3F]; 
            nLineLen += 4; 
            //处理行数越界的情况 
            if(nLineLen >= BASE64_MAXLINE-3) 
            { 
                char* cp = EOL; 
                pszOut[nOutPos++] = *cp++; 
                if(*cp) 
                    pszOut[nOutPos++] = *cp; 
                nLineLen = 0; 
            } 
        } 
        //处理剩余的1或2个字符 
        char* cp; 
        switch(nInLen%3) 
        { 
        case 0: 
            { 
                cp = EOL; 
                pszOut[nOutPos++] = *cp++; 
                if(*cp) 
                    pszOut[nOutPos] = *cp; 
                break; 
            } 
        case 1: 
            { 
                int c1 = pszIn[nInPos]&0xFF; 
                pszOut[nOutPos++] = m_base64tab[(c1&0xFC)>>2]; 
                pszOut[nOutPos++] = m_base64tab[(c1&0x03)<<4]; 
                pszOut[nOutPos++] = '='; 
                pszOut[nOutPos++] = '='; 
                cp = EOL; 
                pszOut[nOutPos++] = *cp++; 
                if(*cp) 
                    pszOut[nOutPos++] = *cp; 
                break; 
            } 
        case 2: 
            { 
                int c1 = pszIn[nInPos++]&0xFF; 
                int c2 = pszIn[nInPos]&0xFF; 
                pszOut[nOutPos++] = m_base64tab[(c1&0xFC)>>2]; 
                pszOut[nOutPos++] = m_base64tab[((c1&0x03)<<4)|((c2&0xF0)>>4)]; 
                pszOut[nOutPos++] = m_base64tab[(c2&0x0F)<<2]; 
                pszOut[nOutPos++] = '='; 
                cp = EOL; 
                pszOut[nOutPos++] = *cp++; 
                if(*cp) 
                    pszOut[nOutPos++] = *cp; 
                break; 
            } 
        default: 
            { 
                //出错了!! 
                ASSERT(FALSE); 
                break; 
            } 
        } 

        pszOut[nOutPos] = 0; 
        *nOutLen = nOutPos; 

    return TRUE; 

#5


你的编码风格不错

#6


呵呵,常来看看啊!