doulv1760 2017-06-27 16:14
浏览 69
已采纳

CRAM-MD5验证期间的不同哈希

As an exercise, I'm trying to implement a mock SMTP server with CRAM-MD5 authentication in Go (without following RFC 2195, since it looks like it doesn't matter to the client what format the pre-hashed challenge is in; I also assume there is only one user "bob" with password "pass"). But I can't seem to get it right as the hash in response is always different from what I have on the server. I send the email using Go as such (running it as a separate package):

{...}
smtp.SendMail("localhost:25", smtp.CRAMMD5Auth("bob", "pass"),
   "bob@localhost", []string{"alice@localhost"}, []byte("Hey Alice!
"))
{...}

Here's what I do when I get the authentication acknowledgement from the client:

{...}
case strings.Contains(ms, "AUTH CRAM-MD5"):
    rndbts = make([]byte, 16) // Declared at package level
    b64b := make([]byte, base64.StdEncoding.EncodedLen(16))
    rand.Read(rndbts)
    base64.StdEncoding.Encode(b64b, rndbts)
    _, err = conn.Write([]byte(fmt.Sprintf("334 %x
", b64b)))
{...}

And this is what I do with the client's response:

{...}
 {
    ms = strings.TrimRight(ms, "
") // The response to the challenge
    ds, _ := base64.StdEncoding.DecodeString(ms)
    s := strings.Split(string(ds), " ")
    login := s[0] // I can get the login from the response.
    h := hmac.New(md5.New, []byte("pass"))
    h.Write(rndbts)
    c := make([]byte, 0, ourHash.Size()) // From smtp/auth.go, not sure why we need this.
    validPass := hmac.Equal(h.Sum(c), []byte(s[1]))
    {...}   
}
{...}

And the validPass is never true. I omitted error handling from the excerpts for brevity, but they're there in the actual code (though they're always nil). Why are the hashes different? I have looked at the source code for net/smtp, and it seems to me that I'm going in the right direction, but not quite.

  • 写回答

1条回答 默认 最新

  • doumi4974 2017-06-28 00:12
    关注

    I hope this helps! Runnable version is at https://play.golang.org/p/-8shx_IcLV. Also note that you'll need to fix your %x (should be %s) so you're sending the right challenge down to the client. Right now I think you're trying to hex-encode your base64 string.

    Once you've fixed that, I believe this code should help you to construct the right response string on the server and compare it to what the client sent.

    // Example values taken from http://susam.in/blog/auth-cram-md5/
    
    challenge := []byte("<17893.1320679123@tesseract.susam.in>")
    username := []byte("alice")
    password := []byte("wonderland")
    clientResponse := []byte("YWxpY2UgNjRiMmE0M2MxZjZlZDY4MDZhOTgwOTE0ZTIzZTc1ZjA=")
    
    // hash the challenge with the user's password
    h := hmac.New(md5.New, password)
    h.Write(challenge)
    hash := h.Sum(nil)
    
    // encode the result in lowercase hexadecimal
    hexEncoded := hex.EncodeToString(hash)
    
    // prepend the username and a space
    toEncode := []byte(string(username) + " " + hexEncoded)
    
    // base64-encode the whole thing
    b64Result := make([]byte, base64.StdEncoding.EncodedLen(len(toEncode)))
    base64.StdEncoding.Encode(b64Result, toEncode)
    
    // check that this is equal to what the client sent
    if hmac.Equal(b64Result, clientResponse) {
        fmt.Println("Matches!")
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 双向孟德尔随机化反向是为什么显示参数长度为零
  • ¥15 用C语言完成一个复杂的游戏
  • ¥15 如何批量更改很多个文件夹里的文件名中包含文件夹名?
  • ¥50 MTK手机模拟HID鼠标出现卡顿
  • ¥20 求下下面这个数据结构代码
  • ¥20 前端 二进制文件流图片转化异常
  • ¥15 github上的这个C语言项目如何跑起来
  • ¥15 java 判断某个数 区间是否存在
  • ¥15 appium控制多个雷电模拟器问题
  • ¥15 C# iMobileDevice