|
Java 智 能 卡 进 阶——Java与 电 子 钱 夹
---- 摘 要 ---- 本 文 描 述 如 何 着 手 去 开 发 一 个 支 持Java 的 智 能 卡。 这 里 所 举 的 例 子 都 基 于Schlumberger Cyberflex 的Java 智 能 卡 系 列 产 品, 这 些 产 品 最 先 对JavaSoft 授 权 的Java Card 1.0 API 提 供 了 支 持。 本 文 所 提 供 的 例 子 展 示 了 在Java 智 能 卡 开 发 过 程 中 的 几 个 步 骤: 如 何 为CyberFlex 智 能 卡 编 制 程 序, 为 下 载 程 序 做 好 准 备, 将 程 序 下 载 至 智 能 卡 中, 最 后 在 智 能 卡 中 运 行 程 序。 除 此 之 外, 还 讨 论 了 以 下 几 方 面 的 内 容: 智 能 卡 的 编 程 技 术、 实 现 基 本 的 安 全 功 能( 例 如 管 脚 确 认) 以 及CyberFlex 智 能 卡 的 个 人 化。 ---- 最 近,JavaSoft 发 布 了Java Card 2.0 API( 这 是JavaSoft 基 于Java 智 能 卡 的 第 二 代 标 准) 并 得 到 了 公 众 的 接 纳, 这 将 导 致 一 些 细 节 上 的 改 变, 但 是 很 多 通 用 的 知 识 和 原 则 仍 然 没 有 过 时。 并 且 因 为CyberFlex 已 经 在 做 这 方 面 的 销 售 工 作, 所 以 实 际 上 你 完 全 可 以 利 用 这 种 技 术 开 发 产 品 并 将 之 推 向 市 场 — — 但 是 你 必 须 认 识 到 技 术 将 随 着Java Card 2.0 API 的 推 出 而 发 生 很 大 的 变 化。Schlumberger 已 经 制 订 好 计 划 生 产 遵 循2.0 API 的CyberFlex 智 能 卡, 但 将 保 持 与Java Card 1.0 API 的 向 后 兼 容 性。 本 文 的 结 尾 是 一 份FAQ。 CyberFlex Java 智 能 卡 简 介---- 在 本 次 专 题 的 前 两 篇 文 章 里( 即《 智 能 卡 基 础 篇》 和《 智 能 卡 与OpenCard 框 架》), 我 们 讨 论 过 如 何 利 用Java 与 智 能 卡 通 信, 以 及 如 何 开 发 一 个 智 能 卡 终 端 接 口。 在Schlumberger 的CyberFlex 智 能 卡 上 运 行 用Java 语 言 编 写 的 程 序。CyberFlex 卡 看 上 去 就 象 一 张 信 用 卡 一 样, 但 实 际 上 它 是 一 个 微 型 的 计 算 机。 该 卡 中 含 有 一 个 具 有 一 定 处 理 能 力 的 微 处 理 器 和 一 片 可 以 存 储 少 量 数 据 和 指 令 的 内 存。 关 于CyberFlex 2.0 与Java 智 能 卡 的 关 系 的 更 多 信 息, 请 参 阅 文 后 的“FAQ” 部 分。 这 种 卡 可 以 按 照 功 能 分 成 以 下 几 个 部 分:
CyberFlex结 构 ---- 一 些 消 费 者 对 于 把 他 们 的 个 人 的 健 康 信 息 和 银 行 信 息 存 储 在 同 一 张 卡 上, 然 后 用 这 张 卡 与 某 些 在 线 服 务 打 交 道 心 存 疑 虑。 智 能 卡 的 制 造 者 已 经 在 这 个 问 题 上 潜 心 数 年, 并 且 已 经 提 出 了 基 于 分 割 的 安 全 方 案。 一 个 简 单 的 例 子---- 我 们 开 始 先 向 大 家 提 供 一 个 极 为 简 单 的 例 子。 正 如 前 文 所 述,ATR("answer to reset") 在ISO7816 这 一 认 可 的 智 能 卡 标 准 中 是 最 为 基 本 的。 当 一 张 智 能 卡 被 复 位 或 是 插 到 阅 读 器 中 时, 它 就 是 通 过ATR 这 一 途 径 提 供 一 些 身 份 确 认 的 信 息。ATR 是 一 个 精 心 定 义 的ISO 标 准。在OpenCard 中 介 绍 了 一 个 出 色 的ATR 卸 出 工 具。---- 我 们 的 第 一 个 例 子 叫 做cardlet( 这 是 智 能 卡 中 运 行 的 一 些Java 类 的 名 字), 它 修 改 了ATR, 可 以 返 回 一 些 特 定 的 信 息。 应 用 程 序 将 会 被 下 载 到 智 能 卡 中, 作 为 启 动 程 序 加 载。 当 智 能 卡 复 位 时, 智 能 卡 通 过 阅 读 器 发 送 到 上 层 应 用 的ATR 是 经 过 我 们 的 应 用 程 序 修 改 的。 完 成 这 项 任 务 要 经 由 以 下 步 骤:
“CardHello” 应 用 程 序---- 下 面 就 是 我 们 所 写 的 应 用 程 序。 我 们 利 用 了 标 准 的ATR, 在 其 域 中 添 入 了“Hello World” 字 符 串。 在ISO 7816-3 中 有ATR 的 详 尽 介 绍。 下 面 是 程 序 的 代 码, 并 加 入 了 详 尽 的 注 释。( 请 注 意2.0 和 以 前 版 本 的 不 同 要 求)/* * CardHello: Custom ATR */ // Use import for CyberFlex 2.0 only; Comment out for pre-release cards // import javacardx.framework.*; public class CardHello { public static void main() { ///////////////////////////////////////// // Without this statement, you could potentially // lock a card out forever. This statement allows the // default system loader to be executed on the // next reset. In other words, without this // statement, the CyberFlex card will run // your downloaded program every time, so if it has // a bug you will be unable to get to it -- // unless, of course, your program has the ability to // unload itself and restore the default loader. ///////////////////////////////////////// _OS.Execute((short)0,(byte)0); // Return control to default loader byte ATR[] = new byte[4]; ATR[0] = 0x3B; //////////////////////////////////////////// // Send the first byte of the ATR to gain some time. // Welcome to the world of real time. Some readers // require responses within x ms of inserting a card, // so we send one byte to the reader to get it to wait, // and then send the rest of the data. //////////////////////////////////////////// _OS.SendMessage(ATR,(byte)1); //////////////////////////////////////////// // Fill the last part of the ATR and send it // starting at ATR[4]. The prior bytes are ATR // data and can be decoded using the ISO 7816 // specification. Unfortunately, ISO charges // you for a copy of the specification. //////////////////////////////////////////// ATR[0] = (0x30 | 0x0a); ATR[1] = 0x15; ATR[2] = 0x00; ATR[3] = 0x49; _OS.SendMessage(ATR,(byte)4); ////////////////////////////// // Write the historical data ////////////////////////////// byte atrHistorical[] = new byte[10]; atrHistorical[0] = 'H'; atrHistorical[1] = 'e'; atrHistorical[2] = 'l'; atrHistorical[3] = 'l'; atrHistorical[4] = 'o'; atrHistorical[5] = 'W'; atrHistorical[6] = 'o'; atrHistorical[7] = 'r'; atrHistorical[8] = 'l'; atrHistorical[9] = 'd'; _OS.SendMessage(atrHistorical,(byte) atrHistorical.length); ////////////////////////////// // Wait here forever ////////////////////////////// while (true) ; } }---- 后 期 处 理: 将Java 类 的 字 节 代 码 转 化 为 智 能 卡 可 识 别 的 格 式为 成 功 编 译 上 面 的 程 序, 你 的 目 录 中 一 定 要 有OS.class 文 件。 这 个 文 件 为 智 能 卡 操 作 系 统 提 供 了 与 智 能 卡 相 关 的 方 法。 这 一 后 期 处 理 步 骤 是 十 分 必 要 的, 它 可 以 将 字 节 代 码 转 换 为 智 能 卡 认 可 的 格 式。 在 此 之 前, 智 能 卡 是 不 能 直 接 理 解Java 类 的 字 节 代 码 的。 运 行mksolo.exe 命 令 后, 你 将 会 得 到 如 下 结 果:Schlumberger (R) (a registered trademark) MakeSolo (a trademark) Post-processor Version 1.001 Copyright (C) Schlumberger Technologies 1997. All rights reserved. Solo size statistics: Output: 238 bytes; Max stack: 8 bytes; Max object: 0 bytes Successfully generated cardlet 'CardHello.bin' 下 载 应 用 程 序---- 下 面 简 单 介 绍 一 下 如 何 利 用EZ Formatter 和Litronic 210 阅 读 器 把Java 程 序 下 载 到CyberFlex 智 能 卡 中。EZ Formatter 是 一 个 用 于 向CyberFlex 智 能 卡 下 载 应 用 程 序 的Windows 95 实 用 工 具。 而Litronic 210 是Schlumberger 开 发 包 中 提 供 的 智 能 卡 阅 读 器。
运 行 并 测 试 应 用 程 序---- 现 在 可 以 开 始 运 行 应 用 程 序 了。 下 一 次 复 位 时, 你 的 程 序 就 开 始 运 行 了。 你 可 以 看 到 上 面 例 子 确 定 的ATR; 在EZ Formatter 中ATR 显 示 在 显 示 器 右 上 角。 假 定 程 序 象 上 面 所 描 述 的 那 样 运 行 了_OS.Execute 命 令, 程 序 运 行 之 后 的 下 一 次 复 位 将 使 智 能 卡 停 在 缺 省 加 载 程 序 里, 这 使 你 能 够 重 复 上 述 过 程 修 改 已 有 的 程 序。 ---- 如 果 要 再 一 次 运 行 同 样 一 段 程 序, 你 可 以 选 择2222 文 件, 选 择Security Manager( 工 具 条 上 的Lock 按 钮), 在Security Manager 中 键 入 你 的Key/Code, 然 后 设 置2222 程 序 再 次 运 行, 跳 过 了“Get Java Program” 和“Download” 两 个 步 骤。 ---- 熟 悉 了 这 些 过 程 之 后, 我 建 议 你 进 一 步 阅 读EZ Formatter 的 文 档, 学 习 如 何 改 进 你 的 程 序。用OpenCard 运 行 例 程---- 安 全 性---- 关 于 智 能 卡 有 许 多 安 全 技 术。 通 行 的 技 术 大 都 基 于 以 下 出 发 点: 在 智 能 卡 中 的 内 容 都 是 安 全 的, 因 为 这 些 内 容 是 以 安 全 的 方 法 放 置 其 中 的, 并 且 智 能 卡 是 抗 篡 改 的。 换 句 话 说, 因 为 你 自 己 把 东 西 放 置 在 你 拥 有 钥 匙 的 房 间 中, 所 以 它 们 总 是 安 全 的。 智 能 卡 具 有 抗 篡 改 的 特 性 — — 这 中 安 全 特 性 使 得 智 能 卡 在 未 经 授 权 的 情 况 下 难 于 被 篡 改 和 干 扰。 为 了 支 持 对 象 和 数 据 在 智 能 卡 之 间 移 动, 可 以 用 访 问 控 制 表 对 访 问 权 限 加 以 控 制。 在 下 载 过 程 中, 我 们 看 到 了 必 须 输 入 一 个 密 匙 才 能 更 新 文 件。 ---- 智 能 卡 经 常 以 文 件 形 式 组 织 在 一 起, 所 以 通 过 设 置 与 文 件 相 关 的 访 问 权 限 和 相 关 的 密 钥, 我 们 可 以 获 得 精 确 的 安 全 性。 举 例 说 来, 你 的 密 钥 仅 仅 允 许 你 读 某 一 文 件, 但 是 我 的 密 钥 却 允 许 我 读 写 同 一 文 件。 为 了 在 最 初 进 行 授 权, 你 需 要 一 个 密 钥, 或 是 设 置 一 个 授 权 密 钥。 我 想 有 一 点 是 十 分 明 显 的, 那 就 是 如 果 你 不 对 安 全 原 则 的 设 定 这 一 权 限 进 行 限 制, 就 毫 无 安 全 性 可 言 了。 ---- 下 面 有 一 个 简 单 的 例 子 展 示 如 何 进 行 持 卡 人 的 身 份 确 认。 持 卡 人 确 认 是 至 关 重 要 的 问 题。 在 这 一 领 域 有 许 多 技 术 和 非 常 复 杂 的 要 求。 例 如, 在OpenCard 中, 我 们 看 到 银 行 方 面 总 是 要 求PIN 恰 好 处 在 智 能 卡 周 围 的“ 信 任 区 域” 之 中。( 安 全 人 员 在 分 析 安 全 方 案 是 总 是 要 定 义 一 部 分 安 全 区; 在 这 里, 智 能 卡、 智 能 卡 阅 读 器、 与 计 算 机 的 连 接 和PIN 入 口 都 属 安 全 区。) 通 常 我 们 利 用 直 接 与PIN 板 连 接 的 智 能 卡 阅 读 器 获 得 安 全 的PIN 入 口, 这 样PIN 就 决 不 会 离 开 阅 读 器 的 环 境。 我 们 的 例 子 并 没 有 使 用 这 一 技 术, 因 为 这 里 的 阅 读 器 没 有PIN 板。 import Java Cardx.framework.*; public class Verifchv { // Constants used throughout the program static final byte ACK_CODE = (byte)0; static final byte BUFFER_LENGTH = 32; static final byte ISO_COMMAND_LENGTH = (byte)5; public static void main () { // Reset the RST bootstrap pointer to the ROM bootstrap _OS.Execute((short)0, (byte)0); byte bReturnStatus; byte pbuffer[] = new byte[ISO_COMMAND_LENGTH]; byte dbuffer[] = new byte[BUFFER_LENGTH]; ///////////////////////////////////////////////////////// // Look for a message that contains the correct key ///////////////////////////////////////////////////////// while (true) { // Command w/ right chv is // pBuffer = C0 20 00 01 08 // dBuffer = 48 49 4A 4B 4C 4D 4E 4F _OS.GetMessage(pbuffer, ISO_COMMAND_LENGTH, ACK_CODE); bReturnStatus = _OS.VerifyCHV(pbuffer[3], dbuffer, (byte)0x00); _OS.SendStatus((byte)bReturnStatus); ///////////////////////////////////////////////////////// // Give the user access and/or data based on success // or failure of the CHV ///////////////////////////////////////////////////////// } } } 智 能 卡 个 人 化 原 则---- 个 人 化 的 问 题 涉 及 到 创 建 一 个 适 于 你 特 定 需 要 的 文 件 结 构。 你 创 建 的 这 些 程 序 或 是 数 据 文 件 被 组 织 到 目 录 或 子 目 录 之 中。CyberFlex 2.0 3K 提 供 了 很 小 的 存 储 空 间。CyberFlex 1.0 引 进 了 一 个 缺 省 的 文 件 系 统。 目 前CyberFlex 2.0 支 持 你 创 建 自 己 的 文 件 系 统; 由 你 根 据 自 身 需 要 对 系 统 进 行 优 化。---- 程 序 文 件 ---- 你 必 须 创 建 一 个 足 以 容 纳 程 序 的 文 件。 开 发 过 程 中, 你 应 该 注 意MakeSolo 给 出 的 统 计 数 字, 确 保 拥 有 足 够 大 的 空 间( 为 保 险 起 见, 最 好 打 出 一 定 的 富 裕 量)。 ---- CHV 文 件 ---- 如 果 你 想 使 用CHV 方 法, 就 必 须 创 建 若 干 特 定 的 文 件。CHV 文 件 对 于 名 字 和 结 构 有 着 非 常 严 格 的 要 求。CHV 所 需 的 两 个 文 件 必 须 位 于 根 目 录 下。CHV1 文 件 的ID 为0000; 而CHV2 的ID 必 须 为0100。 手 册 中 的CHV 部 分 介 绍 了 关 于CHV 许 多 信 息, 本 文 后 面 的 例 子 中 也 对CHV 做 了 介 绍。 ---- 将 结 构 转 变 为 文 件 系 统 布 局 ---- 刚 开 始 你 可 能 无 法 创 建 正 确 的 结 构, 一 般 你 都 得 重 新 创 建。 在CyberFlex 2.0 中, 你 只 能 从 目 录 中 将 上 一 次 创 建 的 文 件 删 除, 因 此 记 住 文 件 的 创 建 顺 序 是 十 分 重 要 的。 你 也 可 以 利 用CyberFlex 加 载 器 中 的Directory APDU 在 你 的 目 录 下 浏 览 所 有 的 文 件, 这 样 你 就 会 对 文 件 结 构 有 一 个 清 晰 的 认 识。。 ---- 例 子: 在2.0 智 能 卡 中 创 建CyberFlex 1.0 缺 省 文 件 结 构 ---- 创 建CyberFlex 1.0 文 件 结 构 的 操 作 步 骤 如 下:
---- 删 除 该 结 构 时, 仅 需 按 照 创 建 步 骤 的 相 反 顺 序 删 除 即 可。
安 全 性---- 前 面 我 们 讨 论 了CHV 和 个 人 化。CHV 作 为 开 端 很 容 易 让 人 理 解。 智 能 卡 最 有 价 值 的 一 个 方 面 就 是 它 们 所 提 供 的 安 全 性。 正 如 上 面 例 子 中 所 展 现 的 那 样, 下 载 和 存 储 程 序 均 需 要 密 钥, 并 且 还 可 以 进 行 持 卡 人 的 身 份 验 证。 下 个 月 我 们 将 更 为 广 泛 和 深 入 的 讨 论 安 全 性 问 题。 我 们 的 讨 论 将 会 集 中 在 以 下 几 方 面:---- 私 用 密 钥 加 密 —— 使 用 同 一 密 钥 进 行 加 密 和 解 密 ---- 公 用 密 钥 加 密 —— 加 密 和 解 密 使 用 两 个 不 同 的 密 钥 ---- 单 向 函 数 —— 这 是 一 种 特 殊 的 函 数, 它 可 以 为 原 始 消 息 生 成 签 名, 用 以 验 证 原 始 消 息 的 可 认 证 性
FAQ---- 有 许 多 问 题 来 自 下 面 两 个 方 面: 智 能 卡 工 业 界 的 读 者 和 用 户。 我 把 这 些 问 题 作 为FAQ 在 这 里 回 答。 ---- PC/SC 与OpenCard 之 间 有 什 么 关 系 ? ---- IBM 和Bull 正 在 积 极 的 开 发PC/SC 的 适 配 器。 它 比 直 接 在PC/SC 中 使 用C 或 是C++ 要 容 易 得 多。 我 不 赞 成 直 接 在PC/SC 的 级 别 开 发, 因 为 这 样 的 应 用 程 序 不 具 有 可 移 植 性。 用OpenCard 或 是 其 它 更 为 高 级 的 标 准 比 较 合 适。 下 个 月, 我 们 将 提 供 更 为 完 整 的OpenCard 实 现。 ---- 我 是 否 可 以 将CyberFlex 和PC/SC 混 用 ? ---- 可 以,Schlumberger 在CyberFlex Developers 手 册 中 提 供 了 这 方 面 的 文 档。 ---- CyberFlex 智 能 卡 的 安 全 模 型 是 什 么 ? ---- 有 多 种 等 级 的 安 全 模 型。 这 种 智 能 卡 提 供 了 加 载 应 用 程 序 和 执 行 持 卡 人 确 认 的 安 全 机 制。 事 实 上, 每 一 种CyberFlex 的 智 能 卡 都 支 持 六 种 标 志 和 密 钥, 可 以 用 于 保 护 不 同 的 应 用 程 序 和 数 据 对 象。 另 外, 借 助 于Java 安 全 防 火 墙,Java 应 用 程 序 不 能 够 访 问 其 它 应 用 程 序 的 数 据。 未 来 的 智 能 卡 将 支 持 工 业 标 准 的 加 密 算 法。 ---- 我 的CyberFlex 程 序 是 否 可 以 移 植 ? ---- 任 何 利 用Java Card 1.0 API 开 发 的 智 能 卡 应 用 都 可 相 互 移 植。 但 是Java Card 2.0 API 的 智 能 卡 就 不 能 再 运 行Java Card 1.0 API 的 应 用 程 序 了, 因 为Java Card 2.0 API 对 于1.0 来 说 不 具 有 向 后 兼 容 性。 但 是,Schlumberger 已 经 决 定 提 供 与 两 个 版 本 的Java Card API 兼 容 的 智 能 卡。 ---- CyberFlex 2.0 是Java 智 能 卡 吗 ? ---- CyberFlex 2.0 是 兼 容 于Java Card 1.0 API 的 第 二 代 产 品。 它 获 得 了JavaSoft 的 许 可, 在 卡 中 运 行Java 虚 拟 机。Java Card 2.0 API 规 范 刚 刚 完 成, 我 们 希 望 在1998 年 的 上 半 年 能 够 有 与2.0 API 兼 容 的 智 能 卡 出 现。 这 里 所 提 供 的 概 念 仍 然 适 用, 但 是 程 序 需 要 修 改。 ---- 如 果 不 将 程 序 下 载 到 智 能 卡 中 如 何 调 试 ? ---- 通 常 需 要 一 个 仿 真 器 实 现 调 试。 ---- 我 可 以 自 己 设 计 安 全 解 决 方 案 吗 ? ---- Schlumberger 提 供 的 一 种CryptoFlex 智 能 卡 是 安 全 的 理 想 之 选, 因 为 这 种 智 能 卡 的 板 上 配 备 了 密 码 处 理 器, 可 以 处 理1024 位 的RSA 密 钥。 我 们 期 望 在1998 年Schlumberger 和 其 它 智 能 卡 厂 家 能 够 提 供 集 成Java 编 程 和 密 码 处 理 能 力 的 智 能 卡。 结 论---- 我 们 向 你 描 述 了 如 何 利 用Schlumberger 的Java 智 能 卡 包 开 发 应 用 程 序。 随 着 时 间 的 推 移, 我 们 期 望2.0 Java Card 规 范 能 够 大 幅 度 的 简 化 应 用 程 序 的 开 发。---- 本 文 中 的 例 子 展 示 了 基 于1.0 Java Card API 的Java 智 能 卡 应 用 程 序 的 开 发 过 程。 我 们 能 够 在100% 的Java 环 境 中 用 各 种 各 样 的JDK 将Java 程 序 编 译 成 类 文 件。Schlumberger 也 提 供 了 一 个Java 版 本 的MakeSolo, 但 是 因 为 它 没 有 一 个 好 的 类 文 件 查 看 器, 所 以Schlumberger 没 把 它 加 入 到 开 发 包 中。Schlumberger 还 提 供 了 一 个 依 赖 于Swing 集 的 仿 真 器 作 为 集 成 开 发 环 境, 这 个 仿 真 器 将 会 在JavaSoft 的 非beta 测 试 版Swing 中 推 出。 编 译:沈 加 翔 文 章 来 源:http://www.javaworld.com/javaworld/jw-02-1998/jw-02-javadev.html 中国计算机世界出版服务公司版权所有
|