This question is probably for Dave Wyatt
I built a PS module that has function that acts as SMTP server - sending only. It works fine. It has the benefit of being able to return and subsequently act based on SMTP Reply Codes, as opposed to sending an email via Send-MailMessage which a) depends on an SMTP server, and b) does not return success/failure status/details with respect to the actual communication of the recipient SMTP server.
At any rate, I’m trying to implement Domain Keys Identified Mail (DKIM). I simply have to add a number of tags to the email message header. I’m supposed to performs digital signing on the message, and add the signature information in the email message header. This is my question to you, any insight on how to sign a message, or where to look?
The message can be something like:
From: Sam Boutros
MIME-Version: 1.0
To:
X-Priority: 1
Priority: urgent
Importance: high
Date: 01/30/2015 08:18:01
Subject: IOPS test 8
Content-Type: text/html; charset=us-ascii
Message-ID:
I’m not sure how soon I would have time to review that standard. However, I can offer a few observations from what I’ve seen so far:
The .NET Framework crypto libraries are not going to be much help to you at the moment, because they all work with Certificates rather than simple key pairs. You’ll have a much easier time if you use a respected third-party crypto library; perhaps BouncyCastle. Here’s an example of importing those key files with BouncyCastle: encryption - Read RSA PrivateKey in C# and Bouncy Castle - Stack Overflow
That aside, all that should be left is figuring out exactly what to hash, which algorithms to use, and how to create your DKIM-Signature header.
I haven’t read through all of the standard yet, but based on some educated guesswork of your example header: looks like the header contains the algorithm, so you can use whatever you like. In your example header, I suspect that the “bh=” portion is a SHA256 hash of the message body, and “b=” is the RSA signature of that hash. The c,q,d, and possible s portions of the header probably refer to the DNS query that is needed in order to download the public key that can be used to verify the signature.
I suppose my next step is to create and use objects with New-Object but I’m having hard time identifying the object types I need to use based on the C# examples above. I have not used C# before.
I played around with it a bit. Here’s some basic code to load up an OpenSSH private RSA key file and use it to sign something. (In this case, I’m signing the byte array 1…32, but you’d probably be using it to sign the hash of your message body or something.)
For giggles, I also included some code to verify the signature, though you may not necessarily care about that part in your project.
As for computing the hash of a string, I’d just stick with the .NET framework classes for that, as they seem to involve a lot fewer steps than the BouncyCastle classes. For example:
$string = 'I am a string.'
$bytes = [System.Text.Encoding]::UTF8.GetBytes($string)
$sha = New-Object System.Security.Cryptography.SHA256CryptoServiceProvider
$hash = $sha.ComputeHash($bytes)
For the heck of it, I started researching how to make this work without Bouncy Castle. Turns out that the CryptoAPI already has the ability to import DER-encoded key files via the CryptDecodeObject function, and you can tell an RsaCryptoServiceProvider object to use that key info.
However, this is extremely limited. It doesn’t handle password-protected private key files, and writing the code to read those headers and decrypt the file first would be more work, so I’d still use Bouncy Castle in practice. I was just curious if I could get it working.