【发布时间】:2021-03-07 14:18:30
【问题描述】:
我正在尝试使用 DKIM 标头向 gmail(或任何其他电子邮件提供商)发送一封非常简单的电子邮件。
gmail中的结果是:dkim=neutral(body hash没有验证)
我认为正文散列不正确。 我把body弄得超级简单,但还是报同样的错误。
这是 SMTP 数据字符串:
DKIM-Signature:v=1; a=rsa-sha1; q=dns/txt; s=default;\r\n c=simple/simple; d=cumulo9.com; h=Date:From:To:Content-Type:Content-Transfer-Encoding;\r\n t=1489977499; bh=rtE3fSBFa/HdaPcuGaMM2mZVL7Mljo9sPTNOBjmNBdgIpGYh+ukt71Joc/qFd/nY70yn/hW0nASN+SZARGY2ri0ymA6NUrCIcSX7yJxJ6MkO78cyGZUoHY6Y+kOsDfCUcH5ANHJs88iUtu4IviWP4vWHXBd/tqP9k7Q+UKaC+m4=;\r\n b=klwC+c8qFKVD32SK22K04/YID+TerTvd26+VnlTljNA3fOEVbi2YlvTFo5LM1VksmO08hu5iJfwmF/3GgSEOnGT3mrzXxofjPbvIWU181zluxObNt8FwrP0kCIUskJEQz2SPF1VzaMQ8QvVchnkEFYrW9Pvssk6hunNr8J6CGrc=\r\nDate: Mon, 20 Mar 2017 15:38:17 +1300\r\nFrom: <leo@cumulo9.com>\r\nTo: leo@cumulo9.com\r\nContent-Type: text/plain; charset=UTF-8\r\nContent-Transfer-Encoding: 7bit\r\n\r\nhelloleo\r\n.
我唯一能想到的就是body hash code一定有错误。
public string SignBody(string body)
{
var cb = body + "\r\n";
IPrivateKeySigner _privateKeySigner = new MailPost.DKIM.PrivateKeySigner(PrivateKey);
byte[] defaultEncoding = Encoding.UTF8.GetBytes(cb);
byte[] hash = _privateKeySigner.Sign(defaultEncoding, SigningAlgorithm.RSASha1);
string bodyHash = Convert.ToBase64String(hash);
return bodyHash;
}
“PrivateKeySigner”类中的函数:
public byte[] Sign(byte[] data, SigningAlgorithm algorithm)
{
if (data == null)
{
throw new ArgumentNullException("data");
}
using (var rsa = OpenSslKey.DecodeRSAPrivateKey(m_key))
{
byte[] signature = rsa.SignData(data, GetHashName(algorithm));
return signature;
}
}
“OpenSslKey”类中的函数:
public static RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey)
{
if (privkey == null)
{
throw new ArgumentNullException("privkey");
}
byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;
// --------- Set up stream to decode the asn.1 encoded RSA private key ------
//var mem = new MemoryStream(privkey);
using (var binr = new BinaryReader(new MemoryStream(privkey))) //wrap Memory Stream with BinaryReader for easy reading
{
ushort twobytes = binr.ReadUInt16();
if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
binr.ReadByte(); //advance 1 byte
else if (twobytes == 0x8230)
binr.ReadInt16(); //advance 2 bytes
else
return null;
twobytes = binr.ReadUInt16();
if (twobytes != 0x0102) //version number
return null;
byte bt = binr.ReadByte();
if (bt != 0x00)
return null;
//------ all private key components are Integer sequences ----
int elems = GetIntegerSize(binr);
MODULUS = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
E = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
D = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
P = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
Q = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
DP = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
DQ = binr.ReadBytes(elems);
elems = GetIntegerSize(binr);
IQ = binr.ReadBytes(elems);
// ------- create RSACryptoServiceProvider instance and initialize with public key -----
var RSA = new RSACryptoServiceProvider();
var RSAparams = new RSAParameters
{
Modulus = MODULUS,
Exponent = E,
D = D,
P = P,
Q = Q,
DP = DP,
DQ = DQ,
InverseQ = IQ
};
RSA.ImportParameters(RSAparams);
return RSA;
}
}
GetIntegerSize() 的代码:
private static int GetIntegerSize([NotNull]BinaryReader binr)
{
if (binr == null)
{
throw new ArgumentNullException("binr");
}
int count;
byte bt = binr.ReadByte();
if (bt != 0x02) //expect integer
return 0;
bt = binr.ReadByte();
if (bt == 0x81)
count = binr.ReadByte(); // data size in next byte
else
if (bt == 0x82)
{
byte highbyte = binr.ReadByte();
byte lowbyte = binr.ReadByte();
byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
count = BitConverter.ToInt32(modint, 0);
}
else
{
count = bt; // we already have the data size
}
while (binr.ReadByte() == 0x00)
{ //remove high order zeros in data
count -= 1;
}
binr.BaseStream.Seek(-1, SeekOrigin.Current); //last ReadByte wasn't a removed zero, so back up a byte
return count;
}
目前我真的被这个问题困住了,不知道我做错了什么。由于您项目的性质,我无法使用其他库,例如“MimeKit”。如果您需要有关此问题的更多信息,请告诉我,我会尽力为您提供。
感谢大家帮助我。
【问题讨论】:
-
为什么不能使用 MimeKit?项目的本质是什么让你无法使用? MimeKit 是 MIT 许可的,这意味着您可以在专有软件或开源软件中使用它。没有许可费。它适用于 .NET Core。可能是什么问题?
-
我们现有的软件已经在发送电子邮件时提供了它所需要的所有功能,并且经过精心开发,可以完全按照我们的意愿行事。我不允许仅仅因为我对 DKIM 有问题而将所有这些都更改为包括 MimeKit。你能帮我解决如何实现 DKIM 而不是使用 MimeKit 的问题吗?
-
MimeKit 的设计目的是让您无需使用 MailKit 即可使用它(即您可以将它与您自己的 SMTP 库一起使用)——所以我猜您的意思是它不是由于MimeKit 的性质,而是由于 您的 项目的性质 :)
-
GetIntegerSize(BinaryReader)的代码是多少? -
我已将问题更改为包含 GetIntegerSize(BinaryReader) 函数。