我正在编写一个C#DKIM验证器,遇到了一个我无法解决的问题。现在我正在计算身体哈希值,如Section 3.7 Computing the Message Hashes中所述。我正在使用Exchange 2010传输代理SDK中使用EdgeTransportAsyncLogging示例的修改版本转储的电子邮件。它不是在保存时转换电子邮件,而是根据MessageID打开文件并将原始数据转储到磁盘。
我可以使用以下代码成功计算Section A.2中提供的示例电子邮件的正文哈希值:
SHA256Managed hasher = new SHA256Managed();
ASCIIEncoding asciiEncoding = new ASCIIEncoding();
string rawFullMessage = File.ReadAllText(@"C:\Repositories\Sample-A.2.txt");
string headerDelimiter = "\r\n\r\n";
int headerEnd = rawFullMessage.IndexOf(headerDelimiter);
string header = rawFullMessage.Substring(0, headerEnd);
string body = rawFullMessage.Substring(headerEnd + headerDelimiter.Length);
byte[] bodyBytes = asciiEncoding.GetBytes(body);
byte[] bodyHash = hasher.ComputeHash(bodyBytes);
string bodyBase64 = Convert.ToBase64String(bodyHash);
string expectedBase64 = "2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=";
Console.WriteLine("Expected hash: {1}{0}Computed hash: {2}{0}Are equal: {3}",
Environment.NewLine, expectedBase64, bodyBase64, expectedBase64 == bodyBase64);
以上代码的输出是:
Expected hash: 2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=
Computed hash: 2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=
Are equal: True
现在,大多数电子邮件都会遇到c=relaxed/relaxed
设置,这需要您在散列和验证之前对主体和标题执行一些操作。当我正在努力(没有让它工作)时,我终于看到了一条带有c=simple/simple
的消息,这意味着你处理整个身体,因为它减去任何空的CRLF
。身体。 (实际上,Body Canonicalization的规则非常...... simple。)
这是使用简单算法(完全未修改)的real DKIM email(右键单击并保存,浏览器使用结尾CRLF
)和签名。现在,使用上面的代码并更新expectedBase64
哈希,我得到以下结果:
Expected hash: VnGg12/s7xH3BraeN5LiiN+I2Ul/db5/jZYYgt4wEIw=
Computed hash: ISNNtgnFZxmW6iuey/3Qql5u6nflKPTke4sMXWMxNUw=
Are equal: False
预期哈希值是bh=
标头的DKIM-Signature
字段中的值。现在,第二个测试中使用的文件是Exchange 2010传输代理的直接原始输出。如果这样倾向,您可以查看修改后的EdgeTransportLogging.txt。
此时,无论我如何修改第二封电子邮件,更改文件末尾的CRLF
的起始位置或数量,我都无法获得匹配的文件。令我担心的是,到目前为止,我无法验证任何正文哈希(简单或放松),并且通过Exchange 2010处理DKIM可能不太可行。
答案 0 :(得分:1)
我在python-dkim中尝试了这个,我也得到了一个正文哈希不匹配。
我认为可能Exchange的GetMimeReadStream
没有给出传输时的实际字节数,因此哈希值不匹配。可能是它将消息分解为其mime部分,然后GetMimeReadStream为您提供 有效的消息表示,但不是最初发送的消息。
也许有另一个API会给你真正的原始字节?
或者也许在这个过程中,消息已经被拆开,原始消息被丢弃,你需要先加入。
您可能应该尝试通过将DKIM签名的邮件发送到非Exchange服务器来拦截它,并查看它是否适用于您的代码。 GetContentReadStream
可能有用吗?
无论如何,我接下来要做的是尝试找到一个API,它可以逐字节地发送所发送的内容。