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
Can you do a print of the array as it is initially received, before any splitting or numeric values have been assigned ?
And looking at this, I think that foreach loop is nothing more than a red herring that doesn’t do anything for this script. Looks like some code that the original author had some sort of idea for using but then abandoned without deleting.

It looks like the array is being split repeatedly and then made into a numeric array. I think the original keys may be getting assigned as values in the words array.

@smorrow123

 

I agree with @Renaissance. Might try printing out $apiresponse alone.

@Renaissance @airman81

 

I agree with @Renaissance that the foreach loop in a red herring. It is basically splitting everything out into just the values in the words array --- so I can't find the field names.

 

I've displayed everything I can think of displaying, and still can't find anything with the field NAMES!

Referring to my code from previous post, I am getting this for $apiresponse:

 

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

 

This is the same information I display when I print out the @words array - just the values of the fields and nothing else. And the script currently accesses values by using the @words array, but those positions in the array (like I pull response_code from the zero element) do not match what the API fields in the HMAC SHA-512 Hash documentation in the SIM manual. Without the field names, I'm dead in the water.

 

AND when I print out the values in @responses as in:

 

my $response  = $useragent->request( $request );
my @responses  = split( /$request_values->{x_delim_char}/, $response->content );

foreach $pair(@responses)
{
   $debug .= "$pair<br>";

}

I get this (which means it is only printing one character at a time before newline - what the heck?):

1
|
1
|
1
|
(
T
E
S
T
M
O
D
E
)

T
h
i
s

t
r
a
n
s
a
c
t
i
o
n

h
a
s

b
e
e
n

a
p
p
r
o
v
e
d
.
|
0
0
0
0
0
0
|
P
|
0
|
8
4
7
8
|
|
3
9
.
0
0

............. on and on

 

There just doesn't seem to be any field names being returned. I'm at a complete loss. Maybe I can TRY to figure out what some of the returned values represent (like the name, address, etc) but some of them are codes (like the first 3 are all 1's) and I have no idea what they represent.

 

How can I get the values in the correct order for hashing if I can't access the field names? When I get a cgi response - not used here - I use $query->param('fieldname') -- would I do something similar here, and if so, what do I use instead of $query->param based on my code in the prior post?  

 

I am way out of my league here. You all have been very patient, but I'm lost.   

I'm not an LWP guy but there should be a ref that has both...

 

    print $response->decoded_content;

 

@airman81

Are you saying that maybe decoded_content would have the field names included or what would decoded_content do?

I've been digging through perl.com for LWP - but it doesn't give any examples like what I'm doing. They are only giving examples of pulling html from a URL. They pull it with ->content so I figure maybe there is another ref that would give the field names - I just can't find anything in the documentation.

I have put so much time into this, I don't know when I should give up.

 

 

@Renaissance @airman81

I decided to try to just use the returned values (without accessing by field names) exactly in the order received and hashing them. So, I started with the ^ and added each value separated by ^'s and a final ^. But just the first 30 as the documentation suggests. I hashed it (hex) along with the key (signature key that has been converted to binary with the pack statement) and sent it through.

It does NOT match the hash value they sent to me in the response. I found a large hex value in element 68 of the array, as I mentioned before, and since I can't get to their hash with a field name, I'm testing to match that element 68 value. Could be wrong - but I'm pretty sure that's it.

 

So, I apparently can't just use the returned values in the order received. Now I AM running this as a test with the Amex number 370000000000002 - I don't know if that makes a difference. When I look at the values, they do not always correspond to the order of API fields that was given with the HMAC SHA-512 info in the SIM manual. The table I'm referring to says "order of API fields in the response". But I think that just means the order they need to be in for the hashing. And unfortunately, I don't know what order is really being returned - some are obvious like the name and address, but the others are impossible to cipher.

 

I'm ready to call it quits. It's been a long day of just spinning my wheels.

Thanks for your support!

@smorrow123 we’re rangers we don’t quit. This is an absolute mess! But you will get there. There has to be some sort of way to retrieve the API response as an associative array. The workaround would be to just find out the position of each element in the reverse engineered numerical array from your previous post. I believe the way it works is the fields come back in the same position every time, and only change when auth.net does an API update on their end. There has not been an update in going on a year and a half for DPM. So you could just periodically check for updates, or to save time just wait for it to break a year or two out and fix it then. Looks like you’re in for a short term or long term headache any way you slice it. I think the short term is the best option.

@Renaissance

Unfortunately, a "year down the road" is not an option. You're talking to an oldtimer who is getting ready to completely retire the END OF THIS MONTH (I've been partially retired for 2 years)! I'm the only person who has ever done any programming for this company and there's no one to replace me once I leave. I need to have some kind of solution built in that will work for them until they retire themselves.  

