# Overview

When followers interact with authorized Official Accounts/Mini Programs, the third-party platform receives the relevant message and event notifications. Since the third-party platform generally helps multiple Official Accounts and Mini Programs with business operations, the Weixin server take two measures to enhance the security of this process:

  1. In the URL used to receive messages and events from authorized Official Accounts, two parameters are added (in addition to the two exiting parameters timestamp and nonce): encrypt_type (the encryption type, set to aes) and msg_signature (the message signature, used to verify the accuracy of the message body).
  2. The XML body in postdata is encrypted using the message encryption symmetric_key (also called EncodingAESKey) obtained when you applying for the third-party platform.

# Technical Solution for Encryption and Decryption

The technical solution for third-party platform message encryption/decryption is implemented based on the AES Encryption Algorithm. Specifically:

  1. EncodingAESKey is the message encryption/decryption key with a fixed length of 43 characters comprised of letters (a-z and A-Z) and numbers (0-9). Developers can enter this key when creating the Official Account plug-in or modify it later.

  2. The AESKey (AESKey=Base64_Decode(EncodingAESKey + "=")) is a 32-character key generated from the EncodingAESKey with the character "=" padded at the end using Base64_Decode.

  3. AES adopts CBC mode. The key length is 32 bytes (256 bits) and the data is filled with PKCS#7. PKCS#7:K is the number of key bytes (32 bytes). Buf is the content to be encrypted and is an integer multiple of K, and N is its number of bytes. (K - N%K) bytes are padded at the end of Buf, and the content of each byte is (K - N%K).

Tail Padding Description Example
01 if ( N%K==(K-1))
0202 if ( N%K==(K-2))
030303 if ( N%K==(K-3))
... ...
KK....KK (K bytes) if ( N%K==0)

For details, see http://tools.ietf.org/html/rfc2315.

  1. BASE64 adopts MIME format. The string is composed of letters (a-z and A-Z), numbers (0-9), and special characters ("+" and "/"), with "=" used as the tail padding.

  2. For security reasons, the Open Platform website provides an EncodingAESKey modification feature to modify the EncodingAESKey if it is disclosed (corresponding to the symmetric_key used to encrypt received messages, which is entered when you apply for a third-party platform). Therefore, we recommend that Open Platform accounts save the current and previous EncodingAESKey. If decryption using the AEAKey generated from the current EncodingAESKey fails, you should use the previous AESKey. The AESKey used to encrypt the response package is the one that can decrypt the message.

  3. The Weixin Team provides code samples in multiple languages (including PHP, Java, C++, Python, and C#). Developers should use the sample code as far as possible and carefully read the technical documentation, sample code, and annotations before programming and debugging. Download the sample.

# Receiving User Messages for the Authorizer

We use a normal text message as an example to provide a detailed description of message body encryption/decryption on the Official Accounts Platform. The process for other normal messages and event messages is similar.

# Message body encryption

]≥;lp-The current message is in plaintext and with the following format:

<xml>
  <ToUserName><![CDATA[sample]]></ToUserName>
  <FromUserName><![CDATA[sample]]></FromUserName>
  <CreateTime>1348831860</CreateTime>
  <MsgType><![CDATA[sample]]></MsgType>
  <Content><![CDATA[sample]]></Content>
  <MsgId>1234567890123456</MsgId>
</xml>

After encryption, the message format is as follows:

<xml>
  <ToUserName><![CDATA[toUser]]></ToUserName>
  <Encrypt><![CDATA[msg_encrypt]]></Encrypt>
</xml>

Where, msg_encrypt = Base64_Encode( AES_Encrypt[ random(16B) + msg_len(4B) + msg + ] ).

The encrypted buf is 32 bytes, composed of a random string of 16 bytes, the 4-byte msg_len (in network byte order), msg, and AESKey =Base64_Decode(EncodingAESKey + "=").

# Message body signature

To verify the validity of the message body, the Open Platform allows developers to use a message body signature to verify the authenticity of the message body and then decrypt the verified message body. This is implemented as follows: when the Weixin server pushes the message to the Official Account plug-in, it adds the msg_signature parameter to its message receipt URL (entered at the time of creation).  msg_signature=sha1(sort(Token, timestamp, nonce, msg_encrypt)).

Parameter Description
Token The token used to verify received messages, which is set by the service provider on the Weixin Open Platform.
timestamp The timestamp, an original parameter in the URL.
nonce A random number, an original parameter in the URL.
msg_encrypt The ciphertext message body described above

# Message body verification and decryption

Developers first use a message body signature to verify the authenticity of the message body and then decrypt the verified message body.

# Verification method:

1. Compute the signature: dev_msg_signature=sha1(sort(Token, timestamp, and nonce, msg_encrypt)).

2. Compare dev_msg_signature with the msg_signature in the URL. If they are the same, the message passes verification.

# Decryption method:

1. aes_msg=Base64_Decode(msg_encrypt)
2. rand_msg=AES_Decrypt(aes_msg)
3. Verify the message tail.
4. Remove the 16-byte random number in the rand_msg header, the 4-byte msg_len, and the tail.

# Example: The service provider replies to users on behalf of the authorizer

# Reply message body signature and encryption

Current message format:

<xml>
  <ToUserName></ToUserName>
  <FromUserName></FromUserName>
  <CreateTime>12345678</CreateTime>
  <MsgType></MsgType>
  <Content></Content>
</xml>

Message format after encryption:

<xml>
  <Encrypt></Encrypt>
  <MsgSignature></MsgSignature>
  <TimeStamp></TimeStamp>
  <Nonce></Nonce>
</xml>

Where, msg_encrypt=Base64_Encode(AES_Encrypt [random(16B)+ msg_len(4B) + msg + ]),

random(16B) is a 16-byte random string, and msg_len is the 4-byte message length (in network byte order).

Enter the values AESKey =Base64_Decode(EncodingAESKey + "="), 32-byte msg_signature=sha1(sort(Token, timestamp, nonce, msg_encrypt))timestamp, and nonce in the message.

# Common errors

Several common errors that developers may encounter when encrypting/decrypting messages and their causes are described below:

  1. Incorrect XML format: Check for typos, such as a lowercase "s" or a space between "p" and ">".
  2. The Official Accounts Platform website provides an EncodingAESKey modification feature. Therefore, official accounts must save the current and previous EncodingAESKey. If the decryption using the current EncodingAESKey fails, you should use the previous one. The key used to encrypt the response package is the one that can decrypt the message.
  3. JDK 1.6 or above is required for Java.
  4. If you get the exception java.security.InvalidKeyException:illegal Key Size, download the JCE Unlimited Strength Jurisdiction Policy Files from the official website (Download JDK7).

Unzip the downloaded file to see the local_policy.jar, Us_export_policy.jar, and readme.txt files. If you have installed JRE, place the two .jar files in the %JRE_HOME%\lib\security directory to overwrite the original files. If you have installed JDK, place the two .jar files in the %JDK_HOME%\jre\lib\security directory to overwrite the original files.