Ingenico CPX10.14 のPINパッドを「POS 連携なしの入力装置」にしたい──そう考えたときに最初にぶつかる壁は、デバイス固有の初期化手順と、PCI準拠ゆえのセキュリティ制約です。本記事では、.NET 環境を前提に、CPX10.14を安全に初期化し、PIN 入力(平文ではなく暗号化ブロック)を取得して外部のHSMや銀行APIへ連携するまでの実装と運用設計を、現場で使える粒度で解説します。
質問の背景とゴール
目的:Ingenico CPX10.14 カードリーダ/PINパッドを、POS 連携なしで「単なる入力デバイス」として利用し、利用者の PIN 変更を受け付ける。
要件:.NET(C#)で自作システムに組み込み、初期化方法とキー入力の取得方法を把握する。
結論(先に要点)
- メーカーの開発資料(SDK・コマンド仕様・PINフロー)が必須です。公開情報だけではコマンドや暗号化仕様が不十分なことが多く、開発は進みません。
- CPX10.14 は PCI PIN 準拠デバイスのため、PIN は平文で取得できません。受け取れるのは暗号化 PIN ブロックであり、HSM や銀行系APIで検証・変更を行う設計が前提です。
- インターフェースは多くが USB HID またはシリアル(RS‑232/CDC)。.NET では HID ライブラリ(例:HidSharp)や標準の
SerialPortで通信できますが、コマンド体系はSDK準拠です。 - 実装は「初期化 → キー共有(Key Exchange/DUKPT等)→ 入力待機 → 暗号化PINブロック受信 → HSM/銀行APIへ転送」の順に進めます。
CPX10.14 を「単なる入力デバイス」にできない理由と、できる形
PCI PIN デバイスは「カード会員データ(PAN/PIN)を店舗アプリが触らない」ことを前提に設計されています。平文PINはデバイス外へ出さない設計であり、代わりに暗号化 PIN ブロック(DUKPT などの鍵管理方式で生成)を出力します。よって「平文PINを自アプリで自由に扱う」は要件不適合です。実現できるのは次のいずれかです。
| 方式 | 概要 | メリット | 注意点 |
|---|---|---|---|
| HSM 連携 | 暗号化 PIN ブロックを HSM に転送し、検証・変更を実施 | PCI 準拠の王道。審査にも耐えやすい | HSM 接続・鍵注入(Key Injection)・運用費が必要 |
| 銀行/イシュア API | カード発行体側のAPIでPIN変更/検証を委託 | 自社でHSMを持たなくてよい | 接続契約・セキュリティ審査・地域要件が厳格 |
| 汎用キーパッド代替 | PCI デバイスを使わず、USB 数値キーパッドで入力 | 実装容易・コスト低い | 金融用途のセキュリティは満たさない(PIN用途には不可) |
開発前チェックリスト(最短でつまずかないために)
- Ingenico SDK / 資料:対象機種のコマンド仕様、サンプル、P/Invoke用DLLやヘッダ。
- 鍵関連:キーインジェクションの方法(センター/現地)、鍵の種別(DUKPT、Master/Session)、TR-31運用可否。
- インターフェース:USB HIDなのかCDC/RS‑232なのか。Windowsドライバの導入有無。
- VenderID/ProductID:デバイス検出・HIDオープンに必要。
- 開発・検証環境:テストカード、PIN試験手順、監査ログ、タイムアウト方針。
- 運用・監査:PCI DSS/PIN の範囲、鍵ローテーション、タンパー反応時の手順。
.NET 実装の全体像(アーキテクチャ)
Windows + .NET(6 以上を推奨)を想定し、アプリは「デバイスI/O層」「暗号/鍵管理層」「業務アプリ層」に分離します。
- デバイスI/O層:HID/シリアル経由で端末と送受信(セッション開始、ディスプレイ表示、PIN入力開始、結果受信)。
- 暗号/鍵管理層:HSM へブロック転送、レスポンスの検証、PIN 変更(必要に応じて TR-31/DUKPT コンテキスト保持)。
- 業務アプリ層:ユーザー識別、UI、結果表示、監査ログ生成(平文PIN非保持)。
通信の基本(HID とシリアル)
どちらも「コマンド(要求)」「レスポンス(応答)」の往復で進みます。コマンドのバイト列・フレーミング(ヘッダ/長さ/CRC等)は機種ごとの仕様に依存します。
HID 例:デバイス検出とオープン(C#)
以下は HID デバイスを列挙し、VendorID/ProductID で CPX10.14 を特定してオープンする雛形です。実際の読み書きは SDK の I/O 仕様に従ってください。
// NuGet: HidSharp
using HidSharp;
public sealed class HidDeviceFinder
{
public HidDevice Find(int vendorId, int productId)
{
var list = DeviceList.Local;
var device = list.GetHidDevices(vendorId, productId).FirstOrDefault();
if (device == null) { throw new InvalidOperationException("CPX10.14 が見つかりません。"); }
return device;
}
public HidStream Open(HidDevice device)
{
if (!device.TryOpen(out var stream))
{
throw new IOException("HID ストリームを開けません。アクセス権限/ドライバを確認してください。");
}
stream.ReadTimeout = 5000;
stream.WriteTimeout = 5000;
return stream;
}
}
シリアル例:基本的な送受信(C#)
using System.IO.Ports;
public sealed class SerialClient : IDisposable
{
private readonly SerialPort _port;
public SerialClient(string portName, int baudRate = 115200, Parity parity = Parity.None, int dataBits = 8, StopBits stopBits = StopBits.One)
{
_port = new SerialPort(portName, baudRate, parity, dataBits, stopBits)
{
ReadTimeout = 5000,
WriteTimeout = 5000
};
_port.Open();
}
```
public void Write(byte[] frame) => _port.Write(frame, 0, frame.Length);
public byte[] ReadExact(int length)
{
var buf = new byte[length];
var offset = 0;
while (offset < length)
{
var read = _port.Read(buf, offset, length - offset);
if (read <= 0) throw new TimeoutException("応答がありません。");
offset += read;
}
return buf;
}
public void Dispose() => _port?.Dispose();
```
}
初期化と PIN 入力フロー(雛形)
以下は概念的な手順です。実際のコマンドコードやフィールドは SDK の仕様に従って置き換えてください。
- セッション開始:端末をアプリ制御モードへ。必要なら「アプリ選択」「スクリーンクリア」。
- キー交換:DUKPT の KSN 取得や、Master/Session のセッション鍵ネゴシエーション。(キーの生成/格納/インジェクションは現場手順に従う)
- PIN 入力開始:端末ディスプレイに案内を表示し、マスク/最小最大桁、タイムアウト、連続失敗回数などを設定。
- 結果取得:暗号化 PIN ブロック(+KSN 等)を受信。
- HSM/銀行APIへ転送:PIN 検証/変更を要求。アプリは平文PINを保持しない。
- ユーザー通知:成功/失敗を表示、監査ログ(機微情報を除外)を記録。
擬似コマンドフレーム(例)
仕様のない場でのプロトコル試行錯誤は厳禁です。ここでは「フレーム分割」「チェックサム」「長さフィールド」といった考え方だけを示します。
public static class Frame
{
// 例: [STX][LENH][LENL][CMD][PAYLOAD...][LRC]
public static byte[] Build(byte cmd, ReadOnlySpan<byte> payload)
{
var length = 1 + payload.Length; // CMD + PAYLOAD
var buf = new byte[1 + 2 + length + 1];
buf[0] = 0x02; // STX
buf[1] = (byte)((length >> 8) & 0xFF);
buf[2] = (byte)(length & 0xFF);
buf[3] = cmd;
payload.CopyTo(buf.AsSpan(4));
buf[^1] = CalcLrc(buf.AsSpan(1, 2 + length)); // LRC over LEN+BODY
return buf;
}
private static byte CalcLrc(ReadOnlySpan<byte> span)
{
byte lrc = 0;
foreach (var b in span) { lrc ^= b; }
return lrc;
}
}
// 使用例(実際の CMD コードは SDK の定義に差し替え)
byte CMD_SESSION_START = 0x30;
byte CMD_PIN_ENTRY_START = 0x31;
var start = Frame.Build(CMD_SESSION_START, ReadOnlySpan<byte>.Empty);
stream.Write(start); // HID/Serial へ送信
HSM/銀行API 連携の設計ポイント
- 鍵管理方式:DUKPT(一回性鍵)か Master/Session。TR-31 キーブロックに対応すると移送が容易。
- インタフェース:REST/ISO8583/独自TCPなど。タイムアウト、再送、冪等性IDを設計。
- ログ:平文PIN/PANは保持しない。監査に必要なフィールド(時刻、端末ID、結果コード、KSN など)を最小限で。
- エラー処理:鍵未注入・タンパー・PIN長不正・連続失敗ロック・時間超過などを明確化。
UI/UX 設計(端末とPC アプリの役割分担)
- 端末画面には「新しいPINを入力→確認入力」の2段階を明示。マスク表示・ビープ・キャンセルキーの動作を定義。
- PC 側は進捗インジケータと、成功/失敗の非機微メッセージのみ表示(「PIN は保存しません」などの注意書き)。
- 多言語・視認性(フォント/コントラスト)・視線誘導(端末側に注目させる)を検討。
例:.NET ラッパークラスの骨格
実機のSDK関数に差し替えやすいよう、I/O とプロトコル、業務ロジックを分けます。
public interface ICpxTransport : IDisposable
{
void Write(ReadOnlySpan<byte> frame);
int Read(Span<byte> buffer); // 実装はフレーム境界で返す
}
public sealed class CpxClient
{
private readonly ICpxTransport _transport;
public CpxClient(ICpxTransport transport) { _transport = transport; }
public void StartSession()
{
var frame = Frame.Build(0x30, ReadOnlySpan<byte>.Empty);
_transport.Write(frame);
var resp = ReadResp();
EnsureOk(resp);
}
public (byte[] PinBlock, byte[] Ksn) RequestPinEntry(int minLen, int maxLen)
{
var payload = new byte[] { (byte)minLen, (byte)maxLen, 0x00 /*オプション*/ };
var frame = Frame.Build(0x31, payload);
_transport.Write(frame);
var resp = ReadResp();
EnsureOk(resp);
// 実際は SDK 定義に従ってオフセットを解釈
var pinBlock = ExtractField(resp, "PINBLOCK");
var ksn = ExtractField(resp, "KSN");
return (pinBlock, ksn);
}
private byte[] ReadResp()
{
var buf = new byte[1024];
var n = _transport.Read(buf);
return buf.Take(n).ToArray();
}
private void EnsureOk(byte[] resp)
{
// ステータスコード解釈(SDKの定義に合わせる)
// 例:resp[3] == 0x00 で成功 など
}
private byte[] ExtractField(byte[] resp, string name)
{
// SDK のTLV/固定長仕様に従って抽出
return Array.Empty<byte>();
}
}
注意: 上記コードは雛形です。実際のコマンド値、レスポンス構造、例外コードは Ingenico の開発資料に従って置き換えてください。推測で実機に送信するのは避けてください(タンパーや鍵消去のリスクがあります)。
運用・セキュリティ設計(PCI 前提)
- 鍵注入(Key Injection):出荷時や現地でのインジェクション手順・記録・責任分界を文書化。タンパー発生時の鍵消去と再注入手順を定義。
- ロール分離:開発者は鍵にアクセスしない。保管は HSM/鍵管理者のみ。
- 端末ハンドリング:物理封印、シール番号、日次点検、保管庫、輸送記録。
- 監査ログ:変更リクエストID、端末ID、結果コード、タイムスタンプ(NTP 同期)、オペレータID を平文で、鍵/機微は持たない。
- 障害時の継続:HSM 障害時のフォールバック(予備系、キューイング、リトライポリシー)。
テスト戦略(PIN 変更ユースケース)
結合テストで「暗号化PINブロック→HSM→応答」まで閉ループを作ることが重要です。
| テストID | 内容 | 期待結果 | 備考 |
|---|---|---|---|
| T-01 | 最小桁(例:4)で PIN 入力 | 暗号化ブロック生成、HSM から OK | マスク表示/ビープ確認 |
| T-02 | 最大桁(例:12)で PIN 入力 | OK | 長押し/連打の挙動 |
| T-03 | 確認入力不一致 | 再入力誘導 | 端末/PC側メッセージ整合 |
| T-04 | タイムアウト | キャンセル扱い | ログとUIの一致 |
| T-05 | 鍵未注入(Simulate) | エラーコード表示、ログ記録 | 現場復旧手順の確認 |
| T-06 | タンパー発生(Simulate) | 鍵消去→再注入必須 | 監査/報告フロー |
| T-07 | HSM ダウン | リトライ/キューイング後に復旧処理 | 冪等性キーで二重更新防止 |
障害・エラー事例と対処
- デバイスが列挙されない:ドライバ/給電/ケーブル/USBポートの見直し。企業端末ではエンドポイント制限がある場合、IT ポリシーに申請。
- 「鍵未注入」エラー:センターでのインジェクション済みか、フィールドローディングが必要かを確認。監査ログと一致させる。
- レスポンス解析失敗:フレーム境界・TLV・CRC を仕様どおりに。ログにダンプする際は機微領域をマスク。
- タイムアウト:端末側のPIN入力待機時間と、アプリのReadTimeoutを一致させる。ユーザーの再試行手順をUIに明記。
- 連続失敗ロック:閾値・解除ポリシーを業務と事前合意。解除には本人確認ステップを追加。
現場導入のコツ(プロジェクトの落とし穴回避)
- メーカー窓口を最初に開く:SDK と最新ファームの入手、対象機種のサポート可否を早期に確定。
- セキュリティ担当を巻き込む:鍵運用・監査要件はアプリ担当だけでは決められません。
- HSM サンドボックス:本番鍵前にテスト鍵で閉ループを構築。ログフォーマットを監査と合意。
- UI モック:ユーザー操作(入力やり直し/キャンセル)を先に設計し、端末とPCの役割を分離。
- 障害訓練:HSM ダウン、ネットワーク分断、タンパー発生時の訓練をリハーサル。
サンプル:PIN 変更ユースケースの疑似実装
以下は「新PIN入力→確認入力→暗号化ブロック×2→HSM 検証→更新」の疑似コードです。平文PINは扱いません。
public sealed class PinChangeService
{
private readonly CpxClient _cpx;
private readonly IHsmClient _hsm; // REST 等で実装
public PinChangeService(CpxClient cpx, IHsmClient hsm)
{
_cpx = cpx; _hsm = hsm;
}
public async Task<bool> ChangePinAsync(string userId, CancellationToken ct = default)
{
_cpx.StartSession();
var (pb1, ksn1) = _cpx.RequestPinEntry(minLen: 4, maxLen: 12);
// 端末自身で「確認入力」を促す仕様の機種もある
var (pb2, ksn2) = _cpx.RequestPinEntry(minLen: 4, maxLen: 12);
var verified = await _hsm.VerifySameAsync(pb1, ksn1, pb2, ksn2, ct); // 平文化はHSM側
if (!verified) { return false; }
var ok = await _hsm.UpdatePinAsync(userId, pb1, ksn1, ct); // イシュア/勘定系に委譲する場合も
return ok;
}
}
監査・ログのサンプル(機微情報を含まない)
{"ts":"2025-10-01T10:23:45Z","terminalId":"CPX1014-00123",
"reqId":"e6b7...","op":"PIN_CHANGE","result":"SUCCESS",
"hsmRef":"HSM-24-09-001","ksn":"FFFF9876543210","durationMs":842}
代表的なQ&A
Q:平文のPINをアプリで読みたい。
A:PCI PIN 準拠デバイスでは仕様上できません。暗号化 PIN ブロックのみ受け取り、復号や照合は HSM/イシュア側で実施します。
Q:SDKなしで独自実装できる?
A:推奨しません。仕様の齟齬でタンパー・鍵消去を招く恐れがあり、保守不能になります。公式SDKの利用が前提です。
Q:DUKPT と Master/Session の違いは?
A:DUKPTは取引ごとに鍵が派生されリスク分散に優れます。Master/Sessionは管理が単純な一方、運用での適切なローテーションが必須です。
Q:POS を使わずPIN変更だけ可能?
A:可能です。ただし暗号化ブロックの検証・更新を受け付ける側(HSM/イシュア)との接続が必須です。
代替案:非決済用途なら汎用入力デバイス
もし要件が「数値入力を受け付けたい」だけで、金融グレードのセキュリティを必要としないなら、汎用 USB キーパッドやタッチパネルのほうが実装負荷もコストも低くなります。ただし PIN という性質上、セキュリティ要件を満たさないため、金融用途では採用できません。
実務フローチャート(概要)
[起動]
↓
[SDK/デバイス検出]
↓
[セッション開始]─NG→[復旧/終了]
↓
[鍵状態チェック/KSN取得]
↓
[端末にPIN入力案内表示]
↓
[暗号化PINブロック受信]
↓
[HSM/銀行APIで検証/変更]
↓
[結果表示・監査ログ]
↓
[セッション終了]
まとめ
- CPX10.14 は PCI PIN 準拠のため、平文PINは外へ出ない。アーキテクチャは暗号化ブロック→HSM/イシュアが前提。
- メーカーSDK/資料の入手が最優先。独自実装は避ける。
- HID/シリアルでの I/O は .NET で容易だが、コマンド/TLV/CRCは機種仕様どおりに。
- 鍵運用・監査・障害時の復旧まで含めた運用設計が成功の鍵。
- 非決済用途なら汎用デバイスの方が適材適所。要件を正しく切り分ける。
付録:要素別チェックリスト
| 領域 | チェック項目 | 完了条件 |
|---|---|---|
| SDK/資料 | 機種特定、コマンド仕様、サンプル、DLL取得 | バージョン記録、リポジトリに格納 |
| 鍵運用 | インジェクション方式、ロール分離、TR-31可否 | 手順書・記録台帳・訓練完了 |
| I/O | HID/Serial 選定、VID/PID、ドライバ | 検出・送受信・タイムアウト動作OK |
| 連携 | HSM/銀行API のI/F、冪等性、リトライ | ステージングで閉ループ通過 |
| UI/UX | 案内文、失敗時動線、アクセシビリティ | ユーザテスト合格 |
| 監査/運用 | ログ、アラート、障害訓練、棚卸 | PCI 監査観点でレビュー済 |
最終アドバイス
「とりあえず動かす」より「きちんと守る」ことが求められるのが PIN デバイスの世界です。CPX10.14 を .NET から扱うこと自体は難しくありませんが、根幹は鍵と運用です。開発初期からメーカー・HSM ベンダ・監査担当とテーブルを囲み、実装と運用を同時に進める──それが最短ルートです。
重要な注意:本記事は一般的な知見と実装の雛形を示すもので、特定機種の詳細仕様や設定値は含みません。実作業では必ずメーカーの最新資料・SDK と契約上の手順に従ってください。推測のコマンド送信や、平文PINの取り扱いは厳禁です。

コメント