cancel
Showing results for 
Search instead for 
Did you mean: 

SHA-512 in Perl

Our authorize.net processing is done in some OLD perl cgi code - any perl programmers out there?

 

We are trying to convert to the SHA-512 hashing.  Our current processing uses MD5, via the perl module Digest::MD5.

I use LWP::UserAgent to POST directly to the secure.authorize.net gateway transact dll URL.

What I get returned is an array of values. The MD5 hash is currently in the 38th array element. Authorize.net has been unable to tell me where I can find the returned SHA-512 hash value to compare to what I am generating in the program.

 

For my test:

I changed it to use Digest::SHA for the hashing. I generated the signature key and have it stored in hex in our database.  

 

 

my $sha512_string = '^' . $auth_net_login_id . '^' . $tranid . '^' . $grandtotal . '^';


my $key = pack 'H*', $sig_key;  ##to convert the store hex value to binary - as recommended here


my $sha512 = Digest::SHA->new;
my $sent_sha512_hash = $sha512->hmac_sha512($sha512_string, $key);

 

When I display that value, it just shows a bunch of weird characters on the screen - I don't know if that's expected or not. I am only displaying it to compare to what comes from authorize.net.

 

When the values are returned from Authorize.net (in the array), I display all the elements. There is a value in element 68 that looks like a hex value but that isn't what is in the hash that I generated.

 

So, isn't the hash returned from Authorize.net in the array? If not, then how do I obtain it using the methods we currently have in place? I don't consider this as using the API.   Or is the problem that I am hashing it wrong on my end?

 

