0  preface 基本概念缩写

TEE   Trusted Execution Environment   可信执行环境,通常用来进行数字版权管理(DRM : Digital Rights Management )、移动支付和敏感数据保护。TEE 的实现是基于 ARM TrustZone。

REE(Rich Execution Environment)是所有移动设备通用的环境,运行通用的 OS,例如 Android,IOS 系统, LINUX等。

OTP One-Time Programmable  一次性可编程

ATF        Arm Trusted Firmware  arm可信固件

OPTEE   Open Portable Trusted Execution Environment开放可移植可信执行环境

BLD        Bootloader  引导装载程序

BST         Bootstrap     引导

GP          Global Platform   全球平台

CA          Client Application  客户机应用程序

TA           Trusted Application受信任的应用程序(用户态执行),含有签名在安全世界

PTA        Pseudo ['sju:dəʊ]   TA  伪受信任的应用程序(在内核态执行),含有签名嵌入信任OS

AES        Advanced Encryption Standard 高级加密标准

RSA        An asymmetric cypher, RSA stands for its inventor’s names (Ron Rivest, Adi Shamir, and Leonard Adleman)  RSA是一个不对称密码,RSA代表其发明者的名字

SHA        Secure Hash Algorithm 安全哈希算法

SSL         Secure Socket Layer   安全套接字层

TLS         Transport Layer Secure 传输层安全

RPC        Remote Procedure Call  远程过程调用

DRM     Digital Rights Management,数字版权管理

svc:      supervisor call 应用程序调用kernel(el0-》el1)功能

hvc:    hypervisor call,os 调用hypervisor(EL2)

smc:     secure monitor call ,os or hypervisor 调用 secure monitor (El3)

spl:      Secondary Program Loader 第二阶段程序加载器   SPL是uboot第一阶段执行的代码. 主要负责搬移uboot第二阶段的代码到内存中运行. SPL   是由固化在芯片内部的ROM引导的

MLO(功能类似于spl) :  The ROM will initialise the SD/MMC device, detect a card and look for a boot image. The ROM bootloader is capable of reading from the card with a filesystem. It will search for a file named MLO which should be located on the boot partition, on a partition of type FAT16/32. So, this explains the name MLO

FSBL:First Stage Boot Loader: 第一阶段bootloader, 初始化DDR clock bus等

PBL: Primary Boot Loader:位于rom,芯片商的第一行代码,调到SBL1

SBL1: Second BootLoader stage 1:第一阶段bootloader, 初始化DDR clock bus等

tee_supplicant:  在正常世界中,用于安全世界访问REE的文件系统

ROT :Root of trust,写入OTP 的key

公钥,私钥,签名,证书基本概念的解释,请参照下文(漫画图文详解,浅显易懂)

https://www.cnblogs.com/xq1314/p/7918644.html

1  Arm TrustZone 介绍

Unlikely previous ambarella platform, Cv2x include Secure Rom

使引导过程能够在整个引导序列期间执行数字签名检查,安全ROM认证BST;BST重复使用安全ROM中的代码块(RSA / SHA)和ATF (BL2)认证。因此,不再需要RO引导分区

basic knowledge of arm trustzone:  https://blog.csdn.net/MageeLen/article/details/98294065

大致分为安全和不安全区域,安全区域可以访问非安全区域信息,反之不可以

1.1  什么是OPTEE-OS

https://www.cnblogs.com/dakewei/p/10267774.html

1.1.1  TEE 启动流程

OP-TEE必须尽可能早启动(因为如果BootLoader 运行优先于OP-TEE会带来缺陷是,触碰敏感数据)

1.  典型linux启动过程:rom 加载第一阶段BootLoader -》第二阶段BootLoader -》linux内核 (安全世界上下文)

2.  ARMV7(附含TEE): SPL 加载OP-TEE和U-BOOT,跳转到OP-TEE,OP-TEE初始化完毕,OP-TEE会切换到非安全上下文,并且跳转到U-BOOT中,OP-TEE代码继续放在内存中,以便为内核提供安全服务。

3. ARMV8(附含TEE):TEE 启动流程涉及一个SPL加载ATF的步骤,SPL 跳转到ATF firmware,这个firmware随后和OP-TEE共同协作,然后OP-TEE 转而跳转到处于非安全上下文的U-BOOT。

4. 在一个ARMV8平台上,ATF提供一个监视器代码去管理安全世界和非安全世界之间切换,而在ARMV7这一功能被嵌入到OP-TEE中。

1.1.2  最小化应用程序修改

为了访问硬件特性,许多安全芯片给用户空间程序提供OpenSSL引擎接口。一个相同的模型能够通过开发一个TEE client app作为OpenSSL引擎与TA之间的接口,因此能够最小化用户空间程序的任何修改。Trusted Application将需要实现密钥管理和加密操作等接口。OP-TEE OS包含libtomcrypt,这个库提供各种各样的对称/非对称/椭圆曲线加密函数,因此TA 大部分工作是负责输入校验和调用合适的OP-TEE 核心API。

2  基本安全的概念

2.1  Chain of Trust

2.2  Secure and Normal World

2.3   RSA

是一种公钥加密系统,用于数据加密。(有一个加密和解密),加密是公钥,解密是私钥

是一种asymmetry(不对称的) 的加密系统. 在RSA中,这种不对称的困难点是基于两个大素数(primer number)乘积(product)的因数分解。RSA 相对较慢,所以不用做直接对数据加密,而是用于对对称密钥加密的共享密钥进行加密,该方法能以高得多的速率执行大量加密-解密操作

CV2x 的secure rom就是包含RSA2048支持,代码量很小

公钥和私钥参考:https://blog.csdn.net/qq_33369979/article/details/88708513

3  安全启动

3.1  About Secure Boot

Secure boot会在boot的每个阶段都做加密检测,避免在running时候不授权或者恶意修改软件。所以启动应该在ROM而不是在RAM。 常用RSA 加密算法,可以生成一个公钥和一个私钥,每个阶段的bin文件,user都用私钥生成一个签名附在bin文件后面。然后将公钥写入一次性写入(OTP,one time programming)的memory(efuse, 通常只有128bit)。

3.2  Secure Boot Flow

启动时,安全的ROM将去从OTP memory中读取RSA 公钥,再去检查RST bin文件的完整性,然后RST bin文件将用该公钥或者由本公钥生成的公钥去验证ATF的完整性,然后ATF验证BLD,BLD验证linux bin文件的完整性。

当然除了ROM从OTP读取RSA公钥外,后面生成的公钥都可以放在NAND中,其完整性由chain of trust 的方法保证。写入OTP memory的公钥称为Root of trust(ROT)。由secure ROM 中先运行的代码具有数字签名授权的能力。” secure ROM” + “ROT in OTP” + “ATF”组合可以对启动过程搭建一个完整的授权chain。从secure ROM的第一条指令到Rich OS/Trust OS启动结束,所有的模块都经过了授权。(Rich OS 主要有linux,Trust OS有OP-TEE等OS)。

下图描述了安全启动流程,黑线为启动顺序,蓝线为授权公钥和授权目标。

通常我们需要cover从secure boot -> BST(BL1)->ATF(BL2),  ATF可以cover ATF->BLD->Linux, 和ATF->OP-TEE。

在生成bin文件时,SHA256 算法将为bin文件生成数字签名,然后用RSA私钥去为签名加密。

在启动阶段时候,每个启动过程都将用SHA256算法根据公钥为后一级的过程生成数字签名,然后和SHA256解密签名(私钥加密的) 做对比。BST和ATF 可以从OTP memory拿root 公钥去授权,后续阶段的授权需要去拿由公钥生成的公钥去完成。

总之就是通常先RSA算法生成一个公钥和私钥,私钥先生成签名附在bin文件后面,公钥写入OTP memory。启动阶段,根据trust chain,前一阶段的公钥生成下一阶段的公钥,每个阶段的公钥生成签名去和之前由私钥生成的签名作对比。

3.3  ATF

在EL3阶段,包含安全监测功能(BL31~BL32)。EL0~EL2阶段由于不在trust zone,不能访问安全相关的寄存器和设备,但是EL3就在trust zone,可以访问所有寄存器和设备。

ATF中做初始化异常向量表,控制寄存区,平台中断,使能标准ARM IP,包括GIC(generic interrupt controller),cache,NIC(network interrupt controller), TZC(trust zone controller), 实现由secure monitor 到normal 连接。

ATF 通过认证延伸(hash ,公钥,无volatile 计数器)来搭建一套trust chain。

下图阐述了ATF中有证书的信任链。

3.4  Memory Layout

Secure world 和 normal world的memory是相互独立的。但是secure world可以访问non-secure world的memory。

Major

Sub1

Sub2

Start Address

End Address

Total Size

Secure World Memory

ATF (BL2)

-

0x00000000

0x0007FFFF

512KB

ATF (BL31)

-

0x00080000

0x000FFFFF

512KB

OPTEE (BL32)

TEE memory

0x00100000

0x001FFFFF

1MB

TA memory

0x00200000

0x00BFFFFF

10MB

Normal World memory

Share memory

-

0x00C00000

0x01000000

4MB

Linux BLD (BL33)

-

0x01000000

0x010FFFFF

1MB

Block Buffer

-

0x01100000

0x011FFFFF

1MB

Left memory

-

0x01200000

-

Total Size - 18MB

4  TrustZone

描述了安全启动后trust zone的实现,包含安全世界OS,TA/CA,  UUID/KEY

4.1  OPTEE

OPTEE是用的全球平台TEE标准,Rich OS(linux)可以用全球平台标准的TEE client API 去访问trust OS。TEE client API同样可以在TEE内触发APP的安全执行。OP-TEE包含完整的开足正常世界的栈,如Client API(OP-TEE_client), Linux kernel TEE driver(op-tee_linuxdriver),trust OS+, secure moniter, test_suite(xtest).

4.2  TA and CA

TA           Trusted Application受信任的应用程序(用户态执行),含有签名在安全世界

PTA        Pseudo ['sju:dəʊ]   TA  伪受信任的应用程序(在内核态执行),含有签名嵌入信任OS

每个TA都有一个UUID 作为其身份,当需要访问Normal TA时候,在其被签名验证通过后,TEE发送访问安全世界请求,将由tee-supplicant 加载到安全世界,tee-supplicant(常驻进程)访问流程图如下。

  从tee_supplicant处理来自TEE侧的请求来看主要是有三个点。

  第一是驱动在触发smc操作之后会进入到loop循环中,根据secure world中的返回值来判定该返回时来自TEE的RPC请求还是最终处理结果,如果是RPC请求,也就是需要驱动或者tee_supplicant执行其他操作,驱动将RPC请求会保存到驱动的请求消息队列中,然后block住等待请求处理结果。

  第二是在tee_supplicant作为一个常驻进程存在于REE中,它会不停的尝试从驱动的请求消息队列中获取到来自TEE侧的请求。如果请求消息队列中并没有请求则会block住,直到拿到了请求才返回。拿到请求之后会对请求进行解析,然后根据func执行具体的操作。

  第三是在tee_supplicant处理完来自TEE的请求后,会调用send操作将处理结果存放到该消息队列的参数区域,并使用complete函数通知驱动该请求已经被处理完毕。驱动block住的地方可以继续往下执行,调用smc操作将结果返回给TEE侧

参考:https://blog.csdn.net/shuaifengyun/article/details/72934531

4.2.1  AES Example for TA/CA

部分常用的库的链接

TEE_Client_API: optee_client\libteec

TEE_Internal_API: optee_os\lib\libutee\include

OP-TEE driver: kernel\linux\drivers\tee\optee

RPC Service: optee_client\tee-supplicant(常用于当私钥不能被工程师知道时,将私钥用RPC 远程获取)

AES :Advanced Encryption Standard高级加密标准

#define DATA_ENCRYPTION_AES_UUID_ID {0xabb6f4b5, 0x7e33, 0x4ad2, \

{ \

0x98, 0x02, 0xe6, 0x4f, 0x2a, 0x7c, 0xc2, 0x0c \

} \

}

abb6f4b5-7e33-4ad2-9802-e64f2a7cc20c作为加密和解密的密码

test_data_encryption_aes's options

'--inputfile [%s]': input file for encryption/decryption

'--outputfile [%s]': output encrypted/decrypted file

'--aesmode: supported aes mode :  CBC, ECB, CTR or CTS

'--aesoper': enc or dec

'--len': 128, 192 or 256

加密解密过程cmd,编辑a.c文件后执行下面的cmd,再cat c 文件,会发现a.c和c文件是一样的(当然本app属于私有的,不能share,依赖driver,不能公开,大致提供一种实现的方式)

test_data_encryption_aes --inputfile a.c --outputfile b --aesmode CBC --aesope

r enc  --len 128

输入密码:abb6f4b5-7e33-4ad2-9802-e64f2a7cc20c

test_data_encryption_aes --inputfile b --outputfile c --aesmode CBC --aesoper

dec  --len 128

输入密码:abb6f4b5-7e33-4ad2-9802-e64f2a7cc20c

4.3  Device Unique ID and Key

为了避免硬件clone,每个芯片出厂时会有个unique ID 存在它的固件中,签名用RSA root 私钥加密,在安全启动阶段,设备unique ID 的签名必须确认无误。设备unique ID可用于获取设备独有的加密key,该加密key只能被安全世界访问,不能被修改。(应用场景:当授权licence时候,客户从算法商买了有限个licence,每个licence对应一个unique ID,为了防止客户生成的每个板子unique ID 设置为相同,算法商会保存一份私钥,check 固件的unique ID,但是万一固件的unique ID被改变了,还有一套保险机制芯片厂商在软件(so,等处不能破解)维护一份unique ID,算法商将固件的unique ID和芯片上的so维护的unique ID做对比,如果不同,在芯片厂商的软件上会处理)。

OPTEE 使用设备独有的加密key使能正常世界的安全存储,如下图所示:

5  OTP

5.1  OTP Data Layout

128bits~32k bits

通常有一个bit的zone lock的bit,可以将其他所有bit的值lock住不能修改,该bit为一次性修改的。

5.2  Program OTP

OTP 可以由CA和PTA来编写,通常会将pubkey 写入OTP中

5.3  Read Unique ID

5.3.1  Read Unique ID with TrustZone Enabled

5.3.2  Read Unique ID with TrustZone Disabled

6  安全计数

6.1  Boot Protection

Secure ROM 确保启动第一阶段的code是只读的,RSA 公钥也是一次性写入OTP,每个启动阶段都会check 签名的,以保证每个阶段启动的完整性,当在任何阶段的一个签名失败时,启动暂停,返回error 信息。

使能安全启动,然后生成key,CA 和PTA会允许写入OTP中。包含写入pubkey,读pubkey,lock pubkey,等操作(软件行为)

6.2  Trusted Execution Environment

为了确保一个可信的执行环境,一个专用的操作系统OPTEE被用来实现secure world软件。这种体系结构最大限度地隔离了安全和正常的世界。敏感数据在安全环境中存储和处理,然后与正常环境进行通信。

OPTEE为所有安全世界应用程序提供基础设施,以及安全和正常世界应用程序之间的接口。安全应用程序作为服务提供者执行,并使用来自Arm信任区的安全监视器过程响应正常应用程序。

6.3  Data Protection

敏感数据在OPTEE安全世界中受到保护,这意味着普通世界应用程序不能访问它。因此,如果一个普通应用程序需要访问敏感数据,建议将该应用程序分成两部分:(1)不需要访问敏感数据的普通应用程序中的CA应用程序, (2)能够处理敏感数据并提供反馈的TA应用程序。

为了在正常情况下保护敏感数据,使用DRAM置乱特性,确保原始数据不能从置乱的数据中得到。置乱方法采用AES等对称数据加密方法。为了保护移动中的数据,建议使用诸如Open SSL等传输层安全方法。

常用为敏感/私有数据加密,4.3小节例子会show怎么样在安全世界中加密数据。

数据加密的key因为不能暴露于正常世界,建议写入OTP,

6.4  Anti-Hardware Clone

有两种硬件克隆方法:包括NAND的复制克隆和带有制造软件的克隆。

为了防止包括NAND在内的硬件复制克隆,制造商可以在每台设备的固件上安装一个唯一的加密密钥。

虽然带有制造软件的克隆存在复杂的安全问题,但在大规模生产过程中激活每台设备(使用私钥为每个芯片分配唯一的ID),防止没有私钥在克隆设备上生成正确数字签名的攻击者。为了确保克隆设备的安全性,建议用户在引导阶段和应用程序中执行数字签名验证。

6.5  Anti-Rollback Attack

为了绕过安全引导,攻击者试图重新编写以前易受攻击的固件。然而,Ambarella在OTP内部包含一个单调计数器,以防止重编程。每个固件编程操作的单调计数器持续增加。因此,在引导过程中检查单调计数器(monotonic counter)有助于防止反回滚攻击。

6.6  Accelerated Crypto Engine

加速加密引擎

CV2x的CPU是四核ARM®-A53。它支持Armv8加密扩展。

加密扩展增加了新的A64, A32,和T32指令的高级SIMD,可对以下加密方法加速:

1 高级加密标准(AES)加密和解密。

2 安全哈希算法(SHA)函数SHA-1、SHA-224和SHA-256。

3 有限域算术用于算法,如Galois/计数器模式和椭圆曲线加密。

7  密钥管理

安全性的一个重要方面是密钥管理。在生成支持安全引导特性的二进制文件时,用户必须生成并存储私钥。这些私钥对于维护安全引导特性的安全性非常重要。

ATF和OPTEE没有成熟的密钥管理机制,因此客户编译ATF或OPTEE时,如果项目中有多位工程师,能够访问私钥比较严重的。注意,如果系统的默认密钥管理是在ATF / OPTEE中,则可能会出现安全问题。

7.1  Local Key Management

结合上文,主要有三种key:

1  安全启动需要ROT key,

2  linux 内核验证的key

3  为TA binary验证的TA key

•应该将ROT公钥(rot_public.bin)编程到OTP中,因为它是所有其他证书的根密钥。

ATF key来自于ATF的CoT中的ROT key。默认情况下,这些key在每个编译阶段生成。在这种情况下,不需要保存这些密钥(ROT密钥除外)。

•对于OPTEE, TA公钥被嵌入到OPTEE- os二进制文件中。

•对于Linux认证内核,内核公钥被嵌入到Amboot二进制文件中。

•由于boot和opte - os在执行前都经过身份验证,因此它们的公钥会自动进行身份验证,这比从OTP读取公钥更容易。

7.2  RPC Development Toolkit Overview

为了防止key的泄露,可以用RPC(remote procedure call) 的方式限制私钥由管理者管理,其它开发者,能够在不访问私钥时候也能编译ATF/OPTEE. 这套工具在开发者侧含一个dameon进程和保护伞,

下图显示了开发工具包的三个组件:开发服务器、守护进程和工具代理。开发人员共享一个服务器,而每个开发人员应该有自己的守护程序和工具代理。

因为保留私钥的开发服务器是由管理员控制的,所以只有管理员可以直接访问私钥。开发服务器通过TLS连接提供私钥相关的服务,称为RPC(远程过程调用)。

每个开发人员端都包括一个守护程序和工具代理。守护进程程序保持与开发服务器的TLS连接,并在开发服务器和工具代理之间中继请求/响应。

开发服务器和守护进程程序之间存在相互身份验证,以保证私有密钥相关RPC只适用于经过批准的开发人员;服务器生成使用口令加密的身份密钥对和自签名证书,开发人员生成同样使用口令加密的身份密钥对)。服务器维护一个开发帐户数据库,并手动批准开发帐户。开发人员使用他的口令运行他的守护程序和登录服务器。

