2

So what I am trying to do is is make a few API calls with AliPays https://global.alipay.com/docs/ac/ams/api API

I followed the integration guide and I created the nessassary private / public keys and Client Id. I also followed the generate signature guide here: https://global.alipay.com/docs/ac/ams/digital_signature#gNWs0

I also copied part of the code from iTest, the Developer Tools of alipay, so actually the function signWithSHA256RSA is from alipay.

I know that my private key should work, because I was able to test sucessfully the same request with the Developer Tools of alipay.

// generate ISO 8601 date
$oDateTime = new \DateTime();
$sDate = $oDateTime->format('c');

$privatekey = '<private_key_removed>';

$curl = curl_init(); 
curl_setopt($curl, CURLOPT_URL, 'https://open-eu.alipay.com/ams/api/v1/payments/pay');

$reqBody = json_encode(array('productCode' => 'IN_STORE_PAYMENT'));

$headers = array();
$headers[] = "Content-Type:application/json; charset=UTF-8";
$headers[] = "Request-Time:".$sDate;
$headers[] = "client-id:<client_id_removed>";
$headers[] = "Signature:". "algorithm=RSA256,keyVersion=1,signature=".signWithSHA256RSA($sDate, $reqBody, $privatekey);

curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_HEADER, true);
curl_setopt($curl, CURLOPT_POST, true);

curl_setopt($curl, CURLOPT_POSTFIELDS, $reqBody);
$rspContent = curl_exec($curl);

function signWithSHA256RSA($timeString, $reqBody, $privateKey){

  $priKey = "-----BEGIN RSA PRIVATE KEY-----\n". 
            wordwrap($privateKey, 64, "\n", true).
            "\n-----END RSA PRIVATE KEY-----";

  $signContent = "POST /ams/api/v1/payments/pay"."\n<client_id_removed>".".".$timeString. ".".$reqBody;
  
  openssl_sign($signContent, $signValue, $priKey, OPENSSL_ALGO_SHA256);

  return base64_encode($signValue);
}

The error code that I am getting is:

{"result":
 {
  "resultCode":"PARAM_ILLEGAL",
  "resultMessage":"illegal parameter:OpenapiV2签名字段异常: algorithm=RSA256,keyVersion=1,signature=<signature_removed>",
"resultStatus":"F"}
}
General Grievance
  • 4,555
  • 31
  • 31
  • 45
Petros Mastrantonas
  • 806
  • 1
  • 15
  • 41

1 Answers1

3

Error via Google Translate: '签名字段异常' -> 'Signature field exception'

  1. Validate the signature. Replace $privateKey and $publicKey from you secrets.
$data = 'POST ...';
$keyPair = openssl_pkey_new(
    [
        'private_key_bits' => 2048,
        'private_key_type' => OPENSSL_KEYTYPE_RSA,
    ]
);
openssl_pkey_export($keyPair, $privateKey);
$details = openssl_pkey_get_details($keyPair);
$publicKey = $details['key'];
openssl_sign($data, $signature, $privateKey, OPENSSL_ALGO_SHA256);
var_dump($signature);
//verify signature
$isValidSignature = openssl_verify(
    $data,
    $signature, 
    $publicKey, 
    'sha256WithRSAEncryption'
);
var_dump($isValidSignature);
  1. In the documentation says generatedSignature=base64UrlEncode(sha256withrsa(<Content_To_Be_Signed>), <privateKey>))

and provided java example

return URLEncoder.encode(new String(Base64.encodeBase64(signed), "UTF-8"), "UTF-8");

php equivalent is

urlencode(base64_encode($signature))

cetver
  • 11,279
  • 5
  • 36
  • 56
  • thank you, but that is not the reason that it doesn't work. I already tried with your method base64UrlEncode. Also as I mentioned, I took my sourcecode from the alipay documentation. Your sourcecode wouldn't work, I can't generate the keys on the fly, the public key has already been uploaded to the alipay backend, and I need to use my private key to sign it as my sourcecode already suggest. – Petros Mastrantonas Jan 10 '22 at 09:07
  • `base64UrlEncode` is mandatory. Keys generation it's just example. Set `$privateKey` and `$publicKey` from your secrets. Is the `openssl_verify` returns 1 ? If yes, same error from the server ? – cetver Jan 10 '22 at 10:02
  • openssl_verify is returning 1, public and private key is matching – Petros Mastrantonas Jan 10 '22 at 10:19
  • Forgot about the `base64UrlEncode` and try this: `Signature: algorithm=RSA256, keyVersion=1, signature=urlencode(base64_encode($signature))` based on java example `return URLEncoder.encode(new String(Base64.encodeBase64(signed), "UTF-8"), "UTF-8");` – cetver Jan 10 '22 at 12:34
  • thank you, i will try and let you know! – Petros Mastrantonas Jan 10 '22 at 12:44
  • 1
    Thank you! Your last suggestion about urlencode did it! Thanks a million, the call to the alipay servers works now! I upvoted and accepted your answer. I would appreciate if you would edit your answer to reflect your last comment with the urlencode command – Petros Mastrantonas Jan 12 '22 at 19:50