首页资源分类嵌入式系统 > PKCS#11中文规范

PKCS#11中文规范

已有 445110个资源

下载专区

上传者其他资源

    文档信息举报收藏

    标    签:PKCS11规范

    分    享:

    文档简介

    PKCS#11规范,是对P11规范的翻译

    文档预览

    组织: PKI论坛 (http://www.pki.com.cn) PKCS/PKIX中文翻译计划 论坛E-mail:pki@pki.com.cn 译者: don’t know 版权:本中文翻译文档版权归PKI论坛的注册用户所共有。可以用于非商业用途自由转载,但必须保留本 文档的翻译及版权信息。如用于商业目的,所得利润需用于PKI论坛的发展。 更改记录 日期 修改章节 类型 修改描述 修改人 C 创建文档 Don’t konw 2003-7-30 M 校对并升级到V2.11 PKI * 修改类型分为 C-CREATE A - ADDED M - MODIFIED D - DELETED PKCS #11 v2.11密码令牌接口标准 (PKCS #11 v2.11: Cryptographic Token Interface Standard) RSA实验室 修订版12001年10月 目录 1. 引言 1 2. 适用范围 1 3. 参考文献 2 4. 定义 4 5. 符号与缩写 6 6. 概述 9 6.1 设计目的 9 6.2 通用模型 9 6.3 令牌的逻辑视图 10 6.4 用户 11 6.5 应用程序和它们的Cryptoki使用 11 6.5.1应用程序和进程 11 6.5.2应用程序和线程 12 6.6 会话 12 6.6.1只读会话状态 12 6.6.2读/写会话状态 13 6.6.3由会话限制的对象访问 14 6.6.4会话事件 15 6.6.5会话句柄和对象句柄 15 6.6.6会话的能力 16 6.6.7会话使用的范例 16 6.7 二次鉴别(反对) 17 6.7.1使用由二次鉴别保护的密钥 18 6.7.2产生由二次鉴别保护的私钥 18 6.7.3改变二次鉴别PIN值 18 6.7.4二次鉴别PIN搜集机制 18 6.8 函数概述 18 7. 安全考虑 21 8. 独立的平台和自动编译器指示C 或 C++ 22 8.1 结构填充 22 8.2 相关指针的宏 22 CK_PTR 22 CK_DEFINE_FUNCTION 22 CK_DECLARE_FUNCTION 22 CK_DECLARE_FUNCTION_POINTER 22 CK_CALLBACK_FUNCTION 23 NULL_PTR 23 8.3 示范独立的平台和自动编译器编码 23 8.3.1Win32 23 8.3.2Win16 24 8.3.3类属 UNIX 24 9. 通用数据类型 25 9.1 通用信息 25 CK_VERSION; CK_VERSION_PTR 25 CK_INFO; CK_INFO_PTR 26 CK_NOTIFICATION 26 9.2 槽和令牌类型 27 CK_SLOT_ID; CK_SLOT_ID_PTR 27 CK_SLOT_INFO; CK_SLOT_INFO_PTR 27 CK_TOKEN_INFO; CK_TOKEN_INFO_PTR 28 9.3 会话类型 34 CK_SESSION_HANDLE; CK_SESSION_HANDLE_PTR 34 CK_USER_TYPE 34 CK_STATE 34 CK_SESSION_INFO; CK_SESSION_INFO_PTR 34 9.4 对象类型 35 CK_OBJECT_HANDLE; CK_OBJECT_HANDLE_PTR 35 CK_OBJECT_CLASS; CK_OBJECT_CLASS_PTR 35 CK_HW_FEATURE_TYPE 36 CK_KEY_TYPE 36 CK_CERTIFICATE_TYPE 37 CK_ATTRIBUTE_TYPE 37 CK_ATTRIBUTE; CK_ATTRIBUTE_PTR 38 CK_DATE 39 9.5 机制的数据类型 39 CK_MECHANISM_TYPE; CK_MECHANISM_TYPE_PTR 39 CK_MECHANISM; CK_MECHANISM_PTR 44 CK_MECHANISM_INFO; CK_MECHANISM_INFO_PTR 44 9.6 函数类型 46 CK_RV 46 CK_NOTIFY 48 CK_C_XXX 48 CK_FUNCTION_LIST; CK_FUNCTION_LIST_PTR; CK_FUNCTION_LIST_PTR_PTR 48 9.7 相关锁定类型 50 CK_CREATEMUTEX 50 CK_DESTROYMUTEX 50 CK_LOCKMUTEX 和CK_UNLOCKMUTEX 51 CK_C_INITIALIZE_ARGS; CK_C_INITIALIZE_ARGS_PTR 51 10. 对象 53 10.1 创建、修改和复制对象 54 10.1.1创建对象 54 10.1.2修改对象 55 10.1.3复制对象 55 10.2 公共属性 55 10.3 硬件特征对象 55 10.3.1时钟对象 56 10.3.2单调计数器对象 56 10.4 存储对象 57 10.5 数据对象 57 10.6 证书对象 58 10.6.1X.509公钥证书对象 59 10.6.2X.509属性证书对象 60 10.7 密钥对象 61 10.8 公钥对象 62 10.8.1RSA公钥对象 63 10.8.2DSA公钥对象 64 10.8.3ECDSA 公共密钥对象 65 10.8.4Diffie-Hellman 公共密钥对象 65 10.8.5KEA 公共密钥对象 66 10.9 私钥对象 66 10.9.1RSA 私钥对象 68 10.9.2ECDSA 公共密钥对象 69 10.9.3Diffie-Hellman 公共密钥对象 70 10.9.4KEA 公共密钥对象 71 10.10 私钥对象 71 10.10.1RSA 私钥对象 73 10.10.2DSA 私钥对象 74 10.10.3ECDSA 私钥对象 75 10.10.4Diffie-Hellman 私钥对象 76 10.10.5KEA 私钥对象 77 10.11 保密密钥对象 78 10.11.1类属保密密钥对象 79 10.11.2RC2 保密密钥对象 80 10.11.3RC4 保密密钥对象 80 10.11.4RC5 保密密钥对象 81 10.11.5AES 保密密钥对象 82 10.11.6DES 保密密钥对象 82 10.11.7DES2 保密密钥对象 83 10.11.8DES3 保密密钥对象 83 10.11.9CAST 保密密钥对象 84 10.11.10CAST3 保密密钥对象 84 10.11.11CAST128 (CAST5) 保密密钥对象 85 10.11.12IDEA 保密密钥对象 85 10.11.13CDMF 保密密钥对象 86 10.11.14SKIPJACK 保密密钥对象 86 10.11.15BATON 保密 密钥对象 87 10.11.16JUNIPER 保密密钥对象 88 11. 函数 90 11.1 函数返回值 90 11.1.1通用 Cryptoki函数返回值 90 11.1.2使用一个对话句柄的函数的Cryptoki函数返回值 91 11.1.3使用一个令牌的函数的 Cryptoki 函数返回值 91 11.1.4 应用提供回叫的特殊返回值 91 11.1.5 Mutex管理函数的特殊返回值 92 11.1.6 所有其他的 Cryptoki函数返回值 92 11.1.7Cryptoki错误的相关优先权的细节 95 11.1.8 错误码 “gotchas” 95 11.2 在可变长度缓冲器中返回函数的惯例 95 11.3 关于样本代码的否认声明 96 11.4 通用函数 96 C_Initialize 96 C_Finalize 97 C_GetInfo 97 C_GetFunctionList 98 11.5 槽和令牌管理函数 99 C_GetSlotList 99 C_GetSlotInfo 100 C_GetTokenInfo 100 C_WaitForSlotEvent 101 C_GetMechanismList 102 C_GetMechanismInfo 103 C_InitToken 104 C_InitPIN 105 C_SetPIN 106 11.6 对话管理函数 107 C_OpenSession 107 C_CloseSession 107 C_CloseAllSessions 108 C_GetSessionInfo 109 C_GetOperationState 109 C_SetOperationState 110 C_Login 112 C_Logout 113 11.7 对象管理函数 113 C_CreateObject 114 C_CopyObject 116 C_DestroyObject 117 C_GetObjectSize 117 C_GetAttributeValue 118 C_SetAttributeValue 120 C_FindObjectsInit 120 C_FindObjects 121 C_FindObjectsFinal 121 11.8 加密函数 122 C_EncryptInit 122 C_Encrypt 123 C_EncryptUpdate 123 C_EncryptFinal 124 11.9 解密函数 126 C_DecryptInit 126 C_Decrypt 126 C_DecryptUpdate 127 C_DecryptFinal 127 11.10 消息摘要函数 129 C_DigestInit 129 C_Digest 129 C_DigestUpdate 130 C_DigestKey 130 C_DigestFinal 131 11.11 签名和 MACing函数 132 C_SignInit 132 C_Sign 132 C_SignUpdate 133 C_SignFinal 133 C_SignRecoverInit 134 C_SignRecover 135 11.12 校验签名和MACs的函数 136 C_VerifyInit 136 C_Verify 136 C_VerifyUpdate 137 C_VerifyFinal 137 C_VerifyRecoverInit 138 C_VerifyRecover 138 11.13 双重目的的密码函数 139 C_DigestEncryptUpdate 140 C_DecryptDigestUpdate 142 C_SignEncryptUpdate 145 C_DecryptVerifyUpdate 147 11.14 密钥管理函数 150 C_GenerateKey 150 C_GenerateKeyPair 151 C_WrapKey 153 C_UnwrapKey 154 C_DeriveKey 155 11.15 随机数生成函数 157 C_SeedRandom 157 C_GenerateRandom 157 11.16 并行功能管理函数 158 C_GetFunctionStatus 158 C_CancelFunction 158 11.17 回调函数 159 11.17.1放弃回调 159 11.17.2卖商定义的回调 159 12. 机制 159 12.1 RSA 机制 164 12.1.1PKCS #1 RSA 密钥对生成 164 12.1.2PKCS #1 RSA 164 12.1.3PKCS #1 RSA OAEP 机制参数 165 CK_RSA_PKCS_MGF_TYPE; CK_RSA_PKCS_MGF_TYPE_PTR 165 CK_RSA_PKCS_OAEP_SOURCE_TYPE; CK_RSA_PKCS_OAEP_SOURCE_TYPE_PTR 165 CK_RSA_PKCS_OAEP_PARAMS; CK_RSA_PKCS_OAEP_PARAMS_PTR 166 12.1.4PKCS #1 RSA OAEP 166 12.1.5ISO/IEC 9796 RSA 167 12.1.6X.509 (raw) RSA 167 12.1.7ANSI X9.31 RSA 168 12.1.8 带有MD2, MD5, 或SHA-1 的PKCS #1 RSA 169 12.1.9带有SHA-1的ANSI X9.31 RSA 签名 169 12.2 DSA 机制 170 12.2.1DSA 密钥对生成 170 12.2.2没有散列的DSA 170 12.2.3带有SHA-1的DSA 170 12.2.4FORTEZZA 时间戳记 171 12.3 关于ECDSA 171 12.4 ECDSA 机制 171 12.4.1ECDSA 密钥对生成 171 12.4.2没有散列的ECDSA 172 12.4.3带有SHA-1的ECDSA 172 12.5 Diffie-Hellman 机制 173 12.5.1PKCS #3 Diffie-Hellman 密钥对生成 173 12.5.2PKCS #3 Diffie-Hellman 密钥派生 173 12.6 KEA 机制参数 173 CK_KEA_DERIVE_PARAMS; CK_KEA_DERIVE_PARAMS_PTR 173 12.7 KEA 机制 174 12.7.1KEA 密钥对生成 174 12.7.2KEA 密钥派生 174 12.8 类属保密密钥机制 175 12.8.1类属保密密钥生成 175 12.9 加密/脱密私钥(RSA, Diffie-Hellman, 和 DSA) 175 12.10 关于RC2 177 12.11 RC2 机制参数 177 CK_RC2_PARAMS; CK_RC2_PARAMS_PTR 177 CK_RC2_CBC_PARAMS; CK_RC2_CBC_PARAMS_PTR 177 CK_RC2_MAC_GENERAL_PARAMS; CK_RC2_MAC_GENERAL_PARAMS_PTR 177 12.12 RC2 机制 178 12.12.1RC2 密钥生成 178 12.12.2RC2-ECB 178 12.12.3RC2-CBC 179 12.12.4带有PKCS填充的RC2-CBC 180 12.12.5通用长度RC2-MAC 180 12.12.6RC2-MAC 180 12.13 RC4 机制 181 12.13.1RC4 密钥生成 181 12.13.2RC4 181 12.14 关于RC5 181 12.15 RC5 机制参数 182 CK_RC5_PARAMS; CK_RC5_PARAMS_PTR 182 CK_RC5_CBC_PARAMS; CK_RC5_CBC_PARAMS_PTR 182 CK_RC5_MAC_GENERAL_PARAMS; CK_RC5_MAC_GENERAL_PARAMS_PTR 182 12.16 RC5 机制 183 12.16.1RC5 密钥生成 183 12.16.2RC5-ECB 183 12.16.3RC5-CBC 184 12.16.4带有PKCS填充的RC5-CBC 184 12.16.5通用长度RC5-MAC 185 12.16.6RC5-MAC 185 12.17 AES 机制参数 186 CK_AES_PARAMS; CK_AES_PARAMS_PTR 186 CK_AES_CBC_PARAMS; CK_AES_CBC_PARAMS_PTR 186 CK_AES_MAC_GENERAL_PARAMS; CK_AES_MAC_GENERAL_PARAMS_PTR 186 12.18 AES 机制 187 12.18.1AES 密钥生成 187 12.18.2AES-ECB 187 12.18.3AES-CBC 187 12.18.4带有PKCS填充的AES-CBC 188 12.18.5通用长度AES-MAC 189 12.18.6AES-MAC 189 12.19 通用块密码机制参数 190 CK_MAC_GENERAL_PARAMS; CK_MAC_GENERAL_PARAMS_PTR 190 12.20 通用块密码机制 190 12.20.1通用块密码密钥生成 190 12.20.2通用块密码ECB 190 12.20.3通用块密码 CBC 191 12.20.4带有PKCS填充的通用块密码CBC 191 12.20.5通用长度通用块密码MAC 192 12.20.6通用块密码MAC 192 12.21 双倍和三倍长度DES 机制 192 12.21.1双倍长度DES 密钥生成 192 12.21.2操作的三倍长DES顺序 193 12.21.3CBC方式中的DES 193 12.22 SKIPJACK 机制参数 193 CK_SKIPJACK_PRIVATE_WRAP_PARAMS; CK_SKIPJACK_PRIVATE_WRAP_PARAMS_PTR 193 CK_SKIPJACK_RELAYX_PARAMS; CK_SKIPJACK_RELAYX_PARAMS_PTR 194 12.23 SKIPJACK 机制 195 12.23.1SKIPJACK 密钥生成 195 12.23.2SKIPJACK-ECB64 195 12.23.3SKIPJACK-CBC64 195 12.23.4SKIPJACK-OFB64 196 12.23.5SKIPJACK-CFB64 196 12.23.6SKIPJACK-CFB32 196 12.23.7SKIPJACK-CFB16 197 12.23.8SKIPJACK-CFB8 197 12.23.9SKIPJACK-WRAP 197 12.23.10SKIPJACK-PRIVATE-WRAP 197 12.23.11SKIPJACK-RELAYX 198 12.24 BATON 机制 198 12.24.1BATON 密钥生成 198 12.24.2BATON-ECB128 198 12.24.3BATON-ECB96 198 12.24.4BATON-CBC128 199 12.24.5BATON-COUNTER 199 12.24.6BATON-SHUFFLE 199 12.24.7BATON 加密 200 12.25 JUNIPER 机制 200 12.25.1JUNIPER 密钥生成 200 12.25.2JUNIPER-ECB128 200 12.25.3JUNIPER-CBC128 200 12.25.4JUNIPER-COUNTER 201 12.25.5JUNIPER-SHUFFLE 201 12.25.6JUNIPER 加密 201 12.26 MD2 机制 202 12.26.1MD2 202 12.26.2通用长度MD2-HMAC 202 12.26.3MD2-HMAC 202 12.26.4MD2 密钥派生 202 12.27 MD5 机制 203 12.27.1MD5 203 12.27.2通用长度 MD5-HMAC 203 12.27.3MD5-HMAC 203 12.27.4MD5 密钥派生 203 12.28 SHA-1 机制 204 12.28.1SHA-1 204 12.28.2通用长度SHA-1-HMAC 204 12.28.3SHA-1-HMAC 204 12.28.4SHA-1 密钥派生 204 12.29 FASTHASH 机制 205 12.29.1FASTHASH 205 12.30 基于口令鉴别的加密机制参数 205 CK_PBE_PARAMS; CK_PBE_PARAMS_PTR 205 12.31 PKCS #5 和PKCS #5-风格口令的加密机制 206 12.31.1用于DES-CBC 的MD2-PBE 206 12.31.2用于DES-CBC 的MD5-PBE 206 12.31.3用于CAST-CBC的MD5-PBE 206 12.31.4用于CAST3-CBC 的MD5-PBE 206 12.31.5用于CAST128-CBC(CAST5-CBC)的 MD5-PBE 207 12.31.6用于CAST128-CBC (CAST5-CBC)的SHA-1-PBE 207 12.31.7PKCS #5 PBKDF2 密钥生成机制参数 207 CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE; CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE_PTR 207 CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE; CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE_PTR 207 CK_ PKCS5_PBKD2_PARAMS; CK_PKCS5_PBKD2_PARAMS_PTR 208 12.31.8PKCS #5 PBKD2 密钥生成 208 12.32 PKCS #12 基于口令的加密/鉴别机制 209 12.32.1用于128-位的RC4 SHA-1-PBE 209 12.32.2用于40-位的RC4 SHA-1-PBE 210 12.32.3用于3-密钥三倍(key triple)-DES-CBC的 SHA-1-PBE 210 12.32.4用于3-密钥三倍(key triple)-DES-CBC的 SHA-1-PBE 210 12.32.5用于128-位 RC2-CBC 的SHA-1-PBE 210 12.32.6用于40-位RC2-CBC 的SHA-1-PBE 210 12.32.7用于SHA-1-HMAC 的SHA-1-PBA 211 12.33 SET 机制参数 211 CK_KEY_WRAP_SET_OAEP_PARAMS; CK_KEY_WRAP_SET_OAEP_PARAMS_PTR 211 12.34 SET 机制 211 12.34.1用于SET的OAEP密钥加密 211 12.35 LYNKS 机制 212 12.35.1LYNKS 密钥加密 212 12.36 SSL 机制参数 212 CK_SSL3_RANDOM_DATA 212 CK_SSL3_MASTER_KEY_DERIVE_PARAMS; CK_SSL3_MASTER_KEY_DERIVE_PARAMS_PTR 213 CK_SSL3_KEY_MAT_OUT; CK_SSL3_KEY_MAT_OUT_PTR 213 CK_SSL3_KEY_MAT_PARAMS; CK_SSL3_KEY_MAT_PARAMS_PTR 214 12.37 SSL 机制 214 12.37.1Pre_master密钥生成 214 12.37.2Master 密钥派生 214 12.37.3密钥和MAC派生 215 10.37.4 SSL 3.0中的MD5 MACing 216 10.37.5 SSL 3.0中的SHA-1 MACing 216 12.38 混杂简单密钥派生机制的参数 216 CK_KEY_DERIVATION_STRING_DATA; CK_KEY_DERIVATION_STRING_DATA_PTR 216 CK_EXTRACT_PARAMS; CK_EXTRACT_PARAMS_PTR 217 12.39 混杂简单密钥派生机制 217 12.39.1一个基本密钥和另一密钥的连接 217 12.39.2一个基本密钥和数据的连接 217 12.39.3数据和一个基本密钥的连接 218 12.39.4将一个密钥和数据执行“异或”运算 219 12.39.5一个密钥从另一个密钥中折取 219 12.40 RIPE-MD 128 机制 220 12.40.1RIPE-MD 128 220 12.40.2通用长度RIPE-MD 128-HMAC 220 12.40.3RIPE-MD 128-HMAC 221 12.41 RIPE-MD 160 机制 221 12.41.1RIPE-MD 160 221 12.41.2通用长度RIPE-MD 160-HMAC 221 12.41.3RIPE-MD 160-HMAC 221 13. Cryptoki 警告和提示 222 13.1 操作、会话和线程 222 13.2 多应用程序访问特性 222 13.3 目标,属性和属性单元 222 13.4 带恢复的签名 223 Appendix A. 令牌剖析 224 Appendix B. Cryptoki 和其它API的比较 225 Appendix C. 明智的性能考虑 229 Appendix D. 通过Cryptoki显示一个令牌上多个PIN的方法 230 虚拟槽和令牌 230 目标可视度 230 数字名单 图 1, 通用Cryptoki 模型 9 图 2, 对象的层次结构 10 图 3, 只读会话状态 13 图 4, 读/写会话状态 14 图5, 对象属性体系 53 表格的名单 表 1, 符号 6 表 2, 前缀 7 表 3, 字符集 8 表 4, 只读会话状态 13 表5, 读/写会话状态 14 表6, 不同种类的会话访问不同种类的对象 14 表7, 会话事件 15 表 8, Cryptoki 函数概述 18 表 9, Cryptoki规范的主次版本号 26 表 10, 槽信息标志 27 表 111, 令牌信息标志 30 表 122, 会话信息标志 35 表 133, 机制信息标志 45 表 144, C_Initialize 参数标志 52 表 15, ECDSA 公共密钥对象属性 65 表 16, Diffie-Hellman 公共密钥对象属性 65 表 17, KEA 公共密钥对象属性 66 表 18, 普通私钥属性 67 表 19, 私钥的cryptoki属性的 X.509 密钥用法标志的映射 68 表 20, RSA 私钥对象属性 68 1. 引言 当密码学有广阔的应用前景而被接受时,将清楚地表明:密码若想继续保持先进的技术并使其象以前一样有效,那么就应当有彼此协作的标准。尽管目前供应商们一致同意基本的密码技术,但执行之间的兼容性无法保证。 互用性需要严格地遵守商定的标准规范。 为了实现这个目标,RSA实验室与本行业、学术界和政府的代表一起合作,已经开发出一套称为公共密钥加密标准(Public-Key Cryptography Standards )的规范,既PKCS。 PKCS 由RSA实验室提供给使用公共密钥和相关技术的计算机系统的开发人员。RSA的目的是与计算机系统开发人员一起提高并改进本标准,即使不是所有的开发人员都接受产生标准的目的。 实验室在标准制定过程中起四个方面的作用: 1. 出版仔细纂写的描述该标准的文件。 2. 对必要的扩展和改变向开发者和用户寻求意见和建议。 3. 在适当的时候出版修订的标准。 4. 提供执行指南和/或参考的执行方法。 在PKCS开发过程中,尽管评论者的意见很有影响,但RSA实验室对每个文件保留最终决定权。然而,RSA实验室的目标是加速正式标准的开发,并不是与这样的工作对抗。因此,当PKCS文件被公认为正式标准的基础文件时,RSA实验室就放弃它对文件的“所有权”,为开放的标准开发过程提供途径。当然,RSA在以上的描述下可继续开发相关的文件。 PKCS文件和信息可在http://www.rsasecurity.com/rsalabs/PKCS得到。在rsasecurity.com,有针对PKCS#11开发和讨论的电子信址列表——“cryptoki”。如要签署这个列表,在消息主体中用“签名cryptoki”把电子邮件发送到 majordomo@rsasecurity.com 。 欢迎对文件进行评论,要求注册标准的扩展部分,给附加的标准提出建议。联系地址: PKCS Editor RSA Laboratories 20 Crosby Drive Bedford, MA 01730 USA pkcs-editor@rsasecurity.com http://www.rsasecurity.com/rsalabs/PKCS/ 很难计算出帮助制定PKCS#11的所有参与者和组织。RSA实验室十分感激他们中的每一位。特别感谢Chrysalis-ITS 的Bruno Couillard 和NSA的John Centafont ,他们花费了大量时间纂写本文的大部分。 在RSA实验室的联系下,1.0版本的PKCS#11的文件主笔是国际计算机服务的Aram Pérez ;项目协调人是RSA实验室。Ray Sidney 担任2.01版本的文件主笔和项目协调人。Intel的Matthew Wood 是2.10版本和2.11版的文件主笔和项目协调人。 2. 适用范围 本标准为那些保存密码信息,执行密码函数的设备确定一种程序设计接口(API),该接口称做Cryptoki。Cryptoki发“Crypto-Key”音,是cryptographic token interface (密码令牌接口)的缩写,它遵循一种基于对象的简单方法,提出技术独立性(各种各样的设备)和资源共享(多个应用程序访问多个设备)的目标,把设备的一种通用的逻辑视图,即密码令牌,提供给应用程序。 本文档通过使用ANSI C程序语言确定适用于需要密码服务的应用程序的数据类型和函数。这些数据类型和函数将由Cryptoki库的供应者通过C字头文档提供。 Cryptoki的通用ANSI C字头文件可在PKCS网页上得到。该文档和Crypto的最新勘误表都可在同一地方得到。 附加文档可提供一个通用的语言独立的Cryptoki界面和/或Cryptoki与其它程序设计语言间的联编。 Cryptoki 把应用从密码设备的详细资料中隔离出来。应用程序不必转换成另一种不同设备的接口或在不同环境下运行,因此,应用程序是很轻便的。Cryptoki怎样提供这种隔离超出了本文档的描述范围,尽管在这里和可能在其他文档中找到某些支持多种设备的协定。 本版本支持许多密码机制。除此之外,新机制能在不改变通用界面的情况下添加进来。可能其它的机制会在不同的文档中发表,也有可能令牌的提供者确定他们自己的机制(即使由于相互合作、通过PKCS处理的注册更可取的缘故)。 Cryptoki 2.1版本用来连接单个用户的密码设备,所以省略了某些通用目的界面中的特点。例如,Cryptoki 2.1 版本没有区别众多用户的方式。重点在单个用户的密钥以及可能与这些密钥相关的证书。况且,重点在加密上。当设备执行有用的非加密函数时,这些函数放到了其它界面上。 3. 参考文献 ANSI C ANSI/ISO. ANSI/ISO 9899: 美国国家程序语言标准 – C。 1990。 ANSI X9.9 ANSI. 美国国家标准X9.9: 财政协会消息鉴别码, 1982。 ANSI X9.17 ANSI. 美国国家标准X9.17: 财政协会密钥管理(大批), 1985。 ANSI X9.31 认可的标准委员会X9. 使用金融服务行业的可逆算法的公共密钥密码术 Part 1: RSA签名算法, 工作草案, 1993年3月7日。 ANSI X9.42 认可的标准委员会X9。 金融服务行业的公共密钥密码术:使用Diffie-Hellman的系统算法密钥的管理。工作草案,1994年9月21日。 ANSI X9.62 认可的标准委员会X9. 金融服务行业的公共密钥密码术:椭曲线数字签名算法(ECDSA)©。工作草案,1997年11月17日 CDPD 美国移动通信等,单元数字包数据系统规格,第406部分: 架空线路安全, 1993。 FIPS PUB 46–3 国家标准和技术研究所(前国家标准局)。 FIPS PUB 46-3: 数据加密标准, 1999年10月25日 FIPS PUB 74 国家标准和技术研究所(前国家标准局)。 FIPS PUB 74: 执行和使用NBS数据机密标准,1981年4月1日。 FIPS PUB 81 国家标准和技术研究所(前国家标准局)。 FIPS PUB 81: DES 操作模式,1980年12月。 FIPS PUB 113 国家标准和技术研究所(前国家标准局)。 FIPS PUB 113: 计算机数据识别,1985年5月30日。 FIPS PUB 180-1 国家标准和技术研究所。 FIPS PUB 180-1: 安全散列标准,1995年4月17日。 FIPS PUB 186 国家标准和技术研究所。 FIPS PUB 186: 数字签名标准,1994年5月19日。 FORTEZZA CIPG NSA, 工作站安全产品。 FORTEZZA 密码界面编程者指南, 1.52修订版,1995年11月。 GCS-API X/Open 有限公司 通用密码服务 (GCS-API), 基本草案2。 1995年2月14日。 ISO 7816-1 ISO. 国际标准7816-1: 标识卡 — 带接触点的集成电路 — 第一部分: 物理特性。 1987。 ISO 7816-4 ISO. 标识卡 — 带接触点的集成电路 —第四部分: 部门间交换命令 委员会草案, 1993。 ISO/IEC 9796 ISO/IEC. 国际标准 9796: 提供消息恢复的数字签名大纲。1991年7月。 PCMCIA 个人计算机存储插件国际协会, PC 插件标准,2.1版, 1993年7月。 PKCS #1 RSA 实验室, RSA加密标准, 2.0版, 1998年10月1日。 PKCS #3 RSA 实验室,Diffie-Hellman 密钥协议标准,1.4版, 1993年11月。 PKCS #5 RSA 实验室, 基于密码加密的标准。2.0版, 19993月25日。 PKCS #7 RSA 实验室,密码消息语法标准,1.5版本, 1993十一月。 PKCS #8 RSA 实验室,私钥信息,私钥信息语法标准。1.2, 1993十一月。 PKCS #12 RSA 实验室 个人信息交换语法标准,1.0版, 1999年6月24日。 RFC 1319 B. Kaliski. RFC 1319: MD2 消息分类算法, RSA 实验室, 1992年4月。 RFC 1321 R. Rivest. RFC 1321: MD5 消息分类算法。计算机科学和RSA数据安全公司的。1992年4月。 RFC 1421 J. Linn. RFC 1421: 增强互联网电子邮件的保密性,第一部分:消息加密和鉴别过程。 IAB IRTF PSRG, IETF PEM WG, 1993年2月。 RFC 1423 D. Balenson. RFC 1423: 增强互联网电子邮件的保密性,第三部分:算法、模式和标识符。TIS 和 IAB IRTF PSRG, IETF PEM WG, 1993年2月。 RFC 1508 J. Linn. RFC 1508: 通用安全应用程序设计接口,Geer Zolot 协会, 1993年9月 RFC 1509 J. Wray. RFC 1509: 通用安全服务API: C-联编,数字设备公司,1993年9月。 RFC 2279 F. Yergeau. RFC 2279: UTF-8, ISO 10646 Alis 技术的转换格式, 1998年1月。 X.500 ITU-T (前身是CCITT)。建议书X.500: 概念和服务的目录概述,1988。 X.509 ITU-T (前身是CCITT)。建议书X.509: 目录鉴别框架,1993。 ( 在ISO/IEC 9594-8 PDAM 1中扩展到X.509: 信息技术-开放系统内部互连-目录:鉴别框架-修订1: 证书扩展, 1994.) X.680 ITU-T (formerly CCITT). 推荐书 X.680: 信息技术-抽象语法注释1(ASN.1):基本注释规范,1994年7月。 X.690 ITU-T (前身是CCITT). 推荐书X.690: 信息技术—ASN.1 加密规则: 基本加密规则的规范(BER), 标准编码规则 (CER), 以及分别加密的规则 (DER),1994年7月。 4. 定义 下列定义适用于本标准: API 应用编程界面 Application(应用程序) 称为 Cryptoki界面的任意计算机程序。 ASN.1 抽象语法注释1,在X.680中定义 Attribute(属性) 对象的一种特性 BATON MISSI的 BATON 分组密码 BER 基本编码规则, 在X.690中定义 CAST Entrust Technologies的专利对称分组密码。 CAST3 Entrust Technologies的专利对称分组密码。 CAST5 对称的分组密码CAST128的另一个名字. CAST128 是可取的名字。 CAST128 Entrust Technologies对称分组密码。 CBC 密码分组链接方式,在FIPS PUB 81中定义。 CDMF 商用数据屏蔽设备,国际商业机器公司指定的一种基于DES的分组加密方法。 Certificate(证书) 连接主体名字和公钥或连接主体名字和一套属性的签名消息。 Cryptographic Device(密码设备) 一种存储密码信息并能执行加密函数的设备。可作为一个智能卡、智能磁盘和PCMCIA 卡来实现,;也可用其他技术,包括软件来实现。 Cryptoki 在本标准中定义的密码令牌界面。 Cryptoki library (Cryptoki库) 用于实现本标准指定的函数的库。 DER 分类编码规则,在X.690中定义。 DES 数据加密标准,在FIPS PUB 46-2中定义。 DSA 数字签名算法,在FIPS PUB 186中定义。 ECB 电子密码本模式,在FIPS PUB 81中定义。 ECDSA 椭圆曲线DSA, 在ANSI X9.62中定义。 FASTHASH MISSI的 FASTHASH 消息分类算法。 IDEA Ascom Systec的对称分组密码。 JUNIPER MISSI的 JUNIPER 分组密码。 KEA MISSI’的密钥交换算法 LYNKS 由SPYRUS制造的智能卡 MAC 消息鉴别码,在ANSI X9.9中定义。 MD2 RSA 数据安全公司的MD2消息分类算法,在 RFC 1319中定义。 MD5 RSA 数据安全公司的MD5 消息分类算法,在 RFC 1321中定义。 Mechanism(机制) 执行密码操作的过程。 OAEP RSA最佳不对称加密填充。 Object(对象) 在令牌中存储的一个项目,可以是数据,一个证书或一个密钥。 PIN 个人识别号码。 RSA RSA 公共密钥密码系统。 RC2 RSA 数据安全公司的RC2 对称分组密码。 RC4 RSA 数据安全公司的专利RC4对称流密码。 RC5 RSA 数据安全公司的RC5对称分组密码。 Reader(阅读器) 用来与一个设备交换信息的工具。 Session(会话) 应用程序和令牌之间的逻辑连接。 SET 安全电子事务处理协议。 SHA-1 修订的安全散列算法,在FIPS PUB 180-1中定义。 Slot(槽) 可能包含一个令牌的逻辑阅读器。 SKIPJACK MISSI的SKIPJACK 分组密码。 SSL 安全套接字层3.0 协议。 Subject Name(主体名字) 配备了密钥的实体的X.500 可识别名。 SO 一个安全官员用户。 Token 由Cryptoki定义的加密设备的逻辑视图。 User(用户) 使用与Cryptoki接口的应用程序的人。 UTF-8 表示ISO 10646和有不同数量的八位字节的UNICODE符号串的通用特性设备(UCS)转换规格(UTF)。 5. 符号与缩写 本标准使用下列符号: 表 1, 符号 符号 定义 N/A 不能应用 R/O 只读 R/W 读/写 本标准使用下列前缀: 表 2, 前缀 前缀 说明 C_ 函数 CK_ 数据类型或通用常数 CKA_ 属性 CKC_ 证书类型 CKF_ 位标志 CKG_ 屏蔽生成功能 CKH_ 硬件特征类型 CKK_ 密钥类型 CKM_ 机制类型 CKN_ 通知 CKO_ 对象级别 CKP_ 伪随机功能 CKS_ 会话状态 CKR_ 返回值 CKU_ 用户种类 CKZ_ Salt/Encoding 参数资源 H 句柄 Ul CK_ULONG P 指针 Pb 指向CK_BYTE的指针 Ph 指向句柄的指针 Pul 指向CK_ULONG的指针 Cryptoki 基于ANSI C 类型, 并定义下列数据类型: /* an unsigned 8-bit value */ typedef unsigned char CK_BYTE; /* an unsigned 8-bit character */ typedef CK_BYTE CK_CHAR; /* an 8-bit UTF-8 character */ typedef CK_BYTE CK_UTF8CHAR; /* a BYTE-sized Boolean flag */ typedef CK_BYTE CK_BBOOL; /* an unsigned value, at least 32 bits long */ typedef unsigned long int CK_ULONG; /* a signed value, the same size as a CK_ULONG */ typedef long int CK_LONG; /* at least 32 bits; each bit is a Boolean flag */ typedef CK_ULONG CK_FLAGS; Cryptoki 使用指向某些数据类型的指针,还使用指向独立执行的void类型的指针。这些指针类型是: CK_BYTE_PTR /* Pointer to a CK_BYTE */ CK_CHAR_PTR /* Pointer to a CK_CHAR */ CK_UTF8CHAR_PTR /* Pointer to a CK_UTF8CHAR */ CK_ULONG_PTR /* Pointer to a CK_ULONG */ CK_VOID_PTR /* Pointer to a void */ Cryptoki 也定义了一个指向CK_VOID_PTR的独立执行的指针: CK_VOID_PTR_PTR /* Pointer to a CK_VOID_PTR */ 除此之外, Cryptoki 定义了一个与其它指针不同的C-style NULL 指针: NULL_PTR /* A NULL pointer */ 由此可见,有许多类型和指针类型因环境而不同(如CK_ULONG 有时是32位,有时是64位)。然而,由于应用程序和与Cryptoki 头文件相一致的Cryptoki 库连接,这些细节不会影响应用程序。 本文中的所有数字和值都是十进制的。如果前面冠有“0x”, 在这种情况下,它们是十六进制的。 CK_CHAR 数据类型包含下表中的字符(摘自ANSI C): 表 3, 字符集 类别 字符 字母 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z 数字 0 1 2 3 4 5 6 7 8 9 图形字符 ! “ # % & ‘ ( ) * + , - . / : ; < = > ? [ \ ] ^ _ { | } ~ 空白字符 ‘ ‘ CK_UTF8CHAR 数据类型包含UTF-8 编码Unicode 字符,并在RFC2279中详细说明。当保持与在PKCS #11版本2.01中定义的Local String保持向后的兼容性, UTF-8 允许国际化。 在Cryptoki中,标志是布尔标志,可以为真,也可以为伪。0值表示标志为伪,非0值表示标志为真。如果需要的话,Cryptoki 定义如下一些宏: #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE (!FALSE) #endif 在单个用户的控制下,当便携式计算部件,如智能卡、PCMCIA 卡以及智能磁盘能安全存储私钥部分时,这些部件是执行公共密钥加密的理想工具。使用这种设备的密码应用程序(而不是执行本身的密码操作程序)使用感测信息(从未展现的私钥)执行操作。当公共密钥密码的更多应用程序被开发时,这些设备的标准编程界面将更有价值。本标准将论述这种需求。 6. 概述 6.1 设计目的 从一开始,我们就把Cryptoki 确定为应用程序与各种各样的便携式密码设备(基于智能卡、PCMCIA卡以及智能软盘)间的一种接口。已经有一些标准(事实上的标准或正式标准)在某一层面上提供同这些设备的接口。例如,机械特点和电连接的定义十分明确,如同提供命令和接受结果的方法。(例如,参见ISO 7816或 PCMCIA 规范。) 还须定义的是执行密码术的专用命令。并不是为每种设备定义命令集就足够了,因为不能解决与设备无关的应用程序接口的一般性问题。这样做仍然是个长期目标,并有助于互操作性。Cryptoki 的主要目标是一个低级程序接口,该接口将设备的细节抽象化,并把密码设备的通用模型—密码令牌,或简称令牌—提供给应用程序。 第二个目标是资源共享。当台式多任务操作系统越来越流行时,单个设备应当也能为一个以上的应用程序所共享。此外,一个应用设备也应当能在给定的时间内与一个以上的设备连接。 成为密码操作或安全服务的一个通用接口并不是Cryptoki 的目标,虽然我们能用Cryptoki提供的功能设置这些操作和服务。Cryptoki旨在从X/Open中实现象“通用安全服务应用编程接口”(RFC 1508 和RFC 1509) 和“通用密码服务API”(GCS-API) 这样一些新出现的和演变中的接口,而不是与之竞争。 6.2 通用模型 Cryptoki的通用模型如下图所示。模型从一个或多个必须执行某些密码操作的应用程序开始,以一个或多个密码设备结束(在密码设备上执行某些或全部操作)。一个用户可涉及也可不涉及一个程序。 图 1, 通用Cryptoki 模型 Cryptoki 为一个或多个密码设备提供一个接口,这些设备通过大量的槽在系统中运行。每个对应于一个物理阅读器或另一个设备接口的槽可包含一个令牌。当一台密码设备存在于阅读器中,一个令牌就存在于该槽中。当然,由于Cryptoki提供槽和令牌的逻辑视图,所以可能有其它的物理译码。多个槽可能共享一个阅读器。问题在于一个系统有相当多的槽,应用程序能连接到这些槽的其中任何一个或全部槽的令牌上。 密码设备可以按照某一命令集执行某些密码操作,这些命令通常要经过标准设备驱动程序,例如PCMCIA卡服务程序或槽服务程序。Cryptoki 使每个密码设备看起来逻辑上很象其它设备,而不管什么技术实现的。因此,应用程序不必直接与设备驱动器接口(或甚至不必知道包括那些设备);Cryptoki 隐藏了这些细节。的确,基础设备完全能用软件来实现,(例如,在一个服务器上运行的处理程序),不须专用硬件。 Cryptoki 或许可以作为支持接口功能的库来实现,而应用程序则与该库连接。应用程序可以直接与Cryptoki 连接,或者,Cryptoki 是一个所谓的“共享”库(或动态连接库),在这种情况下,应用程序动态地连接库。用Microsoft Windows和OS/2操作系统可以比较容易地生成数据库,并且在UNIX和DOS中也可相对容易地生成“共享”库。 由于新库可以使用,所以动态方法有许多优点;但从安全的角度来说,也有一些缺点。要特别指出的是,如果库能较容易地被替换,攻击者有可能用恶意制造的假库取而代之,以截取用户的PIN。即使编码签名技术能防止许多动态连接的安全危险,从安全角度来说,一般采用直接连接。总之,应用程序和Cryptoki 库之间的程序设计接口是相同的。 设备的种类和所支持的能力的种类将取决于专用Cryptoki 库。本标准只定义库的接口,不定义库的特征。要特别指出的是,并不是所有的库支持这个接口(因为不是所有的令牌支持所有的机制)中定义的机制(算法)。并且库也许只支持可使用的所有密码设备的一个子集。(当然,可以预料更多更好的设备种类将被开发,以支持多种令牌,而不是单个供应商提供的令牌。)只要开发出应用程序,就会形成Cryptoki 的接口、标准数据库和令牌“轮廓”(profile)。 6.3 令牌的逻辑视图 Cryptoki的令牌逻辑视图是一个能存储对象和能执行密码函数的设备。Cryptoki定义如下三个对象:数据、证书和密钥。数据对象由应用程序定义。一个证书对象存储一个证书。一个密钥对象存储一个密码密钥。密钥可以是一个公共密钥、一个私钥或是一个保密密钥,每个种类的密钥在专用机制中使用其的辅助型。令牌的这种逻辑视图如下图所示: 图 2, 对象的层次结构 对象也可根据它们的使用期限和可见度进行分类。“令牌对象”能被所有应用程序(与有足够限制的令牌连接)观察;即使在“会话”(应用程序与令牌之间的连接)关闭和令牌从其槽中排出以后,仍保存在令牌上。“会话对象”更具有暂时性,当任何一种方式关闭会话时,由该会话产生的所有会话对象就会自动被破坏。此外,会话对象只能被产生它们的应用程序看见。 更详细的分类确定访问需求。应用程序不需要存入令牌以观察“公共对象”;然而,如果要观察“私有对象”,用户必须由PIN或其它令牌独立方式(例如,一个生物统计学设备)授权给令牌。 访问对象的更详细分类见21页表6。 令牌能建立、破坏、寻找和搜寻对象。还可以执行带有对象的密码函数。令牌可能有内部随机数字发生器。 区分令牌的逻辑视图和执行程序十分重要,因为并不是所有的密码设备有这种“对象”的概念,或执行每一种密码函数。许多设备只使用固定的存储位置来存储固定算法的密钥,并只能执行一组有限的操作。Cryptoki 的作用就是将此转化成逻辑视图,把属性映射到固定的存储单元。并不是所有的Cryptoki 库和令牌需要支持每个对象类型。可以预计,标准“轮廓”将被开发,以确定几组支持的算法。“属性”是区分对象“实例”(instance)的特征。在Cryptoki中, 有诸如对象是私有或公共的通用属性。也有对象专用类型的特殊属性,例如RSA密钥的模数或指数。 6.4 用户 这个Cryptoki版本识别两种令牌用户类型。一个类型就是安全官员(SO)。另一个类型就是普通用户。只有普通用户才能访问令牌上的私有对象,而且只有普通用户在得到授权后才能进行这种访问。 一些令牌可能需要用户在执行令牌上的任意密码功能之前得到授权,不管令牌是否涉及私有对象。SO的作用是初始化一个令牌,设置普通用户的PIN(或由Cryptoki版本以外的方式确定普通用户怎样得到授权),或许还要操作某些公共对象。普通用户只有在SO设置普通用户的PIN以后才能注册。 除了支持两种类型的用户外,Cryptoki 并不涉及SO和用户团体之间的关系。要特别指出的是SO和普通用户可以是同一个人也可以是不同的人,但这已经超出了本标准的范围。 就通过应用程序进入的PIN来说,Cryptoki 仅仅假设它们是表3中本套特征的可变长度字符串。设备需要的任何转换都保留在Cryptoki 库中。下列各项也超出了Cryptoki 的范围: PIN的任意填充字符。 PIN是怎样产生的(由用户,由应用程序或别的方式)。 通过应用程序以外的方式(例如通过令牌上的一个PIN填充付)进入的PIN甚至更抽象。Cryptoki 知道如何等待这样提供和使用的PIN。 6.5 应用程序和它们的Cryptoki使用 对Cryptoki来说,一个应用程序包含一个单个地址空间和在其中运行的控制线程。一个应用程序通过从其中一个线程调用Cryptoki函数C_Initialize (见章节11.4)来成为“Cryptoki 应用”;当这个调用完成后,该应用程序能调用其它Cryptoki 函数。当该应用程序通过使用Cryptoki 完成后,它能调用Cryptoki 函数C_Finalize (见章节11.4),但不再是Cryptoki 应用程序。 6.5.1 应用程序和进程 通常在大多数平台上,前面的段意味着一个应用程序包含单个进程。 假设一个UNIX进程P 通过调用C_Initialize 成为一个Cryptoki应用程序,并使用fork()系统调用建立一个子进程C。因P和C有不同的地址空间(或当其中一个执行一个写操作,如果操作系统使用copy-on-write范例),它们不是同一应用程序的部分。所以,如果C需要使用Cryptoki ,它必须执行自己的C_Initialize 调用。此外,如果C存入令牌,以后只有通过Cryptoki 才能访问。即使P已经存入令牌,C也需要存入;因为P和C是完全分离的应用程序。 在这个特殊的例子中(当C是Cryptoki 应用程序处理的子段时),如果C不试图使用它自己的C_Initialize 调用,Cryptoki 的特性将不能被定义。理论上,这些尝试将返回到值CKR_CRYPTOKI_NOT_INITIALIZED ;然而,由于fork()方式的工程,强调这个返回值在库的性能上可能有较坏的影响。所以,这个状态下的Cryptoki 性能未被定义。因为这样,应用程序不应利用任意可能有用(也可能没用)的潜在“捷径”。 在以上规定的脚本中,不管C是否需要使用Cryptoki ,它应当实际调用C_Initialize ;如果不需要使用Cryptoki ,它应当立即调用C_Finalize 。这(如果母体使用Cryptoki ,就使子段立即调用C_Initialize ,而后调用C_Finalize )被认为是很好的Cryptoki 编程实践,因为它能阻止依附的双重资源的存在(在fork()调用时产生),然而,Cryptoki 并不需要它。 6.5.2 应用程序和线程 一些应用程序将用多线程方法访问Cryptoki 库。Cryptoki 使应用程序为库提供信息,所以它们能给多线程提供适当的支持。要特别指出的是,当一个应用程序通过调用把一个Cryptoki 库初始化成C_Initialize 时,它能为库在四个可能的特性中确定一个: 1. 该程序能确定它不能从多线程中同时访问该库,所以该库不用担心执行任意种类的为了线程安全起见的锁定。 2. 该程序能确定它将从多线程中同时访问库,但该库能使用本地操作系统的同步原语以确保正确的线程安全特性。 3. 该程序能确定它将从多线程中同时访问该库,但该库必须使用一套提供应用程序的同步原语以确保正确的线程安全特性。 4. 该应用程序能确定它将从多线程中同时访问库,但该库必须使用本地操作系统的同步原语或一套提供应用程序的同步原语以确保正确的线程安全特性。 以上列出的第三、四种特性适合于不使用本地操作系统线程模式的多线程应用程序。提供应用程序的同步原语包含四个函数以在应用程序的线程模式中处理mutex(相互“异”操作符—mutex exclusion)对象。Mutex是简单的对象,有锁定和未锁定两种状态。如果一个线程制造的调用锁定一个已经锁定的mutex;线程模块会中断(等待)到mutex解锁,然后再把它锁定,最后调用返回。如果一个以上的线程在一个专用mutex上中断,该mutex将处于未锁定状态;然后其中一个线程将会精确锁定mutex,再把控制返还给调用者(其它中断的线程将继续保持中断,直至轮到它们锁定mutex)。 见章节9.7中更多mutex对象的Cryptoki 的视图。 除了在初始化时间向Cryptoki库提供上述线程控制程序,一个应用程序也能确定应用程序线程执行库是否使用本地操作系统调用分散的新线程。 6.6 会话 Cryptoki 需要用令牌打开一个以上的会话以便使用令牌的对象和函数。会话在应用程序和令牌之间提供一个逻辑连接。会话可以是读/写(R/W)会话,也可以是只读(R/O)会话。读/写和只读指的是通向令牌对象的入口,而不是会话对象。在这两种会话类型下,应用程序能够创建、读、写和破坏会话对象。但是,只有在读/写会话中,应用程序能够创建、修改和破坏令牌对象。 打开一个会话后,应用程序便访问令牌的公共对象。所给应用程序的所有线程有通向相同会话和相同会话对象的通道。为了访问令牌私有对象,不同用户必须先注册并得到授权。 当关闭一个会话后,在该会话过程中创建的任何会话对象都会被破坏。这甚至适用于其它会话正在使用的会话对象。如果单个应用程序用令牌打开多会话,并使用其中一个创建会话对象,那么会话对象就可以通过任意一种应用程序的会话看到。但是,当创建对象的会话关闭时,对象也被破坏了。 Cryptoki 在多令牌上支持多个会话。应用程序可以和一个以上的令牌进行一个以上的会话。一个令牌可以和一个以上的应用程序进行多个会话。但是,一个特定的令牌使应用程序只能有限定数量的会话,或只能有限定数量的读/写会话。 一个打开的会话可以在几种状态之一。会话状态决定通向对象和在会话上执行的函数允许的通道。会话状态在章节6.6.1和章节6.6.2中描述。 6.6.1 只读会话状态 只读会话只存在于两种状态中的一种,如下图所示。当会话最初打开时,它在“R/O公共状态”中(如果应用程序没有以前注册的打开的会话),或“R/O用户状态”中(如果应用程序有已经注册的打开的会话)。值得注意的是,只读会话是不存在的。 图 3, 只读会话状态 下表描述了会话状态 表 4, 只读会话状态 状态 描述 R/O 公共会话 应用程序已打开一个只读会话。应用程序对公共令牌对象进行只读访问,对公共会话对象进行读/写访问。 R/O 用户函数 普通用户由令牌鉴别。应用程序对所有的令牌对象(公共和私有)进行访问,对所有会话对象(公共和私有)进行访问。 6.6.2 读/写会话状态 读/写会话状态只能存在三种状态之一中,如 下图所示。当会话打开,它可能在“读?写公共会话”状态(如果应用程序没有以前注册的打开的会话),“读/写用户功能”状态(如果应用程序有一个普通用户注册的打开会话),“读/写SO功能”状态(如果应用程序已经有一个SO注册的打开会话)。 图 4, 读/写会话状态 下表描述了会话状态: 表5, 读/写会话状态 状态 描述 R/W 公共会话 应用程序已经打开一个读/写会话。应用程序对所有公共对象进行读/写访问。 R/W SO 功能 安全执行官已经由令牌授权。应用程序只能对令牌上的公共对象进行访问。SO能设置普通用户的PIN。 R/W 用户功能 普通用户已经由令牌授权。应用程序对所有对象进行读/写访问。 6.6.3 由会话限制的对象访问 下表总结了该种访问,每种会话只能对一种对象进行访问一个给定种类的会话能进行只读访问,读/写访问,或对一个给定的对象不能进行任何访问。 注意,建立或消除一个对象需要对它进行读/写访问,即“只读用户功能”会话不能建立或消除一个令牌对象。 表6, 不同种类的会话访问不同种类的对象 会话种类 对象类型 只读公共会话 读/写公共会话 只读用户 读/写用户 读/写 SO 公共会话对象 R/W R/W R/W R/W R/W 私有会话对象 R/W R/W 公共令牌对象 R/O R/W R/O R/W R/W 私有令牌对象 R/O R/W 如上表显示,对一个给定的会话对象(在表6中列出)的访问受限于属于拥有该对象的会话(即建立该对象)。 6.6.4 会话事件 会话事件导致会话状态改变。下表描述了该事件。 表7, 会话事件 事件 当...时发生 注册SO SO 由令牌授权 注册用户 普通用户由令牌授权 注销 应用程序注销现有的用户(SO或普通用户) 关闭会话 应用程序关闭该会话或关闭所有会话 拆除设备 位于令牌下面的设备从它的槽中拆除 当设备拆除后,所有应用程序的所有会话自动注销。而且,该设备的应用程序的所有会话被关闭(这个后来的行为不在Cryptoki 的Version 1.0 中进行介绍)——一个带有令牌的应用程序不会有一个不存在的会话。实际上,Cryptoki 不能永远监控令牌是否存在,所以,可以想象令牌的缺省不会被注意到,除非实现Cryptoki 的功能。如果在那之前,令牌被重新插入该槽,那么Cryptoki 可能永远不会知道令牌已经丢失。 在Cryptoki Version 2.1中, 使用令牌的一个应用程序的所有会话必须有相同的注册/注销状态(对于一个给定的应用程序和令牌,保存下列情况之一:所有会话是公共会话,所有会话是SO会话或所有会话是用户会话)。当一个应用程序的会话注册一个令牌,使用该令牌的应用程序的所有会话也被注册;当一个应用程序的会话注销一个令牌,该应用程序的所有会话也被注销。同样,例如,如果使用令牌的一个应用程序已经有一个打开的R/O用户,并且用该令牌打开一个R/W会话,该R/W会话会自动地注册。 这意味着一个给定的应用程序使用一个给定的令牌不可能同时有打开的SO会话和用户会话。这也意味着如果使用一个令牌,一个应用程序有一个R/W SO会话,那么它不能用这个令牌打开一个R/O会话,因为R/O SO会话不存在。同理,如果一个应用程序有一个打开的R/O会话,那么它不可能作为SO把其它会话注册到该令牌。 6.6.5 会话句柄和对象句柄 一个会话句柄是一个Cryptoki 赋予的能够确定会话的值。在许多方式中它类似于一个文件句柄;对于函数来说,它被规定用来确定函数应当执行哪一个会话。一个应用程序的所有线程能平等地访问所有的会话句柄。即一个线程通过一个给定的文件句柄完成的事也能通过相同应用程序的其它线程完成该文件句柄。 Cryptoki 也有对象句柄,这些句柄是用来控制Cryptoki 对象的标识符。 Object handles are similar to session handles in the sense that visibility of a given object through an object handle is the same among all threads of a given application. R/O sessions, of course, only have read-only access to token objects, whereas R/W sessions have read/write access to token objects.对象句柄在同样的意义上与会话句柄类似,即通过一个对象句柄的一个给定对象的可见性与一个给定应用程序的所有线程中的相同。当然,R/O会话仅能对令牌对象进行只读访问,同时在另一方面,R/W会话对令牌对象能进行读/写访问。 Cryptoki 中的Valid 会话句柄和对象句柄总有非零值。为了开发者的方便,Cryptoki 定义了下列符号值: #define CK_INVALID_HANDLE 0 6.6.6 会话的能力 非常笼统的说,一个打开的会话能用来执行三大种类的操作:管理操作(如注册),对象管理操作(如在令牌上建立或销毁一个对象)和密码操作(如计算一个消息摘要)。密码操作有时需要一个以上的函数调用Cryptoki API来完成。通常情况下,在一个时间内单个会话只能执行一个操作,因此,对于单个应用程序,它可能需要单个令牌打开多个会话。然而,为了更加有效,在某个令牌上的单个会话能执行下列类似的操作类型对:消息加密和解密;解密和消息摘要;签名或MACing和加密;以及解密和验证签名或MAC。一个会话中的执行类似密码操作的细节在章节11.13中描述。 通常来说,单个会话在一个时间只能执行一个操作的事实的重要性是:一个应用程序不应使多个类似函数调用使用通用会话的Cryptoki 。如果一个应用程序的多线程在这种形式中使用现有的通用会话,Cryptoki 将不能确定会发生什么。这就意味着如果一个应用程序的多线程全部需要使用Cryptoki 访问一个特殊的令牌,它可能适用于每个线程通过令牌有自己的会话,除非应用程序通过其它方式(即通过某个锁定机制)能确保类似的多线程不使用会话。这确实不顾是否Cryptoki 库在允许安全的多线程访问它的方式中预置。甚至,如果能安全地用类似的多线程访问该库,使用来自类似的多线程的特殊会话也没有必须的安全。 6.6.7 会话使用的范例 我们在这里提供了在Cryptoki 库中多个应用程序怎样使用会话的详细的范例。除了那些读起来有些费劲的细节,我们建议仔细阅读这个范例以便理解会话句柄和对象句柄。 注意,我们的范例决不是表明多个应用程序应当怎样使用类似的Cryptoki ,而是阐明使用什么样Cryptoki 会话、对象和句柄是允许的。换句话说,我们在这里不是证明技术是多好,而是证明“延伸包封”。 例如,我们假设使用Cryptoki库访问一个单个令牌T两个应用程序A 和 B 。每个应用程序有两个运行的线程:A有线程A1和A2,并且B 有线程B1和B2。我们这里没有使用同一会话的单个应用程序的范例,以及没有及时相互叠加的按顺序在我们范例中说明的事件。 1. 每个A1 和B1 通过调用C_Initialize 预置Cryptoki 库(Cryptoki 函数的细节将在章节11中解释)。 注意,其中一个程序精确地调用C_Initialize 应当为每个应用程序制造(例如,每个相反的一个程序为每个线程调用) 2. A1 为会话打开一个R/W 会话并收到该会话句柄7,因为这对A来说是第一个被打开的会话,它是一个公共会话。 3. A2 打开一个R/O 会话并收到会话句柄4。因为A的现有的所有会话是公共会话回话4也是公共会话 4. A1 试图把SO注册到会话7。这个试图失败了,因为如果会话7变成一个SO会话,那么会话4变成SO会话,并且R/O SO会话不存在。A1收到一个错误编码指示R/O会话的存在已经锁住这个注册(CKR_SESSION_READ_ONLY_EXISTS)的企图。 5. A2 把普通用户注册如会话7。这就把会话4转换成一个R/O用户会话。注意,因为A1和A2属于同一个应用程序,它们能平等的访问所有的会话,所以A2能执行这个动作。 6. A2 打开一个R/W会话并收到会话句柄9。因为A的所有存在的会话是用户会话,会话9也是一个用户会话。 7. A1 关闭会话9。 8. B1 试图注销会话4。这个试图失败,因为A和B没有访问各自会话和对象的权利。B1收到一个指示没有这种会话句柄(CKR_SESSION_HANDLE_INVALID)的错误消息。 9. B2 试图关闭会话4。该试图的失败与先前B1试图注册会话4失败的方式相同(即B2收到CKR_SESSION_HANDLE_INVALID 错误编码)。 10. B1 打开一个R/W会话并收到会话句柄7。注意,就B而论,会话句柄7的第一次存在。A会话7和B的会话7是完全不同的会话。 11. B1 把SO注册到[B的] 会话7。这就把B的会话7转换成一个R/W SO 会话,并且对A的会话没有任何影响。 12. B2 试图打开一个R/O会话。该试图失败,因为B 已经使SO会话打开,但R/O SO会话并不存在。B1 收到一个SO会话的存在已经锁定打开R/O会话(CKR_SESSION_READ_WRITE_SO_EXISTS)的企图的错误消息。 13. A1 使用[A的] 会话7建立某种会话对象O1并收到对象句柄7。注意,Cryptoki 可能支持也可能不支持会话和对象的不同地方的句柄。 14. B1 使用 [B的] 会话7建立某种令牌对象O2并收到对象句柄7。当使用会话句柄时,不同的应用程序不能访问各自的对象句柄,所以B的对象句柄7与A的对象句柄7完全不同。当然,因为B1是一个SO会话,它不能建立私有对象,所以O2肯定是一个公共对象(如果B1试图建立一个私有对象,该试图将因为错误编码CKR_USER_NOT_LOGGED_IN or CKR_TEMPLATE_INCONSISTENT 而失败)。 15. B2 使用[B的] 会话7执行某个程序以改进与[B的]对象句柄7相关的对象。这样就改进了O2。 16. A1 使用[A的] 会话4执行一个对象搜索操作得到O2的句柄。该搜索返回对象句柄1。注意,A的 对象句柄1和B的 对象句柄7现在指向同一个对象。 17. A1 试图使用[A的] 会话4改进与[A的] 对象句柄1相关的对象。该试图失败,因为A的的会话4是一个R/O 会话,所以能修改是一个令牌对象的O2。A1 收到一个指示该会话是一个R/O会话(CKR_SESSION_READ_ONLY)的错误消息。 18. A1 使用[A的] 会话7改进与[A的]对象句柄1相关的对象。此时,因为A的 会话7是一个R/W 会话,该企图成功修改O2。 19. B1 使用[B的] 会话7执行一个对象搜索操作以找到O1。因为O1 是一个属于A的会话对象,所以,该搜索不会成功。 20. A2 使用[A的] 会话4执行某个操作以改进与[A的]对象句柄7相关的对象。这个操作改进O1。 21. A2 使用[A的] 会话7销毁与[A的]对象句柄1相关的对象。这销毁了O2。 22. B1 试图用与[B的]对象句柄7相关的执行某个操作。该试图失败,因为没有更长的该种对象。B1 收到一个指示它的对象句柄是无效的(CKR_OBJECT_HANDLE_INVALID)错误消息。 23. A1 注销[A的] 会话4。这就把A的 会话4转化成一个R/O 公共会话,并且把A的会话7转换成一个R/W 公共会话。 24. A1 关闭[A的] 会话7。这就销毁了由A的会话7创建的会话对象O1。 25. A2 试图使用[A的] 会话4执行带有相关[A的]对象句柄7的某个操作。该试图失败,因为这里没有更长的类似对象。它返回一个CKR_OBJECT_HANDLE_INVALID。 26. A2 执行C_CloseAllSessions调用。这就关闭了[A的] 会话4。就这一点来说,如果A 打算打开一个新的密钥,该会话将不会被注册(即它将成为一个公共会话) 27. B2 关闭[B的] 会话7。就这一点而言,如果B 打算打开一个新的密钥,该会话将不会被注册。 28. 每个A 和B 调用C_Finalize 表示它们已经由Cryptoki 库完成。 6.7 二次鉴别(反对) 注意: 本章节中关于Cryptoki 的二次鉴别已经在PKCS #11 v2.11中和更高的版本中否定。它包括在这里是由于向后兼容的原因。新的Cryptoki 执行程序和Cryptoki 所知道的应用程序不能执行这些特点。它将不会在下一个主要版本的说明书中出现。一个可选择的方法就是在Appendix 中描述。 Cryptoki 允许一个应用程序规定一个私钥应当由二次鉴别机制保护。除此之外,该机制是在描述会话的章节6.6中描述的标准注册机制。该机制对应用程序来说很透明,因为 Cryptoki执行程序几乎做了所有的工作。 二次鉴定的目的是为密码令牌提供一种方式,用合理的确定(只有授权的用户才能产生的签名)为非否定(non-repudiation)产生数字签名。这个能力与世界上推广的数字签名规则一样变得越来越重要。 二次鉴别基于下列原则: 1. 私钥的所有者必须在二次授权处理之前由令牌鉴别(即C_Login 必须被成功调用)。 2. 如果一个私钥由一个二次鉴别PIN保护,那么该令牌要求在任何目的密钥使用之前PIN必须列出。 3. 所有的二次鉴别操作通过使用对Cryptoki 用户透明的机制完成。 二次鉴别对于该方式增加了一对微妙点,即一个应用程序为一个用户呈现一个对象和利用附加保护产生新的私钥。下列章节详细阐明了对需要获得二次鉴别好处的应用程序的增补。 6.7.1 使用由二次鉴别保护的密钥 当使用一个只由注册的PIN保护的私钥时,使用一个由二次鉴别保护的私钥的过程和调用序列是相同的 。实际上,为Cryptoki Version 2.01写的应用程序将使用二次鉴别而不是修改。 当一个如数字签名的加密操作使用一个由二次鉴别保护的密钥时,Cryptoki 执行程序和令牌的结合体将汇集所需的PIN值。如果PIN是正确的,那么操作允许完成。否则,函数将返回一个相适应的错误编码。应用程序并不需要从用户汇集PIN的信息并通过Cryptoki 把它发送给令牌。它是完全透明的。 当Cryptoki 和令牌通过询问CKA_SECONDARY_AUTH 属性(见章节10.9)汇集二次鉴别的一个PIN时,应用程序能探测出。如果属性值是TRUE,那么应用程序会对用户做一个提醒。因为Cryptoki Version 2.01不会注意CKA_SECONDARY_AUTH 属性,所以PIN汇集机制应当给一个需要鉴别的用户一个信号。 6.7.2 产生由二次鉴别保护的私钥 为了产生由二次鉴别保护的私钥,应用程序提供在私钥属性单元中带有值TRUE的CKA_SECONDARY_AUTH 属性。如果属性没有存在于属性单元中或有值FALSE,那么私钥由普通的注册保护产生。见章节10.9和11.14中关于私钥属性单元和密钥生成函数的更多信息。 如果新的密钥由二次鉴别保护,Cryptoki 执行程序和部件的结合体将透明的搜集初始PIN值。 6.7.3 改变二次鉴别PIN值 应用程序在私钥上使用C_SetAttributeValue 函数使部件改变二次鉴别PIN。函数的属性单元应当包含CKA_SECONDARY_AUTH 属性。属性单元中CKA_SECONDARY_AUTH 的值无关紧要。 当Cryptoki 执行程序在C_SetAttributeValue 属性单元中找到这个值时,它使部件搜集适宜的值。如果C_SetAttributeValue 是成功的,PIN被转换成新的值。见章节 和 中关于私钥对象和C_SetAttributeValue 更多的信息。 6.7.4 二次鉴别PIN搜集机制 Cryptoki 不为二次鉴别PIN搜集规定一个机制。唯一的需求是搜集机制的操作对用户而言是透明的。 理论上,二次鉴别PIN将使用保护路径部件搜集,但不能总是这种情况。Cryptoki执行程序可以使用平台规定的服务搜集PIN值,包括GUI对话箱。当这与Cryptoki 设计中所需的非移动执行程序的无效特征完全不同时,它允许没有改变的version 2.01知道的应用程序使用二次鉴别。如果应用程序需要从保护路径搜集来的PIN值,它应当确保CKF_PROTECTED_AUTHENTICATION_PATH 标志设置在CK_TOKEN_INFO 结构中。 6.8 函数概述 Cryptoki API 包含大量的函数,生成槽和令牌管理以及对象管理,还有密码函数。这些函数在下表中列出: 表 8, Cryptoki 函数概述 种类 函数 描述 通用l C_Initialize 初始化 Cryptoki 目的函数 C_Finalize 清除各种Cryptoki相关资源 C_GetInfo 获得关于Cryptoki的通用信息 C_GetFunctionList 获得Cryptoki 库函数的进入点 槽和令牌 C_GetSlotList 获得系统中槽的名单 管理 C_GetSlotInfo 获得关于特殊槽的信息 函数 C_GetTokenInfo 获得关于特殊令牌的信息 C_WaitForSlotEvent 等待槽事件(令牌插入,转移等) 的发生 C_GetMechanismList 获得由令牌支持的机制的名单 C_GetMechanismInfo 获得关于特殊机制的信息 C_InitToken 初始化一个令牌 C_InitPIN 初始化普通用户的 PIN C_SetPIN 改变现在用户的PIN 会话管理函数 C_OpenSession 打开一个应用程序和特殊令牌之间的连接或安装一个应用程序呼叫返回令牌插入 C_CloseSession 关闭一个会话 C_CloseAllSessions 用令牌关闭所有的会话 C_GetSessionInfo 获得关于会话的信息 C_GetOperationState 获得会话的加密操作状态 C_SetOperationState 设置会话的加密操作状态 C_Login 注册一个令牌 C_Logout 从一个令牌注销 对象管理函数 C_CreateObject 建立一个对象 C_CopyObject 建立一个对象的拷贝 C_DestroyObject 销毁一个对象 C_GetObjectSize 获取字节中一个对象的大小 C_GetAttributeValue 获取一个对象的属性值 C_SetAttributeValue 改变一个对象的属性值 C_FindObjectsInit 初始化一个对象的搜索操作 C_FindObjects 继续一个对象搜索操作 C_FindObjectsFinal 完成一个对象搜索操作 加密 C_EncryptInit 初始化一个加密操作 函数 C_Encrypt 加密单部分数据 C_EncryptUpdate 继续一个多部分加密操作 C_EncryptFinal 完成一个多部分加密操作 解密 C_DecryptInit 初始化一个解密操作 函数 C_Decrypt 解密单部分加密数据 C_DecryptUpdate 继续一个多部分解密操作 C_DecryptFinal 完成一个多部分解密操作 消息 C_DigestInit 初始化一个消息摘要操作 解密 C_Digest 摘要单部分数据 函数 C_DigestUpdate 继续一个多部分摘要操作 C_DigestKey 摘要一个密钥 C_DigestFinal 完成一个多部分摘要操作 签名 C_SignInit 初始化一个签名操作 和MACing C_Sign 签名单部分数据 函数 C_SignUpdate 继续一个多部分签名操作 C_SignFinal 完成一个多部分签名操作 C_SignRecoverInit 初始化一个签名操作,在操作中数据能从签名中恢复 C_SignRecover 签名单部分数据,在操作中数据能从签名中恢复 鉴定函数 C_VerifyInit 初始化一个鉴定操作 签名 C_Verify 在单部分数据上鉴定一个签名 和 MACs C_VerifyUpdate 继续一个多部分鉴定操作 C_VerifyFinal 完成一个多部分鉴定操作 C_VerifyRecoverInit 初始化一个鉴定操作,在操作中数据能从签名中恢复 C_VerifyRecover 在单部分数据上鉴定一个签名,在操作中数据能从签名中恢复 双效加密 C_DigestEncryptUpdate 继续类似的多部分摘要和加密操作 函数 C_DecryptDigestUpdate 继续类似的多部分解密和摘要操作 C_SignEncryptUpdate 继续类似的多部分签名和加密操作 C_DecryptVerifyUpdate 继续类似的多部分解密和鉴定操作 密钥 C_GenerateKey 产生一个保密密钥 管理 C_GenerateKeyPair 产生一个公共/私钥对 函数 C_WrapKey 加密一个密钥 C_UnwrapKey 解密一个密钥 C_DeriveKey 从基础密钥派生一个密钥 随机数字生成 C_SeedRandom 把一个附加种子材料加入随机数字生成器 函数 C_GenerateRandom 生成随机数据 并行功能管理函数 C_GetFunctionStatus 经常返回 CKR_FUNCTION_NOT_PARALLEL的遗产函数 C_CancelFunction 经常返回 CKR_FUNCTION_NOT_PARALLEL的遗产函数 呼叫返回函数 Cryptoki中应用程序提供的处理通知的函数 7. 安全考虑 作为一个密码部件的接口,Cryptoki 为一个计算机或通信系统的安全提供一个基础。用于这种安全的接口的两个特性如下: 1. 访问一个令牌上的私有对象,并可能访问令牌上的密码函数和/或证书时,需要一个PIN。因此,处理一个执行该令牌的密码设备并不足以使用它,也可能需要PIN。 2. 附加保护通过在它们上面标识“敏感”或“不可萃取的”提供给私钥和保密密钥。敏感密钥不能呈现在令牌以外的明文里,并且不可萃取的密钥不能呈现在令牌以外,即使被加密(尽管他们仍能作为密钥使用)。 预计对私有、敏感或不可萃取的对象的访问是通过其它方式而不是Cryptoki (即其它编程接口,或设备的逆向工程)将会很困难。 如果设备有一个防止篡改环境或有一个存储私有和敏感对象的受保护的存储器,该设备可能通过由用户PIN派生的主密钥加密对象。然而,保护私有对象的特殊机制脱离设备执行程序。 基于这些特点,它应当可能以令牌能为应用程序管理的对象提供足够的安全的方式设计应用程序。 当然,加密只是安全的唯一因素,并且令牌是一个系统中唯一的组成部分。当令牌本身可能安全,它才能必须考虑应用程序介入的操作系统的安全,因为PIN可能通过操作系统。这能使在操作系统上的无赖的应用程序较容易地获取PIN,也可能其它监视密码部件的通信线其它设备能获取PIN。无赖的应用程序和设备也可改变密码部件的命令传送获取服务,而不是应用程序所需要。 确保系统能安全地防止攻击是很重要的。Cryptoki 可以在这里扮演一个很好的角色,例如,令牌可能在系统的“保护罩(booting up)”。 我们注意到没有一次所描述的攻击能损害标有“敏感”的密钥,因为敏感的密钥永远保持敏感。类似地,不可萃取的密钥不能改变为可萃取的密钥。 从某种意义上说,一个应用程序也想确保该令牌是“合法的”(由于各种原因,包括输出保密和基础安全)。这超出了现有标准的范围,但它能通过分布内部令牌由公共/私钥对(通过它令牌能证明自己的身份)成功地证明。证书将由应用程序知道的公共密钥的规范(估计显示令牌是“合法”的一个)签名。应用程序将通过自己的内置私钥签名一个时间验证消息来验证和挑战令牌。 普通用户曾经由令牌鉴别,Cryptoki 并不限制用户可能执行的密码操作,用户能支持任何令牌支持的操作。某些令牌甚至可以不需要任何种类的鉴别就能使用密码函数。 8. 独立的平台和自动编译器指示C 或 C++ Cryptoki 头文件规定了一系列关于Cryptoki 数据类型。这些类型的某些填充和相关指针的特性是独立的平台和自动编译器;所以这些特性通过预处理器命令的方式基于Cryptoki 头文件的外部的一个个平台(或一个个自动编译器)上进行鉴别。 这就意味着当写C或C++时,某些预处理器命令必须在包括Cryptoki 头文件之前提供。这些命令在第八章的剩余部分阐述。 8.1 结构填充 Cryptoki 结构被填充尽可能少的占用空间。要特别指出的是,在Win32和Win16的平台上,Cryptoki 应当由1字节对齐方式进行填充。在一个UNIX环境,它可能需要改变也可能不需要改变结构的字节对齐方式。 8.2 相关指针的宏 因为不同的平台和自动编译器用不同的方式处理不同类型的指针,Cryptoki 需要下列6个宏设置在Cryptoki 的范围外: CK_PTR CK_PTR 是一个给定的平台和自动编译器用来产生一个对象的指针的“间接串”。它在以下方式中使用: typedef CK_BYTE CK_PTR CK_BYTE_PTR; CK_DEFINE_FUNCTION CK_DEFINE_FUNCTION(returnType, name), 遵循括号内讨论的名单和函数定义,定义一个Cryptoki 库中的Cryptoki API 函数。 returnType 是返回类型的函数,并且name 是它的名字。它在以下方式中使用: CK_DEFINE_FUNCTION(CK_RV, C_Initialize)( CK_VOID_PTR pReserved ) { ... } CK_DECLARE_FUNCTION CK_DECLARE_FUNCTION(returnType, name), 根据括号内讨论的名单和分号,在Cryptoki库表示一个Cryptoki API函数。 returnType 是返回类型的函数。并且name 是它的名字。它在以下方式中使用: CK_DECLARE_FUNCTION(CK_RV, C_Initialize)( CK_VOID_PTR pReserved ); CK_DECLARE_FUNCTION_POINTER CK_DECLARE_FUNCTION_POINTER(returnType, name), 根据括号内讨论的名单和分号,在Cryptoki 库中表示不同种类的Cryptoki API 函数的一个指针。returnType 是返回函数,并且name 是它的名字。它在下列两种方式之一定义一个在Cryptoki库中能指向C_Initialize不同的myC_Initialize函数指针(注意,实际上没有任何一个编码部分对 myC_Initialize赋予一个值): CK_DECLARE_FUNCTION_POINTER(CK_RV, myC_Initialize)( CK_VOID_PTR pReserved ); 或 typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, myC_InitializeType)( CK_VOID_PTR pReserved ); myC_InitializeType myC_Initialize; CK_CALLBACK_FUNCTION CK_CALLBACK_FUNCTION(returnType, name), 根据括号内的名单和分号,在Cryptoki 库中通过使用Cryptoki API函数表示不同类型的应用程序呼叫返回函数。returnType 是返回类型的函数,并且name 是它的名字。它能在下列两种方式之一定义不同myCallback的一个函数指针,它能指向带有讨论args和返回 CK_RV 的应用程序呼叫返回(注意,实际上没有任何一个编码部分对myCallback赋予一个值): CK_CALLBACK_FUNCTION(CK_RV, myCallback)(args); or: typedef CK_CALLBACK_FUNCTION(CK_RV, myCallbackType)(args); myCallbackType myCallback; NULL_PTR NULL_PTR 是NULL 指针的值。在任意一个ANSI C 环境——并且在其它环境中也是这样——NULL_PTR 应当被定义为0。 8.3 示范独立的平台和自动编译器编码 8.3.1 Win32 开发商使用Microsoft Developer Studio 5.0 生成C 或C++ 编码,编码执行或使用 Win32 Cryptoki .dll ,先于包括Cryptoki 头文件发出下列命令: #pragma pack(push, cryptoki, 1) #define CK_PTR * #define CK_DEFINE_FUNCTION(returnType, name) \ returnType __declspec(dllexport) name #define CK_DECLARE_FUNCTION(returnType, name) \ returnType __declspec(dllimport) name #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \ returnType __declspec(dllimport) (* name) #define CK_CALLBACK_FUNCTION(returnType, name) \ returnType (* name) #ifndef NULL_PTR #define NULL_PTR 0 #endif 随着包括任意Cryptoki 头文件,它们可能发出下列命令为较早的值重新设置结构填充: #pragma pack(pop, cryptoki) 8.3.2 Win16 开发商使用 Microsoft Developer Studio 5.0以前的版本生成C 或 C++ 编码,编码执行或使用 Win16 Cryptoki .dll ,先于包括Cryptoki 头文件发出下列命令: #pragma pack(1) #define CK_PTR far * #define CK_DEFINE_FUNCTION(returnType, name) \ returnType __export _far _pascal name #define CK_DECLARE_FUNCTION(returnType, name) \ returnType __export _far _pascal name #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \ returnType __export _far _pascal (* name) #define CK_CALLBACK_FUNCTION(returnType, name) \ returnType _far _pascal (* name) #ifndef NULL_PTR #define NULL_PTR 0 #endif 8.3.3 类属 UNIX 开发商进行类属UNIX开发可能先于包括任意头文件发出下列命令: #define CK_PTR * #define CK_DEFINE_FUNCTION(returnType, name) \ returnType name #define CK_DECLARE_FUNCTION(returnType, name) \ returnType name #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \ returnType (* name) #define CK_CALLBACK_FUNCTION(returnType, name) \ returnType (* name) #ifndef NULL_PTR #define NULL_PTR 0 #endif 9. 通用数据类型 通用Cryptoki 数据类型在下面各小节中介绍。本节不介绍各种机制的参数的数据类型以及指向这些参数的指针。这些类型将与信息一起在章节中的机制上介绍。 Cryptoki 应用程序或库中的C 或C++ 源文件通过包括的顶层Cryptoki 包含文件pkcs11.h能确定所有的这些类型(在这里介绍的类型和用作特定机制参数的类型)。一个源文件也能包括pkcs11t.h(而不是pkcs11.h);这就确定了大部分(不是所有)在这里介绍的类型。 当包括任意一种头文件,一个源文件必须确定在第8章中的预处理器指令。 9.1 通用信息 Cryptoki用如下类型表示通用信息: CK_VERSION; CK_VERSION_PTR CK_VERSION 是 描述Cryptoki 接口的版本、Cryptoki 库的版本、SSL执行程序的版本,或者一个槽或令牌的硬件或固定版本的一种结构。它的定义如下: typedef struct CK_VERSION { CK_BYTE major; CK_BYTE minor; } CK_VERSION; 该结构的字段具有如下含义: major 主版本号(版本的整数部分) minor 次版本号(版本的百分之一部分) 对于版本1.0来说, major = 1 and minor = 0。对于版本2.1, major = 2 和minor = 10。 表9中列出了官方发布的Cryptoki规范的主版本号和次版本号。 表 9, Cryptoki规范的主次版本号 Version major minor 1.0 0x01 0x00 2.01 0x02 0x01 2.10 0x02 0x0a 2.11 0x02 0x0b Cryptoki 标准的主修订版本号内总是向上兼容的。 CK_VERSION_PTR 是CK_VERSION的一个指针。 CK_INFO; CK_INFO_PTR CK_INFO 提供有关Cryptoki的通用信息。 其定义如下: typedef struct CK_INFO { CK_VERSION cryptokiVersion; CK_UTF8CHAR manufacturerID[32]; CK_FLAGS flags; CK_UTF8CHAR libraryDescription[32]; CK_VERSION libraryVersion; } CK_INFO; 结构的字段具有下列含义: cryptokiVersion Cryptoki 接口版本号,与该接口的未来版本相兼容。 manufacturerID Cryptoki 库产生的ID。必须填充空白字符(‘ ‘),不应是0终止。 flags 为未来版本保留的位标志。对这个版本来说,必须为0。 libraryDescription 库的字符串描述。必须填充空白字符(‘ ‘),不应是0终止。 libraryVersion Cryptoki 库版本号。 根据本文档实现的Cryptoki库, cryptokiVersion 的值应为2.11; libraryVersion 的值是库软件本身的版本号。 CK_INFO_PTR 是CK_INFO的一个指针。 CK_NOTIFICATION CK_NOTIFICATION 保持Cryptoki 提供给应用程序的通知的类型。其定义如下: typedef CK_ULONG CK_NOTIFICATION; 对于Cryptoki的这个版本来说,定义了下列一些通知类型: #define CKN_SURRENDER 0 通知具有如下含义: CKN_SURRENDER Cryptoki 正在放弃它对一个在串行执行的函数所拥有的执行权,所以应用程序可以执行其它操作。在执行了任何期望的操作之后,应用程序应指示Cryptoki 是继续执行该函数还是取消该函数(见章节)。 9.2 槽和令牌类型 Cryptoki 用如下类型表示槽和令牌信息: CK_SLOT_ID; CK_SLOT_ID_PTR CK_SLOT_ID 是Cryptoki-指定的值,用于识别槽。其定义如下: typedef CK_ULONG CK_SLOT_ID; CK_SLOT_ID的名单由C_GetSlotList返回。CK_SLOT_ID 事先的任意值能成为有效的槽标识符——特别是,一个系统能由0值标识的槽。但是,它并不需要这种槽。 CK_SLOT_ID_PTR 是 CK_SLOT_ID的一个指针。 CK_SLOT_INFO; CK_SLOT_INFO_PTR CK_SLOT_INFO 提供关于一个槽的信息。其定义如下: typedef struct CK_SLOT_INFO { CK_UTF8CHAR slotDescription[64]; CK_UTF8CHAR manufacturerID[32]; CK_FLAGS flags; CK_VERSION hardwareVersion; CK_VERSION firmwareVersion; } CK_SLOT_INFO; 结构的字段具有下列含义: slotDescription 槽的字符串描述。必须填充空白字符(‘ ‘)。 不应是0终止。 manufacturerID 槽生产者的ID。必须填充空白字符(‘ ‘), 不应是0终止。. flags 用于提供槽能力的位标志,该标志定义如下。 hardwareVersion 槽的硬件的版本号。 firmwareVersion 槽的固件的版本号。 下表定义了 flags 字段的参数: 表 10, 槽信息标志 位标志 表征码 含义 CKF_TOKEN_PRESENT 0x00000001 如果槽中存在一个令牌(例如,有一个设备在阅读器中)为真 CKF_REMOVABLE_DEVICE 0x00000002 如果阅读器支持可拆卸设备,为真。 CKF_HW_SLOT 0x00000004 如果槽是一个硬槽,为真。如果是软令牌,为假。 对于一个给定的槽,CKF_REMOVABLE_DEVICE 标志的值不会改变。除此之外,如果对于给定的槽该标志没有设置,那么CKF_TOKEN_PRESENT 标志为该槽将会永远被设置。这就是说,如果一个槽不支持一个可拆卸的部件,那么该槽将会始终有一个令牌。 CK_SLOT_INFO_PTR 是CK_SLOT_INFO的一个指针。 CK_TOKEN_INFO; CK_TOKEN_INFO_PTR CK_TOKEN_INFO 提供关于令牌的信息。其定义如下: typedef struct CK_TOKEN_INFO { CK_UTF8CHAR label[32]; CK_UTF8CHAR manufacturerID[32]; CK_UTF8CHAR model[16]; CK_CHAR serialNumber[16]; CK_FLAGS flags; CK_ULONG ulMaxSessionCount; CK_ULONG ulSessionCount; CK_ULONG ulMaxRwSessionCount; CK_ULONG ulRwSessionCount; CK_ULONG ulMaxPinLen; CK_ULONG ulMinPinLen; CK_ULONG ulTotalPublicMemory; CK_ULONG ulFreePublicMemory; CK_ULONG ulTotalPrivateMemory; CK_ULONG ulFreePrivateMemory; CK_VERSION hardwareVersion; CK_VERSION firmwareVersion; CK_CHAR utcTime[16]; } CK_TOKEN_INFO; 该结构的字段具有下列含义: label 应用程序定义的标记,是在令牌初始化期间指定的。必须填充空白字符(‘ ‘),不应是0终止。 manufacturerID 槽生产者的ID。必须填充空白字符(‘ ‘), 不应是0终止。 model 设备型号。必须填充空白字符(‘ ‘), 不应是0终止。 serialNumber 设备的字符串顺序号。必须填充空白字符(‘ ‘), 不应是0终止。 flags 指示设备的能力和状态的位标志 ulMaxSessionCount 通过单个应用程序能用令牌一次同时打开的最大会话数量 ulSessionCount 当前用令牌打开的会话的数量 ulMaxRwSessionCount 通过单个应用程序能用令牌一次同时打开读/写会话的最大数量 ulRwSessionCount 用令牌打开当前读/写会话的数量 ulMaxPinLen PIN的最大长度(字节数) ulMinPinLen PIN的最小长度(字节数) ulTotalPublicMemory 令牌上可以存放公共对象的总存储容量(字节数) ulFreePublicMemory 用于存放公共对象的空闲(未用)存储容量(字节数) ulTotalPrivateMemory 可以用来存放私有对象的总存储容量(字节数) ulFreePrivateMemory 用于存放私有对象的空闲(未用)存储容量 hardwareVersion 硬盘的版本号 firmwareVersion 固件的版本号 utcTime 当作一个长度为16的字符串看待的当前时间,以YYYYMMDDhhmmssxx形式表示(其中年用4个字符表示,月、日、小时、分和秒各用2个字符表示,另有两个保留‘0’字符)。如令牌信息标志所指示的那样,这个字段的值仅对装备有一个时钟的令牌有意义。(见表11) 下表定义了 flags 字段: 表 111, 令牌信息标志 位标志 表征码 含义 CKF_RNG 0x00000001 如果令牌有自己的随机数发生器,为真 CKF_WRITE_PROTECTED 0x00000002 如果令牌是写保护的,为真 CKF_LOGIN_REQUIRED 0x00000004 如果用户必须注册才能执行密码函数,为真 CKF_USER_PIN_INITIALIZED 0x00000008 如果普通用户的PIN已经被初始化,为真 CKF_RESTORE_KEY_NOT_NEEDED 0x00000020 如果成功保存一个会话的密码操作状态总是包含恢复该会话的状态所需要的所有密钥,则为真 CKF_CLOCK_ON_TOKEN 0x00000040 如果令牌有自己的硬件时钟,则为真 CKF_PROTECTED_AUTHENTICATION_PATH 0x00000100 如果令牌有一个受保护的鉴别路径,用户借此不用把PIN传过Cryptoki 库就能够注册到令牌中,为真 CKF_DUAL_CRYPTO_OPERATIONS 0x00000200 如果与令牌的单一会话能够执行对偶密码操作,为真(参见章节 ) CKF_TOKEN_INITIALIZED 0x00000400 如果使用C_InitializeToken 或本标准范围外的等效机制已经初始化该令牌,则为真。当该标志被设置并使令牌被重新初始化,则调用C_InitializeToken 。 CKF_SECONDARY_AUTHENTICATION 0x00000800 如果令牌支持私钥对象二次鉴别,则为真。(反对,新的执行程序不要把这个机制设置为真) CKF_USER_PIN_COUNT_LOW 0x00010000 如果由于上一次成功的鉴别,一个错误的用户注册的PIN进入至少一次,则为真 CKF_USER_PIN_FINAL_TRY 0x00020000 如果提供一个错误的用户的PIN被锁住,则为真。 CKF_USER_PIN_LOCKED 0x00040000 如果用户的PIN被锁住,则为真。用户注册该令牌是不可能的。 CKF_USER_PIN_TO_BE_CHANGED 0x00080000 如果用户的PIN值通过令牌初始化或加工被设置成错误值,或PIN由卡终止。 CKF_SO_PIN_COUNT_LOW 0x00100000 从最后一次成功的认证,SO登录的PIN至少进入一次,则为真 CKF_SO_PIN_FINAL_TRY 0x00200000 如果提供的错误的SO PIN将被锁住,则为真 CKF_SO_PIN_LOCKED 0x00400000 如果SO PIN被锁住,则为真。用户登录令牌是不可能的。 CKF_SO_PIN_TO_BE_CHANGED 0x00800000 如果SO PIN值通过令牌初始化或加工被设置成错误的值,或PIN由卡终止,则为真。 CKF_WRITE_PROTECTED 标志究竟是指什么,在Cryptoki中没有说明。一个应用程序可能不会对一个写保护令牌执行某些动作。这些动作包括下面任何一种动作: 创建/修改/消除令牌的任意一个对象。 创建/修改/消除令牌上的一个令牌对象 改变SO的PIN。 改变普通用户的PIN。 令牌依靠会话状态执行它的对象管理策略改变CKF_WRITE_PROTECTED 标志的值。例如,只要会话状态是执行策略(不允许任何公共或私有对象创建、修改或消除,除非用户成功调用C_Login)的R/W SO或R/W 用户,令牌可把CKF_WRITE_PROTECTED 标志设置为真。 如果令牌因为它的安全策略不支持函数性或不显示信息,那么CKF_USER_PIN_COUNT_LOW, CKF_USER_PIN_COUNT_LOW, CKF_USER_PIN_FINAL_TRY, 和CKF_SO_PIN_FINAL_TRY 可能被设置成错误。 如果令牌不支持函数性,CKF_USER_PIN_TO_BE_CHANGED 和CKF_SO_PIN_TO_BE_CHANGED 标志可始终设置为错误。如果PIN被设置成错误值,或终止,则适宜的CKF_USER_PIN_TO_BE_CHANGED 或CKF_SO_PIN_TO_BE_CHANGED 标志将被设置为真。当任意一个这些标志是真时,用相对应的PIN注册将会成功,但只有C_SetPIN 函数被调用成功。调用其它需要用户注册的函数将使CKR_PIN_EXPIRED 返回。 注意:字段ulMaxSessionCount, ulSessionCount, ulMaxRwSessionCount, ulRwSessionCount, ulTotalPublicMemory, ulFreePublicMemory, ulTotalPrivateMemory, 和ulFreePrivateMemory 可有特殊值CK_UNAVAILABLE_INFORMATION, 这意味着令牌和/或库不能或不会提供该信息。除此之外,字段ulMaxSessionCount 和ulMaxRwSessionCount 可有特殊的值CK_EFFECTIVELY_INFINITE, 这就意味着一个应用程序用令牌打开的会话(相对应的R/W会话)的数量不会受到实际限制。 这些值的定义如下: #define CK_UNAVAILABLE_INFORMATION (~0UL) #define CK_EFFECTIVELY_INFINITE 0 为这些特殊的值检查这些字段十分重要。这对CK_EFFECTIVELY_INFINITE 是十分真实的,因为在ulMaxSessionCount 或ulMaxRwSessionCount 字段中见到这个值将得出其它的结论它不能用令牌打开任意会话。这决不是一个例子。 所有的这些结果是下列解释(例如)ulMaxSessionCount 字段的正确方法: CK_TOKEN_INFO info; . . . if ((CK_LONG) info.ulMaxSessionCount == CK_UNAVAILABLE_INFORMATION) { /* Token refuses to give value of ulMaxSessionCount */ . . . } else if (info.ulMaxSessionCount == CK_EFFECTIVELY_INFINITE) { /* Application can open as many sessions as it wants */ . . . } else { /* ulMaxSessionCount really does contain what it should */ . . . } CK_TOKEN_INFO_PTR 是CK_TOKEN_INFO的一个指针。 9.3 会话类型 Cryptoki 用如下类型表示会话信息: CK_SESSION_HANDLE; CK_SESSION_HANDLE_PTR CK_SESSION_HANDLE 是一个Cryptoki-指定的值,用于识别会话。其定义如下: typedef CK_ULONG CK_SESSION_HANDLE; Cryptoki中有效的会话句柄始终有非0值。为了开发者的方便,Cryptoki 定义了下列符号值: #define CK_INVALID_HANDLE 0 CK_SESSION_HANDLE_PTR 是CK_SESSION_HANDLE的一个指针。 CK_USER_TYPE CK_USER_TYPE 保持在章节6.4所描述的Cryptoki 用户的类型。其定义如下: typedef CK_ULONG CK_USER_TYPE; 对于Cryptoki的这个版本,用户的类型定义如下: #define CKU_SO 0 #define CKU_USER 1 CK_STATE CK_STATE 保持在章节 和 中所描述的会话状态。其定义如下: typedef CK_ULONG CK_STATE; 对于Cryptoki的这个版本, 会话状态定义如下: #define CKS_RO_PUBLIC_SESSION 0 #define CKS_RO_USER_FUNCTIONS 1 #define CKS_RW_PUBLIC_SESSION 2 #define CKS_RW_USER_FUNCTIONS 3 #define CKS_RW_SO_FUNCTIONS 4 CK_SESSION_INFO; CK_SESSION_INFO_PTR CK_SESSION_INFO 提供关于会话的信息。其定义如下: typedef struct CK_SESSION_INFO { CK_SLOT_ID slotID; CK_STATE state; CK_FLAGS flags; CK_ULONG ulDeviceError; } CK_SESSION_INFO; 结构的字段具有如下含义: slotID 与令牌接口的那个槽的ID state 会话的状态 flags 定义会话的类型的位标志;其定义在后面 ulDeviceError 由密码设备定义的错误编码。用于Cryptoki不能覆盖的错误 下表定义了 flags 字段: 表 122, 会话信息标志 位标志 表征码 含义 CKF_RW_SESSION 0x00000002 如果会话为读/写,则为真;如果会话是只读,则为假 CKF_SERIAL_SESSION 0x00000004 该标志提供向后兼容,并始终设置为真 CK_SESSION_INFO_PTR 是CK_SESSION_INFO的一个指针。 9.4 对象类型 Cryptoki 用如下类型表示对象信息: CK_OBJECT_HANDLE; CK_OBJECT_HANDLE_PTR CK_OBJECT_HANDLE 是对象的一个令牌专用标识符。其定义如下: typedef CK_ULONG CK_OBJECT_HANDLE; 当在令牌上创建或找到一个对象时,Cryptoki 就给它分配一个对象句柄,使应用程序的会话能够访问它。令牌上的一个特定对象在该对象的生存期内不必有一个固定的句柄;但是,如果一个特定的会话能使用一个特定的句柄访问一个特定的对象,那么只要会话继续存在,对象继续存在,对象是该会话可以继续访问的,该会话就能继续使用该令牌访问那个对象。 Cryptoki中有效的会话句柄始终有非0值。为了开发者的方便,Cryptoki 定义了下列符号值: #define CK_INVALID_HANDLE 0 CK_OBJECT_HANDLE_PTR 是CK_OBJECT_HANDLE的一个指针。 CK_OBJECT_CLASS; CK_OBJECT_CLASS_PTR CK_OBJECT_CLASS 是标识Cryptoki 识别的那些对象的类别(或类型)的一个值。其定义如下: typedef CK_ULONG CK_OBJECT_CLASS; 对于Cryptoki的这个版本,定义了如下一些对象类型: #define CKO_DATA 0x00000000 #define CKO_CERTIFICATE 0x00000001 #define CKO_PUBLIC_KEY 0x00000002 #define CKO_PRIVATE_KEY 0x00000003 #define CKO_SECRET_KEY 0x00000004 #define CKO_HW_FEATURE 0x00000005 #define CKO_DOMAIN_PARAMETERS 0x00000006 #define CKO_VENDOR_DEFINED 0x80000000 对象类别CKO_VENDOR_DEFINED 和上述对象类别是为令牌供应者永久保留的。对于互操作性,供应者应通过PKCS进程注册它们的对象类别。 CK_OBJECT_CLASS_PTR 是CK_OBJECT_CLASS的一个指针。 CK_HW_FEATURE_TYPE CK_HW_FEATURE_TYPE 是标识硬件特征类型的部件。其定义如下: typedef CK_ULONG CK_HW_FEATURE_TYPE; 对于Cryptoki的这个版本, 硬件特征类型定义如下: #define CKH_MONOTONIC_COUNTER 0x00000001 #define CKH_CLOCK 0x00000002 #define CKH_VENDOR_DEFINED 0x80000000 特征类型CKH_VENDOR_DEFINED 和上述类型是为令牌供应者保留的。对于互操作性,供应者通过PKCS进程注册它们的特征类型。 CK_KEY_TYPE CK_KEY_TYPE 是标识密钥类型的值。其定义如下: typedef CK_ULONG CK_KEY_TYPE; 对于Cryptoki的这个版本,密钥类型定义如下: #define CKK_RSA 0x00000000 #define CKK_DSA 0x00000001 #define CKK_DH 0x00000002 /* CKK_ECDSA is deprecated in v2.11 */ #define CKK_ECDSA 0x00000003 #define CKK_EC 0x00000003 #define CKK_X9_42_DH 0x00000004 #define CKK_KEA 0x00000005 #define CKK_GENERIC_SECRET 0x00000010 #define CKK_RC2 0x00000011 #define CKK_RC4 0x00000012 #define CKK_DES 0x00000013 #define CKK_DES2 0x00000014 #define CKK_DES3 0x00000015 #define CKK_CAST 0x00000016 #define CKK_CAST3 0x00000017 /* CKK_CAST5 is deprecated in v2.11 */ #define CKK_CAST5 0x00000018 #define CKK_CAST128 0x00000018 #define CKK_RC5 0x00000019 #define CKK_IDEA 0x0000001A #define CKK_SKIPJACK 0x0000001B #define CKK_BATON 0x0000001C #define CKK_JUNIPER 0x0000001D #define CKK_CDMF 0x0000001E #define CKK_AES 0x0000001F #define CKK_VENDOR_DEFINED 0x80000000 密钥类型CKC_VENDOR_DEFINED 和上述类型是为令牌供应者保留的。对于互操作性,供应者通过PKCS进程注册它们的密钥类型。 CK_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE标识证书类型。定义如下: typedef CK_ULONG CK_CERTIFICATE_TYPE; Cryptoki在这个版本中,证书类型定义如下: #define CKC_X_509 0x00000000 #define CKC_X_509_ATTR_CERT 0x00000001 #define CKC_VENDOR_DEFINED 0x80000000 证书类型CKC_VENDOR_DEFINED 和以上将为令牌开发商永久保留。对于互操作性, 供应商可以通过PKCS进程注册证书类型。 CK_ATTRIBUTE_TYPE CK_ATTRIBUTE_TYPE 标识一个属性的类型。其定义如下: typedef CK_ULONG CK_ATTRIBUTE_TYPE; 对于Cryptoki的这个版本,属性类型定义如下: #define CKA_CLASS 0x00000000 #define CKA_TOKEN 0x00000001 #define CKA_PRIVATE 0x00000002 #define CKA_LABEL 0x00000003 #define CKA_APPLICATION 0x00000010 #define CKA_VALUE 0x00000011 #define CKA_OBJECT_ID 0x00000012 #define CKA_CERTIFICATE_TYPE 0x00000080 #define CKA_ISSUER 0x00000081 #define CKA_SERIAL_NUMBER 0x00000082 #define CKA_AC_ISSUER 0x00000083 #define CKA_OWNER 0x00000084 #define CKA_ATTR_TYPES 0x00000085 #define CKA_TRUSTED 0x00000086 #define CKA_KEY_TYPE 0x00000100 #define CKA_SUBJECT 0x00000101 #define CKA_ID 0x00000102 #define CKA_SENSITIVE 0x00000103 #define CKA_ENCRYPT 0x00000104 #define CKA_DECRYPT 0x00000105 #define CKA_WRAP 0x00000106 #define CKA_UNWRAP 0x00000107 #define CKA_SIGN 0x00000108 #define CKA_SIGN_RECOVER 0x00000109 #define CKA_VERIFY 0x0000010A #define CKA_VERIFY_RECOVER 0x0000010B #define CKA_DERIVE 0x0000010C #define CKA_START_DATE 0x00000110 #define CKA_END_DATE 0x00000111 #define CKA_MODULUS 0x00000120 #define CKA_MODULUS_BITS 0x00000121 #define CKA_PUBLIC_EXPONENT 0x00000122 #define CKA_PRIVATE_EXPONENT 0x00000123 #define CKA_PRIME_1 0x00000124 #define CKA_PRIME_2 0x00000125 #define CKA_EXPONENT_1 0x00000126 #define CKA_EXPONENT_2 0x00000127 #define CKA_COEFFICIENT 0x00000128 #define CKA_PRIME 0x00000130 #define CKA_SUBPRIME 0x00000131 #define CKA_BASE 0x00000132 #define CKA_PRIME_BITS 0x00000133 #define CKA_SUB_PRIME_BITS 0x00000134 #define CKA_VALUE_BITS 0x00000160 #define CKA_VALUE_LEN 0x00000161 #define CKA_EXTRACTABLE 0x00000162 #define CKA_LOCAL 0x00000163 #define CKA_NEVER_EXTRACTABLE 0x00000164 #define CKA_ALWAYS_SENSITIVE 0x00000165 #define CKA_KEY_GEN_MECHANISM 0x00000166 #define CKA_MODIFIABLE 0x00000170 /* CKA_ECDSA_PARAMS is deprecated in v2.11 */ #define CKA_ECDSA_PARAMS 0x00000180 #define CKA_EC_PARAMS 0x00000180 #define CKA_EC_POINT 0x00000181 #define CKA_SECONDARY_AUTH 0x00000200 #define CKA_AUTH_PIN_FLAGS 0x00000201 #define CKA_HW_FEATURE_TYPE 0x00000300 #define CKA_RESET_ON_INIT 0x00000301 #define CKA_HAS_RESET 0x00000302 #define CKA_VENDOR_DEFINED 0x80000000 章节 为每个对象类型定义了属性。属性类型CKA_VENDOR_DEFINED 和以上是为令牌供应者保留的。对于互操作性,供应者通过PKCS进程注册它们的属性类型。 CK_ATTRIBUTE; CK_ATTRIBUTE_PTR CK_ATTRIBUTE 是包括属性的类型、值和长度的结构,其定义如下: typedef struct CK_ATTRIBUTE { CK_ATTRIBUTE_TYPE type; CK_VOID_PTR pValue; CK_ULONG ulValueLen; } CK_ATTRIBUTE; 结构的字段具有下列含义: type 属性类型 pValue 属性值的指针 ulValueLen 值的长度(字节数) 如果一个属性没有值,那么ulValueLen = 0, 和 pValue 的值是不相关的。CK_ATTRIBUTE数组 被称为“模板”,用于创建、操作和搜索对象。模板中属性的顺序没有规定,即使模板包含供应者特定的属性。注意:pValue 是一个(空)的指针,便于任意值的传送。应用程序和Cryptoki 库两者必须保证指针能够安全地case所期望的类型(没有字对准错误)。 CK_ATTRIBUTE_PTR 是CK_ATTRIBUTE的一个指针。 CK_DATE CK_DATE 是一个确定日期的结构。其定义如下: typedef struct CK_DATE { CK_CHAR year[4]; CK_CHAR month[2]; CK_CHAR day[2]; } CK_DATE; 结构的字段具有下列含义: year 年 (“1900” - “9999”) month 月 (“01” - “12”) day 日 (“01” - “31”) 各字段保持表3字符集中的数字字符而不是文字字节值。 9.5 机制的数据类型 Cryptoki 支持如下描述机制的类型和它们的参数: CK_MECHANISM_TYPE; CK_MECHANISM_TYPE_PTR CK_MECHANISM_TYPE标识机制的类型。其定义如下: typedef CK_ULONG CK_MECHANISM_TYPE; 对于Cryptoki 2.11版,定义下列机制类型: #define CKM_RSA_PKCS_KEY_PAIR_GEN 0x00000000 #define CKM_RSA_PKCS 0x00000001 #define CKM_RSA_9796 0x00000002 #define CKM_RSA_X_509 0x00000003 #define CKM_MD2_RSA_PKCS 0x00000004 #define CKM_MD5_RSA_PKCS 0x00000005 #define CKM_SHA1_RSA_PKCS 0x00000006 #define CKM_RIPEMD128_RSA_PKCS 0x00000007 #define CKM_RIPEMD160_RSA_PKCS 0x00000008 #define CKM_RSA_PKCS_OAEP 0x00000009 #define CKM_RSA_X9_31_KEY_PAIR_GEN 0x0000000A #define CKM_RSA_X9_31 0x0000000B #define CKM_SHA1_RSA_X9_31 0x0000000C #define CKM_RSA_PKCS_PSS 0x0000000D #define CKM_SHA1_RSA_PKCS_PSS 0x0000000E #define CKM_DSA_KEY_PAIR_GEN 0x00000010 #define CKM_DSA 0x00000011 #define CKM_DSA_SHA1 0x00000012 #define CKM_DH_PKCS_KEY_PAIR_GEN 0x00000020 #define CKM_DH_PKCS_DERIVE 0x00000021 #define CKM_X9_42_DH_KEY_PAIR_GEN 0x00000030 #define CKM_X9_42_DH_DERIVE 0x00000031 #define CKM_X9_42_DH_HYBRID_DERIVE 0x00000032 #define CKM_X9_42_MQV_DERIVE 0x00000033 #define CKM_RC2_KEY_GEN 0x00000100 #define CKM_RC2_ECB 0x00000101 #define CKM_RC2_CBC 0x00000102 #define CKM_RC2_MAC 0x00000103 #define CKM_RC2_MAC_GENERAL 0x00000104 #define CKM_RC2_CBC_PAD 0x00000105 #define CKM_RC4_KEY_GEN 0x00000110 #define CKM_RC4 0x00000111 #define CKM_DES_KEY_GEN 0x00000120 #define CKM_DES_ECB 0x00000121 #define CKM_DES_CBC 0x00000122 #define CKM_DES_MAC 0x00000123 #define CKM_DES_MAC_GENERAL 0x00000124 #define CKM_DES_CBC_PAD 0x00000125 #define CKM_DES2_KEY_GEN 0x00000130 #define CKM_DES3_KEY_GEN 0x00000131 #define CKM_DES3_ECB 0x00000132 #define CKM_DES3_CBC 0x00000133 #define CKM_DES3_MAC 0x00000134 #define CKM_DES3_MAC_GENERAL 0x00000135 #define CKM_DES3_CBC_PAD 0x00000136 #define CKM_CDMF_KEY_GEN 0x00000140 #define CKM_CDMF_ECB 0x00000141 #define CKM_CDMF_CBC 0x00000142 #define CKM_CDMF_MAC 0x00000143 #define CKM_CDMF_MAC_GENERAL 0x00000144 #define CKM_CDMF_CBC_PAD 0x00000145 #define CKM_MD2 0x00000200 #define CKM_MD2_HMAC 0x00000201 #define CKM_MD2_HMAC_GENERAL 0x00000202 #define CKM_MD5 0x00000210 #define CKM_MD5_HMAC 0x00000211 #define CKM_MD5_HMAC_GENERAL 0x00000212 #define CKM_SHA_1 0x00000220 #define CKM_SHA_1_HMAC 0x00000221 #define CKM_SHA_1_HMAC_GENERAL 0x00000222 #define CKM_RIPEMD128 0x00000230 #define CKM_RIPEMD128_HMAC 0x00000231 #define CKM_RIPEMD128_HMAC_GENERAL 0x00000232 #define CKM_RIPEMD160 0x00000240 #define CKM_RIPEMD160_HMAC 0x00000241 #define CKM_RIPEMD160_HMAC_GENERAL 0x00000242 #define CKM_CAST_KEY_GEN 0x00000300 #define CKM_CAST_ECB 0x00000301 #define CKM_CAST_CBC 0x00000302 #define CKM_CAST_MAC 0x00000303 #define CKM_CAST_MAC_GENERAL 0x00000304 #define CKM_CAST_CBC_PAD 0x00000305 #define CKM_CAST3_KEY_GEN 0x00000310 #define CKM_CAST3_ECB 0x00000311 #define CKM_CAST3_CBC 0x00000312 #define CKM_CAST3_MAC 0x00000313 #define CKM_CAST3_MAC_GENERAL 0x00000314 #define CKM_CAST3_CBC_PAD 0x00000315 #define CKM_CAST5_KEY_GEN 0x00000320 #define CKM_CAST128_KEY_GEN 0x00000320 #define CKM_CAST5_ECB 0x00000321 #define CKM_CAST128_ECB 0x00000321 #define CKM_CAST5_CBC 0x00000322 #define CKM_CAST128_CBC 0x00000322 #define CKM_CAST5_MAC 0x00000323 #define CKM_CAST128_MAC 0x00000323 #define CKM_CAST5_MAC_GENERAL 0x00000324 #define CKM_CAST128_MAC_GENERAL 0x00000324 #define CKM_CAST5_CBC_PAD 0x00000325 #define CKM_CAST128_CBC_PAD 0x00000325 #define CKM_RC5_KEY_GEN 0x00000330 #define CKM_RC5_ECB 0x00000331 #define CKM_RC5_CBC 0x00000332 #define CKM_RC5_MAC 0x00000333 #define CKM_RC5_MAC_GENERAL 0x00000334 #define CKM_RC5_CBC_PAD 0x00000335 #define CKM_IDEA_KEY_GEN 0x00000340 #define CKM_IDEA_ECB 0x00000341 #define CKM_IDEA_CBC 0x00000342 #define CKM_IDEA_MAC 0x00000343 #define CKM_IDEA_MAC_GENERAL 0x00000344 #define CKM_IDEA_CBC_PAD 0x00000345 #define CKM_GENERIC_SECRET_KEY_GEN 0x00000350 #define CKM_CONCATENATE_BASE_AND_KEY 0x00000360 #define CKM_CONCATENATE_BASE_AND_DATA 0x00000362 #define CKM_CONCATENATE_DATA_AND_BASE 0x00000363 #define CKM_XOR_BASE_AND_DATA 0x00000364 #define CKM_EXTRACT_KEY_FROM_KEY 0x00000365 #define CKM_SSL3_PRE_MASTER_KEY_GEN 0x00000370 #define CKM_SSL3_MASTER_KEY_DERIVE 0x00000371 #define CKM_SSL3_KEY_AND_MAC_DERIVE 0x00000372 #define CKM_SSL3_MASTER_KEY_DERIVE_DH 0x00000373 #define CKM_TLS_PRE_MASTER_KEY_GEN 0x00000374 #define CKM_TLS_MASTER_KEY_DERIVE 0x00000375 #define CKM_TLS_KEY_AND_MAC_DERIVE 0x00000376 #define CKM_TLS_MASTER_KEY_DERIVE_DH 0x00000377 #define CKM_SSL3_MD5_MAC 0x00000380 #define CKM_SSL3_SHA1_MAC 0x00000381 #define CKM_MD5_KEY_DERIVATION 0x00000390 #define CKM_MD2_KEY_DERIVATION 0x00000391 #define CKM_SHA1_KEY_DERIVATION 0x00000392 #define CKM_PBE_MD2_DES_CBC 0x000003A0 #define CKM_PBE_MD5_DES_CBC 0x000003A1 #define CKM_PBE_MD5_CAST_CBC 0x000003A2 #define CKM_PBE_MD5_CAST3_CBC 0x000003A3 #define CKM_PBE_MD5_CAST5_CBC 0x000003A4 #define CKM_PBE_MD5_CAST128_CBC 0x000003A4 #define CKM_PBE_SHA1_CAST5_CBC 0x000003A5 #define CKM_PBE_SHA1_CAST128_CBC 0x000003A5 #define CKM_PBE_SHA1_RC4_128 0x000003A6 #define CKM_PBE_SHA1_RC4_40 0x000003A7 #define CKM_PBE_SHA1_DES3_EDE_CBC 0x000003A8 #define CKM_PBE_SHA1_DES2_EDE_CBC 0x000003A9 #define CKM_PBE_SHA1_RC2_128_CBC 0x000003AA #define CKM_PBE_SHA1_RC2_40_CBC 0x000003AB #define CKM_PKCS5_PBKD2 0x000003B0 #define CKM_PBA_SHA1_WITH_SHA1_HMAC 0x000003C0 #define CKM_KEY_WRAP_LYNKS 0x00000400 #define CKM_KEY_WRAP_SET_OAEP 0x00000401 #define CKM_SKIPJACK_KEY_GEN 0x00001000 #define CKM_SKIPJACK_ECB64 0x00001001 #define CKM_SKIPJACK_CBC64 0x00001002 #define CKM_SKIPJACK_OFB64 0x00001003 #define CKM_SKIPJACK_CFB64 0x00001004 #define CKM_SKIPJACK_CFB32 0x00001005 #define CKM_SKIPJACK_CFB16 0x00001006 #define CKM_SKIPJACK_CFB8 0x00001007 #define CKM_SKIPJACK_WRAP 0x00001008 #define CKM_SKIPJACK_PRIVATE_WRAP 0x00001009 #define CKM_SKIPJACK_RELAYX 0x0000100a #define CKM_KEA_KEY_PAIR_GEN 0x00001010 #define CKM_KEA_KEY_DERIVE 0x00001011 #define CKM_FORTEZZA_TIMESTAMP 0x00001020 #define CKM_BATON_KEY_GEN 0x00001030 #define CKM_BATON_ECB128 0x00001031 #define CKM_BATON_ECB96 0x00001032 #define CKM_BATON_CBC128 0x00001033 #define CKM_BATON_COUNTER 0x00001034 #define CKM_BATON_SHUFFLE 0x00001035 #define CKM_BATON_WRAP 0x00001036 /* CKM_ECDSA_KEY_PAIR_GEN is deprecated in v2.11 */ #define CKM_ECDSA_KEY_PAIR_GEN 0x00001040 #define CKM_EC_KEY_PAIR_GEN 0x00001040 #define CKM_ECDSA 0x00001041 #define CKM_ECDSA_SHA1 0x00001042 #define CKM_ECDH1_DERIVE 0x00001050 #define CKM_ECDH1_COFACTOR_DERIVE 0x00001051 #define CKM_ECMQV_DERIVE 0x00001052 #define CKM_JUNIPER_KEY_GEN 0x00001060 #define CKM_JUNIPER_ECB128 0x00001061 #define CKM_JUNIPER_CBC128 0x00001062 #define CKM_JUNIPER_COUNTER 0x00001063 #define CKM_JUNIPER_SHUFFLE 0x00001064 #define CKM_JUNIPER_WRAP 0x00001065 #define CKM_FASTHASH 0x00001070 #define CKM_AES_KEY_GEN 0x00001080 #define CKM_AES_ECB 0x00001081 #define CKM_AES_CBC 0x00001082 #define CKM_AES_MAC 0x00001083 #define CKM_AES_MAC_GENERAL 0x00001084 #define CKM_AES_CBC_PAD 0x00001085 #define CKM_DSA_PARAMETER_GEN 0x00002000 #define CKM_DH_PKCS_PARAMETER_GEN 0x00002001 #define CKM_X9_42_DH_PARAMETER_GEN 0x00002002 #define CKM_VENDOR_DEFINED 0x80000000 机制类型CKM_VENDOR_DEFINED和上述类型是为令牌供应者保留的。对于互操作性,供应者通过PKCS进程注册它们的机制类型。 CK_MECHANISM_TYPE_PTR 是CK_MECHANISM_TYPE的一个指针。 CK_MECHANISM; CK_MECHANISM_PTR CK_MECHANISM 是一个确定特定机制及其所需参数的结构。其定义如下: typedef struct CK_MECHANISM { CK_MECHANISM_TYPE mechanism; CK_VOID_PTR pParameter; CK_ULONG ulParameterLen; } CK_MECHANISM; 结构的字段具有如下含义: mechanism 机制的类型 pParameter 指向参数的指针,如果机制需要的话 ulParameterLen 参数的长度(字节数) 注意,pParameter 是一个“空”指针,因此简化了任意值的传送。应用程序和Cryptoki 库两者必须确保指针可以安全地铸造成所期望的类型(没有字对准错误)。 CK_MECHANISM_PTR 是CK_MECHANISM的一个指针。 CK_MECHANISM_INFO; CK_MECHANISM_INFO_PTR CK_MECHANISM_INFO 是一个提供有关一个特定机制信息的结构。其定义如下: typedef struct CK_MECHANISM_INFO { CK_ULONG ulMinKeySize; CK_ULONG ulMaxKeySize; CK_FLAGS flags; } CK_MECHANISM_INFO; 结构的字节具有下列含义: ulMinKeySize 机制密钥的最小大小(不管是由位进行测量还是由字节进行测量,都是独立机制) ulMaxKeySize 机制密钥的最大大小(不管是由位进行测量还是由字节进行测量,都是独立机制) flags 指定机制能力的位标志 对于某些机制,ulMinKeySize 和ulMaxKeySize 字段具有一些无意义的值。 下表定义了 flags 字段: 表 133, 机制信息标志 位标志 表征位 含义 CKF_HW 0x00000001 如果机制是用设备执行的,则为真;如果机制是用软件执行的,则为假。 CKF_ENCRYPT 0x00000100 如果机制可以与C_EncryptInit一起使用则为真。 CKF_DECRYPT 0x00000200 如果机制可以与C_DecryptInit一起使用,则为真 CKF_DIGEST 0x00000400 如果机制可以与 C_DigestInit一起使用,则为真 CKF_SIGN 0x00000800 如果机制可以与C_SignInit一起使用,则为真 CKF_SIGN_RECOVER 0x00001000 如果机制可以与C_SignRecoverInit一起使用,则为真 CKF_VERIFY 0x00002000 如果机制可以与C_VerifyInit一起使用,则为真 CKF_VERIFY_RECOVER 0x00004000 如果机制可以与 C_VerifyRecoverInit一起使用,则为真 CKF_GENERATE 0x00008000 如果机制可以与C_GenerateKey一起使用,则为真 CKF_GENERATE_KEY_PAIR 0x00010000 如果机制可以与C_GenerateKeyPair一起使用,则为真 CKF_WRAP 0x00020000 如果机制可以与C_WrapKey一起使用,则为真 CKF_UNWRAP 0x00040000 如果机制可以与C_UnwrapKey一起使用,则为真 CKF_DERIVE 0x00080000 如果机制可以与C_DeriveKey一起使用,则为真 CKF_EC_F_P 0x00100000 如果该机制在Fp上使用EC域参数, 则为真 CKF_EC_F_2M 0x00200000 如果该机制在F2m上使用EC域参数, 则为真 CKF_EC_ECPARAMETERS 0x00400000 如果该机制在F2m上使用EC域ecParameters的参数, 则为真 CKF_EC_NAMEDCURVE 0x00800000 如果该机制在F2m上使用EC域namedCurve的参数, 则为真 CKF_EC_UNCOMPRESS 0x01000000 TRUE if the mechanism can be used with elliptic curve point uncompressed CKF_EC_COMPRESS 0x02000000 TRUE if the mechanism can be used with elliptic curve point compressed CKF_EXTENSION 0x80000000 如果是标志的延长部分,则为真;如果不是标志的延长部分,则为假。对于该版本必须为假。 CK_MECHANISM_INFO_PTR 是CK_MECHANISM_INFO的一个指针。 9.6 函数类型 Cryptoki 用下列数据类型表示有关函数的信息: CK_RV CK_RV 是一个标识Cryptoki 函数返回值的值。其定义如下: typedef CK_ULONG CK_RV; 对于Cryptoki的这个版本,定义了下列一些返回值: #define CKR_OK 0x00000000 #define CKR_CANCEL 0x00000001 #define CKR_HOST_MEMORY 0x00000002 #define CKR_SLOT_ID_INVALID 0x00000003 #define CKR_GENERAL_ERROR 0x00000005 #define CKR_FUNCTION_FAILED 0x00000006 #define CKR_ARGUMENTS_BAD 0x00000007 #define CKR_NO_EVENT 0x00000008 #define CKR_NEED_TO_CREATE_THREADS 0x00000009 #define CKR_CANT_LOCK 0x0000000A #define CKR_ATTRIBUTE_READ_ONLY 0x00000010 #define CKR_ATTRIBUTE_SENSITIVE 0x00000011 #define CKR_ATTRIBUTE_TYPE_INVALID 0x00000012 #define CKR_ATTRIBUTE_VALUE_INVALID 0x00000013 #define CKR_DATA_INVALID 0x00000020 #define CKR_DATA_LEN_RANGE 0x00000021 #define CKR_DEVICE_ERROR 0x00000030 #define CKR_DEVICE_MEMORY 0x00000031 #define CKR_DEVICE_REMOVED 0x00000032 #define CKR_ENCRYPTED_DATA_INVALID 0x00000040 #define CKR_ENCRYPTED_DATA_LEN_RANGE 0x00000041 #define CKR_FUNCTION_CANCELED 0x00000050 #define CKR_FUNCTION_NOT_PARALLEL 0x00000051 #define CKR_FUNCTION_NOT_SUPPORTED 0x00000054 #define CKR_KEY_HANDLE_INVALID 0x00000060 #define CKR_KEY_SIZE_RANGE 0x00000062 #define CKR_KEY_TYPE_INCONSISTENT 0x00000063 #define CKR_KEY_NOT_NEEDED 0x00000064 #define CKR_KEY_CHANGED 0x00000065 #define CKR_KEY_NEEDED 0x00000066 #define CKR_KEY_INDIGESTIBLE 0x00000067 #define CKR_KEY_FUNCTION_NOT_PERMITTED 0x00000068 #define CKR_KEY_NOT_WRAPPABLE 0x00000069 #define CKR_KEY_UNEXTRACTABLE 0x0000006A #define CKR_MECHANISM_INVALID 0x00000070 #define CKR_MECHANISM_PARAM_INVALID 0x00000071 #define CKR_OBJECT_HANDLE_INVALID 0x00000082 #define CKR_OPERATION_ACTIVE 0x00000090 #define CKR_OPERATION_NOT_INITIALIZED 0x00000091 #define CKR_PIN_INCORRECT 0x000000A0 #define CKR_PIN_INVALID 0x000000A1 #define CKR_PIN_LEN_RANGE 0x000000A2 #define CKR_PIN_EXPIRED 0x000000A3 #define CKR_PIN_LOCKED 0x000000A4 #define CKR_SESSION_CLOSED 0x000000B0 #define CKR_SESSION_COUNT 0x000000B1 #define CKR_SESSION_HANDLE_INVALID 0x000000B3 #define CKR_SESSION_PARALLEL_NOT_SUPPORTED 0x000000B4 #define CKR_SESSION_READ_ONLY 0x000000B5 #define CKR_SESSION_EXISTS 0x000000B6 #define CKR_SESSION_READ_ONLY_EXISTS 0x000000B7 #define CKR_SESSION_READ_WRITE_SO_EXISTS 0x000000B8 #define CKR_SIGNATURE_INVALID 0x000000C0 #define CKR_SIGNATURE_LEN_RANGE 0x000000C1 #define CKR_TEMPLATE_INCOMPLETE 0x000000D0 #define CKR_TEMPLATE_INCONSISTENT 0x000000D1 #define CKR_TOKEN_NOT_PRESENT 0x000000E0 #define CKR_TOKEN_NOT_RECOGNIZED 0x000000E1 #define CKR_TOKEN_WRITE_PROTECTED 0x000000E2 #define CKR_UNWRAPPING_KEY_HANDLE_INVALID 0x000000F0 #define CKR_UNWRAPPING_KEY_SIZE_RANGE 0x000000F1 #define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT 0x000000F2 #define CKR_USER_ALREADY_LOGGED_IN 0x00000100 #define CKR_USER_NOT_LOGGED_IN 0x00000101 #define CKR_USER_PIN_NOT_INITIALIZED 0x00000102 #define CKR_USER_TYPE_INVALID 0x00000103 #define CKR_USER_ANOTHER_ALREADY_LOGGED_IN 0x00000104 #define CKR_USER_TOO_MANY_TYPES 0x00000105 #define CKR_WRAPPED_KEY_INVALID 0x00000110 #define CKR_WRAPPED_KEY_LEN_RANGE 0x00000112 #define CKR_WRAPPING_KEY_HANDLE_INVALID 0x00000113 #define CKR_WRAPPING_KEY_SIZE_RANGE 0x00000114 #define CKR_WRAPPING_KEY_TYPE_INCONSISTENT 0x00000115 #define CKR_RANDOM_SEED_NOT_SUPPORTED 0x00000120 #define CKR_RANDOM_NO_RNG 0x00000121 #define CKR_DOMAIN_PARAMS_INVALID 0x00000130 #define CKR_BUFFER_TOO_SMALL 0x00000150 #define CKR_SAVED_STATE_INVALID 0x00000160 #define CKR_INFORMATION_SENSITIVE 0x00000170 #define CKR_STATE_UNSAVEABLE 0x00000180 #define CKR_CRYPTOKI_NOT_INITIALIZED 0x00000190 #define CKR_CRYPTOKI_ALREADY_INITIALIZED 0x00000191 #define CKR_MUTEX_BAD 0x000001A0 #define CKR_MUTEX_NOT_LOCKED 0x000001A1 #define CKR_VENDOR_DEFINED 0x80000000 章节11.1 定义了每个CK_RV 值的含义。返回值CKR_VENDOR_DEFINED和以上是为令牌供应者保留的。对于互操作性,供应者通过PKCS进程注册它们的返回类型。 CK_NOTIFY CK_NOTIFY 是一种指向Cryptoki 执行通知回调的函数的指针。其定义如下: typedef CK_CALLBACK_FUNCTION(CK_RV, CK_NOTIFY)( CK_SESSION_HANDLE hSession, CK_NOTIFICATION event, CK_VOID_PTR pApplication ); 通知回调函数的变元具有如下含义: hSession 执行回调的会话的句柄 event 通知回调的类型 pApplication 应用程序定义的值。这个值与C_OpenSession 用于打开执行回调的会话的值相同。 CK_C_XXX Cryptoki 还定义了一系列其它函数指针类型。对于Cryptoki API 中的每个函数C_XXX (Cryptoki Version 2.11中有68个这样的函数,关于其中每个函数的详情,请参见第11章),Cryptoki定义了类型CK_C_XXX,它是一个与C_XXX 具有相同变元和返回值的函数的指针。一个应用程序可以使用一套专用的不同类型的CK_C_XXX 调用Cryptoki 函数CK_C_XXX 。 CK_FUNCTION_LIST; CK_FUNCTION_LIST_PTR; CK_FUNCTION_LIST_PTR_PTR CK_FUNCTION_LIST 是包含一个Cryptoki 版本和一个指向Cryptoki API中每个函数的函数指针的结构。其定义如下: typedef struct CK_FUNCTION_LIST { CK_VERSION version; CK_C_Initialize C_Initialize; CK_C_Finalize C_Finalize; CK_C_GetInfo C_GetInfo; CK_C_GetFunctionList C_GetFunctionList; CK_C_GetSlotList C_GetSlotList; CK_C_GetSlotInfo C_GetSlotInfo; CK_C_GetTokenInfo C_GetTokenInfo; CK_C_GetMechanismList C_GetMechanismList; CK_C_GetMechanismInfo C_GetMechanismInfo; CK_C_InitToken C_InitToken; CK_C_InitPIN C_InitPIN; CK_C_SetPIN C_SetPIN; CK_C_OpenSession C_OpenSession; CK_C_CloseSession C_CloseSession; CK_C_CloseAllSessions C_CloseAllSessions; CK_C_GetSessionInfo C_GetSessionInfo; CK_C_GetOperationState C_GetOperationState; CK_C_SetOperationState C_SetOperationState; CK_C_Login C_Login; CK_C_Logout C_Logout; CK_C_CreateObject C_CreateObject; CK_C_CopyObject C_CopyObject; CK_C_DestroyObject C_DestroyObject; CK_C_GetObjectSize C_GetObjectSize; CK_C_GetAttributeValue C_GetAttributeValue; CK_C_SetAttributeValue C_SetAttributeValue; CK_C_FindObjectsInit C_FindObjectsInit; CK_C_FindObjects C_FindObjects; CK_C_FindObjectsFinal C_FindObjectsFinal; CK_C_EncryptInit C_EncryptInit; CK_C_Encrypt C_Encrypt; CK_C_EncryptUpdate C_EncryptUpdate; CK_C_EncryptFinal C_EncryptFinal; CK_C_DecryptInit C_DecryptInit; CK_C_Decrypt C_Decrypt; CK_C_DecryptUpdate C_DecryptUpdate; CK_C_DecryptFinal C_DecryptFinal; CK_C_DigestInit C_DigestInit; CK_C_Digest C_Digest; CK_C_DigestUpdate C_DigestUpdate; CK_C_DigestKey C_DigestKey; CK_C_DigestFinal C_DigestFinal; CK_C_SignInit C_SignInit; CK_C_Sign C_Sign; CK_C_SignUpdate C_SignUpdate; CK_C_SignFinal C_SignFinal; CK_C_SignRecoverInit C_SignRecoverInit; CK_C_SignRecover C_SignRecover; CK_C_VerifyInit C_VerifyInit; CK_C_Verify C_Verify; CK_C_VerifyUpdate C_VerifyUpdate; CK_C_VerifyFinal C_VerifyFinal; CK_C_VerifyRecoverInit C_VerifyRecoverInit; CK_C_VerifyRecover C_VerifyRecover; CK_C_DigestEncryptUpdate C_DigestEncryptUpdate; CK_C_DecryptDigestUpdate C_DecryptDigestUpdate; CK_C_SignEncryptUpdate C_SignEncryptUpdate; CK_C_DecryptVerifyUpdate C_DecryptVerifyUpdate; CK_C_GenerateKey C_GenerateKey; CK_C_GenerateKeyPair C_GenerateKeyPair; CK_C_WrapKey C_WrapKey; CK_C_UnwrapKey C_UnwrapKey; CK_C_DeriveKey C_DeriveKey; CK_C_SeedRandom C_SeedRandom; CK_C_GenerateRandom C_GenerateRandom; CK_C_GetFunctionStatus C_GetFunctionStatus; CK_C_CancelFunction C_CancelFunction; CK_C_WaitForSlotEvent C_WaitForSlotEvent; } CK_FUNCTION_LIST; 每个Cryptoki 库中都有一个静态CK_FUNCTION_LIST 结构,并且它的指针(或它的拷贝的指针也属于该库)可以用C_GetFunctionList 获得(见章节11.2)。该指针指向的值能被一个应用程序使用快速地找出Cryptoki API 中每个函数的可执行编码。Cryptoki API 中的每个函数必须有一个Cryptoki 库的CK_FUNCTION_LIST 结构确定的输入点。如果一个库并不支持Cryptoki API 中的特定函数,那么该库的CK_FUNCTION_LIST 结构中的该函数的函数指针应当能轻易返回CKR_FUNCTION_NOT_SUPPORTED。 一个应用程序可以、也不可以修改一个Cryptoki 库的静态CK_FUNCTION_LIST 结构。无论可以与否,都不要试图这么做。 CK_FUNCTION_LIST_PTR 是CK_FUNCTION_LIST的一个指针。 CK_FUNCTION_LIST_PTR_PTR 是CK_FUNCTION_LIST_PTR的一个指针。 9.7 相关锁定类型 本章中的类型单独提供给需要从类似的多线程中访问Cryptoki 的应用程序。 不这么做的应用程序不使用这些类型。 CK_CREATEMUTEX CK_CREATEMUTEX 是一种应用程序提供的建立一个新的人工干预的对象并返回一个指针函数的指针类型。其定义如下: typedef CK_CALLBACK_FUNCTION(CK_RV, CK_CREATEMUTEX)( CK_VOID_PTR_PTR ppMutex ); 调用的一个 CK_CREATEMUTEX 函数通过ppMutex把指针返回到位置中的新的人工干预的对象。这种函数应该返回下列值之一: CKR_OK, CKR_GENERAL_ERROR, CKR_HOST_MEMORY. CK_DESTROYMUTEX CK_DESTROYMUTEX 是一种毁坏现有的人工干预对象的应用程序提供的函数的指针类型。其定义如下: typedef CK_CALLBACK_FUNCTION(CK_RV, CK_DESTROYMUTEX)( CK_VOID_PTR pMutex ); CK_DESTROYMUTEX 函数的变元是将被毁坏的人工干预的对象的指针。这种函数应当返回下列值之一: CKR_OK, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_MUTEX_BAD。 CK_LOCKMUTEX 和CK_UNLOCKMUTEX CK_LOCKMUTEX 是一种锁住现有的人工干预对象的应用程序支持的函数的指针类型。CK_UNLOCKMUTEX 是一种未锁住现有的人工干预对象的应用程序支持的函数的指针类型。这些类型的函数的合适行为如下: 如果在一个未锁住的人工干预上调用一个CK_LOCKMUTEX 函数,则调用的线程在人工干预上包含一个锁并返回。 如果在一个由某个线程而不是调用线程锁住的人工干预上调用一个CK_LOCKMUTEX 函数,则调用的线程屏蔽并等待人工干预开锁。 如果在一个由调用线程锁住的人工干预上调用一个CK_LOCKMUTEX 函数,函数调用的行为未被确定。 如果在一个由调用的线程锁住的人工干预上调用一个CK_UNLOCKMUTEX 函数,则该人工干预为被锁住并且该函数调用返回。而且: 如果恰好一个线程在在该特定的人工干预上锁住,则该线程停止锁住,在该人工干预上包含一个锁,并且它的CK_LOCKMUTEX 调用返回。 如果不止一个线程在该特定的人工干预上被锁住,则恰好其中一个锁住的线程以某种方法被选择。该幸运的线程停止锁住,在该人工干预上包含一个锁,并且它的CK_LOCKMUTEX 调用返回。其它在该特定的人工干预上锁住的线程,继续被锁住。 如果在一个未被锁住的人工干预上调用一个CK_UNLOCKMUTEX 函数,则该函数调用返回一个错误编码CKR_MUTEX_NOT_LOCKED。 如果在一个由某个线程而不是其它调用线程锁住的人工干预上调用一个CK_UNLOCKMUTEX 函数,则函数调用的行为未被确定。 CK_LOCKMUTEX 定义如下: typedef CK_CALLBACK_FUNCTION(CK_RV, CK_LOCKMUTEX)( CK_VOID_PTR pMutex ); CK_LOCKMUTEX 函数的变元是将被锁住的人工干预的指针。这种函数应该返回下面其中一个值:CKR_OK, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_MUTEX_BAD。 CK_UNLOCKMUTEX 定义如下: typedef CK_CALLBACK_FUNCTION(CK_RV, CK_UNLOCKMUTEX)( CK_VOID_PTR pMutex ); CK_UNLOCKMUTEX 函数的变元是将被开锁的人工干预的一个指针。这种函数应当返回下列其中一个值: CKR_OK, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_MUTEX_BAD, CKR_MUTEX_NOT_LOCKED. CK_C_INITIALIZE_ARGS; CK_C_INITIALIZE_ARGS_PTR CK_C_INITIALIZE_ARGS 是包含C_Initialize函数可选变元的结构。对于Cryptoki的这个版本,这些可选的变元涉及到该库处理线程的方式。 CK_C_INITIALIZE_ARGS 定义如下: typedef struct CK_C_INITIALIZE_ARGS { CK_CREATEMUTEX CreateMutex; CK_DESTROYMUTEX DestroyMutex; CK_LOCKMUTEX LockMutex; CK_UNLOCKMUTEX UnlockMutex; CK_FLAGS flags; CK_VOID_PTR pReserved; } CK_C_INITIALIZE_ARGS; 结构的字段具有下列含义: CreateMutex 用作建立人工干预对象的函数的指针 DestroyMutex 用作销毁人工干预对象的函数的指针 LockMutex 用作锁住人工干预对象的函数的指针 UnlockMutex 用作开锁人工干预对象的函数的指针 flags 为C_Initialize确定选项的位标志;这些标志在以后定义 pReserved 为未来使用保留。Cryptoki的这个版本应为NULL_PTR 下表定义了 flags 字段: 表 144, C_Initialize 参数标志 位标志 表征码 含义 CKF_LIBRARY_CANT_CREATE_OS_THREADS 0x00000001 如果执行库的调用的应用程序线程不可以使用本身的操作系统产生新线程的调用,则为真;如果可以,则为假。 CKF_OS_LOCKING_OK 0x00000002 如果库能使用本身的操作系统穿过模型锁住,则为真。反之为假。 CK_C_INITIALIZE_ARGS_PTR 是CK_C_INITIALIZE_ARGS的一个指针。 10. 对象 Cryptoki 能够识别在CK_OBJECT_CLASS 数据类型中定义的许多对象类别。对象包括一套属性,每个对象都具有一个给定值。一个对象处理的每个属性在先前都有一个值。下图列出了Cryptoki 对象的高级层次结构和它们支持的属性: 图5, 对象属性体系 Cryptoki 提供建立、破坏和复制对象的函数,并且包含并修改它们属性的值。有些密码函数(如, C_GenerateKey) 也能建立对象并保持结果。 对象在Cryptoki中总是“良好形成”的—那就是,一个对象总是包含所有需要的属性,并且该属性从建立对象起就与其它保持一致。这与某些基于对象的范例(当有时建立并未被初始化时,一个对象没有属性而不可能是一个级别)对比。在Cryptoki中,对象总被初始化。 按照属性值的数据类型和属性的意义,第10章的大部分表格确定每个Cryptoki属性,可能包括失败的初始值。某些数据类型清楚地由Cryptoki确定(如CK_OBJECT_CLASS )。属性值可能有下列一些类型: Byte 组 一个任意串的 CK_BYTEs Big 整数 一串CK_BYTE代表一个未签名的有意义的字节在前面的任意大小的整数(如整数32768 表示为2字节串 0x80 0x00) Local 串 带有0结尾的未填充的串CK_CHAR RFC2279 串 带有0结尾的未填充的串 CK_UTF8CHARs 一个令牌能保持几个相同的对象,即它允许两个以上的对象确实有它们属性的相同的值。 除了RSA私钥对象之外(见章节),Cryptoki中详述的每个对象类型处理一套完全确定的Cryptoki属性。例如,一个X.509公共密钥证书对象(见章节10.6.1)确实具有下列Cryptoki属性: CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_MODIFIABLE, CKA_LABEL, CKA_CERTIFICATE_TYPE, CKA_SUBJECT, CKA_ID, CKA_ISSUER, CKA_SERIAL_NUMBER, CKA_VALUE。部分这些属性处理错误值,并当建立一个对象时,不需要被定义;某些这种错误值甚至是空串。然而,该对象处理这些属性。一个给定对象有它所处理的每个属性的单个值,即使该属性是一个供应商专用属性(其意义在Cryptoki 范围之外)。 除了处理Cryptoki 属性之外,对象可能处理额外的供应者专用属性(其含义和值在Cryptoki 中未被规定)。 10.1 创建、修改和复制对象 用于创建、修改和复制对象的所有Cryptoki 函数都将一个模板作为它们的其中一个变元,该模板定义属性值。用于创建对象的密码函数(见第节)还可以拥有它们自己的附加属性值;这些属性值由一个密码函数调用根据当前正在执行哪一种密码机制来确定(见第12节)。在任何情况下,如果某一对象类支持的所有必要属性没有缺省值,那么当创建对象时必须在模板中或由函数本身确定它们。 10.1.1 创建对象 对象可以使用Cryptoki函数C_CreateObject (见第节)、C_GenerateKey、C_GenerateKeyPair、C_UnwrapKey和C_DeriveKey (见第节)来进行创建。另外,复制一个现有对象(使用C_CopyObject函数)也将创建一个新的对象,但对于这种类型的对象创建我们将在第节中单独加以介绍。 使用上述任何一种函数创建对象都需要提供一个恰当的模板。 1. 如果所提供的模板为一个无效属性指定值,那么创建对象的尝试将失败,并返回错误码CKR_ATTRIBUTE_TYPE_INVALID。对于一个属性,只有当它是Cryptoki规范中所描述的属性或是由该函数库和令牌支持的附加专用客户属性时才有效。 2. 如果所提供的模板为一个有效属性指定一个无效值,那么创建对象的尝试也将失败,并返回错误码CKR_ATTRIBUTE_VALUE_INVALID。在Cryptoki规范中对Cryptoki属性的有效值进行了描述。 3. 如果所提供的模板为一个只读属性指定值,那么创建对象的尝试将失败,并返回错误码 CKR_ATTRIBUTE_READ_ONLY。在Cryptoki规范中,对一个给定的Cryptoki属性是否为只读加以了明示;但是,一个特殊的函数库和令牌往往比Cryptoki函数库的要求更严格。换言之,一个Cryptoki认为不是只读的属性在特定情况下(例如与其它属性的组合一起使用)对于一个特殊函数库和令牌则有可能是只读的。一个给定的非Cryptoki属性是否为只读显然不属于Cryptoki规范的讨论范畴。 4. 如果模板中的属性值连同任何缺省属性值以及由对象创建函数本身提供给该对象的属性值都还不足以完全说明将要创建的对象,那么创建对象的尝试将失败,并返回错误码CKR_TEMPLATE_INCOMPLETE。 5. 如果模板中的属性值连同任何缺省属性值以及由对象创建函数本身提供给该对象的属性值是前后不一致的,那么创建该对象的尝试也将会失败,并返回错误码CKR_TEMPLATE_INCONSISTENT。如果一组属性值并不是全部都能够同时满足令牌的要求,那么尽管所有单个值在Cryptoki中都是有效的,该组属性值也是不一致的。例如,对于同一个模板指定两个不同的值。又如,试图用CKA_MODULUS属性来创建一个RC4密钥对象;CKA_MODULUS属性对于多种不同类型的公钥(见第节)或私钥(见第节)是恰当的,但对于RC4密钥则是不恰当的。最后一个例子是,在一个要求所有RSA公钥的指数(exponent)都为65537的令牌上创建一个指数为17的RSA公钥。注意,最后这个不一致模板的例子是与令牌相关的;也就是说,如果是在允许某一个RSA公钥的指数为17的不同令牌上创建此密钥对象,那么该模板就不再是非一致的了。 6. 如果模板不止一次地为一个特定属性指定相同的值(或者该模板为已由对象创建函数本身提供给对象的一个特定属性指定相同的值),那么Cryptoki的行为则不能完全确定。创建对象的尝试有可能会成功——从而创建一个已经被创建的相同对象,如果这个多次指定值的属性只出现一次的话——或者它也有可能失败,返回错误码CKR_TEMPLATE_INCONSISTENT。程序库开发人员应尽可能地把程序库设计成好像属性在模板中只出现一次;而应用程序开发人员则应尽可能地避免将一个特定属性多次放入一个特定的模板中。 在尝试创建一个对象时,如果出现了上述多种情况,那么此次尝试所返回的错误码有可能为上述错误码中的任何一种。 10.1.2 修改对象 对象可以使用Cryptoki函数C_SetAttributeValue (见第节)来进行修改。提供给C_SetAttributeValue的模板可以为该对象已经拥有的属性指定新值; 也可为该对象尚未拥有的属性指定值;或者两种情况皆有。 在一个对象已被创建之后,它的某些属性可以修改,而有些属性则不能修改。此外,在某些令牌上,Cryptoki指定可以修改的属性实际是不能修改的。也就是说,如果一个Cryptoki 属性被描述为是可修改的,那么实际上它只意味着该属性在Cryptoki规范所涉及的范围内是可修改的。一个特定的令牌实际上有可能不支持某些这类属性的修改。因此,在特定的令牌上一个对象的某一特定属性是否可以修改取决于该对象具体属性的值。例如,一个密钥对象的CKA_SENSITIVE属性可以从FALSE改变为TRUE,但是反之则不行。 第节中描述的所有情况——包括它们所返回的错误码——均适用于使用 C_SetAttributeValue函数修改对象,除非存在模板不完备的可能性。 10.1.3 复制对象 对象可以使用Cryptoki函数C_CopyObject (见第节)来进行复制。在复制一个对象的过程中,函数C_CopyObject还可以根据一个由具体应用提供的模板,来修改这个新创建副本的属性。 在C_CopyObject操作过程中可被修改的Cryptoki属性与被描述为可修改的Cryptoki属性相同,外加三个特殊属性CKA_TOKEN、CKA_PRIVATE和CKA_MODIFIABLE。更确切地说,就Cryptoki规范而言,这些属性在C_CopyObject操作过程中是可被修改的。一个特定的令牌在C_CopyObject操作过程中实际上有可能不支持某些这类属性的修改。因此,在特定的令牌上,一个对象的某一特定属性在C_CopyObject操作过程中是否可以被修改取决于该对象具体属性的值。例如,一个密钥对象的CKA_SENSITIVE属性在C_CopyObject函数的操作过程中可以从FALSE改变为TRUE,但是反之则不行。 第节中描述的所有情况——包括它们所返回的错误码——均适用于使用C_CopyObject函数复制对象,除非存在模板不完备的可能性。 10.2 公共属性 下表定义了可为所有对象共用的属性: 表14 公共的对象属性 属 性 数据类型 含 义 CKA_CLASS1 CK_OBJECT_CLASS 对象分类 (类型) 1在创建对象时必须加以指定。 Cryptoki 2.1版支持以下CKA_CLASS值 (即下面的对象分类(类型)): CKO_HW_FEATURE,CKO_DATA,CKO_CERTIFICATE,CKO_PUBLIC_KEY,CKO_PRIVATE_KEY和CKO_SECRET_KEY。 10.3 硬件特征对象 硬件特征对象(CKO_HW_FEATURE) 表示设备的特征。它们提供一种容易扩展的方法,来将新的基于值的特征介绍给Cryptoki接口。下图描绘了硬件特征对象的层次以及它们所支持的一些属性。 图6 硬件特征对象属性的层次结构 当使用C_FindObjectsInit和C_FindObjects搜索对象时,除非模板中的CKA_CLASS属性具有CKO_HW_FEATURE值,否则不返回硬件特征对象。这就可以避免在针对以前的Cryptoki版本而编写的应用程序中存在它们所不能理解的对象。 表15 硬件特征的公共属性 属 性 数据类型 含 义 CKA_HW_FEATURE_TYPE CK_HW_FEATURE 硬件特征 (类型) Cryptoki 2.1版支持以下CKA_FEATURE_TYPE值:CKH_MONOTONIC_COUNTER和CKH_CLOCK. 10.3.1 时钟对象 时钟对象表示设备上存在的实时时钟。这代表的是与CK_TOKEN_INFO 结构中的utcTime 字段相同的时钟源。 表16 时钟对象属性 属 性 数据类型 含 义 CKA_VALUE CK_CHAR[16] 当前时间用一个长度为16的字符串表示,其格式为:YYYYMMDDhhmmssxx (4个字符表示年;分别以2个字符表示月、日、小时、分钟和秒;最后2个为附加的保留‘0’字符)。 如果设备允许的话,CKA_VALUE属性可以使用C_SetAttributeValue函数来设定。用来设定时间的话路(session)必须要注册。设备可能要求SO 作为注册的用户,以修改时间值。C_SetAttributeValue将返回错误码CKR_USER_NOT_LOGGED_IN,表示需要一个不同的用户类型来设定该值。 10.3.2 单调计数器对象 单调计数器对象表示设备上存在的硬件计数器。计数器要确保每次读其值时能够增加值,但不要求每次必须加1。 表17 单调计数器属性 属 性 数据类型 含 义 CKA_RESET_ON_INIT1 CK_BBOOL 如果该令牌被用C_InitializeToken.进行了初始化,那么计数器的值将复位至一个先前返回的值。 CKA_HAS_RESET1 CK_BBOOL 该计数器的值在某些点至少已经被及时复位过一次。 CKA_VALUE1 Byte Array 单调计数器的当前版本。 值以大数在前(big endian)的次序返回。 1只读 客户不能够设定CKA_VALUE属性。 10.4 存储对象 表18 公共的存储对象属性 属 性 数据类型 含 义 CKA_TOKEN CK_BBOOL 如果对象是一个令牌对象,则为TRUE; 如果对象是一个话路对象,则为FALSE; (缺省值为FALSE)。 CKA_PRIVATE CK_BBOOL 如果对象是一个私有对象,则为TRUE; 如果对象是一个公开对象,则为FALSE; 缺省值是随令牌不同而变化的,并且有可能取决于该对象其它属性的值。 CKA_MODIFIABLE CK_BBOOL 如果对象可以被修改,则为TRUE; (缺省值为TRUE) CKA_LABEL RFC2279 string 该对象的说明; (缺省为空)。 在该对象被创建之后,只有CKA_LABEL属性可以被修改。(但是在复制一个对象的过程中,CKA_TOKEN、CKA_PRIVATE和CKA_MODIFIABLE属性可以被改变。) CKA_TOKEN属性标识该对象是一个令牌对象,还是一个话路对象。 当CKA_PRIVATE属性为TRUE时,用户不允许访问这个对象,直至该用户得到此令牌的验证。 CKA_MODIFIABLE属性的值确定一个对象是否为只读。一个不可修改的对象可能允许被删除,也可能不允许被删除。 CKA_LABEL属性旨在帮助用户进行浏览。 10.5 数据对象 数据对象(对象类型为CKO_DATA)含有一个应用所定义的信息。除了提供对它的访问外,Cryptoki不向一个数据对象添加任何特殊含义。下表列出了数据对象所支持的属性,此外数据对象也支持表14和表18中所列出的公共属性。 表19 数据对象属性 属 性 数据类型 含 义 CKA_APPLICATION RFC2279 string 管理该对象的应用说明; (缺省为空)。 CKA_OBJECT_ID Byte Array 表明该数据对象类型的对象标识符DER-编码; (缺省为空)。 CKA_VALUE Byte array 该对象的值; (缺省为空)。 在创建对象之后,这些属性都可以被修改。 CKA_APPLICATION属性为应用提供一种说明其所管理的数据对象相关情况的方法。 但是,Cryptoki并不确保只有一个特殊应用才能访问某一数据对象。 CKA_OBJECT_ID属性提供一种与应用无关的、可扩展的方法,来表明数据对象值的类型。 Cryptoki并不确保数据对象标识符一定匹配数据值。 下面的程序是一个样本模板,它包含用于创建某一数据对象的属性: CK_OBJECT_CLASS class = CKO_DATA; CK_UTF8CHAR label[] = “A data object”; CK_UTF8CHAR application[] = “An application”; CK_BYTE data[] = “Sample data”; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_APPLICATION, application, sizeof(application)-1}, {CKA_VALUE, data, sizeof(data)} }; 10.6 证书对象 下图描绘了证书对象的细节: 图7 证书对象属性的层次结构 证书对象(对象类型为CKO_CERTIFICATE) 含有公钥或属性证书。除了提供对证书对象的访问外,Cryptoki不向证书添加任何特殊含义。下表定义了公共的证书对象属性,此外它还支持表14和表18中列举的公共属性。 表20 公共的证书对象属性 属 性 数据类型 含 义 CKA_CERTIFICATE_TYPE1 CK_CERTIFICATE_TYPE 证书类型; CKA_TRUSTED CK_BBOOL 证书对于所建立的应用来说是可信的。 1在创建对象时,必须指定该属性。在创建对象之后,CKA_CERTIFICATE_TYPE属性不可以修改。 应用不能将CKA_TRUSTED属性设定为TRUE。它必须由一个令牌初始化应用来设定。可信证书不可以修改。 10.6.1 X.509公钥证书对象 X.509证书对象(证书类型为CKC_X_509) 含有X.509公钥证书。下表定义了X.509证书对象属性,此外它还支持表14、表18和表20中列举的公共属性。 表21 X.509证书对象属性 属 性 数据类型 含 义 CKA_SUBJECT1 Byte array 证书主体名称的DER-编码 CKA_ID Byte array 公钥/私钥对的密钥标识符; (缺省为空) CKA_ISSUER Byte array 证书发布者名称的DER-编码; (缺省为空) CKA_SERIAL_NUMBER Byte array 证书序列号的DER-编码; (缺省为空) CKA_VALUE1 Byte array 证书序列号的BER-编码 1在创建对象时,必须指定该属性。 在创建对象之后,只有CKA_ID、CKA_ISSUER和CKA_SERIAL_NUMBER属性可以被修改。 CKA_ID属性旨在用于区别同一主体所含有的多个公钥/私钥对(不管它们是否存储在同一令牌中)。 (由于密钥是根据主体名和标识符来区分的,所以不同主体的密钥有可能含有同一个CKA_ID值,从而不具有任何二重性。) 因此,从有利于互操作性的角度而言,一个证书的主体名和密钥标识符应该与相应的公钥/私钥的主体名和标识符相同(尽管不要求它们所有都必须存储在同一个令牌中)。 然而,Cryptoki并不强迫这种情况, 甚至对一个给定主体也不强调其密钥标识符的唯一性;尤其地,一个应用可以将密钥标识符留为空。 CKA_ISSUER和CKA_SERIAL_NUMBER属性是为了与PKCS #7以及保密增强邮件 (RFC1421)保持兼容而设定的。注意,在X.509 证书的V.3扩展版中,证书可以带有密钥标识符。在这样的一个证书扩展中,倾向于使CKA_ID的值与密钥标识符相同,尽管Cryptoki并不强迫这种情况。 下面的程序是用来创建一个证书对象的样本模板: CK_OBJECT_CLASS class = CKO_CERTIFICATE; CK_CERTIFICATE_TYPE certType = CKC_X_509; CK_UTF8CHAR label[] = “A certificate object”; CK_BYTE subject[] = {...}; CK_BYTE id[] = {123}; CK_BYTE certificate[] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_CERTIFICATE_TYPE, &certType, sizeof(certType)}; {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_SUBJECT, subject, sizeof(subject)}, {CKA_ID, id, sizeof(id)}, {CKA_VALUE, certificate, sizeof(certificate)} }; 10.6.2 X.509属性证书对象 X.509属性证书对象(证书类型为CKC_X_509_ATTR_CERT) 含有X.509属性证书。下表定义了X.509属性证书对象属性,此外它还支持表14、表18和表20中列举的公共属性。 表22 X.509属性证书对象的属性 属 性 数据类型 含 义 CKA_OWNER1 字节组 属性证书主体字段的DER-编码。这与CKC_X_509证书中所包含的CKA_SUBJECT 属性是不同的,因为ASN.1语法和编码是不同的。 CKA_AC_ISSUER 字节组 属性证书发布者字段的DER-编码。这与CKC_X_509证书中所包含的CKA_ISSUER属性是不同的,因为ASN.1语法和编码是不同的。 (缺省为空) CKA_SERIAL_NUMBER 字节组 证书序列号的DER-编码。 (缺省为空) CKA_ATTR_TYPES 字节组 对应于证书中所包含的属性类型的一串对象标识符值的BER-编码。在出现时,这个字段可让应用来搜索一个特殊的属性证书,而不用读取和从语法上解析该证书本身。 (缺省为空) CKA_VALUE1 字节组 证书的BER-编码。 1在创建对象时,必须指定该属性。 在创建对象之后,只有CKA_AC_ISSUER、CKA_SERIAL_NUMBER和CKA_ATTR_TYPES属性可以被修改。 下面的程序是用来创建一个X.509属性证书对象的样本模板: CK_OBJECT_CLASS class = CKO_CERTIFICATE; CK_CERTIFICATE_TYPE certType = CKC_X_509_ATTR_CERT; CK_UTF8CHAR label[] = "An attribute certificate object"; CK_BYTE owner[] = {...}; CK_BYTE certificate[] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_CERTIFICATE_TYPE, &certType, sizeof(certType)}; {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_OWNER, owner, sizeof(owner)}, {CKA_VALUE, certificate, sizeof(certificate)} }; 10.7 密钥对象 下图描绘了密钥对象的细节: 图8 密钥属性一览 密钥对象含有密码或验证密钥,它们可以是公钥、私钥或保密私钥。下面的公共脚注适用于所有描述密钥属性的表格。 表23 密钥属性表格的公共脚注 1 在使用C_CreateObject创建对象时,必须指定该属性。 2 在使用C_CreateObject创建对象时,不能指定该属性。 3 在使用C_GenerateKey或C_GenerateKeyPair生成对象时,必须指定该属性。 4 在使用C_GenerateKey或C_GenerateKeyPair生成对象时,不能指定该属性。 5 在使用C_UnwrapKey将对象拆包时,必须指定该属性。 6 在使用C_Unwrap将对象拆包时,不能指定该属性。 7 如果对象已将它的CKA_SENSITIVE属性设为TRUE或将它的CKA_EXTRACTABLE属性设为FALSE,那么该属性就不能再显现出来。 8 在使用C_SetAttributeValue调用创建对象之后,或在使用C_CopyObject调用复制对象的过程中,该属性可以被修改。但是,正如前面所提到的,一个特殊的令牌有可能不允许修改此属性,或者在C_CopyObject调用的过程中不允许修改此属性。 9 缺省值是随令牌改变而变化的,并且有可能要取决于其它属性的值。 10 一个应用不能将该属性设定为TRUE。它必须通过一个令牌初始化应用来设定。如果为TRUE,那么密钥就不可以被更改。 下表定义了可为公钥、私钥和保密私钥三种类别所共用的属性,此外它们还支持表14和表18中列举的公共属性。 表24 公共的密钥属性 属 性 数据类型 含 义 CKA_KEY_TYPE1,3,5 CK_KEY_TYPE 密钥类型 CKA_ID8 Byte array 密钥的密钥标识符 (缺省为空) CKA_START_DATE8 CK_DATE 密钥的启用日期(缺省为空) CKA_END_DATE8 CK_DATE 密钥的终止日期(缺省为空) CKA_DERIVE8 CK_BBOOL 如果密钥支持密钥派生,则为TRUE ;即如果可从这个密钥派生导出其它密钥。 (缺省为空) CKA_LOCAL2,4,6 CK_BBOOL 仅当密钥是下列情况之一时,为TRUE: 使用C_GenerateKey或 C_GenerateKeyPair调用在本地生成(即在此令牌上); 使用C_CopyObject调用作为一个密钥的副本创建,该密钥的CKA_LOCAL属性设定为TRUE。 CKA_ID字段旨在用来区别多个密钥。对于公钥和私钥来说,该字段支持处理同一个主体含有的多个密钥;一个公钥及其相对应私钥的密钥标识符应该是相同的。对于相应的证书(如果存在的话),密钥标识符也应该是相同的。但是,Cryptoki并不强迫上述这些情况。(有关详细解释,请参见第节) 对于保密私钥而言,CKA_ID属性的含义由应用决定。 注意,CKA_START_DATE和CKA_END_DATE属性仅用于参照引用,Cryptoki不向它们附加任何特殊含义。特别是,它对于日期密钥的使用不加限制;限制工作由应用来做。 当且仅当有可能从该密钥派生导出其它密钥时,CKA_DERIVE 属性的值为TRUE。 当且仅当该密钥的值是由C_GenerateKey或C_GenerateKeyPair调用在此令牌上原始生成的时,CKA_LOCAL属性的值为TRUE。 10.8 公钥对象 公钥对象(对象分类为:CKO_PUBLIC_KEY) 含有公钥。本版Cryptoki支持五种类型的公钥:RSA,DSA,ECDSA,Diffie-Hellman和KEA。下表定义了可为所有公钥共用的属性,此外还包括表14、表18和表24中列举的公共属性。 表25 公共的公钥属性 属 性 数据类型 含 义 CKA_SUBJECT8 Byte array 密钥主体名的DER-编码; (缺省为空)。 CKA_ENCRYPT8 CK_BBOOL 如果密钥支持加密,则为TRUE。 CKA_VERIFY8 CK_BBOOL 如果密钥支持验证,其中签名是数据的一个附录,则为TRUE 9。 CKA_VERIFY_RECOVER8 CK_BBOOL 如果密钥支持验证,其中数据是从签名恢复的,则为TRUE 9。 CKA_WRAP8 CK_BBOOL 如果密钥支持打包(wrapping),即可以用来打包其它密钥,则为TRUE 9。 CKA_TRUSTED10 CK_BBOOL 对于其所创建的应用来说,这个密钥是可信的。 从有利于互操作性的角度而言,一个公钥的主体名和密钥标识符应该与相应的证书和私钥的主体名和密钥标识符相同。但是,Cryptoki不强迫这种情况, 并且不要求证书和私钥也必须存储在这个令牌上。 为了了解在ISO/IEC 9594-8 (X.509) 中公钥的keyUsage(密钥使用)标志与在PKCS #11中公钥的属性之间的映像关系,请参见表26。 表26 X.509密钥使用标志与Cryptoki公钥属性的映像关系 在X.509公钥证书中 公钥的密钥使用标志 相对应的Cryptoki公钥属性 DataEncipherment CKA_ENCRYPT digitalSignature, keyCertSign, cRLSign CKA_VERIFY digitalSignature, keyCertSign, cRLSign CKA_VERIFY_RECOVER KeyAgreement CKA_DERIVE KeyEncipherment CKA_WRAP NonRepudiation CKA_VERIFY NonRepudiation CKA_VERIFY_RECOVER 10.8.1 RSA公钥对象 RSA公钥对象(对象分类为:CKO_PUBLIC_KEY,密钥类型为:CKK_RSA)含有RSA公钥。下表定义了RSA公钥对象属性,此外它还支持表14、表18、表24和表25中列举的公共属性: 表27 RSA公钥对象属性 属 性 数据类型 含 义 CKA_MODULUS1,4,6 Big integer 模数n CKA_MODULUS_BITS2,3,6 CK_ULONG 模数n 的位长度 CKA_PUBLIC_EXPONENT1,3,6 Big integer 公用指数e 根据令牌,对密钥各组成部分的长度是有限制的。关于RSA密钥的详细情况,请参见PKCS #1。 下面的程序是用来创建一个RSA公钥对象的样本模板: CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; CK_KEY_TYPE keyType = CKK_RSA; CK_UTF8CHAR label[] = “An RSA public key object”; CK_BYTE modulus[] = {...}; CK_BYTE exponent[] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_WRAP, &true, sizeof(true)}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_MODULUS, modulus, sizeof(modulus)}, {CKA_PUBLIC_EXPONENT, exponent, sizeof(exponent)} }; 10.8.2 DSA公钥对象 DSA公钥对象(对象分类为:CKO_PUBLIC_KEY,密钥类型为:CKK_DSA)含有DSA公钥。下表定义了DSA公钥对象属性,此外它还支持表14、表18、表24和表25中列举的公共属性: 表28 DSA公钥对象属性 属 性 数据类型 含 义 CKA_PRIME1,3,6 Big 整数 素数(Prime) p (512 ~1024位,每步长64位)。 CKA_SUBPRIME1,3,6 Big 整数 子素数(Subprime) q (160位)。 CKA_BASE1,3,6 Big 整数 基数g CKA_VALUE1,4,6 Big 整数 公共值y CKA_PRIME、CKA_SUBPRIME和CKA_BASE属性值都是“DSA参数”。关于DSA密钥的详细情况,请参见FIPS PUB 186。 下面的程序是用来创建一个DSA公钥对象的样本模板: CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; CK_KEY_TYPE keyType = CKK_DSA; CK_UTF8CHAR label[] = “A DSA public key object”; CK_BYTE prime[] = {...}; CK_BYTE subprime[] = {...}; CK_BYTE base[] = {...}; CK_BYTE value[] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_PRIME, prime, sizeof(prime)}, {CKA_SUBPRIME, subprime, sizeof(subprime)}, {CKA_BASE, base, sizeof(base)}, {CKA_VALUE, value, sizeof(value)} }; 10.8.3 ECDSA 公共密钥对象 ECDSA 公共密钥对象(对象类别CKO_PUBLIC_KEY, 密钥类型 CKK_ECDSA) 持有ECDSA 公共密钥。见章节 中关于ECDSA的更多信息。下表定义了ECDSA公共密钥对象属性,此外普通属性在表14、18、24和25中列出: 表 15, ECDSA 公共密钥对象属性 属 性 数据类型 含 义 CKA_ECDSA_PARAMS1,3,6 字节组 X9.62 ECParameters 值的DER编码 CKA_EC_POINT1,4,6 字节组 X9.62 ECPoint 值 P的DER编码 CKA_ECDSA_PARAMS 属性值作为“ECDSA 参数”知道的。 下面是创建公共密钥对象的范例模板: CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; CK_KEY_TYPE keyType = CKK_ECDSA; CK_UTF8CHAR label[] = “An ECDSA public key object”; CK_BYTE ecdsaParams[] = {...}; CK_BYTE ecPoint[] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_ECDSA_PARAMS, ecdsaParams, sizeof(ecdsaParams)}, {CKA_EC_POINT, ecPoint, sizeof(ecPoint)} }; 10.8.4 Diffie-Hellman 公共密钥对象 Diffie-Hellman 公共密钥对象(对象类别CKO_PUBLIC_KEY, 密钥类型CKK_DH) 持有Diffie-Hellman 公共密钥。下表定义了RSA公共密钥对象属性,此外,普通属性在表14、18、24和25中列出: 表 16, Diffie-Hellman 公共密钥对象属性 属 性 数据类型 含 义 CKA_PRIME1,3,6 Big 整数 质数 p CKA_BASE1,3,6 Big 整数 基础 g CKA_VALUE1,4,6 Big 整数 公共值 y CKA_PRIME 和CKA_BASE 属性值是集合的“Diffie-Hellman 参数”。依靠该令牌,密钥部件的长度可能受到限制。见PKCS#3中Diffie-Hellman 密钥的更多信息。 下面是创建Diffie-Hellman公共密钥对象的范例模板: CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; CK_KEY_TYPE keyType = CKK_DH; CK_UTF8CHAR label[] = “A Diffie-Hellman public key object”; CK_BYTE prime[] = {...}; CK_BYTE base[] = {...}; CK_BYTE value[] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_PRIME, prime, sizeof(prime)}, {CKA_BASE, base, sizeof(base)}, {CKA_VALUE, value, sizeof(value)} }; 10.8.5 KEA 公共密钥对象 KEA 公共密钥对象(对象类别CKO_PUBLIC_KEY, 密钥类型 CKK_KEA) 持有KEA 公共密钥。下表定义了KEA公共密钥对象属性,此外,普通属性在表14、18、24和25中列出: 表 17, KEA 公共密钥对象属性 属 性 数据类型 含 义 CKA_PRIME1,3,6 Big 整数 质数 p (512 到1024 位,以64位为一级) CKA_SUBPRIME1,3,6 Big 整数 子质数 q (160 位) CKA_BASE1,3,6 Big 整数 基础 g (512 到1024 位,以64位为一级) CKA_VALUE1,4,6 Big 整数 公共值 y CKA_PRIME, CKA_SUBPRIME 和CKA_BASE 属性值是集合的“KEA 参数”。 下面是创建KEA公共密钥对象的范例模板: CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; CK_KEY_TYPE keyType = CKK_KEA; CK_UTF8CHAR label[] = “A KEA public key object”; CK_BYTE prime[] = {...}; CK_BYTE subprime[] = {...}; CK_BYTE base[] = {...}; CK_BYTE value[] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_PRIME, prime, sizeof(prime)}, {CKA_SUBPRIME, subprime, sizeof(subprime)}, {CKA_BASE, base, sizeof(base)}, {CKA_VALUE, value, sizeof(value)} }; 10.9 私钥对象 私钥对象(对象类别CKO_PRIVATE_KEY) 持有私钥。这个版本的Cryptoki 承认5种类型的私钥:RSA, DSA, ECDSA, Diffie-Hellman, 和KEA.。下表定义了对 所有私钥都通用的属性,此外,普通属性在表14、18、24和25中列出: 表 18, 普通私钥属性 属 性 数据类型 含 义 CKA_SUBJECT8 字节组 证书主体名字的DER-编码(失败为空) CKA_SENSITIVE8 (see below) CK_BBOOL TRUE 如果密钥敏感9,则为真 CKA_SECONDARY_AUTH CK_BBOOL 如果密钥在允许使用之前需要二次鉴别,则为真。(失败为假)(反对,应用程序必须始终设置为假,或从模板中省去) CKA_AUTH_PIN_FLAGS2,4,6 CK_FLAGS 表征码指示二次鉴别PIN的现在状态。如果 CKA_SECONDARY_AUTH 为假。则该属性为0。(反对) CKA_DECRYPT8 CK_BBOOL 如果密钥支持解密,则为真。 CKA_SIGN8 CK_BBOOL 如果密钥支持签名(签名是数据的附录)则为真 CKA_SIGN_RECOVER8 CK_BBOOL 如果密钥支持签名(数据能从签名中恢复)则为真。 CKA_UNWRAP8 CK_BBOOL 如果密钥支持解密(即能用作解密其它密钥),则为真。 CKA_EXTRACTABLE8 (see below) CK_BBOOL 如果密钥可萃取,则为真 CKA_ALWAYS_SENSITIVE2,4,6 CK_BBOOL 如果密钥始终把 CKA_SENSITIVE属性设置为真,则为真。 CKA_NEVER_EXTRACTABLE2,4,6 CK_BBOOL 如果密钥没有把 CKA_EXTRACTABLE 属性设置为真,则为真。 创建一个对象后,CKA_SENSITIVE 属性可能会改变,但仅对真值。类似,在创建一个对象后,CKA_EXTRACTABLE 属性可能会改变,但仅对假值。试图使这些属性的其它值改变应当返回一个错误编码CKR_ATTRIBUTE_READ_ONLY. 如果CKA_SENSITIVE 属性为真,或如果CKA_EXTRACTABLE 属性为假,则私钥的一般属性不能在令牌外的明文中显示。为每个类型的私钥的属性规定在该章节的属性表中介绍。 如果CKA_EXTRACTABLE 为假,则密钥不能被加密。 为了彼此协作的利益,私钥的主体名字和密钥标识符将与那些对应的证书和公共密钥相同。但是,这并不由Cryptoki增强,并且不需要证书和公共密钥也存储在令牌中。 如果CKA_SECONDARY_AUTH 属性为真,则Cryptoki 执行程序将PIN(使用对Cryptoki用户是透明的机制集合的)联合新的私钥对象。新的PIN每次必须提供给令牌密钥用作密码操作。见章节中完全的用法模式。如果CKA_SECONDARY_AUTH 为真,则CKA_EXTRACTABLE 必须为假并且CKA_PRIVATE 必须为真。用设置为真的CKA_SECONDARY_AUTH 复制私钥的企图有些违反上面的条件,必定会失败。一个能决定是否把CKA_SECONDARY_AUTH 属性设置为真的应用程序由检验CKF_SECONDARY_AUTHENTICATION 标志是否设置在CK_TOKEN_INFO 标志中来决定。 CKA_AUTH_PIN_FLAGS 属性指示二次鉴别PIN的现有状态。这个值只有在CKA_SECONDARY_AUTH 属性为真时有效。这个属性的有效标志是在表10中为CK_TOKEN_INFO 标志字段定义的CKF_USER_PIN_COUNT_LOW, CKF_USER_PIN_FINAL_TRY, CKF_USER_PIN_LOCKED, 和CKF_USER_PIN_TO_BE_CHANGED。因为安全政策如果令牌不支持函数性或不显示信息,CKF_USER_PIN_COUNT_LOW 和CKF_USER_PIN_FINAL_TRY 可以始终设置为真。如果令牌不支持函数性,CKF_USER_PIN_TO_BE_CHANGED 标志可以始终设置为假 公共密钥ISO/IEC 9594-8 (X.509) keyUsage 标志和公共密钥的PKCS #11 属性之间的映射,使用下表: 表 19, 私钥的cryptoki属性的 X.509 密钥用法标志的映射 X.509 公共密钥证书中的公共密钥的密钥用法标志 对应的私钥cryptoki 属性 DataEncipherment CKA_DECRYPT digitalSignature, keyCertSign, cRLSign CKA_SIGN digitalSignature, keyCertSign, cRLSign CKA_SIGN_RECOVER KeyAgreement CKA_DERIVE KeyEncipherment CKA_UNWRAP NonRepudiation CKA_SIGN NonRepudiation CKA_SIGN_RECOVER 10.9.1 RSA 私钥对象 RSA 私钥对象 (对象类别CKO_PRIVATE_KEY, 密钥类型CKK_RSA) 持有RSA 私钥。下表定义了RSA私钥对象属性,此外,普通属性在表14、18、24和25中列出: 表 20, RSA 私钥对象属性 属 性 数据类型 含 义 CKA_MODULUS1,4,6 Big 整数 模 n CKA_PUBLIC_EXPONENT4,6 Big 整数 公共指数 e CKA_PRIVATE_EXPONENT1,4,6,7 Big 整数 私有指数 d CKA_PRIME_14,6,7 Big 整数 质数 p CKA_PRIME_24,6,7 Big 整数 指数 q CKA_EXPONENT_14,6,7 Big 整数 私有指数 d 模 p-1 CKA_EXPONENT_24,6,7 Big 整数 私有指数 d 模 q-1 CKA_COEFFICIENT4,6,7 Big 整数 CRT 系数 q-1 模 p 依靠令牌,密钥部件长度可能被限制。见PKCS #1 RSA密钥上的更多信息。 令牌改变它们为RSA私钥实际存储的。一些令牌存储上面所有的属性,这些属性能帮助执行快速的RSA计算。其它令牌只能存储CKA_MODULUS 和CKA_PRIVATE_EXPONENT 值。 因此,Cryptoki 能灵活的处理RSA私钥对象。当令牌生成一个RSA私钥,它存储表34中记录的任何一个字段。然后,如果一个应用程序要求该密钥的不同属性的值, Cryptoki 只为其值能保留的属性提供值(即如果Cryptoki 被索要它不能保留的一个属性的值,则请求失败)。注意,Cryptoki 执行程序可以或不可以能/或支持不能存储在令牌上的RSA私钥的不同属性。例如,如果一个特定的令牌只为CKA_PRIVATE_EXPONENT, CKA_PRIME_1, 和CKA_PRIME_2 属性存储值,则Cryptoki 当然能为上面所有的属性记录值(因为他们能从这三个值中有效地计算)。但是,Cryptoki 执行程序实际上可以或不可以做额外的计算。表34的唯一属性(为此Cryptoki 执行程序被要求返回值)是CKA_MODULUS 和CKA_PRIVATE_EXPONENT。 如果一个RSA 私钥对象在一个令牌上创建,并且表34更多的属性是对象创建调用提供,而不是由令牌支持,其它的属性可能不拒绝。如果试图在一个令牌上用该特定令牌的不足属性创建一个RSA私钥对象,则对象创建失败并返回CKR_TEMPLATE_INCOMPLETE。 注意,当生成一个RSA时,没有规定CKA_MODULUS_BITS 属性。这是因为RSA私钥只作为一个RSA密钥对的部分,并且该对的CKA_MODULUS_BITS 属性在RSA公共密钥的模板中规定 下面是创建RSA私钥对象的范例模板: CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; CK_KEY_TYPE keyType = CKK_RSA; CK_UTF8CHAR label[] = “An RSA private key object”; CK_BYTE subject[] = {...}; CK_BYTE id[] = {123}; CK_BYTE modulus[] = {...}; CK_BYTE publicExponent[] = {...}; CK_BYTE privateExponent[] = {...}; CK_BYTE prime1[] = {...}; CK_BYTE prime2[] = {...}; CK_BYTE exponent1[] = {...}; CK_BYTE exponent2[] = {...}; CK_BYTE coefficient[] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_SUBJECT, subject, sizeof(subject)}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_DECRYPT, &true, sizeof(true)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_MODULUS, modulus, sizeof(modulus)}, {CKA_PUBLIC_EXPONENT, publicExponent, sizeof(publicExponent)}, {CKA_PRIVATE_EXPONENT, privateExponent, sizeof(privateExponent)}, {CKA_PRIME_1, prime1, sizeof(prime1)}, {CKA_PRIME_2, prime2, sizeof(prime2)}, {CKA_EXPONENT_1, exponent1, sizeof(exponent1)}, {CKA_EXPONENT_2, exponent2, sizeof(exponent2)}, {CKA_COEFFICIENT, coefficient, sizeof(coefficient)} }; 10.9.2 ECDSA 公共密钥对象 ECDSA 公共密钥对象(对象类别CKO_PUBLIC_KEY, 密钥类型CKK_ECDSA) 持有ECDSA 公共密钥。见章节 关于ECDSA更多的信息。下表定义了DECSA公共密钥对象属性,此外,普通属性在表14,18,24和25中列出: 表35, ECDSA 公共密钥对象属性 属性 数据类型 含义 CKA_ECDSA_PARAMS1,3,6 字节组 一个 X9.62 DER编码中的 ECParameters 值 CKA_EC_POINT1,4,6 字节组 DER-encoding of X9.62 DER编码中的 ECPoint 值 P CKA_ECDSA_PARAMS 属性值作为“ECDSA 参数”被知道的。 下面是建立ECDSA公共密钥对象的范例模板: CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; CK_KEY_TYPE keyType = CKK_ECDSA; CK_UTF8CHAR label[] = “An ECDSA public key object”; CK_BYTE ecdsaParams[] = {...}; CK_BYTE ecPoint[] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_ECDSA_PARAMS, ecdsaParams, sizeof(ecdsaParams)}, {CKA_EC_POINT, ecPoint, sizeof(ecPoint)} }; 10.9.3 Diffie-Hellman 公共密钥对象 Diffie-Hellman 公共密钥对象(对象类别CKO_PUBLIC_KEY, 密钥类型 CKK_DH) 持有Diffie-Hellman 公共密钥。下表定义了RSA公共密钥对象属性,此外,普通属性在表14,18,24和25中定义。 表36, Diffie-Hellman 公共密钥对象属性 属性 数据类型 含义 CKA_PRIME1,3,6 Big 整数 指数 p CKA_BASE1,3,6 Big 整数 基础 g CKA_VALUE1,4,6 Big 整数 公共值 y CKA_PRIME 和CKA_BASE 属性值是集合的“Diffie-Hellman 参数”。依靠该令牌,密钥部件的长度可能会受限制。参见PKCS#3中Diffie-Hellman 密钥上的更多信息。 下表是建立Diffie-Hellman 公共密钥对象的范例模板: CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; CK_KEY_TYPE keyType = CKK_DH; CK_UTF8CHAR label[] = “A Diffie-Hellman public key object”; CK_BYTE prime[] = {...}; CK_BYTE base[] = {...}; CK_BYTE value[] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_PRIME, prime, sizeof(prime)}, {CKA_BASE, base, sizeof(base)}, {CKA_VALUE, value, sizeof(value)} }; 10.9.4 KEA 公共密钥对象 KEA 公共密钥对象(对象类别CKO_PUBLIC_KEY, 密钥类型CKK_KEA) 持有KEA公共密钥。下表定义了KEA公共密钥对象属性,此外,普通属性在表14,18,24和25中列出: 表37, KEA 公共密钥对象属性 属性 数据类型 含义 CKA_PRIME1,3,6 Big 整数 质数 p (512 到1024 位,以64位为一级) CKA_SUBPRIME1,3,6 Big 整数 子质数q (160 位) CKA_BASE1,3,6 Big 整数 基础 g (512 到1024 位,以64位为一级) CKA_VALUE1,4,6 Big 整数 公共值y CKA_PRIME, CKA_SUBPRIME 和CKA_BASE 属性值总的来说是“KEA 参数。” 下面是建立一个KEA公共密钥对象的范例模板: CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; CK_KEY_TYPE keyType = CKK_KEA; CK_UTF8CHAR label[] = “A KEA public key object”; CK_BYTE prime[] = {...}; CK_BYTE subprime[] = {...}; CK_BYTE base[] = {...}; CK_BYTE value[] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_PRIME, prime, sizeof(prime)}, {CKA_SUBPRIME, subprime, sizeof(subprime)}, {CKA_BASE, base, sizeof(base)}, {CKA_VALUE, value, sizeof(value)} }; 10.10 私钥对象 私钥对象(对象类别CKO_PRIVATE_KEY) 持有私钥。Cryptoki 的这个版本承认5种类型的私钥:RSA, DSA, ECDSA, Diffie-Hellman, 和 KEA。下表定义了所有私钥的普通属性,此外普通属性在表14,18和24中列出: 表38, 普通私钥属性 属性 数据类型 含义 CKA_SUBJECT8 字节组 证书主体名字的DER编码(默认为空) CKA_SENSITIVE8 (see below) CK_BBOOL 如果密钥是敏感9,则为真 CKA_SECONDARY_AUTH CK_BBOOL 如果在密钥允许使用前使用二次鉴别发生,则为真(默认为空)。(反对,应用程序必须始终设置为假,省略模板) CKA_AUTH_PIN_FLAGS2,4,6 CK_FLAGS 表征码指示现有二次鉴别PIN状态。如果CKA_SECONDARY_AUTH 错误,则这个属性是0。(反对) CKA_DECRYPT8 CK_BBOOL 如果密钥支持解密9,则为真 CKA_SIGN8 CK_BBOOL 如果密钥支持签名(在这里该签名是该数据9的附录),则为真。 CKA_SIGN_RECOVER8 CK_BBOOL 如果密钥支持签名(在这里该数据能从签名9中恢复),则为真。 CKA_UNWRAP8 CK_BBOOL 如果密钥支持解密,则为真(即能被用作解密其它密钥) CKA_EXTRACTABLE8 (see below) CK_BBOOL 如果密钥能萃取9,则为真。 CKA_ALWAYS_SENSITIVE2,4,6 CK_BBOOL 如果密钥始终把CKA_SENSITIVE 属性设置为真,则为真。 CKA_NEVER_EXTRACTABLE2,4,6 CK_BBOOL 如果密钥不能把CKA_EXTRACTABLE属性设置为真,则为真 当对象建立后,只有真值的CKA_SENSITIVE 属性可能被改变。同样,在一个对象建立后,只有假值的CKA_EXTRACTABLE 属性可能被改变。改变这些属性其它值的企图应当返回一个错误编码CKR_ATTRIBUTE_READ_ONLY。 如果CKA_SENSITIVE 属性为真,或者如果CKA_EXTRACTABLE 属性为假,这个私钥的某些属性不能在令牌外的明文中显示出来。这里的属性在介绍该类型密钥的章节的属性表中规定了每一种类型的私钥。 如果CKA_EXTRACTABLE 属性为假,则密钥不能被加密。 在相互协调的利益中,私钥的主体名字和密钥标识符试图与证书和公共密钥的相应部分相同。但是,这并没有被Cryptoki加强,并且也不需要证书和公共密钥存储在令牌中。 如果CKA_SECONDARY_AUTH 属性为真,则Cryptoki 执行程序将联合新的带有用可以透过Cryptoki客户的机制汇集起来的PIN私钥对象。新的PIN必须在每一次密钥用作密码操作时出现在令牌前。参见章节6.7中完整的用法模式。如果CKA_SECONDARY_AUTH 为真,则CKA_EXTRACTABLE 肯定为假,CKA_PRIVATE 肯定为真。在某种意义上试图用设置为真的CKA_SECONDARY_AUTH 复制私钥将违反上述条件而失败。一个应用程序是否能决定设置为真的CKA_SECONDARY_AUTH 属性由检验支持,要看CKF_SECONDARY_AUTHENTICATION标志是否设置在CK_TOKEN_INFO标志中。 CKA_AUTH_PIN_FLAGS 属性指示二次鉴别PIN的现在状态。该值在CKA_SECONDARY_AUTH 属性为真时才有效。这个属性有效的标志是定义在表10中的CK_TOKEN_INFO 标志字段的CKF_USER_PIN_COUNT_LOW, CKF_USER_PIN_FINAL_TRY, CKF_USER_PIN_LOCKED, 和CKF_USER_PIN_TO_BE_CHANGED 。如果由于安全政策,令牌不支持函数性或不显示信息,则CKF_USER_PIN_COUNT_LOW 和CKF_USER_PIN_FINAL_TRY 始终被设置成假。如果令牌不支持函数性,CKF_USER_PIN_TO_BE_CHANGED 标志始终被设置成假。 公共密钥的ISO/IEC 9594-8 (X.509) keyUsage 的标志和公共密钥PKCS #11 属性之间的属性使用下表: 表39, X.509 密钥用法标志到私钥的cryptoki 属性的映射 X.509 公共密钥证书中的公共密钥的密钥用法标志 反应私钥的cryptoki DataEncipherment CKA_DECRYPT digitalSignature, keyCertSign, cRLSign CKA_SIGN digitalSignature, keyCertSign, cRLSign CKA_SIGN_RECOVER KeyAgreement CKA_DERIVE KeyEncipherment CKA_UNWRAP NonRepudiation CKA_SIGN NonRepudiation CKA_SIGN_RECOVER 10.10.1 RSA 私钥对象 RSA 私钥对象(对象类别CKO_PRIVATE_KEY, 密钥类型CKK_RSA) 持有RSA私钥。下表定义了RSA私钥对象属性,其它的普通属性在表14,18,24,32中列出: 表40, RSA 私钥对象属性 属性 数据类型 含义 CKA_MODULUS1,4,6 Big 整数 模n CKA_PUBLIC_EXPONENT4,6 Big 整数 公共指数 e CKA_PRIVATE_EXPONENT1,4,6,7 Big 整数 私有指数 d CKA_PRIME_14,6,7 Big 整数 质数 p CKA_PRIME_24,6,7 Big 整数 质数 q CKA_EXPONENT_14,6,7 Big 整数 私有指数 d 模 p-1 CKA_EXPONENT_24,6,7 Big 整数 私有指数 d 模 q-1 CKA_COEFFICIENT4,6,7 Big 整数 CRT 系数 q-1 mod p 依靠这些令牌,就可以限制密钥部件的长度。参见PKCS #1 中有关RSA的更多信息。 令牌改变它们实际存储的RSA私钥。一些令牌存储上面的所有属性,这些属性有助于加速执行RSA计算。其它令牌可能只存储CKA_MODULUS 和CKA_PRIVATE_EXPONENT 值。 因为这样,Cryptoki 能灵活的处理RSA私钥对象。当一个令牌生成一个RSA私钥时,它存储表34中记录的任何一个字段。然后,如果一个应用程序索要该密钥的不同属性的值,Cryptoki 只为它能包含属性值的属性提供值(如果Cryptoki 被索要属性值它不能包含,则索要失败)。注意,一个Cryptoki 执行程序能或不能和/或愿意或不愿意提供不在令牌上存储的RSA私钥的不同属性。例如,如果一个特定的令牌只存储CKA_PRIVATE_EXPONENT, CKA_PRIME_1, 和 CKA_PRIME_2属性的值,那么Cryptoki 当然能记录上面所有的属性的值(因为它们能调用从这三个值中有效计算的部分)。但是,一个Cryptoki 执行程序实际上可以或不可以进行额外的计算。表34中Cryptoki 执行程序所需的能返回值的唯一属性是CKA_MODULUS 和CKA_PRIVATE_EXPONENT。 如果一个RSA私钥对象建立在一个令牌上,并且来自表34的更多属性提供给对象建立调用而不是由令牌支持,则额外的属性可能被拒绝。如果为该特定令牌试图在一个带有不适当属性的令牌上建立一个RSA私钥对象,则对象建立调用失败并返回CKR_TEMPLATE_INCOMPLETE。 注意,当生成一个RSA私钥时,则没有规定的CKA_MODULUS_BITS 属性。这是因为RSA私钥作为RSA密钥对的一部分生成,并且该密钥对的CKA_MODULUS_BITS 属性为RSA公共密钥在模板中规定。 下面就是建立DSA私钥对象的范例模板: CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; CK_KEY_TYPE keyType = CKK_RSA; CK_UTF8CHAR label[] = “An RSA private key object”; CK_BYTE subject[] = {...}; CK_BYTE id[] = {123}; CK_BYTE modulus[] = {...}; CK_BYTE publicExponent[] = {...}; CK_BYTE privateExponent[] = {...}; CK_BYTE prime1[] = {...}; CK_BYTE prime2[] = {...}; CK_BYTE exponent1[] = {...}; CK_BYTE exponent2[] = {...}; CK_BYTE coefficient[] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_SUBJECT, subject, sizeof(subject)}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_DECRYPT, &true, sizeof(true)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_MODULUS, modulus, sizeof(modulus)}, {CKA_PUBLIC_EXPONENT, publicExponent, sizeof(publicExponent)}, {CKA_PRIVATE_EXPONENT, privateExponent, sizeof(privateExponent)}, {CKA_PRIME_1, prime1, sizeof(prime1)}, {CKA_PRIME_2, prime2, sizeof(prime2)}, {CKA_EXPONENT_1, exponent1, sizeof(exponent1)}, {CKA_EXPONENT_2, exponent2, sizeof(exponent2)}, {CKA_COEFFICIENT, coefficient, sizeof(coefficient)} }; 10.10.2 DSA 私钥对象 DSA 私钥对象(对象类别CKO_PRIVATE_KEY, 密钥类型CKK_DSA) 持有DSA私钥。下表定义了DSA私钥对象属性,其它的普通属性在表14,18,24,32中列出: 表41, DSA 私钥对象属性 属性 数据类型 含义 CKA_PRIME1,4,6 Big 整数 质数 p (512 到 1024 位,以64位为一级) CKA_SUBPRIME1,4,6 Big 整数 子质数 q (160 位) CKA_BASE1,4,6 Big 整数 基础 g CKA_VALUE1,4,6,7 Big 整数 私有值 x CKA_PRIME, CKA_SUBPRIME 和CKA_BASE 属性值是集合的“DSA参数”。参见FIPS PUB186中DSA密钥上更多的信息。 注意,当生成一个DSA私钥,DSA参数不在该密钥的模板中规定。这是因为DSA私钥作为DSA密钥对的一部分生成,并且该密钥对的DSA参数为DSA公共密钥在模板中规定。 下面就是建立DSA私钥对象的范例模板: CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; CK_KEY_TYPE keyType = CKK_DSA; CK_UTF8CHAR label[] = “A DSA private key object”; CK_BYTE subject[] = {...}; CK_BYTE id[] = {123}; CK_BYTE prime[] = {...}; CK_BYTE subprime[] = {...}; CK_BYTE base[] = {...}; CK_BYTE value[] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_SUBJECT, subject, sizeof(subject)}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_PRIME, prime, sizeof(prime)}, {CKA_SUBPRIME, subprime, sizeof(subprime)}, {CKA_BASE, base, sizeof(base)}, {CKA_VALUE, value, sizeof(value)} }; 10.10.3 ECDSA 私钥对象 ECDSA 私钥对象(对象类别CKO_PRIVATE_KEY, 密钥类型CKK_ECDSA) 持有ECDSA 私钥。参见章节 关于ECDSA更多的信息。下表定义ECDSA私钥对象属性,此外,其它的普通属性在表14,18,24,32中列出: 表42, ECDSA 私钥对象属性 属性 数据类型 含义 CKA_ECDSA_PARAMS1,4,6 字节组 X9.62DER编码 ECParameters 值 CKA_VALUE1,4,6,7 Big 整数 X9.62 私有值 d CKA_ECDSA_PARAMS 属性值作为“ECDESA参数”被知道的。 注意,当生成一个ECDSA 私钥,ECDSA参数在密钥模板中未被规定。这是因为ECDSA私钥作为ECDSA密钥对的一部分生成,并且该密钥对的ECDSA参数为ECDSA公共密钥在模板中规定。 下面就是建立ECDSA私钥对象的范例模板: CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; CK_KEY_TYPE keyType = CKK_ECDSA; CK_UTF8CHAR label[] = “An ECDSA private key object”; CK_BYTE subject[] = {...}; CK_BYTE id[] = {123}; CK_BYTE ecdsaParams[] = {...}; CK_BYTE value[] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_SUBJECT, subject, sizeof(subject)}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_DERIVE, &true, sizeof(true)}, {CKA_ECDSA_PARAMS, ecdsaParams, sizeof(ecdsaParams)}, {CKA_VALUE, value, sizeof(value)} }; 10.10.4 Diffie-Hellman 私钥对象 Diffie-Hellman 私钥对象(对象类别CKO_PRIVATE_KEY, 密钥类型CKK_DH) 持有Diffie-Hellman 私钥。下表定义了Diffie-Hellman 私钥对象属性,此外,其它的普通属性在表14,18,24,32中列出: 表43, Diffie-Hellman 私钥对象属性 属性 数据类型 含义 CKA_PRIME1,4,6 Big 整数 质数 p CKA_BASE1,4,6 Big 整数 基础 g CKA_VALUE1,4,6,7 Big 整数 私有值 x CKA_VALUE_BITS2,6 CK_ULONG 私有值x的位中的长度 CKA_PRIME 和CKA_BASE 属性值是集合的“Diffie-Hellman 参数”。依据这个令牌,可能限制对该密钥部件长度。参见PKCS#3中关于 Diffie-Hellman密钥的更多信息。 注意,当生成一个Diffie-Hellman 私钥时,Diffie-Hellman 参数在密钥模板中未被规定。这是因为Diffie-Hellman私钥作为Diffie-Hellman密钥对的一部分生成,并且该密钥对的Diffie-Hellman参数为Diffie-Hellman公共密钥在模板中规定。 下面就是建立Diffie-Hellman私钥对象的范例模板: CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; CK_KEY_TYPE keyType = CKK_DH; CK_UTF8CHAR label[] = “A Diffie-Hellman private key object”; CK_BYTE subject[] = {...}; CK_BYTE id[] = {123}; CK_BYTE prime[] = {...}; CK_BYTE base[] = {...}; CK_BYTE value[] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_SUBJECT, subject, sizeof(subject)}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_DERIVE, &true, sizeof(true)}, {CKA_PRIME, prime, sizeof(prime)}, {CKA_BASE, base, sizeof(base)}, {CKA_VALUE, value, sizeof(value)} }; 10.10.5 KEA 私钥对象 KEA 私钥对象(对象类型CKO_PRIVATE_KEY, 密钥类型CKK_KEA) 持有KEA 私钥。下表定义了KEA对象属性,下表定义了KEA私钥对象属性,此外,其它的普通属性在表14,18,24,32中列出: 表44, KEA 私钥对象属性 属性 数据类型 含义 CKA_PRIME1,4,6 Big 整数 质数 p (512 到1024位,以64位为一级) CKA_SUBPRIME1,4,6 Big 整数 子质数q (160 位) CKA_BASE1,4,6 Big 整数 基础g (512 到1024 位,以64位为一级) CKA_VALUE1,4,6,7 Big 整数 私有值x CKA_PRIME, CKA_SUBPRIME 和CKA_BASE 属性值是集合的“KEA参数”。 注意,当生成一个KEA私钥时,KEA参数在密钥模板中未被规定。这是因为KEA私钥作为KEA密钥对的一部分生成,并且该密钥对的KEA参数为KEA公共密钥在模板中规定。 下面就是建立KEA私钥对象的范例模板: CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; CK_KEY_TYPE keyType = CKK_KEA; CK_UTF8CHAR label[] = “A KEA private key object”; CK_BYTE subject[] = {...}; CK_BYTE id[] = {123}; CK_BYTE prime[] = {...}; CK_BYTE subprime[] = {...}; CK_BYTE base[] = {...}; CK_BYTE value[] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_SUBJECT, subject, sizeof(subject)}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_DERIVE, &true, sizeof(true)}, {CKA_PRIME, prime, sizeof(prime)}, {CKA_SUBPRIME, subprime, sizeof(subprime)}, {CKA_BASE, base, sizeof(base)}, {CKA_VALUE, value, sizeof(value)} }; 10.11 保密密钥对象 保密密钥对象(对象类别CKO_SECRET_KEY)持有保密密钥。这个版本的Cryptoki承认下列类型的保密密钥:类属RC2, RC4, RC5, DES, DES2, DES3, CAST, CAST3, CAST128 (如我们知道的 CAST5), IDEA, CDMF, SKIPJACK, BATON, JUNIPER和AES。下表定义了所有保密密钥的普通属性,此外,普通属性在表14,18和24中列出: 表45, 普通保密密钥属性 属性 数据类型 含义 CKA_SENSITIVE8 (see below) CK_BBOOL 如果对象敏感,则为真 (省略 FALSE) CKA_ENCRYPT8 CK_BBOOL 如果支持加密9,则为真 CKA_DECRYPT8 CK_BBOOL 如果密钥支持解密9,则为真 CKA_SIGN8 CK_BBOOL 如果密钥支持签名(即鉴别编码,在这里签名是数据9的附录),则为真 CKA_VERIFY8 CK_BBOOL 如果密钥支持验证(即鉴别编码,在这里签名似乎数据9的附录),则为真 CKA_WRAP8 CK_BBOOL 如果密钥支持加密(即能用作加密其它密钥)9,则为真 CKA_UNWRAP8 CK_BBOOL 如果密钥支持解密(即能用作解密其它密钥)9 CKA_EXTRACTABLE8 (see below) CK_BBOOL 如果密钥是可萃取的9,则为真TRUE CKA_ALWAYS_SENSITIVE2,4,6 CK_BBOOL 如果密钥始终把CKA_SENSITIVE 属性设置为真,则为真 CKA_NEVER_EXTRACTABLE2,4,6 CK_BBOOL 如果密钥没有把CKA_EXTRACTABLE 属性设置为真,则为真 建立了一个对象后,CKA_SENSITIVE 属性可能被改变,但只能设置为真值。同样,建立了一个对象后, CKA_EXTRACTABLE 可能被改变,但只能设置为假值。试图对这些属性的值做其它改变将返回错误编码CKR_ATTRIBUTE_READ_ONLY。 如果CKA_SENSITIVE 属性是真,或如果CKA_EXTRACTABLE 属性是假,那么该保密密钥的某些属性不能在令牌外的明文中显示。这里的属性规定介绍了密钥类型的章节中的属性表中的每种类型的保密密钥。 如果CKA_EXTRACTABLE 属性是假,则该密钥不能被加密。 10.11.1 类属保密密钥对象 类属保密密钥对象(对象类别CKO_SECRET_KEY, 密钥类型CKK_GENERIC_SECRET) 持有类属保密密钥。这些密钥不支持加密、解密、签名或验证;但是,其它的密钥能从它们中派生。下表定义该类属保密密钥对象属性,此外,普通属性在表14,18,24,39中列出: 表46, 类属保密密钥对象属性 属性 数据类型 含义 CKA_VALUE1,4,6,7 字节组 密钥值(任意长度) CKA_VALUE_LEN2,3,6 CK_ULONG 密钥值的字节中的长度 下面就是建立类属保密密钥对象的范例模板: CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_GENERIC_SECRET; CK_UTF8CHAR label[] = “A generic secret key object”; CK_BYTE value[] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_DERIVE, &true, sizeof(true)}, {CKA_VALUE, value, sizeof(value)} }; 10.11.2 RC2 保密密钥对象 RC2 保密密钥对象(对象类别CKO_SECRET_KEY, 密钥类型CKK_RC2) 持有RC2 密钥。下表定义了RC2保密密钥对象属性,此外,普通属性在表14,18,24,39中列出: 表47, RC2 保密密钥对象属性 属性 数据类型 含义 CKA_VALUE1,4,6,7 字节组 密钥值(1 到128 字节) CKA_VALUE_LEN2,3,6 CK_ULONG 密钥值的字节中的长度 下面是建立RC2保密密钥对象的范例模板: CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_RC2; CK_UTF8CHAR label[] = “An RC2 secret key object”; CK_BYTE value[] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_VALUE, value, sizeof(value)} }; 10.11.3 RC4 保密密钥对象 RC4 保密密钥对象(对象类别CKO_SECRET_KEY, 密钥类型CKK_RC4) 持有RC4密钥。下表定义了RC4保密密钥对象属性,此外,普通属性在表14,18,24,39中列出: 表48, RC4 保密密钥对象 属性 数据类型 含义 CKA_VALUE1,4,6,7 字节组 密钥值(1 到256 字节) CKA_VALUE_LEN2,3,6 CK_ULONG 密钥值的字节中的长度 下面是建立RC4保密密钥对象的范例模板: CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_RC4; CK_UTF8CHAR label[] = “An RC4 secret key object”; CK_BYTE value[] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_VALUE, value, sizeof(value)} }; 10.11.4 RC5 保密密钥对象 RC5 保密密钥对象(对象类别CKO_SECRET_KEY, 密钥类型CKK_RC5) 持有RC5密钥。下表定义了RC5保密密钥对象属性,此外,普通属性在表14,18,24,39中列出: 表49, RC5保密密钥对象 属性 数据类型 含义 CKA_VALUE1,4,6,7 字节组 密钥值(0 到255 字节) CKA_VALUE_LEN2,3,6 CK_ULONG 密钥值的字节中的长度 下面建立RC5保密密钥对象的范例模板: CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_RC5; CK_UTF8CHAR label[] = “An RC5 secret key object”; CK_BYTE value[] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_VALUE, value, sizeof(value)} }; 10.11.5 AES 保密密钥对象 AES保密密钥对象(对象类别CKO_SECRET_KEY, 密钥类型CKK_AES) 持有AES密钥。下表定义了AES保密密钥对象属性,此外,普通属性在表14,18,24,39中列出: 表50, AES 保密密钥对象属性 属性 数据类型 含义 CKA_VALUE1,4,6,7 字节组 密钥值(16 到32 字节) CKA_VALUE_LEN2,3,6 CK_ULONG 密钥值的字节中的长度 下面是建立RC2保密密钥对象的范例模板: CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_AES; CK_UTF8CHAR label[] = “An AES secret key object”; CK_BYTE value[] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_VALUE, value, sizeof(value)} }; 10.11.6 DES 保密密钥对象 DES保密密钥对象(对象类别CKO_SECRET_KEY, 密钥类型CKK_DES) 持有DES密钥。下表定义了DES保密密钥对象属性,此外,普通属性在表14,18,24,39中列出: 表51, DES 保密密钥对象 属性 数据类型 含义 CKA_VALUE1,4,6,7 字节组 密钥值(始终为8 字节长) DES 密钥必须如同在FIPS PUB 46-2中介绍的那样,始终把它们的奇偶校验位适当地设置。试图用错误的奇偶校验位建立或解密DES密钥将返回一个错误。 下面是建立DES保密密钥对象的范例模板: CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_DES; CK_UTF8CHAR label[] = “A DES secret key object”; CK_BYTE value[8] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_VALUE, value, sizeof(value)} }; 10.11.7 DES2 保密密钥对象 DES2保密密钥对象(对象类别CKO_SECRET_KEY, 密钥类型CKK_DES2) 持有DES2密钥。下表定义了DES2保密密钥对象属性,此外,普通属性在表14,18,24,39中列出: 表52, DES2 保密密钥对象属性 属性 数据类型 含义 CKA_VALUE1,4,6,7 字节组 密钥值(始终为16 字节长度) DES2 密钥必须如同在FIPS PUB 46-2中介绍的那样,始终把它们的奇偶校验位适当地设置(即每个包含DES2密钥的DES密钥必须适当设置它的奇偶校验位)。试图用错误的奇偶校验位建立或解密DES密钥将返回一个错误。 下面是建立DES2保密密钥对象的范例模板: CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_DES2; CK_UTF8CHAR label[] = “A DES2 secret key object”; CK_BYTE value[16] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_VALUE, value, sizeof(value)} }; 10.11.8 DES3 保密密钥对象 DES3保密密钥对象(对象类别CKO_SECRET_KEY, 密钥类型CKK_DES3) 持有DES3密钥。下表定义了DES3保密密钥对象属性,此外,普通属性在表14,18,24,39中列出: 表53, DES3 保密密钥对象属性 属性 数据类型 含义 CKA_VALUE1,4,6,7 字节组 密钥值(始终为24字节长度 ) DES3 密钥必须如同在FIPS PUB 46-2中介绍的那样,始终把它们的奇偶校验位适当地设置(即每个包含DES3密钥的DES密钥必须适当设置它的奇偶校验位)。试图用错误的奇偶校验位建立或解密DES3密钥将返回一个错误。 下面是建立三倍长度DES保密密钥对象的范例模板: CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_DES3; CK_UTF8CHAR label[] = “A DES3 secret key object”; CK_BYTE value[24] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_VALUE, value, sizeof(value)} }; 10.11.9 CAST 保密密钥对象 CAST保密密钥对象(对象类别CKO_SECRET_KEY, 密钥类型CKK_CAST) 持有CAST密钥。下表定义了CAST保密密钥对象属性,此外,普通属性在表14,18,24,39中列出: 表54, CAST 保密密钥对象属性 属性 数据类型 含义 CKA_VALUE1,4,6,7 字节组 密钥值 (1到8长度) CKA_VALUE_LEN2,3,6 CK_ULONG 密钥值的字节中的长度 下面是建立CAST保密密钥对象的范例模板: CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_CAST; CK_UTF8CHAR label[] = “A CAST secret key object”; CK_BYTE value[] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_VALUE, value, sizeof(value)} }; 10.11.10 CAST3 保密密钥对象 CAST3保密密钥对象(对象类别CKO_SECRET_KEY, 密钥类型CKK_CAST3) 持有CAST3密钥。下表定义了CAST3保密密钥对象属性,此外,普通属性在表14,18,24,39中列出: 表55, CAST3 保密密钥对象属性 属性 数据类型 含义 CKA_VALUE1,4,6,7 字节组 密钥值(1 到8 字节) CKA_VALUE_LEN2,3,6 CK_ULONG 密钥值的字节中的长度 下面是建立CAST3保密密钥对象的范例模板: CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_CAST3; CK_UTF8CHAR label[] = “A CAST3 secret key object”; CK_BYTE value[] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_VALUE, value, sizeof(value)} }; 10.11.11 CAST128 (CAST5) 保密密钥对象 CAST128(正如我们所知的CAST5)保密密钥对象(对象类别CKO_SECRET_KEY, 密钥类型CKK_CAST128或CKK_CAST5) 持有CAST128密钥。下表定义了CAST128保密密钥对象属性,此外,普通属性在表14,18,24,39中列出: 表56, CAST128 (CAST5) 保密密钥对象属性 属性 数据类型 含义 CKA_VALUE1,4,6,7 字节组 密钥值(1 到16 字节) CKA_VALUE_LEN2,3,6 CK_ULONG 密钥值的字节中的长度 下面是建立CAST128(CAST5)保密密钥对象的范例模板: CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_CAST128; CK_UTF8CHAR label[] = “A CAST128 secret key object”; CK_BYTE value[] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_VALUE, value, sizeof(value)} }; 10.11.12 IDEA 保密密钥对象 IDEA保密密钥对象(对象类别CKO_SECRET_KEY, 密钥类型CKK_IDEA) 持有IDEA密钥。下表定义了IDEA保密密钥对象属性,此外,普通属性在表14,18,24,39中列出: 表57, IDEA 保密密钥对象 属性 数据类型 含义 CKA_VALUE1,4,6,7 字节组 密钥值(始终为16字节长) 下面是建立IDEA保密密钥对象的范例模板: CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_IDEA; CK_UTF8CHAR label[] = “An IDEA secret key object”; CK_BYTE value[16] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_VALUE, value, sizeof(value)} }; 10.11.13 CDMF 保密密钥对象 CDMF保密密钥对象(对象类别CKO_SECRET_KEY, 密钥类型CKK_CDMF) 持有CDMF密钥。下表定义了CDMF保密密钥对象属性,此外,普通属性在表14,18,24,39中列出: 表 58, CDMF 保密密钥对象 属性 数据类型 含义 CKA_VALUE1,4,6,7 字节组 密钥值(始终是8 字节长) CDMF密钥必须如同在FIPS PUB 46-2中的DES密钥介绍的那样,始终把它们的奇偶校验位适当地设置(即每个包含DES3密钥的DES密钥必须适当设置它的奇偶校验位)。试图用错误的奇偶校验位建立或解密CDMF密钥将返回一个错误。 下面是建立CDMF保密密钥对象的范例模板。 CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_CDMF; CK_UTF8CHAR label[] = “A CDMF secret key object”; CK_BYTE value[8] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_VALUE, value, sizeof(value)} }; 10.11.14 SKIPJACK 保密密钥对象 SKIPJACK保密密钥对象(对象类别CKO_SECRET_KEY, 密钥类型CKK_SKIPJACK) 持有单个长度MEK或TEK。下表定义了SKIPJACK保密密钥对象属性,此外,普通属性在表14,18,24,39中列出: 表59, SKIPJACK 保密密钥对象 属性 数据类型 含义 CKA_VALUE1,4,6,7 字节组 密钥值(始终为12 字节长) SKIPJACK 密钥有16个检验和(checksum)位,并且这些位必须被适当的设置。试图用错误的检验和位建立或解密一个SKIPJACK密钥将返回一个错误。 允许一个应用程序用一个规定的值建立一个SKIPJACK密钥的任意令牌并不明显地存在(或曾经存在)。然而,我们为这么做提供模板。 下面是建立一个SKIPJACK MEK保密密钥对象的范例模板: CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_SKIPJACK; CK_UTF8CHAR label[] = “A SKIPJACK MEK secret key object”; CK_BYTE value[12] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_VALUE, value, sizeof(value)} }; 下面是建立一个SKOPJACK TEK保密密钥对象的范例模板: CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_SKIPJACK; CK_UTF8CHAR label[] = “A SKIPJACK TEK secret key object”; CK_BYTE value[12] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_WRAP, &true, sizeof(true)}, {CKA_VALUE, value, sizeof(value)} }; 10.11.15 BATON 保密 密钥对象 BATON 保密密钥对象(对象类别CKO_SECRET_KEY, 密钥类型 CKK_BATON)持有单个长度BATON密钥。下表定义了BATON保密密钥对象属性,此外,普通属性在表14,18,24,39中列出: 表60, BATON 保密密钥对象 属性 数据类型 含义 CKA_VALUE1,4,6,7 字节组 密钥值(始终为40字节长度) BATON密钥有160个检验和(checksum)位,并且这些位必须被适当的设置。试图用错误的检验和位建立或解密一个BATON密钥将返回一个错误。 允许一个应用程序用一个规定的值建立一个BATON密钥的任意令牌并不明显地存在(或曾经存在)。然而,我们为这么做提供模板。 下面是建立一个BATON MEK保密密钥对象的范例模板: CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_BATON; CK_UTF8CHAR label[] = “A BATON MEK secret key object”; CK_BYTE value[40] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_VALUE, value, sizeof(value)} }; 下面是建立一个BATON TEK保密密钥对象的范例模板: CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_BATON; CK_UTF8CHAR label[] = “A BATON TEK secret key object”; CK_BYTE value[40] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_WRAP, &true, sizeof(true)}, {CKA_VALUE, value, sizeof(value)} }; 10.11.16 JUNIPER 保密密钥对象 JUNIPER 保密密钥对象(对象类别CKO_SECRET_KEY, 密钥类型 CKK_JUNIPER)持有单个长度JUNIPER密钥。下表定义了JUNIPER保密密钥对象属性,此外,普通属性在表14,18,24,39中列出: 表61, JUNIPER 保密密钥对 属性 数据类型 含义 CKA_VALUE1,4,6,7 字节组 密钥值(始终为40字节的长度) JUNIPER密钥有160个检验和(checksum)位,并且这些位必须被适当的设置。试图用错误的检验和位建立或解密一个JUNIPER密钥将返回一个错误。 允许一个应用程序用一个规定的值建立一个JUNIPER密钥的任意令牌并不明显地存在(或曾经存在)。然而,我们为这么做提供模板。 下面是建立一个JUNIPER MEK保密密钥对象的范例模板: CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_JUNIPER; CK_UTF8CHAR label[] = “A JUNIPER MEK secret key object”; CK_BYTE value[40] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_VALUE, value, sizeof(value)} }; 下面是建立一个JUNIPER TEK保密密钥对象的范例模板: CK_OBJECT_CLASS class = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_JUNIPER; CK_UTF8CHAR label[] = “A JUNIPER TEK secret key object”; CK_BYTE value[40] = {...}; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &class, sizeof(class)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_LABEL, label, sizeof(label)-1}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_WRAP, &true, sizeof(true)}, {CKA_VALUE, value, sizeof(value)} }; 11. 函数 Cryptoki's 的函数分为以下几类: 通用函数(4个) 槽与令牌管理函数(9个) 对话管理函数 (8个) 对象管理函数 (9个) 加密函数 (4个) 解密函数 (4个) 消息摘要函数( 4个) 签名和 MAC函数 (6个) 验证签名和 MAC的函数 (6个) 双重加密函数 (4个) 密钥管理函数 (5个) 随机数生成函数 (2个) 并行功能管理函数 (2 个) 除了Cryptoki v2.1API 中固有的68个函数外, Cryptoki可以采用应用程序提供的调回函数把特定事件通知给一个应用程序,同时还能采用应用程序提供的函数为安全访问多线程库进行mutex对象的管理。 执行Cryptoki函数的调用整体上而言是一种全有或全无的情况,换言之,函数调用要么完全达到目的,要么彻底失败。 如果 Cryptoki函数执行成功,将返回 CKR_OK的值。 如果Cryptoki 函数不能成功执行,将返回 CKR_OK以外的其他某些值,令牌处于优先于函数调用的同样状态。如果假设函数调用能修改主机上某些存储器地址的内容的话,这些存储器地址可能会被修改,除非函数调用失败。 在某些偶然(极其令人不愉快)的情况下,函数可能调用失败,返回 CKR_GENERAL_ERROR的值。 这种情况下,令牌和/或主机可能处于不相容的状态,函数可能已部分地达到其目的。 有一小部分Cryptoki函数的返回值并不和以上所述的一模一样,这些例外情况将在说明函数本身时单独指出。 Cryptoki库不必支持Cryptoki API的每个函数。然而,即使是不支持的函数也应当在库中有一个“存根”,它只返回 CKR_FUNCTION_NOT_SUPPORTED的值。库 CK_FUNCTION_LIST结构中的函数目录(如由C_GetFunctionList获得的)应当指向该存根函数(参见9.6节)。 11.1 函数返回值 Cryptoki接口拥有大量的函数和返回值。在错误:引用源未找到节中,我们枚举了 Cryptoki 函数各种可能的返回值,11章的其余部分则详细阐述了Cryptoki 函数的性能,包括他们各自将返回什么样的值。 鉴于Cryptoki 规程的复杂性,最好Cryptoki 应用程序在判读Cryptoki 函数返回值时能允许一些误差范围。我们已尽力在可行性允许的情况下完全地确定Cryptoki 函数的性能,但是无论如何还存在着差距。比如说,可能存在这样的情况,即某一个可能应用于特定Cryptoki函数的错误码事实上并没有被列在对可能是错误码的描述中。可以想象Cryptoki库的开发商可能无论如何都允许他/她的该函数的实现能返回该错误码。很显然,如果采用该库的一个Cryptoki应用在接收到该函数的错误码时以突然清除核心来终止的话显得有些不体面。所以应用更倾向于检查函数的返回值,看一下返回值表明的错误类型(即使应用并不能确切地知道错误种类),然后相应地采取措施。 11.1.1 通用 Cryptoki函数返回值 任何 Cryptoki函数都能返回以下任何一个值: CKR_GENERAL_ERROR: 表示发生了某些可怕的、无法挽回的错误。最坏的情况下,函数有可能会部分地获得成功,计算机和/或令牌处于不相容的状态。 CKR_HOST_MEMORY: Cryptoki 库正在运行的计算机没有足够的内存来执行请求的函数。 CKR_FUNCTION_FAILED: 无法执行所请求的函数,但错误返回中并没有原因的信息。如果失败的函数使用一个对话,则通过调用C_GetSessionInfo 能够获得的CK_SESSION_INFO结构将持有关于ulDeviceError字段中所发生事态的有用信息。 在任何情况下,尽管函数调用失败,但并不表示事态无可救药,正如返回CKR_GENERAL_ERROR时的那样。根据导致错误的根本原因,有可能重新执行同样的函数调用时获得成功。 CKR_OK: 该函数成功执行。技术上而言,CKR_OK 并不完全是一个“通用”的返回值,特别是传统函数 C_GetFunctionStatus和C_CancelFunction (参见节) 不能返回CKR_OK. 以上依次列出了这些错误的相关优先权,例如,如果CKR_GENERAL_ERROR 或者 CKR_HOST_MEMORY 可能是一个适当的错误返回,那么也应当返回 CKR_GENERAL_ERROR。 11.1.2 使用一个对话句柄的函数的Cryptoki函数返回值 把一个对话句柄作为其变元 (即,除C_Initialize, C_Finalize, C_GetInfo, C_GetFunctionList, C_GetSlotList, C_GetSlotInfo, C_GetTokenInfo, C_WaitForSlotEvent, C_GetMechanismList, C_GetMechanismInfo, C_InitToken, C_OpenSession, 和 C_CloseAllSessions外的任何Cryptoki函数) 的任何一个Cryptoki函数均可返回下列值: CKR_SESSION_HANDLE_INVALID: 当函数被调用时,指定的对话句柄无效。注意,如果在函数调用之前删除对话的令牌的话,指定的对话句柄无效,因为删除了一个令牌也就关闭了带有令牌的所有对话。 CKR_DEVICE_REMOVED: 在函数执行的过程中,从槽中删除该令牌。 CKR_SESSION_CLOSED: 函数执行过程中,关闭该对话。注意,正如节所述, 如果一个应用的多线程试图同时访问一个通用Cryptoki 对话,则不规定 Cryptoki的性能。因此,事实上不能保证函数调用一直能返回CKR_SESSION_CLOSED值——如果一线正在使用一个对话而另一线则关闭了该对话,这就是多线程同时访问一个通用对话的例子。 上文依次列出了这些错误的相关优先权,即,如果 CKR_SESSION_HANDLE_INVALID 或者CKR_DEVICE_REMOVED可能是一个适当的错误返回,那么应当返回 CKR_SESSION_HANDLE_INVALID 。 事实上,Cryptoki 库能够区分出一个函数调用前被删除的令牌和在函数执行过程中被删除的令牌通常并不重要(或可能)。 11.1.3 使用一个令牌的函数的 Cryptoki 函数返回值 任何一个使用特定令牌的Cryptoki函数(即除 C_Initialize, C_Finalize, C_GetInfo, C_GetFunctionList, C_GetSlotList, C_GetSlotInfo, or C_WaitForSlotEvent之外的任何一个Cryptoki函数) 都能够返回下列任何一个值: CKR_DEVICE_MEMORY: 令牌无足够的内存来执行请求的函数。 CKR_DEVICE_ERROR: 因令牌和/或槽而出现某个问题。不仅是以上提及的函数会返回该错误码。特别是C_GetSlotInfo可能会返回CKR_DEVICE_ERROR CKR_TOKEN_NOT_PRESENT: 该函数被调用时,令牌不在槽中。 CKR_DEVICE_REMOVED: 在函数执行过程中,该令牌被从槽中删除。 上文依次列出了这些错误的相关优先权,例如,如果CKR_DEVICE_MEMORY或者 CKR_DEVICE_ERROR 函数可能会是一个相称的错误返回,那么应当返回 CKR_DEVICE_MEMORY 。 实际上,Cryptoki库能够区别一个函数调用前正被删除的一个令牌与一个函数执行过程中正被删除的一个令牌之间的差别通常并不很重要(或可能)。 11.1.4 应用提供回叫的特殊返回值 这是一种特殊效用的返回值,在实际的Cryptoki API 中并不是任何函数都返回该值,而应用提供回叫函数可能会返回该值。 CKR_CANCEL: 当一个应用连续执行的函数决定给应用机会干些活时,它调用一个带CKN_SURRENDER回叫的应用支持函数(见Section )。如果回叫返回CKR_CANCEL 的值,那么函数异常终止并返回CKR_FUNCTION_CANCELED。 11.1.5 Mutex管理函数的特殊返回值 有两种特殊效用的返回值,实际上并不是每个Cryptoki函数都返回这些值。应用支持mutex管理函数可能会返回这些值,而不使用自己的线模型的应用开发人员可以忽略它们。reading model. CKR_MUTEX_BAD: mutex管理函数会返回该错误码,mutex函数被传递当作是变元的一个坏的mutex对象。不幸的是,这样一个函数可能不一定能识别出坏的mutex对象。因此不能保证这样一个函数将能成功地检测出坏的mutex对象并返回该值。 CKR_MUTEX_NOT_LOCKED: This error code can be returned by mutex-unlocking functions. It indicates that the mutex supplied to the mutex-unlocking function was not locked. 11.1.6 所有其他的 Cryptoki函数返回值 其他所有Cryptoki函数返回值如下所述。除如特定错误代码的描述中所指出的外,通常下列错误中没有特定的优先权,即如果多个错误代码适用于函数的执行,则功能会返回任何可适用的错误代码。 CKR_ARGUMENTS_BAD: 这是一个相当通用的错误码, 它说明提供给Cryptoki 函数的变元在某种程度上是不适当的。 CKR_ATTRIBUTE_READ_ONLY: 试图为可能未被设置或修改的一个属性设定一个值。详情参见节。 CKR_ATTRIBUTE_SENSITIVE:试图获得一个对象的属性值,该对象因其敏感性或不可抽取性而不能满意。 CKR_ATTRIBUTE_TYPE_INVALID: 模板中指定的一种无效属性。参见 节。 CKR_ATTRIBUTE_VALUE_INVALID: 为模板中的一个属性指定指定无效值。参见 节。 CKR_BUFFER_TOO_SMALL:该函数的输出太大,与提供的缓冲器不配。 CKR_CANT_LOCK: 该值只能由C_Initialize返回。这意味着应用因为线程安全而请求的这种类型的锁定在该库中得不到,因此该应用不能以指定的方式使用该库。 CKR_CRYPTOKI_ALREADY_INITIALIZED: 该值只能由 C_Initialize返回。这意味着Cryptoki库已经初始化(通过之前调用没有相匹配的C_Finalize 调用的C_Initialize) CKR_CRYPTOKI_NOT_INITIALIZED: 该值可以由除C_Initialize 和C_GetFunctionList 以外的任何函数返回。这表明由于Cryptoki 库尚未通过调用C_Initialize 而初始化因而函数不能执行。 CKR_DATA_INVALID: 密码操作的明文输入数据无效。目前,该错误仅适用于CKM_RSA_X_509机制。当提供的明文有与RSA模同样的字节数而且数值上至少与模同样大时,返回该值。该返回值的优先权比CKR_DATA_LEN_RANGE 的低。 CKR_DATA_LEN_RANGE: 密码操作明文输入数据有一个坏的长度。基于操作的机制,有可能是说明明文数据太短、太长,或不是某个特定字组尺寸的倍数。该返回值的优先权比CKR_DATA_INVALID 的要高。 CKR_ENCRYPTED_DATA_INVALID: 解密操作的加密输入已被确定为无效密文。该返回值的优先权比CKR_ENCRYPTED_DATA_LEN_RANGE 的低。 CKR_ENCRYPTED_DATA_LEN_RANGE: 解密操作的密文输入仅仅根据其长度就被被确认为是无效密文。视操作的机制,可能是密文太短、太长,或者不是某个特定字组尺寸的倍数。该返回值的优先权比CKR_ENCRYPTED_DATA_INVALID 的高。 CKR_FUNCTION_CANCELED: 该函数在执行中被取消。如果函数进行一次返回CKR_CANCEL的CKN_SURRENDER 应用回叫,那么密码函数就发生这种情况(参见CKR_CANCEL)。 CKR_FUNCTION_NOT_PARALLEL: 目前指定的对话中没有函数并行执行。这是一个传统的错误码,它只由传统函数C_GetFunctionStatus和 C_CancelFunctio返回。 CKR_FUNCTION_NOT_SUPPORTED:该Cryptoki库不支持请求函数。即使是Cryptoki API中的非支持函数也应当在库中有一个“存根”。该存根仅返回CKR_FUNCTION_NOT_SUPPORTED的值。 CKR_INFORMATION_SENSITIVE: 由于令牌认为请求的信息敏感或不愿意显示,因而不能获得请求的信息。 CKR_KEY_CHANGED: 该值仅由C_SetOperationState返回. 这表明指定的某个密钥并不是原来保存的对话中使用的同一密钥。 CKR_KEY_FUNCTION_NOT_PERMITTED: 尝试使用密钥达到密钥的属性没有设置成允许的加密目的。举例来说,要使用密钥进行加密,密钥就必须将其CKA_ENCRYPT 属性设置成TRUE。(密钥必须有其CKA_ENCRYPT属性说明该密钥不能是私钥)。返回值的优先权低于CKR_KEY_TYPE_INCONSISTENT 。 CKR_KEY_HANDLE_INVALID: 指定的密钥句柄无效。可能出现这样的情况,即不是密钥的一个对象的指定的句柄是有效句柄。 CKR_KEY_INDIGESTIBLE: 该错误码只能由C_DigestKey 返回。这表明指定的密钥的值由于某种原因而不能被摘要(可能该密钥不是一个保密密钥,也可能令牌不能摘要这种密钥)。 CKR_KEY_NEEDED: 该值只能由C_SetOperationState返回. 它表明由于需要给C_SetOperationState提供一个或多个原来保存的对话中使用的密钥,因而对话的状态不能恢复。 CKR_KEY_NOT_NEEDED: 给C_SetOperationState 提供一个附加的密钥。比如说,尝试恢复一个正在执行消息摘要操作的对话,提供一个加密密钥。 CKR_KEY_NOT_WRAPPABLE: 尽管指定的私有或保密密钥并没有将自己的CKA_UNEXTRACTABLE 属性设置成TRUE,但Cryptoki (或令牌)不能应请求打包密钥(可能令牌只能打包带有特定类型密钥的给定密钥,而指定的打包密钥却不是这些类型之一)。与CKR_KEY_UNEXTRACTABLE 做比较。 CKR_KEY_SIZE_RANGE:尽管请求密钥加密操作原则上可以执行,但该Cryptoki库(或令牌)实际上并不能完成,这是因为提供的密钥的尺寸超出了它能管理的密钥尺寸的范围。 CKR_KEY_TYPE_INCONSISTENT: 指定的密钥不是配合指定的机制使用的正确类型的密钥。返回值的优先权高于CKR_KEY_FUNCTION_NOT_PERMITTED. CKR_KEY_UNEXTRACTABLE: 由于其CKA_UNEXTRACTABLE属性被设置为TRUE,因而指定的私有或保密密钥不能被打包。与CKR_KEY_NOT_WRAPPABLE作比较。 CKR_MECHANISM_INVALID: 给密码操作指定一个无效的机制。如果指定的是一个未知的机制或者指定的机制不能在带有所选函数的所选令牌中使用,那么该错误码就是个合适的返回值。 CKR_MECHANISM_PARAM_INVALID: 给为密码操作指定的机制提供无效的参数。给定机制支持的参数值因令牌而异。 CKR_NEED_TO_CREATE_THREADS: 该值只能由C_Initialize 返回。以下两种情况下返回该值: 1. 应用以某种方式调用C_Initialize ,它告知Cryptoki 库调用的应用线程不能采用本地操作系统方法来产生新的线程。 2. 在以上的方式中,库不能产生新的线程就不能正常地执行其功能。 CKR_NO_EVENT: 该值只能由 C_GetSlotEvent返回。当以无阻塞模式调用C_GetSlotEvent 而且没有新的槽事件返回时就返回该值。 CKR_OBJECT_HANDLE_INVALID: 指定的对象句柄无效。这里我们要重申0决不是一个有效的对象句柄。 CKR_OPERATION_ACTIVE: 已经有一个现用的操作(或现用操作的组合)防止Cryptoki 激活指定的操作。举例而言,一个现用的搜寻对象的操作会防止Cryptoki 激活一个带C_EncryptInit 的加密操作。或者,现用的摘要操作和现用的加密操作会防止Cryptoki 激活签名操作。还有一种情况,在对话中不支持同时双重密码操作的令牌上(参见CK_TOKEN_INFO结构中对CKF_DUAL_CRYPTO_OPERATIONS标志的叙述), 现用的操作会防止Cryptoki 激活加密操作。 CKR_OPERATION_NOT_INITIALIZED: 指定的对话中没有适当类型的现用操作。比如说,一个应用如果不首先C_EncryptInit 来激活一个加密操作的话就不能在对话中调用C_Encrypt 。 CKR_PIN_EXPIRED: 指定的PIN已到期,请求的操作不能执行,除非调用 C_SetPIN 来改变PIN的值。令牌上普通用户的PIN是否到期因令牌而异。 CKR_PIN_INCORRECT: 指定的PIN不正确,即与令牌上储存的PIN不匹配。更通常的情况下,当对令牌的认证包含了PIN之外的一些东西,这时认证用户就失败。 CKR_PIN_INVALID: 指定的PIN中含有无效的字符。返回的编码只应用于试图设置PIN的函数。 CKR_PIN_LEN_RANGE: 指定的PIN太长或太短。返回的编码只应用于试图设置PIN的函数。 CKR_PIN_LOCKED: 指定的PIN被“锁定”,不能使用。也就是说,失败的认证尝试已经达到了某个特定的数,令牌不再允许进一步尝试认证。根据令牌的不同,指定的PIN可能一直被锁定,也有可能不。 CKR_RANDOM_NO_RNG: 该值能由 C_SeedRandom 和 C_GenerateRandom返回。 表明指定的令牌没有随机数字产生器。该返回值的优先权高于CKR_RANDOM_SEED_NOT_SUPPORTED. CKR_RANDOM_SEED_NOT_SUPPORTED: 该值只能由 C_SeedRandom返回. 说明令牌的随机数字产生器不接收应用的引晶。该返回值的优先权低于 CKR_RANDOM_NO_RNG. CKR_SAVED_STATE_INVALID: 该值只能由C_SetOperationState返回. 说明提供保存的密码操作状态无效,因此不能在指定的对话中恢复。 CKR_SESSION_COUNT: 该值只能由C_OpenSession返回。说明或者是因为令牌有太多的对话已打开,或者因为令牌有太多的读/写对话已打开,所以尝试打开对话失败。 CKR_SESSION_EXISTS: 该值只能由C_InitToken 返回。说明有令牌的对话已打开,因此令牌不能初始化。 CKR_SESSION_PARALLEL_NOT_SUPPORTED: 指定的令牌不支持并行对话。这是一个传统错误码——在Cryptoki 2.01及以上版本中,没有令牌支持并行对话。 CKR_SESSION_PARALLEL_NOT_SUPPORTED 只能由C_OpenSession返回,而且当以一种特殊方式(反对)调用 C_OpenSession时才返回该值。 CKR_SESSION_READ_ONLY: 指定的对话不能获得想要的执行动作,因为它是一个只读对话。该返回值的优先权低于CKR_TOKEN_WRITE_PROTECTED 。 CKR_SESSION_READ_ONLY_EXISTS:只读对话已经存在,因此不能注册SO。 CKR_SESSION_READ_WRITE_SO_EXISTS: 读/写SO对话已经存在,因此不能打开只读对话。 CKR_SIGNATURE_LEN_RANGE: 不能只根据其长度就将提供的签名看成是无效的。该返回值的优先权高于CKR_SIGNATURE_INVALID 。 CKR_SIGNATURE_INVALID: 提供的签名/MAC无效。该返回值的优先权低于CKR_SIGNATURE_LEN_RANGE 。 CKR_SLOT_ID_INVALID: 指定的槽ID无效。 CKR_STATE_UNSAVEABLE: 由于某种原因(可能只是令牌不能保存当前的状态),不能保存指定对话的密码操作状态。该返回值的优先权低于CKR_OPERATION_NOT_INITIALIZED. CKR_TEMPLATE_INCOMPLETE: 为创建一个对象而指定的模板不完整,缺少某些必要的属性。详情参见节。 CKR_TEMPLATE_INCONSISTENT: 为创建一个对象而指定的模板有相矛盾的属性。详情参见节。 CKR_TOKEN_NOT_RECOGNIZED: Cryptoki库和/或槽不能识别槽中的令牌。 CKR_TOKEN_WRITE_PROTECTED: 由于令牌有写保护,因而不能执行请求的动作。该返回值的优先权高于CKR_SESSION_READ_ONLY 。 CKR_UNWRAPPING_KEY_HANDLE_INVALID: 该值只能由C_UnwrapKey 返回。说明指定用于解包另一个密钥的密钥句柄无效。 CKR_UNWRAPPING_KEY_SIZE_RANGE: 该值只能由C_UnwrapKey返回。说明尽管理论上不能执行请求的解包操作,但该Cryptoki库(或令牌)实际上不能执行,因为密钥的尺寸超出了它能处理的密钥尺寸的范围。 CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT:该值只能由C_UnwrapKey返回。说明指定来解包另一个密钥的密钥类型与指定于解包的机制不一致。 CKR_USER_ALREADY_LOGGED_IN: 该值只能由C_Login 返回。说明指定的用户不能注册进入对话,因为它已经注册进对话了。举例来说,如果一个应用有一个打开的SO对话,而且它试图将SO注册进去,那么它就会接收到该错误码。 CKR_USER_ANOTHER_ALREADY_LOGGED_IN: 该值只能由C_Login 返回。说明因为其他用户已经注册进对话了,因而指定的用户不能注册进对话。举例来说,如果一个应用有一个打开的SO对话,而且试图将普通用户注册进去,它会接收到该错误码。 CKR_USER_NOT_LOGGED_IN: 因为恰当的用户(或一个恰当的用户)没有注册,因而不能执行想要的动作。举个例子,除非对话已注册,否则不能被注销。再有,除非试图创建私有对象的对话作为普通用户来注册,否则令牌上不能创建私有对象。最后,除非普通用户注册,否则不能执行某些令牌上的密码操作。 CKR_USER_PIN_NOT_INITIALIZED: 该值只能由C_Login返回。说明尚不能用C_InitPIN来初始化普通用户的PIN。 CKR_USER_TOO_MANY_TYPES: 尝试同时在令牌中注册超过令牌和/或库所允许的更多的不同用户。比如说,如果某个应用有一个打开的SO对话,而且另一个应用试图将普通用户注册进对话,这种尝试会返回该错误。但是并不要求这样做。只有如果不能同时支持不同用户时,C_Login才必须返回该值。 注意,该错误码推广出正确的多用户令牌。 CKR_USER_TYPE_INVALID: 将一个无效值指定成CK_USER_TYPE 。有效类型为CKU_SO和 CKU_USER。 CKR_WRAPPED_KEY_INVALID: 该值只能由C_UnwrapKey 返回。说明提供的打包密钥无效。如果调用C_UnwrapKey 来打包一个特定类型的密钥(即,在提供给C_UnwrapKey的模板中规定了某种特定的密钥类型),而且可以识别出提供给C_UnwrapKey 的打包密钥的类型不适合,那么C_UnwrapKey应当返回 CKR_WRAPPED_KEY_INVALID。该返回值的优先权低于 CKR_WRAPPED_KEY_LEN_RANGE的。 CKR_WRAPPED_KEY_LEN_RANGE:该值只能由C_UnwrapKey返回. 说明只根据密钥的长度就能将打包密钥看成是无效的。该返回值的优先权高于CKR_WRAPPED_KEY_INVALID。 CKR_WRAPPING_KEY_HANDLE_INVALID:该值只能由C_WrapKey返回。说明用来打包另一个密钥的密钥句柄无效。 CKR_WRAPPING_KEY_SIZE_RANGE: 该值只能由C_WrapKey 返回。说明理论上可以执行请求的打包操作,但实际上该Cryptoki 库(或令牌)不能进行,这是因为提供的打包密钥的尺寸超出了它能处理的密钥的尺寸的范围。 CKR_WRAPPING_KEY_TYPE_INCONSISTENT: 该值只能由C_WrapKey返回。说明指定打包另一密钥的密钥类型与指定打包的机制不一致。 11.1.7 Cryptoki错误的相关优先权的细节 总体而言,当执行一次 Cryptoki调用时,节中的错误码(而不是CKR_OK)优先于 节中的错误码,优先于节中的错误码,还优先于 节中的错误码。有一个小提示,即使用对话句柄的函数(即大部分函数)决不会返回错误码 CKR_TOKEN_NOT_PRESENT (相反他们返回CKR_SESSION_HANDLE_INVALID)。 除了这些优先权外,如果有不止一个错误码应用于Cryptoki 调用的结果,则可能返回任何可应用的错误码。例外的情况将在函数的说明中明确指出。 11.1.8 错误码 “gotchas” 以下是Cryptoki 开发商想要留意的有关返回值的一些特殊事项。 1. 如节 和节中提到的, Cryptoki库可能不能将函数调用之前被删除的令牌和函数调用过程中被删除的令牌区分开。 2. 如节中提到的,应用收到CKR_SESSION_CLOSED时从不记数。 3. CKR_DATA_INVALID 和CKR_DATA_LEN_RANGE之间的区别很微妙。除非应用需要能够将这两种返回值区分开,否则最好将他们平等看待 4. 类似地, CKR_ENCRYPTED_DATA_INVALID和CKR_ENCRYPTED_DATA_LEN_RANGE, CKR_WRAPPED_KEY_INVALID和 CKR_WRAPPED_KEY_LEN_RANGE之间的区别也很微妙,也最好将他们平等看待。 5. 即使有节的说明,Cryptoki 库开发人员也很难知道将返回CKR_ATTRIBUTE_VALUE_INVALID、 CKR_TEMPLATE_INCOMPLETE,或 CKR_TEMPLATE_INCONSISTENT 中的哪一个。如果可能的话,应用开发人员最好在解释这些错误码时解释得宽泛一些。 11.2 在可变长度缓冲器中返回函数的惯例 Cryptoki 中定义的许多函数返回由某种密码机制产生的输出值。由这些函数返回的输出值的数量在可变长度的应用提供的缓冲器返回。这类函数的事例是C_Encrypt,它把明文作为一个变元,输出装满密文的缓冲器。 这些函数有一些共同的调用惯例。该函数的两个变元中,一个是指向输出缓冲器(即pBuf) 的指示符,另一个是拥有所生成的输出长度的单元指示符(pulBufLen)。调用这样的函数有两种方法。 1. 如果 pBuf 是 NULL_PTR, 则该功能所做的一切就是返回(以 *pulBufLen )一些字节,它将足以拥有从输入到该函数所生成的加密输出。这个数字多少会超出所需字节的精确数,但不会超出许多。该功能返回 CKR_OK。 2. 如果 pBuf 不是 NULL_PTR,那么*pulBufLen 必须包含由pBuf 指向的缓冲器的字节数。如果该缓冲器达到足以容纳由输入到该功能所形成的加密输出,则该加密输出置于此地,并由该功能返回CKR_OK 。反之,返回CKR_BUFFER_TOO_SMALL。在任何一种情况下,*pulBufLen 都被设置为拥有容纳从输入到函数所生成的加密输出所必须的精确的字节数。i 适用于使用上述惯例的所有函数。 在可变长度缓冲器中返回输出的加密功能应当尽可能多地返回迄今为止所能计算的通过该缓冲器传送到该函数的输出。例如,考虑这样一个对话,它正在以PKCS填充的密文链方式用DES执行一个多重解密运算。假设,最初有8字节的密文被传送到C_DecryptUpdate 函数。DES的块大小是8字节,但PKCS填充在此阶段没有明确该密文是从加密一个0字节串中产生密文还是从加密至少8字节长的串中产生的密文。因此,调用C_DecryptUpdate应当返回0字节的明文。如果密文的一个额外字节被接着提供给C_DecryptUpdate ,则调用C_DecryptUpdate 应当返回8字节的明文(一个完整的DES块大小)。 11.3 关于样本代码的否认声明 第11章的其余部分中,列举了Cryptoki 中定义的各种函数。大多数功能将至少用以一个样本代码片段来说明。为简便起见,样本代码时常不太完整。特别是,样本代码通常会忽略来自C库功能的可能的才错误返回,而且不能以实际的方式处理Cryptoki 错误返回。 11.4 通用函数 Cryptoki提供下列通用函数 C_Initialize CK_DEFINE_FUNCTION(CK_RV, C_Initialize)( CK_VOID_PTR pInitArgs ); C_Initialize 初始化 Cryptoki库。 pInitArgs 要么拥有NULL_PTR 的值,要么指向含有说明库应该如何处理多线程访问的信息的CK_C_INITIALIZE_ARGS 结构。如果一个应用将不同时多线程地访问Cryptoki,那么大体上它能给 C_Initialize (提供该值的后果将在以下解释)提供值NULL_PTR。 如果pInitArgs 是非NULL_PTR, C_Initialize会将其投入一个 CK_C_INITIALIZE_ARGS_PTR ,然后撤消定位最终的指针以获得CK_C_INITIALIZE_ARGS 字段CreateMutex,DestroyMutex, LockMutex, UnlockMutex, flags, 和 pReserved. 该版本的Cryptoki中, 由此获得的 pReserved 的值必须是 NULL_PTR;否则,C_Initialize应该返回值 CKR_ARGUMENTS_BAD。 如果标志字段中设置了If the CKF_LIBRARY_CANT_CREATE_OS_THREADS字段,这就说明, 不允许正在执行调用Cryptoki 库的应用线程使用本地操作系统调用来产生新的线程。也就是说,库的编码不能创建自己的线程。如果库在该限制下不能正常工作,则C_Initialize 应该返回值 CKR_NEED_TO_CREATE_THREADS。 调用 C_Initialize指定了通过标志字段中CKF_OS_LOCKING_OK 的值和CreateMutex, DestroyMutex, LockMutex, 和 UnlockMutex 函数指针字段的值来支持多线程访问的四种不同方法中的一种。 1. 如果没有设置标志,并且没有提供函数指针字段(即它们都有NULL_PTR值),这说明应用不会同时多线程访问Cryptoki 库。 2. 如果设置了标志,但是没有提供函数指针字段(即它们都有NULL_PTR值),这说明应用将执行多线程Cryptoki 访问,而且库需要使用本地操作系统原语来保证多线程访问的安全。如果库不能这么做, C_Initialize应当返回CKR_CANT_LOCK 值。 3. 如果标志没有设置,但提供了函数指针字段(即它们都有非-NULL_PTR值),这说明应用将执行多线程Cryptoki 访问,库需要使用提供来进行mutex管理的函数指针来确保多线程访问的安全。如果库不能这么做,C_Initialize 将返回CKR_CANT_LOCK 值。 4. 如果设置了标志,也提供了函数指针字段(即它们都有非-NULL_PTR值),这说明应用将执行多线程Cryptoki 访问,库需要或者使用本地操作系统原语或者使用提供用于mutex管理的函数指针来保证多线程访问的安全。如果库不能这么做,C_Initialize 将返回CKR_CANT_LOCK 值。 如果提供给C_Initialize 的函数指针中的某一些,不是全部,为非-NULL_PTR ,那么C_Initialize 应当返回CKR_ARGUMENTS_BAD 值。 调用其pInitArgs 设置为NULL_PTR 的C_Initialize 就如调用其pInitArgs 指向CK_C_INITIALIZE_ARGS (其CreateMutex, DestroyMutex, LockMutex, UnlockMutex, 和 preserved字段设置为NULL_PTR ,标志设置为0)的C_Initialize 。 C_Initialize 应该是应用执行的首次Cryptoki调用,C_GetFunctionList调用除外。该函数实际上所做的是依赖安装的,特别是,它可能会让Cryptoki初始化其内部的存储缓冲器或者其它资源。 如果几个应用都在使用Cryptoki,每一个都需要调用C_Initialize。每调用一次C_Initialize 都接着要单独调用一次C_Finalize。详情参见 节。 返回值: CKR_ARGUMENTS_BAD, CKR_CANT_LOCK, CKR_CRYPTOKI_ALREADY_INITIALIZED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_NEED_TO_CREATE_THREADS, CKR_OK. 实例:参见 C_GetInfo. C_Finalize CK_DEFINE_FUNCTION(CK_RV, C_Finalize)( CK_VOID_PTR pReserved ); 调用C_Finalize表明,用Cryptoki库完成了一个应用。它应当是应用所做的最后一次调用。 pReserved 参数为未来版本使用。对于该版本,它应当被设置成NULL_PTR 。(如果 调用C_Finalize 的pReserved为非-NULL_PTR 值,那么应该返回CKR_ARGUMENTS_BAD 值。) 如果几个应用正在使用Cryptoki ,则每个应用应当调用C_Finalize 。每次调用C_Finalize 前,应当调用一次C_Initialize 。在两个调用中,应用还调用其它的Cryptoki 功能。详情参见节。 除了提供给C_Initialize 的参数大体上能允许安全地进行Cryptoki 库的多线程访问这一事实外,如果其它应用的线程在执行Cryptoki 调用时C_Finalize被一个应用线程调用,那么不管怎样C_Finalize 的性能是没有规定的。只有当线程在应用的另一个线程在Cryptoki的 C_WaitForSlotEvent函数中封锁的的同时调用 C_Finalize 时C_Finalize 的特殊性能会有例外情况发生。这时,封锁的线程被接锁,并返回 CKR_CRYPTOKI_NOT_INITIALIZED值。详情参见C_WaitForSlotEvent 部分。 返回值:CKR_ARGUMENTS_BAD, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK. 实例:参见C_GetInfo. C_GetInfo CK_DEFINE_FUNCTION(CK_RV, C_GetInfo)( CK_INFO_PTR pInfo ); C_GetInfo 返回有关Cryptoki的通用消息。 pInfo 指向接收信息单元。 返回值:CKR_ARGUMENTS_BAD, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK. 实例: CK_INFO info; CK_RV rv; CK_C_INITIALIZE_ARGS InitArgs; InitArgs.CreateMutex = &MyCreateMutex; InitArgs.DestroyMutex = &MyDestroyMutex; InitArgs.LockMutex = &MyLockMutex; InitArgs.UnlockMutex = &MyUnlockMutex; InitArgs.flags = CKF_OS_LOCKING_OK; InitArgs.pReserved = NULL_PTR; rv = C_Initialize((CK_VOID_PTR)&InitArgs); assert(rv == CKR_OK); rv = C_GetInfo(&info); assert(rv == CKR_OK); if(info.version.major == 2) { /* Do lots of interesting cryptographic things with the token */ . . . } rv = C_Finalize(NULL_PTR); assert(rv == CKR_OK); C_GetFunctionList CK_DEFINE_FUNCTION(CK_RV, C_GetFunctionList)( CK_FUNCTION_LIST_PTR_PTR ppFunctionList ); C_GetFunctionList 获得一个指向Cryptoki库的函数指针表的指针。 ppFunctionList 指向一个值,该值将接收一个指向该库的CK_FUNCTION_LIST 结构的指针,它包括库中所有Cryptoki API 例行程序的函数指针。所获得的指针可以指入Cryptoki 库所拥有的存储器,该存储器可能是也可能不是可写的。在任何情况下,都不要写入该存储器。 在调用C_Initialize 之前, C_GetFunctionList 是应用可能会调用的唯一的函数。这样可使应用方便、快速地使用共享Cryptoki 库和同时使用多个Cryptoki 库。 返回值:CKR_ARGUMENTS_BAD, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK. 实例: CK_FUNCTION_LIST_PTR pFunctionList; CK_C_Initialize pC_Initialize; CK_RV rv; /* It’s OK to call C_GetFunctionList before calling C_Initialize */ rv = C_GetFunctionList(&pFunctionList); assert(rv == CKR_OK); pC_Initialize = pFunctionList -> C_Initialize; /* Call the C_Initialize function in the library */ rv = (*pC_Initialize)(NULL_PTR); 11.5 槽和令牌管理函数 Cryptoki 为槽和令牌管理提供下列函数。 C_GetSlotList CK_DEFINE_FUNCTION(CK_RV, C_GetSlotList)( CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount ); C_GetSlotList 用于获得系统中的一个槽列表。tokenPresent 表明所获得的列表是否只包括带有一个当前令牌(TRUE)的那些槽,或者包括所有槽(FALSE);pulCount 指向接收槽数量的单元。 应用调用 C_GetSlotList有两种方法: 1. 如果 pSlotList 是 NULL_PTR, 那么 C_GetSlotList 所能做的一切是返回(in *pulCount) 槽的数量,而不是实际返回一个槽列表。在C_GetSlotList 入口上由pulCount指向的缓冲器的内容此时无意义,该调用返回值CKR_OK。 2. 如果 pSlotList 不是NULL_PTR, 那么*pulCount 必须包含由pSlotList 所指的缓冲器的大小(以CK_SLOT_ID 单元为单位)。如果该缓冲器有足够大的空间容纳槽列表,那么在该缓冲器中返回该列表,并返回CKR_OK。反之,调用C_GetSlotList 返回值CKR_BUFFER_TOO_SMALL。在任何一种情况下,值*pulCount 被设置为可容纳槽数的大小。 由于C_GetSlotList 不划分自己的空间,因此应用经常两次调用C_GetSlotList (有时甚至会是试图与当前令牌一起获取所有槽的列表的次数,然后,槽数就会在该应用询问有多少个槽时和应用自己询问槽数时之间变化)。然而,多重调用C_GetSlotList 并不是所请求的。 C_GetSlotList 报告的所有槽必须能够被C_GetSlotInfo 象有效槽那样排队。另外,通过Cryptoki库可访问的槽的设置在调用C_Initialize时就被确定。如果一个应用调用C_Initialize and C_GetSlotList,那么用户接入一个新的设备,如果再次调用C_GetSlotList 的话,该设备不能突然一下子作为一个新槽出现。为了识别新的设备, 需要首先调用C_Initialize (为了能够成功调用C_Initialize),需要首先调用C_Finalize )。即使 Even if C_Initialize 被成功调用,新设备有可能也可能不能被成功识别。在某些平台上,可能需要重新启动整个系统。 返回值:CKR_ARGUMENTS_BAD, CKR_BUFFER_TOO_SMALL, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK. 实例: CK_ULONG ulSlotCount, ulSlotWithTokenCount; CK_SLOT_ID_PTR pSlotList, pSlotWithTokenList; CK_RV rv; /* Get list of all slots */ rv = C_GetSlotList(FALSE, NULL_PTR, &ulSlotCount); if (rv == CKR_OK) { pSlotList = (CK_SLOT_ID_PTR) malloc(ulSlotCount*sizeof(CK_SLOT_ID)); rv = C_GetSlotList(FALSE, pSlotList, &ulSlotCount); if (rv == CKR_OK) { /* Now use that list of all slots */ . . . } free(pSlotList); } /* Get list of all slots with a token present */ pSlotWithTokenList = (CK_SLOT_ID_PTR) malloc(0); ulSlotWithTokenCount = 0; while (1) { rv = C_GetSlotList( TRUE, pSlotWithTokenList, ulSlotWithTokenCount); if (rv != CKR_BUFFER_TOO_SMALL) break; pSlotWithTokenList = realloc( pSlotWithTokenList, ulSlotWithTokenList*sizeof(CK_SLOT_ID)); } if (rv == CKR_OK) { /* Now use that list of all slots with a token present */ . . . } free(pSlotWithTokenList); C_GetSlotInfo CK_DEFINE_FUNCTION(CK_RV, C_GetSlotInfo)( CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo ); C_GetSlotInfo 获得系统中有关一个特定槽的信息。slotID 是槽的ID。pInfo 指向接收槽信息的单元。 返回值: CKR_ARGUMENTS_BAD, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_SLOT_ID_INVALID. 实例:参见C_GetTokenInfo. C_GetTokenInfo CK_DEFINE_FUNCTION(CK_RV, C_GetTokenInfo)( CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo ); C_GetTokenInfo 获得系统中有关一个特定令牌的信息。slotID 是令牌的槽的ID。pInfo 指向接收令牌信息的单元。 返回值: CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_SLOT_ID_INVALID, CKR_TOKEN_NOT_PRESENT, CKR_TOKEN_NOT_RECOGNIZED, CKR_ARGUMENTS_BAD. 实例: CK_ULONG ulCount; CK_SLOT_ID_PTR pSlotList; CK_SLOT_INFO slotInfo; CK_TOKEN_INFO tokenInfo; CK_RV rv; rv = C_GetSlotList(FALSE, NULL_PTR, &ulCount); if ((rv == CKR_OK) && (ulCount > 0)) { pSlotList = (CK_SLOT_ID_PTR) malloc(ulCount*sizeof(CK_SLOT_ID)); rv = C_GetSlotList(FALSE, pSlotList, &ulCount); assert(rv == CKR_OK); /* Get slot information for first slot */ rv = C_GetSlotInfo(pSlotList[0], &slotInfo); assert(rv == CKR_OK); /* Get token information for first slot */ rv = C_GetTokenInfo(pSlotList[0], &tokenInfo); if (rv == CKR_TOKEN_NOT_PRESENT) { . . . } . . . free(pSlotList); } C_WaitForSlotEvent CK_DEFINE_FUNCTION(CK_RV, C_WaitForSlotEvent)( CK_FLAGS flags, CK_SLOT_ID_PTR pSlot, CK_VOID_PTR pReserved ); C_WaitForSlotEvent 等待一个槽事件的发生,例如令牌插入或令牌删除。标志确定C_WaitForSlotEvent 调用是否锁定(即等待槽事件的发生)。pSlot 指向接收事件发生所在槽的ID的单元。 pReserved 用于未来版本。就Cryptoki 的该版本而言,应该是 NULL_PTR. 目前,在标志变元中规定使用的唯一标志是CKF_DONT_BLOCK: #define CKF_DONT_BLOCK 1 在内部,每个Cryptoki应用的每个槽都有一个标志,用来跟踪是否包含该槽的任何未识别的事件有所发生。当应用首次调用C_Initialize时,每个槽的标志被清除。无论槽事件何时发生,对应于事件发生的槽的标志被设置。 如果调用C_WaitForSlotEvent ,在标志变元中设置CKF_DONT_BLOCK 标志,而且设置了某个槽事件的标志,那么清除该事件的标志,并且调用返回pSlot.所指的单元中槽的ID。如果在调用时设置了不止一个槽的事件标志,那么库会选择这样的一个槽,将其事件标志清除并返回其槽的ID。 如果调用 C_WaitForSlotEvent ,在标志变元中设置CKF_DONT_BLOCK标志,但没有设置槽的事件标志,那么调用返回CKR_NO_EVENT值。这种情况下,pSlot 所指的单元内容没有规定。. 如果调用C_WaitForSlotEvent,标志变元中清除 CKF_DONT_BLOCK 标志,那么调用象以前一样进行,除了产生封锁的情况。即,在调用时没有设置槽的事件标志,C_WaitForSlotEvent 会一直等待某些槽的事件标志被设置。如果当应用的另一个线程调用C_Finalize 时应用的一个线程有一个 C_WaitForSlotEvent 调用封锁,那么C_WaitForSlotEvent 调用返回CKR_CRYPTOKI_NOT_INITIALIZED值。 尽管提供给C_Initialize 的参数一般都能保证安全地多线程访问Cryptoki库, C_WaitForSlotEvent 是个例外,即如果单个应用的多线程同时调用C_WaitForSlotEvent ,那么Cryptoki 的性能没有规定。 返回值:CKR_ARGUMENTS_BAD, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_NO_EVENT, CKR_OK. 实例: CK_FLAGS flags = 0; CK_SLOT_ID slotID; CK_SLOT_INFO slotInfo; . . . /* Block and wait for a slot event */ rv = C_WaitForSlotEvent(flags, &slotID, NULL_PTR); assert(rv == CKR_OK); /* See what’s up with that slot */ rv = C_GetSlotInfo(slotID, &slotInfo); assert(rv == CKR_OK); . . . C_GetMechanismList CK_DEFINE_FUNCTION(CK_RV, C_GetMechanismList)( CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount ); C_GetMechanismList 用于获取由一个令牌所支持的机制类型列表。SlotID 是令牌的ID; pulCount 指向接收机制数的单元。 应用调用C_GetMechanismList 有两种方法: 1. 如果 pMechanismList 是 NULL_PTR,那么C_GetMechanismList 所能做的一切是返回 (用 *pulCount) 机制的数目,而不是实际返回一个机制列表。C_GetMechanismList 入口上的*pulCount 内容此时无意义,该调用返回CKR_OK值。 2. 如果 pMechanismList 不是 NULL_PTR,那么*pulCount 必须包含由pMechanismList 所指的缓冲器的大小(以CK_MECHANISM_TYPE 单元为单位)。如果该缓冲器有足够大的空间容纳机制列表,那么在缓冲器中返回该列表,并返回 CKR_OK。反之,调用 C_GetMechanismList 返回CKR_BUFFER_TOO_SMALL值。在任何一种情况下, *pulCount 值被设置成可容纳机制数的大小。 由于C_GetMechanismList 不划分自己的空间,因此应用会经常两次调用C_GetMechanismList 。然而,该性能并不是要求的。 返回值:CKR_BUFFER_TOO_SMALL, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_SLOT_ID_INVALID, CKR_TOKEN_NOT_PRESENT, CKR_TOKEN_NOT_RECOGNIZED, CKR_ARGUMENTS_BAD. 实例: CK_SLOT_ID slotID; CK_ULONG ulCount; CK_MECHANISM_TYPE_PTR pMechanismList; CK_RV rv; . . . rv = C_GetMechanismList(slotID, NULL_PTR, &ulCount); if ((rv == CKR_OK) && (ulCount > 0)) { pMechanismList = (CK_MECHANISM_TYPE_PTR) malloc(ulCount*sizeof(CK_MECHANISM_TYPE)); rv = C_GetMechanismList(slotID, pMechanismList, &ulCount); if (rv == CKR_OK) { . . . } free(pMechanismList); } C_GetMechanismInfo CK_DEFINE_FUNCTION(CK_RV, C_GetMechanismInfo)( CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo ); C_GetMechanismInfo 获取可能由一个令牌支持的一个特定机制的信息。slotID 是令牌槽的ID;type 是机制的类型;pInfo 指向接收机制信息的单元。 返回值: CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_MECHANISM_INVALID, CKR_OK, CKR_SLOT_ID_INVALID, CKR_TOKEN_NOT_PRESENT, CKR_TOKEN_NOT_RECOGNIZED, CKR_ARGUMENTS_BAD. 实例: CK_SLOT_ID slotID; CK_MECHANISM_INFO info; CK_RV rv; . . . /* Get information about the CKM_MD2 mechanism for this token */ rv = C_GetMechanismInfo(slotID, CKM_MD2, &info); if (rv == CKR_OK) { if (info.flags & CKF_DIGEST) { . . . } } C_InitToken CK_DEFINE_FUNCTION(CK_RV, C_InitToken)( CK_SLOT_ID slotID, CK_CHAR_PTR pPin, CK_ULONG ulPinLen, CK_UTF8CHAR_PTR pLabel ); C_InitToken 初始化一个令牌。slotID 是令牌的槽的ID;pPin 指向SO的初始PIN (不需要是0值终止);ulPinLen 是PIN字节的长度;pLabel 指向该令牌的32字节标记(必须用空白字符填充,不必是0值终止)。 如果令牌尚未初始化(即,新出厂的),那么pPin 参数成为SO PIN的初始值。如果正在重新初始化令牌,那么用pPin 参数值核查现有的SO PIN以认证初始化操作。在两种情况下, 在函数成功完成后,SO PIN 就是 pPin 的值。如果丢失了SO PIN ,那么必须用该标准范围之外的机制来重新初始化卡。CK_TOKEN_INFO 结构中的CKF_TOKEN_INITIALIZED 标志说明将从调用C_InitToken中产生的动作。如果设置了,该令牌将被初始化,客户必须在pPin 中提供现有的SO口令。 当初始化一个令牌时,所有能被破坏的对象都被破坏了(即,除“难以描述”的对象外的所有对象,如令牌内置的密钥)。同样,普通用户访问是不允许的,除非SO设置了普通用户的PIN。根据令牌,可以建立“缺省”对象,一些对象的属性可以设置为缺省值。 如果CKF_PROTECTED_AUTHENTICATION_PATH 标志在其CK_TOKEN_INFO 中被设置所表明的,令牌有一个“受保护的认证通道”,那么就意味着在不必使应用通过Cryptoki 库发送一个PIN的情况下,用户就可以采取某种方式被认证到该令牌。有一个可能性是,用户进入令牌本身或槽设备上的PINpad上的一个PIN。要这样一个受保护的认证路径来初始化一个令牌,那么C_InitToken 的pPin参数应当是NULL_PTR。在C_InitToken的执行过程中,将通过受保护的认证路径进入SO的PIN。 如果除PINpad外,令牌还有一个受保护的认证路径,那么无论C_InitToken 能否能用于初始令牌,它都与令牌相关。 如果Cryptoki 检查出一个应用打开了一个对话,那么就不能初始化该令牌;此时,当调用C_InitToken 时,该调用会因错误CKR_SESSION_EXISTS而失败。此类情况也会发生在没有与令牌一起打开对话的其它应用上,但Cryptoki 不会加以检查,因为用该令牌不能检查出任何有关该应用的信息。如果情况的确如此,那么就不能规定 C_InitToken 调用的结果。 C_InitToken 函数可能不足以合适地初始化复杂的令牌。在这些情况下,必须采用Cryptoki 之外的初始化机制。“复杂令牌”的规定根据产品而异。 返回值: CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_PIN_INCORRECT, CKR_PIN_LOCKED, CKR_SESSION_EXISTS, CKR_SLOT_ID_INVALID, CKR_TOKEN_NOT_PRESENT, CKR_TOKEN_NOT_RECOGNIZED, CKR_TOKEN_WRITE_PROTECTED, CKR_ARGUMENTS_BAD. 实例 CK_SLOT_ID slotID; CK_CHAR_PTR pin = “MyPIN”; CK_UTF8CHAR label[32]; CK_RV rv; . . . memset(label, ‘ ’, sizeof(label)); memcpy(label, “My first token”, strlen(“My first token”)); rv = C_InitToken(slotID, pin, strlen(pin), label); if (rv == CKR_OK) { . . . } C_InitPIN CK_DEFINE_FUNCTION(CK_RV, C_InitPIN)( CK_SESSION_HANDLE hSession, CK_CHAR_PTR pPin, CK_ULONG ulPinLen ); C_InitPIN 初始化普通用户的PIN. hSession 是对话的句柄; pPin 指向普通用户的PIN;ulPinLen 是PIN的字节长度。 C_InitPIN 只能在“R/W SO函数”状态下调用。试图在其他任何状态调用会因错误CKR_USER_NOT_LOGGED_IN而失败。 如果象设置CK_TOKEN_INFO中的CKF_PROTECTED_AUTHENTICATION_PATH标志表明的,令牌有一个“保护认证路径”,那么也就意味着无需应用通过Cryptoki 库发送PIN,用户就有某种方法认证到令牌。有一种可能性是,用户进入其令牌本身上或槽设备上PINpad的PIN。要用这样一个受保护的认证通道在一个令牌上初始化普通用户的PIN,则C_InitPIN 的pPin 参数应该为 NULL_PTR。在C_InitPIN的执行过程中,SO将通过保护认证路径进入新的PIN。 如果令牌有一个保护认证路径而不是一个PINpad,那么无论能否用C_InitPIN 来初始化普通用户的令牌访问,它都是与令牌相关的 返回值:CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_PIN_INVALID, CKR_PIN_LEN_RANGE, CKR_SESSION_CLOSED, CKR_SESSION_READ_ONLY, CKR_SESSION_HANDLE_INVALID, CKR_TOKEN_WRITE_PROTECTED, CKR_USER_NOT_LOGGED_IN, CKR_ARGUMENTS_BAD. 实例: CK_SESSION_HANDLE hSession; CK_CHAR newPin[]= {“NewPIN”}; CK_RV rv; rv = C_InitPIN(hSession, newPin, sizeof(newPin)); if (rv == CKR_OK) { . . . } C_SetPIN CK_DEFINE_FUNCTION(CK_RV, C_SetPIN)( CK_SESSION_HANDLE hSession, CK_CHAR_PTR pOldPin, CK_ULONG ulOldLen, CK_CHAR_PTR pNewPin, CK_ULONG ulNewLen ); C_SetPIN 修改目前注册的用户的PIN,或者如果没有注册进对话就修改CKU_USER PIN 。hSession 是对话的句柄;pOldPin 指向旧的PIN; ulOldLen 是旧的PIN的字节长度; pNewPin 指向新的PIN; ulNewLen 是新的PIN的字节长度。 C_SetPIN只能在“R/W公共对话”状态、“R/W SO函数”状态,或者“R/W用户函数”状态下调用。其他任何状态下试图调用都会因错误CKR_SESSION_READ_ONLY 而失败。 正如设置的CK_TOKEN_INFO中的CKF_PROTECTED_AUTHENTICATION_PATH标志所表明的,如果标志有一个“保护认证路径”,那就是说不需要应用通过Cryptoki库发送PIN用户就有某种方法被认证到令牌。有一种可能性就是,用户进入令牌本身的上的或槽设备上的PINpad 的PIN。为了用这样一个保护认证路径来修改令牌上当前用户的PIN, C_SetPIN 的pOldPin 和 pNewPin 参数应当为NULL_PTR。在执行C_SetPIN的过程中,当前用户将通过保护认证路径进入旧的PIN和新的PIN。但并没有规定如何使用PINpad进入PIN,情况各异。 如果令牌有一个保护认证路径,而不是一个PINpad,那么无论能否用C_SetPIN 来修改当前用户的PIN,它都是与令牌相关的。 返回值:CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_PIN_INCORRECT, CKR_PIN_INVALID, CKR_PIN_LEN_RANGE, CKR_PIN_LOCKED, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_SESSION_READ_ONLY, CKR_TOKEN_WRITE_PROTECTED, CKR_ARGUMENTS_BAD. 实例: CK_SESSION_HANDLE hSession; CK_CHAR oldPin[] = {“OldPIN”}; CK_CHAR newPin[] = {“NewPIN”}; CK_RV rv; rv = C_SetPIN( hSession, oldPin, sizeof(oldPin), newPin, sizeof(newPin)); if (rv == CKR_OK) { . . . } 11.6 对话管理函数 一个典型的应可能会执行以下各步骤来使用令牌(注意,应用也可能执行其它可行的步骤) 1. 选择一个令牌。 2. 一次或多次调用C_OpenSession 来获得一个或多个带令牌的对话。 3. 调用C_Login 将用户注册进令牌。由于一个应用的所有带令牌的对话都有一个共享的注册状态,所以只需为一个对话调用C_Login 4. 使用带令牌的对话来执行密码操作 5. 为应用包含的带令牌的每个对话调用一次C_CloseSession, 或者调用C_CloseAllSessions 同时关闭应用的所有对话。 正如我们所看到的,一个应用可能有带不止一个令牌的并行对话。也有可能令牌有带有不止一个应用的并行对话。 Cryptoki 提供了以下对话管理函数: C_OpenSession CK_DEFINE_FUNCTION(CK_RV, C_OpenSession)( CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession ); C_OpenSession 打开某一特定槽中应用和令牌间的对话。slotID 是槽的ID; flags 表明对话的类型; pApplication 是一个要传递给通知回调的应用定义的指针;iNotify 是通知回调函数的地址(见节); phSession 指向接收新对话句柄的单元。 当打开一个带C_OpenSession的对话时,标志参数由CK_SESSION_INFO 数据类型中定义的零位或多位标志的逻辑OR组成。由于传统原因,必须总是设置 CKF_SERIAL_SESSION 位;如果调用C_OpenSession 的该位没有设置,那么调用不成功,返回错误码CKR_PARALLEL_NOT_SUPPORTED。 一个应用可能并行的对话数量会有一个限制,它取决于对话是“只读”还是“读/写”。尝试打开一个由于有太多某种类型的现有对话而不能成功的对话时应当返回CKR_SESSION_COUNT. 如果令牌是写保护的(如CK_TOKEN_INFO结构中所说),那么打开带令牌的只读对话。 如果调用C_OpenSession 的应用已经有带令牌的R/W SO打开的 对话,那么任何试图打开带令牌的R/O对话均失败,返回错误码CKR_SESSION_READ_WRITE_SO_EXISTS (参见节)。 Cryptoki采用 Notify 回调函数来指明某些事件的应用。如果应用不希望支持回调,则应该传输一个NULL_PTR值作为Notify 参数。有关应用回调的更多情况参见节 。 返回值:CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_SESSION_COUNT, CKR_SESSION_PARALLEL_NOT_SUPPORTED, CKR_SESSION_READ_WRITE_SO_EXISTS, CKR_SLOT_ID_INVALID, CKR_TOKEN_NOT_PRESENT, CKR_TOKEN_NOT_RECOGNIZED, CKR_TOKEN_WRITE_PROTECTED, CKR_ARGUMENTS_BAD. 实例:参见 C_CloseSession. C_CloseSession CK_DEFINE_FUNCTION(CK_RV, C_CloseSession)( CK_SESSION_HANDLE hSession ); C_CloseSession 关闭应用和令牌见的对话。hSession 是对话的句柄。 当关闭一个对话时,对话创建的所有对话对象均被自动破坏,即使应用还有其它对话在“使用”该对象(详情参见- 节)。 如果该函数执行成功,关闭了应用和令牌间的最后一个对话,那么应用的令牌的逻辑状态返回到公共对话。应用打开的令牌的任何新的对话或者是R/O 公共对话或者是R/W 公共对话。 根据令牌,当关闭任何应用的最后一个带令牌的打开的对话时,令牌可能会从其读者方“射出”(如果存在这种能力的话)。 尽管假设该C_CloseSession 关闭一个对话,返回值CKR_SESSION_CLOSED 还是一个错误的返回。它事实上表明(有时不可能)在该函数正在执行的时候,调用另一个C_CloseSession 来关闭该特定的对话,该调用首先结束执行。这种方式使用对话不好,如果一个应用总是执行这种行为,那么 Cryptoki总体上就很少能确保将会有什么情况发生。 返回值:CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID. 实例: CK_SLOT_ID slotID; CK_BYTE application; CK_NOTIFY MyNotify; CK_SESSION_HANDLE hSession; CK_RV rv; . . . application = 17; MyNotify = &EncryptionSessionCallback; rv = C_OpenSession( slotID, CKF_RW_SESSION,(CK_VOID_PTR) &application, MyNotify, &hSession); if (rv == CKR_OK) { . . . C_CloseSession(hSession); } C_CloseAllSessions CK_DEFINE_FUNCTION(CK_RV, C_CloseAllSessions)( CK_SLOT_ID slotID ); C_CloseAllSessions 关闭一个应用所有的带令牌的对话。slotID 指定令牌的槽 当关闭一个对话时,该对话创建的所有对话对象均自动破坏。 成功执行该函数后,应用的令牌的逻辑状态返回公共对话。应用打开的 令牌的任何新的对话或者是R/O 公共对话或者是R/W 公共对话。 根据令牌,当任何应用的带有令牌的最后一个打开的对话被关闭时,令牌可能会被从其读者中“射出”(如果存在这种能力的话)。 返回值: CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_SLOT_ID_INVALID, CKR_TOKEN_NOT_PRESENT. 实例: CK_SLOT_ID slotID; CK_RV rv; . . . rv = C_CloseAllSessions(slotID); C_GetSessionInfo CK_DEFINE_FUNCTION(CK_RV, C_GetSessionInfo)( CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo ); C_GetSessionInfo 获得有关一个对话的信息。hSession 是对话的句柄;pInfo 指向接收对话信息的单元。 返回值:CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_ARGUMENTS_BAD. 实例: CK_SESSION_HANDLE hSession; CK_SESSION_INFO info; CK_RV rv; . . . rv = C_GetSessionInfo(hSession, &info); if (rv == CKR_OK) { if (info.state == CKS_RW_USER_FUNCTIONS) { . . . } . . . } C_GetOperationState CK_DEFINE_FUNCTION(CK_RV, C_GetOperationState)( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, CK_ULONG_PTR pulOperationStateLen ); C_GetOperationState 获得对话密码操作状态的副本,编码成一串字节。hSession 是对话的句柄;pOperationState 指向接收该状态的单元;pulOperationStateLen 指向接收状态字节长的单元。 尽管C_GetOperationState 输出的保存状态实际上不是由“加密机制”产生的, C_GetOperationState 也会采用节中所述的产生输出的惯例。 精确地说,令牌的该函数保存的“密码操作状态”各不相同;然而,该状态正是所提供来输入C_SetOperationState 以恢复对话的加密活动的。 考虑一下采用SHA-1执行消息摘要操作的对话(即,对话采用CKM_SHA_1机制)。假设消息摘要操作被合适地初始化,而且至今正好有80个 字节的数据被输入到SHA-1。当前应用想“保存”摘要操作的状态,以便以后能继续。在这一特定情况下,由于SHA-1一次处理512位(64字节)的输入,因而对话的密码操作状态最有可能由三个不同的部分组成:SHA-1的160位内部链接变量的状态;16位的非处理输入输入数据;以及说明该保存状态来自正在执行的SHA-1散列的对话的某些管理数据。综合起来,这三条信息足以在以后继续当前的散列运算。 考虑正在执行CBS(密码块链接)模式(即,对话在使用CKM_DES_CBC机制)的带DES(块大小为64位的块密码)的密码操作的下一个对话。假设至今正好给DES提供了22字节的数据(除了CBC模式的一个IV外),这说明密文的前8字节的块已经被产生和输出。 这种情况下,对话的密码操作状态最有可能由三或四中不同的部分组成:密文的第二个8字节的块(将被用做产生密文下一个块的密码块链接);仍在等待加密的6字节数据;表明该保存状态来自正在以CBC方式 执行DES加密的对话的管理数据;以及可能用于加密的DES密钥(有关保存状态中是否存在密钥的详情,参见C_SetOperationState)。 如果一个对话同时在执行两个密码操作(参见节),那么对话的密码操作状态将包含用于恢复两个运算的所有必要的信息。 试图保存一个目前没有有效的可保存密码操作(不需要消息恢复的加密、解密、摘要、签名,不用消息恢复的验证,或这两种情况的一些合法组合)对话的密码操作状态将会因错误CKR_OPERATION_NOT_INITIALIZED 而失败。 试图保存一个正在执行一个适当的密码操作(或两个),但因各种原因不大满意的(例如,特定的必要状态信息和/或密钥信息不能脱离该令牌)的对话的密码操作状态,将因错误CKR_STATE_UNSAVEABLE 而失败。 返回值:CKR_BUFFER_TOO_SMALL, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_OPERATION_NOT_INITIALIZED, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_STATE_UNSAVEABLE, CKR_ARGUMENTS_BAD. 实例:参见C_SetOperationState. C_SetOperationState CK_DEFINE_FUNCTION(CK_RV, C_SetOperationState)( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey, CK_OBJECT_HANDLE hAuthenticationKey ); C_SetOperationState 从用C_GetOperationState 获得的一串字节中恢复一个对话的密码操作状态。hSession 是对话的句柄;pOperationState 指向包含保存状态的单元; ulOperationStateLen 包含保存状态的长度;hEncryptionKey 包含一个在恢复对话中用来进行加密或解密操作的密钥的句柄(或者如果由于要么储存的对话中没有进行这样的操作,要么保存的状态中现有所有必要的密钥,因而不需要加密或解密密钥时,为0)。hAuthenticationKey 包含将用来在恢复的对话中进行签名、MACing,或者认证操作的密钥的句柄(或者如果由于要么储存的对话中没有这样的操作,要么保存的状态中现有所有必要的密钥,因而不需要这样的密钥时,为0)。 由于状态被恢复到“目的对话”,因而不需要从同一对话(“源对话”)获取状态。然而,源对话和目的对话应该有一个共同的对话状态,(如CKS_RW_USER_FUNCTIONS)并应该带有一个共同的令牌。同时也不保证密码操作状态能通过注册或通过不同的Cryptoki 安装。 如果给C_SetOperationState 提供的所谓的保存的密码操作状态——它能确定的是非有效保存状态(或者是带有不同对话状态的对话的密码操作状态,亦或不同令牌的密码操作状态),则因错误CKR_SAVED_STATE_INVALID而失败。 从调用C_GetOperationState 获得的保存状态可能含有也可能不含用来进行密码操作的密钥的信息。如果一个保存的密码操作状态有一个正在进行的加密或解密操作,而且用来操作的密钥没有保存在状态中,那么必须将其提供给hEncryptionKey 变元中的C_SetOperationState。否则,C_SetOperationState 失败并返回错误CKR_KEY_NEEDED。 如果用做操作的密钥保存在状态中,那么可以在hEncryptionKey 变元中提供,但不做要求。 类似地,如果一个保存的密码操作状态有一个正在执行的签名、MACing或认证操作,而且用做操作的密钥没有保存在状态中,那么必须将其提供给C_SetOperationState。否则, C_SetOperationState 因错误CKR_KEY_NEEDED而失败。如果用做操作的密钥保存在状态中,那么可以在hAuthenticationKey 中提供它,但不做要求。I 如果给C_SetOperationState 调用提供了一个不相关调用,如,hEncryptionKey 变元中提交了一个非零密钥句柄,但提供的保存密码操作状态并没有执行中的加密或解密操作,那么C_SetOperationState 出错,错误为CKR_KEY_NOT_NEEDED。 如果将密钥作为一个变元提供给C_SetOperationState,,而且C_SetOperationState 能在某种程度上发现此密钥不是源对话中用于提供的密码操作状态的密钥(举个例子,如果如果密钥或密钥的散列出现在保存的状态中时),那么C_SetOperationState 出错,错误为 CKR_KEY_CHANGED。 应用会查询CK_TOKEN_INFO 字段中标志字段里的CKF_RESTORE_KEY_NOT_NEEDED 标志来确定是否需要为C_SetOperationState 调用提供密钥句柄。如果该标志为TRUE,则决不需要给调用 C_SetOperationState 提供密钥句柄。如果标志为FALSE,那么C_SetOperationState 至少在某些时候需要密钥句柄,因此应用在将密码操作恢复到对话时应该总能传递任何相关的密钥句柄。 即使当调用C_SetOperationState时对话有现用密码或对象搜寻操作(进行中的操作突然取消),C_SetOperationState 也能成功地将密码操作状态恢复到对话。 返回值:CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_KEY_CHANGED, CKR_KEY_NEEDED, CKR_KEY_NOT_NEEDED, CKR_OK, CKR_SAVED_STATE_INVALID, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_ARGUMENTS_BAD. 实例: CK_SESSION_HANDLE hSession; CK_MECHANISM digestMechanism; CK_ULONG ulStateLen; CK_BYTE data1[] = {0x01, 0x03, 0x05, 0x07}; CK_BYTE data2[] = {0x02, 0x04, 0x08}; CK_BYTE data3[] = {0x10, 0x0F, 0x0E, 0x0D, 0x0C}; CK_BYTE pDigest[20]; CK_ULONG ulDigestLen; CK_RV rv; . . . /* Initialize hash operation */ rv = C_DigestInit(hSession, &digestMechanism); assert(rv == CKR_OK); /* Start hashing */ rv = C_DigestUpdate(hSession, data1, sizeof(data1)); assert(rv == CKR_OK); /* Find out how big the state might be */ rv = C_GetOperationState(hSession, NULL_PTR, &ulStateLen); assert(rv == CKR_OK); /* Allocate some memory and then get the state */ pState = (CK_BYTE_PTR) malloc(ulStateLen); rv = C_GetOperationState(hSession, pState, &ulStateLen); /* Continue hashing */ rv = C_DigestUpdate(hSession, data2, sizeof(data2)); assert(rv == CKR_OK); /* Restore state. No key handles needed */ rv = C_SetOperationState(hSession, pState, ulStateLen, 0, 0); assert(rv == CKR_OK); /* Continue hashing from where we saved state */ rv = C_DigestUpdate(hSession, data3, sizeof(data3)); assert(rv == CKR_OK); /* Conclude hashing operation */ ulDigestLen = sizeof(pDigest); rv = C_DigestFinal(hSession, pDigest, &ulDigestLen); if (rv == CKR_OK) { /* pDigest[] now contains the hash of 0x01030507100F0E0D0C */ . . . } C_Login CK_DEFINE_FUNCTION(CK_RV, C_Login)( CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_CHAR_PTR pPin, CK_ULONG ulPinLen ); C_Login 将每个用户注册一个令牌。hSession 是对话句柄;userType 是用户类型;pPin 指向用户的PIN; ulPinLen 是PIN的长度。 如果调用成功,则根据用户的类型,应用的各个对话要么进入“R/W SO函数”状态,要么进入“R/O用户函数”状态。 如果正如其设置的CK_TOKEN_INFO 中的CKF_PROTECTED_AUTHENTICATION_PATH 标志所表明的,令牌有一条“受保护的认证路径”,那就意味着应用不需通过Cryptoki库发送PIN,用户也有某种办法能让其被令牌认证。其中一种可能的方法是用户进入令牌自身的或槽设备的PINpad上的PIN。或者用户可能甚至不使用PIN——比如说,可以由某种指纹阅读设备取得认证。为了注册一个带受保护认证的路径,C_Login 的pPin参数应该是NULL_PTR 。当C_Login 返回时,无论令牌支持的什么方法都将被执行;返回值CKR_OK说明用户已被成功认证,返回值CKR_PIN_INCORRECT 则说明用户被拒绝访问。 如果一个应用的对话中存在任何的现用密码或对象搜寻操作,而且接着该应用成功执行了C_Login ,那么那些操作可能是也可能不再是现用操作了。因此,在注册前应该结束任何现用操作。 如果调用C_Login 的应用有一个带令牌的R/O对话是打开的,那么它将不能把SO注册进对话(见节)。这种尝试将产生错误码CKR_SESSION_READ_ONLY_EXISTS。 返回值:CKR_ARGUMENTS_BAD, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_PIN_INCORRECT, CKR_PIN_LOCKED, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_SESSION_READ_ONLY_EXISTS, CKR_USER_ALREADY_LOGGED_IN, CKR_USER_ANOTHER_ALREADY_LOGGED_IN, CKR_USER_PIN_NOT_INITIALIZED, CKR_USER_TOO_MANY_TYPES, CKR_USER_TYPE_INVALID. 实例:参见 C_Logout. C_Logout CK_DEFINE_FUNCTION(CK_RV, C_Logout)( CK_SESSION_HANDLE hSession ); C_Logout 将用户从令牌中注销。hSession 是对话的句柄。 如果调用成功,应用的每个对话根据当前的用户类型或者进入“R/W公共对话”状态,或者进入“R/O公共对话”状态。 当C_Logout 成功执行后,专用对象的任何应用的句柄就都无效了(即使用户以后又返回注册到令牌,那些应用仍然是无效的)。另外,属于应用的对话的所有专用对话对象都被破坏。 如果应用的对话中有任何现用的密码或对象搜寻的操作,而且接着该应用成功执行C_Logout ,那么那些操作有可能也可能不再是现用的。因此,注销前应当结束任何现用的操作。 返回值:CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_USER_NOT_LOGGED_IN. 实例: CK_SESSION_HANDLE hSession; CK_CHAR userPIN[] = {“MyPIN”}; CK_RV rv; rv = C_Login(hSession, CKU_USER, userPIN, sizeof(userPIN)); if (rv == CKR_OK) { . . . rv == C_Logout(hSession); if (rv == CKR_OK) { . . . } } 11.7 对象管理函数 Cryptoki 提供了下列管理对象的函数。特别为管理密钥对象提供的附加的函数参见节。 C_CreateObject CK_DEFINE_FUNCTION(CK_RV, C_CreateObject)( CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject ); C_CreateObject 创建了一个新的对象。hSession 是对话的句柄;pTemplate 指向对象的模板;ulCount 是模板中的属性数;phObject 指向接收新对象句柄的单元。 如果调用C_CreateObject 不能支持提供给它的精确的模板,将不能创建任何对象,失败而返回。 如果用C_CreateObject 来创建一个密钥对象,那么密钥对象的CKA_LOCAL 属性应设置成FALSE。 在只读对话中只能创建对话对象。能创建公共对象, 除非普通用户注册了。 返回值:CKR_ATTRIBUTE_READ_ONLY, CKR_ATTRIBUTE_TYPE_INVALID, CKR_ATTRIBUTE_VALUE_INVALID, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_SESSION_READ_ONLY, CKR_TEMPLATE_INCOMPLETE, CKR_TEMPLATE_INCONSISTENT, CKR_TOKEN_WRITE_PROTECTED, CKR_USER_NOT_LOGGED_IN, CKR_ARGUMENTS_BAD, CKR_PIN_EXPIRED. 实例: CK_SESSION_HANDLE hSession; CK_OBJECT_HANDLE hData, hCertificate, hKey; CK_OBJECT_CLASS dataClass = CKO_DATA, certificateClass = CKO_CERTIFICATE, keyClass = CKO_PUBLIC_KEY; CK_KEY_TYPE keyType = CKK_RSA; CK_CHAR application[] = {“My Application”}; CK_BYTE dataValue[] = {...}; CK_BYTE subject[] = {...}; CK_BYTE id[] = {...}; CK_BYTE certificateValue[] = {...}; CK_BYTE modulus[] = {...}; CK_BYTE exponent[] = {...}; CK_BYTE true = TRUE; CK_ATTRIBUTE dataTemplate[] = { {CKA_CLASS, &dataClass, sizeof(dataClass)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_APPLICATION, application, sizeof(application)}, {CKA_VALUE, dataValue, sizeof(dataValue)} }; CK_ATTRIBUTE certificateTemplate[] = { {CKA_CLASS, &certificateClass, sizeof(certificateClass)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_SUBJECT, subject, sizeof(subject)}, {CKA_ID, id, sizeof(id)}, {CKA_VALUE, certificateValue, sizeof(certificateValue)} }; CK_ATTRIBUTE keyTemplate[] = { {CKA_CLASS, &keyClass, sizeof(keyClass)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_WRAP, &true, sizeof(true)}, {CKA_MODULUS, modulus, sizeof(modulus)}, {CKA_PUBLIC_EXPONENT, exponent, sizeof(exponent)} }; CK_RV rv; . . . /* Create a data object */ rv = C_CreateObject(hSession, &dataTemplate, 4, &hData); if (rv == CKR_OK) { . . . } /* Create a certificate object */ rv = C_CreateObject( hSession, &certificateTemplate, 5, &hCertificate); if (rv == CKR_OK) { . . . } /* Create an RSA public key object */ rv = C_CreateObject(hSession, &keyTemplate, 5, &hKey); if (rv == CKR_OK) { . . . } C_CopyObject CK_DEFINE_FUNCTION(CK_RV, C_CopyObject)( CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phNewObject ); C_CopyObject 拷贝一个对象,为拷贝创建一个新的对象。hSession 是对话的句柄; hObject 是对象的句柄;pTemplate 指向新对象的模板;ulCount 是模板中的属性数;phNewObject 指向接收对象拷贝的句柄。 模板能确定通常能修改的对象的任何属性的新的值(例如,在拷贝一个保密密钥的过程中,密钥的CKA_EXTRACTABLE属性可能从TRUE转变成FAULSE,但反之不行)。如果已经进行了变化,那么新密钥的CKA_NEVER_EXTRACTABLE 属性将有值FALSE。 类似地,模板可能会确定新密钥的 CKA_SENSITIVE 属性为TRUE;新密钥将有和原始密钥同样的CKA_ALWAYS_SENSITIVE 属性的值。它可能也指定CKA_TOKEN 和 CKA_PRIVATE 属性新的值(例如,将对话对象拷贝到令牌对象)。如果模板指定一个与其它现有对象的属性不兼容的属性的值,那么调用失败,返回编码CKR_TEMPLATE_INCONSISTENT。 如果调用C_CopyObject 不能支持提供给它的精确模板,那么不能创建任何对象,将失败并返回。 只有在只读对话过程中创建对话对象。只能创建公共对象,除非普通用户注册。 返回值:CKR_ATTRIBUTE_READ_ONLY, CKR_ATTRIBUTE_TYPE_INVALID, CKR_ATTRIBUTE_VALUE_INVALID, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OBJECT_HANDLE_INVALID, CKR_OK, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_SESSION_READ_ONLY, CKR_TEMPLATE_INCONSISTENT, CKR_TOKEN_WRITE_PROTECTED, CKR_USER_NOT_LOGGED_IN, CKR_ARGUMENTS_BAD, CKR_PIN_EXPIRED. 实例: CK_SESSION_HANDLE hSession; CK_OBJECT_HANDLE hKey, hNewKey; CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_DES; CK_BYTE id[] = {...}; CK_BYTE keyValue[] = {...}; CK_BYTE false = FALSE; CK_BYTE true = TRUE; CK_ATTRIBUTE keyTemplate[] = { {CKA_CLASS, &keyClass, sizeof(keyClass)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_TOKEN, &false, sizeof(false)}, {CKA_ID, id, sizeof(id)}, {CKA_VALUE, keyValue, sizeof(keyValue)} }; CK_ATTRIBUTE copyTemplate[] = { {CKA_TOKEN, &true, sizeof(true)} }; CK_RV rv; . . . /* Create a DES secret key session object */ rv = C_CreateObject(hSession, &keyTemplate, 5, &hKey); if (rv == CKR_OK) { /* Create a copy which is a token object */ rv = C_CopyObject(hSession, hKey, ©Template, 1, &hNewKey); . . . } C_DestroyObject CK_DEFINE_FUNCTION(CK_RV, C_DestroyObject)( CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject ); C_DestroyObject 破坏一个对象。 hSession 是对话的句柄;hObject 是对象的句柄。 只能在只读对话过程中破坏对话对象。 只能破坏公共对象,除非注册了普通用户。 返回值:CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OBJECT_HANDLE_INVALID, CKR_OK, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_SESSION_READ_ONLY, CKR_TOKEN_WRITE_PROTECTED, CKR_PIN_EXPIRED. 实例:参见C_GetObjectSize。 C_GetObjectSize CK_DEFINE_FUNCTION(CK_RV, C_GetObjectSize)( CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ULONG_PTR pulSize ); C_GetObjectSize 获得对象字节的大小。hSession 是对话的句柄;hObject 是对象的句柄; pulSize 指向接收对象字节大小的单元。 Cryptoki 没有规定对象大小的精确意义。直觉上,它是对象所占令牌内存大小的某种量度。如果一个应用删除大小为S的专用对象,那么认定令牌CK_TOKEN_INFO 结构的ulFreePrivateMemory 字段增加了大约S是合理的。 返回值:CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_INFORMATION_SENSITIVE, CKR_OBJECT_HANDLE_INVALID, CKR_OK, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_ARGUMENTS_BAD. 实例: CK_SESSION_HANDLE hSession; CK_OBJECT_HANDLE hObject; CK_OBJECT_CLASS dataClass = CKO_DATA; CK_CHAR application[] = {“My Application”}; CK_BYTE dataValue[] = {...}; CK_BYTE value[] = {...}; CK_BYTE true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &dataClass, sizeof(dataClass)}, {CKA_TOKEN, &true, sizeof(true)}, {CKA_APPLICATION, application, sizeof(application)}, {CKA_VALUE, value, sizeof(value)} }; CK_ULONG ulSize; CK_RV rv; . . . rv = C_CreateObject(hSession, &template, 4, &hObject); if (rv == CKR_OK) { rv = C_GetObjectSize(hSession, hObject, &ulSize); if (rv != CKR_INFORMATION_SENSITIVE) { . . . } rv = C_DestroyObject(hSession, hObject); . . . } C_GetAttributeValue CK_DEFINE_FUNCTION(CK_RV, C_GetAttributeValue)( CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount ); C_GetAttributeValue 获得对象的一个或多个属性值。hSession 是对话的句柄;hObject 是对象的句柄;pTemplate 指向规定即将获得的属性值的模板,并接收属性值;pulCount 是模板中的属性数。 对于模板中的每个三元组(type, pValue, ulValueLen),C_GetAttributeValue 执行以下的算法: 1. 如果由于对象敏感或不可抽取因而不能透露对象的规定属性(即type字段规定的属性)的话,那么该三元组中的ulValueLen 字段被修改,包含的值-1(即当投向CK_LONG时,包含值-1)。 2. 否则,如果对象的规定属性无效(对象没有这种属性),那么该三元组中的ulValueLen 字段被修改,包含的值-1。 3. 否则,如果pValue 字段的值为NULL_PTR, 那么ulValueLen 字段被修改,包含的是对象指定属性的实际长度。 4. 否则,如果ulValueLen 中规定的长度足够长,能包含对象指定属性的值,那么属性就被拷贝到pValue中的缓冲器里,ulValueLen 字段被修改,包含属性的实际长度。 5. 否则,ulValueLen 字段被修改,包含的饿值-1。 如果情况1应用于任何请求的属性,那么调用返回CKR_ATTRIBUTE_SENSITIVE值。如果情况2应用于任何请求的属性,那么调用返回CKR_ATTRIBUTE_TYPE_INVALID值。如果情况5应用于任何请求的属性,那么调用返回CKR_BUFFER_TOO_SMALL值。通常,如果这些错误码中的不止一个能用, Cryptoki 可能返回其中的任意一个。只有如果没有一个能适用于请求的属性时才返回CKR_OK。 注意,错误码CKR_ATTRIBUTE_SENSITIVE,CKR_ATTRIBUTE_TYPE_INVALID,和 CKR_BUFFER_TOO_SMALL 并不指出C_GetAttributeValue的真实错误。如果调用 C_GetAttributeValue 返回这三个值中的任意一个,那么调用必须无论如何要已经处理过提供给C_GetAttributeValue 的模板中的每个属性。值能够通过调用C_GetAttributeValue 返回的模板的属性将通过调用C_GetAttributeValue 来返回。 返回值:CKR_ATTRIBUTE_SENSITIVE, CKR_ATTRIBUTE_TYPE_INVALID, CKR_BUFFER_TOO_SMALL, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OBJECT_HANDLE_INVALID, CKR_OK, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_ARGUMENTS_BAD. 实例: CK_SESSION_HANDLE hSession; CK_OBJECT_HANDLE hObject; CK_BYTE_PTR pModulus, pExponent; CK_ATTRIBUTE template[] = { {CKA_MODULUS, NULL_PTR, 0}, {CKA_PUBLIC_EXPONENT, NULL_PTR, 0} }; CK_RV rv; . . . rv = C_GetAttributeValue(hSession, hObject, &template, 2); if (rv == CKR_OK) { pModulus = (CK_BYTE_PTR) malloc(template[0].ulValueLen); template[0].pValue = pModulus; /* template[0].ulValueLen was set by C_GetAttributeValue */ pExponent = (CK_BYTE_PTR) malloc(template[1].ulValueLen); template[1].pValue = pExponent; /* template[1].ulValueLen was set by C_GetAttributeValue */ rv = C_GetAttributeValue(hSession, hObject, &template, 2); if (rv == CKR_OK) { . . . } free(pModulus); free(pExponent); } C_SetAttributeValue CK_DEFINE_FUNCTION(CK_RV, C_SetAttributeValue)( CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount ); C_SetAttributeValue 修改对象一个或多个属性的值。hSession 是对话的句柄; hObject 是对象的句柄;pTemplate 指向规定要被修改的属性值及其新值的模板;ulCount 是模板中的属性数。 只读对话过程中,只能修改对话对象。 模板能够指定能被修改的对象的任何属性的新值。如果模板指定的属性的新值与其它对象现有的属性不兼容,则调用失败,返回编码CKR_TEMPLATE_INCONSISTENT。 并不是所有的属性都能被修改;详情参见节。 返回值:CKR_ATTRIBUTE_READ_ONLY, CKR_ATTRIBUTE_TYPE_INVALID, CKR_ATTRIBUTE_VALUE_INVALID, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OBJECT_HANDLE_INVALID, CKR_OK, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_SESSION_READ_ONLY, CKR_TEMPLATE_INCONSISTENT, CKR_TOKEN_WRITE_PROTECTED, CKR_ARGUMENTS_BAD, CKR_USER_NOT_LOGGED_IN. 实例: CK_SESSION_HANDLE hSession; CK_OBJECT_HANDLE hObject; CK_UTF8CHAR label[] = {“New label”}; CK_ATTRIBUTE template[] = { CKA_LABEL, label, sizeof(label)-1 }; CK_RV rv; . . . rv = C_SetAttributeValue(hSession, hObject, &template, 1); if (rv == CKR_OK) { . . . } C_FindObjectsInit CK_DEFINE_FUNCTION(CK_RV, C_FindObjectsInit)( CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount ); C_FindObjectsInit 启动对匹配模板的令牌和对话对象的搜寻。hSession 是对话的句柄; pTemplate 指向确定要匹配的属性值的搜寻模板;ulCount 是搜寻模板中的属性数。匹配标准是与模板中所有属性精确的逐字节的匹配。为了找到所有的目标,将ulCount 设置为0。 调用C_FindObjectsInit后,应用可能一次或多次调用C_FindObjects 以获得匹配模板的对象的句柄,接着最终调用C_FindObjectsFinal 来结束现用的搜寻操作。在一个给定的对话中一次至多有一个搜寻操作是现用的。 目标搜寻只能发现对话能看见的对象。比如,“R/W公共对话”中的对象搜寻不能发现任何专用对象(即使搜寻模块中的一个属性指定该搜寻用于专用对象)。 如果搜寻操作是现用的,而且为现用搜寻操作创建或破坏适合搜寻模板的目标,那么,这些对象有可能也可能不被搜寻操作发现。要指出的是,这意味着在这些情况下,搜寻操作可能返回无效的对象句柄。 尽管C_FindObjectsInit能够返回值CKR_ATTRIBUTE_TYPE_INVALID和CKR_ATTRIBUTE_VALUE_INVALID,但没有必要。比如,如果给定一个其中含不存在的属性的搜寻模板,就会返回CKR_ATTRIBUTE_TYPE_INVALID,或者返回CKR_OK并启动一次不会匹配任何对象的搜寻操作,并返回CKR_OK。 返回值:CKR_ATTRIBUTE_TYPE_INVALID, CKR_ATTRIBUTE_VALUE_INVALID, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_OPERATION_ACTIVE, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_ARGUMENTS_BAD, CKR_PIN_EXPIRED. 实例:参见C_FindObjectsFinal. C_FindObjects CK_DEFINE_FUNCTION(CK_RV, C_FindObjects)( CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount ); C_FindObjects继续搜寻匹配模板的令牌和对话对象,获得附加的对象句柄。hSession 是对话句柄;phObject 指向接收附加对象句柄列表(阵列)的单元;ulMaxObjectCount是要返回的对象句柄的最大数;pulObjectCount指向接收实际返回对象句柄数的单元。 如果已没有匹配模板的对象了的话,那么pulObjectCount 所指的单元接收值0。 搜寻必须是用C_FindObjectsInit 启动了的。 返回值: CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_OPERATION_NOT_INITIALIZED, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_ARGUMENTS_BAD. 实例:参见C_FindObjectsFinal。 C_FindObjectsFinal CK_DEFINE_FUNCTION(CK_RV, C_FindObjectsFinal)( CK_SESSION_HANDLE hSession ); C_FindObjectsFinal 结束搜寻令牌和对话对象。hSession 是对话的句柄。 返回值:CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_OPERATION_NOT_INITIALIZED, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID. 实例: CK_SESSION_HANDLE hSession; CK_OBJECT_HANDLE hObject; CK_ULONG ulObjectCount; CK_RV rv; . . . rv = C_FindObjectsInit(hSession, NULL_PTR, 0); assert(rv == CKR_OK); while (1) { rv = C_FindObjects(hSession, &hObject, 1, &ulObjectCount); if (rv != CKR_OK || ulObjectCount == 0) break; . . . } rv = C_FindObjectsFinal(hSession); assert(rv == CKR_OK); 11.8 加密函数 Cryptoki 为加密数据提供了以下的函数: C_EncryptInit CK_DEFINE_FUNCTION(CK_RV, C_EncryptInit)( CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey ); C_EncryptInit 初始化一个加密操作。hSession 是对话的句柄;pMechanism 指向加密机制; hKey 是加密密钥的句柄。 加密密钥的CKA_ENCRYPT 属性——说明密钥是否支持加密——必须为TRUE。 调用C_EncryptInit 后,应用或者调用C_Encrypt 来加密单一部分数据;或者0次或多次调用C_EncryptUpdate,接着调用C_EncryptFinal来加密多部分的数据。加密操作是现用的,一直持续到应用调用C_Encrypt或C_EncryptFinal确实获得密文的最后一条。若要处理附加数据(单部分或多部分),应用程序必须再次调用C_EncryptInit。 返回值:CKR_CRYPTOKI_NOT_INITIALIZED,CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_KEY_FUNCTION_NOT_PERMITTED, CKR_KEY_HANDLE_INVALID, CKR_KEY_SIZE_RANGE, CKR_KEY_TYPE_INCONSISTENT, CKR_MECHANISM_INVALID, CKR_MECHANISM_PARAM_INVALID, CKR_OK, CKR_OPERATION_ACTIVE, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_USER_NOT_LOGGED_IN, CKR_PIN_EXPIRED. 实例:参见C_EncryptFinal. C_Encrypt CK_DEFINE_FUNCTION(CK_RV, C_Encrypt)( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen ); C_Encrypt加密单部分数据。HSession是对话句柄;pData指向数据;ulDataLen是数据字节的长度;pEncryptedData指向接收加密数据的单元;pulEncryptedDatedLen指向包含加密数据字节长度的单元。 C_Encrypt采用11.2节中有关制造输出部分所述的惯例。 加密操作操作必须以C_EncryptInit预置。除非返回CKR_BUFFER_TOO_SMALL 或这是一次成功的调用(如返回CKR_OK)能确定包含密文所需缓冲器的长度,否则调用C_Encrypt 总是会终止现用的加密操作。 不能用C_Encrypt来结束一次多部分操作,必须在不插入C_EncryptUpdate调用的情况下在C_EncryptInit之后调用。 对某些加密机制来说,输入平文数据有特定的长度限制(或者是因为机制只能加密相对短的平文,或者因为输入数据的机制必须由几个块集合构成。)如果不能满足这些限制要求,C_Encrypt 失败,返回码CKR_DATA_LEN_RANGE 。 平文和密文可以位于同一位置,比如,如果pData 和pEncryptedData 指向同一单元也可以。 对于大部分机制,C_Encrypt 相当于一串C_EncryptUpdate 操作后面跟着_EncryptFinal。 返回值:CKR_BUFFER_TOO_SMALL, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DATA_INVALID, CKR_DATA_LEN_RANGE, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_OPERATION_NOT_INITIALIZED, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_ARGUMENTS_BAD. 实例:类似函数参见C_EncryptFinal 。 C_EncryptUpdate CK_DEFINE_FUNCTION(CK_RV, C_EncryptUpdate)( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen ); C_EncryptUpdate 继续多部分加密操作,处理另一个数据部分。hSession 是对话句柄;pPart 指向数据部分;ulPartLen是数据部分的长度;pEncryptedPart指向接收加密数据部分的单元;pulEncryptedPartLen指向包含加密数据部分字节长度的单元。 C_EncryptUpdate 采用 中生产输出部分所述的惯例。 加密操作必须用C_EncryptInit 预置。该函数可以连续调用若干次。产生错误而不是CKR_BUFFER_TOO_SMALL 的C_EncryptUpdate 调用会终止当前的加密操作。 加密操作必须用C_EncryptInit 预置。调用C_Encrypt 总是会终止现用的加密操作,除非它返回CKR_BUFFER_TOO_SMALL ,或这是一次成功的调用(即,返回CKR_OK )来确定包含密文所需的缓冲器的长度。 明文和密文 可以位于同一位置,比如,如果pPart 和 pEncryptedPart 指向同一单元是可以的。 返回值:CKR_BUFFER_TOO_SMALL, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DATA_LEN_RANGE, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_OPERATION_NOT_INITIALIZED, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_ARGUMENTS_BAD. 实例:参见C_EncryptFinal. C_EncryptFinal CK_DEFINE_FUNCTION(CK_RV, C_EncryptFinal)( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastEncryptedPart, CK_ULONG_PTR pulLastEncryptedPartLen ); C_EncryptFinal 结束一次多部分加密操作。hSession 是对话句柄;pLastEncryptedPart 指向接收最后一个加密数据部分的单元,如果有的话;pulLastEncryptedPartLen 指向包含最后加密数据部分长度的单元。 C_EncryptFinal 采用节中生产输出部分所述的惯例。 加密操作必须用C_EncryptInit来预置。调用C_EncryptFinal 总是会结束现用的加密操作,除非它返回CKR_BUFFER_TOO_SMALL 或这是一次成功的调用(即,返回CKR_OK )来确定包含密文所需的缓冲器的长度。 对于某些多部分加密机制而言,由于输入数据必须由一些块集合构成,因而输入的平文数据有特定的长度限制。如果不能满足这些限制要求,C_EncryptFinal 就会失败,返回编码CKR_DATA_LEN_RANGE。 返回值:CKR_BUFFER_TOO_SMALL, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DATA_LEN_RANGE, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_OPERATION_NOT_INITIALIZED, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_ARGUMENTS_BAD. 实例: #define PLAINTEXT_BUF_SZ 200 #define CIPHERTEXT_BUF_SZ 256 CK_ULONG firstPieceLen, secondPieceLen; CK_SESSION_HANDLE hSession; CK_OBJECT_HANDLE hKey; CK_BYTE iv[8]; CK_MECHANISM mechanism = { CKM_DES_CBC_PAD, iv, sizeof(iv) }; CK_BYTE data[PLAINTEXT_BUF_SZ]; CK_BYTE encryptedData[CIPHERTEXT_BUF_SZ]; CK_ULONG ulEncryptedData1Len; CK_ULONG ulEncryptedData2Len; CK_ULONG ulEncryptedData3Len; CK_RV rv; . . . firstPieceLen = 90; secondPieceLen = PLAINTEXT_BUF_SZ-firstPieceLen; rv = C_EncryptInit(hSession, &mechanism, hKey); if (rv == CKR_OK) { /* Encrypt first piece */ ulEncryptedData1Len = sizeof(encryptedData); rv = C_EncryptUpdate( hSession, &data[0], firstPieceLen, &encryptedData[0], &ulEncryptedData1Len); if (rv != CKR_OK) { . . . } /* Encrypt second piece */ ulEncryptedData2Len = sizeof(encryptedData)-ulEncryptedData1Len; rv = C_EncryptUpdate( hSession, &data[firstPieceLen], secondPieceLen, &encryptedData[ulEncryptedData1Len], &ulEncryptedData2Len); if (rv != CKR_OK) { . . . } /* Get last little encrypted bit */ ulEncryptedData3Len = sizeof(encryptedData)-ulEncryptedData1Len-ulEncryptedData2Len; rv = C_EncryptFinal( hSession, &encryptedData[ulEncryptedData1Len+ulEncryptedData2Len], &ulEncryptedData3Len); if (rv != CKR_OK) { . . . } } 11.9 解密函数 Cryptoki 为解密数据提供了以下的函数: C_DecryptInit CK_DEFINE_FUNCTION(CK_RV, C_DecryptInit)( CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey ); C_DecryptInit 启动一项加密操作。hSession 是对话句柄;pMechanism 指向解密机制;hKey 是解密密钥的句柄。 解密密钥的CKA_DECRYPT属性,——说明密钥是否支持解密——必须为TRUE。 调用C_DecryptInit 后,应用或者调用C_Decrypt 来解密单部分的数据,或者先调用C_DecryptUpdate 零次或多次,接着调用C_DecryptFinal 来解密多部分中的数据。解密操作是现用的直到应用调用C_Decrypt 或C_DecryptFinal 来确实获得最终的平文。要处理另外的数据(单部分或多部分中),应用必须再次调用C_DecryptInit 。 返回值:CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_KEY_FUNCTION_NOT_PERMITTED, CKR_KEY_HANDLE_INVALID, CKR_KEY_SIZE_RANGE, CKR_KEY_TYPE_INCONSISTENT, CKR_MECHANISM_INVALID, CKR_MECHANISM_PARAM_INVALID, CKR_OK, CKR_OPERATION_ACTIVE, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_USER_NOT_LOGGED_IN, CKR_ARGUMENTS_BAD, CKR_PIN_EXPIRED. 实例:参见C_DecryptFinal. C_Decrypt CK_DEFINE_FUNCTION(CK_RV, C_Decrypt)( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen ); C_Decrypt 解密单部分中的加密数据。hSession 是对话句柄;pEncryptedData 指向加密数据;ulEncryptedDataLen是加密数据的长度;pData 指向接收恢复数据的单元;pulDataLen 指向包含恢复数据长度的单元。 C_Decrypt 采用 中生产输出部分所述的惯例。 解密操作必须用C_DecryptInit 预置。调用C_Decrypt 总是会终止现有的解密操作,除非它返回CKR_BUFFER_TOO_SMALL 或这是一次成功的调用(即,返回CKR_OK)以确定包含平文所需的缓冲器的长度。 不能用C_Decrypt 来结束一次多部分操作,必须在不插入C_DecryptUpdate 调用的情况下在C_DecryptInit 之后调用。 平文和密文可以位于同一位置,即,如果pEncryptedData 和 pData 指向同一单元是可以的。 如果由于输入密文数据由于长度不合适而不能被解密,那么会返回CKR_ENCRYPTED_DATA_INVALID或者CKR_ENCRYPTED_DATA_LEN_RANGE 。 对于大部分的机制,C_Decrypt 相当于一系列C_DecryptUpdate 后面跟着C_DecryptFinal。 返回值:CKR_BUFFER_TOO_SMALL, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_ENCRYPTED_DATA_INVALID, CKR_ENCRYPTED_DATA_LEN_RANGE, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_OPERATION_NOT_INITIALIZED, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_ARGUMENTS_BAD. 实例:类似函数的实例参见 C_DecryptFinal。 C_DecryptUpdate CK_DEFINE_FUNCTION(CK_RV, C_DecryptUpdate)( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen ); C_DecryptUpdate 继续一项多部分的解密操作,处理另一个加密数据部分。hSession 是数据句柄;pEncryptedPart 指向加密数据部分;ulEncryptedPartLen 是加密数据部分的长度;pPart 指向接收恢复数据部分的单元;pulPartLen 指向包含恢复的数据部分的长度。 C_DecryptUpdate 采用中生产输出部分所述的惯例。 解密操作必须用C_DecryptInit 来预置。该函数可以连续调用若干次。如果调用C_DecryptUpdate 产生错误而不是CKR_BUFFER_TOO_SMALL ,那么结束当前的解密操作。 密文和平文可以位于同一位置,即,如果pEncryptedPart 和pPart 指向同一单元是可以的。 返回值:CKR_BUFFER_TOO_SMALL, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_ENCRYPTED_DATA_INVALID, CKR_ENCRYPTED_DATA_LEN_RANGE, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_OPERATION_NOT_INITIALIZED, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_ARGUMENTS_BAD. 实例:参见 C_DecryptFinal。 C_DecryptFinal CK_DEFINE_FUNCTION(CK_RV, C_DecryptFinal)( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastPart, CK_ULONG_PTR pulLastPartLen ); C_DecryptFinal结束多部分解密操作。hSession 是对话句柄;pLastPart 指向接收最终恢复数据部分的单元,如果有的话;pulLastPartLen 指向包含最后恢复的数据部分的长度。 C_DecryptFinal 采用中生产输出部分所述的惯例。 解密操作必须用C_DecryptInit 来预置。调用C_DecryptFinal 总是会终止现用的解密操作,除非它返回CKR_BUFFER_TOO_SMALL,或这是一次成功的调用(即,返回CKR_OK)来确定包含平文所需的缓冲器的长度。 如果由于输入密文数据的长度不适当因而不能被解密,那么会返回CKR_ENCRYPTED_DATA_INVALID 或者CKR_ENCRYPTED_DATA_LEN_RANGE。 返回值:CKR_BUFFER_TOO_SMALL, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_ENCRYPTED_DATA_INVALID, CKR_ENCRYPTED_DATA_LEN_RANGE, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_OPERATION_NOT_INITIALIZED, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_ARGUMENTS_BAD. 实例: #define CIPHERTEXT_BUF_SZ 256 #define PLAINTEXT_BUF_SZ 256 CK_ULONG firstEncryptedPieceLen, secondEncryptedPieceLen; CK_SESSION_HANDLE hSession; CK_OBJECT_HANDLE hKey; CK_BYTE iv[8]; CK_MECHANISM mechanism = { CKM_DES_CBC_PAD, iv, sizeof(iv) }; CK_BYTE data[PLAINTEXT_BUF_SZ]; CK_BYTE encryptedData[CIPHERTEXT_BUF_SZ]; CK_ULONG ulData1Len, ulData2Len, ulData3Len; CK_RV rv; . . . firstEncryptedPieceLen = 90; secondEncryptedPieceLen = CIPHERTEXT_BUF_SZ-firstEncryptedPieceLen; rv = C_DecryptInit(hSession, &mechanism, hKey); if (rv == CKR_OK) { /* Decrypt first piece */ ulData1Len = sizeof(data); rv = C_DecryptUpdate( hSession, &encryptedData[0], firstEncryptedPieceLen, &data[0], &ulData1Len); if (rv != CKR_OK) { . . . } /* Decrypt second piece */ ulData2Len = sizeof(data)-ulData1Len; rv = C_DecryptUpdate( hSession, &encryptedData[firstEncryptedPieceLen], secondEncryptedPieceLen, &data[ulData1Len], &ulData2Len); if (rv != CKR_OK) { . . . } /* Get last little decrypted bit */ ulData3Len = sizeof(data)-ulData1Len-ulData2Len; rv = C_DecryptFinal( hSession, &data[ulData1Len+ulData2Len], &ulData3Len); if (rv != CKR_OK) { . . . } } 11.10 消息摘要函数 Cryptoki 为摘要数据提供了以下的函数: C_DigestInit CK_DEFINE_FUNCTION(CK_RV, C_DigestInit)( CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism ); C_DigestInit预置消息摘要操作。hSession 是对话句柄;pMechanism 指向摘要机制。 调用C_DigestInit 后,应用可以调用C_Digest 摘要单部分中的数据,或者先调用C_DigestUpdate 零次或多次,接着调用C_DigestFinal 来摘要多部分中的数据。消息摘要操作是现用的,直到应用调用C_Digest 或C_DigestFinal 确实获得最后的密文。要处理另外的数据(单部分或多部分),应用必须再次调用C_DigestInit 。 返回值:CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_MECHANISM_INVALID, CKR_MECHANISM_PARAM_INVALID, CKR_OK, CKR_OPERATION_ACTIVE, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_USER_NOT_LOGGED_IN, CKR_ARGUMENTS_BAD, CKR_PIN_EXPIRED. 实例:参见C_DigestFinal. C_Digest CK_DEFINE_FUNCTION(CK_RV, C_Digest)( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen ); C_Digest 摘要单部分中的数据。hSession 是对话句柄,pData指向数据;ulDataLen 是数据的长度;pDigest 指向接收消息摘要的单元;pulDigestLen 指向包含消息摘要长度的单元。 C_Digest 采用节中生产输出部分所述的惯例。 摘要操作必须用C_DigestInit 来预置。调用C_Digest 总是会终止现用的摘要操作,除非它返回CKR_BUFFER_TOO_SMALL ,或这是一次成功的调用(即,返回CKR_OK)来确定包含消息摘要所需的缓冲器的长度。 不能用C_Digest来结束一个多部分操作,必须在不插入C_DigestUpdate调用的情况下在C_DigestInit之后调用。 输入数据和摘要输出可以位于同一位置,即,如果pData 和 pDigest 指向同一单元是可以的。 C_Digest 相当于一系列C_DigestUpdate 操作后面跟着C_DigestFinal 。 返回值:CKR_BUFFER_TOO_SMALL, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_OPERATION_NOT_INITIALIZED, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_ARGUMENTS_BAD. 实例:类似函数实例参见C_DigestFinal 。 C_DigestUpdate CK_DEFINE_FUNCTION(CK_RV, C_DigestUpdate)( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen ); C_DigestUpdate 继续多部分消息摘要操作,处理另一个数据部分。hSession 是对话句柄;pPart 指向数据部分;ulPartLen 是数据部分的长度。 消息摘要操作必须以C_DigestInit预置。可以以任何顺序若干次交替调用该函数和C_DigestKey 。调用C_DigestUpdate 产生错误时会终止目前的摘要操作。 返回值:CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_OPERATION_NOT_INITIALIZED, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_ARGUMENTS_BAD. 实例:参见C_DigestFinal. C_DigestKey CK_DEFINE_FUNCTION(CK_RV, C_DigestKey)( CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey ); C_DigestKey 摘要保密密钥值,继续多部分消息摘要的操作。hSession 是对话句柄;hKey 是要被摘要的保密密钥的句柄。 消息摘要操作必须用C_DigestInit预置。可以以任何顺序若干次交替调用该函数和C_DigestUpdate 。 如果提供的密钥值仅仅因为和长度有关的某些原因而不能被摘要,那么,C_DigestKey 应该返回错误码CKR_KEY_SIZE_RANGE 。 返回值:CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_KEY_HANDLE_INVALID, CKR_KEY_INDIGESTIBLE, CKR_KEY_SIZE_RANGE, CKR_OK, CKR_OPERATION_NOT_INITIALIZED, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID. 实例:参见C_DigestFinal. C_DigestFinal CK_DEFINE_FUNCTION(CK_RV, C_DigestFinal)( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen ); C_DigestFinal 结束多部分消息摘要操作,返回消息摘要。hSession 是对话句柄;pDigest 指向接收消息摘要的单元;pulDigestLen 指向包含消息摘要长度的单元。 C_DigestFinal 采用 节中生产输出部分所述的惯例。 摘要操作必须用C_DigestInit 预置。调用C_DigestFinal 总是会终止现用的摘要操作,除非它返回CKR_BUFFER_TOO_SMALL ,或这是一次成功的调用(即,返回CKR_OK)来确定包含消息摘要所需的缓冲器的长度。 返回值:CKR_BUFFER_TOO_SMALL, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_OPERATION_NOT_INITIALIZED, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_ARGUMENTS_BAD. 实例: CK_SESSION_HANDLE hSession; CK_MECHANISM mechanism = { CKM_MD5, NULL_PTR, 0 }; CK_BYTE data[] = {...}; CK_BYTE digest[16]; CK_ULONG ulDigestLen; CK_RV rv; . . . rv = C_DigestInit(hSession, &mechanism); if (rv != CKR_OK) { . . . } rv = C_DigestUpdate(hSession, data, sizeof(data)); if (rv != CKR_OK) { . . . } rv = C_DigestKey(hSession, hKey); if (rv != CKR_OK) { . . . } ulDigestLen = sizeof(digest); rv = C_DigestFinal(hSession, digest, &ulDigestLen); . . . 11.11 签名和 MACing函数 Cryptoki 提供以下的签名函数(为了Cryptoki ,这些操作也包含消息验证码)。 C_SignInit CK_DEFINE_FUNCTION(CK_RV, C_SignInit)( CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey ); C_SignInit 预置签名操作,其中签名是数据的附录。hSession 是对话的句柄;pMechanism 指向签名机制;hKey 是签名密钥的句柄。 签名密钥的CKA_SIGN 属性——说明密钥是否支持带附录的签名——必须为TRUE。 调用C_SignInit后,应用或者调用C_Sign 在单部分中签名,或者先调用C_SignUpdate 零次或多次,接着调用C_SignFinal,给多部分中的数据签名。签名操作是现用的,直到应用调用C_Sign 或C_SignFinal 确实获得签名。要处理另外的数据(单部分或多部分),应用必须再次调用C_SignInit 。 返回值:CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_KEY_FUNCTION_NOT_PERMITTED,CKR_KEY_HANDLE_INVALID, CKR_KEY_SIZE_RANGE, CKR_KEY_TYPE_INCONSISTENT, CKR_MECHANISM_INVALID, CKR_MECHANISM_PARAM_INVALID, CKR_OK, CKR_OPERATION_ACTIVE, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_USER_NOT_LOGGED_IN, CKR_ARGUMENTS_BAD, CKR_PIN_EXPIRED. 实例:参见C_SignFinal. C_Sign CK_DEFINE_FUNCTION(CK_RV, C_Sign)( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen ); C_Sign 给单部分中的数据签名,其中签名是数据的附录。hSession 是对话句柄;pData 指向数据;ulDataLen 是数据长度;pSignature 指向接收签名的单元;pulSignatureLen 指向包含签名长度的单元。 C_Sign 采用节中生产输出部分所述的惯例。 签名操作必须用C_SignInit预置。调用C_Sign 总是会结束现用的签名操作,除非它返回CKR_BUFFER_TOO_SMALL 或这是一次成功的调用(即,返回CKR_OK)来确定包含签名所需的缓冲器的长度。 不能使用C_Sign来结束多部分操作,必须在不插入C_SignUpdate的情况下在C_SignInit之后调用。 对于大部分机制,C_Sign 相当于一系列C_SignUpdate 操作后面跟着C_SignFinal。 返回值:CKR_BUFFER_TOO_SMALL, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DATA_INVALID, CKR_DATA_LEN_RANGE, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_OPERATION_NOT_INITIALIZED, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_ARGUMENTS_BAD. 实例:类似函数实例参见 C_SignFinal。 C_SignUpdate CK_DEFINE_FUNCTION(CK_RV, C_SignUpdate)( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen ); C_SignUpdate 继续多部分签名操作,处理另一个数据部分。hSession 是对话句柄;pPart 指向数据部分;ulPartLen 是数据部分的长度。 签名操作必须用C_SignInit预置。这一函数可以连续调用若干次。调用C_SignUpdate 产生错误时终止当前的签名操作。 返回值:CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DATA_LEN_RANGE, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_OPERATION_NOT_INITIALIZED, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_ARGUMENTS_BAD. 实例:参见 C_SignFinal. C_SignFinal CK_DEFINE_FUNCTION(CK_RV, C_SignFinal)( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen ); C_SignFinal 结束多部分签名操作,返回签名。hSession 是对话句柄;pSignature 指向接收签名的单元;pulSignatureLen 指向包含签名长度的单元。 C_SignFinal 采用节中生产输出部分所述的惯例。 签名操作必须用C_SignInit预置。调用C_SignFinal 总是会结束现用的签名操作,除非它返回CKR_BUFFER_TOO_SMALL 或这是一次成功的调用(即,返回CKR_OK )来确定包含签名所需的缓冲器的长度。 返回值:CKR_BUFFER_TOO_SMALL, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DATA_LEN_RANGE, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_OPERATION_NOT_INITIALIZED, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_ARGUMENTS_BAD. 实例: CK_SESSION_HANDLE hSession; CK_OBJECT_HANDLE hKey; CK_MECHANISM mechanism = { CKM_DES_MAC, NULL_PTR, 0 }; CK_BYTE data[] = {...}; CK_BYTE mac[4]; CK_ULONG ulMacLen; CK_RV rv; . . . rv = C_SignInit(hSession, &mechanism, hKey); if (rv == CKR_OK) { rv = C_SignUpdate(hSession, data, sizeof(data)); . . . ulMacLen = sizeof(mac); rv = C_SignFinal(hSession, mac, &ulMacLen); . . . } C_SignRecoverInit CK_DEFINE_FUNCTION(CK_RV, C_SignRecoverInit)( CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey ); C_SignRecoverInit 预置签名操作,其中数据能从签名中恢复。hSession 是对话句柄;pMechanism 指向规定签名机制的结构;hKey 是签名密钥的句柄。 签名密钥的CKA_SIGN_RECOVER 属性——说明密钥是否支持那些数据能够从中恢复的签名)——必须为TRUE。 调用C_SignRecoverInit 后,应用可以调用C_SignRecover 在单部分中签名。签名操作是现用的,直到应用调用C_SignRecover 来确实获得签名。要处理单部分中另外的数据,应用必须再次调用C_SignRecoverInit 。 返回值:CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_KEY_FUNCTION_NOT_PERMITTED, CKR_KEY_HANDLE_INVALID, CKR_KEY_SIZE_RANGE, CKR_KEY_TYPE_INCONSISTENT, CKR_MECHANISM_INVALID, CKR_MECHANISM_PARAM_INVALID, CKR_OK, CKR_OPERATION_ACTIVE, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_USER_NOT_LOGGED_IN, CKR_ARGUMENTS_BAD, CKR_PIN_EXPIRED. 实例:参见C_SignRecover. C_SignRecover CK_DEFINE_FUNCTION(CK_RV, C_SignRecover)( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen ); C_SignRecover 给单一操作中的数据签名,其中数据可以签名中恢复。hSession 是对话句柄;pData 指向数据;uLDataLen 是数据的长度;pSignature 指向接收签名的单元;pulSignatureLen 指向包含签名长度的单元。 C_SignRecover 采用中生产输出部分所述的惯例。 签名操作必须用C_SignRecoverInit 启动。调用C_SignRecover 总是会结束现用的签名操作,除非它返回CKR_BUFFER_TOO_SMALL 或这是一次成功的调用(即,返回CKR_OK )来确定包含签名所需的缓冲器的长度。 返回值:CKR_BUFFER_TOO_SMALL, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DATA_INVALID, CKR_DATA_LEN_RANGE, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_OPERATION_NOT_INITIALIZED, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_ARGUMENTS_BAD. 实例: CK_SESSION_HANDLE hSession; CK_OBJECT_HANDLE hKey; CK_MECHANISM mechanism = { CKM_RSA_9796, NULL_PTR, 0 }; CK_BYTE data[] = {...}; CK_BYTE signature[128]; CK_ULONG ulSignatureLen; CK_RV rv; . . . rv = C_SignRecoverInit(hSession, &mechanism, hKey); if (rv == CKR_OK) { ulSignatureLen = sizeof(signature); rv = C_SignRecover( hSession, data, sizeof(data), signature, &ulSignatureLen); if (rv == CKR_OK) { . . . } } 11.12 校验签名和MACs的函数 Cryptoki Cryptoki提供了以下的数据校验签名功能(为了Cryptoki,这些操作也包括消息验证码)。 C_VerifyInit CK_DEFINE_FUNCTION(CK_RV, C_VerifyInit)( CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey ); C_VerifyInit 预置校验操作,其中签名是数据的附录。hSession 是对话句柄;pMechanism 指向确定校验机制的结构;hKey 是校验密码的句柄。 校验密码的CKA_VERIFY 属性——说明密钥是否支持那些其中签名是数据的附录的校验——必须为TRUE。 调用C_VerifyInit 后,应用或者调用C_Verify 来校验单部分中数据的签名,或者先调用C_VerifyUpdate 一次或多次,接着调用C_VerifyFinal ,来校验多部分中数据的签名。校验操作是现用的,直到应用调用C_Verify 或 C_VerifyFinal。要处理另外的数据(单部分或者多部分),应用程序必须再次调用C_VerifyInit 。 返回值:CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_KEY_FUNCTION_NOT_PERMITTED, CKR_KEY_HANDLE_INVALID, CKR_KEY_SIZE_RANGE, CKR_KEY_TYPE_INCONSISTENT, CKR_MECHANISM_INVALID, CKR_MECHANISM_PARAM_INVALID, CKR_OK, CKR_OPERATION_ACTIVE, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_USER_NOT_LOGGED_IN, CKR_ARGUMENTS_BAD, CKR_PIN_EXPIRED. 实例:参见C_VerifyFinal。 C_Verify CK_DEFINE_FUNCTION(CK_RV, C_Verify)( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen ); C_Verify 校验单部分操作中的签名,其中签名是数据的附录。hSession 是对话句柄;pData 指向数据;ulDataLen 是数据的长度;pSignature 指向签名;ulSignatureLen 是签名的长度。 校验操作必须用C_VerifyInit 预置。调用C_Verify 总是会终止现用的校验操作。 成功的调用C_Verify 应该或者返回CKR_OK值(表明提供的签名是有效的),或者返回CKR_SIGNATURE_INVALID值(表明提供的签名是无效的)。如果签名单纯由于长度的原因而被看成无效,那么应该返回CKR_SIGNATURE_LEN_RANGE。在上述任何一种情况下,现用签名操作都被终止。 不能使用C_Verify来结束一个多部分操作,必须在不插入C_VerifyUpdate调用的情况下在C_VerifyInit 之后调用。 在大部分机制下,C_Verify 相当于一系列C_VerifyUpdate 操作后面跟着C_VerifyFinal。 返回值:CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DATA_INVALID, CKR_DATA_LEN_RANGE, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_OPERATION_NOT_INITIALIZED, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_SIGNATURE_INVALID, CKR_SIGNATURE_LEN_RANGE, CKR_ARGUMENTS_BAD. 实例:类似函数的实例参见C_VerifyFinal。 C_VerifyUpdate CK_DEFINE_FUNCTION(CK_RV, C_VerifyUpdate)( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen ); C_VerifyUpdate 继续一个多部分的校验操作,处理另一数据部分。hSession 是对话句柄,pPart 指向数据部分;ulPartLen 是数据部分的长度。 校验操作必须是以C_VerifyInit预置的。该函数可以连续调用任意次。调用C_VerifyUpdate 导致错误时会结束当前的校验操作。 返回值:CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DATA_LEN_RANGE, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_OPERATION_NOT_INITIALIZED, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_ARGUMENTS_BAD. 实例:参见C_VerifyFinal. C_VerifyFinal CK_DEFINE_FUNCTION(CK_RV, C_VerifyFinal)( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen ); C_VerifyFinal 结束一次多部分校验操作,核查签名。hSession 是对话句柄;pSignature 指向签字;ulSignatureLen 是签字的长度。 校验操作必须以C_VerifyInit 预置。调用C_VerifyFinal 总是会结束现有的校验操作。 成功的调用C_VerifyFinal 应该或者返回CKR_OK值(表明提供的签字是有效的),或者返回CKR_SIGNATURE_INVALID值(表明提供的签字是无效的)。如果签字单纯由于长度的原因而被看成无效,那么应该返回CKR_SIGNATURE_LEN_RANGE 。在上述任何一种情况下,现用校验操作都会结束。 返回值: CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DATA_LEN_RANGE, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_OPERATION_NOT_INITIALIZED, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_SIGNATURE_INVALID, CKR_SIGNATURE_LEN_RANGE, CKR_ARGUMENTS_BAD. 实例: CK_SESSION_HANDLE hSession; CK_OBJECT_HANDLE hKey; CK_MECHANISM mechanism = { CKM_DES_MAC, NULL_PTR, 0 }; CK_BYTE data[] = {...}; CK_BYTE mac[4]; CK_RV rv; . . . rv = C_VerifyInit(hSession, &mechanism, hKey); if (rv == CKR_OK) { rv = C_VerifyUpdate(hSession, data, sizeof(data)); . . . rv = C_VerifyFinal(hSession, mac, sizeof(mac)); . . . } C_VerifyRecoverInit CK_DEFINE_FUNCTION(CK_RV, C_VerifyRecoverInit)( CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey ); C_VerifyRecoverInit 预置签字校验操作,其中数据从签字恢复。hSession 是对话句柄;pMechanism 指向确定校验机制的结构;hKey 是校验密钥的句柄。 校验密钥CKA_VERIFY_RECOVER 的属性(说明密钥是否支持其中数据从签字恢复的校验)必须为TRUE。 调用C_VerifyRecoverInit 后,应用可以调用C_VerifyRecover 来校验单部分中数据的签字。校验操作是现用的,直到应用调用C_VerifyRecover 来确实获得恢复的消息。 返回值:CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_KEY_FUNCTION_NOT_PERMITTED, CKR_KEY_HANDLE_INVALID, CKR_KEY_SIZE_RANGE, CKR_KEY_TYPE_INCONSISTENT, CKR_MECHANISM_INVALID, CKR_MECHANISM_PARAM_INVALID, CKR_OK, CKR_OPERATION_ACTIVE, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_USER_NOT_LOGGED_IN, CKR_ARGUMENTS_BAD, CKR_PIN_EXPIRED. 实例:参见C_VerifyRecover. C_VerifyRecover CK_DEFINE_FUNCTION(CK_RV, C_VerifyRecover)( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen ); C_VerifyRecover 校验单部分操作中的签字,其中数据从签字中恢复。hSession 是对话句柄;pSignature 指向签字;ulSignatureLen 是签字的长度;pData 指向接收恢复数据的单元;pulDataLen 指向包含恢复数据长度的单元。 C_VerifyRecover 采用中生产输出部分所述的惯例 校验操作必须以C_VerifyRecoverInit 预置。调用C_VerifyRecover 总是会结束现用的校验操作,除非它返回CKR_BUFFER_TOO_SMALL 或这是一次成功的调用(即,返回CKR_OK )来确定包含恢复的数据所需的缓冲器的长度。 成功的调用C_VerifyRecover 应该或者返回值CKR_OK (表明提供的签字是有效的),或者返回值CKR_SIGNATURE_INVALID (表明提供的签字是无效的)。如果签字单纯由于长度的原因而被看成无效,那么应该返回CKR_SIGNATURE_LEN_RANGE 。返回码CKR_SIGNATURE_INVALID 和CKR_SIGNATURE_LEN_RANGE 的优先级比返回码CKR_BUFFER_TOO_SMALL 的高,即,如果提供给C_VerifyRecover 的是无效的签字,则决不会返回CKR_BUFFER_TOO_SMALL。 返回值:CKR_BUFFER_TOO_SMALL, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DATA_INVALID, CKR_DATA_LEN_RANGE, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_OPERATION_NOT_INITIALIZED, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_SIGNATURE_LEN_RANGE, CKR_SIGNATURE_INVALID, CKR_ARGUMENTS_BAD. 实例: CK_SESSION_HANDLE hSession; CK_OBJECT_HANDLE hKey; CK_MECHANISM mechanism = { CKM_RSA_9796, NULL_PTR, 0 }; CK_BYTE data[] = {...}; CK_ULONG ulDataLen; CK_BYTE signature[128]; CK_RV rv; . . . rv = C_VerifyRecoverInit(hSession, &mechanism, hKey); if (rv == CKR_OK) { ulDataLen = sizeof(data); rv = C_VerifyRecover( hSession, signature, sizeof(signature), data, &ulDataLen); . . . } 11.13 双重目的的密码函数 Cryptoki 在一个对话中提供以下的函数“同时”执行两个密码操作。提供这些函数是为了避免不必要数据出入令牌。 C_DigestEncryptUpdate CK_DEFINE_FUNCTION(CK_RV, C_DigestEncryptUpdate)( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen ); C_DigestEncryptUpdate 继续进行多部分的摘要和加密操作,处理另一个数据部分。hSession 是对话句柄;pPart 指向数据部分;ulPartLen 是数据部分的长度;pEncryptedPart 指向接收摘要和加密数据部分的单元;pulEncryptedPartLen 指向包含加密数据部分长度的单元。 C_DigestEncryptUpdate 采用中生产输出部分所述的惯例 如果一次调用 C_DigestEncryptUpdate 不能产生加密输出(因为发生错误,或者因为pEncryptedPart的值为NULL_PTR ,亦或因为pulEncryptedPartLen 太小而不能包含整个加密部分输出),那么不传输平文给现用的摘要操作。 摘要和加密操作必须都是现用的(他们必须分别以C_DigestInit 和C_EncryptInit 来预置)。该函数可以连续调用若干次,也可以中途调用C_DigestUpdate ,C_DigestKey 和C_EncryptUpdate (但是调用C_DigestKey 时插入调用C_DigestEncryptUpdate 是不常见的)。 返回值:CKR_BUFFER_TOO_SMALL, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DATA_LEN_RANGE, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_OPERATION_NOT_INITIALIZED, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_ARGUMENTS_BAD. 实例: #define BUF_SZ 512 CK_SESSION_HANDLE hSession; CK_OBJECT_HANDLE hKey; CK_BYTE iv[8]; CK_MECHANISM digestMechanism = { CKM_MD5, NULL_PTR, 0 }; CK_MECHANISM encryptionMechanism = { CKM_DES_ECB, iv, sizeof(iv) }; CK_BYTE encryptedData[BUF_SZ]; CK_ULONG ulEncryptedDataLen; CK_BYTE digest[16]; CK_ULONG ulDigestLen; CK_BYTE data[(2*BUF_SZ)+8]; CK_RV rv; int i; . . . memset(iv, 0, sizeof(iv)); memset(data, ‘A’, ((2*BUF_SZ)+5)); rv = C_EncryptInit(hSession, &encryptionMechanism, hKey); if (rv != CKR_OK) { . . . } rv = C_DigestInit(hSession, &digestMechanism); if (rv != CKR_OK) { . . . } ulEncryptedDataLen = sizeof(encryptedData); rv = C_DigestEncryptUpdate( hSession, &data[0], BUF_SZ, encryptedData, &ulEncryptedDataLen); . . . ulEncryptedDataLen = sizeof(encryptedData); rv = C_DigestEncryptUpdate( hSession, &data[BUF_SZ], BUF_SZ, encryptedData, &ulEncryptedDataLen); . . . /* * The last portion of the buffer needs to be handled with * separate calls to deal with padding issues in ECB mode */ /* First, complete the digest on the buffer */ rv = C_DigestUpdate(hSession, &data[BUF_SZ*2], 5); . . . ulDigestLen = sizeof(digest); rv = C_DigestFinal(hSession, digest, &ulDigestLen); . . . /* Then, pad last part with 3 0x00 bytes, and complete encryption */ for(i=0;i<3;i++) data[((BUF_SZ*2)+5)+i] = 0x00; /* Now, get second-to-last piece of ciphertext */ ulEncryptedDataLen = sizeof(encryptedData); rv = C_EncryptUpdate( hSession, &data[BUF_SZ*2], 8, encryptedData, &ulEncryptedDataLen); . . . /* Get last piece of ciphertext (should have length 0, here) */ ulEncryptedDataLen = sizeof(encryptedData); rv = C_EncryptFinal(hSession, encryptedData, &ulEncryptedDataLen); . . . C_DecryptDigestUpdate CK_DEFINE_FUNCTION(CK_RV, C_DecryptDigestUpdate)( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen ); C_DecryptDigestUpdate 继续多部分合并的解密和摘要操作,处理另一个数据部分。hSession hSession 是对话句柄;pEncryptedPart 指向加密数据;ulEncryptedPartLen 是加密数据的长度;pPart 指向接收恢复数据的单元;pulPartLen 指向包含恢复数据长度的单元。 C_DecryptDigestUpdate 采用中生产输出部分所述的惯例。 解密和摘要操作必须都是现用的(他们必须分别以C_DecryptInit 和C_DigestInit 预置)。该函数可以连续调用若干次,也可以中途调用C_DecryptUpdate ,C_DigestUpdate 和C_DigestKey (但是调用C_DigestKey时插入调用C_DigestEncryptUpdate 是不常见的)。使用C_DecryptDigestUpdate 涉及在使用C_DigestEncryptUpdate 时不会发生的流水线问题,——C_DecryptDigestUpdate 的“逆函数”。这是因为当调用C_DigestEncryptUpdate 函数时,完全相同的输入传送到现用的摘要操作和现用的加密操作;但是,调用C_DecryptDigestUpdate 时,传送到现用摘要操作的输入是现用解密操作的输出。只有当用做解密的机制执行填充时会出现这个问题。 特别是,想象一个通过加密一个PKCS 填充的CBC 模式中的DES 18字节平文获得的24字节密文。考虑一个将同时解密该密文并摘要由此获得的源平文的应用。 预置解密和摘要操作后,应用将24字节密文(3 DES 块)传送到C_DecryptDigestUpdate 。由于在这一点上,Cryptoki不知道是否有更多的密文到达,或者是否最后的密文块包含任何,因而C_DecryptDigestUpdate 正好返回16字节的平文。这16字节的平文被传送到现用的摘要操作。 由于不再有密文了,于是应用调用C_DecryptFinal 。这就告诉Cryptoki 不再有密文到达了,调用返回平文的最后两个字节。然而,由于现用的解密和摘要操作仅通过C_DecryptDigestUpdate 调用来链接,因而平文的这两个字节不会被传送去摘要。 因此,调用C_DigestFinal会计算平文前16个字节的消息摘要,而不是整个平文的消息摘要。非常关键的是,在调用C_DigestFinal 之前,平文的最后两个字节通过C_DigestUpdate调用被被传送到现用的摘要操作。 由于这个原因,因此当应用使用带C_DecryptDigestUpdate的填充解密机制时,它知道有多少平文已被传送到现用的摘要操作是非常关键的。当使用带C_DecryptDigestUpdate 的填充解密机制时要非常小心。 返回值:CKR_BUFFER_TOO_SMALL, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_ENCRYPTED_DATA_INVALID, CKR_ENCRYPTED_DATA_LEN_RANGE, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_OPERATION_NOT_INITIALIZED, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_ARGUMENTS_BAD. 实例: #define BUF_SZ 512 CK_SESSION_HANDLE hSession; CK_OBJECT_HANDLE hKey; CK_BYTE iv[8]; CK_MECHANISM decryptionMechanism = { CKM_DES_ECB, iv, sizeof(iv) }; CK_MECHANISM digestMechanism = { CKM_MD5, NULL_PTR, 0 }; CK_BYTE encryptedData[(2*BUF_SZ)+8]; CK_BYTE digest[16]; CK_ULONG ulDigestLen; CK_BYTE data[BUF_SZ]; CK_ULONG ulDataLen, ulLastUpdateSize; CK_RV rv; . . . memset(iv, 0, sizeof(iv)); memset(encryptedData, ‘A’, ((2*BUF_SZ)+8)); rv = C_DecryptInit(hSession, &decryptionMechanism, hKey); if (rv != CKR_OK) { . . . } rv = C_DigestInit(hSession, &digestMechanism); if (rv != CKR_OK){ . . . } ulDataLen = sizeof(data); rv = C_DecryptDigestUpdate( hSession, &encryptedData[0], BUF_SZ, data, &ulDataLen); . . . ulDataLen = sizeof(data); rv = C_DecryptDigestUpdate( hSession, &encryptedData[BUF_SZ], BUF_SZ, data, &ulDataLen); . . . /* * The last portion of the buffer needs to be handled with * separate calls to deal with padding issues in ECB mode */ /* First, complete the decryption of the buffer */ ulLastUpdateSize = sizeof(data); rv = C_DecryptUpdate( hSession, &encryptedData[BUF_SZ*2], 8, data, &ulLastUpdateSize); . . . /* Get last piece of plaintext (should have length 0, here) */ ulDataLen = sizeof(data)-ulLastUpdateSize; rv = C_DecryptFinal(hSession, &data[ulLastUpdateSize], &ulDataLen); if (rv != CKR_OK) { . . . } /* Digest last bit of plaintext */ rv = C_DigestUpdate(hSession, &data[BUF_SZ*2], 5); if (rv != CKR_OK) { . . . } ulDigestLen = sizeof(digest); rv = C_DigestFinal(hSession, digest, &ulDigestLen); if (rv != CKR_OK) { . . . } C_SignEncryptUpdate CK_DEFINE_FUNCTION(CK_RV, C_SignEncryptUpdate)( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen ); C_SignEncryptUpdate 继续一个多部分结合的签名和加密操作,处理另一个数据部分。hSession 是对话的句柄;pPart 指向数据部分;ulPartLen 是数据部分的长度; pEncryptedPart 指向接收摘要和加密数据部分的单元;pulEncryptedPart 指向包含加密的数据部分的长度的单元。 C_SignEncryptUpdate 采用节生产输出中所述的惯例。 如果调用C_SignEncryptUpdate 并不产生加密输出(因为错误发生,或者因为pEncryptedPart的值为NULL_PTR, 亦或因为 pulEncryptedPartLen 太小而不能包含整个加密部分的输出),那么不将平文传输到现用的签名操作。 签名和加密操作都必须是现用的(他们必须分别用C_SignInit 和C_EncryptInit 预置)。 该函数可以连续调用若干次,也可以中途调用C_SignUpdate 和 C_EncryptUpdate。 返回值:CKR_BUFFER_TOO_SMALL, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DATA_LEN_RANGE, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_OPERATION_NOT_INITIALIZED, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_ARGUMENTS_BAD. 实例: #define BUF_SZ 512 CK_SESSION_HANDLE hSession; CK_OBJECT_HANDLE hEncryptionKey, hMacKey; CK_BYTE iv[8]; CK_MECHANISM signMechanism = { CKM_DES_MAC, NULL_PTR, 0 }; CK_MECHANISM encryptionMechanism = { CKM_DES_ECB, iv, sizeof(iv) }; CK_BYTE encryptedData[BUF_SZ]; CK_ULONG ulEncryptedDataLen; CK_BYTE MAC[4]; CK_ULONG ulMacLen; CK_BYTE data[(2*BUF_SZ)+8]; CK_RV rv; int i; . . . memset(iv, 0, sizeof(iv)); memset(data, ‘A’, ((2*BUF_SZ)+5)); rv = C_EncryptInit(hSession, &encryptionMechanism, hEncryptionKey); if (rv != CKR_OK) { . . . } rv = C_SignInit(hSession, &signMechanism, hMacKey); if (rv != CKR_OK) { . . . } ulEncryptedDataLen = sizeof(encryptedData); rv = C_SignEncryptUpdate( hSession, &data[0], BUF_SZ, encryptedData, &ulEncryptedDataLen); . . . ulEncryptedDataLen = sizeof(encryptedData); rv = C_SignEncryptUpdate( hSession, &data[BUF_SZ], BUF_SZ, encryptedData, &ulEncryptedDataLen); . . . /* * The last portion of the buffer needs to be handled with * separate calls to deal with padding issues in ECB mode */ /* First, complete the signature on the buffer */ rv = C_SignUpdate(hSession, &data[BUF_SZ*2], 5); . . . ulMacLen = sizeof(MAC); rv = C_DigestFinal(hSession, MAC, &ulMacLen); . . . /* Then pad last part with 3 0x00 bytes, and complete encryption */ for(i=0;i<3;i++) data[((BUF_SZ*2)+5)+i] = 0x00; /* Now, get second-to-last piece of ciphertext */ ulEncryptedDataLen = sizeof(encryptedData); rv = C_EncryptUpdate( hSession, &data[BUF_SZ*2], 8, encryptedData, &ulEncryptedDataLen); . . . /* Get last piece of ciphertext (should have length 0, here) */ ulEncryptedDataLen = sizeof(encryptedData); rv = C_EncryptFinal(hSession, encryptedData, &ulEncryptedDataLen); . . . C_DecryptVerifyUpdate CK_DEFINE_FUNCTION(CK_RV, C_DecryptVerifyUpdate)( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen ); C_DecryptVerifyUpdate 继续一个多部分结合的解密和校验操作,处理另一个数据部分。 hSession 是对话的句柄;pEncryptedPart 指向加密的数据;ulEncryptedPartLen 是加密数据的长度;pPart 指向接收恢复数据的单元;pulPartLen 指向包含恢复数据长度的单元。 C_DecryptVerifyUpdate 采用节中生产输出中所述的惯例。如果 C_DecryptVerifyUpdate 调用不产生解密输出(因为发生错误或者因为pPart的值为 NULL_PTR, 亦或因为 pulPartLen 太小而不能包含整个加密部分的输出),那么不将平文输出到现用的校验操作。 解密和签名操作必须都是现用的(他们都必须分别用 C_DecryptInit 和C_VerifyInit来预置)。该函数可以连续调用若干次,而且可以中途调用C_DecryptUpdate 和 C_VerifyUpdate。 使用C_DecryptVerifyUpdate 涉及一个在使用C_SignEncryptUpdate时不会出现的流水线问题,这是C_DecryptVerifyUpdate 的“逆函数”。这是因为当调用C_SignEncryptUpdate 时,完全相同的输入被传输到现用的签名操作和现用的加密操作;然而,当调用 C_DecryptVerifyUpdate 时,传输给现用校验操作的输入是现用解密操作的输出。只有当用于解密的机制执行填充时才出现这个问题。 特别是,想象一下PKCS填充的CBC模式中由带DES的18字节平文加密获得的24字节密文。考虑一下将同时解密该密文并校验由此获得的源平文上的签名的应用。 预置解密和校验操作后,应用将24字节的密文(3 DES块)传输到C_DecryptVerifyUpdate。 C_DecryptVerifyUpdate 将正好16个字节的平文返回,这是由于在这一点上,Cryptoki不知道是否还有密文到达,或者密文最后的块是否含有任何填充。这16个字节的平文被传输到现用的校验操作。 由于不再有密文,因而应用调用C_DecryptFinal。 这告诉Cryptoki 再没有密文到达,而且调用返回平文的最后两个字节。然而,由于现用的解密和校验操作只通过C_DecryptVerifyUpdate 调用链接,因此平文的这两个字节不被传输到校验机制。 因此,调用C_VerifyFinal 将校验提供的签名是否在平文的前16个字节上是有效的签名,并不是整个平文。关键是,调用C_VerifyFinal 之前,平文的最后两个字节通过C_VerifyUpdate 被传输到现用的校验操作。 因此,关键的一点是,当应用使用带C_DecryptVerifyUpdate 的填充解密机制时,它能知道到底有多少平文被传输到现用的校验操作。当使用带C_DecryptVerifyUpdate 的填充解密机制时必须非常谨慎。 返回值:CKR_BUFFER_TOO_SMALL, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DATA_LEN_RANGE, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_ENCRYPTED_DATA_INVALID, CKR_ENCRYPTED_DATA_LEN_RANGE, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_OPERATION_NOT_INITIALIZED, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_ARGUMENTS_BAD. 实例: #define BUF_SZ 512 CK_SESSION_HANDLE hSession; CK_OBJECT_HANDLE hDecryptionKey, hMacKey; CK_BYTE iv[8]; CK_MECHANISM decryptionMechanism = { CKM_DES_ECB, iv, sizeof(iv) }; CK_MECHANISM verifyMechanism = { CKM_DES_MAC, NULL_PTR, 0 }; CK_BYTE encryptedData[(2*BUF_SZ)+8]; CK_BYTE MAC[4]; CK_ULONG ulMacLen; CK_BYTE data[BUF_SZ]; CK_ULONG ulDataLen, ulLastUpdateSize; CK_RV rv; . . . memset(iv, 0, sizeof(iv)); memset(encryptedData, ‘A’, ((2*BUF_SZ)+8)); rv = C_DecryptInit(hSession, &decryptionMechanism, hDecryptionKey); if (rv != CKR_OK) { . . . } rv = C_VerifyInit(hSession, &verifyMechanism, hMacKey); if (rv != CKR_OK){ . . . } ulDataLen = sizeof(data); rv = C_DecryptVerifyUpdate( hSession, &encryptedData[0], BUF_SZ, data, &ulDataLen); . . . ulDataLen = sizeof(data); rv = C_DecryptVerifyUpdate( hSession, &encryptedData[BUF_SZ], BUF_SZ, data, &uldataLen); . . . /* * The last portion of the buffer needs to be handled with * separate calls to deal with padding issues in ECB mode */ /* First, complete the decryption of the buffer */ ulLastUpdateSize = sizeof(data); rv = C_DecryptUpdate( hSession, &encryptedData[BUF_SZ*2], 8, data, &ulLastUpdateSize); . . . /* Get last little piece of plaintext. Should have length 0 */ ulDataLen = sizeof(data)-ulLastUpdateSize; rv = C_DecryptFinal(hSession, &data[ulLastUpdateSize], &ulDataLen); if (rv != CKR_OK) { . . . } /* Send last bit of plaintext to verification operation */ rv = C_VerifyUpdate(hSession, &data[BUF_SZ*2], 5); if (rv != CKR_OK) { . . . } rv = C_VerifyFinal(hSession, MAC, ulMacLen); if (rv == CKR_SIGNATURE_INVALID) { . . . } 11.14 密钥管理函数 Cryptoki 为密钥的管理提供以下的函数。 C_GenerateKey CK_DEFINE_FUNCTION(CK_RV, C_GenerateKey)( CK_SESSION_HANDLE hSession CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey ); C_GenerateKey 产生一个保密密钥,创建一个新的密钥对象。 hSession 是对话的句柄; pMechanism 指向密钥产生机制;pTemplate 指向新密钥的模板;ulCount 是模板中的属性数; phKey 指向接收新密钥句柄的单元。 由于要产生的密钥类型在密钥生成机制中是隐式的,因此模板不需要提供一个密钥类型。如果它提供了一个与密钥生成机制不一致的密钥类型,则C_GenerateKey 失败并返回错误码 CKR_TEMPLATE_INCONSISTENT。以类似方式处理CKA_CLASS 属性。 如果调用C_GenerateKey 不能支持提供给它的精确模板,则不创建任何密钥对象,失败并返回。 成功调用C_GenerateKey 创建的密钥对象的CKA_LOCAL 属性设置为TRUE。 返回值:CKR_ATTRIBUTE_READ_ONLY, CKR_ATTRIBUTE_TYPE_INVALID, CKR_ATTRIBUTE_VALUE_INVALID, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_MECHANISM_INVALID, CKR_MECHANISM_PARAM_INVALID, CKR_OK, CKR_OPERATION_ACTIVE, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_SESSION_READ_ONLY, CKR_TEMPLATE_INCOMPLETE, CKR_TEMPLATE_INCONSISTENT, CKR_TOKEN_WRITE_PROTECTED, CKR_USER_NOT_LOGGED_IN, CKR_ARGUMENTS_BAD, CKR_PIN_EXPIRED. 实例: CK_SESSION_HANDLE hSession; CK_OBJECT_HANDLE hKey; CK_MECHANISM mechanism = { CKM_DES_KEY_GEN, NULL_PTR, 0 }; CK_RV rv; . . . rv = C_GenerateKey(hSession, &mechanism, NULL_PTR, 0, &hKey); if (rv == CKR_OK) { . . . } C_GenerateKeyPair CK_DEFINE_FUNCTION(CK_RV, C_GenerateKeyPair)( CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount, CK_OBJECT_HANDLE_PTR phPublicKey, CK_OBJECT_HANDLE_PTR phPrivateKey ); C_GenerateKeyPair 生成一个公共/私钥对,创建新的密钥对象。hSession 是对话的句柄;pMechanism 指向密钥生成机制;pPublicKeyTemplate 指向公共密钥的模板;ulPublicKeyAttributeCount 是公共密钥模板的属性数;pPrivateKeyTemplate 指向私钥的模板;ulPrivateKeyAttributeCount 是私钥模板中的属性数;phPublicKey 指向接收新公共密钥句柄的单元;phPrivateKey 指向接收新私钥句柄的单元。 由于要生成的密钥的类型在密钥对生成机制中是隐式的,因此模板不需要提供密钥类型。如果一个模板提供的密钥类型与密钥生成机制不一致,那么C_GenerateKeyPair 失败并返回错误码CKR_TEMPLATE_INCONSISTENT。以类似方式处理CKA_CLASS 属性。 如果调用C_GenerateKeyPair 不能支持为它提供的精确模板,则不创建任何密钥对象,失败并返回。 调用C_GenerateKeyPair 决不只创建一个密钥并返回。调用会失败,而且不创建密钥;或者会成功,而且创建一个相匹配的公共/私钥对。 成功调用C_GenerateKeyPair 所创建的密钥对象将其CKA_LOCAL属性设置为TRUE。 注意C_GenerateKeyPair 的变元的顺序。最后两个变元的顺序与原始Cryptoki 1.0版本文件中的顺序不同。这两个变元的顺序以导致了某些混淆。 返回值:CKR_ATTRIBUTE_READ_ONLY, CKR_ATTRIBUTE_TYPE_INVALID, CKR_ATTRIBUTE_VALUE_INVALID, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_MECHANISM_INVALID, CKR_MECHANISM_PARAM_INVALID, CKR_OK, CKR_OPERATION_ACTIVE, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_SESSION_READ_ONLY, CKR_TEMPLATE_INCOMPLETE, CKR_TEMPLATE_INCONSISTENT, CKR_TOKEN_WRITE_PROTECTED, CKR_USER_NOT_LOGGED_IN, CKR_ARGUMENTS_BAD, CKR_PIN_EXPIRED. 实例: CK_SESSION_HANDLE hSession; CK_OBJECT_HANDLE hPublicKey, hPrivateKey; CK_MECHANISM mechanism = { CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0 }; CK_ULONG modulusBits = 768; CK_BYTE publicExponent[] = { 3 }; CK_BYTE subject[] = {...}; CK_BYTE id[] = {123}; CK_BBOOL true = TRUE; CK_ATTRIBUTE publicKeyTemplate[] = { {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_VERIFY, &true, sizeof(true)}, {CKA_WRAP, &true, sizeof(true)}, {CKA_MODULUS_BITS, &modulusBits, sizeof(modulusBits)}, {CKA_PUBLIC_EXPONENT, publicExponent, sizeof (publicExponent)} }; CK_ATTRIBUTE privateKeyTemplate[] = { {CKA_TOKEN, &true, sizeof(true)}, {CKA_PRIVATE, &true, sizeof(true)}, {CKA_SUBJECT, subject, sizeof(subject)}, {CKA_ID, id, sizeof(id)}, {CKA_SENSITIVE, &true, sizeof(true)}, {CKA_DECRYPT, &true, sizeof(true)}, {CKA_SIGN, &true, sizeof(true)}, {CKA_UNWRAP, &true, sizeof(true)} }; CK_RV rv; rv = C_GenerateKeyPair( hSession, &mechanism, publicKeyTemplate, 5, privateKeyTemplate, 8, &hPublicKey, &hPrivateKey); if (rv == CKR_OK) { . . . } C_WrapKey CK_DEFINE_FUNCTION(CK_RV, C_WrapKey)( CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hWrappingKey, CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pWrappedKey, CK_ULONG_PTR pulWrappedKeyLen ); C_WrapKey 打包 (即., 加密) 一个私有或保密密钥。hSession 是对话的句柄;pMechanism 指向打包机制;hWrappingKey 是打包密钥的句柄;hKey 是要打包的密钥的句柄; pWrappedKey 指向接收打包密钥的单元;pulWrappedKeyLen 指向接收打包密钥长度的单元。 C_WrapKey 采用节中生产输出部分所述的惯例。 打包密钥的CKA_WRAP 属性——说明该密钥是否支持打包——必须为TRUE。要被打包的密钥的CKA_EXTRACTABLE 属性必须为 TRUE。 如果由于某种和令牌有关的原因而不能打包密钥的话,即使其CKA_EXTRACTABLE 属性设置为TRUE,C_WrapKey 还是会失败,出现错误码CKR_KEY_NOT_WRAPPABLE。如果单纯因为长度而不能用特定的打包密钥和机制打包的话,那么 C_WrapKey 失败,返回错误码CKR_KEY_SIZE_RANGE。 C_WrapKey 可以用在以下场合: 用RSA公共密钥打包任何保密密钥。 用SKIPJACK, BATON, 或JUNIPER 密钥之外的保密密钥打包任何保密密钥。 用另一个KIPJACK, BATON, 或 JUNIPER 密钥(两种密钥不必为同种类型)打包 SKIPJACK, BATON, 或 JUNIPER密钥。 用SKIPJACK, BATON, or JUNIPER 密钥之外的保密密钥打包RSA, Diffie-Hellman, 或 DSA 私钥。 用SKIPJACK 密钥打包KEA 或 DSA 私钥。 当然,令牌会随实际用哪种机制打包哪种类型的的密钥而变化。 返回值:CKR_BUFFER_TOO_SMALL, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_KEY_HANDLE_INVALID, CKR_KEY_NOT_WRAPPABLE, CKR_KEY_SIZE_RANGE, CKR_KEY_UNEXTRACTABLE, CKR_MECHANISM_INVALID, CKR_MECHANISM_PARAM_INVALID, CKR_OK, CKR_OPERATION_ACTIVE, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_USER_NOT_LOGGED_IN, CKR_WRAPPING_KEY_HANDLE_INVALID, CKR_WRAPPING_KEY_SIZE_RANGE, CKR_WRAPPING_KEY_TYPE_INCONSISTENT, CKR_ARGUMENTS_BAD, CKR_PIN_EXPIRED. 实例: CK_SESSION_HANDLE hSession; CK_OBJECT_HANDLE hWrappingKey, hKey; CK_MECHANISM mechanism = { CKM_DES3_ECB, NULL_PTR, 0 }; CK_BYTE wrappedKey[8]; CK_ULONG ulWrappedKeyLen; CK_RV rv; . . . ulWrappedKeyLen = sizeof(wrappedKey); rv = C_WrapKey( hSession, &mechanism, hWrappingKey, hKey, wrappedKey, &ulWrappedKeyLen); if (rv == CKR_OK) { . . . } C_UnwrapKey CK_DEFINE_FUNCTION(CK_RV, C_UnwrapKey)( CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hUnwrappingKey, CK_BYTE_PTR pWrappedKey, CK_ULONG ulWrappedKeyLen, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey ); C_UnwrapKey 解包(即,解密)一个打包密钥,创建一个新的私钥或秘密密钥对象。hSession 是对话的句柄;pMechanism 指向未打包的机制;hUnwrappingKey 是未打包的密钥的句柄;pWrappedKey 指向打包的密钥;ulWrappedKeyLen 是打包的密钥的的长度; pTemplate 指向新密钥的模块;ulAttributeCount 是模块中的属性数;phKey 指向接收恢复密钥的句柄的单元。 未打包的密钥的CKA_UNWRAP 属性——说明密钥是否未打包——必须为TRUE。 新密钥的CKA_ALWAYS_SENSITIVE属性应该设置成FALSE,CKA_EXTRACTABLE属性设置成 TRUE。 当采用C_UnwrapKey 来解包带CKM_KEY_WRAP_SET_OAEP 机制的密钥时(见节),密钥解包的同时解包附加的“额外数据”。该数据的返回依照节生产输出部分的惯例。 如果额外的数据没有从调用 C_UnwrapKey 返回(或者是因为调用只是要发现额外的数据到底有多大,或者是因为提供给额外数据的缓冲器太小),那么C_UnwrapKey 也不创建新的密钥。 如果调用C_UnwrapKey 不支持提供给它的精确模板,它将不创建任何密钥对象,失败并返回。 成功调用C_UnwrapKey 创建的密钥对象的CKA_LOCAL 属性设置成 FALSE。 返回值:CKR_ATTRIBUTE_READ_ONLY, CKR_ATTRIBUTE_TYPE_INVALID, CKR_ATTRIBUTE_VALUE_INVALID, CKR_BUFFER_TOO_SMALL, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_MECHANISM_INVALID, CKR_MECHANISM_PARAM_INVALID, CKR_OK, CKR_OPERATION_ACTIVE, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_SESSION_READ_ONLY, CKR_TEMPLATE_INCOMPLETE, CKR_TEMPLATE_INCONSISTENT, CKR_TOKEN_WRITE_PROTECTED, CKR_UNWRAPPING_KEY_HANDLE_INVALID, CKR_UNWRAPPING_KEY_SIZE_RANGE, CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT, CKR_USER_NOT_LOGGED_IN, CKR_WRAPPED_KEY_INVALID, CKR_WRAPPED_KEY_LEN_RANGE, CKR_ARGUMENTS_BAD, CKR_PIN_EXPIRED. 实例: CK_SESSION_HANDLE hSession; CK_OBJECT_HANDLE hUnwrappingKey, hKey; CK_MECHANISM mechanism = { CKM_DES3_ECB, NULL_PTR, 0 }; CK_BYTE wrappedKey[8] = {...}; CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_DES; CK_BBOOL true = TRUE; CK_ATTRIBUTE template[] = { {CKA_CLASS, &keyClass, sizeof(keyClass)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_DECRYPT, &true, sizeof(true)} }; CK_RV rv; . . . rv = C_UnwrapKey( hSession, &mechanism, hUnwrappingKey, wrappedKey, sizeof(wrappedKey), template, 4, &hKey); if (rv == CKR_OK) { . . . } C_DeriveKey CK_DEFINE_FUNCTION(CK_RV, C_DeriveKey)( CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey ); C_DeriveKey 从基础密钥中衍生出一个密钥,创建一个新的密钥对象。hSession 是对话的句柄;pMechanism 指向规定密钥衍生机制的结构;hBaseKey 是基础密钥的句柄; pTemplate 指向新密钥的模板;ulAttributeCount 是模板中的属性数;phKey 指向接收衍生密钥的句柄的单元。 基础密钥的CK_SENSITIVE, CK_ALWAYS_SENSITIVE, CK_EXTRACTABLE, 和 CK_NEVER_EXTRACTABLE 的属性值影响这些属性能够为新衍生的密钥包含的值。该类型的限制参见节中每种特定的密钥衍生机制。 如果调用C_DeriveKey 不能支持提供给它的精确模板,那么它不创建任何密钥对象,失败并返回。 成功调用C_DeriveKey 创建的密钥对象的CKA_LOCAL 属性设置为FALSE。 返回值:CKR_ATTRIBUTE_READ_ONLY, CKR_ATTRIBUTE_TYPE_INVALID, CKR_ATTRIBUTE_VALUE_INVALID, CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_KEY_HANDLE_INVALID, CKR_KEY_SIZE_RANGE, CKR_KEY_TYPE_INCONSISTENT, CKR_MECHANISM_INVALID, CKR_MECHANISM_PARAM_INVALID, CKR_OK, CKR_OPERATION_ACTIVE, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_SESSION_READ_ONLY, CKR_TEMPLATE_INCOMPLETE, CKR_TEMPLATE_INCONSISTENT, CKR_TOKEN_WRITE_PROTECTED, CKR_USER_NOT_LOGGED_IN, CKR_ARGUMENTS_BAD, CKR_PIN_EXPIRED. 实例: CK_SESSION_HANDLE hSession; CK_OBJECT_HANDLE hPublicKey, hPrivateKey, hKey; CK_MECHANISM keyPairMechanism = { CKM_DH_PKCS_KEY_PAIR_GEN, NULL_PTR, 0 }; CK_BYTE prime[] = {...}; CK_BYTE base[] = {...}; CK_BYTE publicValue[128]; CK_BYTE otherPublicValue[128]; CK_MECHANISM mechanism = { CKM_DH_PKCS_DERIVE, otherPublicValue, sizeof(otherPublicValue) }; CK_ATTRIBUTE pTemplate[] = { CKA_VALUE, &publicValue, sizeof(publicValue)} }; CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; CK_KEY_TYPE keyType = CKK_DES; CK_BBOOL true = TRUE; CK_ATTRIBUTE publicKeyTemplate[] = { {CKA_PRIME, prime, sizeof(prime)}, {CKA_BASE, base, sizeof(base)} }; CK_ATTRIBUTE privateKeyTemplate[] = { {CKA_DERIVE, &true, sizeof(true)} }; CK_ATTRIBUTE template[] = { {CKA_CLASS, &keyClass, sizeof(keyClass)}, {CKA_KEY_TYPE, &keyType, sizeof(keyType)}, {CKA_ENCRYPT, &true, sizeof(true)}, {CKA_DECRYPT, &true, sizeof(true)} }; CK_RV rv; . . . rv = C_GenerateKeyPair( hSession, &keyPairMechanism, publicKeyTemplate, 2, privateKeyTemplate, 1, &hPublicKey, &hPrivateKey); if (rv == CKR_OK) { rv = C_GetAttributeValue(hSession, hPublicKey, &pTemplate, 1); if (rv == CKR_OK) { /* Put other guy’s public value in otherPublicValue */ . . . rv = C_DeriveKey( hSession, &mechanism, hPrivateKey, template, 4, &hKey); if (rv == CKR_OK) { . . . } } } 11.15 随机数生成函数 Cryptoki 为生成随机数提供以下的函数: C_SeedRandom CK_DEFINE_FUNCTION(CK_RV, C_SeedRandom)( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed, CK_ULONG ulSeedLen ); C_SeedRandom 将附加的种子材料混入令牌的随机数产生器。hSession 是对话的句柄;pSeed 指向种子材料;ulSeedLen 是种子材料的字节长。 返回值:CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_OPERATION_ACTIVE, CKR_RANDOM_SEED_NOT_SUPPORTED, CKR_RANDOM_NO_RNG, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_USER_NOT_LOGGED_IN, CKR_ARGUMENTS_BAD. 实例:参见C_GenerateRandom。 C_GenerateRandom CK_DEFINE_FUNCTION(CK_RV, C_GenerateRandom)( CK_SESSION_HANDLE hSession, CK_BYTE_PTR pRandomData, CK_ULONG ulRandomLen ); C_GenerateRandom 产生随机或伪随机的数据。hSession 是对话的句柄;pRandomData 指向接收随机数据的单元;ulRandomLen 是要生成的随机或伪随机数据的长度。 返回值:CKR_CRYPTOKI_NOT_INITIALIZED, CKR_DEVICE_ERROR, CKR_DEVICE_MEMORY, CKR_DEVICE_REMOVED, CKR_FUNCTION_CANCELED, CKR_FUNCTION_FAILED, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_OK, CKR_OPERATION_ACTIVE, CKR_RANDOM_NO_RNG, CKR_SESSION_CLOSED, CKR_SESSION_HANDLE_INVALID, CKR_USER_NOT_LOGGED_IN, CKR_ARGUMENTS_BAD. 实例: CK_SESSION_HANDLE hSession; CK_BYTE seed[] = {...}; CK_BYTE randomData[] = {...}; CK_RV rv; . . . rv = C_SeedRandom(hSession, seed, sizeof(seed)); if (rv != CKR_OK) { . . . } rv = C_GenerateRandom(hSession, randomData, sizeof(randomData)); if (rv == CKR_OK) { . . . } 11.16 并行功能管理函数 Cryptoki 为管理并行执行加密函数提供了以下的函数。这些函数只为反向兼容性而存在。 C_GetFunctionStatus CK_DEFINE_FUNCTION(CK_RV, C_GetFunctionStatus)( CK_SESSION_HANDLE hSession ); 在Cryptoki 以前的版本中,C_GetFunctionStatus 获得与应用并行运行的函数的资格。然而,目前的C_GetFunctionStatus 是一个传统函数,只能返回 CKR_FUNCTION_NOT_PARALLEL值。 返回值:CKR_CRYPTOKI_NOT_INITIALIZED, CKR_FUNCTION_FAILED, CKR_FUNCTION_NOT_PARALLEL, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_SESSION_HANDLE_INVALID, CKR_SESSION_CLOSED. C_CancelFunction CK_DEFINE_FUNCTION(CK_RV, C_CancelFunction)( CK_SESSION_HANDLE hSession ); 在Cryptoki以前的版本中, C_CancelFunction 取消与应用并行运行的函数。然而,目前的 C_CancelFunction 是一个传统函数,只应返回CKR_FUNCTION_NOT_PARALLEL值。 返回值:CKR_CRYPTOKI_NOT_INITIALIZED, CKR_FUNCTION_FAILED, CKR_FUNCTION_NOT_PARALLEL, CKR_GENERAL_ERROR, CKR_HOST_MEMORY, CKR_SESSION_HANDLE_INVALID, CKR_SESSION_CLOSED. 11.17 回调函数 Cryptoki 对话能使用CK_NOTIFY 类型的函数指针来说明某些事件的应用。 11.17.1 放弃回调 在Cryptoki对话中,如果正在执行中的对话在打开时有一个与之相联系的通知回调功能,那么执行的密码函数 (即,这些类别中的任何函数:加密函数;解密函数消息摘要函数;签名和MAC函数;双重目的密码函数;密钥管理函数;随机数生成函数) 能阶段性地放弃控制调用他们的应用。他们通过调用带变元(hSession, CKN_SURRENDER, pApplication)的对话回调来执行,其中hSession 是对话的句柄,当对话打开时将pApplication 提供给C_OpenSession 。放弃回调或者返回 CKR_OK值 (说明Cryptoki应该继续执行该函数)或者返回CKR_CANCEL值 (说明Cryptoki 应该放弃执行该函数)。 当然,在返回其中一个值之前,如果需要的话,回调函数能够执行某种计算。 放弃回调的一个典型用途是在长的密钥对生成操作过程中给应用用户回调。每次应用接收一个回调,它都会指示一个附加的“.”给用户看。也可能自最后的放弃回调来检查键盘的现用性,如果用户敲击就放弃密钥对生成操作(很可能返回CKR_CANCEL值)。 不要求Cryptoki 库能进行任何放弃回调。 11.17.2 卖商定义的回调 库的卖商也能定义其他类型的回调。由于这种扩展的能力,应用提供的通知回调惯例应该检查他们接收的每个回调,如果他们不熟悉某种回调的类型的话,他们应该立即返回CKR_OK值,将控制返还给库。 12. 机制 机制详细说明某种加密过程是如何执行的。 下表说明不同的密码操作支持哪种Cryptoki 机制。当然,也不保证,一个令牌(该令牌对于某一个操作支持一种机制)对于任何其它操作它支持任何其它机制(或者甚至对任何其它操作它支持那个同样的机制)。例如,即使一个令牌能用CKM_RSA_PKCS 机制建立RSA数字签名,它可以是同一令牌,也能用CKM_RSA_PKCS 执行RSA加密这种情况也可不是这种情况。 表62, 机制与函数 函数 机制 加密 & 解密 签名 & 验证 SR & VR1 摘要 类属密钥/密钥对 加密 & 脱密 派生 CKM_RSA_PKCS_KEY_PAIR_GEN  CKM_RSA_PKCS 2 2   CKM_RSA_PKCS_OAEP 2  CKM_RSA_9796 2  CKM_RSA_X_509 2 2   CKM_RSA_X9_31 2 CKM_MD2_RSA_PKCS  CKM_MD5_RSA_PKCS  CKM_SHA1_RSA_PKCS  CKM_RIPEMD128_RSA_PKCS  CKM_RIPEMD160_RSA_PKCS  CKM_SHA1_RSA_X9_31  CKM_DSA_KEY_PAIR_GEN  CKM_DSA 2 CKM_DSA_SHA1  CKM_FORTEZZA_TIMESTAMP 2 CKM_ECDSA_KEY_PAIR_GEN  CKM_ECDSA 2 CKM_ECDSA_SHA1  CKM_DH_PKCS_KEY_PAIR_GEN  CKM_DH_PKCS_DERIVE  CKM_KEA_KEY_PAIR_GEN  CKM_KEA_KEY_DERIVE  CKM_GENERIC_SECRET_KEY_GEN  CKM_RC2_KEY_GEN  CKM_RC2_ECB   CKM_RC2_CBC   CKM_RC2_CBC_PAD   CKM_RC2_MAC_GENERAL  CKM_RC2_MAC  CKM_RC4_KEY_GEN  CKM_RC4  CKM_RC5_KEY_GEN  CKM_RC5_ECB   CKM_RC5_CBC   CKM_RC5_CBC_PAD   CKM_RC5_MAC_GENERAL  CKM_RC5_MAC  CKM_AES_KEY_GEN  CKM_AES_ECB   CKM_AES_CBC   CKM_AES_CBC_PAD   CKM_AES_MAC_GENERAL  CKM_AES_MAC  CKM_DES_KEY_GEN  CKM_DES_ECB   CKM_DES_CBC   CKM_DES_CBC_PAD   CKM_DES_MAC_GENERAL  CKM_DES_MAC  CKM_DES2_KEY_GEN  CKM_DES3_KEY_GEN  CKM_DES3_ECB   CKM_DES3_CBC   CKM_DES3_CBC_PAD   CKM_DES3_MAC_GENERAL  CKM_DES3_MAC  CKM_CAST_KEY_GEN  CKM_CAST_ECB   CKM_CAST_CBC   CKM_CAST_CBC_PAD   CKM_CAST_MAC_GENERAL  CKM_CAST_MAC  CKM_CAST3_KEY_GEN  CKM_CAST3_ECB   CKM_CAST3_CBC   CKM_CAST3_CBC_PAD   CKM_CAST3_MAC_GENERAL  CKM_CAST3_MAC  CKM_CAST128_KEY_GEN (CKM_CAST5_KEY_GEN)  CKM_CAST128_ECB (CKM_CAST5_ECB)   CKM_CAST128_CBC (CKM_CAST5_CBC)   CKM_CAST128_CBC_PAD (CKM_CAST5_CBC_PAD)   CKM_CAST128_MAC_GENERAL (CKM_CAST5_MAC_GENERAL)  CKM_CAST128_MAC (CKM_CAST5_MAC)  CKM_IDEA_KEY_GEN  CKM_IDEA_ECB   CKM_IDEA_CBC   CKM_IDEA_CBC_PAD   CKM_IDEA_MAC_GENERAL  CKM_IDEA_MAC  CKM_CDMF_KEY_GEN  CKM_CDMF_ECB   CKM_CDMF_CBC   CKM_CDMF_CBC_PAD   CKM_CDMF_MAC_GENERAL  CKM_CDMF_MAC  CKM_SKIPJACK_KEY_GEN  CKM_SKIPJACK_ECB64  CKM_SKIPJACK_CBC64  CKM_SKIPJACK_OFB64  CKM_SKIPJACK_CFB64  CKM_SKIPJACK_CFB32  CKM_SKIPJACK_CFB16  CKM_SKIPJACK_CFB8  CKM_SKIPJACK_WRAP  CKM_SKIPJACK_PRIVATE_WRAP  CKM_SKIPJACK_RELAYX 3 CKM_BATON_KEY_GEN  CKM_BATON_ECB128  CKM_BATON_ECB96  CKM_BATON_CBC128  CKM_BATON_COUNTER  CKM_BATON_SHUFFLE  CKM_BATON_WRAP  CKM_JUNIPER_KEY_GEN  CKM_JUNIPER_ECB128  CKM_JUNIPER_CBC128  CKM_JUNIPER_COUNTER  CKM_JUNIPER_SHUFFLE  CKM_JUNIPER_WRAP  CKM_MD2  CKM_MD2_HMAC_GENERAL  CKM_MD2_HMAC  CKM_MD2_KEY_DERIVATION  CKM_MD5  CKM_MD5_HMAC_GENERAL  CKM_MD5_HMAC  CKM_MD5_KEY_DERIVATION  CKM_SHA_1  CKM_SHA_1_HMAC_GENERAL  CKM_SHA_1_HMAC  CKM_SHA1_KEY_DERIVATION  CKM_RIPEMD128  CKM_RIPEMD128_HMAC_GENERAL  CKM_RIPEMD128_HMAC  CKM_RIPEMD160  CKM_RIPEMD160_HMAC_GENERAL  CKM_RIPEMD160_HMAC  CKM_FASTHASH  CKM_PBE_MD2_DES_CBC  CKM_PBE_MD5_DES_CBC  CKM_PBE_MD5_CAST_CBC  CKM_PBE_MD5_CAST3_CBC  CKM_PBE_MD5_CAST128_CBC (CKM_PBE_MD5_CAST5_CBC)  CKM_PBE_SHA1_CAST128_CBC (CKM_PBE_SHA1_CAST5_CBC)  CKM_PBE_SHA1_RC4_128  CKM_PBE_SHA1_RC4_40  CKM_PBE_SHA1_DES3_EDE_CBC  CKM_PBE_SHA1_DES2_EDE_CBC  CKM_PBE_SHA1_RC2_128_CBC  CKM_PBE_SHA1_RC2_40_CBC  CKM_PBA_SHA1_WITH_SHA1_HMAC  CKM_PKCS5_PBKD2  CKM_KEY_WRAP_SET_OAEP  CKM_KEY_WRAP_LYNKS  CKM_SSL3_PRE_MASTER_KEY_GEN  CKM_SSL3_MASTER_KEY_DERIVE  CKM_SSL3_KEY_AND_MAC_DERIVE  CKM_SSL3_MD5_MAC  CKM_SSL3_SHA1_MAC  CKM_CONCATENATE_BASE_AND_KEY  CKM_CONCATENATE_BASE_AND_DATA  CKM_CONCATENATE_DATA_AND_BASE  CKM_XOR_BASE_AND_DATA  CKM_EXTRACT_KEY_FROM_KEY  1 SR = SignRecover(签名恢复), VR = VerifyRecover(验证恢复)。 2 只进行单方操作。 3 机制只能用来加密,不能用来脱密。 章节 的其余部分将详细介绍由Cryptoki Version 2.1 支持的机制和提供给它们的参数。 一般来说,如果一种机制不说明CK_MECHANISM_INFO 结构的ulMinKeyLen 和 ulMaxKeyLen 字段,那么这些字段对于那种特定的机制就没有意义。 12.1 RSA 机制 12.1.1 PKCS #1 RSA 密钥对生成 PKCS #1 RSA 密钥对生成机制,表示成CKM_RSA_PKCS_KEY_PAIR_GEN, 是一种基于如PKCS #1中定义的RSA公共密钥密码系统的密钥对生成机制。 它没有参数。 该机制生成RSA公共/私钥对,具有如公共密钥的属性单元的 CKA_MODULUS_BITS 和 CKA_PUBLIC_EXPONENT 属性中规定的那样的特定的位中模长和公共指数。 这种机制把CKA_CLASS, CKA_KEY_TYPE, CKA_MODULUS, 和 CKA_PUBLIC_EXPONENT 属性贡献给新的公共密钥。它把CKA_CLASS 和 CKA_KEY_TYPE 属性贡献给新的私钥;它还可以把某些下面属性贡献给新的私钥:CKA_MODULUS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT, CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT (见章节). 。由这些RSA公共 和 私有类型支持的其它属性(尤其是指示这些密钥支持哪些函数的标志)衣能在这些密钥的属性单元中加以说明,否则赋予缺省初始值。 对于下列机制可以使用由该机制产生的密钥,这些机制是:PKCS #1 RSA; ISO/IEC 9796 RSA; X.509 (raw) RSA; PKCS #1 RSA with MD2; PKCS #1 RSA with MD5; PKCS #1 RSA with SHA-1; 和 OAEP 密钥 wrapping for SET. 对于该机制来说,CK_MECHANISM_INFO 结构的ulMinKeySize 和ulMaxKeySize 字段规定位中RSA模长的支持范围。 12.1.2 PKCS #1 RSA PKCS #1 RSA 机制,表示成CKM_RSA_PKCS, 是一种基于PKCS#1 RSA公共密钥加密系统和块格式的多用途机制。它支持单方加密和脱密;单方签名和验证带消息恢复和不带消息恢复;密钥加密和密钥脱密。这种机制只对应涉及RSA的PKCS#1的这部分;它不计算如PKCS#1中md2withRSAEncryption 和 md5withRSAEncryption 算法规定的消息摘要或DigestInfo 编码。 该机制没有参数。 该机制可以加密和脱密适宜长度的任何保密密钥。当然,一个特定的令牌可能不能加密/脱密它支持的每一个适宜长度的保密密钥。对于加密,加密操作的”input”是被加密的这个密钥的CKA_VALUE 属性的值;对于脱密情况类似。这种机制不加密密钥或关于这个密钥的其它信息,密钥长度除外;该应用程序必须独立地传送它们。尤其是,在脱密时这种机制只把CKA_CLASS 和 CKA_VALUE (和 CKA_VALUE_LEN, 如果该密钥有它的话)属性贡献给恢复的密钥;其它属性必须在属性单元中规定。 密钥类型和数据长度列于下表。对于加密、脱密、签名和签名验证,输入和输出数据可以在存储器中同一单元上开始。表中,k 是RSA模(modulus)的字节中的长度。 表 63, PKCS #1 RSA: 密钥和数据长度 函数 密钥类型 输入长度 输出长度 说明 C_Encrypt1 RSA 公共密钥  k-11 k block type 02 C_Decrypt1 RSA 私钥 k  k-11 block type 02 C_Sign1 RSA 私钥  k-11 k block type 01 C_SignRecover RSA 私钥  k-11 k block type 01 C_Verify1 RSA 公共密钥  k-11, k2 N/A block type 01 C_VerifyRecover RSA 公共密钥 k  k-11 block type 01 C_WrapKey RSA 公共密钥  k-11 k block type 02 C_UnwrapKey RSA 私钥 k  k-11 block type 02 1 只进行单方操作。 2 数据长度,签名长度。 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和 ulMaxKeySize 字段规定所支持的位中RSA模长的范围。 12.1.3 PKCS #1 RSA OAEP 机制参数 CK_RSA_PKCS_MGF_TYPE; CK_RSA_PKCS_MGF_TYPE_PTR 当格式化PKCS#1 OAEP加密方案的一个消息块时,CK_RSA_PKCS_MGF_TYPE 用来指示消息生成函数(MGF) 施加给一个消息块。定义如下: typedef CK_ULONG CK_RSA_PKCS_MGF_TYPE; 在PKCS #1 v2.0. 中定义了下列MGF。下表列出所定义的函数。 表 64, PKCS #1 RSA: 消息生成函数 源表示符 值 CKG_MGF1_SHA1 0x00000001 CK_RSA_PKCS_MGF_TYPE_PTR 是CK_RSA_PKCS_ MGF_TYPE的指针。 CK_RSA_PKCS_OAEP_SOURCE_TYPE; CK_RSA_PKCS_OAEP_SOURCE_TYPE_PTR 对于PKCS #1 OAEP 加密方案当将一个消息块格式化时,则使用CK_RSA_PKCS_OAEP_SOURCE_TYPE 来指示编码参数的源。定义如下: typedef CK_ULONG CK_RSA_PKCS_OAEP_SOURCE_TYPE; 在PKCS #1 v2.0. 中定义了下列编码参数源。下表列出所定义的源以及用于下面定义的CK_RSA_PKCS_OAEP_PARAMS 结构中pSourceData 字段的相应的数据类型。 表 65, PKCS #1 RSA OAEP: 编码参数源 源标识符 值 数据类型 CKZ_DATA_SPECIFIED 0x00000001 含编码 参数值的CK_BYTE 的阵列。如果该参数为空,则 pSourceData 必须是 NULL ,ulSourceDataLen 必须是0。 CK_RSA_PKCS_OAEP_SOURCE_TYPE_PTR 是 CK_RSA_PKCS_OAEP_SOURCE_TYPE的指针。 CK_RSA_PKCS_OAEP_PARAMS; CK_RSA_PKCS_OAEP_PARAMS_PTR CK_RSA_PKCS_OAEP_PARAMS 是给CKM_RSA_PKCS_OAEP 机制提供参数的结构。该结构定义如下: typedef struct CK_RSA_PKCS_OAEP_PARAMS { CK_MECHANISM_TYPE hashAlg; CK_RSA_PKCS_OAEP_MGF_TYPE mgf; CK_RSA_PKCS_OAEP_SOURCE_TYPE source; CK_VOID_PTR pSourceData; CK_ULONG ulSourceDataLen; } CK_RSA_PKCS_OAEP_PARAMS; 该结构的字段具有下面的含义: hashAlg 用来计算编码参数的摘要的消息摘要算法的机制ID mgf 在编码的块上使用的屏蔽生成函数 source 编码参数的源 pSourceData 用作编码参数源的输入的数据 ulSourceDataLen 编码参数源输入的长度 CK_RSA_PKCS_OAEP_PARAMS_PTR 是CK_RSA_PKCS_OAEP_PARAMS的指针。 12.1.4 PKCS #1 RSA OAEP PKCS #1 RSA OAEP 机制,表示成CKM_RSA_PKCS_OAEP,是一种基于RSA公共密钥加密系统和PKCS#1中定义的OAEP块格式的多用途机制。它支持单个部分的加密和脱密;密钥加密;密钥脱密。 它有一个参数,一个CK_RSA_PKCS_OAEP_PARAMS 结构。 该机制可以加密和脱密任意适宜长度的保密密钥。当然,一个特定的令牌不可能加密/脱密每个适宜长度的它支持的保密密钥。对于加密,加密操作的“input”是被加密的这个密钥的CKA_VALUE 属性的值;对于脱密情况类似。该机制不加密密钥类型或关于这个密钥的任何其它信息,密钥长度除外;应用程序必须分别传送它们。尤其是在脱密期间,该机制只将CKA_CLASS 和 CKA_VALUE (和CKA_VALUE_LEN ,如果该密钥有它的话)属性提供给恢复的密钥;其它属性必须在属性单元中规定。 下表列出密钥类型和数据长度的限制。对于加密和脱密,输入和输出数据可以在存储器同一单元上开始。表中,k 是RSA模的字节中的长度,hLen 是由CK_RSA_PKCS_OAEP_PARAMS 结构的hashAlg 字段规定的消息摘要算法的输出长度。 表 66, PKCS #1 RSA OAEP: 密钥和数据长度 函数 密钥类型 输入长度 输出长度 C_Encrypt1 RSA 公共密钥  k-2-2hLen k C_Decrypt1 RSA 私钥 k  k-2-2hLen C_WrapKey RSA 公共密钥  k-2-2hLen k C_UnwrapKey RSA 私钥 k  k-2-2hLen 1 只进行单方操作。 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和 ulMaxKeySize 字段规定所支持的位中RSA模长的范围。 12.1.5 ISO/IEC 9796 RSA ISO/IEC 9796 RSA 机制,表示成CKM_RSA_9796, 是一种基于公共密钥加密系统和ISO/IEC 9796及其附录A中定义的块格式的用于单方签名和验证,带和不带消息恢复的机制。该机制与草案ANSI X9.31(假定X9.31散列值的位中长度为8的倍数)兼容。 这种机制只处理字节串,而ISO/IEC 9796 处理位串。因此执行下列变换: 通过把字节串的第一个字节的最高有效位认为是位串的最左有效位,把字节串尾部字节的最低有效位认为是位串的最右边的位(这是假定这个数据的位中长度是8的倍数)以此将数据在字节串之间进行转换。 通过在左边以0至7个0位填充这个位串使位中产生的长度为8的倍数,并按上边所说的办法转换这个生成的位串,以此把一个签名从一个位串转换成一个字节串;通过按上述办法转换字节串并从左边去除一些位中产生的长度与RSA模的长度相同以此从一个字节串转换成一个位串。 该机制没有参数。 密钥类型和输入输出长度上的限制列于下表。表中,k 是RSA模的字节中的长度。 表 67 , ISO/IEC 9796 RSA: 密钥和数据长度 函数 密钥类型 输入长度 输出长度 C_Sign1 RSA 私钥  k/2 k C_SignRecover RSA 私钥  k/2 k C_Verify1 RSA 公共密钥  k/2, k2 N/A C_VerifyRecover RSA 公共密钥 k  k/2 1 只进行单方操作。 2 数据长度,签名长度。 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和ulMaxKeySize 字段规定所支持位中RSA模长范围。 12.1.6 X.509 (raw) RSA X.509 (raw) RSA 机制,表示成CKM_RSA_X_509, 是一种基于RSA公共密钥加密系统的多用途机制。它支持单个部分加密和脱密;单个部分签名和验证带消息恢复和不带消息恢复;密钥加密。所有这些操作都基于所谓的X.509中认定的“raw”RSA。 正如这里定义的“Raw” RSA 加密一个字节串,是通过把它转换一个整数,第一个最高有效字节,施加“raw” RSA 冥并将结果转换成一个字节串,第一个最高有效字节。输入串,被认为是一个整数,必须小于这个模;输出串也小于这个模。 该机制没有参数。 该机制可以加密和脱密任何适宜长度的保密密钥。当然,一个特定的令牌可能不能加密/脱密每个适宜长度的它支持的保密密钥。对于加密,加密操作的“input”是被加密的这个密钥的CKA_VALUE 属性的值;对于脱密相类似。该机制不加密密钥类型、密钥长度或关于该密钥的任何其它信息;这个应用系统必须独立地传送它们。 然而,X.509没有说明对于RSA加密如何执行填充。对于该机制,填充应当通过以一些0值的字节考虑明文来执行。实际上,为了加密明文字节序列b1 b2 … bn (n  k), Cryptoki 形成 P=2n-1b1+2n-2b2+…+bn。该数必须小于RSA模数。k-字节密文(k 是RSA 模的字节中的长度) 是通过把C提高到RSA私有指数模上RSA模数来产生的。一个k-字节密文C的脱密是通过把C提高到RSA私有指数模上RSA模数,并返回作为恰好k 个字节的一个序列的结果值来实现的。如果形成的这个明文是用来产生一个脱密的密钥,那么从这个字节序列的后端拿走这个密钥长度的属性单元中规定的许多字节。 从技术上来说,上边的这些方法X.509规定的某些细节来看差别不是很大。 使用该机制执行密码操作可能产生错误返回CKR_DATA_INVALID (如果提供的明文具有的长度和RSA模数一样并且数值至少和该模数一样大)和CKR_ENCRYPTED_DATA_INVALID (如果提供的密文具有的长度和RSA模数一样并且数值至少和该模数一样)。 在密钥类型和输入及输出数据长度上的限制列于下面。表中,k 是RSA模数的字节中的长度。 表68, X.509 (Raw) RSA: 密钥和数据长度 函数 密钥类型 输入长度 输出长度 C_Encrypt1 RSA 公共密钥  k k C_Decrypt1 RSA 私钥 k k C_Sign1 RSA 私钥  k k C_SignRecover RSA 私钥  k k C_Verify1 RSA 公共密钥  k, k2 N/A C_VerifyRecover RSA 公共密钥 k k C_WrapKey RSA 公共密钥  k k C_UnwrapKey RSA 私钥 k  k (在属性单元中说明) 1 只进行单方操作。 2 数据长度,签名长度。 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和ulMaxKeySize 字段规定所支持的位中RSA模长范围。 该机制旨在与不执行PKCS #1 或ISO/IEC 9796 块格式的应用兼容。 12.1.7 ANSI X9.31 RSA ANSI X9.31 RSA 机制,表示成CKM_RSA_X9_31, 是一种基于RSA公钥加密系统和ANSI X9.31中定义的块格式的单个部分签名和验证无消息恢复的机制。 该机制施加报头和散列压缩的填充字段。尾字段必须由该应用系统施加。 这种机制只处理字节串,而ANSI X9.31 处理位串。因此执行下面的变换: 通过把字节串的第一个字节的最高有效位解释成位串的最左位,把字节串的尾字节的最低有效位解释成位串的最右位以此将数据在字节和位串格式之间进行转换(这是假定数据的位中长度为8的倍数)。 通过在左边以0-7个0位填充位串使产生的位中的长度为8的倍数并按上边所说的转换所得的位串以此把一个签名从一位串转换成字节串;通过按上述方法转换字节串并从左边移走一些位使所得的位中长度与RSA模的长度一样,以此从一字节串转换成一个位串。 该机制没有参数。 下表列出密钥类型和输入输出长度上的限制。表中,k 是RSA模的字节中的长度。 表69, ANSI X9.31 RSA: 密钥和数据长度 函数 密钥类型 输入长度 输出长度 C_Sign1 RSA 私钥  k-1 k C_Verify1 RSA 公共密钥  k-1, k2 N/A 1 只进行单方操作。 2 数据长度,签名长度。 对于该机制,CK_MECHANISM_INFO 的ulMinKeySize 和ulMaxKeySize 字段规定位中RSA模长的支持范围。 12.1.8 带有MD2, MD5, 或SHA-1 的PKCS #1 RSA 带有MD2机制的PKCS #1 RSA 签名,表示成CKM_MD2_RSA_PKCS, 执行单方和多方数字签名和验证操作,不带消息恢复。所执行的这些操作如带有对象标识符md2WithRSAEncryption 的PKCS #1中介绍的那样。 同样,带有MD5机制的PKCS #1 RSA 签名,表示成CKM_MD5_RSA_PKCS, 执行在带有对象标识符md5WithRSAEncryption 的PKCS#1中介绍的相同的操作。带有SHA-1机制的PKCS#1 RSA签名,表示成CKM_SHA1_RSA_PKCS, 执行同样的操作,但它使用散列函数 SHA-1而不是MD2或MD5。 这些机制都没有参数。 对于这些机制,密钥类型和数据长度上的限制列于下表。表中,k 是RSA模的字节中的长度。对于带有MD2的PKCS #1 RSA 签名和带有MD5的PKCS #1 RSA 签名,必须至少是27;对于带有SHA-1机制的PKCS #1 RSA 签名,k 必须至少是31。 表70, 带有MD2,MD5和SHA-1的PKCS #1 RSA 签名: 密钥和数据长度 函数 密钥类型 输入长度 输出长度 说明 C_Sign RSA 私钥 任意 k block type 01 C_Verify RSA 公共密钥 任意, k2 N/A block type 01 2 数据长度,签名长度。 对于这些机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和ulMaxKeySize 字段规定所支持的位中RSA模长范围。 12.1.9 带有SHA-1的ANSI X9.31 RSA 签名 带有SHA-1机制的ANSI X9.31 RSA 签名,表示成CKM_SHA1_RSA_X9_31, 执行单方和多方数字签名和验证操作,不带消息恢复,所执行的这些操作,如ANSI X9.31中所述。 该机制没有参数。 下表列出了这些机制的密钥类型和数据长度的限制。表中k 是RSA模的字节中的长度。对于带有SHA-1机制的ANSI X9.31 RSA 签名,k 必须至少为23。 表71, 带有SHA-1的ANSI X9.31 RSA 签名: 密钥和数据长度 函数 密钥类型 输入长度 输出长度 C_Sign RSA 私钥 任意 k C_Verify RSA 公共密钥 任意, k2 N/A 2 数据长度,签名长度。 对于这些机制,CK_MECHANISM_INFO结构的ulMinKeySize 和 ulMaxKeySize 字段规定位中RSA模长的支持范围。 12.2 DSA 机制 12.2.1 DSA 密钥对生成 DSA 密钥对生成机制,表示成CKM_DSA_KEY_PAIR_GEN, 是一种基于FIPS PUB 186中定义的数字算法的密钥对生成机制。 该机制没有参数。 该机制使用一个特定的素数(prime)、子素数和基数来产生DSA公共/私钥对,如公共密钥属性单元的CKA_PRIME, CKA_SUBPRIME, 和 CKA_BASE 属性中规定的那样。注意,该版的Cryptoki 不包括生成这些DSA参数的机制。 这种机制把CKA_CLASS, CKA_KEY_TYPE, 和 CKA_VALUE 属性贡献给新的公共密钥,把CKA_CLASS, CKA_KEY_TYPE, CKA_PRIME, CKA_SUBPRIME, CKA_BASE, 和 CKA_VALUE 属性贡献给新的私钥。由DSA公共和私钥类型支持的其它属性(尤其是这些密钥支持哪些函数的标志)也可在这些密钥的属性单元中规定,否则赋予缺省初始值。 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和ulMaxKeySize 字段规定位中所支持的DSA素数长度的范围。 12.2.2 没有散列的DSA 没有散列机制的DSA,表示成CKM_DSA, 是一种基于FIPS PUB 186中定义的数字签名算法用于单方签名和验证的机制。(这种机制仅对应处理20字节散列值的DSA的这一部分;它不计算这个散列值。) 为了实现这种机制的用途,一个DSA签名是一个40字节串,对应DSA值r 和s, 的连接,每一个值代表第一个最高有效字节。 它没有参数。 密钥类型和数据长度的限制列于下表: 表72, DSA: 密钥和数据长度 函数 密钥类型 输入长度 输出长度 C_Sign1 DSA 私钥 20 40 C_Verify1 DSA 公共密钥 20, 402 N/A 1 只进行单方操作。 2 数据长度,签名长度。 对于该机制CK_MECHANISM_INFO结构的ulMinKeySize 和ulMaxKeySize 字段确定位中所支持的DSA素数长度范围。 12.2.3 带有SHA-1的DSA 带有SHA-1机制的DSA ,表示成CKM_DSA_SHA1, 是一种基于FIPS PUB 186中定义的数字签名算法用于单方签名和验证的机制。这种机制计算整个DSA规范(specification),包括带有散列的SHA-1。 为了实现这种机制的用途,一个DSA签名是一个40字节串,对应DSA值r 和s的连接,每个值代表第一个最高有效字节。 该机制没有参数。 密钥类型和数据长度的限制列于下表: 表73, 带有SHA-1的DSA: 密钥和数据类型 函数 密钥类型 输入长度 输出长度 C_Sign1 DSA 私钥 任意 40 C_Verify1 DSA 公共密钥 任意, 402 N/A 2 数据长度,签名长度。 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和ulMaxKeySize 字段规定所支持的位中DSA素数大小范围。 12.2.4 FORTEZZA 时间戳记 FORTEZZA 时间机制,表示成CKM_FORTEZZA_TIMESTAMP, 是一种适用于单方签名和验证的机制。它产生和验证的机制。它产生和验证的这些签名是在所提供的散列值和当前时间上的DSA数字签名。 它没有参数。 密钥类型和数据长度的限制列于下表。输入和输出数据可以在存储器同一单元处开始。 表74, FORTEZZA 时间戳记: 密钥和数据长度 函数 密钥类型 输入长度 输出长度 C_Sign1 DSA 私钥 20 40 C_Verify1 DSA 公共密钥 20, 402 N/A 1 只进行单方操作。 2 数据长度,签名长度。 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和ulMaxKeySize 字段规定位中支持的DSA素数大小的范围。 12.3 关于ECDSA 该文件中的ECDSA (Elliptic Curve Digital Signature Algorithm) 是1997年11月17日的 ANSI X9.62 工作草案中描述的那个ECDSA。希望Cryptoki 参考的该文件的这些部分在最终的ANSI X9.62 文件中不要发生变化,但不保证不发生变化。 在这个工作草案中定义了三种不同的ECDSA: 1. ECDSA使用一个字段,该字段具有奇数数个要素。 2. ECDSA,它使用一个characteristic 2 字段,该字段的要素使用最佳正规基本表示。 3. ECDSA,它使用一个characteristic 2 的字段,该字段的要素使用最佳正规来表示。 Cryptoki 中的ECDSA密钥含有哪种ECDSA适用的信息。最好是能够执行各种操作;然而,这是不需要的。 假如进行建立、生成、推导或脱密未支持类型的(或类型得到支持但长度未受到支持)的ECDSA密钥的尝试,那么这种尝试应以错误代码 CKR_TEMPLATE_INCONSISTENT而告失败。 12.4 ECDSA 机制 12.4.1 ECDSA 密钥对生成 ECDSA 密钥对生成机制,表示成CKM_DSA_KEY_PAIR_GEN, 是一种用于ECDSA的密钥对生成机制。 该机制没有参数。 该机制使用特定的ECDSA参数生成ECDSA公共/私钥对,如公共密钥的属性单元的CKA_ECDSA_PARAMS 属性规定的那样。注意,该版本的Cryptoki 不包括产生这些ECDSA参数的机制。 该机制把CKA_CLASS, CKA_KEY_TYPE, 和 CKA_EC_POINT 属性贡献给新的公共密钥,把CKA_CLASS, CKA_KEY_TYPE, CKA_ECDSA_PARAMS 和 CKA_CKA_VALUE 属性贡献给新的私钥。由ECDSA公共和私钥类型支持的其它属性(尤其是指示这些密钥支持哪些函数的标志)也可在这些密钥的属性单元中规定,否则赋予缺省初始值。 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和 ulMaxKeySize 字段规定所支持的最小位数和最大位数。例如,如果一个Cryptoki 库仅支持使用characteristic 2的字段(它有2200 和 2300 要素),那么ulMinKeySize = 201 和 ulMaxKeySize = 301(当以二进制表示时,2200 这个数是由一个1位后跟200个0位构成。它因此是一个201位的数。同理,2300 是一个301位的数)。 12.4.2 没有散列的ECDSA 没有散列机制的ECDSA,表示成CKM_ECDSA, 用于ECDSA的单方签名和验证的机制。(该机制仅对应处理20字节散列值的ECDSA的这一部分;它不计算这个散列值。) 对于该机制的用途,一个ECDSA签名是一个40字节串,对应 ECDSA值r 和s的连接,每个值代表第一个最高有效字节。 该机制没有参数。 密钥类型和数据长度的限制列于下表: 表75, ECDSA: 密钥和数据长度 函数 密钥类型 输入长度 输出长度 C_Sign1 ECDSA 私钥 20 40 C_Verify1 ECDSA 公共密钥 20, 402 N/A 1 只进行单方操作。 2 数据长度,签名长度。 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和ulMaxKeySize 字段在字段长度中分别规定最小和最大支持的位数。例如,如果一个Cryptoki 仅支持使用characteristic 2 的字段(该字段有2200 和 2300要素),那么ulMinKeySize = 201 和ulMaxKeySize = 301。(当用二进制表示时,2200这个数由一个一位后跟200个0位构成,因此这是一个201位的数。同理,2300是一个301位的数。) 12.4.3 带有SHA-1的ECDSA 带有SHA-1机制的ECDSA ,表示成CKM_ECDSA_SHA1, 是一种用于ECDSA的单方和多方签名和验证的机制。该机制计算整个ECDSA规范,包括带有SHA-1的散列。 对于该机制的用途,一个ECDSA签名是一个40字节串,对应 ECDSA值r 和s的连接,每个值代表第一个最高有效字节。 密钥类型和数据长度的限制列于下表: 表76, ECDSA with SHA-1: 密钥和数据长度 函数 密钥类型 输入长度 输出长度 C_Sign1 ECDSA 私钥 任意 40 C_Verify1 ECDSA 公共密钥 任意, 402 N/A 2 数据长度,签名长度。 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和ulMaxKeySize 字段在字段长度中分别规定最小和最大支持的位数。例如,如果一个Cryptoki 仅支持使用characteristic 2 的字段(该字段有2200 和 2300要素),那么ulMinKeySize = 201 和ulMaxKeySize = 301。(当用二进制表示时,2200这个数由一个一位后跟200个0位构成,因此这是一个201位的数。同理,2300是一个301位的数。) 12.5 Diffie-Hellman 机制 12.5.1 PKCS #3 Diffie-Hellman 密钥对生成 PKCS #3 Diffie-Hellman 密钥对生成机制,表示成CKM_DH_PKCS_KEY_PAIR_GEN, 是一种基于PKCS #3中定义的Diffie-Hellman 密钥协议的密钥对生成机制。(它与PKCS #3调用“phase I”的情况相类似。) 它没有参数。 该机制使用公共属性单元的CKA_PRIME 和 CKA_BASE 属性中规定的一个特定的素数和基数来产生Diffie-Hellman 公共/私钥对。如果规定私钥的CKA_VALUE_BITS 属性,那么该机制限制私有值的位中的长度,如PKCS#3中介绍的那样。注意,该版本的Cryptoki不包括产生一个素数和基数的机制。 该机制把CKA_CLASS, CKA_KEY_TYPE, 和 CKA_VALUE 属性贡献给新的公共密钥;把CKA_CLASS, CKA_KEY_TYPE, CKA_PRIME, CKA_BASE, 和 CKA_VALUE (以及 CKA_VALUE_BITS 属性,假如在这个属性单元中没有提供它)属性贡献给新的私钥密钥;由Diffie-Hellman 公共和私钥类型要求的其它属性必须在这些属性单元中规定。 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和 ulMaxKeySize 字段规定位中所支持的Diffie-Hellman 素数大小的范围。 12.5.2 PKCS #3 Diffie-Hellman 密钥派生 PKCS #3 Diffie-Hellman 密钥派生机制,表示成CKM_DH_PKCS_DERIVE, 是一种基于 Diffie-Hellman 密钥协定的密钥派生机制,如PKCS#3中定义的那样。(它类似于PKCS #3 调用“phase II”的情况。) 它有一个参数,该参数是密钥一致性协议中它方的公共值,表示成Cryptoki “Big integer” (就是说一个字节序列,第一个最高有效字节)。 该机制从一个Diffie-Hellman 私钥和它方的公共值中派生一个保密密钥。它根据PKCS#3从公共值和私钥中计算一个Diffie-Hellman 保密值并根据这个属性单元的 CKA_KEY_TYPE 属性截取结果,如果它有一个属性并且密钥类型支持它,即属性单元的 CKA_VALUE_LEN 属性的话。(截取是从这个保密值的前端去除一些字节。)该机制提供这个结果作为新密钥的CKA_VALUE 属性;密钥类型需要的其它属性必须在这个属性单元中规定。 派生密钥继承了基本密钥的CKA_SENSITIVE, CKA_ALWAYS_SENSITIVE, CKA_EXTRACTABLE, 和 CKA_NEVER_EXTRACTABLE 属性的值,但 CKA_SENSITIVE 和 CKA_EXTRACTABLE 属性的值可能超越了派生密钥的这个属性单元。当然,如果基本密钥具有设置成TRUE的CKA_ALWAYS_SENSITIVE 属性,那么这个属性单元可以不规定派生密钥应有设置成FALSE的CKA_SENSITIVE 属性;同样,如果基本密钥具有设置成TRUE的CKA_NEVER_EXTRACTABLE 属性,那么这个属性单元可以不规定派生的密钥应有设置成TRUE的CKA_EXTRACTABLE 属性。 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和 ulMaxKeySize 字段规定位中所支持的Diffie-Hellman 素数大小的范围。 12.6 KEA 机制参数 CK_KEA_DERIVE_PARAMS; CK_KEA_DERIVE_PARAMS_PTR CK_KEA_DERIVE_PARAMS 是一种结构,该结构给CKM_KEA_DERIVE 机制提供这些参数。规定如下: typedef struct CK_KEA_DERIVE_PARAMS { CK_BBOOL isSender; CK_ULONG ulRandomLen; CK_BYTE_PTR pRandomA; CK_BYTE_PTR pRandomB; CK_ULONG ulPublicDataLen; CK_BYTE_PTR pPublicData; } CK_KEA_DERIVE_PARAMS; 该结构的这些字段具有下列含义: isSender 用来产生密钥(叫TEK)的任选项(Option)。如果发方(发起人)产生这个TEK,该值为TRUE,如果接收者正在再生这个TEK,则该值为FALSE。 ulRandomLen 字节中随机Ra 和 Rb的长度 pRandomA 指向Ra数据的指针 pRandomB 指向Rb数据的指针 ulPublicDataLen 另一方的KEA公共密钥长度 pPublicData 指向另一方的KEA公共密钥值的指针 CK_KEA_DERIVE_PARAMS_PTR 是一个指向一个CK_KEA_DERIVE_PARAMS的指针。 12.7 KEA 机制 12.7.1 KEA 密钥对生成 KEA 密钥对生成机制,表示成CKM_KEA_KEY_PAIR_GEN, 产生密钥交换算法的密钥对,如NIST的“SKIPJACK 和KEA 算法说明 1998年5月29日2.0版”所定义的那样。 它没有参数。 该机制使用一个特定的素数、子素数和基数来产生KEA公共/私钥对,如公共密钥的属性单元的CKA_PRIME, CKA_SUBPRIME, 和 CKA_BASE 属性中规定的那样。该版本的 Cryptoki 不包括产生这些KEA参数的机制。 该机制把CKA_CLASS, CKA_KEY_TYPE 和 CKA_VALUE 属性贡献给新的公共密钥,把CKA_CLASS, CKA_KEY_TYPE, CKA_PRIME, CKA_SUBPRIME, CKA_BASE, 和 CKA_VALUE 属性贡献给新的私钥。由KEA公共和私钥类型支持的其它属性(尤其是指示这些密钥支持哪些函数的标志)也可在这些密钥的属性单元中规定,否则赋予缺省初始值。 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和 ulMaxKeySize 字段规定位中所支持的KEA素数大小的范围。 12.7.2 KEA 密钥派生 KEA 密钥派生机制,表示成CKM_KEA_DERIVE, 是一种基于KEA(密钥交换算法)的密钥派生机制,如1998年5月29日2.0版的NIST的“SKIPJACK 和 KEA 算法说明”定义的那样。 它有一个参数,一个CK_KEA_DERIVE_PARAMS 结构。 该机制派生一个保密值并根据这个属性单元的CKA_KEY_TYPE 属性截取结果,如果它有一个属性并且密钥类型支持它,即一个密钥单元的CKA_VALUE_LEN 属性(截取是从保密值的前端移走若干字节)。该机制提供这个结果作为新密钥的CKA_VALUE 属性;这种密钥类型需要的其它属性必须在这个单元中规定。 正如这个规范定义的那样,可以两种不同的工作方式使用KEA:全方位(full mode)和e-mail方式。全方式是一个两阶段的密钥派生序列,它要求实时的参数交换。E-mail方式是一个一阶段密钥派生序列,它不需要实时的参数交换。按照惯例,e-mail方式对于KEA参数Rb (pRandomB)被称为使用1的固定的值。 该机制的工作取决于所提供的CK_KEA_DERIVE_PARAMS 结构中的两个值。详细情况见下表。注意,在任何情况下,由参数结构字段pRandomA 和 pRandomB 指向的数据缓冲器必须在调用C_DeriveKey 之间由呼叫着分配。另外,由pRandomA 和 pRandomB 指向的值被表示成Cryptoki “Big integer” 数据(即一个字节序列,第一个最高有效字节)。 表77, KEA 参数值和操作 Value of boolean isSender Value of big integer pRandomB 令牌动作 (检查数据和属性单元值之后) TRUE 0 计算KEA Ra 值,将其存入pRandomA, 返回 CKR_OK。不建立派生的密钥体。 TRUE 1 计算KEA Ra 值。将其存入 pRandomA, 使用 e-mail 方式派生密钥值,建立密钥体,返回 CKR_OK。 TRUE >1 计算KEA Ra 值,将其存入pRandomA, 使用全方式派生密钥值,建立密钥体,返回 CKR_OK。 FALSE 0 计算KEA Rb 值,将其存入pRandomB, 返回 CKR_OK。不建立派生的密钥体。 FALSE 1 使用e-mail 方式派生密钥体,建立密钥体,返回 CKR_OK。 FALSE >1 使用全方式派生密钥值,建立密钥体,返回 CKR_OK。 注意,参数值 pRandomB==0 是一个标记,就是说KEA机制正在被调用以便(分别为发送者或接收者)计算这方的公共随机值(Ra 或 Rb),而不是派生一个密钥。在这些情况下,任何作为C_DeriveKey pTemplate 变量而提供的客体属性单元都应忽略。 派生的密钥继承了基本密钥的CKA_SENSITIVE, CKA_ALWAYS_SENSITIVE, CKA_EXTRACTABLE, 和 CKA_NEVER_EXTRACTABLE 属性。但对于派生的密钥, CKA_SENSITIVE 和 CKA_EXTRACTABLE 属性的值可能超越这个属性单元。当然,如果基本密钥具有设置成TRUE的CKA_ALWAYS_SENSITIVE 属性,那么这个属性单元可以不规定,派生的密钥应有设置成TRUE的CKA_SENSITIVE 属性。同样,如果基本密钥具有设置成TRUE的CKA_NEVER_EXTRACTABLE 属性,那么该属性单元可以不规定,派生的密钥应有设置成TRUE的CKA_EXTRACTABLE 属性。 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和 ulMaxKeySize 字段规定位中所支持的KEA素数大小的范围。 12.8 类属保密密钥机制 12.8.1 类属保密密钥生成 类属保密密钥生成机制,表示成CKM_GENERIC_SECRET_KEY_GEN, 用来产生类属保密密钥。所生成的密钥具有转到C_GenerateKey 调用的属性单元中提供的任何属性, CKA_VALUE_LEN 属性规定要生成的密钥的长度。 它没有参数。 所提供的这个属性单元必须为CKA_VALUE_LEN 属性规定一个值。如果这个属性单元规定一个客体类型(object type)和一个类(class),那么它们必须具有下列值: CK_OBJECT_CLASS = CKO_SECRET_KEY; CK_KEY_TYPE = CKK_GENERIC_SECRET; 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和 ulMaxKeySize 字段规定位中所支持的密钥长度范围。 12.9 加密/脱密私钥(RSA, Diffie-Hellman, 和 DSA) 版本2.01及其以上版本的Cryptoki 允许使用保密密钥来加密和脱密RSA私钥, Diffie-Hellman 私钥和DSA私钥。对于加密,一个私钥是根据PKCS #8的 PrivateKeyInfo ASN.1 类型编码-BER。对于保密密钥类型,PKCS#8为保密密钥的类型要求一个算法标识符。用于所需算法标识符的目标标识符如下: rsaEncryption OBJECT IDENTIFIER ::= { pkcs-1 1 } dhKeyAgreement OBJECT IDENTIFIER ::= { pkcs-3 1 } id-dsa OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 1 } where pkcs-1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) US(840) rsadsi(113549) pkcs(1) 1 } pkcs-3 OBJECT IDENTIFIER ::= { iso(1) member-body(2) US(840) rsadsi(113549) pkcs(1) 3 } 用于这些算法标识符的这些参数分别具有下面的类型: NULL DHParameter ::= SEQUENCE { prime INTEGER, -- p base INTEGER, -- g privateValueLength INTEGER OPTIONAL } Dss-Parms ::= SEQUENCE { p INTEGER, q INTEGER, g INTEGER } 在PrivateKeyInfo 类型中: RSA 私钥是根据PKCS #1的 RSAPrivateKey ASN.1 类型的编码的BER。对于专用于Cryptoki的 RSA私钥体的所有属性,这种类型要求的值对于专门用于Cryptoki 的RSA私钥体的所有属性都是存在的。换句话说,如果一个Cryptoki库没有适用于一个RSA私钥的CKA_MODULUS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT, CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT2, 和 CKA_COEFFICIENT 值,那么它就不能建立该密钥的 RSAPrivateKey BER-编码,因此就不能准备用它去加密。 Diffie-Hellman 私钥表示成BER-编码的ASN.1 类型INTEGER。 DSA 私钥表示成BER-编码的ASN.1 类型INTEGER。 一旦一个私钥被BER编码成一个PrivateKeyInfo 类型,那么用这个保密密钥加密所得的字节串。这种加密必须以CBC方式加上PKCS填充来完成。 将一个加密的私人密钥脱密不执行上述过程。CBC-加密的密文被脱密,并去除这个PKCS填充。由此而获得的数据作为一个PrivateKeyInfo 类型来分析,并得出加了密的密钥。如果原始加了密的密钥不能正确地分析,或它的类型与这个新密钥的属性单元中规定的密钥类型不符合,则产生错误。这种脱密机制只将PrivateKeyInfo 类型中规定的那些属性贡献给新近脱了密的密钥;其它属性必须在这个属性单元中规定,或将采用它们的缺省值。 PKCS #11 2.0版和2.01版的草稿使用对象标识符 DSA OBJECT IDENTIFIER ::= { algorithm 12 } algorithm OBJECT IDENTIFIER ::= { iso(1) identifier-organization(3) oiw(14) secsig(3) algorithm(2) } 相关的参数 DSAParameters ::= SEQUENCE { prime1 INTEGER, -- modulus p prime2 INTEGER, -- modulus q base INTEGER -- base g } 用于加密DSA私钥。注意,即使保存DSA参数的这两个结构出现的相同,当它们的一些例子被编码时,这两个对应的对象标识符仍是不同的。 12.10 关于RC2 RC2是一种由RSA Data Security注册或专利的块密码。它有一个可变的密钥长度和一个附加参数,即“RC2搜索空间中位的有效数字” (effective number of bits in the RC2 search space), 可取1-1024范围的值。RC2搜索空间中位的有效数字有时由一个RC2“版本号”(version number)规定;然而这个版本号与“位的有效数字” (effective number of bits )不是同一个东西。有一个典型的方法从一个转换到另一个。 12.11 RC2 机制参数 CK_RC2_PARAMS; CK_RC2_PARAMS_PTR CK_RC2_PARAMS 给CKM_RC2_ECB 和 CKM_RC2_MAC 机制提供这些参数。它在RC2搜索空间保持位的有效数字。定义如下: typedef CK_ULONG CK_RC2_PARAMS; CK_RC2_PARAMS_PTR 是CK_RC2_PARAMS的一个指针。 CK_RC2_CBC_PARAMS; CK_RC2_CBC_PARAMS_PTR CK_RC2_CBC_PARAMS 是一种给CKM_RC2_CBC 和 CKM_RC2_CBC_PAD 机制提供参数的结构。它的定义如下: typedef struct CK_RC2_CBC_PARAMS { CK_ULONG ulEffectiveBits; CK_BYTE iv[8]; } CK_RC2_CBC_PARAMS; 这种结构的字段具有如下含义: ulEffectiveBits RC2搜索空间里的有效数字 iv 密码块链接方式的初始向量(IV) CK_RC2_CBC_PARAMS_PTR 是CK_RC2_CBC_PARAMS的一个指针。 CK_RC2_MAC_GENERAL_PARAMS; CK_RC2_MAC_GENERAL_PARAMS_PTR CK_RC2_MAC_GENERAL_PARAMS 是一种给CKM_RC2_MAC_GENERAL 机制提供参数的结构。定义如下: typedef struct CK_RC2_MAC_GENERAL_PARAMS { CK_ULONG ulEffectiveBits; CK_ULONG ulMacLength; } CK_RC2_MAC_GENERAL_PARAMS; 该结构的字段具有如下定义: ulEffectiveBits RC2搜索空间里的位的有效数字 ulMacLength 字节中生成MAC的长度 CK_RC2_MAC_GENERAL_PARAMS_PTR 是CK_RC2_MAC_GENERAL_PARAMS的一个指针。 12.12 RC2 机制 12.12.1 RC2 密钥生成 RC2 密钥生成机制,表示成CKM_RC2_KEY_GEN, 是一个用于RSA Data Security的块密码RC2的密钥生成机制。 它没有参数。 该机制生成字节中具有特定长度的RC2密钥,如该密钥的属性单元的CKA_VALUE_LEN 属性中规定的那样。 该机制把CKA_CLASS, CKA_KEY_TYPE, 和 CKA_VALUE 属性贡献给新的密钥。由RC2密钥类型支持的其它属性(尤其是,指示该密钥支持哪些函数的标志)可以在该密钥的属性单元中规定,否则赋予缺省初始值。 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和 ulMaxKeySize 字段规定位中所支持的RC2密钥长度位中的范围。 12.12.2 RC2-ECB RC2-ECB, 表示成CKM_RC2_ECB, 是一种根据RSA Data Security 块密码RC2和FIPS PUB 81中定义的电子代码手册方式用于单方和多方加密和脱密;密钥加密和脱密的机制。 它有一个参数,即一个CK_RC2_PARAMS, 它指示RC2搜索空间中位的有效数字。 该机制可以加密和脱密任何一个保密密钥。当然,一个特定的令牌可能不能加密/脱密它支持的每个保密密钥。对于加密,该机制加密这个要加密的密钥的CKA_VALUE 属性的值,在尾端填充最高7个零字节,以使所得到的长度是8的倍数。输出数据和被填充的输入数据的长度一样。它不加密密钥类型、密钥长度或关于该密钥的任何其它信息;该应用系统必须独立地传送它们。 对于脱密,该机制脱密加了密的密钥,并根据这个属性单元的CKA_KEY_TYPE 属性截取结果,如果它有一个并且密钥类型支持它的属性单元的CKA_VALUE_LEN 属性的话。该机制提供这个结果作为新密钥的CKA_VALUE 属性;由密钥类型要求的其它属性必须在这个属性单元中规定。 密钥类型和数据长度的限制在下表中列出: 表78, RC2-ECB: 密钥和数据长度限制 函数 密钥类型 输入长度 输出长度 说明 C_Encrypt RC2 8的倍数 与输入长度相同 没有最终部分 C_Decrypt RC2 8的倍数 与输入长度相同 没有最终部分 C_WrapKey RC2 任意 输入长度舍入到8的倍数 C_UnwrapKey RC2 8的倍数 由未被加密的密钥类型或 CKA_VALUE_LEN决定 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和 ulMaxKeySize 字段规定位中所支持的RC2有效数字的范围。 12.12.3 RC2-CBC RC2-CBC, 表示成CKM_RC2_CBC, 是一种根据RSA Data Security 块密码RC2和FIPS PUB 81中定义的电子代码手册方式用于单方和多方加密和脱密;密钥加密和脱密的机制。 它有一个参数,即CK_RC2_CBC_PARAMS 结构,这里第一个字段指示RC2搜索空间中位的有效数字,而下一个字段是密码块连接方式的初始向量。 该机制可以加密和脱密任何一个保密密钥。当然,一个特定的令牌可能不能加密/脱密它支持的每个保密密钥。对于加密,该机制加密这个要加密的密钥的CKA_VALUE 属性的值,在尾端填充最高7个零字节,以使所得到的长度是8的倍数。输出数据和被填充的输入数据的长度一样。它不加密密钥类型、密钥长度或关于该密钥的任何其它信息;该应用系统必须独立地传送它们。 对于脱密,该机制脱密加了密的密钥,并根据这个属性单元的CKA_KEY_TYPE 属性截取结果,如果它有一个并且密钥类型支持它的属性单元的CKA_VALUE_LEN 属性的话。该机制提供这个结果作为新密钥的CKA_VALUE 属性;由密钥类型要求的其它属性必须在这个属性单元中规定。 密钥类型和数据长度的限制在下表中列出: 表79, RC2-CBC: 密钥和数据长度 函数 密钥类型 输入长度 输出长度 说明 C_Encrypt RC2 8的倍数 与输入长度相同 没有最终部分 C_Decrypt RC2 8的倍数 与输入长度相同 没有最终部分 C_WrapKey RC2 任意 输入长度舍入到8的倍数 C_UnwrapKey RC2 8的倍数 由未被加密的密钥类型或 CKA_VALUE_LEN决定 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和 ulMaxKeySize 字段规定位中所支持的RC2有效数字的范围。 12.12.4 带有PKCS填充的RC2-CBC 带有PKCS填充的RC2-CBC,表示成CKM_RC2_CBC_PAD, 是一种根据RSA Data Security 的块密码RC2和FIPS PUB 81中定义的密码块链接方式用于单方和多方加密和脱密;密钥加密和脱密的机制。 它有一个参数,即CK_RC2_CBC_PARAMS 结构,这里第一个字段指示RC2搜索空间中位的有效数字,而下一字段是初始向量。 该机制中的PKCS 填充允许明文值的长度从密文值中恢复。因此,当使用该机制脱密这些密钥时,不应对CKA_VALUE_LEN 属性规定值。 除了能加密和脱密保密密钥外,该机制还能加密和脱密和RSA, Diffie-Hellman, 和 DSA 私钥(详细见章节 )。当加密和脱密密钥不适用加密和脱密私人密钥时,则下表列出了数据长度限制。 密钥类型和数据长度限制列于下表: 表80, 带有PKCS填充的RC2-CBC : 密钥和数据长度 函数 密钥类型 输入长度 输出长度 C_Encrypt RC2 任意 输入长度舍入到8的倍数 C_Decrypt RC2 8的倍数 在1到8字节之间,比输入长度短 C_WrapKey RC2 任意 输入长度舍入到8的倍数 C_UnwrapKey RC2 8的倍数 在1到8字节之间,比输入长度短 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和 ulMaxKeySize 字段规定位的所支持的RC2有效数字的范围。 12.12.5 通用长度RC2-MAC 通用长度RC2-MAC, 表示成CKM_RC2_MAC_GENERAL, 是一种基于RSA Data Security的块密码RC2和FIPS PUB 113中定义的数据鉴别用于单方和多方签名和验证。 它有一个参数,即CK_RC2_MAC_GENERAL_PARAMS结构,它规定RC2搜索空间中位的有效数字和该机制所需的输出长度。 该机制的输出字节是从MACing 进程中产生的最终RC2密码块的开始处取的。 密钥类型和数据长度的限制列于下表: 表81, 通用长度RC2-MAC: 密钥和数据长度 函数 密钥类型 数据长度 签名长度 C_Sign RC2 任意 0-8, 与参数中规定的相同 C_Verify RC2 任意 0-8, 与参数中规定的相同 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和ulMaxKeySize 字段规定位的所支持的RC2有效数字范围。 12.12.6 RC2-MAC RC2-MAC, 表示成CKM_RC2_MAC, 是通用长度RC2-MAC 机制的特例(请参见章节 )。它是取CK_RC2_PARAMS 参数,而不是取CK_RC2_MAC_GENERAL_PARAMS 参数,只含RC2搜索空间中位的有效数字。RC2-MAC 始终产生和验证4字节MAC。 密钥类型和数据长度的限制列于下表: 表82, RC2-MAC: 密钥和数据长度 函数 密钥类型 数据长度 签名长度 C_Sign RC2 任意 4 C_Verify RC2 任意 4 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和ulMaxKeySize 字段规定位的所支持的RC2有效数字范围。 12.13 RC4 机制 12.13.1 RC4 密钥生成 RC4密钥生成机制,表示成CKM_RC4_KEY_GEN, 是用于RSA Data Security的专有流密码RC4的一种密钥生成机制。 它没有参数。 该机制生成字节中具有特定长度的RC4密钥,如该密钥的属性单元的CKA_VALUE_LEN 属性中规定的那样。 该机制把CKA_CLASS, CKA_KEY_TYPE, 和 CKA_VALUE 属性贡献给新的密钥。由RC2密钥类型支持的其它属性(尤其是,指示该密钥支持哪些函数的标志)可以在该密钥的属性单元中规定,否则赋予缺省初始值。 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和 ulMaxKeySize 字段规定位中所支持的RC4密钥长度位中的范围。 12.13.2 RC4 RC4, 表示成CKM_RC4, 是一种基于RSA Data Security的专有流密码RC4的用于单方和多方加密、脱密的机制。 它没有参数。 下表归纳了密钥类型、输入和输出数据长度的约束: 表83, RC4: 密钥和数据长度 函数 密钥类型 输入长度 输出长度 说明 C_Encrypt RC4 任意 与输入长度相同 没有最终部分 C_Decrypt RC4 任意 与输入长度相同 没有最终部分 对于该机制而言,CK_MECHANISM_INFO 结构的ulMinKeySize 和 ulMaxKeySize 字段规定位中所支持的RC4密钥长度的范围。 12.14 关于RC5 RC5 是参数化分块密码,RSA Data Security 已经申请了专利。它有不同的字长,不同的密钥长度,不同数量的舍入。RC5的块长始终等于它的字长的两倍。 12.15 RC5 机制参数 CK_RC5_PARAMS; CK_RC5_PARAMS_PTR CK_RC5_PARAMS 把这些参数提供给CKM_RC5_ECB 和 CKM_RC5_MAC 机制。其定义如下: typedef struct CK_RC5_PARAMS { CK_ULONG ulWordsize; CK_ULONG ulRounds; } CK_RC5_PARAMS; 结构的字段有如下的含义: ulWordsize 字节中RC5密码的字长 ulRounds RC5密码的舍入的数 CK_RC5_PARAMS_PTR 是CK_RC5_PARAMS的一个指针。 CK_RC5_CBC_PARAMS; CK_RC5_CBC_PARAMS_PTR CK_RC5_CBC_PARAMS 是一个结构,它为CKM_RC5_CBC 和 CKM_RC5_CBC_PAD 机制提供参数。其定义如下: typedef struct CK_RC5_CBC_PARAMS { CK_ULONG ulWordsize; CK_ULONG ulRounds; CK_BYTE_PTR pIv; CK_ULONG ulIvLen; } CK_RC5_CBC_PARAMS; 该结构的字段具有如下含义: ulWordsize 字节中RC5密码的字长 ulRounds RC5密码的舍入的数 pIv CBC加密的初始化向量(IV) 的指针 ulIvLen 初始化向量长度(必须与块长相同) CK_RC5_CBC_PARAMS_PTR 是CK_RC5_CBC_PARAMS的一个指针。 CK_RC5_MAC_GENERAL_PARAMS; CK_RC5_MAC_GENERAL_PARAMS_PTR CK_RC5_MAC_GENERAL_PARAMS 是一种结构,它为CKM_RC5_MAC_GENERAL 机制提供参数。其定义如下: typedef struct CK_RC5_MAC_GENERAL_PARAMS { CK_ULONG ulWordsize; CK_ULONG ulRounds; CK_ULONG ulMacLength; } CK_RC5_MAC_GENERAL_PARAMS; 结构的字段有如下含义: ulWordsize 字节中RC5密码的字长 ulRounds RC5密码的舍入的数 ulMacLength 字节中所生成的MAC的长度 CK_RC5_MAC_GENERAL_PARAMS_PTR 是CK_RC5_MAC_GENERAL_PARAMS的指针。 12.16 RC5 机制 12.16.1 RC5 密钥生成 RC5 密钥生成机制,表示成CKM_RC5_KEY_GEN, 是一种用于RSA Data Security的块密码RC5的密钥生成机制。 它没有参数。 象在密钥模板的CKA_VALUE_LEN 属性中规定的一样,该机制生成RC5密钥,在字节中具有特定长度。 该机制为新密钥提供CKA_CLASS, CKA_KEY_TYPE和 CKA_VALUE 属性。由RC5密钥类型支持的其它属性(尤其是该密钥支持哪些函数的标志)可在该密钥的这个属性单元中规定,否则赋予缺省初始值。 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和 ulMaxKeySize 字段规定了字节中支持的RC5密钥长度的范围。 12.16.2 RC5-ECB RC5-ECB, 表示成CKM_RC5_ECB, 是一种基于RSA Data Security的块密码RC5和FIPS PUB 81中定义的电子代码簿方式。 它有一个参数,即CK_RC5_PARAMS, 指示使用的加密的字长和舍入的数字。 这个机制能加密和脱密任何保密密钥。当然,一个特定的令牌可能不能加密/脱密它所支持的每一个保密的密钥。对于加密,该机制加密被加密的CKA_VALUE 属性的值,在尾部用零字节填充,使所得的长度是密钥块长度(字长的两倍)的倍数。输出数据与填充的输入数据相同。它不加密密钥类型,密钥长度,或任何其它的有关密钥的信息,应用程序必须独立传送它们。 对于脱密,该机制脱密加了密的密钥,并根据属性单元的CKA_KEY_TYPE 属性截取结果。如果它有一个且密钥支持它属性单元的CKA_VALUE_LEN 属性;密钥类型所需的其它属性必须在这个属性单元中确定。 密钥类型和数据长度的限制在下表中列出: 表84, RC5-ECB: 密钥和数据长度 函数 密钥类型 输入长度 输出长度 说明 C_Encrypt RC5 块长的倍数 与输入长度相同 没有最终部分 C_Decrypt RC5 块长的倍数 与输入长度相同 没有最终部分 C_WrapKey RC5 任意 输入长度舍入到块长的倍数 C_UnwrapKey RC5 块长的倍数 由被脱密的密钥类型或 CKA_VALUE_LEN决定 12.16.3 RC5-CBC RC5-CBC, 表示成CKM_RC5_CBC, 是一种基于RSA数据安全的块密码RC5和FIPS PUB 81中定义的密码块链接方式的单方和多方加密和脱密、密钥加密、密钥脱密的机制。 它有一个参数,即CK_RC5_CBC_PARAMS 结构,该参数规定要用的字长和加密的舍入数字,以及密码块链接方式的初始化向量。 该机制能加密和脱密的密钥。当然,一个特定的令牌可能不能加密/脱密它所支持的每一个保密密钥。就加密而言,该机制加密被加密的密钥的CKA_VALUE 属性的值,末尾填完7个0字节,使产生的长度是8的倍数。输出数据和填充输入数据的长度一样。它不加密密钥类型、密钥长度,或者其它关于密钥的信息;应用字段必须独立传输它们。 对于脱密,该机制脱密加了密的密钥,并根据这个属性单元的CKA_KEY_TYPE 属性截取结果,如果它有一个且密钥类型支持它——这个属性单元的CKA_VALUE_LEN 属性的话。该机制提供这个结果作为新密钥的CKA_VALUE 属性;其密钥类型支持要求的其它属性,必须在这个属性单元中规定。 密钥类型和数据长度的限制在下表中列出: 表85, RC5-CBC: 密钥和数据长度 函数 密钥类型 输入长度 输出长度 说明 C_Encrypt RC5 块长的倍数 与输入长度相同 没有最终部分 C_Decrypt RC5 块长的倍数 与输入长度相同 没有最终部分 C_WrapKey RC5 任意 输入长度舍入到块长的倍数 C_UnwrapKey RC5 块长的倍数 由被脱密的密钥类型或 CKA_VALUE_LEN决定 12.16.4 带有PKCS填充的RC5-CBC 带有PKCS填充的RC5-CBC ,表示成CKM_RC5_CBC_PAD, 是一种基于RSA数据安全的块密码RC5和FIPS PUB 81中定义的密码块链接方式以及PKCS#7中详细介绍的块密码填充方法的用于单方和多方加密和脱密、密钥加密、密钥脱密的机制。 它有一个参数,即CK_RC5_CBC_PARAMS 结构,该参数规定要用的字长和加密的舍入数字,以及密码块链接方式的初始化向量。 这一机制中的PKCS填充允许密文值的长度从明文值中恢复。因此,当用这机制将密钥脱密时,不应为CKA_VALUE_LEN属性确定什么值。 除了能加密/脱密保密密钥外,该机制还能加密、脱密RSA,Diffie-Hellman, 和DSA 私钥(见章节 )。当加密和脱密密钥不适应加密和脱密私钥时,下表给出数据长度限制。 密钥类型和数据长度的限制在下表中列出: 表86, RC5-CBC with PKCS Padding: 密钥和数据长度 函数 密钥类型 输入长度 输出长度 C_Encrypt RC5 任意 输入长度舍入到块长的倍数 C_Decrypt RC5 块长的倍数 在1到块长字节之间,比输入长度短 C_WrapKey RC5 任意 输入长度舍入到块长的倍数 C_UnwrapKey RC5 块长的倍数 在1到块长字节之间,比输入长度短 12.16.5 通用长度RC5-MAC 通用长度RC5-MAC, 表示成CKM_RC5_MAC_GENERAL, 是一种基于RSA Data Security的块密码RC5和FIPS PUB 113中定义的数据验证的单方和多方签名和验证的机制。 该机制有一个参数,即CK_RC5_MAC_GENERAL_PARAMS 结构,它规定字长和用来加密的舍入的数字,以及该机制所需的输入长度。 该机制的输出字节是从MACing 进程中产生的最后的RC5密码块的起始处取得的。 密钥类型和数据长度的限制在下表中列出: 表87, 通用长度RC2-MAC: 密钥和数据长度 函数 密钥类型 数据长度 签名长度 C_Sign RC2 任意 0-块长,如参数中规定的那样 C_Verify RC2 任意 0-块长,如参数中规定的那样 12.16.6 RC5-MAC RC5-MAC, 表示成CKM_RC5_MAC, 是通用长度RC5-MAC机制中的一个特殊的例子。(见章节)。它取CK_RC5_PARAMS 参数,而不是CK_RC5_MAC_GENERAL_PARAMS 参数。RC5-MAC 始终产生和验证MAC,它的一半与RC5块长一样大。 数据类型和数据长度的限制在下表中列出: 表88, RC5-MAC: 密钥和数据长度 函数 密钥类型 数据长度 签名长度 C_Sign RC5 任意 RC5 字长 = 块长/2 C_Verify RC5 任意 RC5 字长 = 块长/2 12.17 AES 机制参数 CK_AES_PARAMS; CK_AES_PARAMS_PTR CK_AES_PARAMS 为CKM_AES_ECB 和 CKM_AES_MAC 机制提供参数。它保持密码的块长。定义如下: typedef CK_ULONG CK_AES_PARAMS; CK_AES_PARAMS_PTR 是CK_AES_PARAMS的指针。 CK_AES_CBC_PARAMS; CK_AES_CBC_PARAMS_PTR CK_AES_CBC_PARAMS 是一种结构,该结构给CKM_AES_CBC 和 CKM_AES_CBC_PAD 机制提供参数。其定义如下: typedef struct CK_AES_CBC_PARAMS { CK_ULONG ulBlockSize; CK_BYTE_PTR pIv; CK_ULONG ulIvLen; } CK_AES_CBC_PARAMS; 结构的字段有下列含义: ulBlockSize AES密码的块长 pIv CBC加密的初始化向量(IV) 的指针 ulIvLen 初始化向量长度(必须与块长相同) CK_AES_CBC_PARAMS_PTR 是CK_AES_CBC_PARAMS的一个指针。 CK_AES_MAC_GENERAL_PARAMS; CK_AES_MAC_GENERAL_PARAMS_PTR CK_AES_MAC_GENERAL_PARAMS 是一种结构,该结构给CKM_AES_MAC_GENERAL 机制提供参数。定义如下: typedef struct CK_AES_MAC_GENERAL_PARAMS { CK_ULONG ulBlockSize; CK_ULONG ulMacLength; } CK_AES_MAC_GENERAL_PARAMS; 该结构的字段具有下列含义: ulBlockSize AES密码的块长 ulMacLength 字节中所生成的MAC的长度 CK_AES_MAC_GENERAL_PARAMS_PTR 是CK_AES_MAC_GENERAL_PARAMS的一个指针。 12.18 AES 机制 12.18.1 AES 密钥生成 AES 密钥生成机制,表示成CKM_AES_KEY_GEN, 是一种用于NIST的先进加密标准的密钥生成机制。 它没有参数。 该机制生成AES密钥,字节中具有特定的长度,如该密钥的属性单元的 CKA_VALUE_LEN 属性中规定的那样。 该机制把CKA_CLASS, CKA_KEY_TYPE, 和 CKA_VALUE 属性提供给新的密钥,由AES密钥类型支持的其它属性(尤其是指示该密钥支持哪些功能的标记)可以在该密钥的这个属性单元中规定,否则赋予缺省初始值。 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和 ulMaxKeySize 字段规定位中所支持的AES密钥长度的范围。 12.18.2 AES-ECB AES-ECB, 表示成CKM_AES_ECB, 是一种基于NIST先进加密标准和FIPS PUB81中定义的电子代码簿方式的用于单方和多方加密和脱密,密钥加密和密钥脱密的机制。 它有一个参数,即CK_AES_PARAMS, 该参数指示AES密码的块长。 该机制可加密脱密任何保密密钥。当然,一个特定的令牌可以不能加密/脱密它支持的每个保密密钥。对于加密,该机制加密被加密的这个密钥的CKA_VALUE 值,在尾部填充块长减1个0字节,使所产生的长度为块长的倍数。输出数据和填充的输入数据的长度一样。它不加密密钥类型、密钥长度或关于密钥的任何其它信息;应用系统必须独立地传送它们。 对于脱密,该机制脱密加了密的密钥,并根据这个属性单元的CKA_KEY_TYPE 属性截取结果,如果它有一个并且密钥类型支持它——属性单元的CKA_VALUE_LEN 属性的话。该机制把这个结果作为新密钥的CKA_VALUE 属性;由密钥类型要求的其它属性必须在这个属性单元中规定。 下表列出了密钥类型和数据长度的限制: 表89, AES-ECB: 密钥和数据长度 .+ 函数 密钥类型 输入长度 输出长度 说明 C_Encrypt AES 块长的倍数 与输入长度相同 没有最终部分 C_Decrypt AES 块长的倍数 与输入长度相同 没有最终部分 C_WrapKey AES 任意 输入长度舍入到块长的倍数 C_UnwrapKey AES 块长的倍数 由被脱密的密钥类型或 CKA_VALUE_LEN决定 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和 ulMaxKeySize 字段规定位中所支持的AES密钥长度的范围。 12.18.3 AES-CBC AES-CBC, 表示成CKM_AES_CBC, 是一种基于NIST先进加密标准和FIPS PUB81中定义的密码块链接方式的用于单方和多方加密和脱密,密钥加密和密钥脱密的机制。 它有一个参数,即CK_AES_CBC_PARAMS 结构,这里第一个字段指示位中块长,下面两个字段是密码块链接方式的初始向量和初始向量的长度。初始向量必须和块长一样长。 该机制可加密脱密任何保密密钥。当然,一个特定的令牌可能不能加密/脱密它支持的每个保密密钥。对于加密,该机制加密被加密的这个密钥的CKA_VALUE 属性的值,在尾端填充块长减1个0字节使所得的长度为块长的倍数。输出数据和填充的输入数据一样长。它不加密密钥类型、密钥长度或关于该密钥的任何其它信息;应用系统必须独立地传送它们。 对于脱密,该机制脱密加了密的密钥并根据这个属性单元的CKA_KEY_TYPE 属性截取结果,如果它有一个且密钥类型支持它——属性单元的CKA_VALUE_LEN 属性的话。该机制提供这个结果作为新密钥的CKA_VALUE 属性;由密钥类型要求的其它属性必须在这个属性单元中规定。 下表列出密钥类型和数据长度的限制: 表90, AES-CBC: 密钥和数据长度 函数 密钥类型 输入长度 输出长度 说明 C_Encrypt AES 块长的倍数 与输入长度相同 没有最终部分 C_Decrypt AES 块长的倍数 与输入长度相同 没有最终部分 C_WrapKey AES 任意 输入长度舍入到块长的倍数 C_UnwrapKey AES 块长的倍数 由被脱密的密钥类型或 CKA_VALUE_LEN决定 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和 ulMaxKeySize 字段规定位中所支持的AES密钥长度的范围。 12.18.4 带有PKCS填充的AES-CBC 带有PKCS填充的AES-CBC ,表示成CKM_AES_CBC_PAD,是一种基于NIST的先进的加密标准,FIPS PUB 81中定义的密码块链接方式和PKCS#7中详细介绍的块密码填充方法用于单方和多方加密和脱密、密钥加密和密钥脱密的机制。 它有一个参数,即CK_AES_CBC_PARAMS 结构,这里第一个字段指示块长,下两个字段是初始化向量的长度。初始化向量必须和块长一样长。 该机制中的PKCS 填充允许明文值的长度从密文值中恢复。因此,当用这种机制脱密密钥时,不应为CKA_VALUE_LEN 属性规定值。 除了能加密和脱密保密密钥外,这种机制还可加密和脱密RSA, Diffie-Hellman, 和 DSA 私钥(见章节 )。当加密和脱密一些密钥不适合加密和脱密某些保密密钥时,下表给出了数据长度的限制。 下表列出密钥类型和数据长度的限制: 表91, 带有PKCS填充的AES-CBC: 密钥和数据长度 函数 密钥类型 输入长度 输出长度 C_Encrypt AES 任意 输入长度舍入到块长的倍数 C_Decrypt AES 块长的倍数 在1到块长之间,字节小于输入长度 C_WrapKey AES 任意 输入长度舍入到块长的倍数 C_UnwrapKey AES 块长的倍数 在1到块长之间,字节小于输入长度 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和 ulMaxKeySize 字段规定位中所支持的AES密钥长度的范围。 12.18.5 通用长度AES-MAC 通用长度AES-MAC, 表示成CKM_AES_MAC_GENERAL, 是一种基于NIST的先进加密标准和FIPS PUB 113中定义的数字鉴别的用于单方和多方签名和验证的机制。 它有一个参数,即CK_AES_MAC_GENERAL_PARAMS 结构,它规定该机制需要的块长和输出长度。 该机制的输出字节从MACing进程中生成的最后的AES密码块的起始处获取。 下表列出密钥类型和数据长度的限制: 表92, 通用长度RC2-MAC: 密钥和数据长度 函数 密钥类型 数据长度 签名长度 C_Sign AES 任意 0-块长,如参数中规定的那样 C_Verify AES 任意 0-块长,如参数中规定的那样 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和 ulMaxKeySize 字段规定位中所支持的AES密钥长度的范围。 12.18.6 AES-MAC AES-MAC, 表示成CKM_AES_MAC, 是通用长度AES-MAC 机制的特例(见章节 )。它不是取CK_AES_MAC_GENERAL_PARAMS 参数,而是取CK_AES_PARAMS 参数,该参数只含块长。AES-MAC 始终生成并验证4字节MAC。 下表列出密钥类型和数据长度的限制: 表93, AES-MAC: 密钥和数据长度 函数 密钥类型 数据长度 签名长度 C_Sign AES 任意 4 C_Verify AES 任意 4 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和 ulMaxKeySize 字段规定位中所支持的AES密钥长度的范围。 12.19 通用块密码机制参数 CK_MAC_GENERAL_PARAMS; CK_MAC_GENERAL_PARAMS_PTR CK_MAC_GENERAL_PARAMS 为DES, DES3 (triple-DES), CAST, CAST3, CAST128 (CAST5), IDEA, 和 CDMF密码的通用长度MACing机制提供这些参数。它保持这些机制将生成的MAC长度。其定义如下: typedef CK_ULONG CK_MAC_GENERAL_PARAMS; CK_MAC_GENERAL_PARAMS_PTR 是CK_MAC_GENERAL_PARAMS的一个指针。 12.20 通用块密码机制 为了简明扼要,DES, DES3 (triple-DES), CAST, CAST3, CAST128 (CAST5), IDEA, 和 CDMF 块密码的机制将在此一起介绍。每一个密码都有下面的机制,将以属性单元的形式给予介绍。 12.20.1 通用块密码密钥生成 密码 有一个密钥生成机制,“ 密钥生成”, 表示成CKM__KEY_GEN. 该机制没有参数。 该机制为新密钥提供CKA_CLASS, CKA_KEY_TYPE, 和 CKA_VALUE 属性。由密钥类型支持的其它属性(尤其是,指示该密钥支持哪些函数的标记)可在密钥的这个属性单元中规定,否则赋予缺省初始值。 当DES 密钥或CDMF 密钥生成时,它们的奇偶校验位被正确地设置,如FIPS PUB 46-2中所描述的那样。同样的,当三倍DES密钥生成时,包括它的每个DES都正确地设置了它的奇偶校验位。 当DES 或CDMF 密钥生成时,能否生成“弱”(weak)或“半弱”(seni weak)密钥则取决于令牌。同样,当生成三倍DES密钥时,是否生成DES密钥的任何密钥成为“弱”或“半弱”密钥则取决于令牌。 当CAST, CAST3, 和 CAST128 (CAST5) 密钥生成时,保密密钥的这个属性单元必须规定CKA_VALUE_LEN 的属性。 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和 ulMaxKeySize 字段可以使用,也可不使用。CAST, CAST3, 和 CAST128 (CAST5) 密码都有不同的密钥长度,对于用于这些密码的密钥生成机制也如此。CK_MECHANISM_INFO结构的ulMinKeySize 和 ulMaxKeySize 字段规定位中所支持的密钥长度的范围。对于DES, DES3 (三倍DES), IDEA, 和 CDMF 密码,这些字节不使用。 12.20.2 通用块密码ECB 密码 有一个电子代码簿机制,即“-ECB”, 表示成CKM__ECB。这是一种使用进行单方和多方加密和脱密、密钥加密、脱密的机制。 它没有参数。 该机制能加密、脱密任意保密密钥。当然,一个特定令牌可能不能加密、脱密它所支持的每一个保密密钥。就加密而言,该机制加密被加密的这个密钥的CKA_VALUE 属性的值,在尾部填充0字节,使所得的长度是块长的倍数。输出数据的长度和填充的输入数据的长度一样。它不加密密钥类型、密钥长度或者关于密钥的其它信息;应用系统必须独立传输它们。 对于脱密,该机制脱密加了密的密钥,并根据这个属性单元的CKA_KEY_TYPE 属性截取结果,如果它有一个并且密钥类型支持它——属性单元的CKA_VALUE_LEN 属性的话。该机制把这个结果作为新密钥的CKA_VALUE 属性;由密钥类型要求的其它属性必须在这个属性单元中规定。 下表列出了密钥类型和数据长度的限制: 表94, General Block Cipher ECB: Key And Data Length 函数 密钥类型 输入长度 输出长度 说明 C_Encrypt 块长的倍数 与输入长度相同 没有最终部分 C_Decrypt 块长的倍数 与输入长度相同 没有最终部分 C_WrapKey 任意 输入长度舍入到块长的倍数 C_UnwrapKey 任意 由被脱密的密钥类型或 CKA_VALUE_LEN决定 12.20.3 通用块密码 CBC 密码 有一个密码块连接方式,即“-CBC”, 表示成CKM__CBC。这是一种使用进行单方和多方加密和脱密、密钥加密、脱密的机制。 它有一个参数,即一个密码块连接方式的初始化矢量。初始化矢量具有与的块长相同的长度。 密钥类型和数据长度的限制在下表中列出: 表95, 通用块密码CBC: 密钥和数据长度 函数 密钥类型 输入长度 输出长度 说明 C_Encrypt 块长的倍数 与输入长度相同 没有最终部分 C_Decrypt 块长的倍数 与输入长度相同 没有最终部分 C_WrapKey 任意 输入长度舍入到块长的倍数 C_UnwrapKey 任意 由被脱密的密钥类型或 CKA_VALUE_LEN决定 12.20.4 带有PKCS填充的通用块密码CBC 密码 有一个带有PKCS填充的密码块连接方式,即 “-CBC with PKCS padding”, 表示成CKM__CBC_PAD。这是一种使用进行单方和多方加密和脱密的密钥加密和脱密的机制。所有的密文都用PKCS填充来填充。 它有一个参数,即用于密码块连接方式的初始化向量。初始化向量的路与的块长相同。 这一机制中的PKCS填充允许明文值的长度从密文值中恢复。因此,当用这机制脱密密钥时,不应为CKA_VALUE_LEN 属性规定什么值。 除了能加密脱了密的密钥外,该机制还能加密、脱密RSA, Diffie-Hellman, 和DSA 私钥(见章节 )。当加密、脱密密钥不适宜加密、脱密所有密钥时,下表列出了数据长度的限制。 密钥类型和数据长度的限制在下表中列出: 表96, 带有PKCS填充的通用块密码CBC : 密钥和数据长度 函数 密钥类型 输入长度 输出长度 C_Encrypt 任意 输入长度舍入到块长的倍数 C_Decrypt 块长的倍数 在1到块长之间,字节小于输入长度 C_WrapKey 任意 输入长度舍入到块长的倍数 C_UnwrapKey 块长的倍数 在1到块长之间,字节小于输入长度 12.20.5 通用长度通用块密码MAC 密码 有一个通用长度MACing方式,即“通用长度-MAC”, 表示成 CKM__MAC_GENERAL,是一种用于单方、多方签名和验证的机制。 它有一个参数,即CK_MAC_GENERAL_PARAMS, 它规定输出的长度。 该机制的输出字节从MAC进程中产生最后的密码块起始处取。 输入和输出数据的密钥类型和长度的限制在下表中列出: 表97, 通用长度通用块密码MAC: 密钥和数据长度 函数 密钥类型 数据长度 签名长度 C_Sign 任意 0-块长,取决于参数 C_Verify 任意 0-块长,取决于参数 12.20.6 通用块密码MAC 密码 有一个MACing机制,即“-MAC”, 表示成CKM__MAC。 该机制是章节中介绍的CKM__MAC_GENERAL 机制的特殊情况。它产生的输出长度与的块长相同。 该机制没有参数。 数据的密钥类型和长度在下表中列出: 表98, 通用块密码MAC: 密钥和数据长度 函数 密钥类型 数据长度 签名长度 C_Sign any 块长/2 C_Verify any 块长/2 12.21 双倍和三倍长度DES 机制 12.21.1 双倍长度DES 密钥生成 双倍DES密钥生成机制,表示成CKM_DES2_KEY_GEN, 是一种用于双倍长DES密钥。形成双倍长DES密钥的DES密钥以及双倍长DES密钥两者都正确地设置了它们的奇偶检验位,如FIPS PUB 46-3中规定的那样。 它没有参数。 该机制为新密钥提供CKA_CLASS, CKA_KEY_TYPE, 和 CKA_VALUE 属性。由双倍长DES密钥类型支持的其它属性(尤其是指示该密钥支持哪些函数的标记)可在密钥的这个属性中被规定,否则赋予缺省初始值。 双倍长DES密钥可以和所有相同机制一起使用,如:CKM_DES3_ECB, CKM_DES3_CBC, CKM_DES3_CBC_PAD, CKM_DES3_MAC_GENERAL, 和 CKM_DES3_MAC (这些值以属性单元化形式在章节中介绍)。使用双倍长DES密钥的三倍DES加密等效于使用三倍长DES密钥(K1=K3)的加密,如FIPS PUB 46-3中规定的那样。 当双倍长DES密钥生成时,任何部分的DES密钥能否成为“弱”或“半弱”取决于令牌。 12.21.2 操作的三倍长DES顺序 三倍长DES加密的执行如FIPS PUB 46-3中所规定的那样:加密、脱密、加密。脱密则以相反的步骤执行:脱密、加密、脱密。加密和脱密操作的数字表达式如下: DES3-E( {K1,K2,K3}, P ) = E( K3, D( K2, E( K1, P ) ) ) DES3-D( {K1,K2,K3}, C ) = D( K1, E( K2, D( K3, P ) ) ) 12.21.3 CBC方式中的DES CBC方式中的三倍长DES操作(使用双倍或三倍长密钥)是使用如X9.52中定义的外部的CBC执行的。X9.52把这种方式描述成TCBC。CBC加密和脱密操作的数学表达式如下: DES3-CBC-E( {K1,K2,K3}, P ) = E( K3, D( K2, E( K1, P + I ) ) ) DES3-CBC-D( {K1,K2,K3}, C ) = D( K1, E( K2, D( K3, P ) ) ) + I 值I 是一个8字节初始化向量或密文前面的块,该块加到当前的输入块上。所用的附加操作是模2加(XOR)。 12.22 SKIPJACK 机制参数 CK_SKIPJACK_PRIVATE_WRAP_PARAMS; CK_SKIPJACK_PRIVATE_WRAP_PARAMS_PTR CK_SKIPJACK_PRIVATE_WRAP_PARAMS 是一种结构,它把这些参数提供给 CKM_SKIPJACK_PRIVATE_WRAP 机制,其定义如下: typedef struct CK_SKIPJACK_PRIVATE_WRAP_PARAMS { CK_ULONG ulPasswordLen; CK_BYTE_PTR pPassword; CK_ULONG ulPublicDataLen; CK_BYTE_PTR pPublicData; CK_ULONG ulPandGLen; CK_ULONG ulQLen; CK_ULONG ulRandomLen; CK_BYTE_PTR pRandomA; CK_BYTE_PTR pPrimeP; CK_BYTE_PTR pBaseG; CK_BYTE_PTR pSubprimeQ; } CK_SKIPJACK_PRIVATE_WRAP_PARAMS; 该结构的字段具有如下含义: ulPasswordLen 口令长度 pPassword 用户提供的口令的缓冲器的指针 ulPublicDataLen 另一方的密钥交换公钥长度 pPublicData 另一方的密钥交换公钥值的指针 ulPandGLen 素数和基数值的长度 ulQLen 子数值的长度 ulRandomLen 字节中随机Ra长度 pRandomA Ra 数据的指针 pPrimeP 素数、p值的指针 pBaseG 基数、g值的指针 pSubprimeQ 子素数、q值的指针 CK_SKIPJACK_PRIVATE_WRAP_PARAMS_PTR 是CK_PRIVATE_WRAP_PARAMS的一个指针。 CK_SKIPJACK_RELAYX_PARAMS; CK_SKIPJACK_RELAYX_PARAMS_PTR CK_SKIPJACK_RELAYX_PARAMS 是一种结构,它把这些参数提供给 CKM_SKIPJACK_RELAYX 机制。其定义如下: typedef struct CK_SKIPJACK_RELAYX_PARAMS { CK_ULONG ulOldWrappedXLen; CK_BYTE_PTR pOldWrappedX; CK_ULONG ulOldPasswordLen; CK_BYTE_PTR pOldPassword; CK_ULONG ulOldPublicDataLen; CK_BYTE_PTR pOldPublicData; CK_ULONG ulOldRandomLen; CK_BYTE_PTR pOldRandomA; CK_ULONG ulNewPasswordLen; CK_BYTE_PTR pNewPassword; CK_ULONG ulNewPublicDataLen; CK_BYTE_PTR pNewPublicData; CK_ULONG ulNewRandomLen; CK_BYTE_PTR pNewRandomA; } CK_SKIPJACK_RELAYX_PARAMS; 该结构的字段具有如下含义: ulOldWrappedXLen 字节中旧的加密密钥的长度 pOldWrappedX 旧的加密密钥的指针 ulOldPasswordLen 旧的口令长度 pOldPassword 含旧的用户提供口令的缓冲器的指针 ulOldPublicDataLen 旧的密钥交换公共密钥的长度 pOldPublicData 旧的密钥交换公共密钥值的指针 ulOldRandomLen 字节中旧的随机Ra的长度 pOldRandomA 旧的Ra 数据的指针 ulNewPasswordLen 新口令的长度 pNewPassword 含新用户提供的口令的缓冲器的指针 ulNewPublicDataLen 新密钥交换公共密钥的长度 pNewPublicData 新密钥交换公共密钥值的指针 ulNewRandomLen 字节中新的随机Ra的长度 pNewRandomA 新Ra数据的指针 CK_SKIPJACK_RELAYX_PARAMS_PTR 是CK_SKIPJACK_RELAYX_PARAMS的指针。 12.23 SKIPJACK 机制 12.23.1 SKIPJACK 密钥生成 SKIPJACK 密钥生成机制,表示成CKM_SKIPJACK_KEY_GEN, 是用于SKIPJACK的密钥生成机制。该机制的输出称为消息加密密钥(MEK)。 它没有参数。 该机制为新密钥提供CKA_CLASS, CKA_KEY_TYPE, 和 CKA_VALUE 属性。 12.23.2 SKIPJACK-ECB64 SKIPJACK-ECB64, 表示成CKM_SKIPJACK_ECB64, 是一种FIPS PUB 185中定义的64位电子代码簿方式中的SKIPJACK进行单方和多方加密和解密的机制。 它有一个参数,即一个24字长初始化向量。在加密操作中,这个IV被设置成由这个令牌生成的某个值,换句话说,不能规定一个特定的IV。当然,在脱密时它不能规定一个特定的IV。 密钥类型、数据长度的限制在下表中列出: 表99, SKIPJACK-ECB64: 数据和长度 函数 密钥类型 输入长度 输出长度 说明 C_Encrypt SKIPJACK 8的倍数 与输入长度相同 没有最终部分 C_Decrypt SKIPJACK 8的倍数 与输入长度相同 没有最终部分 12.23.3 SKIPJACK-CBC64 SKIPJACK-CBC64, 表示成CKM_SKIPJACK_CBC64, 是一种FIPS PUB 185中定义的64位密码块方式中的SKIPJACK进行单方和多方加密和解密的机制。 它有一个参数,即一个24位的初始向量。在加密操作中,这个IV被设置成由这个令牌生成的某个值,换句话说,在加密时应用系统不能规定一个特定的IV。当然,在脱密时它能规定一个特定的IV。 密钥类型、数据长度的限制在下表中列出: 表100, SKIPJACK-CBC64: 数据和长度 函数 密钥类型 输入长度 输出长度 说明 C_Encrypt SKIPJACK 8的倍数 与输入长度相同 没有最终部分 C_Decrypt SKIPJACK 8的倍数 与输入长度相同 没有最终部分 12.23.4 SKIPJACK-OFB64 SKIPJACK-OFB64, 表示成CKM_SKIPJACK_OFB64, 是一种使用FIPS PUB 185定义的64位输出反馈方式中的SKIPJACK进行单方加密和脱密的机制。 它有一个参数,即一个24位的初始向量。在加密操作中,这个IV被设置成由这个令牌生成的某个值,换句话说,在加密时应用系统不能规定一个特定的IV。当然,在脱密时它能规定一个特定的IV。 密钥类型、数据长度的限制在下表中列出: 表101, SKIPJACK-OFB64: 数据和长度 函数 密钥类型 输入长度 输出长度 说明 C_Encrypt SKIPJACK 8的倍数 与输入长度相同 没有最终部分 C_Decrypt SKIPJACK 8的倍数 与输入长度相同 没有最终部分 12.23.5 SKIPJACK-CFB64 SKIPJACK-CFB64, 表示成CKM_SKIPJACK_CFB64, 是一种使用FIPS PUB 185定义的64位密码反馈方式中的SKIPJACK进行单方加密和脱密的机制。 它有一个参数,即一个24位的初始向量。在加密操作中,这个IV被设置成由这个令牌生成的某个值,换句话说,在加密时应用系统不能规定一个特定的IV。当然,在脱密时它能规定一个特定的IV。 密钥类型、数据长度的限制在下表中列出: 表102, SKIPJACK-CFB64: 数据和长度 函数 密钥类型 输入长度 输出长度 说明 C_Encrypt SKIPJACK 8的倍数 与输入长度相同 没有最终部分 C_Decrypt SKIPJACK 8的倍数 与输入长度相同 没有最终部分 12.23.6 SKIPJACK-CFB32 SKIPJACK-CFB32, 表示成CKM_SKIPJACK_CFB32, 是一种使用FIPS PUB 185定义的32位密码反馈方式中的SKIPJACK进行单方加密和脱密的机制。 它有一个参数,即一个24位的初始向量。在加密操作中,这个IV被设置成由这个令牌生成的某个值,换句话说,在加密时应用系统不能规定一个特定的IV。当然,在脱密时它能规定一个特定的IV。 密钥类型、数据长度的限制在下表中列出: 表103, SKIPJACK-CFB32: 数据和长度 函数 密钥类型 输入长度 输出长度 说明 C_Encrypt SKIPJACK 4的倍数 与输入长度相同 没有最终部分 C_Decrypt SKIPJACK 4的倍数 与输入长度相同 没有最终部分 12.23.7 SKIPJACK-CFB16 SKIPJACK-CFB16, 表示成CKM_SKIPJACK_CFB16, 是一种使用FIPS PUB 185定义的16位密码反馈方式中的SKIPJACK进行单方加密和脱密的机制。 它有一个参数,即一个24位的初始向量。在加密操作中,这个IV被设置成由这个令牌生成的某个值,换句话说,在加密时应用系统不能规定一个特定的IV。当然,在脱密时它能规定一个特定的IV。 密钥类型、数据长度的限制在下表中列出: 表104, SKIPJACK-CFB16: 数据和长度 函数 密钥类型 输入长度 输出长度 说明 C_Encrypt SKIPJACK 4的倍数 与输入长度相同 没有最终部分 C_Decrypt SKIPJACK 4的倍数 与输入长度相同 没有最终部分 12.23.8 SKIPJACK-CFB8 SKIPJACK-CFB8, 表示成CKM_SKIPJACK_CFB8, 是一种使用FIPS PUB 185定义的8位密码反馈方式中的SKIPJACK进行单方加密和脱密的机制。 它有一个参数,即一个24位的初始向量。在加密操作中,这个IV被设置成由这个令牌生成的某个值,换句话说,在加密时应用系统不能规定一个特定的IV。当然,在脱密时它能规定一个特定的IV。 密钥类型、数据长度的限制在下表中列出: 表105, SKIPJACK-CFB8: 数据和长度 函数 密钥类型 输入长度 输出长度 说明 C_Encrypt SKIPJACK 4的倍数 与输入长度相同 没有最终部分 C_Decrypt SKIPJACK 4的倍数 与输入长度相同 没有最终部分 12.23.9 SKIPJACK-WRAP SKIPJACK-WRAP 机制,表示成CKM_SKIPJACK_WRAP, 用作加密和脱密一个保密密钥(MEK)。它可加密和脱密SKIPJACK, BATON,和JUNIPER 密钥。 它没有参数。 12.23.10 SKIPJACK-PRIVATE-WRAP SKIPJACK-PRIVATE-WRAP 机制,表示成CKM_SKIPJACK_PRIVATE_WRAP, 用作加密和脱密一个保密密钥。她可加密KEA 和DSA 私钥。 它有一个参数,即CK_SKIPJACK_PRIVATE_WRAP_PARAMS 结构。 12.23.11 SKIPJACK-RELAYX SKIPJACK-RELAYX 机制,表示成CKM_SKIPJACK_RELAYX, 用作与C_WrapKey 函数一起更改用于SKIPJACK-PRIVATE-WRAP机制加密的一个私钥的“加密”。 它有一个参数,即CK_SKIPJACK_RELAYX_PARAMS 结构。 虽然SKIPJACK-RELAYX 机制与C_WrapKey一起使用,但它仍与其它密钥加密机制有区别。其它密钥加密机制把密钥句柄为C_WrapKey的自变量之一。然而,对于SKIPJACK_RELAYX 机制,[始终无效的]0值应当作为C_WrapKey的密钥句柄传送,已经加密的密钥应作为CK_SKIPJACK_RELAYX_PARAMS 结构的一部分送入。 12.24 BATON 机制 12.24.1 BATON 密钥生成 BATON 密钥生成机制,表示成CKM_BATON_KEY_GEN, 是一种用于BATON的密钥生成机制。该机制的输出称为消息加密密钥。 它没有参数。 这种机制为新密钥提供CKA_CLASS, CKA_KEY_TYPE, 和 CKA_VALUE 属性。 12.24.2 BATON-ECB128 BATON-ECB128, 表示成CKM_BATON_ECB128, 是一种使用128位电子代码簿方式中的BATON进行单方、多方的加密和解密。 它有一个参数,即为一个24字节的初始量。在加密操作中,这个IV被设置成由这个令牌生成的某个值。换句话说,应用系统不能规定一个特定的IV。当然在脱密时它能规定一个特定的IV。 数据的密钥类型和长度限制在下表中列出: 表106, BATON-ECB128: 数据和长度 函数 密钥类型 输入长度 输出长度 说明 C_Encrypt BATON 16的倍数 与输入长度相同 没有最终部分 C_Decrypt BATON 16的倍数 与输入长度相同 没有最终部分 12.24.3 BATON-ECB96 BATON-ECB96, 表示成 CKM_BATON_ECB96, 是一种使用96位电子代码簿方式中的BATON进行单方、多方的加密和解密。 它有一个参数,即为一个24字节的初始量。在加密操作中,这个IV被设置成由这个令牌生成的某个值。换句话说,应用系统不能规定一个特定的IV。当然在脱密时它能规定一个特定的IV。 数据的密钥类型和长度限制在下表中列出: 表107, BATON-ECB96: Data and Length 函数 密钥类型 输入长度 输出长度 说明 C_Encrypt BATON 12的倍数 与输入长度相同 没有最终部分 C_Decrypt BATON 12的倍数 与输入长度相同 没有最终部分 12.24.4 BATON-CBC128 BATON-CBC128, 表示成CKM_BATON_CBC128, 是一种使用128位块密码连接方式中的BATON进行单方、多方的加密和解密。 它有一个参数,即为一个24字节的初始量。在加密操作中,这个IV被设置成由这个令牌生成的某个值。换句话说,应用系统不能规定一个特定的IV。当然在脱密时它能规定一个特定的IV。 数据的密钥类型和长度限制在下表中列出: 表108, BATON-CBC128: 数据和长度 函数 密钥类型 输入长度 输出长度 说明 C_Encrypt BATON 16的倍数 与输入长度相同 没有最终部分 C_Decrypt BATON 16的倍数 与输入长度相同 没有最终部分 12.24.5 BATON-COUNTER BATON-COUNTER, 表示成CKM_BATON_COUNTER, 是一种使用计数器方式中的BATON进行单方、多方的加密和解密。 它有一个参数,即为一个24字节的初始量。在加密操作中,这个IV被设置成由这个令牌生成的某个值。换句话说,应用系统不能规定一个特定的IV。当然在脱密时它能规定一个特定的IV。 数据的密钥类型和长度限制在下表中列出: 表109, BATON-COUNTER: 数据和长度 函数 密钥类型 输入长度 输出长度 说明 C_Encrypt BATON 16的倍数 与输入长度相同 没有最终部分 C_Decrypt BATON 16的倍数 与输入长度相同 没有最终部分 12.24.6 BATON-SHUFFLE BATON-SHUFFLE, 表示成CKM_BATON_SHUFFLE, 是一种使用洗牌方式中的BATON进行单方、多方的加密和解密。 它有一个参数,即为一个24字节的初始量。在加密操作中,这个IV被设置成由这个令牌生成的某个值。换句话说,应用系统不能规定一个特定的IV。当然在脱密时它能规定一个特定的IV。 数据的密钥类型和长度限制在下表中列出: 表110, BATON-SHUFFLE: 数据和长度 函数 密钥类型 输入长度 输出长度 说明 C_Encrypt BATON 16的倍数 与输入长度相同 没有最终部分 C_Decrypt BATON 16的倍数 与输入长度相同 没有最终部分 12.24.7 BATON 加密 BATON 加密和脱密机制,表示成CKM_BATON_WRAP, 是一个用来将一个保密密钥加密和脱密的函数。它能加密、脱密SKIPJACK, BATON, 和 JUNIPER keys。 它没有参数。 当一个密钥用作脱密时,该机制把CKA_CLASS, CKA_KEY_TYPE, 和 CKA_VALUE 属性提供给它。 12.25 JUNIPER 机制 12.25.1 JUNIPER 密钥生成 JUNIPER 密钥生成机制,表示成CKM_JUNIPER_KEY_GEN, 是一种用于JUNIPER的密钥生成机制。该机制的输出称为消息加密密钥MEK。 它没有参数。 该机制把CKA_CLASS, CKA_KEY_TYPE, 和 CKA_VALUE 属性提供给新的密钥。 12.25.2 JUNIPER-ECB128 JUNIPER-ECB128, 表示成CKM_JUNIPER_ECB128, 是一种使用128位电子代码簿方式中的JUNIPER进行单方、多方的加密和解密。 它有一个参数,即为一个24字节的初始量。在加密操作中,这个IV被设置成由这个令牌生成的某个值。换句话说,应用系统不能规定一个特定的IV。当然在脱密时它能规定一个特定的IV。 数据的密钥类型和长度限制在下表中列出。对于加密和脱密而言,输入和输出数据可能从存储器的同一个地方开始。 表111, JUNIPER-ECB128: 数据和长度 函数 密钥类型 输入长度 输出长度 说明 C_Encrypt JUNIPER 16的倍数 与输入长度相同 没有最终部分 C_Decrypt JUNIPER 16的倍数 与输入长度相同 没有最终部分 12.25.3 JUNIPER-CBC128 JUNIPER-CBC128, 表示成CKM_JUNIPER_CBC128, 是一种使用128位块密码方式中的JUNIPER进行单方、多方的加密和解密。 它有一个参数,即为一个24字节的初始量。在加密操作中,这个IV被设置成由这个令牌生成的某个值。换句话说,应用系统不能规定一个特定的IV。当然在脱密时它能规定一个特定的IV。 数据的密钥类型和长度限制在下表中列出。对于加密和脱密而言,输入和输出数据可能从存储器的同一个地方开始。 表112, JUNIPER-CBC128: 数据和长度 函数 密钥类型 输入长度 输出长度 说明 C_Encrypt JUNIPER 16的倍数 与输入长度相同 没有最终部分 C_Decrypt JUNIPER 16的倍数 与输入长度相同 没有最终部分 12.25.4 JUNIPER-COUNTER JUNIPER COUNTER, 表示成CKM_JUNIPER_COUNTER, 是一种使用计数器方式中的JUNIPER进行单方、多方的加密和解密。 它有一个参数,即为一个24字节的初始量。在加密操作中,这个IV被设置成由这个令牌生成的某个值。换句话说,应用系统不能规定一个特定的IV。当然在脱密时它能规定一个特定的IV。 数据的密钥类型和长度限制在下表中列出。对于加密和脱密而言,输入和输出数据可能从存储器的同一个地方开始。 表113, JUNIPER-COUNTER: 数据和长度 函数 密钥类型 输入长度 输出长度 说明 C_Encrypt JUNIPER 16的倍数 与输入长度相同 没有最终部分 C_Decrypt JUNIPER 16的倍数 与输入长度相同 没有最终部分 12.25.5 JUNIPER-SHUFFLE JUNIPER-SHUFFLE, 表示成CKM_JUNIPER_SHUFFLE, 是一种使用洗牌方式中的JUNIPER进行单方、多方的加密和解密。 它有一个参数,即为一个24字节的初始量。在加密操作中,这个IV被设置成由这个令牌生成的某个值。换句话说,应用系统不能规定一个特定的IV。当然在脱密时它能规定一个特定的IV。 数据的密钥类型和长度限制在下表中列出。对于加密和脱密而言,输入和输出数据可能从存储器的同一个地方开始。 表114, JUNIPER-SHUFFLE: 数据和长度 函数 密钥类型 输入长度 输出长度 说明 C_Encrypt JUNIPER 16的倍数 与输入长度相同 没有最终部分 C_Decrypt JUNIPER 16的倍数 与输入长度相同 没有最终部分 12.25.6 JUNIPER 加密 JUNIPER 加密和解密机制,表示成CKM_JUNIPER_WRAP, 是一个用来将一个MEK加密、脱密的函数。它能加密、脱密SKIPJACK, BATON和 JUNIPER 密钥。 它没有参数。 当用来脱密一个密钥时,该机制把CKA_CLASS, CKA_KEY_TYPE, 和CKA_VALUE 属性贡献给它。 12.26 MD2 机制 12.26.1 MD2 MD2 机制,表示成CKM_MD2, 是一种遵守RFC 1319中规定MD2消息处理算法的消息处理机制。 它没有参数。 数据长度的限制在下表中列出: 表115, MD2: 数据长度 函数 数据长度 分类长度 C_Digest 任意 16 12.26.2 通用长度MD2-HMAC 通用长度MD2-HMAC 机制,表示成CKM_MD2_HMAC_GENERAL, 是一种用于签名和验证的机制。它用的是基于MD2散列函数的HMAC结构。它用的密钥是类属保密密钥。 它有一个参数,即CK_MAC_GENERAL_PARAMS, 该参数保持着所需输出的字节中的长度。该长度应在0——16范围内。由该机制生成的签名将从全16字节HMAC输出的开始处获取。 表116, 通用长度MD2-HMAC: 密钥和数据长度 函数 密钥类型 数据长度 签名长度 C_Sign 类属保密 任意 0-16, 由参数决定 C_Verify 类属保密 任意 0-16, 由参数决定 12.26.3 MD2-HMAC MD2-HMAC 机制,表示成CKM_MD2_HMAC, 是章节中的通用长度MD2-HMAC机制的一个特殊情况。 它没有参数,始终生成长度为16的输出。 12.26.4 MD2 密钥派生 MD2 密钥派生,表示成CKM_MD2_KEY_DERIVATION, 是一种使用MD2处理另一个保密密钥的值以派生一个保密密钥能力的机制。 基础密钥的值一经处理后,其结果用于产生派生保密密钥的值。 如果在这个属性单元中没有提供长度或密钥类型,那么该机制产生的密钥将是一个类属保密密钥。其长度是16字节(MD2的输出长度)。 如果这个属性单元中只提供密钥类型,而没有长度,那么该机制产生的密钥将是一个规定长度的类属保密密钥。 如果这个属性单元中只提供长度,而没有密钥类型,那么该密钥类型必须有严格定义的长度。如果是这样,则该机制产生的密钥将具有这个属性单元中规定的类型。如果不是,则返回一个错误。 如果这个属性单元中提供密钥类型和长度,那么长度必须和密钥类型兼容。该机制产生的密钥将具有规定的类型和长度。 如果DES, DES2, 或 CDMF 密钥是用该机制派生出来的,那么该密钥的奇偶校验位将被正确的设置。 如果要求的密钥类型超过16字节,例如DES3,则生成一个错误。 该机制就密钥的灵敏度和可萃取性有如下规则: 对于新密钥属性单元中的CKA_SENSITIVE 和 CKA_EXTRACTABLE 都可规定为真或假。如果省略,这些属性的每一个都可取某个缺省值。 如果一个基础密钥具有它的设置为FALSE的CKA_ALWAYS_SENSITIVE 属性,那么派生密钥也是这样。如果基础密钥具有它的设置为TRUE的CKA_ALWAYS_SENSITIVE 属性,则派生密钥具有它的设置成和CKA_SENSITIVE 属性具有相同值的 CKA_ALWAYS_SENSITIVE 属性。 同样,如果基础密钥具有它的设置成FALSE的CKA_NEVER_EXTRACTABLE 属性,那么派生密钥也将是这样。如果基础密钥具有它的设置为TRUE的CKA_NEVER_EXTRACTABLE 属性,则派生密钥具有它的设置成和CKA_EXTRACTABLE 属性相反的值的CKA_NEVER_EXTRACTABLE 属性。 12.27 MD5 机制 12.27.1 MD5 MD5 机制,表示成CKM_MD5, 是一种按照RFC 1321中定义的MD5消息处理算法的消息处理机制。 它没有参数。 输入和输出的数据长度限制在下表中列出。就单方摘要来说,数据和处理可在存储器的同一单元处开始。 表117, MD5: 数据长度 函数 数据长度 摘要长度 C_Digest 任意 16 12.27.2 通用长度 MD5-HMAC 通用长度MD5-HMAC 机制,表示成CKM_MD5_HMAC_GENERAL, 是一种用于签名和验证的机制。它用的是基于MD5散列函数的HMAC结构。它用的密钥是类属保密密钥。 它有一个参数,即CK_MAC_GENERAL_PARAMS, 该参数保持着所需输出的字节中的长度。该长度应在0——16范围内。由该机制生成的签名将从全16字节HMAC输出的开始处获取。 Table表118, 通用长度MD5-HMAC: 密钥和数据长度 函数 密钥类型 数据长度 签名长度 C_Sign 类属保密 任意 0-16, 由参数决定 C_Verify 类属保密 任意 0-16, 由参数决定 12.27.3 MD5-HMAC MD5-HMAC 机制,表示成CKM_MD5_HMAC, 是章节中的通用长度MD5-HMAC机制的一个特殊情况。 它没有参数,始终生成长度为16的输出。 12.27.4 MD5 密钥派生 MD5 密钥派生,表示成CKM_MD5_KEY_DERIVATION, 是一种使用MD5摘要另一个保密密钥的值以派生一个保密密钥能力的机制。 基础密钥的值一经摘要后,其结果用于产生派生保密密钥的值。 如果在这个属性单元中没有提供长度或密钥类型,那么该机制产生的密钥将是一个类属保密密钥。其长度是16字节(MD5的输出长度)。 如果这个属性单元中只提供密钥类型,而没有长度,那么该机制产生的密钥将是一个规定长度的类属保密密钥。 如果这个属性单元中只提供长度,而没有密钥类型,那么该密钥类型必须有严格定义的长度。如果是这样,则该机制产生的密钥将具有这个属性单元中规定的类型。如果不是,则返回一个错误。 如果这个属性单元中提供密钥类型和长度,那么长度必须和密钥类型兼容。该机制产生的密钥将具有规定的类型和长度。 如果DES, DES2, 或 CDMF 密钥是用该机制派生出来的,那么该密钥的奇偶校验位将被正确的设置。 如果要求的密钥类型超过16字节,例如DES3,则生成一个错误。 该机制就密钥的灵敏度和可萃取性有如下规则: 对于新密钥属性单元中的CKA_SENSITIVE 和 CKA_EXTRACTABLE 都可规定为真或假。如果省略,这些属性的每一个都可取某个缺省值。 如果一个基础密钥具有它的设置为FALSE的CKA_ALWAYS_SENSITIVE 属性,那么派生密钥也是这样。如果基础密钥具有它的设置为TRUE的CKA_ALWAYS_SENSITIVE 属性,则派生密钥具有它的设置成和CKA_SENSITIVE 属性具有相同值的 CKA_ALWAYS_SENSITIVE 属性。 同样,如果基础密钥具有它的设置成FALSE的CKA_NEVER_EXTRACTABLE 属性,那么派生密钥也将是这样。如果基础密钥具有它的设置为TRUE的CKA_NEVER_EXTRACTABLE 属性,则派生密钥具有它的设置成和CKA_EXTRACTABLE 属性相反的值的CKA_NEVER_EXTRACTABLE 属性。 12.28 SHA-1 机制 12.28.1 SHA-1 SHA-1 机制表示成CKM_SHA_1, 是一个按照FIPS PUB 180-1中定义的保密散列算法进行消息摘要的机制。 它没有参数。 输入和输出的数据长度限制在下表中列出。就单方摘要来说,数据和处理可在存储器的同一单元处开始。 表119, SHA-1: 数据长度 函数 数据长度 摘要长度 C_Digest 任意 20 12.28.2 通用长度SHA-1-HMAC 通用长度SHA-1-HMAC 机制表示成CKM_SHA_1_HMAC_GENERAL, 是一种用于签名和验证的机制。它用的是基于SHA-1散列函数的HMAC结构。它用的密钥是类属保密密钥。 它有一个参数,即CK_MAC_GENERAL_PARAMS, 该参数保持着所需输出的字节中的长度。该长度应在0——20范围内。由该机制生成的签名将从全20字节HMAC输出的开始处获取。 表120, 通用长度SHA-1-HMAC: 密钥和数据长度 函数 密钥类型 数据长度 签名长度 C_Sign 类属保密 任意 0-20, 由参数决定 C_Verify 类属保密 任意 0-20, 由参数决定 12.28.3 SHA-1-HMAC SHA-1-HMAC 机制,表示成CKM_SHA_1_HMAC, 是章节中通用长度SHA-1-HMAC 机制的一个特殊情况。 它没有参数,始终产生长度为20的输出。 12.28.4 SHA-1 密钥派生 SHA-1 密钥派生,表示成CKM_SHA1_KEY_DERIVATION, 是一种使用SHA-1摘要另一个保密密钥的值以派生一个保密密钥能力的机制。 基础密钥的值一经摘要后,其结果用于产生派生保密密钥的值 如果在这个属性单元中没有提供长度或密钥类型,那么该机制产生的密钥将是一个类属保密密钥。其长度是20字节(SHA-1的输出长度)。 如果这个属性单元中只提供密钥类型,而没有长度,那么该机制产生的密钥将是一个规定长度的类属保密密钥。 如果这个属性单元中只提供长度,而没有密钥类型,那么该密钥类型必须有严格定义的长度。如果是这样,则该机制产生的密钥将具有这个属性单元中规定的类型。如果不是,则返回一个错误。 如果这个属性单元中提供密钥类型和长度,那么长度必须和密钥类型兼容。该机制产生的密钥将具有规定的类型和长度。 如果DES, DES2, 或 CDMF 密钥是用该机制派生出来的,那么该密钥的奇偶校验位将被正确的设置。 如果要求的密钥类型超过20个字节,例如DES3,则生成一个错误。 该机制就密钥的灵敏度和可萃取性有如下规则: 对于新密钥属性单元中的CKA_SENSITIVE 和 CKA_EXTRACTABLE 都可规定为真或假。如果省略,这些属性的每一个都可取某个缺省值。 如果一个基础密钥具有它的设置为FALSE的CKA_ALWAYS_SENSITIVE 属性,那么派生密钥也是这样。如果基础密钥具有它的设置为TRUE的CKA_ALWAYS_SENSITIVE 属性,则派生密钥具有它的设置成和CKA_SENSITIVE 属性具有相同值的 CKA_ALWAYS_SENSITIVE 属性。 同样,如果基础密钥具有它的设置成FALSE的CKA_NEVER_EXTRACTABLE 属性,那么派生密钥也将是这样。如果基础密钥具有它的设置为TRUE的CKA_NEVER_EXTRACTABLE 属性,则派生密钥具有它的设置成和CKA_EXTRACTABLE 属性相反的值的CKA_NEVER_EXTRACTABLE 属性。 12.29 FASTHASH 机制 12.29.1 FASTHASH FASTHASH 机制,表示成CKM_FASTHASH, 是一个遵照美国政府算法进行信息摘要的机制。 它没有参数。 输入和输出数据的长度限制在下表中列出。 表121, FASTHASH: 数据长度 函数 输入长度 摘要长度Digest length C_Digest 任意 40 12.30 基于口令鉴别的加密机制参数 CK_PBE_PARAMS; CK_PBE_PARAMS_PTR CK_PBE_PARAMS 是一个提供CKM_PBE 机制(见PKCS #5 和PKCS #12 关于PBE生成机制的信息) 和CKM_PBA_SHA1_WITH_SHA1_HMAC 机制。其定义如下: typedef struct CK_PBE_PARAMS { CK_CHAR_PTR pInitVector; CK_CHAR_PTR pPassword; CK_ULONG ulPasswordLen; CK_CHAR_PTR pSalt; CK_ULONG ulSaltLen; CK_ULONG ulIteration; } CK_PBE_PARAMS; 该结构的字段具有如下含义: pInitVector 接收8字节初始化向量(IV)的单元的指针 pPassword 指向PBE密钥生成中使用的口令 ulPasswordLen 口令信息字节的长度 pSalt 指向PBE密钥生成中使用的salt ulSaltLen salt信息的字节中的长度 ulIteration 该生成需要的迭代数 CK_PBE_PARAMS_PTR 是CK_PBE_PARAMS的指针。 12.31 PKCS #5 和PKCS #5-风格口令的加密机制 本节中的这些机制用来生成密钥和IV以执行基于口令的加密。用来生成密钥和IV的这种方法在PKCS #5中说明。 12.31.1 用于DES-CBC 的MD2-PBE 用于DES-CBC 的MD2-PBE, 表示成CKM_PBE_MD2_DES_CBC, 是一种机制。这种机制通过使用MD2摘要算法和迭代数从一个口令、一个salt值中生成一个DES保密和一个IV。这种函数性是作为PBKDF1在PKCS#5中定义的。 它有一个参数,即CK_PBE_PARAMS 结构。该参数规定密钥生成进程的输入信息和应用系统提供的缓冲器的单元,该单元将接收由这种机制生成的8字节IV。 12.31.2 用于DES-CBC 的MD5-PBE 用于DES-CBC 的MD5-PBE,表示成CKM_PBE_MD5_DES_CBC, 是一种机制,这种机制使用MD5摘要算法和迭代数量从一个口令、一个salt值中生成一个DES保密密钥和一个IV。这种函数性在PKCS#5中是作为PBKDF1定义的。 它有一个参数,即CK_PBE_PARAMS 结构。该参数为密钥生成过程和应用系统提供的缓冲器的单元(该单元的接收由这种机制生成的8字节IV)规定输入信息。 12.31.3 用于CAST-CBC的MD5-PBE 用于CAST-CBC的MD5-PBE ,表示成 CKM_PBE_MD5_CAST_CBC, 是一种机制,这种机制使用MD5摘要算法和迭代数量从一个口令、一个salt值中生成一个CAST保密密钥和一个IV。这种函数性与在PKCS#5中定义的用于MD5和DES的功能性相似。 它有一个参数,即CK_PBE_PARAMS 结构。该参数为密钥生成过程和应用系统提供的缓冲器的单元(该单元的接收由这种机制生成的8字节IV)规定输入信息。 由这种机制生成的CAST密钥的长度可在提供的这个属性单元中规定;如果在该属性单元不提供它的话,缺省为8字节。 12.31.4 用于CAST3-CBC 的MD5-PBE 用于CAST3-CBC的MD5-PBE,表示成CKM_PBE_MD5_CAST3_CBC, 是一种机制,这种机制使用MD5摘要算法和迭代数量从一个口令、一个salt值中生成一个CAST3保密密钥和一个IV。这种函数性与在PKCS#5中定义的用于MD5和DES的功能性相似。 它有一个参数,即CK_PBE_PARAMS 结构。该参数为密钥生成过程和应用系统提供的缓冲器的单元(该单元的接收由这种机制生成的8字节IV)规定输入信息。 由这种机制生成的CAST3密钥的长度可在提供的这个属性单元中规定;如果在该属性单元不提供它的话,缺省为8字节。 12.31.5 用于CAST128-CBC(CAST5-CBC)的 MD5-PBE 用于CAST128-CBC (CAST5-CBC)的MD5-PBE,表示成CKM_PBE_MD5_CAST128_CBC 或 CKM_PBE_MD5_CAST5_CBC, 是一种机制,这种机制使用MD5摘要算法和迭代数量从一个口令、一个salt值中生成一个CAST128(CAST5-CBC)保密密钥和一个IV。这种函数性与在PKCS#5中定义的用于MD5和DES的功能性相似。 它有一个参数,即CK_PBE_PARAMS 结构。该参数为密钥生成过程和应用系统提供的缓冲器的单元(该单元的接收由这种机制生成的8字节IV)规定输入信息。 由这种机制生成的CAST128(CAST5-CBC)密钥的长度可在提供的这个属性单元中规定;如果在该属性单元不提供它的话,缺省为8字节。 12.31.6 用于CAST128-CBC (CAST5-CBC)的SHA-1-PBE 用于CAST128-CBC (CAST5-CBC)的SHA-1-PBE,表示成CKM_PBE_SHA1_CAST128_CBC 或CKM_PBE_SHA1_CAST5_CBC, 是一种机制,这种机制使用SHA-1摘要算法和迭代数量从一个口令、一个salt值中生成一个CAST128(CAST5-CBC)保密密钥和一个IV。这种函数性与在PKCS#5中定义的用于MD5和DES的功能性相似。 它有一个参数,即CK_PBE_PARAMS 结构。该参数为密钥生成过程和应用系统提供的缓冲器的单元(该单元的接收由这种机制生成的8字节IV)规定输入信息。 由这种机制生成的CAST128(CAST5-CBC)密钥的长度可在提供的这个属性单元中规定;如果在该属性单元不提供它的话,缺省为8字节。 12.31.7 PKCS #5 PBKDF2 密钥生成机制参数 CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE; CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE_PTR CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE 用来指示使用PKCS #5 PBKDF2生成密钥位的伪随机函数(Pseudo-Random Function –PRF)。定义如下: typedef CK_ULONG CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE; PKCS #5 v2.0.中定义了下列PRF。下表列出所定义的函数。 表122, PKCS #5 PBKDF2 密钥生成: 伪随机函数 源标识符 值 参数类型 CKP_PKCS5_PBKD2_HMAC_SHA1 0x00000001 无参数。 pPrfData 必须是NULL 和 ulPrfDataLen 必须是0。 CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE_PTR 是CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE的指针。 CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE; CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE_PTR 当使用CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE 派生一个密钥时,用来指示salt值的源。定义如下: typedef CK_ULONG CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE; 下列salt值源在PKCS #5 v2.0.中定义。下表列出所定义的源以及用于下面定义的CK_PKCS5_PBKD2_PARAM结构中pSaltSourceData 字段的对应的数据类型。 表123, PKCS #5 PBKDF2 密钥生成: Salt 源 源标识符 值 数据类型 CKZ_SALT_SPECIFIED 0x00000001 含salt值的CK_BYTE 阵列 CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE_PTR 是 CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE的一个指针。 CK_ PKCS5_PBKD2_PARAMS; CK_PKCS5_PBKD2_PARAMS_PTR CK_PKCS5_PBKD2_PARAMS 是一种结构,该结构将这些参数提供给CKM_PKCS5_PBKD2 机制,该结构定义如下: typedef struct CK_PKCS5_PBKD2_PARAMS { CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE saltSource; CK_VOID_PTR pSaltSourceData; CK_ULONG ulSaltSourceDataLen; CK_ULONG iterations; CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf; CK_VOID_PTR pPrfData; CK_ULONG ulPrfDataLen; } CK_PKCS5_PBKD2_PARAMS; 该结构的字段具有下列含义: saltSource salt值的源 pSaltSourceData 用作salt源的输入的数据 ulSaltSourceDataLen salt源输入的长度 iterations 当生成每块的堆积数据时执行的迭代数量 prf 用来产生该密钥的伪随机函数 pPrfData 用作PRF的输入的数据(除salt值外) ulPrfDataLen PRF的输入数据的长度 CK_PKCS5_PBKD2_PARAMS_PTR 是CK_PKCS5_PBKD2_PARAMS的一个指针。 12.31.8 PKCS #5 PBKD2 密钥生成 PKCS #5 PBKDF2 密钥生成,表示成CKM_PKCS5_PKKD2, 是一种用来从口令和salt值中产生保密密钥的机制。这种函数性在PKCS#5 中作为 PBKDF2定义的。 它有一个参数,即CK_PKCS5_PBKD2_PARAMS 结构。该参数规定用来产生新密钥的salt值的源、伪随机函数和迭代数量。 由于该机制可用来产生任何类型的保密密钥,因此新密钥属性单元必须含 CKA_KEY_TYPE 和 CKA_VALUE_LEN 属性。如果密钥类型有固定长度,那么可省略 CKA_VALUE_LEN 属性。 12.32 PKCS #12 基于口令的加密/鉴别机制 本节中的这些机制用来生成执行基于口令的加密或鉴别的密钥和IV。生成密钥和IV的这种方法是基于PKCS#12原始草案中规定的一种方法。 这里我们来说明从口令, p; salt位串, s; 和迭代数量, c中生成各种类型的伪随机位的一种通用的方法。要生成的伪随机位的“类型”由一个表示字节、ID来标识,它的意义将在后边讨论。 令H 是一个基于压缩函数的散列函数 f: Z2u  Z2v  Z2u (也就是说,H 有一个链接变元和长度为u 位的输出,对H的压缩函数的消息输入是v 位)。对于MD2和MD5,u=128 , v=512; 对于SHA-1, u=160 和 v=512。 我们假定这里u 和v 都是8的倍数,正如口令和salt串以及所需的伪随机位数n 也是8的倍数一样。另外,当然u 和v 都是非0。 1. 通过连接ID的v/8个拷贝构建一个串,D ( “diversifier”)。 2. 把salt的一些拷贝连接在一起以建立一个长度为vs/v位的串S (该salt的最后一个拷贝可以截取以建立S)。注意,如果salt是空串,那么就是S。 3. 把口令的一些拷贝连接在一起以建立一个长度为vp/v位的串P (该口令的最后一个拷贝可以截取以建立P)。注意,如果该口令是空串,那么就是P。 4. 令 I=S||P 是S 和P的连接。 5. 令 j=n/u. 6. 对于i=1, 2, …, j, 进行下面的动作: a) 令 Ai=Hc(D||I), D||I的第c 个散列。 就是说,计算D||I; 的散列;计算那个散列的散列;等等;以这种形式一直持续到总共c 个散列计算出来,每一个都依靠前面的散列的结果。 b) 连接Ai 个拷贝以建立一个长度为v 位的串B (Ai 的最后拷贝可以截取以建立B)。 c) 把I 看作是v-位块的I0, I1, …, Ik-1 的连接,这里k=s/v+p/v, 对每个j,通过令Ij=(Ij+B+1) 模2v 来修改I 。为了执行这个加法,把每个v-位块看成一个第一位最高有效位表示的二进制数。 7. 把A1, A2, …, Aj 连接在一起以形成一个伪随机位串,A。 8. 使用A 的前 n 位作为整个过程的输出。 当使用本节介绍的基于口令的加密机制来从口令、salt和一个迭代数量产生密钥和IV(如果需要的话)时,则使用上述算法。为了产生一个密钥,标识符字节ID设置成值1;为了产生一个IV,标识符字节ID设置成值2。 当使用本节介绍的基于口令的鉴别机制来从口令、salt和一个迭代数产生密钥时,则使用上述算法。标识符字节ID设置成值3。 12.32.1 用于128-位的RC4 SHA-1-PBE 用于128-位的SHA-1-PBE,表示成CKM_PBE_SHA1_RC4_128, 是一种用来从口令、salt值使用SHA-1摘要算法和一个迭代数产生128位RC4保密密钥的机制。产生该密钥的使用的方法已在上边介绍。 它有一个参数,即一个CK_PBE_PARAMS 结构。该参数规定密钥生成过程的输入信息。该参数还有一个保持所提供的应用缓冲器位置的字段(所提供的应用缓冲器将接收一个IV);对于该机制,该字段的内容被忽略掉,因为RC4不需要一个IV。 该机制产生的密钥一般将用于执行基于口令的加密。 12.32.2 用于40-位的RC4 SHA-1-PBE 用于40-位的SHA-1-PBE,表示成CKM_PBE_SHA1_RC4_40, 是一种用来从口令、salt值使用SHA-1摘要算法和一个迭代数产生40位RC4保密密钥的机制。产生该密钥的使用的方法已在上边介绍。 它有一个参数,即一个CK_PBE_PARAMS 结构。该参数规定密钥生成过程的输入信息。该参数还有一个保持所提供的应用缓冲器位置的字段(所提供的应用缓冲器将接收一个IV);对于该机制,该字段的内容被忽略掉,因为RC4不需要一个IV。 该机制产生的密钥一般将用于执行基于口令的加密。 12.32.3 用于3-密钥三倍(key triple)-DES-CBC的 SHA-1-PBE 用于3-密钥三倍-DES-CBC 的SHA-1-PBE,表示成CKM_PBE_SHA1_DES3_EDE_CBC, 是一种使用SHA-1摘要算法和一个迭代数生成一个来自一个口令和一个salt值的3-密钥三倍-DES 保密密钥和IV的机制。用来生成该密钥和IV的方法上面已经介绍。所生成的这个密钥的每个字节将有其被调整的最低位(如果需要的话),因此,获得了一个具有适宜奇偶校验位的有效3-密钥三倍-DES 密钥。 它有一个参数,即CK_PBE_PARAMS 结构。该参数规定密钥生成过程的输入信息和所提供的应用缓冲器的位置,所提供的这个应用缓冲器将接收由该机制产生的8字节IV。 由该机制生成的密钥和IV一般用于执行基于口令的加密。 12.32.4 用于3-密钥三倍(key triple)-DES-CBC的 SHA-1-PBE 用于2-密钥三倍-DES-CBC 的SHA-1-PBE,表示成CKM_PBE_SHA1_DES2_EDE_CBC, 是一种使用SHA-1摘要算法和一个迭代数生成一个来自一个口令和一个salt值的2-密钥三倍-DES 保密密钥和IV的机制。用来生成该密钥和IV的方法上面已经介绍。所生成的这个密钥的每个字节将有其被调整的最低位(如果需要的话),因此,获得了一个具有适宜奇偶校验位的有效2-密钥三倍-DES 密钥。 它有一个参数,即CK_PBE_PARAMS 结构。该参数规定密钥生成过程的输入信息和所提供的应用缓冲器的位置,所提供的这个应用缓冲器将接收由该机制产生的8字节IV。 由该机制生成的密钥和IV一般用于执行基于口令的加密。 12.32.5 用于128-位 RC2-CBC 的SHA-1-PBE 用于128-位 RC2-CBC的SHA-1-PBE,表示表示成CKM_PBE_SHA1_RC2_128_CBC, 是一种使用SHA-1摘要算法和一个迭代数生成一个来自一个口令和一个salt值的128-位保密密钥和IV的机制。用来生成该密钥和IV的方法上面已经介绍。 它有一个参数,即CK_PBE_PARAMS 结构。该参数规定密钥生成过程的输入信息和所提供的应用缓冲器的位置,所提供的这个应用缓冲器将接收由该机制产生的8字节IV。 当由该机制生成的密钥和IV用来加密或脱密时,则RC2搜索空间中的有效位应设置成128。这就确保了与ASN.1 Object Identifier pbeWithSHA1And128BitRC2-CBC的兼容。 由该机制生成的密钥和IV一般用于执行基于口令的加密。 12.32.6 用于40-位RC2-CBC 的SHA-1-PBE 用于40-位RC2-CBC的SHA-1-PBE,表示成CKM_PBE_SHA1_RC2_40_CBC, 是一种使用SHA-1摘要算法和一个迭代数生成一个来自一个口令和一个salt值的40-位保密密钥和IV的机制。用来生成该密钥和IV的方法上面已经介绍。 它有一个参数,即CK_PBE_PARAMS 结构。该参数规定密钥生成过程的输入信息和所提供的应用缓冲器的位置,所提供的这个应用缓冲器将接收由该机制产生的8字节IV。 当由该机制生成的密钥和IV用来加密或脱密时,则RC2搜索空间中的有效位应设置成128。这就确保了与ASN.1 Object Identifier pbeWithSHA1And128BitRC2-CBC的兼容。 由该机制生成的密钥和IV一般用于执行基于口令的加密。 12.32.7 用于SHA-1-HMAC 的SHA-1-PBA 用于SHA-1-PBA的SHA-1-PBA,表示成CKM_PBA_SHA1_WITH_SHA1_HMAC, 是一种使用SHA-1摘要算法和一个迭代数生成一个来自一个口令和一个salt值的160位保密密钥和IV的机制。用来生成该密钥和IV的方法上面已经介绍。 它有一个参数,即CK_PBE_PARAMS 结构。该参数规定密钥生成过程的输入信息。该参数还有一个保持两个所提供的应用缓冲器位置的字段,所提供的这个应用缓冲器将接收一个IV;对于这种机制,该字段的内容被忽略掉,因为使用SHA-1 HMAC来执行基于口令的鉴别不要求一个IV。 由该机制生成的密钥一般用来计算一个SHA-1 HMAC 来执行基于口令的鉴别(不是基于口令的加密)。在写这个文件时,这样做主要是为了保证PKCS #12 PDU的完整性。 12.33 SET 机制参数 CK_KEY_WRAP_SET_OAEP_PARAMS; CK_KEY_WRAP_SET_OAEP_PARAMS_PTR CK_KEY_WRAP_SET_OAEP_PARAMS 是为CKM_KEY_WRAP_SET_OAEP 机制提供参数的一种结构。其定义如下: typedef struct CK_KEY_WRAP_SET_OAEP_PARAMS { CK_BYTE bBC; CK_BYTE_PTR pX; CK_ULONG ulXLen; } CK_KEY_WRAP_SET_OAEP_PARAMS; 该结构字段的含义如下: bBC 块内容字节 pX 明文数据(如果有的话)和附加数据(如果有的话)的散列的连接 ulXLen 明文数据(如果有的话)和附加数据(如果有的话)的散列的连接的字节中长度 CK_KEY_WRAP_SET_OAEP_PARAMS_PTR 是CK_KEY_WRAP_SET_OAEP_PARAMS的指针。 12.34 SET 机制 12.34.1 用于SET的OAEP密钥加密 用于SET机制的OAEP 密钥加密,表示成CKM_KEY_WRAP_SET_OAEP, 是一种使用RSA密钥加密和脱密一个DES密钥的机制。某些明文数据和/或某些附加数据的散列可一起任意用这个DES密钥加密。在SET协议规范中定义了这种机制。 它取一个参数,即CK_KEY_WRAP_SET_OAEP_PARAMS 结构。这种结构保持这个数据的“块内容(Block Contents)”字节和明文数据(如果有的话)散列和待加密的附加数据(如果有的话)的连接。如果即无散列又无附加数据,那么这种情况由具有值0的ulXLen 字段指示。 当使用这种机制将一个密钥脱密时,明文数据(如果有的话)的散列和附加数据(如果有的话)的连接在生成输出时按章节介绍的待定返回。注意,如果对C_UnwrapKey 的输入使附加数据不返回(例如CK_KEY_WRAP_SET_OAEP_PARAMS 结构中提供的缓冲器是NULL_PTR ),那么就不会建立脱了密的密钥体。 要知道,当这种机制用来脱密一个密钥时,对这种机制提供的这个参数的bBC 和 pX 字段可以修改。 如果一种应用程序使用带有CKM_KEY_WRAP_SET_OAEP 的C_UnwrapKey ,对于这种情况最好是简单地为明文数据的散列和附加数据的连接分配一个128字节的缓冲器(这种连接绝不会大于128字节),而不是再次调用C_UnwrapKey 。每当调用带有CKM_KEY_WRAP_SET_OAEP 的C_UnwrapKey ,则要求执行一个RSA脱密操作,而通过这种办法可以避免这种计算开销。 12.35 LYNKS 机制 12.35.1 LYNKS 密钥加密 LYNKS 密钥加密机制,表示成CKM_WRAP_LYNKS, 是一种用来使用DES密钥加密和脱密保密密钥的机制。它可加密任意8字节保密密钥,它生成一个10字节加密密钥,含一个密码检验和(cryptographic checksum )。 它没有参数。 为了使一个DES密钥W加密一个8字节保密密钥K ,该机制执行下列步骤: 1. 将两个16位整数sum1 和sum2初始化成0。 2. 通过K 的这些字节从第一个到最后一个循环。 3. 含sum1= sum1+这个密钥字节(把这个密钥字节看成是0-255范围的一个数)。 4. 令sum2= sum2+ sum1。 5. 用W的ECB方式加密K ,获得一个加密密钥E。 6. 把E 后6个字节与sum2连接起来,代表sum2 第一个最高有效位。得到的结果是一个8字节块T。 7. 用W的ECB方式加密T ,获得一个加密的检验(checksum), C。 8. 把E 与C 的后两个字节连接起来,以获得加密密钥。 当使用这种机制脱密一个密钥时,如果这个密码检验和(cryptographic checksum )不能正确地检验出,则返回一个错误。另外,如果使用这种机制脱密一个DES密钥或CDEMF密钥,那么加密密钥上的奇偶校验位必须设置得当。如果设置得不正确,则返回一个错误。 12.36 SSL 机制参数 CK_SSL3_RANDOM_DATA CK_SSL3_RANDOM_DATA 是一种结构,该结构以一个SSL关联(SSL context)提供关于一个客户机和一个服务器的随机数据的信息。这种结构由CKM_SSL3_MASTER_KEY_DERIVE 和CKM_SSL3_KEY_AND_MAC_DERIVE 机制使用。定义如下: typedef struct CK_SSL3_RANDOM_DATA { CK_BYTE_PTR pClientRandom; CK_ULONG ulClientRandomLen; CK_BYTE_PTR pServerRandom; CK_ULONG ulServerRandomLen; } CK_SSL3_RANDOM_DATA; 该结构的字段有如下含义: pClientRandom 这个客户机的随机数据的指针 ulClientRandomLen 这个客户机的随机数据的字节中的长度 pServerRandom 这个服务器的随机数据的指针 ulServerRandomLen 这个服务器的随机数据的字节中的长度 CK_SSL3_MASTER_KEY_DERIVE_PARAMS; CK_SSL3_MASTER_KEY_DERIVE_PARAMS_PTR CK_SSL3_MASTER_KEY_DERIVE_PARAMS 是一种结构,该结构给CKM_SSL3_MASTER_KEY_DERIVE 机制提供参数。定义如下: typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS { CK_SSL3_RANDOM_DATA RandomInfo; CK_VERSION_PTR pVersion; } CK_SSL3_MASTER_KEY_DERIVE_PARAMS; 该结构的字段具有下列含义: RandomInfo 客户机和服务器的随机数据信息 pVersion 接收SSL协议版信息的CK_VERSION 结构的指针 CK_SSL3_MASTER_KEY_DERIVE_PARAMS_PTR 是CK_SSL3_MASTER_KEY_DERIVE_PARAMS的指针。 CK_SSL3_KEY_MAT_OUT; CK_SSL3_KEY_MAT_OUT_PTR CK_SSL3_KEY_MAT_OUT 是一种结构,该结构含以CKM_SSL3_KEY_AND_MAC_DERIVE 机制执行C_DeriveKey 函数后产生的密钥句柄。定义如下: typedef struct CK_SSL3_KEY_MAT_OUT { CK_OBJECT_HANDLE hClientMacSecret; CK_OBJECT_HANDLE hServerMacSecret; CK_OBJECT_HANDLE hClientKey; CK_OBJECT_HANDLE hServerKey; CK_BYTE_PTR pIVClient; CK_BYTE_PTR pIVServer; } CK_SSL3_KEY_MAT_OUT; 结构的字段具有下列含义: hClientMacSecret 产生的Client MAC 保密密钥的密钥句柄 hServerMacSecret 产生的Server MAC 保密密钥的密钥句柄 hClientKey 产生的客户机保密密钥的密钥句柄 hServerKey 产生的服务器保密密钥的密钥句柄 pIVClient 一个单元指针,该单元接收为该客户机(即使有也很少)建立的初始化向量(IV) pIVServer 一个单元指针,该单元接收为该服务器(即使有也很少)建立的初始化向量 CK_SSL3_KEY_MAT_OUT_PTR 是CK_SSL3_KEY_MAT_OUT的指针。 CK_SSL3_KEY_MAT_PARAMS; CK_SSL3_KEY_MAT_PARAMS_PTR CK_SSL3_KEY_MAT_PARAMS 是一种结构,该结构给CKM_SSL3_KEY_AND_MAC_DERIVE 机制提供参数。定义如下: typedef struct CK_SSL3_KEY_MAT_PARAMS { CK_ULONG ulMacSizeInBits; CK_ULONG ulKeySizeInBits; CK_ULONG ulIVSizeInBits; CK_BBOOL bIsExport; CK_SSL3_RANDOM_DATA RandomInfo; CK_SSL3_KEY_MAT_OUT_PTR pReturnedKeyMaterial; } CK_SSL3_KEY_MAT_PARAMS; 该结构的字段具有如下含义: ulMacSizeInBits 在协议握手阶段MACing密钥的位中长度一致 ulKeySizeInBits 在协议握手阶段,保密密钥的位中长度一致 ulIVSizeInBits 在协议握手阶段,IV的位中长度一致。如果不需要IV,那么该长度应设置成0 bIsExport 一个Boolean 值,它指示对于出口型的协议,这些密钥是否必须派生 RandomInfo 客户机和服务器的随机数据信息 pReturnedKeyMaterial 指向CK_SSL3_KEY_MAT_OUT 结构,该结构所生成的这些密钥的句柄和IV CK_SSL3_KEY_MAT_PARAMS_PTR 是CK_SSL3_KEY_MAT_PARAMS的指针。 12.37 SSL 机制 12.37.1 Pre_master密钥生成 SSL3.0中Pre_master密钥生成,表示成CKM_SSL3_PRE_MASTER_KEY_GEN, 是一种生成48字节类属保密密钥的机制。使用它来生成SSL3.0使用的"pre_master"密钥。 它有一个参数,即CK_VERSION 结构,它提供这个客户机的SSL版号。 该机制把CKA_CLASS, CKA_KEY_TYPE, 和 CKA_VALUE 属性提供给新的密钥(还有CKA_VALUE_LEN 属性,如果该属性未在该属性单元中提供的话)。其它属性可在这个属性单元中规定,否则赋予缺省值。 在C_GenerateKey 调用期间除了这种机制以外,这种属性单元也可指示目标分类(object class)是CKO_SECRET_KEY,密钥类型是CKK_GENERIC_SECRET, CKA_VALUE_LEN 属性具有值48。然而,由于这些事情在这种机制中都是隐式的,因此不必规定任何一个。 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和 ulMaxKeySize 字段都指示48个字节。 12.37.2 Master 密钥派生 SSL 3.0中的Master密钥派生,表示成CKM_SSL3_MASTER_KEY_DERIVE, 是一种用来从另一种48字节类属保密密钥派生一个48字节类属保密密钥的机制。它用来生成"pre_master"密钥生成SSL协议中使用的"master_secret"密钥。该机制返回装入"pre_master" 密钥的客户机类型(client version)的值和派生的"master_secret"密钥的句柄。 它有一个参数,即CK_SSL3_MASTER_KEY_DERIVE_PARAMS 结构,它允许把随机数据发送给这个令牌以及返回属于pre-master 密钥一部分的协议版本号。在章节.定义了这种结构。 该机制把CKA_CLASS, CKA_KEY_TYPE, 和 CKA_VALUE 属性(以及CKA_VALUE_LEN 属性,如果该属性在这个属性单元未提供的话)提供给新的密钥。其它属性可以在这个属性单元中规定,否则赋予缺省值。 在C_GenerateKey 调用期间随同该机制一同发送的这个属性单元可以指示对象分类是 CKO_SECRET_KEY, 密钥类型是CKK_GENERIC_SECRET,CKA_VALUE_LEN 属性具有值48。然而,由于这些在该机制中都是隐式的,因此不必去说明它们了。 关于密钥灵敏性和可萃性,该机制具有如下规则: 新密钥的这个属性单元中CKA_SENSITIVE 和CKA_EXTRACTABLE 属性可以规定为TRUE或FALSE。如果省略,这些属性每个都可取某一缺省值。 如果基本密钥具有设置成FALSE的CKA_ALWAYS_SENSITIVE 属性,那么派生密钥也是这样。如果基本密钥具有设置成和它的CKA_SENSITIVE 属性具有相同的值的CKA_ALWAYS_SENSITIVE 属性。 同样,如果基本密钥具有它的设置成FALSE的CKA_NEVER_EXTRACTABLE 属性,那么派生密钥也是这样。如果基本密钥具有其设置成TRUE的CKA_NEVER_EXTRACTABLE 属性,那么派生密钥具有其设置成和它的CKA_EXTRACTABLE 属性具有相反值的CKA_NEVER_EXTRACTABLE 属性。 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和 ulMaxKeySize 字段都指示48字节。 注意,由CK_SSL3_MASTER_KEY_DERIVE_PARAMS 结构的pVersion 字段指出的CK_VERSION 结构将通过C_DeriveKey 调用来修改。尤其是,当该调用返回时,这个结构将保持与提供的pre_master 密钥相关的SSL版本。 12.37.3 密钥和MAC派生 在SSL 3.0中,密钥、MAC和IV 派生,表示成CKM_SSL3_KEY_AND_MAC_DERIVE, 是一种用来从"master_secret"密钥和随机数据中派生由"CipherSuite"使用的适宜的加密密钥材料的机制。该机制返回过程中生成的密钥的密钥句柄以及建立的IV。 它有一个参数,即CK_SSL3_KEY_MAT_PARAMS 结构,它允许把随机数据以及给定的CipherSuite 的密码材料的特性和指针传送给接收生成的句柄和IV结构。章节中有这种结构的定义。 该机制有助于在这个令牌上建立四个不同的密钥并将两个IV(如果这两个IV被调用程序请求的话)返回给这个调用程序。这些密钥都给出一个CKO_SECRET_KEY 的对象分类。 对于这两个MACing 密钥("client_write_MAC_secret" 和"server_write_MAC_secret") 始终给出CKK_GENERIC_SECRET类型。对于签名、验证和派生操作它们被标志为有效。 对于其它两个密钥("client_write_key" 和 "server_write_key") 则根据C_DeriveKey 函数调用期间随同该机制一起发送的这个属性单元中的信息给出类型。通过缺省,对于加密、脱密和派生操作它们被标志为有效。 如果CK_SSL_KEY_MAT_PARAMS 字段的ulIVSizeInBits 字段具有一个非零值,则IV将被生成并被返回。如果它们被生成,它们的位中长度将与ulIVSizeInBits 字段中的值一致。 所有四个密钥都继承基本密钥的CKA_SENSITIVE, CKA_ALWAYS_SENSITIVE, CKA_EXTRACTABLE, 和 CKA_NEVER_EXTRACTABLE 属性的值。对于这些属性9这些属性与基本密钥保持的属性不同)的任何属性提供给C_DeriveKey 的这个属性单元可以不规定值。 注意,由CK_SSL3_KEY_MAT_PARAMS 结构的pReturnedKeyMaterial 字段指向的CK_SSL3_KEY_MAT_OUT 结构将通过C_DeriveKey 调用来修改。尤其是,CK_SSL3_KEY_MAT_OUT 结构中的四个密钥句柄;另外,由CK_SSL3_KEY_MAT_OUT 结构的pIVClient 和pIVServer 字段指向的缓冲器将有在它们中返回的IV(如果这些IV被这个调用程序请求的话)。因此,这两个字段必须指明具有充分空间的缓冲器以便保持将被返回的任何IV。 在其返回的信息上,该机制与Cryptoki 中其它密钥派生机制不一致。对于大多数的密钥派生机制来说,C_DeriveKey 返回单个密钥句柄作为成功完成的结果。然而,由于CKM_SSL3_KEY_AND_MAC_DERIVE 机制返回中规定为机制参数的CK_SSL3_KEY_MAT_PARAMS 结构指出的CK_SSL3_KEY_MAT_OUT 结构中的所有的它的密钥句柄,因此传送给C_DeriveKey 的参数phKey 是不必须的,并且应是一个NULL_PTR 。 如果使用这种机制调用C_DeriveKey 失败,那么在这个令牌上将不会建立这四个密钥中任何一个密钥。 10.37.4 SSL 3.0中的MD5 MACing SSL3.0中的MD5 MACing ,表示成CKM_SSL3_MD5_MAC, 是一种基于SSL3.0协议使用MD5进行单方和多方签名(数字鉴别)和验证的机制。该技术十分类似于HMAC技术。 它有一个参数,即CK_MAC_GENERAL_PARAMS,它规定由该机制生成的签名的字节中的长度。 下表列出密钥类型和输入输出数据长度的限制: 表124, SSL 3.0中的MD5 MACing: 密钥和数据长度 函数 密钥类型 数据长度 签名长度 C_Sign 类属保密 任意 4-8,取决于参数 C_Verify 类属保密 任意 4-8, 取决于参数 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和 ulMaxKeySize 字段规定位中类属保密密钥长度的支持范围。 10.37.5 SSL 3.0中的SHA-1 MACing SSL3.0中的SHA-1MACing ,表示成CKM_SSL3_SHA1_MAC, 是一种基于SSL3.0协议使用SHA-1进行单方和多方签名(数字鉴别)和验证的机制。该技术十分类似于HMAC技术。 它有一个参数,即CK_MAC_GENERAL_PARAMS,它规定由该机制生成的签名的字节中的长度。 下表列出密钥类型和输入输出数据长度的限制: 表125, 中的SHA-1 MD5 MACing: 密钥和数据长度 函数 密钥类型 数据长度 签名长度 C_Sign 类属保密 任意 4-8,取决于参数 C_Verify 类属保密 任意 4-8, 取决于参数 对于该机制,CK_MECHANISM_INFO 结构的ulMinKeySize 和 ulMaxKeySize 字段规定位中类属保密密钥长度的支持范围。 12.38 混杂简单密钥派生机制的参数 CK_KEY_DERIVATION_STRING_DATA; CK_KEY_DERIVATION_STRING_DATA_PTR CK_KEY_DERIVATION_STRING_DATA 是一种结构,该结构保持一个字节串和该字节串长度的指针。它给CKM_CONCATENATE_BASE_AND_DATA, CKM_CONCATENATE_DATA_AND_BASE, 和 CKM_XOR_BASE_AND_DATA 机制提供参数。定义如下: typedef struct CK_KEY_DERIVATION_STRING_DATA { CK_BYTE_PTR pData; CK_ULONG ulLen; } CK_KEY_DERIVATION_STRING_DATA; 该结构的字段具有下列含义: pData 这个字节串的指针 ulLen 这个字节串的长度 CK_KEY_DERIVATION_STRING_DATA_PTR 是CK_KEY_DERIVATION_STRING_DATA的一个指针。 CK_EXTRACT_PARAMS; CK_EXTRACT_PARAMS_PTR CK_KEY_EXTRACT_PARAMS 为CKM_EXTRACT_KEY_FROM_KEY 机制提供参数。它规定基本密钥的哪一位应用作派生密钥的第一个位。定义如下: typedef CK_ULONG CK_EXTRACT_PARAMS; CK_EXTRACT_PARAMS_PTR 是CK_EXTRACT_PARAMS的一个指针。 12.39 混杂简单密钥派生机制 12.39.1 一个基本密钥和另一密钥的连接 该机制,表示成CKM_CONCATENATE_BASE_AND_KEY, 从两个现有保密密钥的连接中派生一个保密密钥。这两个密钥由句柄规定;所规定的这些密钥的值在一个缓冲器中连接在一起。 该机制取一个参数,即CK_OBJECT_HANDLE。该句柄产生密钥值信息,该密钥值附加在基本密钥值消息的尾部(基本密钥这样一个密钥,它的句柄作为一个变量提供给C_DeriveKey) 例如,如果基本密钥的值是0x01234567, 而另一密钥的值是0x89ABCDEF, 那么派生密钥的值将从一个含0x0123456789ABCDEF这个一样串的缓冲器中取出。 如果在这个属性单元中未提供密钥类型或长度,那么由这种机制生成的密钥将是一个类属保密密钥。它的长度将等于这两个原始密钥的值的长度的总和。 如果这个属性单元中未提供密钥类型,而只提供长度,那么该机制产生的密钥将是一个规定长度的类属保密密钥。 如果这个属性单元中未提供长度,而提供密钥类型,那么该密钥类型必须有严格定义的长度。如果是这样,则该机制产生的密钥将具有这个属性单元中规定的类型。如果不是,则返回一个错误。 如果这个属性单元中提供密钥类型和长度,那么长度必须和密钥类型兼容。该机制产生的密钥将具有规定的类型和长度。 如果使用这种机制派生出一个DES, DES2, DES3, 或CDMF 密钥,那么该密钥的奇偶校验位将被正确地设置。 如果密钥的所需类型需要的字节多于由连接两个原始密钥的值而具有的字节,则产生错误。 就密钥的灵敏性和可萃性来说,该机制具有如下的规则: 如果这两个原始密钥的任何一个密钥具有其它的设置成TRUE的CKA_SENSITIVE 属性,那么派生的密钥也是这样的。如果不是这样,那么派生密钥的CKA_SENSITIVE 属性则从所提供的这个属性单元中设置或从缺省值中设置。 同样,如果这两个原始密钥中的任何一个密钥具有它的设置成FALSE的CKA_EXTRACTABLE 属性,那么派生密钥也是这样的。如果不是这样,那么派生密钥的CKA_EXTRACTABLE 属性则从所提供的这个属性单元中设置或从缺省值中设置。 但并且仅当这两个原始密钥都具有它们的设置成TRUE的CKA_ALWAYS_SENSITIVE 属性,那么派生密钥的CKA_ALWAYS_SENSITIVE 属性才被设置成TRUE。 同样,当并且仅当这两个原始密钥都具有它们的设置成TRUE的CKA_NEVER_EXTRACTABLE 属性,那么派生密钥的CKA_NEVER_EXTRACTABLE 属性才被设置成TRUE。 12.39.2 一个基本密钥和数据的连接 该机制表示成,CKM_CONCATENATE_BASE_AND_DATA, 通过把数据连接到指定保密密钥的末端来派生一个保密密钥。 该机制取一个参数,即CK_KEY_DERIVATION_STRING_DATA 结构,它规定将要附加到基本密钥来派生另一密钥的数据的长度和值。 例如,如果基本密钥的值是0x01234567, 而数据的值是0x89ABCDEF, 那么派生密钥的值将从含0x0123456789ABCDEF这个串的缓冲器中取出。 如果在这个属性单元中未提供密钥类型或长度,那么由这种机制生成的密钥将是一个类属保密密钥。它的长度将等于原始密钥和这个数据的值的长度的总和。 如果这个属性单元中未提供密钥类型,而提供度,那么该机制产生的密钥将是一个规定长度的类属保密密钥。 如果这个属性单元中没有提供长度,而提供了密钥类型,那么该密钥类型必须有严格定义的长度。如果是这样,则该机制产生的密钥将具有这个属性单元中规定的类型。如果不是,则返回一个错误。 如果这个属性单元中提供密钥类型和长度,那么长度必须和密钥类型兼容。该机制产生的密钥将具有规定的类型和长度。 如果使用这种机制派生出一个DES, DES2, DES3, 或CDMF 密钥,那么该密钥的奇偶校验位将被正确地设置。 如果密钥的所需类型需要的字节多于由连接两个原始密钥的值而具有的字节,则产生错误。 就密钥的灵敏性和可萃性来说,该机制具有如下的规则: 如果基本密钥具有它的设置成TRUE的CKA_SENSITIVE 属性,那么派生的密钥也是这样。如果不是这样,那么派生密钥的CKA_SENSITIVE 属性从所提供的这个属性单元中设置或从缺省值中设置。 同样,如果基本密钥具有它的设置成TRUE的CKA_EXTRACTABLE 属性,那么派生密钥也是这样。如果不是,那么派生密钥的CKA_EXTRACTABLE 属性从所提供的这个属性单元中设置或从缺省值中设置。 当并且仅当基本密钥具有它的设置成TRUE的 CKA_ALWAYS_SENSITIVE 属性,派生密钥的CKA_ALWAYS_SENSITIVE 属性才被设置成TRUE。 同样,当仅当基本密钥具有它的设置成TRUE的CKA_NEVER_EXTRACTABLE 属性,派生密钥的CKA_NEVER_EXTRACTABLE 属性才被设置成TRUE。 12.39.3 数据和一个基本密钥的连接 该机制,表示成CKM_CONCATENATE_DATA_AND_BASE, 通过把数据预附在一个指定保密密钥的起始处来派生一个保密密钥。 该机制取一个参数,即CK_KEY_DERIVATION_STRING_DATA 结构,它规定将要附加到基本密钥来派生另一密钥的数据的长度和值。 例如,如果基本密钥的值是0x01234567, 而数据的值是0x89ABCDEF, 那么派生密钥的值将从含0x89ABCDEF01234567这个串的缓冲器中取出。 如果在这个属性单元中未提供密钥类型或长度,那么由这种机制生成的密钥将是一个类属保密密钥。它的长度将等于原始密钥的和这个数据的值的长度的总和。 如果这个属性单元中未提供密钥类型,而提供度,那么该机制产生的密钥将是一个规定长度的类属保密密钥。 如果这个属性单元中没有提供长度,而提供了密钥类型,那么该密钥类型必须有严格定义的长度。如果是这样,则该机制产生的密钥将具有这个属性单元中规定的类型。如果不是,则返回一个错误。 如果这个属性单元中提供密钥类型和长度,那么长度必须和密钥类型兼容。该机制产生的密钥将具有规定的类型和长度。 如果使用这种机制派生出一个DES, DES2, DES3, 或CDMF 密钥,那么该密钥的奇偶校验位将被正确地设置。 如果密钥的所需类型需要的字节多于由连接两个原始密钥的值而具有的字节,则产生错误。 就密钥的灵敏性和可萃性来说,该机制具有如下的规则: 如果基本密钥具有它的设置成TRUE的CKA_SENSITIVE 属性,那么派生的密钥也是这样。如果不是这样,那么派生密钥的CKA_SENSITIVE 属性从所提供的这个属性单元中设置或从缺省值中设置。 同样,如果基本密钥具有它的设置成TRUE的CKA_EXTRACTABLE 属性,那么派生密钥也是这样。如果不是,那么派生密钥的CKA_EXTRACTABLE 属性从所提供的这个属性单元中设置或从缺省值中设置。 当并且仅当基本密钥具有它的设置成TRUE的 CKA_ALWAYS_SENSITIVE 属性,派生密钥的CKA_ALWAYS_SENSITIVE 属性才被设置成TRUE。 同样,当仅当基本密钥具有它的设置成TRUE的CKA_NEVER_EXTRACTABLE 属性,派生密钥的CKA_NEVER_EXTRACTABLE 属性才被设置成TRUE。 12.39.4 将一个密钥和数据执行“异或”运算 XORing 密钥推倒,表示成CKM_XOR_BASE_AND_DATA, 是一种机制,该机制通过对由一个基本密钥句柄指示的一个密钥与某一数据执行按位“异或”运算提供派生一个保密密钥的能力。 该机制取一个参数,即CK_KEY_DERIVATION_STRING_DATA 结构,它规定将原始密钥的值与其进行XRO运算的数据。 例如,如果基本密钥的值是0x01234567, 而数据的值是0x89ABCDEF, 那么派生密钥的值将从含0x88888888这个串的缓冲器中取出。 如果在这个属性单元中未提供密钥类型或长度,那么由这种机制生成的密钥将是一个类属保密密钥。它的长度将等于原始密钥的和这个数据的值的长度的最小值。 如果这个属性单元中未提供密钥类型,而提供度,那么该机制产生的密钥将是一个规定长度的类属保密密钥。 如果这个属性单元中没有提供长度,而提供了密钥类型,那么该密钥类型必须有严格定义的长度。如果是这样,则该机制产生的密钥将具有这个属性单元中规定的类型。如果不是,则返回一个错误。 如果这个属性单元中提供密钥类型和长度,那么长度必须和密钥类型兼容。该机制产生的密钥将具有规定的类型和长度。 如果使用这种机制派生出一个DES, DES2, DES3, 或CDMF 密钥,那么该密钥的奇偶校验位将被正确地设置。 如果密钥的所需类型需要的字节多于由连接两个原始密钥值中较短的那个而存在的字节数,则产生一个错误。 就密钥的灵敏性和可萃性来说,该机制具有如下的规则: 如果基本密钥具有它的设置成TRUE的CKA_SENSITIVE 属性,那么派生的密钥也是这样。如果不是这样,那么派生密钥的CKA_SENSITIVE 属性从所提供的这个属性单元中设置或从缺省值中设置。 同样,如果基本密钥具有它的设置成TRUE的CKA_EXTRACTABLE 属性,那么派生密钥也是这样。如果不是,那么派生密钥的CKA_EXTRACTABLE 属性从所提供的这个属性单元中设置或从缺省值中设置。 当并且仅当基本密钥具有它的设置成TRUE的 CKA_ALWAYS_SENSITIVE 属性,派生密钥的CKA_ALWAYS_SENSITIVE 属性才被设置成TRUE。 同样,当仅当基本密钥具有它的设置成TRUE的CKA_NEVER_EXTRACTABLE 属性,派生密钥的CKA_NEVER_EXTRACTABLE 属性才被设置成TRUE。 12.39.5 一个密钥从另一个密钥中折取 从另一个密钥折取一个密钥,表示成CKM_EXTRACT_KEY_FROM_KEY, 是一种机制,该机制提供从另一保密密钥的位中建立一个保密密钥的能力。 该机制有一个参数,即CK_EXTRACT_PARAMS, 它规定原始密钥的哪一个位应当用作新派生密钥的第一个位。 我们给出一个例子来说明这种机制是如何工作的。假定一个令牌具有一个保密密钥,该保密密钥具有4字节值0x329F84A9。我们将从这一密钥派生一个2字节保密密钥,从位的位置21处开始(即CKM_EXTRACT_KEY_FROM_KEY 机制的参数值是21)。 1. 我们以二进制写下这个密钥的值:0011 0010 1001 1111 1000 0100 1010 1001。我们把这个二进制串看作是包含了这个密钥的这些32位,标记成b0, b1, …, b31。 2. 然后我们从这个二进制串中抽取16个连续的位(即2字节),从b21开始。我们得到的二进制串是1001 0101 0010 0110。 3. 因此新密钥的值是0x9526。 注意,当构成派生密钥的这个值时,允许把代表原始密钥的值的这个二进制串的末端环绕(抱合)起来。 如果在这个过程中使用的原始密钥是敏感的,那么派生密钥对于成功进行的派生也必须是敏感的。 如果在这个属性单元中即未提供长度又未提供密钥类型,那么将返回一个错误。 如果这个属性单元中未提供密钥类型,而提供度,那么该机制产生的密钥将是一个规定长度的类属保密密钥。 如果这个属性单元中没有提供长度,而提供了密钥类型,那么该密钥类型必须有严格定义的长度。如果是这样,则该机制产生的密钥将具有这个属性单元中规定的类型。如果不是,则返回一个错误。 如果这个属性单元中提供密钥类型和长度,那么长度必须和密钥类型兼容。该机制产生的密钥将具有规定的类型和长度。 如果使用这种机制派生出一个DES, DES2, DES3, 或CDMF 密钥,那么该密钥的奇偶校验位将被正确地设置。 如果密钥的所需类型需要的字节多于由连接两个原始密钥值具有的字节,则产生一个错误。 就密钥的灵敏性和可萃性来说,该机制具有如下的规则: 如果基本密钥具有它的设置成TRUE的CKA_SENSITIVE 属性,那么派生的密钥也是这样。如果不是这样,那么派生密钥的CKA_SENSITIVE 属性从所提供的这个属性单元中设置或从缺省值中设置。 同样,如果基本密钥具有它的设置成TRUE的CKA_EXTRACTABLE 属性,那么派生密钥也是这样。如果不是,那么派生密钥的CKA_EXTRACTABLE 属性从所提供的这个属性单元中设置或从缺省值中设置。 当并且仅当基本密钥具有它的设置成TRUE的 CKA_ALWAYS_SENSITIVE 属性,派生密钥的CKA_ALWAYS_SENSITIVE 属性才被设置成TRUE。 同样,当仅当基本密钥具有它的设置成TRUE的CKA_NEVER_EXTRACTABLE 属性,派生密钥的CKA_NEVER_EXTRACTABLE 属性才被设置成TRUE。 12.40 RIPE-MD 128 机制 12.40.1 RIPE-MD 128 RIPE-MD 128机制,表示成CKM_RIPEMD128, 是一种遵守RIPE-MD 128 消息摘要算法的用于消息摘要的机制。 它没有参数。 下表列出了数据长度的限制: 表126, RIPE-MD 128: 数据长度 函数 数据长度 摘要长度 C_Digest 任意 16 12.40.2 通用长度RIPE-MD 128-HMAC 通用长度RIPE-MD 128-HMAC机制,表示成CKM_RIPEMD128_HMAC_GENERAL,是一种用于签名和验证的机制。它使用HMAC结构,基于RIPE-MD 128散列函数。它使用的这些密钥是类属保密密钥。 它有一个参数,即CK_MAC_GENERAL_PARAMS, 它保持所需字节中的长度。这一长度应在0-16的范围内(RIPE-MD 128的输出长度是16字节)。由该机制生成的签名(MAC)将从全16字节HMAC输出的起始处获取。 表127, 通用长度RIPE-MD 128-HMAC: 函数 密钥类型 数据长度 签名长度 C_Sign 类属保密 任意 0-16, 视参数而定 C_Verify 类属保密 任意 0-16, 视参数而定 12.40.3 RIPE-MD 128-HMAC RIPE-MD 128-HMAC 机制,表示成CKM_RIPEMD128_HMAC, 是章节中通用长度RIPE-MD 128-HMAC 机制的特例。 它没有参数,始终生成一个长度为16的输出。 12.41 RIPE-MD 160 机制 12.41.1 RIPE-MD 160 RIPE-MD 160 机制,表示成CKM_RIPEMD160, 是一种用于遵守ISO-10118中定义的RIPE-MD 160消息摘要算法的消息摘要机制。 它没有参数。 下表列出数据长度的限制: 表128, RIPE-MD 160: 数据长度 函数 数据长度 摘要长度 C_Digest 任意 20 12.41.2 通用长度RIPE-MD 160-HMAC 通用长度RIPE-MD 160-HMAC 机制,表示成CKM_RIPEMD160_HMAC_GENERAL, 是一种用于签名和验证的机制。它使用HMAC结构,基于RIPE-MD 160散列函数。它使用的密钥是类属保密密钥。 它有一个参数,即CK_MAC_GENERAL_PARAMS, 它保持所需输出的字节中的长度。这一长度应当在0-20的范围内(RIPE-MD 160的输出长度是20字节)。由该机制生成的签名将从全20字节HMAC输出的起始处获取。 表129, 通用长度RIPE-MD 160-HMAC: 函数 密钥类型 数据长度 签名长度 C_Sign 类属保密 任意 0-20, 取决于参数 C_Verify 类属保密 任意 0-20, 取决于参数 12.41.3 RIPE-MD 160-HMAC RIPE-MD 160-HMAC 机制,表示成CKM_RIPEMD160_HMAC, 是章节.中的通用长度RIPE-MD 160-HMAC 机制的特例。 它没有参数,始终生成长度为20的输出。 13. Cryptoki 警告和提示 在这一章节里我们说明、评论和/或强调Cryptoki 如何工作的奇特之事和带有结局性的事情。 13.1 操作、会话和线程 Cryptoki中,有一些不同类型的操作,这些操作在会话中可能是“active”的。一个“active”操作本质是这样一个操作,它取多个Cryptoki函数调用来执行。这些类型的“active”操作是目标搜索;加密、脱密、消息摘要、带附录的验证和带恢复的验证。 一个给定的会话一次可以有0, 1,或 2个操作是“active”的。在同一时间只可有2个操作是active的,即使这个令牌支持这样做;并且这两个操作必须是下面四个操作对中的一对;摘要和加密,脱密和摘要,签名和加密,脱密和验证。 如果一个应用程序试图初始化一个会话中的一个操作(使其成为active),但由于某些其它的active操作。该应用程序接收了这个错误值CKR_OPERATION_ACTIVE,使应用程序试图初始化会话中的一个操作不能实现。如果一个会话有了一个active操作并且这个应用程序试图使用那个会话去执行不能成为active的但要求密文处理的(例如使用这个令牌的随机数发生器,或生成/加密/脱密/派生一个密钥)任何一个不同的操作,那么也可能收到这个错误值。 一个应用程序的不同线程绝对不应共享一些会话,除非这些不同的线程极其谨慎地在同一时间不进行几个函数调用。即使这个Cryptoki 库用线程安全赋能锁初始化了也是这样。 13.2 多应用程序访问特性 当多个应用程序或一个应用程序中的多个线程正在访问一组公共目标时,那么目标保护的问题变的重要起来。尤其是当应用程序A使用目标O启动一个操作,而应用程序B试图在应用程序A完成了这个操作之前删除0更是这样。但设备能力的不同作出一个绝对的性能规范是不现实的。这里对目标将保护特性给出一些一般的指导原则。 只要有可能,删除一个应用程序中的一个目标不应造成那个目标对正在在一个active操作中使用这个目标的另一应用程序或线程在那个操作完成之前不可使用。例如,应用程序A使用私钥P开始了一个签名操作,而应用程序B试图在该签名正在进行中的一种。要么从这个设备中删除这个目标,但该操作是允许完成的,因为这个操作使用这个目标的一个临时的拷贝,要么限制这个删除操作直至完成了这个签名操作。如果在现实中不能支持这两个动作中的任何一个,那么错误代码CKR_OBJECT_HANDLE_INVALID可能返回个应用程序A以指示正在被使用的执行它的active操作的应用程序。 只要有可能,改变一个目标属性的值就会影响另一些应用程序或线程中的active操作的动作。如果在一个现实中这一点得不到支持,那么指示失败原因的适宜的错误代码应当返回给具有这个active操作的应用程序。 13.3 目标,属性和属性单元 Cryptoki中,每个目标(RSA私钥可能是个例外)始终具有Cryptoki为它的类型的一个目标规定的所有可能的属性。这意味着,例如,一个Diffie-Hellman私钥始终具有一个 CKA_VALUE_BITS 属性,即使当生成这个密钥时未规定这个属性(在这样一种情况下,在密钥生成过程中计算这个属性的正确性)。 一般来说,为一个目标要求一个属性单元的一个Cryptoki函数需要这个属性单元来显式地或隐式地规定另外未规定的属性。如果一个属性单元不止一次地规定一个特定的属性,那么这个函数可以返回CKR_TEMPLATE_INVALID 或者它可以规定的这些属性值中选择一个特定的属性值并使用那个值。在任何情况下,这些目标属性始终是单值的(valued)。 13.4 带恢复的签名 带恢复的签名是一般数字签名(“signing with appendix”) 的普通代替方法,它受到某些机制的支持。记得对于一般数字签名来说,一个消息的签名是作为这个消息和签名人的私钥的某种函数而计算的;那么这种签名(与这个消息和签名人的公共密钥一起)可以用作验证过程的输入,而验证过程得到简单的“签名有效/签名无效”的判定。 带恢复的签名还可从一个消息和签名人的私钥中建立一个签名。然而,为了验证这个签名,不需要消息作为输入。只有这个签名和签名人的公共密钥是验证过程的输入,而验证过程输出“签名有效”或者在该签名有效时输出原始消息。 让我们考虑使用CKM_RSA_X_509 机制的一个简单例子。这里,一个消息是一个字节串,我们把它考虑成是一个数模n (签名人RSA数模)。当把这种机制用于一般数字签名时(带附录的签名),那个签名是通过把这个消息提高到签名人的私有指数模n而计算的。为了验证这个签名,一个验证人把这个签名提高到签名人的公共指数模n而且但并且仅当结果符合原始消息时认为这个签名是有效的。 如果CKM_RSA_X_509 用来建立带恢复的签名,那么这些签名则以完全相同的方式生成。对于这种特别的机制,任何数模n都是有效签名。为了从一个签名中恢复这个消息,将该签名提高到签名人的公共指数模n。 Appendix A. 令牌剖析 本附录对一个令牌在各种常见类型的应用中应该支持的机制集做一些剖析。预计这些机制会作为各种应用的一部分而标准化,比如满足给应用提供密码服务的这样一个模块上的一系列要求(这个模块在某些情况下可以是一个Cryptoki 令牌)。因此,这些剖析在这里仅仅作为参照,它们并不是该标准的一部分。 下表给出与两种常见类型的应用相关的机制: 表 A-1, 机制和剖析 应用 机制 仅用于政府鉴别 单元数字包数据 CKM_DSA_KEY_PAIR_GEN  CKM_DSA  CKM_DH_PKCS_KEY_PAIR_GEN  CKM_DH_PKCS_DERIVE  CKM_RC4_KEY_GEN  CKM_RC4  CKM_SHA_1  A.1 仅用于政府鉴别 美国政府在FIPS PUB 180-1中定义的用于消息摘要的保密散列算法上已经实现了标准化。相关的机制有: DSA 密钥生成(512-1024 位) DSA (512-1024 位) SHA-1 注意,本版的Cryptoki 没有一种机制用来生成DSA参数。 A.2 单元数字包数据 单元数字包数据Cellular Digital Packet Data (CDPD) 是一个用于无线通信的协议集。支持CDPD应用的机制的基本集有: Diffie-Hellman 密钥生成(256-1024 位) Diffie-Hellman 密钥派生(256-1024 位) RC4 密钥生成 (40-128 位) RC4 (40-128 位) (最初的CDPD保密规范把Diffie-Hellman 密钥的长度限制在256位上,但已建议把这个长度提高到512位。)。 注意该版的Cryptoki 没有一个机制用来生成Diffie-Hellman 参数。 Appendix B. Cryptoki 和其它API的比较 该附录把Cryptoki 与下列密码的API进行了比较: ANSI N13-94 - Guideline X9.TG-12-199X, 使用金融系统中的Tessera:一个应用程序接口,1994年4月29日。 X/Open GCS-API – 类属密钥服务API,草案2,1995年2月14日 B.1 FORTEZZA CIPG, 修订版 1.52 该文件定义了对FORTEZZA PCMCIA Crypto 卡的API。是在类似于Cryptoki的级上。下表列出FORTEZZA CIPG 函数,一切列出的还有等效的Cryptoki 函数: 表 B-1, FORTEZZA CIPG vs. Cryptoki FORTEZZA CIPG Equivalent Cryptoki CI_ChangePIN C_InitPIN, C_SetPIN CI_CheckPIN C_Login CI_Close C_CloseSession CI_Decrypt C_DecryptInit, C_Decrypt, C_DecryptUpdate, C_DecryptFinal CI_DeleteCertificate C_DestroyObject CI_DeleteKey C_DestroyObject CI_Encrypt C_EncryptInit, C_Encrypt, C_EncryptUpdate, C_EncryptFinal CI_ExtractX C_WrapKey CI_GenerateIV C_GenerateRandom CI_GenerateMEK C_GenerateKey CI_GenerateRa C_GenerateRandom CI_GenerateRandom C_GenerateRandom CI_GenerateTEK C_GenerateKey CI_GenerateX C_GenerateKeyPair CI_GetCertificate C_FindObjects CI_Configuration C_GetTokenInfo CI_GetHash C_DigestInit, C_Digest, C_DigestUpdate, and C_DigestFinal CI_GetIV No equivalent CI_GetPersonalityList C_FindObjects CI_GetState C_GetSessionInfo CI_GetStatus C_GetTokenInfo CI_GetTime C_GetTokenInfo or C_GetAttributeValue(clock object) [preferred] CI_Hash C_DigestInit, C_Digest, C_DigestUpdate, and C_DigestFinal CI_Initialize C_Initialize CI_InitializeHash C_DigestInit CI_InstallX C_UnwrapKey CI_LoadCertificate C_CreateObject CI_LoadDSAParameters C_CreateObject CI_LoadInitValues C_SeedRandom CI_LoadIV C_EncryptInit, C_DecryptInit CI_LoadK C_SignInit CI_LoadPublicKeyParameters C_CreateObject CI_LoadPIN C_SetPIN CI_LoadX C_CreateObject CI_Lock Implicit in session management CI_Open C_OpenSession CI_RelayX C_WrapKey CI_Reset C_CloseAllSessions CI_Restore Implicit in session management CI_Save Implicit in session management CI_Select C_OpenSession CI_SetConfiguration No equivalent CI_SetKey C_EncryptInit, C_DecryptInit CI_SetMode C_EncryptInit, C_DecryptInit CI_SetPersonality C_CreateObject CI_SetTime No equivalent CI_Sign C_SignInit, C_Sign CI_Terminate C_CloseAllSessions CI_Timestamp C_SignInit, C_Sign CI_Unlock Implicit in session management CI_UnwrapKey C_UnwrapKey CI_VerifySignature C_VerifyInit, C_Verify CI_VerifyTimestamp C_VerifyInit, C_Verify CI_WrapKey C_WrapKey CI_Zeroize C_InitToken B.2 GCS-API 提出的这一标准将一个API定义到更高级的保密服务上例如一致性和数据起源、非否定、分离和保护的鉴别。它比Cryptoki 更高级。下表列出GCS-API 函数和用来实现这些功能的Cryptoki函数。注意完全支持GCS-API留给未来版本的Cryptoki。 表 B-2, GCS-API vs. Cryptoki GCS-API Cryptoki implementation retrieve_CC release_CC generate_hash C_DigestInit, C_Digest generate_random_number C_GenerateRandom generate_checkvalue C_SignInit, C_Sign, C_SignUpdate, C_SignFinal verify_checkvalue C_VerifyInit, C_Verify, C_VerifyUpdate, C_VerifyFinal data_encipher C_EncryptInit, C_Encrypt, C_EncryptUpdate, C_EncryptFinal data_decipher C_DecryptInit, C_Decrypt, C_DecryptUpdate, C_DecryptFinal create_CC derive_key C_DeriveKey generate_key C_GenerateKey store_CC delete_CC replicate_CC export_key C_WrapKey import_key C_UnwrapKey archive_CC C_WrapKey restore_CC C_UnwrapKey Set_key_state generate_key_pattern verify_key_pattern derive_clear_key C_DeriveKey generate_clear_key C_GenerateKey load_key_parts clear_key_encipher C_WrapKey clear_key_decipher C_UnwrapKey change_key_context load_initial_key generate_initial_key Set_current_master_key protect_under_new_master_key protect_under_current_master_key initialise_random_number_generator C_SeedRandom install_algorithm de_install_algorithm disable_algorithm enable_algorithm Set_defaults Appendix C. 明智的性能考虑 RSA公共密钥加密系统是受美国专利4,405,829 保护的,而RC5 块密码是受美国5,724,428 和5,835,600保护的。尽管可能涉及特殊的基础技术,但RSA保密公司对于该文件描述的结构不作另外的专利声明。 RSA, RC2 和 RC4的是RSA保密公司的注册商标。RC5是RSA保密公司的商标。 CAST, CAST3, CAST5, 和 CAST128是Entrust Technologies的注册商标。 OS/2 和CDMF (Commercial Data Masking Facility) 是IBM公司的注册商标。LYNKS是SPYRUS公司的注册商标。IDEA注册商标是Ascom Systec。 Windows, Windows 3.1, Windows 95, Windows NT, 和 Developer Studio 注册商标的微软公司。UNIX 是UNIX系统实验室的注册商标。FORTEZZA 是国际保密公司的注册商标。 只要在提及或引用本文件的所有材料中认定是“RSA 保密公司公共密钥标准(PKCS)”则准于许可拷贝该文件。 对于它方作出的明智的性能说明RSA保密公司不再作出说明。这样一个决定是用户的职责。 Appendix D. 通过Cryptoki显示一个令牌上多个PIN的方法 下面介绍如何通过这个Cryptoki 接口来显示单个令牌上的多个PIN。在SmartTrust 的一些产品上已经实现该附录中这种功能性来满足一致性的要求,但这是显示PKCS #11 v2.x 库中多个PIN的优选方法。 虚拟槽和令牌 显示多个PIN需要建立一个用于由Cryptoki 库支持的每个PIN的虚拟槽(virtual slot)和令牌对。对于这个库来说,有一个槽和卡,但对这种应用来说,似乎有多个槽和令牌。由于一些库不允许动态地增加槽,因此,当调用 C_Initialize 时,必须从开始就分配所有的虚拟槽。当一个卡插入读出器时,这个库决定在这个卡上有多少PIN然后把那么多的虚卡插入这些虚拟槽中。比如,如果这个库在一个卡上最多支持2个PIN,并且插入的是具有单个PIN的卡,那么这两个虚拟槽中只有一个虚拟槽将出现已插入的一个卡。 使用CK_SLOT_INFO结构中的 slotDescription 字段把代表同一物理设备的一些虚拟槽连在一起。同一设备的所有虚拟槽必须具有同样的slotDescription 值如同实际槽会具有的那样。这就允许了解这种特性的各种应用就象处理具有多个PIN的单个设备那样来处理这些虚拟槽和卡。最终这个库确保了这个slotDescription 值对所有实际槽是独一无二的。 一个卡上的PIN是使用CK_TOKEN_INFO 结构中的tokenLabel 字段来识别的,tokenLabel值从这个实际值和这个PIN标记的结合中产生的。这种格式是" ()" (即 "Electronic ID (PIN1)")。最终,用户就可知道使用的是哪个PIN,即使这个应用并不了解多个PIN。这就需要这个应用显示这个tokenLabel值,假如它想要一个PIN的话。 幸运地是大多数应该都是这样做的。使用上边的格式,这种相结合的令牌和PIN标记限制到29个字节(32减去白空格和括号)。 目标可视度 目标(例如证书、公共密钥和私钥)的虚拟槽中是可见的。这就允许各种应用继续下去,假如私钥是在和对应的证书和/或公共密钥相同的槽中。 这种处理有优点也有缺点。因为该库分开了基于保护对象的PIN上的对象的视图。只能在虚拟卡上使用对象的应用程序将会正确的运行。当一个应用程序试图更新对象时,问题就出现了。该库必须确保证书、公共密钥和私钥在一块虚拟卡上更新。应用程序并不需要使用PIN2的虚拟卡执行私钥,并且更新PIN1的虚拟卡中相应的证书。如果应用程序知道这个访问行为,那这将不是问题,但它将不会成为一个类属PKCS #11 应用程序。当卡由同一间公司发行和更新时,就没有缺点(在大多数情况下都是这样的)。

    Top_arrow
    回到顶部
    EEWORLD下载中心所有资源均来自网友分享,如有侵权,请发送举报邮件到客服邮箱bbs_service@eeworld.com.cn 或通过站内短信息或QQ:273568022联系管理员 高进,我们会尽快处理。