工具代理提供与ATF / OPTEE中的原始工具相同的服务,但有一个例外:私钥不是本地的—它们存在于远程服务器端。

8  Guide

正常可以提供生成key,编译方法和用安全启动和trustzone生成的bin文件。

8.1  Generate Local Keys and Compile

在编译bin文件之前,sdk可以生成本地key以替换默认的key,保证openSSL 加载进编译器,此时在本地编译服务器可以生成新的key。

8.1.1  Generate New Keys

通常,这些Keys只需要生成一次。生成后,保持私钥的机密性。生成一对新的ROT密钥(包括公钥 bin文件):

用户在生成ROT密钥时应谨慎使用。在继续之前,确保生成是必要的。生成后,备份ROT密钥对。如果其中一个密钥丢失,验证过程将不会通过,系统将无法工作。

8.1.2  Derive ROT Public Key (Optional)

如果用户已经有一个私有ROT密钥,需要有命令生成相应的二进制格式的公钥。这一步非常重要,因为公钥bin将以bin格式被编进OTP。

可以根据ROT 私钥推到出ROT公钥,然后其他公钥可以在编译过程中生成。因此,如果用户希望使用现有的私钥,就需要替换默认的公钥。

8.2  Deploy the Remote Keys and Compile

8.2.1  Compile Toolkit

