cancel
Showing results for 
Search instead for 
Did you mean: 

Working php hash verification

**If you find this helpful please kudo this post. This has consumed a huge chunk of my day and you will help me build credibility for when I enroll in the authorize.net certified developer program. **

 

Here is 100% tested, working php hash verification code for the php SDK. I believe this will also work with SIM/AIM, etc.

 

You need the following to have an apples to apples setup with what I used:

 

1: The most recent php SDK package from GitHub. I downloaded this today and installed. I believe it is a few days old.

 

2: If you have not generated a signature key from your production or sandbox merchant interface to use for testing, do so. You won’t get the hash in the response without it. Generate it and copy it for use in this script.

 

3: An API call script for some payment transaction that returns the hash. With the SDK I am getting this for voidTransaction, refundTransaction, capture, etc. I believe that any payment function that directly charges or affects a transaction will contain this. The Accept Hosted form API call obviously does not.

 

For requirement 1, the SIM/DPM, etc. users do not have this, if my understanding is correct. You should be able to use this as well, only substituting my method for extracting the transHashSha2 value from the response with however you accomplish this using your integration. You may also have to use different parameters in your delimited string, I would try this method first, but I have seen other developers posting attempts with more fields in the string than login, transId, and amount, and there is probably a good reason for this. 

 

 

