Since the official Alipay SDK does not provide a Swift version, you need to implement signing and verification yourself. This article uses Swift version 5.7+ in conjunction with krzyzanowskim/CryptoSwift. Of course, using vapor/jwt-kit is also an option; jwt-kit is actually more convenient (no need to handle key formats manually) and has been verified to work. However, since I required other features from CryptoSwift, I will use CryptoSwift as the example here.
Key Handling
1. Generate Application Public and Private Keys
Download the Alipay Open Platform Key Tool to generate your keys. Use the RSA2 encryption algorithm to generate the Application Public Key and Application Private Key. By default, the tool generates X.509/SPKI and PKCS#8 formats, which need to be converted to PKCS#1.
2. Obtain the Alipay Public Key

In the Alipay Merchant Dashboard, set the "Signature Method" (加签方式). Copy the Application Public Key from the tool into the input box and click confirm to upload. You will then obtain the Alipay Public Key. Download this key as a .txt file. The Application Public Key's job is now done and can be deleted.
3. Processing the Alipay Public Key
Open the downloaded Alipay Public Key .txt file and add the identifiers at the header and footer:
// Add to Header
-----BEGIN PUBLIC KEY-----
// Add to Footer
-----END PUBLIC KEY-----The modified content should look similar to:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ……
-----END PUBLIC KEY-----Execute the following command in your terminal to convert it to PKCS#1 format. This will yield the alipayPublicKey_RSA2_pkcs1.txt file for subsequent use:
openssl rsa -pubin -in alipayPublicKey_RSA2.txt -RSAPublicKey_out -out alipayPublicKey_RSA2_pkcs1.txt4. Application Private Key Processing
Rename the Application Private Key .txt file generated by the tool to private_pkcs8.txt. Open the file and add the following identifiers:
// Add to Header
-----BEGIN PRIVATE KEY-----
// Add to Footer
-----END PRIVATE KEY-----The modified content should look like:
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASC……
-----END PRIVATE KEY-----Execute the following command to convert it to PKCS#1 format, resulting in private_pkcs1.txt:
openssl pkey -in private_pkcs8.txt -out private_pkcs1.txt -traditionalInitiating Payment
Key Points:
- The form's
gateway.doneeds thecharsetparameter set, otherwise it defaults to GBK.
var html = "<html><body onload='document.forms[0].submit()'>"
html += "<form method='POST' action='https://openapi.alipay.com/gateway.do?charset=utf-8'>"- Construct the POST parameter dictionary. Do not remove
sign_typeduring encryption, and use the PKCS#1 format private key for signing. - The signing function expects the digest or the message. You can use:
String concatenation for signing:
let unsignedString = parameters
.filter { $0.key != "sign"}
.sorted(by: { $0.key < $1.key })
.map { "\($0)=\($1)" }
.joined(separator: "&")Signing implementation:
privateKeyRAS.sign(Data(unsignedString.utf8).byteArray.sha256(), variant: .digest_pkcs1v15_SHA256)OR
privateKeyRAS.sign(Data(unsignedString.utf8).byteArray, variant: .message_pkcs1v15_SHA256)Payment Verification (Verification of Signature)
Key Points:
- Use the PKCS#1 formatted Alipay Public Key generated earlier, NOT the Application Public Key generated by the tool.
- In the notification return parameter list, all parameters except
signandsign_typeare parameters to be verified. (Note: Asynchronous notifications for "Life Accounts" may require keepingsign_type). - Perform
url_decodeon the remaining parameters, sort them alphabetically by key, and concatenate them into a string to get the "to-be-signed" string. - Decode the
signparameter from Base64 into a byte array.
String concatenation for verification:
let unsignedString = params
.filter { $0.key != "sign" && $0.value != "" && $0.key != "sign_type" }
.sorted(by: { $0.key < $1.key })
.map { "\($0.key)=\($0.value)" }
.joined(separator: "&")Verification implementation:
let publicKeyRAS = try RSA(rawRepresentation: publicKeyData)
let result = try publicKeyRAS.verify(signature: signData.byteArray, for: Data(unsignedString.utf8).byteArray, variant: .message_pkcs1v15_SHA256)
return resultCopyright:Damon胡东东 - hudd.me
This article is licensed under a Creative Commons Attribution 4.0 International License.Reprinting or using large sections must include a link to this article, otherwise you will constitute infringement!
Damon胡东东
Comments(0)