1. SHA-256哈希概述

1.1 基本概念

SHA-256(Secure Hash Algorithm 256-bit)是SHA-2哈希函数家族的核心成员,由美国国家标准与技术研究院(NIST)于2001年发布,旨在替代已被破解的SHA-1。SHA-256通过一系列复杂的数学运算,将任意长度的输入数据转换为固定长度的256位哈希值。

备注:团队最近在做演示demo,整理一部分HSM中SHA-256的资料分享,如果错误欢迎大家批评指正。support@softor.com.cn

1.2 核心特性

1.3 SHA-256算法流程

  1. 1. 数据填充:将输入数据填充到512位的整数倍
  2. 2. 初始化哈希值:使用8个初始哈希值(H0-H7)
  3. 3. 分块处理:将填充后的数据分成512位的块
  4. 4. 压缩函数:对每个块执行64轮运算
  5. 5. 结果输出:最终的8个哈希值连接形成256位哈希值

2. 应用场景

2.1 主要应用领域

2.2 为什么使用SHA-256

3. 英飞凌TC3xx单片机HSM上的SHA-256实现

3.1 TC3xx HSM特性

英飞凌TC3xx系列单片机集成了高性能的硬件安全模块(HSM),专为安全关键应用设计:

3.2 SHA-256硬件加速原理

HSM通过专用的HASH硬件模块实现SHA-256加速,主要优势:

3.3 HSM哈希模块架构

TC3xx HSM的哈希模块由以下部分组成:

3.4 实现代码分析

3.4.1 HSM端实现(code_hsm.c)

void HASH_SHA256(unsigned int num_blocks)
{
    int
 i;
    unsigned
 int block_num = 0;
    unsigned
 int *psrc, *pdst;
    
    // 配置哈希算法为SHA-256

    HSM_HASH->HASH_CFG = ((HASH_ALGO_SHA_256 << HASH_CFG_ALGO_Pos) |
                         (HASH_ORDER_OUT_MSW_FIRST << HASH_CFG_ORDER_OUT_Pos));
    
    // 初始化定时器,用于性能测量

    HSM_TIM->TIM_CFG = 0x0008; // 禁用预分频器
    HSM_TIM->TIM_CTRL = 0x0001; // 开启定时器1
    
    // 记录开始时间

    Start = HSM_TIM->TIM_CNT0;
    STStart = STM0_COUNT;
    
    // 处理数据块

    while
 (num_blocks)
    {
        // 写入64字节数据到HASH_DATA寄存器

        for
 (i = 0; i < 16; i++)
        {
            HSM_HASH->HASH_DATA = pHOST2HSMbuf[(block_num * 16) + i];
        }
        
        if
 (--num_blocks > 0)
        {
            // 等待数据FIFO非满,确保可以继续写入数据

            while
 ((HSM_HASH->HASH_STAT & HASH_STAT_DF_NF_Msk) != HASHSTAT_FIFO_NOT_FULL)
                ;
        }
        
        block_num += 1;
    }
    
    // 等待哈希计算完成

    while
 ((HSM_HASH->HASH_STAT & HASH_STAT_BSY_Msk) == HASHSTAT_BSY)
        ;
    
    // 读取哈希结果

    i = 0;
    while
 ((HSM_HASH->HASH_STAT & HASH_STAT_CNT_Msk) != 0x0)
    {
        pHSM2HOSTbuf[i++] = HSM_HASH->HASH_VAL;
    }
    
    // 记录结束时间,用于性能分析

    if
(overflow > 0)
        Finish = HSM_TIM->TIM_CNT0 + 0xFFFF;
    else

        Finish = HSM_TIM->TIM_CNT0;
    STFinish = STM0_COUNT;
    Total = Finish - Start;
    STTotal = STFinish - STStart;
}

3.4.2 TriCore端实现(IfxHsm_HASH.c)

