What I'm trying to do:
I'm trying to list Devpay S3 buckets.
References I'm using:
1. http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTServiceGET.html
2. http://docs.amazonwebservices.com/AmazonDevPay/latest/DevPayDeveloperGuide/QuickReferenceS3Products.html
3. http://docs.amazonwebservices.com/AmazonDevPay/2007-12-01/DevPayDeveloperGuide/DesktopAWSCalls.html
How I'm doing it:
A simple REST GET request using the PHP libcURL library:
GET / HTTP/1.1
Host: s3.amazonaws.com
Date: $date
X-Amz-Date: $date
X-Amz-Security-Token: $userToken, $productToken
Authorization: $signatureValue
where
$date // = timestamp at the time of request
$signatureValue //= Authorization: AWS $signature
$signature //= $userAccessKey:$signatureString
$signatureString //=base64 encoded HMAC-SHA1 of $stringToSign with $userSecretKey
$stringToSign //= utf8 encoded string:
this string -
GET\n
""\n
""\n
$date\n
$canonicalized_AMZ_Headers\n
/
I'm using curl_exec() to execute the GET request.
Error that I'm getting:
"SignatureDoesNotMatch"
"The request signature we calculated does not match the signature you provided. Check your key and signing method"
Thanks!
Any help would be greatly appreciated
In the returned error message from S3 will be a StringToSign element (use View Source to see it more clearly). Compare this carefully with the string you are appending together to sign the request — they must be exactly the same.
Related
I am trying to fetch byte array from C# Web API. C# client can perfectly fetch byte array but it comes in PHP then it shows random string. This string looks like encoded.
I have tried the same API with POSTMAN also. Postman also provided same encoded string. How can I fetch byte array from C# web API in PHP?
I am using HTTP request with content-type of application/x-www-form-urlencoded. This API suppose to give byte array for the following the text,
Required Byte array of content: This is demo file.
Actual response: VGhpcyBpcyBkZW1vIGZpbGUuCg==
Byte values come from webapi as strings. You need to convert this value to base64 type.
string str = yourbytestring;
byte[] cnvbyte = Convert.FromBase64String(str.ToString());
I try to send EBICS HPB request, but get always the same error:
EBICS_AUTHENTICATION_FAILED
I think the problem is on my code, below is what the code is doing to get the signature value :
Get signature Certificate from pem file
Remove CR, LF and Ctrl-Z
Convert PEM to DER.
Apply ISO10126
hash sha256
Encryption rsa PKCS #1 v1.5: rsa_encrypt($SignatureValue, $public_key)
Then I put the result as signature value, but I'm not sure to do the right procedure before sending my request.
I need to translate some existing PHP code to Python. This job connects to gravity forms and queries for certain data. In order to make the query, a signature must be calculated in order to verify the connection.
The Gravity Forms web api gives good PHP directions here.
The PHP method is as follows:
function calculate_signature( $string, $private_key ) {
$hash = hash_hmac( 'sha1', $string, $private_key, true );
$sig = rawurlencode( base64_encode( $hash ) );
return $sig;
}
Based on my understanding of Python and the information about hash-hmac and rawurlencoded from php2python.com, I wrote the following:
import hmac, hashlib, urllib, base64
def calculate_signature(string, private_key):
hash_var = hmac.new(private_key, string, hashlib.sha1).digest()
sig = urllib.quote(base64.b64encode(hash_var))
return sig
However, the two signatures are not equivalent, and thus Gravity Forms returns a HTTP 403: Bad Request response.
Am I missing something within my translation?
Update (11/04/15)
I have now matched my php and python urls. However, I still receive a 403 error.
The reason the php and python signatures did not match had nothing to do with their calculate_signature() methods.
The issue was caused by differing expires variables. Php used strtotime("+60 mins") which resulted in a UTC time 60 minutes from now. Whereas Python used datetime.date.now() + timedelta(minutes=60). This is also 60 minutes from now, but in your current timezone.
I always want to calculate the expire variable in UTC so I replaced my Python calculation with datetime.datetime.utcnow() + timedelta(minutes=60).
You're almost there. urllib.quote does not encode slashes, for example, as PHP's rawurlencode does. You can use urllib.quote_plus to achieve the desired effect:
import hmac, hashlib, urllib, base64
def calculate_signature(string, private_key):
hash_var = hmac.new(private_key, string, hashlib.sha1).digest()
sig = urllib.quote_plus(base64.b64encode(hash_var))
return sig
I'm following several examples I've found online and I'm trying to recreate the signature they have in the official API documentation here. However, I'm failing to generate the same signature.
They state the string to sign is as follows:
GET
webservices.amazon.com
/onca/xml
AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&ItemId=0679722769&Operation=I
temLookup&ResponseGroup=ItemAttributes%2COffers%2CImages%2CReview
s&Service=AWSECommerceService&Timestamp=2009-01-01T12%3A00%3A00Z&
Version=2009-01-06
It states to "Calculate an RFC 2104-compliant HMAC with the SHA256 hash algorithm using the string above with our "dummy" Secret Access Key: 1234567890."
I do this using the following code:
$private_key = "1234567890";
$string_to_sign = "GET
webservices.amazon.com
/onca/xml
AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&ItemId=0679722769&Operation=I
temLookup&ResponseGroup=ItemAttributes%2COffers%2CImages%2CReview
s&Service=AWSECommerceService&Timestamp=2009-01-01T12%3A00%3A00Z&
Version=2009-01-06";
$signature = base64_encode(hash_hmac("sha256",$string_to_sign, $private_key, True));
This yields the following signature:
LM5S6MrycUETu1p94QDnLurKIpwiqKnCxm3B73a0QiE=
Amazon's signature is:
M/y0+EAFFGaUAp4bWv/WEuXYah99pVsxvqtAuC8YN7I=
I've followed a bunch of examples I found via Google and they all appear to do this the same way. However, I can't arrive at the same signature that Amazon gets and I can't figure out why.
Any help is appreciated.
I just burned a few hours of my life trying to figur out why my signature wasn't matching. In case this helps somebody out, use Amazon's example as mentioned by the OP. I started having trouble at steps 6 and 7. Amazon says to prepend the following three lines (including line breaks) to your string:
Get
webservices.amazon.com
/onca/xml
On my windows 7 platform, here's what I did for those steps:
$string_to_sign = "AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&AssociateTag=mytag-20&ItemId=0679722769&Operation=ItemLookup&ResponseGroup=Images%2CItemAttributes%2COffers%2CReviews&Service=AWSECommerceService&Timestamp=" . "2014-08-18T12%3A00%3A00Z&Version=2013-08-01";
$prepend = "GET\nwebservices.amazon.com\n/onca/xml\n";
$string_to_sign = $prepend . $string_to_sign;
Then, step 8 threw me off too because I was using the sample's secret key:
Secret Access Key: "1234567890"
instead of the correct key:
Secret Access Key: 1234567890
Hope these little mistakes don't burn anybody else.
Do you really have all those linebreaks in your actual code? Because I\ntemLookup is not the same as ItemLookup. That GET URI should be a single long string, not a multi-line string.
GET webservices.amazon.com /onca/xmlAWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&ItemId=0679722769&Operation=ItemLookup&ResponseGroup=ItemAttributes%2COffers%2CImages%2CReviews&Service=AWSECommerceService&Timestamp=2009-01-01T12%3A00%3A00Z&Version=2009-01-06
Notice how it's all on the SAME line
I am writing a PHP app (acting as a SAML IdP) which is trying to do a login via a SAML Response to a server (acting as the SAML SP. I am currently stuck with the server rejecting the request (I just get a 500 Bad Request).
I have written a test app (in Java/openSAML - which I'm pretty sure the server is using), and can see that the problem is that the SAML SignatureValidator validate generates
org.apache.xml.security.signature.XMLSignatureException: Invalid XMLDSIG format of DSA signature
Looking at the SAML SignatureValidator code I can see that it checks that the XMLDISG signature is exactly 40 bytes long (P1363 format?) - whereas the generated signature is 46-48 bytes long (DER ASN.1 format?).
The signature is being generated by PHP openssl_sign as below.
openssl_sign($canonicalized_signedinfo,
$signature,
$private_key,
OPENSSL_ALGO_DSS1))
An example signature (displayed as binary to hex for clarity) is as below. This is 46 bytes, but I notice it varies (depending on the random key?) from 46 to 48 bytes.
302c02146e74afeddb0fafa646757d73b43bca688a12ffc5021473dc0ca572352c922b80abd0662965e7b866416d
I can successfully verify this signature using PHP openssl_verify as below.
openssl_verify ($canonicalized_signedinfo,
$signature ,
$public_key,
OPENSSL_ALGO_DSS1))
But in my test app when I do a SignatureValidator validate (as below) I get the XMLSignatureException: Invalid XMLDSIG format of DSA signature exception.
BasicCredential credential = new BasicCredential();
credential.setPublicKey(publicKey);
credential.setUsageType(UsageType.SIGNING);
SignatureValidator sigValidator = new SignatureValidator(credential);
sigValidator.validate(signature);
Does anyone know how to do the PHP signature conversion from the 46-48 DER ASN.1 format generated by PHP openssl_sign to the 40 byte P1363 format expected by openSAML?
That resource from code project has explanations about how to convert ASN.1 format into P1363 with code examples. It may be useful to write a Java validation method.
And I propose you use this C++ code to generate a DSIG compliant signature from PHP: http://xmlsig.sourceforge.net/
By the way, it sounds more complex than simply generate the signature and validate it. You may be interested in XMLBlackbox