I obtained the perl code for our current processing via Authorize.net MANY years ago from one of their perl customers. It has worked fine ever since. I do not have the knowledge, experience or brain power to change the whole process, unless someone could provide all the perl code (I know that's asking a lot). I also have a general knowlege of php but unfortunately the examples on this forum are too different from our perl process to be able to correlate the two.

 

I hope someone can help!   Thanks in advance!

 

smorrow123
Contributor
76 REPLIES 76

@jgoebel

I see that you DID have a link to the AIM documentation with the order of the reply - SORRY about that!! Other documentation DOES say you can't count on the order staying static, but it looks like it is in this case - so I'll go with it. It matches what I am using in the script (response code in 0 element, etc.). This looks much more like it - and I am grateful for the assistance and the link. I

have NO documentation from the Authorize.net implementation - so I had no idea where to start.

 

Now I just noticed that the chart for the "Order of API fields in the response" for calculating the hash are using some fields from the returned data, and some from the originating data, as was suggested by @Renaissance - so now that I have this, I will work on that premise.

 

Thanks again! I'll post again if I ever get it to actually work!

 

 

 

As far as I remember when using AIM the order of response fields never changes - they have added fields, but to the end of the string, so the order doesn't change.

 

The warning about field order changes only applies to the APIs which return name value pairs, DPM and SIM if I remember correctly.

 

Yes, the hash will use some fields from the originating data. It would be pointless if it didn't use some data not in the response and know only to you and authorize.net.

 

If you are using AIM, I'm not sure why you need the hash at all. Authorize.net says the hash is " Optional. Transaction responses are returned using SSL/ TLS, so this field is useful mainly as a redundant security check." As others have pointed out if you are using AIM you have other security issues to consider.

 

 

@Renaissance

The order on the SIM method appears to be a little different from the order of the AIM. But I DO have that order now, and I'll work with the AIM documentation. Thanks!

I know that you were trying to help me extract the fields from different places, but I kept trying to do it by field name and that's why all the scrambling. I am finally ready to cry uncle and stick with the various values now that I have the correct order.

 

I have one question, though, on the documentation (using the SIM developer Guide) on the HMAC SHA-512 Hash feature, it lists the second element in the hash calculation to be "x_test_request". I'm currently working on a test version of the script until I can get this working, so I DO send x_test_request in the original POST to Authorize.net with a value "TRUE". The live/production version of the script, however, doesn't even USE that field in the original POST to Authorize.net. It doesn't send a "TRUE" OR "FALSE" - doesn't send it at all. SO, if the HMAC SHA-512 Hash feature says to include x_test_request as the second value in the hash calculation (according to the chart on pg 73), so do I include it in the test script but NOT on the production version? Or do I include a value of "FALSE" in the live/production version when calculating the hash?

 

They include a sample (in the HMAC SHA-512 documentation) that DOES show FALSE in the string but this was originally from the SIM method documentation, and I'm concerned there could be a difference - since like I said, I don't send x_test_request at ALL in the production version;  I send x_test_request='TRUE' in the test version. That has me a little baffled. All my testing has to be in this test script so as to not impact customers. So, I need to know that the hashing will work the same in the live version!

 

 

@smorrow123 

 

The disclaimer about not counting on the fields to be in the same order has the qualifier "Future updates to the API may cause your code to not work if you rely on the order" in roughly those words.

 

What I take that to mean is that the fields will be in the same order consistently, until an update is made to the API. And since the API for AIM/DPM/SIM is only going to be updated for critical security updates, you probably will get an email like this.  I would take a guess that you can leave this alone for 2 to 3 years after it works, unless some crack in the sha2 algorithm is found. sha3 will probably be the standard in a couple of years and there will be a notice somewhere I would imagine. I think most people here got an email on this one. 

Regarding x_test_request, I think you would leave that out but can't say for sure. If you leave it out totally, you will have another pipe bar in place of where the test mode is. So if you're processing a pipe bar delimited array, the order could change. I may post an example of how to extract the values you need later. I'm not the sharpest in Perl and have never used it, but programming is programming and you could alter what I post to tweak the syntax and make it

syntactically correct.

 

If I were you my process would be something like this-

 

-get it working in test mode

-run a test transaction will your personal details and print the response

-run a live transaction also with your personal details, and do so for an amount of 1 penny and charge it to your card. Print that response too.

 

That will give you a side by side to see how the live string differs from the test string.  

 

 

And read this- I don't think you understand what I am saying in the previous post. This exercise you are going through of getting the exact order of the values as they are returned in AIM is already done in my post from a few days ago. I will post it again below this.

 

Whatever you are using, AIM/SIM/DPM, I took your specific string that you posted. That is the order that YOUR response comes in, and for the purposes of this validation you don't even have to know what method it is.

 

And I would highly encourage you to read my post about PCI. If you are in fact using AIM then you have such an enormous compliance burden, and you may not have been notified of this by anyone. 

 

The PCI requires you to do the things in their guide, and if your business was ever under the microscope you would be in very hot water in the case you are not doing them.  Go to the PCI document library and get the PCI compliance self questionaire for PCI SAQ D scope. All of the things in that document are what you are supposed to be doing if you are in fact using AIM. Again, not trying to get in your business but just trying to help you. 

@smorrow123 

What is below is YOUR string as returned by the API. It is in the exact order that it is returned because I copied it directly from you.

 

1|1|1|(TESTMODE) This transaction has been approved.|000000|P|0|8478||39.00|CC|auth_capture|10001253|

 

I think the first set of three 1’s is the response code and response reason code. (TESTMODE)  is x_test_request. Then we have response reason text, x_auth_code, x_avs_code, x_trans_id, x_invoice_num, a | representing the empty description field, then x_amount, x_method, x_type

 

The 10001253 maybe you have an idea of. It could be numerous things. Maybe customer Id. * or

x_customer_id if you use what your API calls it.

 

|Sharon|Shatest||123 Somewhere Street|Anywhere|PA|19666|US|||sharon.shatest@test.com

 

This is all self-explanatory. Name, address and email. * AKA x_first_name, x_last_name  etc. if you use what the API calls them. The | after sharons last name is the empty company field.

  

||||||||||||||5E3E841F808768EA1E68EB5800CD0A48|||||||||||||XXXX0002|American Express|||||||||||||||||422E3EF8AA729B89FC102825EA9FEE6DCCB701D861B4248CF24C12600AB1EAF04371257B7163091AFCD883D57C3F9B83424717C7317BCFD90392CE33E87BFCE2

 

Here is md5 hash, x_account_number, and x_card_type, followed by the sha512 hash value. *AKA 

x_sha2_hash, if you use what the API calls it

 

Of these you need the values of x_trans_id,  x_respone_code, x_auth_code, x_sha_512, and x_method (maybe on x_method, you can probably pass this in your call too)  **this is what I mean. If you pass x_method in your API call, then you need a total of 4 values from this array, and the rest can be canned.

 

In regards to the order, the order will change in the near term future when they remove the md5 hash, but if you create your arrays the way I would suggest doing, it won't affect you.

 

 

****EDIT: The above is a breakdown of this, which you posted on 1/21/2019 at 6:31 my time:

1|1|1|(TESTMODE) This transaction has been approved.|000000|P|0|8478||39.00|CC|auth_capture|10001253|Sharon|Shatest||123 Somewhere Street|Anywhere|PA|19666|US|||sharon.shatest@test.com||||||||||||||5E3E841F808768EA1E68EB5800CD0A48|||||||||||||XXXX0002|American Express|||||||||||||||||422E3EF8AA729B89FC102825EA9FEE6DCCB701D861B4248CF24C12600AB1EAF04371257B7163091AFCD883D57C3F9B83424717C7317BCFD90392CE33E87BFCE2

 

 

It is a breakdown line by line. Your work has already been done for you, with the exception of tying down what the 10001253 is. 

@Renaissance

Sorry I missed reviewing your prior post with the final breakdown. I've been getting a lot of different responses, and I'm never sure what I've looked at and what I haven't.

 

The issue with running a charge with the live/production version and printing the results that come back - that can't be done in our environment. If I put the code in place in the live version, it will process for all customers who pay with a credit card on our system. I can't "shut them out" and we are a 24x7 online operation (of course).  That's why all the testing is done in a separate script that they don't access. I can't execute a live version of the script other than what the "public" is using so I don't want to put any test code in there for displaying, etc. Yes, I could create a separate program that would run "live" and JUST do this part of the processing from the script, but that would take longer than the time I have to finish this because the data is so dependent on prior scripts.

 

So, I guess I'll go with putting the TEST request in there for both live (FALSE) and test (TRUE) versions of the script and go from there.

 

I really do appreciate the time you've spent helping me with this - and sorry I haven't followed everything you've posted. I have been investigating and testing with suggestions from others, and by the time I finish and find that didn't work, I've got 3 more suggestions and am falling behind. BUT I DO appreciate it, and I will continue to plug along to the best of my ability.

 

 

@jgoebel I understand what you and @Renaissance are saying about security issues, but they are currently PCI compliant, so I'm not going to worry about it.   I'm retiring in another week, and I'm sure my employers would love to hire someone to implement a better/secure/compliant method, but it would need to be incorporated into the existing perl/cgi script. Any takers? I'll pass along names of anyone interested.

 

Now, since you are a perl programmer, I have what might be a dumb question due to my extreme "rustiness" - but I just can't figure it out after delving into my perl books:

It is currently creating the original POST request to Authorize.net this way :

 

my $request_values =
 {
 x_test_request  => "TRUE",
 x_login    => $auth_net_login_id,
 x_tran_key   => $auth_net_tran_key,
 x_version   => "3.1",

.....

};

 

And I POST it to authorize.net as a string. No problem.

Then later in the code I try to access an individual value as $request_values{x_login} because I thought this was creating a hash-array.

I'm getting compilation errors that says I have not defined %request_values. So, I'm thinking that maybe this isn't really a hash array.

How would I code it to extract the value in x_login (for an example) to use in the SHA calculation? Yes, I know I could just repeat how I got the value in the first place - like use $auth_net_login_id but by using the x fields, it becomes more self-documenting.

 

 

 

 

@smorrow123

 

In regards to this- 

 

"I'm retiring in another week, and I'm sure my employers would love to hire someone to implement a better/secure/compliant method, but it would need to be incorporated into the existing perl/cgi script. Any takers? I'll pass along names of anyone interested."

 

I sent you a message.

 

In regards to "they are currently PCI compliant" that is great. I just get skeptical when I hear of smaller merchants doing AIM or modern API on a non-hosted form and having issues like this. Depending on the size of your business, the vulnerability scans and pen testing alone are going to cost probably $16,000 per year at minimum, quite likely much higher. And that is just 2 of the list of requirements that runs dozens of pages. The scans and pen testing have to be done by people with special training to be valid. The remaining requirements are satisified by internal procedures, but add up and someone has to be paid to do them. 

 

But that's not your bone to pick. I'm sure that retirement is sounding better and better with each day you dig into this exercise. 

 

 

$request_values is a hash reference. To access you need to dereference. 

$request_values->{x_login}