void hsm_hash_sha256_Test(unsigned int num_blocks)
{
    uint32 i;
    
    // 初始化标志,用于等待HSM处理完成

    HashProcessEnd = FALSE;
    
    // 清空缓冲区,准备数据

    for
 (i = 0; i < (16 * num_blocks); i += 1)
    {
        HOST2HSMbuf[i] = 0;
        HSM2HOSTbuf[i] = 0;
    }
    
    // 准备测试数据

    if
 (num_blocks == HASH_ONE_BLOCK)
    {
        // 单个数据块(512位)

        HOST2HSMbuf[0] = 0x61626380; // "abc" + 0x80填充
        HOST2HSMbuf[15] = 0x18; // 24位长度
    }
    else
 if (num_blocks == HASH_TWO_BLOCKS)
    {
        // 两个数据块(1024位)

        HOST2HSMbuf[0] = 0x61626300; // "abc0"
        HOST2HSMbuf[16] = 0x01020304; // "1234"
        HOST2HSMbuf[17] = 0x05060708; // "5678"
        HOST2HSMbuf[18] = 0x09800000; // "9" + 0x80填充
        HOST2HSMbuf[31] = 0x248; // 584位长度
    }
    
    // 设置数据块数并触发HSM中断

    HSM_HT2HSMS.U = num_blocks; // 要哈希的512位数据块数
    HSM_HT2HSMF.U = (1 << CMD_HASH_SHA_256); // 向HSM发出中断
    
    // 等待处理完成

    while
 (!HashProcessEnd)
        ;
    
    // 验证响应状态

    if
 (HSM_HSM2HTS.U != (0xCCCC0000 | CMD_HASH_SHA_256))
        __debug(); // 响应不正确或超时
    
    // 验证结果

    for
 (i = 0; i < 8; i += 1)
    {
        if
 (HSM2HOSTbuf[i] != SHA256_Val[num_blocks - 1][i])
        {
            DBG_Store_Trace(str_dbg("HASH"), str_dbg("-SHA"), str_dbg("-256"),
                    str_dbg("FAIL"), i, HSM2HOSTbuf[i], 0xE003);
            __debug();
        }
    }
}

3.5 代码说明

注意:上述代码中的寄存器命名(如HSM_HASH->HASH_CFG、HSM_TIM等)为示例逻辑,实际使用时需根据芯片手册替换为正确的寄存器地址和位定义。TC3xx系列的HSM哈希模块实际名称可能为HASH或HASH_ACC,具体寄存器定义请参考英飞凌官方文档。

4. HSM初始化步骤

4.1 时钟使能

  1. 1. 使能HSM模块时钟

    // 使能HSM时钟
    Ccu60_CLC.B.DISR = 0; // 清除HSM时钟禁用位
    while
     (Ccu60_CLC.B.DISS != 0); // 等待时钟使能完成

4.2 释放HSM复位

  1. 1. 释放HSM复位

    // 释放HSM复位
    HSM_RSTSTAT.B.RST = 1; // 触发HSM复位
    while
     (HSM_RSTSTAT.B.RST != 0); // 等待复位完成

4.3 HSM固件加载

  1. 1. 加载HSM固件

    // 加载HSM固件到HSM代码RAM
    memcpy
    ((void*)HSM_CODE_RAM_BASE, hsm_firmware, hsm_firmware_size);

    // 启动HSM

    HSM_CTL.B.START = 1; // 启动HSM执行

4.4 共享内存配置

  1. 1. 配置共享内存区域

    // 设置共享内存基地址
    HSM_SAHBASE.B.ADDRESS = (uint32_t)HOST2HSMbuf >> 16;

4.5 中断配置

  1. 1. 配置HSM中断

    // 配置HSM到主机的中断
    HSM_IGCR0.B.IRQEN = 1; // 使能HSM中断

    // 配置中断路由器

    SRC_HSM.B.SRE = 1; // 使能服务请求
    SRC_HSM.B.TOS = 3; // 设置服务优先级
    SRC_HSM.B.SRR = 1; // 清除服务请求

5. TC3xx单片机TriCore与HSM数据传递机制

5.1 TC3xx通信架构

5.2 TC3xx数据传递流程

  1. 1. 数据准备:TriCore在HOST2HSMbuf中准备待哈希的数据,包括数据填充和长度信息
  2. 2. 参数设置:通过HSM_HT2HSMS(主机到HSM状态)设置数据块数等参数
  3. 3. 触发中断:设置HSM_HT2HSMF触发HSM中断,通知HSM开始处理
  4. 4. HSM处理:HSM执行SHA-256哈希计算,包括数据读取、哈希运算和结果生成
  5. 5. 结果返回:HSM将计算结果写入HSM2HOSTbuf
  6. 6. 状态通知:HSM设置HSM_HSM2HTS并触发TriCore中断,通知TriCore处理完成
  7. 7. 结果验证:TriCore读取结果并与预期值比较,验证计算正确性

5.3 数据传输优化

