# Dxplaination of message decryption

Service Account Message encryption and decryption is a new mechanism provided by the public platform to further strengthen the security of service numbers.Developers should note that the service number actively invokes the API will not be affected. Message decryption is required only when a user's message is replying passively. Specific modifications to message decryption include:

  1. Added message body signature verification for public platforms and Service Account to verify the correctness of message bodies
  2. Encrypt normal and event messages pushed to WeChat Service Account and device messages pushed to the device service number
  3. Service Account Replies to ciphertext messages also require encryption

Developers are asked to review the Access Guide and the Developer FAQ to access the message body signature and encryption and decryption: Access Guide

After enabling the decryption feature (i.e. selecting compatibility mode or security mode), the public platform server configures the address to the Service Account server (available on the WeChat developer platform).When a message is pushed, - My Business - Service Number - Message and Event Pushing]] adds two new parameters (encryption type and message body signature) to reflect the new functionality.The encryption algorithm uses AES, the specific encryption and decryption process and program, please see access guidelines, technical solutions and sample code.

In order to complement the launch of message encryption features and to help developers adapt to new features, The public platform offers three modes of decryption for developers to choose, namely, plaintext mode, compatibility mode, and security mode (you can choose the corresponding mode in the Developer Center). Before choosing compatibility mode and security mode, you need to fill in the EncodingAESKey message decryption key in the Developer Centre.

# The plain text format

  • Maintain the existing mode, no new features are adapted for decryption, message body is plain text, set to plain text mode by default

# Compatibility Mode

  • The content of messages sent by public platforms will include both plain and cipher text, and the length of message packets will be increased to about three times the original.Service Account Reply can be plaintext or ciphertext, without affecting existing messages;Developers can debug in this mode
  • The content of the public platform to send the message body contains only ciphertext, Service Account reply to the message body is also ciphertext, it is recommended that developers use this mode to send and receive messages after successful debugging

# Introduction to EncodingAESKey

WeChat public platform uses AES symmetric encryption algorithm to encrypt the message body sent to Service Account, and EncodingAESKey is the secret key used for encryption.The service number uses this key to decrypt the received cipher message body, and the reply message body is also encrypted with this key.

