Alipay, China's leading third-party online payment solutionAlipay, China's leading third-party online payment solutionDOCS

      Digital signature

      To guarantee that data have not been altered in transmission, digital signature and encryption mechanism can be adopted. For all messages, the digital signature is mandatory. In addition, data encryption is required if sensitive information is enclosed in the message. For more details about encryption, see Encryption.


      The signature algorithm used for data transmission is RSA 256. You can use RSA256 for creating or validating signatures. When creating a signature, calculate a sha256 digest first, and then encrypt the digest by using RSA algorithm. The recommended RSA key size is 2048 bits. 


      #Preparing keys

      You can create asymmetric keys in your own way or by using the tool provided in the Alipay Developer Center. You can set up and then exchange keys for the sandbox and production environments respectively with the provided tool. The following figure shows where you can obtain the key generation tool and configure the key.

      image.png


      Besides using the tool to generate RSA2 key pair, you can also generate the RSA2 key pairs manually, for example:


      copy
      # 1. Generating the private key
      openssl genrsa -out client_private_key_php_dotnet.pem
      
      # 2. If you are a Java developer, convert the private key to PKCS8 format
      openssl pkcs8 -topk8 -inform PEM -in client_private_key_php_dotnet.pem -outform PEM -nocrypt -out client_private_key_pkcs8.pem 
      
      # 3. Generate the public key
      openssl rsa -in client_private_key_php_dotnet.pem -pubout -out client_public_key_php_dotnet.pem 
      
      # 4. Generate the private key that can be used in Java
      cat client_private_key_pkcs8.pem | grep -v "^\-" | tr -d "\n" | sed 's/%$//' > client_private_key_java.pem
      
      # 5. Generate the public key that can be used in Java
      cat client_public_key_php_dotnet.pem | grep -v "^\-" | tr -d "\n" | sed 's/%$//' > client_public_key_java.pem



      #Creating a signature 

      See the following figure for an overview of the signature creation process


      image.png


      Figure 1. Signature creation process 


      Complete the following steps to create a signature: 


      1. Obtain the private key. See Preparing keys for details.


      2. Create the string to sign. The string to be signed is: 

      copy
      <HTTP Method> <HTTP-URI-with-query-string>
      <Client-Id>.<Request-Time|Response-Time>.<HTTP body>


      3. Generate the signature. Use the algorithm and private key obtained in step1 to generate the signature. The following example assumes that RSA256 algorithm is used to generate the signature:

      copy
      signature=base64UrlEncode(sha256withrsa(string-to-sign))


      Demo code:

      copy
      /**
           * 
           * @param requestURI // domain part excluded, sample: /ams/api/v1/payments/pay
           * @param clientId
           * @param requestTime
           * @param privateKey
           * @param requestBody
           * @return
           */
          public static String sign(String requestURI, String clientId, String requestTime,
                                    String privateKey, String requestBody) {
      
              String content = String.format("POST %s\n%s.%s.%s", requestURI, clientId, requestTime,
                  requestBody);
      
              try {
                  java.security.Signature signature = java.security.Signature
                      .getInstance("SHA256withRSA");
      
                  PrivateKey priKey = KeyFactory.getInstance("RSA").generatePrivate(
                      new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey.getBytes("UTF-8"))));
      
                  signature.initSign(priKey);
                  signature.update(content.getBytes("UTF-8"));
      
                  byte[] signed = signature.sign();
      
                  return URLEncoder.encode(new String(Base64.encodeBase64(signed), "UTF-8"), "UTF-8");
              } catch (Exception e) {
                  throw new RuntimeException(e);
              }
          }


      1. Add the signature to header. Assemble the signature algorithm, the key version used for the signature, and the signature into Signature header. The following example shows a finished Signature header: 


      copy
      key: Signature ;
      value:algorithm=<algorithm>,keyVersion=<key-version>,signature=<signature>



      #Validating a signature 

      See the following figure for an overview of the signature validation process: 

      image.png

      Figure 2. Signature validation process 


      The signature verification process consists of the following steps: 


      1. Obtain the public key, see Preparing keys for details. Obtain Client-Id and algorithm from header.


      2. Create the string to sign. The string to be signed is: 

      copy
      <HTTP Method> <HTTP-URI-with-query-string>
      <Client-Id>.<Request-Time|Response-Time>.<HTTP body>


      1. Use the algorithm obtained in step 1 to calculate a digest of the string you created in step 2. Then, decrypt the signature by using the public key to get a digest. Compare two digests, if the digests match the signature is verified. For example, assume RSA256 algorithm is used, base64url decode the signature content to obtain the original signature, and then validate the signature by using the sender’s public key and sha256withrsa algorithm. 


      copy
      sha256withrsa_verify(base64UrlDecode(<signature>), <content_to_be_verified>, <serverPublicKey>)


      Demo code:

      copy
      /**
           * 
           * @param requestURI // domain part excluded, sample: /ams/api/v1/payments/pay
           * @param clientId
           * @param reponseTime
           * @param alipayPublicKey
           * @param responseBody
           * @param signatureToBeVerified
           * @return
           */
          public static boolean verify(String requestURI, String clientId, String reponseTime,
                                       String alipayPublicKey, String responseBody,
                                       String signatureToBeVerified) {
      
              //signatureToBeVerified would not be present in the response when AMS returns a SIGNATURE_INVALID
              if (StringUtil.isBlank(signatureToBeVerified)) {
                  return false;
              }
      
              String content = String.format("POST %s\n%s.%s.%s", requestURI, clientId, reponseTime,
                  responseBody);
      
              try {
                  java.security.Signature signature = java.security.Signature
                      .getInstance("SHA256withRSA");
      
                  PublicKey pubKey = KeyFactory.getInstance("RSA").generatePublic(
                      new X509EncodedKeySpec(Base64.decodeBase64(alipayPublicKey.getBytes("UTF-8"))));
      
                  signature.initVerify(pubKey);
                  signature.update(content.getBytes("UTF-8"));
      
                  return signature.verify(Base64.decodeBase64(URLDecoder.decode(signatureToBeVerified,
                      "UTF-8").getBytes("UTF-8")));
      
              } catch (Exception e) {
                  throw new RuntimeException(e);
              }
      
          }