5.4 DMA传输优化

  1. 1. 配置DMA通道

    // 配置DMA通道用于HSM数据传输
    IfxDma_Dma_Config dmaConfig;
    IfxDma_Dma_initModuleConfig(&dmaConfig, &MODULE_DMA);
    IfxDma_Dma_initModule(&g_dma, &dmaConfig);

    // 配置DMA通道

    IfxDma_ChannelConfig channelConfig;
    IfxDma_Channel_initConfig(&channelConfig, &g_dma);
    channelConfig.channelId = IfxDma_ChannelId_0;
    channelConfig.transferCount = 16; // 每次传输16个32位字(64字节)
    channelConfig.sourceAddress = (uint32)&HOST2HSMbuf[0];
    channelConfig.destinationAddress = (uint32)&HSM_HASH->HASH_DATA;
    channelConfig.transferMode = IfxDma_ChannelTransferMode_continuous;
    channelConfig.requestSource = IfxDma_ChannelRequestSource_software;
    IfxDma_Channel_init(&g_dmaChannel, &channelConfig);
  2. 2. 使用DMA传输数据

    // 启动DMA传输
    IfxDma_Channel_start(&g_dmaChannel);

    // 等待DMA传输完成

    while
     (IfxDma_Channel_getStatus(&g_dmaChannel) == IfxDma_ChannelStatus_busy);

6. TC3xx单片机SHA-256使用方法

6.1 初始化配置

  1. 1. HSM初始化:确保HSM已正确初始化,包括时钟配置、电源管理和安全配置
  2. 2. 缓冲区设置:配置HOST2HSMbufHSM2HOSTbuf缓冲区,确保内存分配正确
  3. 3. 中断配置:配置HSM中断处理,包括中断向量表设置和中断优先级配置
  4. 4. 时钟配置:确保HSM时钟配置正确,以获得最佳性能

6.2 数据准备

  1. 1. 数据填充:根据SHA-256标准对数据进行填充,包括:
  2. 2. 字节序处理

    // 注意:SHA-256标准使用大端字节序,需要确保数据正确处理
    // 方法1:通过HASH_CFG配置字节序

    HSM_HASH->HASH_CFG |= (HASH_ORDER_IN_MSW_FIRST << HASH_CFG_ORDER_IN_Pos);

    // 方法2:手动转换字节序

    uint32_t
     swap_endian(uint32_t value) {
        return
     ((value >> 24) & 0x000000FF) |
               ((value >> 8) & 0x0000FF00) |
               ((value << 8) & 0x00FF0000) |
               ((value << 24) & 0xFF000000);
    }
  3. 3. 正确的数据填充实现

    // 正确的SHA-256数据填充
    void
     sha256_pad(uint8_t *data, uint32_t length, uint32_t *padded_data, uint32_t *num_blocks) {
        uint32_t
     i, pad_length;
        uint64_t
     bit_length = (uint64_t)length * 8;
        
        // 计算需要的数据块数

        *num_blocks = (length + 9 + 63) / 64; // 1字节0x80 + 8字节长度 + 填充
        
        // 清空填充数据

        memset
    (padded_data, 0, (*num_blocks) * 16 * 4);
        
        // 复制原始数据

        memcpy
    (padded_data, data, length);
        
        // 添加0x80

        padded_data[length / 4] |= 0x80 << ((length % 4) * 8);
        
        // 添加长度(大端)

        uint32_t
     last_word = (*num_blocks * 16) - 1;
        padded_data[last_word] = (uint32_t)(bit_length & 0xFFFFFFFF);
        padded_data[last_word - 1] = (uint32_t)(bit_length >> 32);
    }

6.3 执行哈希计算

  1. 1. 设置参数:通过HSM_HT2HSMS设置数据块数
  2. 2. 触发HSM:设置HSM_HT2HSMF触发SHA-256计算
  3. 3. 等待完成:等待HSM处理完成,可以使用忙等待或事件通知
  4. 4. 获取结果:从HSM2HOSTbuf读取哈希结果,共8个32位字(256位)

6.4 结果验证

  1. 1. 状态检查:验证HSM_HSM2HTS状态,确保操作成功完成
  2. 2. 结果比较:将计算结果与预期值比较,验证计算正确性
  3. 3. 错误处理:处理可能的错误情况,如超时、硬件错误等

6.5 完整代码示例