In addition, the WeChat public platform provides developers with sample code in 5 languages (including C + +, PHP, Java, Python, and C # versions, Click to download ).

# Access guidelines

# Message decryption is in plain text mode

  1. Assume that URL is configured as https://www.qq.com/revice and the data format is JSON, Token = "AAAAA."
  2. Push URL link: https://www.qq.com/recive?signature=899cf89e464efb63f54ddac96b0a0a235f53aa78×tamp=1714037059&nonce=486452656
  3. The pushed wrap:
{
    "ToUserName": "gh_97417a04a28d",
    "FromUserName": "o9AgO5Kd5ggOC-bXrbNODIiE3bGY",
    "CreateTime": 1714037059,
    "MsgType": "event",
    "Event": "debug_demo",
    "debug_str": "hello world"
}
  1. Verifies that the signature is correct to determine if the request is from the WeChat server.
    1. Lexicographic sorting of token, timestamp (in URL parameter), nonce (in the URL parameter), and the result is: ["1714037059," "486452656," "AAAAA"]
    2. Concatenate the three argument character strings into one string: "1714037059486452656AAA"
    3. Perform sha1 calculationSigned: 899cf89e464efb63f54ddac96b0a0a235f53aa78
    4. In contrast to the signature parameter in the URL link, equality indicates that the request is valid from the WeChat server.
  2. Back to WeChat, the specific back to the content of the package depends on the specific interface document requirements, such as no specific requirements, the return of the empty string or success can be.

# The message is decrypted in secure mode

  1. Assume that URL is configured with https://www.qq.com/revice and the data format isJSON,Token="AAAAA",EncodingAESKey="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",Service Account Appid="wxba5fad812f8e6fb9"。
  2. Push URL link:: https://www.qq.com/recive?signature=6c5c811b55cc85e0e1b54100749188c20beb3f5d×tamp=1714112445&nonce=415670741&openid=o9AgO5Kd5ggOC-bXrbNODIiE3bGY&encrypt_type=aes&msg_signature=046e02f8204d34f8ba5fa3b1db94908f3df2e9b3
  3. The pushed wrap:
{
    "ToUserName": "gh_97417a04a28d",
    "Encrypt": "+qdx1OKCy+5JPCBFWw70tm0fJGb2Jmeia4FCB7kao+/Q5c/ohsOzQHi8khUOb05JCpj0JB4RvQMkUyus8TPxLKJGQqcvZqzDpVzazhZv6JsXUnnR8XGT740XgXZUXQ7vJVnAG+tE8NUd4yFyjPy7GgiaviNrlCTj+l5kdfMuFUPpRSrfMZuMcp3Fn2Pede2IuQrKEYwKSqFIZoNqJ4M8EajAsjLY2km32IIjdf8YL/P50F7mStwntrA2cPDrM1kb6mOcfBgRtWygb3VIYnSeOBrebufAlr7F9mFUPAJGj04="
}
  1. Verify that the msg_signature signature is correct to determine if the request is from the WeChat server.Note: Do not use signature validation!
    • Lexicographically sort token, timestamp (in the URL parameter), nonce (in the URL parameter), and Encrypt (in the field inside the package). The result is: ["+qdx1OKCy+5JPCBFWw70tm0fJGb2Jmeia4FCB7kao+/Q5c/ohsOzQHi8khUOb05JCpj0JB4RvQMkUyus8TPxLKJGQqcvZqzDpVzazhZv6JsXUnnR8XGT740XgXZUXQ7vJVnAG+tE8NUd4yFyjPy7GgiaviNrlCTj+l5kdfMuFUPpRSrfMZuMcp3Fn2Pede2IuQrKEYwKSqFIZoNqJ4M8EajAsjLY2km32IIjdf8YL/P50F7mStwntrA2cPDrM1kb6mOcfBgRtWygb3VIYnSeOBrebufAlr7F9mFUPAJGj04=", "1714112445", "415670741", "AAAAA"]。
    • The four parameter string stitching into a character string, and then calculate the signature sha1: 046e02f8204d34f8ba5fa3b1db9908f2e9b3
    • In contrast to the msg_signature parameter in the URL parameter, equality indicates that the request is valid from the WeChat server.
  2. Decrypts the message body "Encrypt" ciphertext.
    1. AESKey = Base64_Decode (EncodingAESKey + "="), EncodingAESKey ends with a character "=," using Base64_Decode to generate a 32-byte AESKey;
    2. Base64 decodes the Encrypt ciphertext to get TmpMsg with a byte length of 224
    3. The TmpMsg is AES decrypted using AESKey to get a FullStr with a byte length of 205. AES uses 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 bytes of the key (32), Buf is the content to be encrypted, and N is the number of bytes. Buf needs to be filled in as an integer multiple of K. Fill the tail of the Buf with (K-N% K) bytes, each containing (K-N% K).WeChat The team provides sample code in a variety of languages (including PHP, Java, C + +, Python, C #) and asks developers to use sample code whenever possible, and to carefully read the technical documentation, sample code, and annotations before coding debugging. Sample Download
    4. FullStr = random(16B) + msg_len(4B) + msG + AppID where:
      • Random (16B) is a 16-byte random character string;
      • Msg_len is the length of msg, accounting for 4 bytes (network byte order);
      • MSG is the decrypted plaintext;
      • AppID is a Service Account Appid, and developers need to verify that this Appid matches their service number.
    5. In this example:
      • random(16B)="a8eedb185eb2fecf"
      • Msg_len = 167 (note: 4 bytes in network byte order)
      • msg="{"ToUserName":"gh_97417a04a28d","FromUserName":"o9AgO5Kd5ggOC-bXrbNODIiE3bGY","CreateTime":1714112445,"MsgType":"event","Event":"debug_demo","debug_str":"hello world"}"
      • appid="wxba5fad812f8e6fb9"
  3. To reply back to the WeChat server, you first need to determine the plaintext content of the reply packet, depending on the specific interface document requirements. If there is no specific requirement, reply a string or success (no encryption required), and other reply content needs to be encrypted.Assuming that the plain text in the body of the envelope is "{" demo_resp ":" goodluck "}" and the data format is JSON, here's how to encrypt the envelope:
  4. Depending on the data format you configure (JSON or XML), where:
    • Encrypt: the encrypted content;
    • MsgSignature: Signature, WeChat The server verifies the signature;
    • TimeStamp: Time stamp;
    • Nonce: Take the chance
    {
        "Encrypt": "${msg_encrypt}$",
        "MsgSignature": "${msg_signature}$",
        "TimeStamp": ${timestamp}$,
        "Nonce": ${nonce}$
    }
    
    <xml>
        <Encrypt><![CDATA[${msg_encrypt}$]]></Encrypt>
        <MsgSignature><![CDATA[${msg_signature}$]]></MsgSignature>
        <TimeStamp>${timestamp}$</TimeStamp>
        <Nonce><![CDATA[${nonce}$]]></Nonce>
    </xml>
    
  5. Encrypt的生成方法:
    1. AESKey = Base64_Decode( EncodingAESKey + "=" ),EncodingAESKey 尾部填充一个字符的 "=", 用 Base64_Decode 生成 32 个字节的 AESKey;
    2. 构造FullStr=random(16B) + msg_len(4B) + msg + appid,其中
      • random(16B)为 16 字节的随机字符串;
      • msg_len 为 msg 长度,占 4 个字节(网络字节序);
      • msg为明文;
      • appid为服务号Appid。
    3. 在此示例中:
      • random(16B)="707722b803182950"
      • msg_len=25(注意:需按网络字节序,占4个字节)
      • msg="{"demo_resp":"good luck"}"
      • appid="wxba5fad812f8e6fb9"
      • FullStr的字节大小为63
    4. 将FullStr用AESKey进行加密,得到TmpMsg,字节大小为64。AES 采用 CBC 模式,秘钥长度为 32 个字节(256 位),数据采用 PKCS#7 填充; PKCS#7:K 为秘钥字节数(采用 32),Buf 为待加密的内容,N 为其字节数。Buf 需要被填充为 K 的整数倍。在 Buf 的尾部填充(K - N%K)个字节,每个字节的内容 是(K - N%K)。微信团队提供了多种语言的示例代码(包括 PHP、Java、C++、Python、C#),请开发者尽量使用示例代码,仔细阅读技术文档、示例代码及其注释后,再进行编码调试。示例下载
    5. 对TmpMsg进行Base64编码,得到Encrypt="ELGduP2YcVatjqIS+eZbp80MNLoAUWvzzyJxgGzxZO/5sAvd070Bs6qrLARC9nVHm48Y4hyRbtzve1L32tmxSQ=="。
  6. TimeStamp由开发者生成,使用当前时间戳即可,示例使用1713424427。
  7. Nonce回填URL参数中的nonce参数即可,示例使用415670741。
  8. MsgSignature的生成方法:
    1. 将token、TimeStamp(回包中的)、Nonce(回包中的)、Encrypt(回包中的)四个参数进行字典序排序,排序后结果为: ["1713424427", "415670741", "AAAAA", "ELGduP2YcVatjqIS+eZbp80MNLoAUWvzzyJxgGzxZO/5sAvd070Bs6qrLARC9nVHm48Y4hyRbtzve1L32tmxSQ=="]
    2. 将四个参数字符串拼接成一个字符串,并进行sha1计算签名:1b9339964ed2e271e7c7b6ff2b0ef902fc94dea1
  9. 最终回包为:
{
    "Encrypt": "ELGduP2YcVatjqIS+eZbp80MNLoAUWvzzyJxgGzxZO/5sAvd070Bs6qrLARC9nVHm48Y4hyRbtzve1L32tmxSQ==",
    "MsgSignature": "1b9339964ed2e271e7c7b6ff2b0ef902fc94dea1",
    "TimeStamp": 1713424427,
    "Nonce": "415670741"
}

为了便于开发者调试,我们提供了相关的调试工具(请求构造调试工具)供开发者使用。

  • “请求构造”允许开发者填写相关参数后,生成debug_demo事件发包或回包的相关调试信息,供开发者使用。
  • “调试工具”允许开发者填写AccessToken、Body后,微信服务器会拉取你在服务号后台配置的消息推送配置,实际推送一条debug_demo事件供开发者调试。