云真机

API接口文档


数据包加解密

<h2>1.简介</h2> <p>当事件(如聊天消息、成员变更等)发生或下发任务(如获取群二维码等)执行完成时,会推送数据到用户开发的回调地址,用户可根据接收到的数据进行相应的逻辑处理。推送的数据已加密,下面介绍加解密相关内容。解密后的数据结构和类型请参考:&lt;a href=&quot;<a href="https://www.showdoc.com.cn/yunzhenji/11490693160849765&quot;&gt;被动接收数据&lt;/a&gt">https://www.showdoc.com.cn/yunzhenji/11490693160849765&quot;&gt;被动接收数据&lt;/a&gt</a>;</p> <p>&lt;font color=&quot;red&quot;&gt;注意: 回调请求<strong>超时时间</strong>为<strong>1s</strong>,故在开发回调地址时,接收到数据后请先存入消息队列,复杂的业务逻辑之后慢慢消费队列,以免造成业务执行不完的问题。 另需注意,为了保证回调整体性能,避免因某些回调地址异常且有大批量回调占用耗时的情况,目前有自动触发限制的机制:当天回调超时(<strong>超时时间</strong>为<strong>1s</strong>)超过1000次,会被自动加入限制,当天后续不会再回调。API用户遇到不回调的情况,可以先查验回调地址是否异常,排除异常后可以联系我们移出限制。&lt;/font&gt;</p> <h2>2. 数据加解密</h2> <p> 为确保数据推送的安全性,推送到用户回调地址的数据已被整体加密,用户需要对接收到的数据进行对称解密后使用。  加密采用AES算法的CBC模式,秘钥长度为32个字节(在申请API应用时已返回,即:encoding_aes_key),算法初始向量使用秘钥(即:encoding_aes_key)的前16个字节,数据采用PKCS#7方式填充。  加密前的数据为json字符串,包含多条消息通知,数据结构如:&quot;[{&quot;type&quot;:&quot;chatMsg &quot;,&quot;data&quot;:{}},{&quot;type&quot;:&quot;contacts &quot;,&quot;data&quot;:{}}]&quot;,作为待加密数据,对该数据采用PKCS#7进行填充后,使用AES-256-CBC算法进行对称加密。</p> <p><em>&lt;font color=&quot;red&quot;&gt;注:1、PKCS#7:K为秘钥字节数(采用32),buf为待加密的内容,N为其字节数。Buf需要被填充为K的整数倍。在buf的尾部填充(K-N%K)个字节,每个字节的内容是(K- N%K)对应的ASCII 字符; 2、填充时明文分组长度为256位(32字节),与微信开放平台AES-256-CBC加密填充方式一致,与AES加密标准固定块长128位(16字节)不同,所以加密时注意先按32字节填充,调用加密方法时采用不填充模式;&lt;/font&gt;</em></p> <p>php基于openssl加解密示例:</p> <pre><code>/** * 填充算法 * @param string $source * @return string */ function addPKCS7Padding($source, $blocksize = 16) { $datasize = strlen($source); $padsize = $blocksize - ($datasize % $blocksize); $char = chr($padsize); $source .= str_repeat($char, $padsize); return $source; } /** * 移去填充算法 * @param string $source * @return string */ function stripPKSC7Padding($source, $blocksize = 16) { $char = substr($source, -1, 1); $num = ord($char); if ($num &amp;gt; $blocksize) { return $source; } return substr($source, 0, -$num); } 加密示例: $data = &amp;quot;123456&amp;quot;; $encoding_aes_key = &amp;quot;4b7ee5e6210e056fb00ff518d1653854&amp;quot;; $data = addPKCS7Padding($data, 32);//填充至32字节的倍数 $iv = substr($encoding_aes_key, 0, 16); $encryptedData = openssl_encrypt($data, 'AES-256-CBC', $encoding_aes_key, OPENSSL_NO_PADDING, $iv); $encryptedData = base64_encode($encryptedData); print_r($encryptedData);//打印结果:&amp;quot;slinTeomuAR91ljVsl0qSZZLtpfGpJ/gDP8nRur1GA8=&amp;quot; 解密示例: $encryptedData = base64_decode($encryptedData); $data = openssl_decrypt($encryptedData, 'AES-256-CBC', $encoding_aes_key, OPENSSL_NO_PADDING, $iv); $data = stripPKSC7Padding($data, 32);//移去填充字符 print_r($data);//打印结果:&amp;quot;123456&amp;quot;</code></pre> <p>&lt;font color=&quot;red&quot;&gt;<strong>java加解密可参考:</strong></p> <pre><code>import org.apache.commons.codec.binary.Base64; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.Charset; import java.util.Arrays; /** * Unit test for simple App. */ public class Demo { public static void main(String[] args) { try { String rawContent = &amp;quot;123456&amp;quot;; String aesKey = &amp;quot;4b7ee5e6210e056fb00ff518d1653854&amp;quot;; String iv = aesKey.substring(0,16); String enResult = encrypt(rawContent, aesKey, iv); System.out.println(enResult); String deResult = decrypt(enResult, aesKey, iv); System.out.println(deResult); }catch (Exception e){ e.printStackTrace(); } } /** * 加密 * @param data * @param key * @param iv * @return * @throws Exception */ public static String encrypt(String data, String key, String iv) throws Exception { SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), &amp;quot;AES&amp;quot;); IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes()); Cipher cipher = Cipher.getInstance(&amp;quot;AES/CBC/NoPadding&amp;quot;);//&amp;quot;算法/模式/补码方式&amp;quot; cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec); byte[] encrypted = cipher.doFinal(PKCS7Encode(data).getBytes()); return new Base64().encodeToString(encrypted); } /** * 解密 * @param encryptData * @param key * @param iv * @return * @throws Exception */ public static String decrypt(String encryptData, String key, String iv) throws Exception { byte[] encrypted1 = new Base64().decode(encryptData); SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), &amp;quot;AES&amp;quot;); IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes()); Cipher cipher = Cipher.getInstance(&amp;quot;AES/CBC/NoPadding&amp;quot;); cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec); byte[] original = cipher.doFinal(encrypted1); // 去除补位字符 byte[] bytes = PKCS7Decode(original); return new String(bytes); } /** * 补全 * @param data * @return */ public static String PKCS7Encode(String data) { int blocksize = 32; int padsize = blocksize - (data.getBytes().length % blocksize); if (padsize &amp;lt;= 0) { return data; } char[] result = new char[padsize]; for (int i = 0; i &amp;lt; padsize; i++) { result[i] = (char) padsize; } data += new String(result); return data; } /** * 剔除补全 * @param decrypted * @return */ static byte[] PKCS7Decode(byte[] decrypted) { int pad = (int)decrypted[decrypted.length - 1]; if (pad &amp;lt; 1 || pad &amp;gt; 32) { pad = 0; } return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad); } } </code></pre> <p><strong>其他语言加解密参考微信公众号同类型加解密demo:</strong>&lt;/font&gt; <a href="https://cdn-qyb-hz.wxb.com/u/21/20220419/f5e59ac09ddbc732f2653ed59d6eb880.zip">https://cdn-qyb-hz.wxb.com/u/21/20220419/f5e59ac09ddbc732f2653ed59d6eb880.zip</a></p> <h1>3.解密后的数据结构和类型,点击跳至:&lt;a href=&quot;<a href="https://www.showdoc.com.cn/1702411877508139/7988199114453636&quot;&gt;解密后的数据结构介绍&lt;/a&gt;查看">https://www.showdoc.com.cn/1702411877508139/7988199114453636&quot;&gt;解密后的数据结构介绍&lt;/a&gt;查看</a>。</h1>

页面列表

ITEM_HTML