// TC3xx SHA-256使用示例
void
 tc3xx_sha256_example(const uint8_t *data, uint32_t length, uint32_t *hash_result)
{
    uint32_t
 i, num_blocks;
    uint32_t
 padded_data[64]; // 最大支持512字节数据
    
    // 填充数据

    sha256_pad(data, length, padded_data, &num_blocks);
    
    // 清空缓冲区

    for
 (i = 0; i < (16 * num_blocks); i++) {
        HOST2HSMbuf[i] = 0;
        HSM2HOSTbuf[i] = 0;
    }
    
    // 复制填充后的数据到共享缓冲区

    for
 (i = 0; i < (16 * num_blocks); i++) {
        HOST2HSMbuf[i] = padded_data[i];
    }
    
    // 执行哈希计算

    HashProcessEnd = FALSE;
    HSM_HT2HSMS.U = num_blocks;
    HSM_HT2HSMF.U = (1 << CMD_HASH_SHA_256);
    
    // 等待完成(带超时检测)

    uint32_t
 start_time = get_system_time_ms();
    while
 (!HashProcessEnd) {
        if
 (get_system_time_ms() - start_time > 100) { // 100ms超时
            // 处理超时错误

            for
 (i = 0; i < 8; i++) {
                hash_result[i] = 0;
            }
            return
;
        }
    }
    
    // 验证结果

    if
 (HSM_HSM2HTS.U == (0xCCCC0000 | CMD_HASH_SHA_256)) {
        // 复制结果到输出缓冲区

        for
 (i = 0; i < 8; i++) {
            hash_result[i] = HSM2HOSTbuf[i];
        }
    } else {
        // 处理错误,返回全0

        for
 (i = 0; i < 8; i++) {
            hash_result[i] = 0;
        }
    }
}

// 使用示例

void
 example_usage(void)
{
    uint8_t
 test_data[] = "Hello, TC3xx SHA-256!";
    uint32_t
 hash_result[8];
    uint32_t
 i;
    
    // 计算SHA-256哈希

    tc3xx_sha256_example(test_data, sizeof(test_data) - 1, hash_result);
    
    // 打印结果

    printf
("SHA-256 hash: ");
    for
 (i = 0; i < 8; i++) {
        printf
("%08X ", hash_result[i]);
    }
    printf
(" ");
}

7. 执行效率优化

7.1 代码优化建议

  1. 1. 批量处理
  2. 2. 缓存优化
  3. 3. 并行处理
  4. 4. 数据填充优化
  5. 5. 硬件参数优化
  6. 6. 内存优化

7.2 性能测试

根据英飞凌官方文档和实测数据,SHA-256的执行时间取决于数据块数量:

7.3 性能优化案例

// 优化后的SHA-256批量处理函数
void
 tc3xx_sha256_batch(const uint8_t *data, uint32_t length, uint32_t *hash_result)
{
    uint32_t
 i, num_blocks, processed_blocks = 0;
    const
 uint8_t *current_data = data;
    uint32_t
 remaining_length = length;
    
    // 批量处理,每次最多处理4块数据

    while
 (remaining_length > 0) {
        // 计算本次处理的数据块数

        num_blocks = (remaining_length + 63) / 64;
        if
 (num_blocks > 4) num_blocks = 4; // 限制每次处理的块数
        
        // 准备数据

        uint32_t
 padded_data[64];
        sha256_pad(current_data, remaining_length > 4*64 ? 4*64 : remaining_length, padded_data, &num_blocks);
        
        // 复制到共享缓冲区

        for
 (i = 0; i < (16 * num_blocks); i++) {
            HOST2HSMbuf[i] = padded_data[i];
        }
        
        // 执行哈希计算

        HashProcessEnd = FALSE;
        HSM_HT2HSMS.U = num_blocks;
        HSM_HT2HSMF.U = (1 << CMD_HASH_SHA_256);
        
        // 等待完成

        while
 (!HashProcessEnd);
        
        // 处理结果

        if
 (processed_blocks == 0) {
            // 第一次处理,保存结果

            for
 (i = 0; i < 8; i++) {
                hash_result[i] = HSM2HOSTbuf[i];
            }
        } else {
            // 后续处理,需要合并哈希结果(复杂,实际应用中建议使用HSM的多部分哈希功能)

        }
        
        // 更新指针和长度

        current_data += num_blocks * 64;
        remaining_length -= num_blocks * 64;
        processed_blocks += num_blocks;
    }
}

8. 验证方法