需要编译出develop server,daemon,tool proxy(工具代理)

8.2.2  Set up the RPC Environment

1. 第一次,您需要生成服务器密钥和服务器证书,先让服务器运行。

2 . developer在用安全启动feature编译sdk之前,第一次,你应该获取服务器的公钥并生成守护进程的私钥和公钥,运行developer守护进程(需要server的公钥)(如果同一台构建机器上有多个帐户,则每个帐户有一个守护进程和一个本地端口)

3. 通过openSSL 让deamon和server建立连接

4. 守护进程运行前,注册你的帐户,输入"your_account_name" + ENTER,然后等待管理员的批准(在服务器控制台输入'y' + ENTER)。在管理员批准之后,您可以使用存储在服务器端的私有密钥进行编译。

8.3  Run Secure Boot

通常会设计跳线帽,进入安全启动模式,然后重启根据log看是否进入secure boot

最后想要跟各位推荐一本书:图解密码技术(日本作家(结城浩),译(周自恒))

目标读者: 对密码相关知识感兴趣的人; 希望理解公钥密码,数字签名等密码技术原理的人; 对信息安全感兴趣的人;

OP-TEE基本的从芯片设计到给客户的安全问题浅析相关推荐

  1. 重磅!中国电信研究院、浦发银行、冲量在线和中国信通院联合发布-隐私计算之TEE技术实践分析

    隐私计算之TEE技术和应用实践分析 大数据时代,数据流通.安全等问题接踵而至. 据IDC预测,全球数据总量预计2020年达到44ZB,我国数据量将达到8060EB,占全球数据总量的18%.2025年全 ...

  2. 【CA-TA实战系列六】CA与TA背后的故事一:TEE OS

    一.前言 TEE OS就是可信环境的操作系统,这里我们的参考资料是前辈的<手机安全和可信应用开发指南>,因此这里我们的TEE OS就是OP TEE. 那么为什么在搞TA CA的设计实现要关 ...

  3. 我的世界java服务器刷_一个教程, 叫你如何在服务器刷op

    教 你 如 何 在 服 务 器 内 刷 取op~! 首先打开JAVA文件夹 找到bin\client 里面的Xusage 然后打开 然后会得到这个内容 -Xmixed           mixed ...

  4. 2023年你最值得了解的信息技术-国内篇

    一.信息安全相关 二.数字化转型相关 智慧城市科技:是一家智慧政务解决方案提供商,运用云计算.大数据.物联网等技术,建设电子政务网.政务云.大数据能力平台.互联网+政务服务平台.政务服务机构信息化设施 ...

  5. 嵌入式开发工具介绍与下载

    ARM RealView 2.2 (微电子设计) 下载地址:http://www.9iv.com/down/soft/274.htm?eid=217990                     ht ...

  6. 从多核到众核处理器究竟经历了什么?

    halo,大家好,我是彦祖,今天来和大家唠唠多核到众核处理器的历程,大家系好安全带,准备发车! 其实"多核"这个词已经流行很多年了,世界上第一款商用的非嵌入式多核处理器是2002年 ...

  7. MPS——超小尺寸 IEEE802.3af PD 解决方案

    MPS--超小尺寸 IEEE802.3af PD 解决方案 PoE 电子产品发展到今天,其功能越来越多,尺寸越来越小,设计越来越简单. Q:如何用最简单的芯片设计出为客户创造最大价值的产品? A:功能 ...

  8. 对话PlatON曲俊杰:隐私计算市场爆发尚需4个条件 |链捕手

    隐私计算越来越成为区块链行业的重点发展方向,PlatON作为主打隐私计算的知名项目,致力于成为全球新一代隐私计算和分布式经济体基础设施,其投资方包括万向区块链.复星集团联合创始人梁信军.Hashkey ...

  9. 2019年终总结-浅谈SAP S4 HANA CLOUD项目

    从2015年陆续发布,2018年落地中国,伴随着2019年第一个Cloud项目的成功上线,SAP首推的SaaS产品S/4 HANA Cloud(简称S4HC)正式进军中国云ERP市场.SAP将其目标市 ...

