For our DPM website, we used @stw's solution, instead of @Renaissance's, because Renaissance's requires the latest AuthorizeNet PHP library, which requires PHP version 5.6, which would require re-writing our entire website.
In step 1, stw's solution calls the PHP function base_convert, which did not work for us. Both hex2bin and pack worked. We used pack because hex2bin isn't available in our version of PHP.
Note that @stw's solution will fail in "2-3 months" because AuthorizeNet plans to stop sending the MD5 Hash in the API response:
https://support.authorize.net/s/article/MD5-Hash-End-of-Life-Signature-Key-Replacement
So we don't do this part of @stw's solution:
$response = new AuthorizeNetSIM($apiLoginID, $md5Setting);
Instead, we simply check if the transaction was approved, x_response_code === '1'.
Unfortunately, this exposes us to the risk of an imposter posing as AuthorizeNet.
So, to make the site a little harder to hack, we added a our own hash to an HTML hidden field, and check the value when it comes back in the AuthorizeNet API response. So while we can't be sure the response came from AuthorizeNet, we'll know if the custom hash came from our server.