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. 

Generating an RSA key pair

RSA key pair

An RSA key pair contains the private key and the public key. The private key is required for generating the signature, while the public key is used for verifying the signature.

Generating an RSA key pair

Many tools can be used to generate the RSA key pair. The following steps assume that you use OpenSSL to generate the RSA key pair.

1.Install OpenSSL.

For linux system, use the following command:

sudo apt-get install openssl

For windows system, download and then install OpenSSL from the official site

2.Generate RSA2 key pair.

For linux system, use the following command:

$ openssl

OpenSSL> genrsa -out rsa_private_key.pem 2048 ##generate private key

OpenSSL> pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM - nocrypt ##transform private key into PKCS8 format

OpenSSL> rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem

##Generate public key

OpenSSL> exit

Uploading RSA public key

After the RSA2 key pair is generated, you must exchange the public key with the AlipayHK server for signature verification by completing the following steps:

  1. Upload your public key to AlipayHK
  2. Obatin AlipayHK public key

Creating a signature 

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


image

Complete the following steps to create a signature: 

1. Obtain the private key.

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

The signature verification process consists of the following steps: 

1. Obtain the public key, 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);
        }

    }