I have a very old and large php (5.3) site that uses A.Net SIM and Relay Response for CC processing. I have managed to update the code which submits the transaction to A.Net and transactions are successfully occuring. The problem is my code in the Relay Response URL which pulls the A.Net response and parses it so that the correct processing can occur.
I last worked on my A.Net integration 6 years ago, and my Relay reponse logic starts with the following call which is obviously no longer working.
$response = new AuthorizeNetSIM($api_login_id, $md5_setting);
The AuthorizeNetSIM class is contained in the A.Net SDK from that time which is stored on my webserver. Where do I find a replacement for this code? Or if there is no simple replacement using SHA-512, what do I use instead to receive the response so I can parse it to determine the necessary logic? Note that if I attempt to upgrade to Php 5.6 or higher, my entire site stops working. Thus, I am constrained since I do not have time to upgrade my entire site to a newer php before md5 ends and my organization's credit card processing comes crashing down.
Any assistance would be greatly appreciated.
Solved! Go to Solution.
06-23-2019 11:43 AM
I sent you an IM. Does your class file have code in it that looks like this-
class AuthorizeNetSIM extends AuthorizeNetResponse { // For ARB transactions public $subscription_id; public $subscription_paynum; /** * Constructor. * * @param string $api_login_id * @param string $md5_setting For verifying an Authorize.Net message. */ public function __construct($api_login_id = false, $md5_setting = false) { $this->api_login_id = ($api_login_id ? $api_login_id : (defined('AUTHORIZENET_API_LOGIN_ID') ? AUTHORIZENET_API_LOGIN_ID : "")); $this->md5_setting = ($md5_setting ? $md5_setting : (defined('AUTHORIZENET_MD5_SETTING') ? AUTHORIZENET_MD5_SETTING : "")); $this->response = $_POST; // Set fields without x_ prefix foreach ($_POST as $key => $value) { $name = substr($key, 2); $this->$name = $value; } // Set some human readable fields $map = array( 'invoice_number' => 'x_invoice_num', 'transaction_type' => 'x_type', 'zip_code' => 'x_zip', 'email_address' => 'x_email', 'ship_to_zip_code' => 'x_ship_to_zip', 'account_number' => 'x_account_number', 'avs_response' => 'x_avs_code', 'authorization_code' => 'x_auth_code', 'transaction_id' => 'x_trans_id', 'customer_id' => 'x_cust_id', 'md5_hash' => 'x_MD5_Hash', 'card_code_response' => 'x_cvv2_resp_code', 'cavv_response' => 'x_cavv_response', ); foreach ($map as $key => $value) { $this->$key = (isset($_POST[$value]) ? $_POST[$value] : ""); } $this->approved = ($this->response_code == self::APPROVED); $this->declined = ($this->response_code == self::DECLINED); $this->error = ($this->response_code == self::ERROR); $this->held = ($this->response_code == self::HELD); } /** * Verify the request is AuthorizeNet. * * @return bool */ public function isAuthorizeNet() { return count($_POST) && $this->md5_hash && ($this->generateHash() == $this->md5_hash); } /** * Generates an Md5 hash to compare against Authorize.Net's. * * @return string Hash */ public function generateHash() { $amount = ($this->amount ? $this->amount : "0.00"); return strtoupper(md5($this->md5_setting . $this->api_login_id . $this->transaction_id . $amount)); } }
If so, change the above code to this-
class AuthorizeNetSIM extends AuthorizeNetResponse { // For ARB transactions public $subscription_id; public $subscription_paynum; /** * Constructor. */ public function __construct($signatureKey) { $this->signatureKey = hex2bin($signatureKey); $this->response = $_POST; // Set fields without x_ prefix foreach ($_POST as $key => $value) { $name = substr($key, 2); $this->$name = $value; } // Set some human readable fields $map = array( 'invoice_number' => 'x_invoice_num', 'transaction_type' => 'x_type', 'zip_code' => 'x_zip', 'email_address' => 'x_email', 'ship_to_zip_code' => 'x_ship_to_zip', 'account_number' => 'x_account_number', 'avs_response' => 'x_avs_code', 'authorization_code' => 'x_auth_code', 'transaction_id' => 'x_trans_id', 'customer_id' => 'x_cust_id', 'md5_hash' => 'x_MD5_Hash', 'card_code_response' => 'x_cvv2_resp_code', 'cavv_response' => 'x_cavv_response', 'sha512_hash'=>'x_SHA2_Hash', ); foreach ($map as $key => $value) { $this->$key = (isset($_POST[$value]) ? $_POST[$value] : ""); } $this->approved = ($this->response_code == self::APPROVED); $this->declined = ($this->response_code == self::DECLINED); $this->error = ($this->response_code == self::ERROR); $this->held = ($this->response_code == self::HELD); } /** * Verify the request is AuthorizeNet. * * @return bool */ public function isAuthorizeNet() { return count($_POST) && $this->sha512_hash && ($this->generateHash() == $this->sha512_hash); } /** * Generates a sha512 hash to compare against Authorize.Net's. * * @return string Hash */ public function generateHash() { $string = "^"; $fields = array( 'x_trans_id'=>'', 'x_test_request'=>'', 'x_response_code'=>'', 'x_auth_code'=>'', 'x_cvv2_resp_code'=>'', 'x_cavv_response'=>'', 'x_avs_code'=>'', 'x_method'=>'', 'x_account_number'=>'', 'x_amount'=>'', 'x_company'=>'', 'x_first_name'=>'', 'x_last_name'=>'', 'x_address'=>'', 'x_city'=>'', 'x_state'=>'', 'x_zip'=>'', 'x_country'=>'', 'x_phone'=>'', 'x_fax'=>'', 'x_email'=>'', 'x_ship_to_company'=>'', 'x_ship_to_first_name'=>'', 'x_ship_to_last_name'=>'', 'x_ship_to_address'=>'', 'x_ship_to_city'=>'', 'x_ship_to_state'=>'', 'x_ship_to_zip'=>'', 'x_ship_to_country'=>'', 'x_invoice_num'=>''); foreach($fields as $key => $value){ $string .= $_POST[$key] .='^'; } return strtoupper(HASH_HMAC('sha512',$string,$this->signatureKey)); } }
Then change your response var as below-
this: $response = new AuthorizeNetSIM($api_login_id, $md5_setting); needs to be replaced with: $response = new AuthorizeNetSim($signatureKey);
where $signatureKey is the signature key you get
from the merchant interface
And if it works, please kindly mark this thread as solved.
06-24-2019 06:41 PM
06-24-2019 08:53 AM
I sent you an IM. Does your class file have code in it that looks like this-
class AuthorizeNetSIM extends AuthorizeNetResponse { // For ARB transactions public $subscription_id; public $subscription_paynum; /** * Constructor. * * @param string $api_login_id * @param string $md5_setting For verifying an Authorize.Net message. */ public function __construct($api_login_id = false, $md5_setting = false) { $this->api_login_id = ($api_login_id ? $api_login_id : (defined('AUTHORIZENET_API_LOGIN_ID') ? AUTHORIZENET_API_LOGIN_ID : "")); $this->md5_setting = ($md5_setting ? $md5_setting : (defined('AUTHORIZENET_MD5_SETTING') ? AUTHORIZENET_MD5_SETTING : "")); $this->response = $_POST; // Set fields without x_ prefix foreach ($_POST as $key => $value) { $name = substr($key, 2); $this->$name = $value; } // Set some human readable fields $map = array( 'invoice_number' => 'x_invoice_num', 'transaction_type' => 'x_type', 'zip_code' => 'x_zip', 'email_address' => 'x_email', 'ship_to_zip_code' => 'x_ship_to_zip', 'account_number' => 'x_account_number', 'avs_response' => 'x_avs_code', 'authorization_code' => 'x_auth_code', 'transaction_id' => 'x_trans_id', 'customer_id' => 'x_cust_id', 'md5_hash' => 'x_MD5_Hash', 'card_code_response' => 'x_cvv2_resp_code', 'cavv_response' => 'x_cavv_response', ); foreach ($map as $key => $value) { $this->$key = (isset($_POST[$value]) ? $_POST[$value] : ""); } $this->approved = ($this->response_code == self::APPROVED); $this->declined = ($this->response_code == self::DECLINED); $this->error = ($this->response_code == self::ERROR); $this->held = ($this->response_code == self::HELD); } /** * Verify the request is AuthorizeNet. * * @return bool */ public function isAuthorizeNet() { return count($_POST) && $this->md5_hash && ($this->generateHash() == $this->md5_hash); } /** * Generates an Md5 hash to compare against Authorize.Net's. * * @return string Hash */ public function generateHash() { $amount = ($this->amount ? $this->amount : "0.00"); return strtoupper(md5($this->md5_setting . $this->api_login_id . $this->transaction_id . $amount)); } }
If so, change the above code to this-
class AuthorizeNetSIM extends AuthorizeNetResponse { // For ARB transactions public $subscription_id; public $subscription_paynum; /** * Constructor. */ public function __construct($signatureKey) { $this->signatureKey = hex2bin($signatureKey); $this->response = $_POST; // Set fields without x_ prefix foreach ($_POST as $key => $value) { $name = substr($key, 2); $this->$name = $value; } // Set some human readable fields $map = array( 'invoice_number' => 'x_invoice_num', 'transaction_type' => 'x_type', 'zip_code' => 'x_zip', 'email_address' => 'x_email', 'ship_to_zip_code' => 'x_ship_to_zip', 'account_number' => 'x_account_number', 'avs_response' => 'x_avs_code', 'authorization_code' => 'x_auth_code', 'transaction_id' => 'x_trans_id', 'customer_id' => 'x_cust_id', 'md5_hash' => 'x_MD5_Hash', 'card_code_response' => 'x_cvv2_resp_code', 'cavv_response' => 'x_cavv_response', 'sha512_hash'=>'x_SHA2_Hash', ); foreach ($map as $key => $value) { $this->$key = (isset($_POST[$value]) ? $_POST[$value] : ""); } $this->approved = ($this->response_code == self::APPROVED); $this->declined = ($this->response_code == self::DECLINED); $this->error = ($this->response_code == self::ERROR); $this->held = ($this->response_code == self::HELD); } /** * Verify the request is AuthorizeNet. * * @return bool */ public function isAuthorizeNet() { return count($_POST) && $this->sha512_hash && ($this->generateHash() == $this->sha512_hash); } /** * Generates a sha512 hash to compare against Authorize.Net's. * * @return string Hash */ public function generateHash() { $string = "^"; $fields = array( 'x_trans_id'=>'', 'x_test_request'=>'', 'x_response_code'=>'', 'x_auth_code'=>'', 'x_cvv2_resp_code'=>'', 'x_cavv_response'=>'', 'x_avs_code'=>'', 'x_method'=>'', 'x_account_number'=>'', 'x_amount'=>'', 'x_company'=>'', 'x_first_name'=>'', 'x_last_name'=>'', 'x_address'=>'', 'x_city'=>'', 'x_state'=>'', 'x_zip'=>'', 'x_country'=>'', 'x_phone'=>'', 'x_fax'=>'', 'x_email'=>'', 'x_ship_to_company'=>'', 'x_ship_to_first_name'=>'', 'x_ship_to_last_name'=>'', 'x_ship_to_address'=>'', 'x_ship_to_city'=>'', 'x_ship_to_state'=>'', 'x_ship_to_zip'=>'', 'x_ship_to_country'=>'', 'x_invoice_num'=>''); foreach($fields as $key => $value){ $string .= $_POST[$key] .='^'; } return strtoupper(HASH_HMAC('sha512',$string,$this->signatureKey)); } }
Then change your response var as below-
this: $response = new AuthorizeNetSIM($api_login_id, $md5_setting); needs to be replaced with: $response = new AuthorizeNetSim($signatureKey);
where $signatureKey is the signature key you get
from the merchant interface
And if it works, please kindly mark this thread as solved.
06-24-2019 06:41 PM
That works perfectly! Thank you so much! You saved me hours upon hours of work.
06-25-2019 04:08 PM
I tried using this but the function hex2bin does not return the binary value correctly. I also tried alternate methods to convert to binary (http://phprevolution.blogspot.com/2012/06/convert-hexadecimal-to-binary-string-in.html). That converts to binary but still the SHA values do not match. Could you please let me know if I am missing something?
The only change I did to the code you have given is that I removed some keys from $fields array in generateHash() which does not have POST values
NOTE: I am doing this with an sandbox account
07-09-2019 06:24 AM - edited 07-09-2019 06:36 AM
07-09-2019 07:50 AM
Thanks. I tried it but does not generate matching SHA value. There are a lot of links related to generating the SHA value and they contradict with the values used in generating the SHA.
https://support.authorize.net/s/article/MD5-Hash-End-of-Life-Signature-Key-Replacement - Matches with what you have told but still does not generate the correct SHA
https://www.authorize.net/content/dam/authorize/documents/SIM_guide.pdf - Contains less fields (refer page 73) which I believe is old document. This too does not work.
https://github.com/AuthorizeNet/sample-code-php/blob/master/Sha512/compute_trans_hashSHA2.php and https://developer.authorize.net/support/hash_upgrade/- Completely different fields but this too does not generate matching SHA
https://community.developer.authorize.net/t5/Integration-and-Testing/Coldfusion-SIM-HMAC-SHA512-Upda... and https://support.authorize.net/s/article/Do-I-need-to-upgrade-my-transaction-fingerprint-from-HMAC-MD... - This also does not work as many of the fields like x_login,x_fp_sequence,x_fp_timestamp,x_currency_code does not come in POST
Is this because we are using SIM/DPM which is old method?
I can see the below statement in https://support.authorize.net/s/article/MD5-Hash-End-of-Life-Signature-Key-Replacement which bring me to the question if it is really needed to compare the SHA value?
"The SHA2 has field contains HMAC-SHA512 hash that Authorize.Net generated for the transaction and can be used to validate the response came from Authorize.Net but is not required to do so."
Please advise since I am completely blocked here.
I hope the behavior does not vary between LIVE and Sandbox environments
07-09-2019 10:36 PM - edited 07-09-2019 10:40 PM
07-10-2019 12:15 PM
Found the root cause of the issue. Looks like hex2bin is available only in PHP >5.4 and we were having 5.3.3. Hence had to use a alternative as given in https://www.php.net/manual/en/function.hex2bin.php#110973
It would be better if you could you please update the same in your documentation so that others who implement this check their PHP version and implement accodingly.
07-11-2019 02:01 AM