Here is the code (p.s. do not follow the hyperlink to the C# byte array description and try to implement a php equivalent to the C# byte array script. This makes things 100X harder than they have to be, as I know well at this point. Without further delay…..)

 

 

$login = "copy and paste your merchant login id here";
$signatureKey ="copy and paste your signature key here";
$signatureKey = hex2bin($signatureKey);
$amount = $amount;

//$response stands for the response object returned by your API call
//e.g.  $response = refundTransaction($refTransId,$amount,$lastFour);

$transId = $response->getTransactionResponse()->getTransId();
$string = '^'.$login.'^'.$transId.'^'.$amount.'^';


$hash = $response->getTransactionResponse()->getTransHashSha2();
$digest = strtoupper(HASH_HMAC('sha512',$string,$signatureKey));

if(hash_equals ($digest,$hash)){

    //This if statement is the verification piece 
    //Put whatever you want your app to do with the transaction here
    //to test you can do something like echo "Hash verification validated";
    //or try this:
    //$dump = print_r($string,true);
    //$fp = file_put_contents( 'transhash.log', $dump );
    //and if your directory populates with a file named transhash.log you know 
    //verification succeeded
    

}

 

Renaissance
All Star
67 REPLIES 67

Hi *,

 

I try anything I could imagine, but no success yet. Just can not get the right SHA512 hash... After the calculations I always get a string with length 32 chars, but the x_SHA2_Hash is 128 chars long... What I am missing? Is there any working soluton for PHP?

What you need to find out is what integration method you are using. That will help determine which string you use. If your hash function is only outputting 32 characters you are probably using the wrong function. But first determine your integration method. I have code that is tested an works for AIM/API verification, and also code for DPM/SIM verification. Others have posted the DPM/SIM fingerprint solution, which involves 30 fields encapsulated in carets.

Thanks a lot about the answer!

 

I try both methods, mentioned by you, and both use the "hash_hmac('sha256', ..., ...)" PHP function, that returns 64 chars (my fault above, seems was too sleepy...), while the provided "x_SHA2_Hash" POST argument is 128 chars long. And they never will be equal strings. That's my problem now...

 

You’re welcome my friend,

I think you read my post too fast. It’s not sha256 it’s sha512. You use AIM or SIM or DPM? Plugging sha512 will fix your problem with the string being too short.

https://developer.authorize.net/api/reference/index.html#payment-transactions-charge-a-customer-prof...

 

This api live console return empty,is there anyone has the same problem?

 

{
    "transactionResponse": {
        "responseCode": "1",
        "authCode": "WSD94V",
        "avsResultCode": "Y",
        "cvvResultCode": "P",
        "cavvResultCode": "2",
        "transId": "40025175521",
        "refTransID": "",
        "transHash": "82E60A2E49E34891C4DA3408D0A6832E",
        "testRequest": "0",
        "accountNumber": "XXXX1111",
        "accountType": "Visa",
        "messages": [
            {
                "code": "1",
                "description": "This transaction has been approved."
            }
        ],
        "transHashSha2": "",
        "profile": {
            "customerProfileId": "1506424532",
            "customerPaymentProfileId": "1505770522"
        },
        "SupplementalDataQualificationIndicator": 0
    },
    "refId": "123456",
    "messages": {
        "resultCode": "Ok",
        "message": [
            {
                "code": "I00001",
                "text": "Successful."
            }
        ]
    }
}

 

bfp3
Member

@Renaissance Thank you for helping out here. 

I have tried implementing your example using the latest PHP SDK from Github, and my hashes are not matching up. Here's my example code. Am I missing something?

 

<?php
// Include the Authorize.net PHP SDK from https://github.com/AuthorizeNet/sdk-php
require_once '../../vendor/autoload.php';
use net\authorize\api\contract\v1 as AnetAPI;
use net\authorize\api\controller as AnetController;

$amount = '10';
$my_api_key = 'your api key here';
$my_transaction_key = 'your transaction key here';
$my_signature_key = 'your signature key here';

/* Create a merchantAuthenticationType object with authentication details
	 retrieved from the constants file */
$merchantAuthentication = new AnetAPI\MerchantAuthenticationType();
$merchantAuthentication->setName( $my_api_key );
$merchantAuthentication->setTransactionKey( $my_transaction_key );

// Set the transaction's refId
$refId = 'ref' . time();

// Create the payment data for a credit card
$creditCard = new AnetAPI\CreditCardType();
$creditCard->setCardNumber( '4242424242424242' );
$creditCard->setExpirationDate( '12/34' );
$creditCard->setCardCode( '123' );

// Add the payment data to a paymentType object
$newPayment = new AnetAPI\PaymentType();
$newPayment->setCreditCard($creditCard);

// Create order information
$order = new AnetAPI\OrderType();
$order->setDescription( 'My description' );

// Set the customer's Bill To address
$customerAddress = new AnetAPI\CustomerAddressType();
$customerAddress->setFirstName( 'MyFirstName' );
$customerAddress->setLastName( 'MyLastName' );
$customerAddress->setAddress( '123 Fake Street' );
$customerAddress->setCity( 'New York' );
$customerAddress->setState( 'New York' );
$customerAddress->setZip( '10001' );
$customerAddress->setCountry( 'United States' );

// This is Authorize.net's version of an Idempotency Key. It prevents the same purchase data within X seconds
$duplicateWindowSetting = new AnetAPI\SettingType();
$duplicateWindowSetting->setSettingName("duplicateWindow");
$duplicateWindowSetting->setSettingValue("10");

// Set the customer's identifying information
$customerData = new AnetAPI\CustomerDataType();
$customerData->setType( "individual" );
$customerData->setId( '1' );
$customerData->setEmail( 'user@example.com' );

// Create a TransactionRequestType object and add the previous objects to it
$transactionRequestType = new AnetAPI\TransactionRequestType();
$transactionRequestType->setTransactionType("authCaptureTransaction");
$transactionRequestType->setAmount( $amount );
$transactionRequestType->setOrder( $order );
$transactionRequestType->setPayment( $newPayment );
$transactionRequestType->setBillTo( $customerAddress );
$transactionRequestType->setCustomer( $customerData );
$transactionRequestType->addToTransactionSettings( $duplicateWindowSetting );

// Assemble the complete transaction request
$request = new AnetAPI\CreateTransactionRequest();
$request->setMerchantAuthentication( $merchantAuthentication );
$request->setRefId( $refId );
$request->setTransactionRequest( $transactionRequestType );

// Create the controller and get the response
$controller = new AnetController\CreateTransactionController( $request );
$response = $controller->executeWithApiResponse( \net\authorize\api\constants\ANetEnvironment::SANDBOX );

// Check to see if the API request was successfully received and acted upon
if ( $response->getMessages()->getResultCode() == "Ok" ) {
	// Since the API request was successful, look for a transaction response
	// and parse it to display the results of authorizing the card
	$tresponse = $response->getTransactionResponse();

	// If the transaction was successful
	if ( $tresponse != null && $tresponse->getMessages() != null ) {

		// Ge the hash returned from Authorize.net
		$authorize_hash = $tresponse->getTransHashSha2();

		// Generate the hash that attempts to match it
		$string = '^' . $my_api_key . '^' . $tresponse->getTransId() . '^' . $amount . '^';
		$key = hex2bin( $my_signature_key );
		$my_hash = strtoupper( HASH_HMAC( 'sha512', $string, $key ) );

		if( hash_equals ( $authorize_hash, $my_hash ) ) {
			echo '<p>Hashes Match</p>';
		} else {
			echo '<p>Hashes DO NOT Match</p>';
		}

		echo '<p>Authorize.net Hash: ' . $authorize_hash . '</p>';
		echo '<p>My Hash: ' . $my_hash . '</p>';

	}
}
eddphil1
Member

Your $amount needs to be a decimal value. Try putting it in as either 10.00 or "10.00"; Sometimes the string vs number makes a difference, sometimes not. You will never get a match without 2 decimal places. 

That was it! I added 2 decimal places and the hashes match now. You're awesome thank you. 

Thanks! My fault...

We're using Magento Open Source Version 2.2.6; PHP version 7x, using the Direct Post Method.

 

Do the recommendations for the fix in this forum thread apply to the above mentioned versions?

 

When we researched a fix for this issue, we also found this extension

https://marketplace.magento.com/authorizenet-magento-module-authorizenet.html, which is from authorize.net.

 

Not sure how stable this extension is, like is this extension going to be deprecated or updated? And will it work for Magento version 2.2.6? Internally which method or API is used by this extension for authorize.net? Has anyone used this extension? Thanks--

wenabar16
Member