This section was code borrowed from someone else (provided via authorize.net) and I haven't made ANY modifications to it since it was implemented many years ago. I still access the same array element values , and it surprises me that it still works. But it's only a few fields - we don't use a lot of the fields after they're returned. Just a response code and reasoncode, etc. Until now anyway. We collect all the detail info on our site before sending it, so we don't need it back from them. Apparently the ones I access haven't moved - they're still in the same place in the response. But I can't seem to figure out what some of the other array elements are - and they are needed in the right order or the hashing won't work.

 

I think my only solution is to leave the MD5 hash logic there (I've been told it will still work for the near future), and document for down-the-road how to just remove the hash check, and they'll just lose that extra security. I was also told by authorize.net that it isn't an absolute requirement. I don't like it, but I'm not sure I have any choice.

 

I'm quitting for now. Appreciate your help and patience. I can't get back to this until Wednesday at the earliest, and at this point after spinning my wheels all afternoon and most of the evening, I may not bother then, either. Life is too short!   

 

 

I was referring to after you get it working. But I see what you are saying. My basic idea was that once you get it working, instead of you or whoever takes over stalking the guide for API updates you could just wait around for the thing to break. It would probably be years, because this product is deprecated. And further, you wouldn’t even have to worry about it breaking. They are only updating for security related stuff, so anything they change you would be getting emails like you did about this.

In other words, once you figure out the position of the values they likely will be the same until 2 or 3 years from now sha3 is implemented and becomes the standard, at which point you’ll get a friendly email.

And I didn’t expect you back so fast! Didn’t want to bring you back into this after the hair pulling exercise you’ve been through today. When I say rangers don’t quit I don’t mean that rangers don’t take a break. I’m kind of gung ho and work 20 hours at a time but it catches up with me eventually too.

So please disregard this message until your brain cells are refreshed from the frying pan exercise of the past few days. when you do get back, I think that array is totally the wrong way to go about it. The API response looks to be every field submitted being returned with the corresponding value, and those fields that are not submitted being returned as pipe bars.

So you end up with an unnecessarily large and hard to manage array. You could test my assumption of the values being returned in the same order every time by submitting a series of dummy transactions with the exact same values, only changing the amount or whatever else you have to change to avoid a duplicate transaction flag.

Print the API response for each of them and see if you get the same thing every time. If you do that means everything is in the same order systematically and you can avoid the associative array. This is as long as you are willing to repeat this exercise of figuring out where everything is once every 2 or 3 years.

Then what you may want to do is create multiple arrays. Make one that is delimited by a series of pipe bars so that you extract the sha512 as the value as key1.

Then you could make one or more arrays that make it easy and straightforward to extract the rest of your values. Extract all the values you need from each array and then assign them to unique variables to use in the hash calculation.


And this is not a mandatory step to verify the response. What will become mandatory at some point in the relatively near term future is to submit the fingerprint in sha512. That’s going to be easier than this. The acrobatics aren’t going to get any easier going forward I don’t think, and the solution might be to foot a one time expense for a modern API integration.

I am on my second integration of the accept hosted form and this type of walking on a tightrope blindfolded while drinking water and unlocking a safe exercise doesnt exist. The verification end that you are doing here can be reduced to about 10 lines of code, and the fingerprint equivalent for accept hosted is literally about a third of a single line of code.

You’re basically contending with 2 sets of switching costs. There is the programming for a new implementation method which will make life easier going forward and then there is the cost in time and frustration involved in what will likely be increasingly acrobatic exercises such as this to keep an ever more obsolete product functional.

Then you’ve got d-day at some point if and when this product loses all support period and your successors at your company will be forced to deal with the first set of switching costs anyways.

And to get back to making this work, once you figure out where everything is in that string/reverse engineered series of arrays make a note because the position will change when the MD5 is removed. So get yourself some rest and take a break and the next time I’m killing time we’ll get further into this ever more thickening plot.