• 实验一密码引擎加密API研究


    实验一-密码引擎-加密API研究

    密码引擎API的主要标准和规范包括:
    1 微软的Crypto API
    2 RAS公司的PKCS#11标准
    3 中国商用密码标准:GMT 0016-2012 智能密码钥匙密码应用接口规范,GMT 0018-2012密码设备应用接口规范等

    研究以上API接口,总结他们的异同,并以龙脉GM3000Key为例,写出调用不同接口的代码,提交博客链接和代码链接。
    内容:
    0 查找各种标准的原始文档,研究学习(至少包含Crypto API,PKCS#11,GMT 0016-2012,GMT 0018-2012)(5分)
    1 总结这些API在编程中的使用方式(5分)
    2 列出这些API包含的函数,进行分类,并总结它们的异同(10分)
    3 以龙脉GM3000Key为例,写出调用不同接口的代码(Crypto API,PKCS#11,SKF接口),把运行截图加入博客,并提供代码链接(10分)

    CryptoAPI

    CryptoAPI 是微软提供的一组加密函数。其功能是为应用程序开发者提供在 Win32环境下使用加密、验证等安全服务时的标准加密接口。CryptoAPI 处于应用程序和CSP (CryptographicService Provider)之间。

    CryptoAPI 的组成

    CryptoAPI由简单消息函数(Simplified Message Functions)、低层消息函数(Low-level MessageFunctions)、基本加密函数(Base Cryptographic Functions)、证书编解码函数(Certificate EncodelDecode Functions)和证书库管理函数(Certificate Store Functions)5部分组成。其中前三者可用于对敏感信息进行加密或签名处理,从而保证网络传输信息的保密、防篡改、防抵赖等;后两者是对证书的操作,实现身份的认证。

    密码服务提供者 CSP函数

    CryptoAPI 的密码服务提供者函数主要包括6个函数。连接或断开 CSP函数CryptAcquireContext、CryptReleaseContext,枚举CSP函数 CryptEnumProviders,获得或设置默认CSP函数CryptGetDefaultProvider、CryptSetProvider,获取或设置CSP参数函数CryptGetProvParam、CryptSetProvParam。

    1.接CSP函数CryptAcquireContext

    函数功能:连接CSP,获得指定CSP的密钥容器的句柄。函数定义:

    BOOL WINAPI CryptAcquireContext(HCRYPTPROV *phProv,
    LPCTSTR pszContainer,
    LPCTSTRpszProvider,
    DWORD.dwProvType,
    DWORD dwFlags);
    

    参数说明:
    phProv: [OUT] CSP句柄指针。
    pszContainer:[IN]密钥容器名称,指向密钥容器的字符串指针。如果dwFlags为CRYPTVERIFYCONTEXT,pszContainer必须为NULL。
    pszProvider:[IN]指向CSP名称的字符串指针。如果为NULL,就使用默认的 CSP。dwProvType:[IN] CSP类型。

    2.枚举CSP函数CryptEnumProviders

    BOOL WINAPI CryptEnumProviders(
    DWORD dwIndex,
    DWORD *pdwReserved,
    DWORD dwFlags,
    DWORD *pdwProvType,
    LPTSTR pSzProvName,
    DWORD *pcbProvName);
    

    参数说明:
    dwIndex:[IN]枚举下一个CSP的索引。
    pdwReserved:[IN]保留参数,必须为NULL。pdwProvType:[OUT] CSP的类型。
    pszProvName:[OUT]指向接收CSP名称的缓冲区字符串指针。pcbProvName:[IN/OUT]指出pszProvName字符串的大小。
    返回值:操作成功返回TRUE,否则返回FALSE。出错可以使用GetLastError()函数获得错误码。

    3.获得默认CSP函数CryptGetDefaultProvider

    BOOL WINAPI CryptGetDefaultProvider (
    DWORD dwProvType,
    DWORD *pdwReserved,
    DWORD dwFlags,
    LPTSTR pszProvName,
    DWORD *pcbFrovName
    };
    

    参数说明:
    dwProvType:[IN] CSP类型。
    pdwReserved:. [IN]保留参数,必须为NULL。dwFlags:[IN]标志位。
    pszProvName: [OUT] 指向接收CSP名称的缓冲区字符串指针。pcbProvName: [IN/OUT]指出pszProvName字符串的大小。
    返回值:操作成功返回TRUE,否则返回FALSE。出错可以通过 GetLastError()函数获得错误码。

    4.设置默认CSP函数CryptSetProvider

    BOOL WINAPI CryptsetProvider(
    LPCTSTRpszProvName,
    DWORD dwProvType
    };
    

    参数说明:
    dwProvType:[IN]CSP类型。
    pszProvName:[IN]CSP名称的缓冲区字符串指针。
    返回值:操作成功返回TRUE,否则返回FALSE。出错可以通过GetLastError()函数获得错误码。

    5.获得CSP参数属性函数CryptGetProvParam

    BOOL WINAPI CryptGetProvParam(
    HCRYPTPROV hProv,
    DWORD dwParam,
    BYTE *pbData,
    DWORD *pdwDataLen,DWORD dwFlags
    };
    

    参数说明:
    hProv:[IN] CSP句柄。
    dwParam:[IN]指定查询的参数。
    可选择的值和意义

    pbData:[OUT] 指向接收数据的缓冲区指针。
    pdwDataLen: [IN/OUT]指出pbData数据长度。
    dwFlags:[IN]标志位。
    返回值:操作成功返回TRUE,否则返回FALSE。出错可以通过GetLastErrorO)函数获得错误码。

    6.设置CSP参数函数CryptSetProvParam

    BOOL WINAPI CryptSetProvParam(
    HCRYPTPROV hProv,
    DWORD dwParam,
    BYTE *pbData,
    DWORD dwFlags
    };
    

    hProv: [IN] CSP句柄。
    dwParam:[IN]指定设置的参数。
    可选择的值和意义

    pbData:[IN]指向设置数据的缓冲区指针。dwFlags:[IN]标志位。
    返回值:操作成功返回TRUE,否则返回FALSE。出错可以通过GetLastError()函数获得错误码。

    7.断开CSP函数 CryptReleaseContext

    BOOL WINAPT CryptReleaseContext(
    HCRYPTPROV hProv,
    DWORDdwFlags
    );
    参数说明:
    hProv :[IN] CSP句柄。
    dwFlags: [IN]标志位,保留参数,必须为0。
    返回值:操作成功返回TRUE,否则返回FALSE。出错可以通过GetLastErrorO)函数获得错误码。

    密钥的产生和交换函数

    CryptoAPI密钥产生和交换函数主要有生成密钥函数 CryptGenKey、派生密钥函数CryptDeriveKey、销毁密钥函数CryptDestoryKey、夏制出钥图效 TypLDupalcaeKey、Vuuot四数CryptExportKey、导入密钥函数CryptImportKey、获得密钥参效函效UrypietKeyraran、以且密钥参数函数 CryptSetKeyParam、产生随机函数 CryptGenRandom。

    1.生成函数 CryptGenKey

    BOOL WINAPI CryptGenKey (
    HCRYPTPROV hProv,
    ALG_ID Algid,
    DWORD dwFlags,
    HCRYPTKEY *phKey
    );
    参数说明:
    phProv:[IN] CSP句柄指针。
    Algid:[IN]密码算法标示。
    Algid支持的参数

    dwFlags: [IN]标志位,指定生成密钥的参数,如对称密钥的长度,RSA密钥的长度。phKey:[OUT] 新产生的密钥句柄。
    返回值:操作成功返回TRUE,否则返回FALSE。出错可以使用GetLastError()函数获得错误码。

    2.派生密钥函数CryptDeriveKey

    函数功能:根据基础数据派生一对称密钥(会话密钥)。

    BOOL WINAPI CryptDeriveKey (
    HCRYPTPROV hProv,
    ALG ID Algid,
    HCRYPTHASH hBaseData,
    DWORD dwFlags,
    HCRYPTKEY *phKey
    };
    

    参数说明:
    phProv: [IN] CSP句柄指针。Algid:[IN]密码算法标识。
    hBaseData:[IN]基础数据的摘要句柄。dwFlags:[IN]标志位。
    phKey: [IN/OUT] 新产生的会话密钥句柄。

    3.销毁密钥函数CryptDestroyKey

    BOOL WINAPI Crypt DestroyKey (
    HCRYPTKEY hKey
    );
    

    hKey:[IN]密钥句柄。
    返回值:操作成功返回TRUE,否则返回FALSE。出错可以通过GetLastError()函数获得错误码。

    4.复制密钥函数CryptDuplicateKey

    函数功能:复制一个密钥。产生一个密钥的铂贝,包括其状态。

    BOOL WINAPI Crypt DuplicateKey(
    HCRYPTKEY hKey,
    DWORD *pdwReservea,
    DWORD dwFlags,
    HCRYPTKEY *phKey
    );
    

    参数说明:
    hKey:[IN]密钥句柄。
    pdwReserved:[IN]保留参数,必须为NULL。dwFlags:[IN]保留参数,必须为0。
    phKey:[OUT]复制后的密钥句柄。
    返回值:操作成功返回TRUE,否则返回FALSE。出错可以使用GetLastError()函数获得错误码。

    5.导出密钥函数CryptExportKey

    函数功能:从 CSP导出密钥或密钥对。函数定义:

    BOOL WINAPICryptExportKey (
    HCRYPTKEY hKey,版
    HCRYPTKEY hExpKey,
    DWORD dwBlobType,DWORD dwFlags,
    BYTE*pbData,
    DWORD *pdwDataLen
    );
    
    

    hKey:[IN] 密钥句柄。
    返回值:操作成功返回TRUE,否则返回FALSE。出错可以通过GetLastError()函数获得错误码。

    6.导入密钥函数CryptlmportKey

    函数功能:把 BLOB数据导入的CSP。该函数可以导入会话密钥、公钥、或者公/私钥对。
    函数定义:

    BOOL WINAPI Crypt ImportKey(
    HCRYPTPROV hProv,
    BYTE *pbData,
    DWORD dwDataLen,HCRYPTKEY hPubKey,DWORD dwFlags,
    HCRYPTKEY *phKey);
    

    参数说明:
    hProv:[IN] CSP句柄。pbData: [IN] BLOB数据。
    dwDataLen:[IN] BLOB数据长度。
    hPubKey:[N]此函数的意义根据CSP的类型以及导入的BLOB数据的类型不同而不同。如果BLOB 数据是由交换密钥加密的,该参数就是交换密钥的句柄。
    如果BLOB数据是由会话密钥加密的,该参数就是会话密钥的句柄。如果BLOB数据没有被加密,则该参数为NULL。
    dwFlags:[IN]标志位。
    phKey:[IN]导入密钥的句柄。
    返回值:操作成功返回TRUE,否则返回FALSE。出错可以通过GetLastError()函数获得错误码。

    数据的加密和解密函数

    CryptoAPI利用CryptEncrypt函数实现数据加密,利用CryptDecrypt实现数据解密。调用这2个函数前必须指定一个密钥,这个密钥可以由 CryptGenKey、CryptDeriveKey或CryptImportKey产生。也可用CryptSetKeyParam函数指定额外的加密参数。

    1.数据加密函数CryptEncrypt

    函数功能:使用hKey 指定的密钥和算法加密数据。函数定义:

    BOOL WINAPI CryptEncrypt(
    HCRYPTKEY hKey,
    HCRYPTHASH hHash,BOOL Final,
    DWORD dwFlags,BYTE *pbData,
    DWORD *pdwDataLen,DWORD dwBufLen
    );
    

    参数说明:
    hKey:[IN]密钥句柄。该句柄指定了加密的密钥和算法。
    hHash:[IN] HASH对象的句柄。如果数据需要同时被哈希和加密,hHash则指定了哈希对象。
    Final:[IN]指出是否是最后一次加密操作。
    dwFlags:[IN]保留参数。
    pbData:[IN/OUT]作为输入参数为被加密数据的缓冲区指针,其长度由dwBufLen指定。作为输出参数为加密后的数据缓冲区指针,其长度由pdwDataLen指定。此函数会把pbData数据加密后的结果覆盖到pbData缓冲区中。
    pdwDataLen:[OUT] 加密后的数据长度。
    dwBufLen:[IN]被加密数据的长度。
    返回值:操作成功返回TRUE,否则返回FALSE。出错可以通过GetLastError()函数获得错误码。

    2.数据解密函数CryptDecrypt

    函数功能:使用hKey指定的密钥和算法对加密数据解密。函数定义:

    BOOL WINAPI Crypt Decrypt (
    HCRYPTKEY hKey,
    HCRYPTHASH hHash,
    BOOL Final,
    DWORD dwFlags,
    BYTE *pbData,
    DWORD *pdwDataLen
    );
    

    参数说明:
    hKey:[IN]密钥句柄。该句柄指定了解密的密钥和算法。
    hHash: [IN HASH对象的句柄。如果数据需要同时被解密和哈希,hHash则指定了哈希对象。
    Final:[IN]指出是否是最后一次解密操作。时深个欢国药dwFlags:[IN]保留参数。
    pbData: [IN/OUT]作为输入参数为被解密数据的缓冲区指针,其长度由pdwDataLen指定。作为输出参数为解密后的明文数据缓冲区指针,其长度由pdwDataLen 指定。此函数会把pbData数据解密后的结果覆盖到pbData缓冲区中。
    pdwDataLen:[IN/OUT]解密前为被解密数据长度,解密后为明文数据长度。
    返回值:操作成功返回TRUE,否则返回FALSE。出错可以通过 GetLastError()函数获得错误码。

    哈希和数字签名函数

    CryptoAPI提供的哈希和数字签名函数包括创建哈希函数CryptCreateHash、销毁哈希CryptDestroyHash、复制哈希函数CryptDuplicateHash、获得哈希参数函数CryptGetHashParam、设置哈希参数函数CryptSetHashParam、哈希会话密钥函数CryptHashSessionKey、哈希数据函数CryptHashData、对哈希签名函数CryptSignHash和对哈希验证签名函数CryptVerifySignature.

    1.创建哈希函数CryptCreateHash

    函数功能:创建哈希。函数定义:

    BOOL WINAPI CryptCreateHash(
    HCRYPTPROV hProv,
    ALG_ID Algid,
    HCRYPTKEY hKey,DWORD dwFlags,
    HCRYPTHASH *phHash
    );
    

    参数说明:
    hProv: [IN] CSP句柄。Algid:[IN指定哈希算法。
    hKey: [N]如果哈希算法是密钥哈希,如HMAC或 MAC算法,就用此密钥句柄传递密钥。对于非密钥算法,此参数为NULL。
    dwFlags:[IN]保留参数。
    phHash:[OUT] 输出的哈希对象指针。
    返回值:操作成功返回TRUE,否则返回FALSE。出错可以通过GetLastError()函数获得错误码。

    2.肖毁哈希CryptDestroyHash

    BOOL WINAPI CryptDestroyHash (
    HCRYPTHASH hHash
    );
    

    参数说明:
    hHash:[IN]哈希对象句柄。
    返回值:操作成功返回TRUE,否则返回FALSE。出错可以通过GetLastError()函数获得错误码。

    3. 复制哈希函数CryptDuplicateHash

    函数功能:复制一个哈希对象。
    函数定义:

    BOOL WINAPI CryptDuplicateHash(
    HCRYPTHASH hHash,
    DWORD *pdwReserved,DWORD dwFlags,
    HCRYPTHASH *phHash);
    

    参数说明:
    hHash:[IN]哈希对象句柄。
    pdwReserved:[IN]保留参数,必须为0。dwFlags:[IN]保留参数。
    phHash:[OUT]输出的哈希对象句柄指针。
    返回值:操作成功返回TRUE,否则返回FALSE。出错可以通过 GetLastError()函数获得错误码。

    证书和证书库函数

    CryptoAPI 证书和证书库函数主要包括打开证书库函数 CertOpenStore、关闭证书库函数CertCloseStore、从证书库枚举证书函数 CertEnumCertificatesInStore、从证书库查找证书函数CertFindCertificateInStore、创建证书句柄函数 CertCreateCertificateContext、释放证书句柄函数CertFreeCertificateContext、获得证书句柄属性函数CertGetCertificateContextProperty、设置证书句柄属性函数CertSetCertificateContextProperty 和获得证书主题名称函数CertGetNameString.

    1.打开证书库函数CertOpenStore

    函数功能:根据证书库类型,打开证书库。函数定义:

    HCERTSTORE WINAPI CertOpenstore(
    LPCSTR 1pszStoreProvider,
    DWORD dwMsgAndCertEncodingType,HCRYPTPROV hCryptProv,
    DWORD dwFlags,
    const void *pvPara
    };
    

    参数说明:
    lpszStoreProvider:[IN]指定证书库的类型。可选参数如表17.1所示
    dwMsgAndCertEncodingType:[N]指定证书的编码类型,通常为X509_ASN_ENCODINGPKCS 7_ASN_ ENCODING。

    2.关闭证书库函数 CertCloseStore

    函数功能:关闭证书库。函数定义:
    BOOL WINAPI CertCloseStore(
    HCERTSTORE hCertStore,
    DWORD dwFlags
    );
    参数说明:
    hCertStore: [IN]证书库句柄。
    dwFlags:[IN]标志位。
    可选的参数

    返回值:操作成功返回TRUE,否则返回NULL。出错可以使用GetLastError()函数获得错误码。

    RAS公司的PKCS#11标准

    PKCS#11

    架构

    会话状态

    对象


    机制

    根据机制标记,可以分为几类:
    CKF_ENCRYPT:加密类
    CKF_DECRYPT:解密类
    CKF_DIGEST:摘要类
    CKF_SIGN:签名类
    CKF_SIGN_RECOVER:可恢复签名类
    CKF_VERIFY:验证类
    CKF_VERIFY_RECOVER:可恢复验证类
    CKF_GENERATE:密钥产生
    CKF_GENERATE_KEY_PAIR:密钥对产生
    CKF_WRAP:密钥封装
    CKF_UNWRAP:密钥解封
    CKF_DERIVE:密钥派生

    操作

    调用流程

    下列缩略语适用于本部分:
    ECC:椭圆曲线算法(Elliptic Curve Cryptography)
    IPK:内部加密公钥(Internal Public Key)
    ISK:内部加密私钥(Internal Private Key)
    EPK:外部加密公钥(External Public Key)
    KEK:密钥加密密钥(Key Encrypt Key)

    GM/T 0006设备定义信息如下

    实际数字结构定义:

    typedef struct DeviceInfo_st{
    unsigned char IssuerName[40];
    unsigned char DeviceName[16];
    unsigned char DeviceSerial[16];
    unsigned int DeviceVersion;
    unsigned int StandardVersion;
    unsigned int AsymAlgAbility[2];
    unsigned int SymAlgAbility;
    unsigned int HashAlgAbility;
    unsigned int BufferSize;
    }DEVICEINFO;
    

    GB/T 0018-2012

    # define RSAref_MAX_BIT S2048
    # define RSAref_MAX_LEN
    ((RSAref_MAX_BITS+7)/8)
    # define RSAref_MAX_PBITS
    ((RSAref_MAX_BITS+1)/2)
    #define RSAref_MAX_PLEN
    ((RSAref_MAX_PBITS+7)/8)
    typedef struct RSArefPublicKey_st
    unsigned int bits;
    unsigned char m[RSAref_MAX_LEN];
    unsigned char e[RSAref_MAX_LEN];
    }RSArefPublicKey;
    typedef struct RSArefPrivateKey_st
    {
    unsigned int bits;
    unsigned char m[RSAref_MAX_LEN];
    unsigned char e[RSAref_MAX_LEN];
    unsigned char d[RSAref_MAX_LEN];
    unsigned char prime[2][RSAref_MAX_PLEN]; u
    nsigned char pexp[2][RSAref_MAX_PLEN];
    unsigned char coef RSArefMAX_PLEN];
    }RSArefPrivateKey;
    
    

    ECC加密如下:

    #define ECCref MAX BITS 512 
    #define ECCref MAX LEN ((ECCrefMAX BITS+7)/8) 
    typedef struct ECCrefPublicKey_st{
    unsigned int bits;
    unsigned char x[ECCrefMAXLEN]; unsigned char y[ECCref_MAX_LEN];
    }ECCrefPublicKey;
    
    typedef struct ECCrefPrivateKey_st{
    unsigned int bits;
    unsigned char K[ECCrefMAXLEN];
    }ECCrefPrivateKey;
    
    //******************************************
    //设备管理
    //******************************************
    /*
    功能:打开密码设备,返回设备句柄。
    参数:
    返回值:0(SDR OK) 成功
    非0 失败,返回错误代码
    /
    int SDF_OpenDevice(void* phDeviceHandle);
    /*
    功能:关闭密码设备,并释放相关资源。
    参数:hDeviceHandle[in] 已打开的设备句柄
    返回值:0(SDR OK) 成功
    非0 失败,返回错误代码
    /
    int SDF_CloseDevice(void hDeviceHandle);
    /*
    功能: 创建与密码设备的会话。
    已打开的设备句柄
    hDeviceHandlein]参数:h
    phessionHiandle[out]
    返回与密码设备建立的新会话句柄成功
    返回值:0(SDR OK) 成功
    非0 失败,返回错误代码
    /
    int SDF_OpenSession(void hDeviceHandle, void** phSessionHandle);
    
    /*
    功能:关闭与密码设备已建立的会话,并释放相关资源。
    参数:hSessionHandle[in] 与密码设备已建立的会话句柄
    返回值:0(SDR OK) 成功
    非0 失败,返回错误代码
    /
    int SDF_CloseSesson(void hSessionHandle);
    
    /*
    功能:获取密码设备能力描述。
    参数:hSessionHandle[in] 与设备建立的会话句柄
    pstDevicelnfo[our] 设备能力描述信息,内容及格式见设备信息定义成功
    返回值:0(SDR OK) 成功
    非0 失败,返回错误代码
    /
    
    int SDF_GetDeviceInfo(
    void hSessionHandle,
    DEVICEINFO* pstDeviceInfo);
    
    
    /*
    功能:获取指定长度的随机数。
    参数:
    hSessonHandle[in] 与设备建立的会话句柄
    uiLegth[in] 欲获取的随机数长度
    pucRandom[out] 缓冲区指针,用于存放获取的随机数
    返回值:0(SDR OK) 成功
    非0 失败,返回错误代码
    /
    
    int SDF_GenerateRandom(
    void hSessionHandle,
    unsigned int uiLength,
    unsigned char* pucRandom);
    
    
    /*
    功能:获取密码设备内部存储的指定索引私钥的使用权。
    参数:
    hSessionHandle[in] 与设备建立的会话句柄
    uiKeyIndex[in] 密码设备存储私钥的索引值
    pucPassword[in] 使用私钥权限的标识码
    uiPwdLength[in] 私钥访问控制码长度,不少于8 字节
    返回值:0(SDR OK) 成功
    非0 失败,返回错误代码
    /
    
    
    int SDF_GetPrivateKeyAccessRight(
    void hSessionHandle,
    unsigned int uiKeyIndex,
    unsigned char* pucPassword,
    unsigned int uiPwdLength);
    
    
    
    /*
    功能:释放密码设备存储的指定索引私钥的使用授权。
    参数:
    hSessonHandle[in] 与设备建立的会话句柄
    uiKeyIndex[in] 密码设备存储私钥索引值成功
    返回值∶0(SDR OK) 成功
    非0 失败,返回错误代码
    /
    
    
    int SDF_ReleasePrivateKeyAccessRight(
    void hSessionHandle,
    unsigned int uiKeyIndex);
    

    列出这些API包含的函数,进行分类,并总结它们的异同

    • 异:Crypto API与PKCS#11
      CryptoAPI是通过容器来组织密钥。一个容器可以存放两个RSA密钥对,一个用于签名验证,一个用于加解密。此外每个用户在加密对话其间还会随机产生许多会话密钥。
      PKCS#11没有容器概念,它对密钥数据的保存和组织主要通过对象。p11定义了三种对象类型:数据对象,证书对象和密钥对象。
      在CryptoAPI中的证书和证书库函数对应着PKCS#11中槽和令牌管理函数,其中CryptoAPI中多了证书库回调函数,可以进行返回操作。
    • 同:
      有最基本的加解密函数,以及签名和验证函数,以及证书的管理函数、密钥管理函数、信息处理函数。

    龙脉测试

    Crypto API

    Signa_Verify

    Enum_certs

    EncryptFile

    PKCS#11

    GetUSBInfos

    enumobj:

    exportcert:

    PKCSDEMO

    TEST

    SKF接口

    DevAuth --------------设备认证例程
    EncryptData --------------数据加解密例程
    RemoteUnblock ------------远程解锁例程
    Signature -------------签名验证例程

    代码

    码云

  • 相关阅读:
    CDN的实现原理
    【Android】 textview 中超出屏幕宽度的字符 省略号显示
    【用户反馈】海外产品大牛: 让用户反馈推着你走
    谷歌2013年搜索热榜 全球榜曼德拉抢榜首 中国区小爸爸第一
    数字(数码)舵机和模拟舵机的区别
    x86 版的 Arduino Intel Galileo 开发板的体验、分析和应用
    【Android】Android自定义属性,attr format取值类型
    android中Textview 和图片同时显示时,文字省略号显示,图片自动靠到右边
    Android webView打不开baidu网页的解决办法
    企鹅的石头
  • 原文地址:https://www.cnblogs.com/harperhjl/p/16175313.html
Copyright © 2020-2023  润新知