jjzjj

go - CRAM-MD5 身份验证期间的不同哈希值

coder 2024-07-07 原文

作为练习,我正在尝试在 Go 中实现一个带有 CRAM-MD5 身份验证的模拟 SMTP 服务器(不遵循 RFC 2195,因为对于客户端来说,预哈希挑战是什么格式似乎无关紧要in; 我还假设只有一个用户“bob”,密码为“pass”)。但我似乎无法正确处理,因为响应中的哈希总是与我在服务器上拥有的不同。我使用 Go 发送电子邮件(将其作为单独的包运行):

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

这是我从客户端收到身份验证确认后所做的事情:

{...}
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\n", b64b)))
{...}

这就是我对客户的回应所做的:

{...}
 {
    ms = strings.TrimRight(ms, "\r\n") // 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]))
    {...}   
}
{...}

validPass 永远不会true。为简洁起见,我在摘录中省略了错误处理,但它们存在于实际代码中(尽管它们始终为 nil)。为什么哈希不同?我查看了 net/smtp 的源代码,在我看来我的方向是正确的,但又不完全是。

最佳答案

希望对您有所帮助!可运行版本位于 https://play.golang.org/p/-8shx_IcLV .另请注意,您需要修复 %x(应为 %s),以便向客户端发送正确的质询。现在我认为您正在尝试对 base64 字符串进行十六进制编码。

一旦你解决了这个问题,我相信这段代码应该可以帮助你在服务器上构建正确的响应字符串并将其与客户端发送的内容进行比较。

// 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!")
}

关于go - CRAM-MD5 身份验证期间的不同哈希值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44785181/

有关go - CRAM-MD5 身份验证期间的不同哈希值的更多相关文章

  1. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  2. java - 为什么 ruby​​ modulo 与 java/other lang 不同? - 2

    我基本上来自Java背景并且努力理解Ruby中的模运算。(5%3)(-5%3)(5%-3)(-5%-3)Java中的上述操作产生,2个-22个-2但在Ruby中,相同的表达式会产生21个-1-2.Ruby在逻辑上有多擅长这个?模块操作在Ruby中是如何实现的?如果将同一个操作定义为一个web服务,两个服务如何匹配逻辑。 最佳答案 在Java中,模运算的结果与被除数的符号相同。在Ruby中,它与除数的符号相同。remainder()在Ruby中与被除数的符号相同。您可能还想引用modulooperation.

  3. ruby-on-rails - 在 RSpec 中,如何以任意顺序期望具有不同参数的多条消息? - 2

    RSpec似乎按顺序匹配方法接收的消息。我不确定如何使以下代码工作:allow(a).toreceive(:f)expect(a).toreceive(:f).with(2)a.f(1)a.f(2)a.f(3)我问的原因是a.f的一些调用是由我的代码的上层控制的,所以我不能对这些方法调用添加期望。 最佳答案 RSpecspy是测试这种情况的一种方式。要监视一个方法,用allowstub,除了方法名称之外没有任何约束,调用该方法,然后expect确切的方法调用。例如:allow(a).toreceive(:f)a.f(2)a.f(1)

  4. ruby-on-rails - 如何用不同的用户运行nginx主进程 - 2

    A/ctohttp://wiki.nginx.org/CoreModule#usermaster进程曾经以root用户运行,是否可以以不同的用户运行nginxmaster进程? 最佳答案 只需以非root身份运行init脚本(即/etc/init.d/nginxstart),就可以用不同的用户运行nginxmaster进程。如果这真的是你想要做的,你将需要确保日志和pid目录(通常是/var/log/nginx&/var/run/nginx.pid)对该用户是可写的,并且您所有的listen调用都是针对大于1024的端口(因为绑定(

  5. ruby - 从 sinatra 中的 before do block 返回不同的值 - 2

    有没有办法在sinatra的beforedoblock中停止执行并返回不同的值?beforedo#codeishere#Iwouldliketo'return"Message"'#Iwouldlike"/home"tonotgetcalled.end//restofthecodeget'/home'doend 最佳答案 beforedohalt401,{'Content-Type'=>'text/plain'},'Message!'end如果你愿意,你可以只指定状态,这里有状态、标题和正文的例子

  6. ruby-on-rails - Sunspot:如何对具有不同值的多个字段进行全文查询? - 2

    我想用sunspot重现以下原始solr查询q=exact_term_text:fooORterm_textv:foo*ORalternate_text:bar*但我无法通过标准的太阳黑子界面理解这是否可能以及如何实现,因为看起来:fulltext方法似乎不接受多个文本/搜索字段参数我不知道将什么参数作为第一个参数传递给fulltext,就好像我通过了"foo"或"bar"结果不匹配如果我传递一个空参数,我得到一个q=*:*范围过滤器(例如with(:term).starting_with('foo*')(顾名思义)作为过滤器查询应用,因此不参与评分。似乎可以手动编写字符串(或者可能使

  7. ruby-on-rails - Rails 基本 Base64 身份验证 - 2

    我正在尝试复制此GETcurl请求:curl-D--XGET-H"Authorization:BasicdGVzdEB0YXByZXNlYXJjaC5jb206NGMzMTg2Mjg4YWUyM2ZkOTY2MWNiNWRmY2NlMTkzMGU="-H"Content-Type:application/json"http://staging.example.com/api/v1/campaigns在Ruby中,通过电子邮件+apikey生成身份验证:auth="Basic"+Base64::encode64("test@example.com:4c3186288ae23fd9661c

  8. ruby-on-rails - (Ruby,Rails) 基于角色的身份验证和用户管理...? - 2

    我正在寻找用于Rails的优质管理插件。似乎大多数现有的插件/gem(例如“restful_authentication”、“acts_as_authenticated”)都围绕着self注册等展开。但是,我正在寻找一种功能齐全的基于管理/管理角色的解决方案——但不是简单地附加到另一个非基于角色的解决方案。如果我找不到,我想我会自己动手......只是不想重新发明轮子。 最佳答案 RyanBates最近做了两个关于授权的railscast(注意身份验证和授权之间的区别;身份验证检查用户是否如她所说的那样,授权检查用户是否有权访问资源

  9. ruby-on-rails - 在 Rails 3 中进行身份验证最常用的方法是什么? - 2

    我需要在rail3中使用标准注册/登录/忘记密码功能进行身份验证。是否有大多数人为此使用的插件或其他东西? 最佳答案 我不确定最常用的方法是什么-但可以肯定的是,Plataformatec的“Devise”是一个非常流行的方法:http://github.com/plataformatec/devise我已经尝试了一些authgem,对我来说,它是最简单的设置和修改以满足我的需要。它内置了密码恢复、帐户确认(如果需要)和其他一些非常方便的功能。 关于ruby-on-rails-在Rail

  10. ruby - 拆分字符串并分配给不同的变量 - 2

    我从ui中得到日期范围为-approved_between"=>"2013-03-17-2013-03-18"我需要拆分此approved_start_date="2013-03-17"和approved_end_date="2013-03-18"...我希望使用它在mysql中查询,因为mysql中的日期格式是created_at:2012-07-2810:35:01.我正在做的是:approved=approved_between.split("")approved_start_date=approved[0]approved_end_date=approved[2]很确定这不是处

随机推荐