8.1 结果验证

  1. 1. 预计算哈希值比较

    // 预计算的哈希值
    static
     const unsigned int SHA256_Val [2][8] = {
        {0xBA7816BF, 0x8F01CFEA, 0x414140DE, 0x5DAE2223, 0xB00361A3, 0x96177A9C, 0xB410FF61, 0xF20015AD}, // "abc"
        {0xf198213f, 0x738513eb, 0xfaab6a49, 0xf2915f47, 0xc8791536, 0xd01e0f42, 0xbfe654c0, 0x927ed6be}  // 测试数据
    };

    // 验证结果

    for
     (i = 0; i < 8; i += 1)
    {
        if
     (HSM2HOSTbuf[i] != SHA256_Val[num_blocks - 1][i])
        {
            // 验证失败,处理错误

            error_handler(ERROR_HASH_MISMATCH);
        }
    }
  2. 2. 响应状态验证

    // 验证HSM响应状态
    if
     (HSM_HSM2HTS.U != (0xCCCC0000 | CMD_HASH_SHA_256))
    {
        // 响应不正确或超时,处理错误

        error_handler(ERROR_HSM_RESPONSE);
    }
  3. 3. 自验证

8.2 常见错误处理

8.3 错误处理代码示例

// 错误处理函数
void
 error_handler(uint32_t error_code)
{
    switch
 (error_code)
    {
        case
 ERROR_HASH_MISMATCH:
            printf
("Error: Hash mismatch ");
            // 处理哈希不匹配错误

            break
;
        case
 ERROR_HSM_RESPONSE:
            printf
("Error: HSM response error ");
            // 处理HSM响应错误

            break
;
        case
 ERROR_TIMEOUT:
            printf
("Error: HSM timeout ");
            // 处理超时错误

            break
;
        default
:
            printf
("Error: Unknown error ");
            break
;
    }
    
    // 记录错误日志

    log_error(error_code);
    
    // 可能的恢复措施

    hsm_reset();
}

// 带超时检测的SHA-256计算

int
 tc3xx_sha256_with_timeout(const uint8_t *data, uint32_t length, uint32_t *hash_result, uint32_t timeout_ms)
{
    uint32_t
 start_time = get_system_time_ms();
    
    // 执行哈希计算

    tc3xx_sha256_example(data, length, hash_result);
    
    // 检查超时

    if
 (get_system_time_ms() - start_time > timeout_ms)
    {
        error_handler(ERROR_TIMEOUT);
        return
 ERROR_TIMEOUT;
    }
    
    return
 SUCCESS;
}

9. 调试方法

9.1 调试工具

  1. 1. DBG_Store_Trace:记录调试信息到内存缓冲区

    // 记录调试信息
    DBG_Store_Trace(str_dbg("HASH"), str_dbg("-SHA"), str_dbg("-256"),
            0x0
    , str_dbg("Strt"), num_blocks, 0x0);

    // 记录结果

    DBG_Store_Trace(str_dbg("HASH"), str_dbg("-SHA"), str_dbg("-256"),
            0x0
    , str_dbg("Done"), num_blocks, 0x0);
  2. 2. __debug():触发调试断点

    if (error_condition)
        __debug(); // 触发调试器断点
  3. 3. 内存查看
  4. 4. 性能分析

9.2 调试流程

  1. 1. 数据准备检查
  2. 2. HSM响应检查
  3. 3. 结果验证
  4. 4. 性能分析

9.3 常见问题及解决方法

问题
可能原因
解决方法
HSM无响应
中断配置错误
检查中断向量表和优先级配置
哈希结果错误
数据填充不正确
检查填充逻辑,确保符合SHA-256标准
性能不佳
数据传输效率低
优化缓冲区使用,使用批量处理和DMA
内存访问错误
缓冲区越界
增加边界检查,确保缓冲区大小足够
硬件错误
HSM配置错误
检查HSM时钟和电源配置

10. TC3xx单片机实际应用场景

10.1 安全启动 (Secure Boot)

10.2 安全通信

10.3 空中下载升级 (OTA)

10.4 数据完整性校验

10.5 密钥派生与安全存储

11. 多核系统使用注意事项

11.1 共享资源管理

11.2 中断处理

11.3 性能优化

12. 不同TC3xx型号的HSM差异

12.1 TC3xx系列HSM对比

型号
HSM版本
支持的哈希算法
国密SM3
公钥加密(PKC)
真随机数(TRNG)
HSM内存大小
应用场景举例
定位
TC33x
v1.0
SHA-256
无(仅软件)
小(8KB代码+4KB数据)
车身控制、简单安全启动
入门级
TC35x
v1.1
SHA-256, SHA-512
部分支持
中(16KB代码+8KB数据)
网关、区域控制器、OTA客户端
中档
TC37x
v2.0
SHA-256, SHA-512, SM3
支持ECDSA/ECC
有(AIS-31认证)
大(32KB代码+16KB数据)
自动驾驶域控、中央计算平台、V2X、国密合规产品
高端
TC39x
v2.0
SHA-256, SHA-512, SM3
支持ECDSA/ECC
有(AIS-31认证)
大(同TC37x)
自动驾驶域控、中央计算平台、V2X、国密合规产品
顶级