最新文章

  1. Loadrunner的Tuxedo脚本分析,基本流程和基本函数介绍
  2. redis 启动时 Warning 警告解决及说明
  3. 推送公司今日菜单内容到手机
  4. android生成aar无效,android studio生成aar包并在其他工程引用aar包的方法
  5. CANOpen同步报文
  6. eclipse插件本地扩展安装
  7. Vue2 使用Volar 报错:<template v-for> key should be placed on the <template> tag
  8. VR/AR平台战略与实践(1)
  9. L2-014. 列车调度-PAT团体程序设计天梯赛GPLT
  10. IPsec的NAT穿越详解
  11. 如何彻底修改SQL server的数据库名
  12. 台达触摸屏编程软件(Scredit)官方免费版 v2.00.23
  13. 注册美国iTunes账号步骤(跳过绑定银行卡)
  14. XZ_Swift 之HealthKit 获取手机计步统计
  15. 初中数学抽象教学的案例_初中数学数形结合思想教学研究与案例分析
  16. postman测试是否支持跨域_POSTMAN接口测试
  17. 浅谈python运算符运算法则
  18. DNS解析与CDN加速
  19. 第四十天 阿乐在其中—Android小游戏的飞机(四)加入敌人
  20. 中国石油大学《计算机网络课程设计》第三次在线作业

热门文章

  1. Bootstrap 图片轮播
  2. 如何用计算机制作动态图,怎么制作Gif动画?用电脑制作Gif动图
  3. ZOJ 3587 Marlon's String 扩展KMP
  4. 怎么删除计算机的打印机设备,win7系统的打印机删除不掉怎么办?完美解决方法看这里!...
  5. ArchLinux安装完成登陆时出现login incorrect错误
  6. 人工智能助力未来教育
  7. sql 注入_商洛学院司徒荆_新浪博客
  8. uniapp 搜索关键字高亮显示实现
  9. eclipse 左侧导航栏不见怎么办
  10. JAVA——实现输出1~1000之间既能被3整除也能被5整除的数,并每行打印5个数。