【问题标题】:DIGEST-MD5 implementation in NodeJSNodeJS 中的 DIGEST-MD5 实现
【发布时间】:2021-06-29 21:45:19
【问题描述】:

我正在尝试使用 NodeJS 应用程序访问本地 XMPP 服务器 (Openfire)。
我想使用 DIGEST-MD5 机制(我知道它已被宣布为过时)。

我发现这篇文章解释了该机制的工作原理: https://wiki.xmpp.org/web/SASL_and_DIGEST-MD5

但是,在实现文章中描述的机制时,我计算的响应不正确。
我已尽力找出我做错了什么,但我似乎无法弄清楚。 我确信我的其余部分是正确的,只是响应不正确。

这是我计算响应的代码:

  var x = username + ':' + realm + ':' + pswd;
  var y = crypto.createHash('md5').update(x).digest();
  var a1 = y + ':' + nonce + ':' + cnonce + ':' + authzid;
  var a2 = 'AUTHENTICATE:' + digestUri;
  var ha1 = crypto.createHash('md5').update(a1).digest("hex");
  var ha2 = crypto.createHash('md5').update(a2).digest("hex");
  var kd = ha1 + ':' + nonce + ':00000001:' + cnonce + ':auth:' + ha2;
  var z = crypto.createHash('md5').update(kd).digest("hex");

其中 z 是最终响应。
如您所见,我正在使用加密库进行哈希处理。

上面文章中提到的例子如下:

username="rob",realm="cataclysm.cx",nonce="OA6MG9tEQGm2hh",cnonce="OA6MHXh6VqTrRk",nc=00000001,qop=auth,digesturi="xmpp/cataclysm.cx",response=d388dad90d4bbd760a152321f2143af7,charset=utf-8,authzid="rob@cataclysm.cx/myResource"

当我将所有这些值插入到我自己的实现中(密码为“秘密”)时,我计算出的响应是:

5093acf6b3bc5687231539507cc2fb20

而不是预期的 d388dad90d4bbd760a152321f2143af7
其他例子也没有给我正确的结果。

那么,我到底做错了什么?
任何和所有的帮助将不胜感激!

【问题讨论】:

    标签: node.js hash cryptography xmpp md5


    【解决方案1】:

    在计算响应时,第三行将缓冲区 y(包含 MD5 哈希)与字符串连接起来,其中 y 使用 UTF-8 隐式转换为字符串。
    但是,任意字节序列(例如哈希)将被 UTF8 编码 s 破坏。 here。为防止这种情况,应将各个部分连接为缓冲区而不是字符串。
    相反,其余的连接(在这一行和其他行中)并不重要,因为它们是真正的字符串:

    var crypto = require('crypto');
    
    var charset = 'utf-8';
    var username = 'chris';
    var realm = 'elwood.innosoft.com';
    var nonce = 'OA6MG9tEQGm2hh';
    var nc = '00000001';
    var cnonce = 'OA6MHXh6VqTrRk';
    var digestUri = 'imap/elwood.innosoft.com';
    var response = 'd388dad90d4bbd760a152321f2143af7';
    var qop = 'auth'
    var pswd = 'secret';
    
    var x = username + ':' + realm + ':' + pswd;
    var y = crypto.createHash('md5').update(x).digest();
    var a1 = Buffer.concat([y, Buffer.from(':' + nonce + ':' + cnonce, 'utf8')]); // + ':' + authzid; // Concat buffers instead of strings
    var a2 = 'AUTHENTICATE:' + digestUri;
    var ha1 = crypto.createHash('md5').update(a1).digest('hex');
    var ha2 = crypto.createHash('md5').update(a2).digest('hex');
    var kd = ha1 + ':' + nonce + ':00000001:' + cnonce + ':auth:' + ha2;
    var z = crypto.createHash('md5').update(kd).digest('hex');
    
    console.log(z); // d388dad90d4bbd760a152321f2143af7
    

    注意,代码sn-p中的示例数据不是来自website linked in the question,而是来自RFC2831 (Using Digest Authentication as a SASL Mechanism), chapter 4

    charset=utf-8,username="chris",realm="elwood.innosoft.com",nonce="OA6MG9tEQGm2hh",nc=00000001,cnonce="OA6MHXh6VqTrRk",digest-uri="imap/elwood.innosoft.com",response=d388dad90d4bbd760a152321f2143af7,qop=auth
    

    代码返回response指定的结果,证明计算结果的正确性。


    我不认为website linked in the question 的例子是一致的。预期结果与 RFC 示例中的结果相同,尽管摘要的一些相关输入数据不同。
    巧合匹配的可能性很小(s.collision probability for MD5),因此链接网站的输入数据和预期结果很可能不属于一起。另外,这里没有指定密码。

    所应用的算法在chapter 2.1.2.1 Response-value中有详细描述。请注意,与链接网站上的示例相比,在 RFC 示例中未指定 authzid。根据2.1.2.1章节的描述,这种情况下':' + authzid就直接省略了。

    正如问题中已经提到的,MD5 以及此处使用的算法已被弃用(同样RFC6331)。

    【讨论】:

    • 这是我一直在寻找的答案。它突然起作用了。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-11
    • 2011-09-23
    • 2017-08-30
    • 1970-01-01
    • 2014-05-28
    • 2014-06-22
    • 2011-01-17
    相关资源
    最近更新 更多