12.2 选型建议

13. 功耗和实时性分析

13.1 功耗分析

13.2 实时性分析

14. 完整示例项目结构

14.1 项目文件结构

HSM_SHA256_Demo/
├── 0_Src/
│   ├── AppSw/
│   │   ├── Tricore/
│   │   │   ├── MAIN_HSM.c          # 主应用
│   │   │   ├── HSM_Test_def.h      # 测试定义
│   │   │   └── HsmDemo/
│   │   │       ├── IfxHsm_HASH.c    # SHA-256测试
│   │   │       └── IfxHsm_TestsCommon.c  # 公共测试代码
│   │   └── ArmCortexM3/
│   │       └── code_hsm.c          # HSM端代码
│   └── BaseSw/
│       ├── iLLD/                    # Infineon Low Level Drivers
│       └── Service/                 # 基础服务
├── 1_Config/
│   ├── Config_Tricore_Tasking/      # Tasking编译配置
│   └── Config_Arm_Tasking/          # ARM编译配置
├── 2_Out/
│   ├── Tricore_Tasking/             # TriCore编译输出
│   └── Arm_Tasking/                 # ARM编译输出
├── Makefile                         # 主Makefile
└── README.md                        # 项目说明

14.2 Tasking编译器配置

# Tasking编译器配置

# 目标处理器
TARGET = tc39xa

# 包含路径
INCLUDES = -I0_Src/AppSw/Tricore \
           -I0_Src/AppSw/CpuGeneric/Config \
           -I0_Src/BaseSw/Service/CpuGeneric/SysSe/Bsp \
           -I0_Src/BaseSw/iLLD/TC39A/Tricore \
           -I0_Src/BaseSw/iLLD/TC39A/Tricore/Cpu/Std

# 编译选项
CFLAGS = -mtc39xa -O2 -g

# 链接选项
LDFLAGS = -liltd_tc39a -Tlinker.lsl

15. 同类密码算法

15.1 SHA系列算法

15.2 国密算法

15.3 其他哈希算法

15.4 算法选择建议

16. 总结

SHA-256是一种广泛应用的密码哈希算法,在英飞凌TC3xx单片机的HSM上通过硬件加速实现,可以提供高效、安全的哈希计算能力。通过本文档的介绍,您应该已经了解:

这些知识将帮助您在英飞凌TC3xx单片机项目中有效使用SHA-256功能,确保数据的安全性和完整性。通过合理的代码设计和优化,您可以充分发挥TC3xx HSM的性能优势,实现高效、安全的哈希计算应用。

参考文档

关于hsm开发大家在使用过程中欢迎一起交流学习:

support@softor.com.cn

tianpengbo@softor.com.cn


‘,
create_time: ‘2026-04-07 06:22’,
cdn_url: ‘https://mmbiz.qpic.cn/mmbiz_jpg/M9XQklgjm1eWKRHn7jicy8B1NkpzRtcMekROxjHk8Cy1ZZwu1xW0tqcjicJWwiaR3D5Y3YBCJ8Ofdov2TT6Bgh7KuTx79vRibHHZ6sy15Xl0mqA/0?wx_fmt=jpeg’,
link: ‘https://mp.weixin.qq.com/s/kuPWHvKk9qYbh6_YDPCQDQ’,
source_url: ”,
can_share: ‘0’ * 1,
alias: ”,
type: ‘9’ * 1,
author: ‘tianpb

作者与交流

作者:tianpengbo / 田朋博。大家如果在项目中遇到相关技术问题,欢迎联系我交流。
support@softor.com.cn
tianpengbo@softor.com.cn

作者与交流

作者:tianpengbo / 田朋博。大家如果在项目中遇到相关技术问题,欢迎联系我交流。
support@softor.com.cn
tianpengbo@softor.com.cn

作者与交流

作者:tianpengbo / 田朋博。大家如果在项目中遇到相关技术问题,欢迎联系我交流。
support@softor.com.cn
tianpengbo@softor.com.cn

作者与交流

作者:tianpengbo / 田朋博。大家如果在项目中遇到相关技术问题,欢迎联系我交流。
support@softor.com.cn
tianpengbo@softor.com.cn

在线留言