mirror of
https://github.com/arx-research/libhalo.git
synced 2026-01-10 05:38:10 -05:00
HaLo: Implement key export feature (C8) (#266)
This commit is contained in:
committed by
GitHub
parent
8dd4e89731
commit
9328caba47
@@ -59,22 +59,26 @@ Addons ver. - first HaLo Addons version to support the indicated driver.
|
||||
## Command compatibility table
|
||||
### Commands available in HaLo OSS
|
||||
|
||||
| Command | Core ver. | Comment |
|
||||
|--------------------|-----------|-----------------------------------------------|
|
||||
| `version` | 01.C1 | Only for PCSC/React Native drivers. |
|
||||
| `sign` | 01.C1 | Only with `command.legacySignCommand = true`. |
|
||||
| `get_pkeys` | 01.C1 | |
|
||||
| `write_latch` | 01.C3 | |
|
||||
| `sign` | 01.C4 | All combinations of options. |
|
||||
| `sign_random` | 01.C4 | |
|
||||
| `get_key_info` | 01.C6 | |
|
||||
| `gen_key` | 01.C7 | |
|
||||
| `gen_key_confirm` | 01.C7 | |
|
||||
| `gen_key_finalize` | 01.C7 | |
|
||||
| `set_password` | 01.C7 | |
|
||||
| `replace_password` | 01.C7 | |
|
||||
| `unset_password` | 01.C7 | |
|
||||
| `pcsc_detect` | 01.C1 | Only with CLI tool. |
|
||||
| Command | Core ver. | Comment |
|
||||
|---------------------|-----------|--------------------------------------------------------|
|
||||
| `version` | 01.C1 | Only for PCSC/React Native drivers. |
|
||||
| `sign` | 01.C1 | Only with `command.legacySignCommand = true`. |
|
||||
| `get_pkeys` | 01.C1 | |
|
||||
| `write_latch` | 01.C3 | |
|
||||
| `sign` | 01.C4 | All combinations of options. |
|
||||
| `sign_random` | 01.C4 | |
|
||||
| `get_key_info` | 01.C6 | |
|
||||
| `gen_key` | 01.C7 | |
|
||||
| `gen_key_confirm` | 01.C7 | |
|
||||
| `gen_key_finalize` | 01.C7 | |
|
||||
| `set_password` | 01.C7 | |
|
||||
| `replace_password` | 01.C7 | |
|
||||
| `unset_password` | 01.C7 | |
|
||||
| `get_transport_pk` | 01.C8 | Only with `options.method = 'credential'` or CLI tool. |
|
||||
| `load_transport_pk` | 01.C8 | Only with `options.method = 'credential'` or CLI tool. |
|
||||
| `export_key` | 01.C8 | Only with `options.method = 'credential'` or CLI tool. |
|
||||
| `import_key` | 01.C8 | Only with `options.method = 'credential'` or CLI tool. |
|
||||
| `pcsc_detect` | 01.C1 | Only with CLI tool. |
|
||||
|
||||
Core ver. - first HaLo Core version to officially support the indicated command.
|
||||
|
||||
|
||||
@@ -10,15 +10,14 @@ const {
|
||||
} = require("../halo/exceptions");
|
||||
const {
|
||||
cmdGetPkeys, cmdSign, cmdCfgNDEF, cmdWriteLatch, cmdSignRandom, cmdGenKey, cmdGenKeyConfirm, cmdGenKeyFinalize,
|
||||
cmdSignChallenge, cmdSetURLSubdomain, cmdSetPassword, cmdUnsetPassword, cmdReplacePassword, cmdGetKeyInfo
|
||||
cmdSignChallenge, cmdSetURLSubdomain, cmdSetPassword, cmdUnsetPassword, cmdReplacePassword, cmdGetKeyInfo,
|
||||
cmdGetTransportPK, cmdLoadTransportPK, cmdExportKey, cmdImportKey
|
||||
} = require("../halo/commands");
|
||||
const {ERROR_CODES} = require("../halo/errors");
|
||||
|
||||
async function execHaloCmd(command, options) {
|
||||
command = Object.assign({}, command);
|
||||
|
||||
console.log(command);
|
||||
|
||||
let commandName = command.name;
|
||||
delete command['name'];
|
||||
|
||||
@@ -51,6 +50,14 @@ async function execHaloCmd(command, options) {
|
||||
return await cmdUnsetPassword(options, command);
|
||||
case 'get_key_info':
|
||||
return await cmdGetKeyInfo(options, command);
|
||||
case 'get_transport_pk':
|
||||
return await cmdGetTransportPK(options, command);
|
||||
case 'load_transport_pk':
|
||||
return await cmdLoadTransportPK(options, command);
|
||||
case 'export_key':
|
||||
return await cmdExportKey(options, command);
|
||||
case 'import_key':
|
||||
return await cmdImportKey(options, command);
|
||||
default:
|
||||
throw new HaloLogicError("Unsupported command.name parameter specified.");
|
||||
}
|
||||
|
||||
@@ -37,6 +37,11 @@ const CMD_CODES = {
|
||||
"SHARED_CMD_GET_DATA_VERSION": 0xD7,
|
||||
"SHARED_CMD_GET_URL_SUBDOMAIN": 0xD6,
|
||||
"SHARED_CMD_SET_NDEF_MODE": 0xD8,
|
||||
|
||||
"CRED_CMD_GET_TRANSPORT_PK_ATT": 0xA6,
|
||||
"CRED_CMD_EXPORT_KEY": 0xA7,
|
||||
"CRED_CMD_IMPORT_KEY": 0xA8,
|
||||
"CRED_CMD_LOAD_TRANSPORT_PK": 0xA9,
|
||||
};
|
||||
|
||||
module.exports = {CMD_CODES};
|
||||
|
||||
@@ -546,6 +546,88 @@ async function cmdReplacePassword(options, args) {
|
||||
return {"status": "ok"};
|
||||
}
|
||||
|
||||
async function cmdGetTransportPK(options, args) {
|
||||
if (options.method !== "credential" && options.method !== "pcsc") {
|
||||
throw new HaloLogicError("Unsupported execution method. Please set options.method = 'credential'.");
|
||||
}
|
||||
|
||||
let payload = Buffer.concat([
|
||||
Buffer.from([CMD.CRED_CMD_GET_TRANSPORT_PK_ATT])
|
||||
]);
|
||||
|
||||
let resp = await options.exec(payload);
|
||||
|
||||
return {
|
||||
"data": resp.result.toString('hex')
|
||||
}
|
||||
}
|
||||
|
||||
async function cmdLoadTransportPK(options, args) {
|
||||
if (options.method !== "credential" && options.method !== "pcsc") {
|
||||
throw new HaloLogicError("Unsupported execution method. Please set options.method = 'credential'.");
|
||||
}
|
||||
|
||||
let payload = Buffer.concat([
|
||||
Buffer.from([CMD.CRED_CMD_LOAD_TRANSPORT_PK]),
|
||||
Buffer.from(args.data, 'hex')
|
||||
]);
|
||||
|
||||
let resp = await options.exec(payload);
|
||||
|
||||
return {
|
||||
"data": resp.result.toString('hex')
|
||||
}
|
||||
}
|
||||
|
||||
async function cmdExportKey(options, args) {
|
||||
if (options.method !== "credential" && options.method !== "pcsc") {
|
||||
throw new HaloLogicError("Unsupported execution method. Please set options.method = 'credential'.");
|
||||
}
|
||||
|
||||
let derivedKey = pbkdf2.pbkdf2Sync(args.password, 'HaLoChipSalt', 5000, 16, 'sha512');
|
||||
let dataBuf = Buffer.from(args.data, 'hex');
|
||||
let sigLen = dataBuf[1] + 2;
|
||||
|
||||
let pwdHash = Buffer.from(sha256(Buffer.concat([
|
||||
Buffer.from([0x19]),
|
||||
Buffer.from("Key backup:\n"),
|
||||
Buffer.from([args.keyNo]),
|
||||
derivedKey,
|
||||
dataBuf.slice(sigLen),
|
||||
])), "hex");
|
||||
|
||||
let payload = Buffer.concat([
|
||||
Buffer.from([CMD.CRED_CMD_EXPORT_KEY]),
|
||||
Buffer.from([args.keyNo]),
|
||||
dataBuf,
|
||||
pwdHash
|
||||
]);
|
||||
|
||||
let resp = await options.exec(payload);
|
||||
|
||||
return {
|
||||
"data": resp.result.toString('hex')
|
||||
}
|
||||
}
|
||||
|
||||
async function cmdImportKey(options, args) {
|
||||
if (options.method !== "credential" && options.method !== "pcsc") {
|
||||
throw new HaloLogicError("Unsupported execution method. Please set options.method = 'credential'.");
|
||||
}
|
||||
|
||||
let payload = Buffer.concat([
|
||||
Buffer.from([CMD.CRED_CMD_IMPORT_KEY]),
|
||||
Buffer.from([args.keyNo]),
|
||||
Buffer.from(args.data, 'hex')
|
||||
]);
|
||||
|
||||
let resp = await options.exec(payload);
|
||||
|
||||
return {
|
||||
"publicKey": resp.result.toString('hex')
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
cmdSign,
|
||||
cmdSignRandom,
|
||||
@@ -560,5 +642,9 @@ module.exports = {
|
||||
cmdSetPassword,
|
||||
cmdUnsetPassword,
|
||||
cmdReplacePassword,
|
||||
cmdGetKeyInfo
|
||||
cmdGetKeyInfo,
|
||||
cmdGetTransportPK,
|
||||
cmdLoadTransportPK,
|
||||
cmdExportKey,
|
||||
cmdImportKey,
|
||||
};
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
<li><a href="gateway_requestor.html">gateway_requestor.html - Executing commands through HaLo Gateway</a></li>
|
||||
<li><a href="gen_key.html">gen_key.html - Additional key generation demo</a></li>
|
||||
<li><a href="pwd_management.html">pwd_management.html - Key slot password management demo</a></li>
|
||||
<li><a href="key_backup.html">key_backup.html - Key backup demo</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
115
web/examples/key_backup.html
Normal file
115
web/examples/key_backup.html
Normal file
@@ -0,0 +1,115 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<!--
|
||||
LibHaLo - Programmatically interact with HaLo tags from the web browser, mobile application or the desktop.
|
||||
Copyright by Arx Research, Inc., a Delaware corporation
|
||||
License: MIT
|
||||
-->
|
||||
<title>LibHaLo Demo</title>
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css"
|
||||
integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
|
||||
|
||||
<script type="text/javascript">
|
||||
// ensure the library is always fully reloaded
|
||||
document.write('<script src="../dist/libhalo.js?_v=' + (Math.random() + '') + '"></scr' + 'ipt>');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container mt-3 mb-5">
|
||||
<h1>LibHaLo Demo</h1>
|
||||
<div class="mb-4">
|
||||
<strong>Key slot number:</strong>
|
||||
<input type="text" class="form-control" id="keySlot" value="8">
|
||||
<p class="text-muted">Supported key slots: 8, 9. The key on the source card must already exist.</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<strong>Key password:</strong>
|
||||
<input type="text" class="form-control" id="password" value="">
|
||||
<p class="text-muted">Source card's key password.</p>
|
||||
</div>
|
||||
|
||||
<strong>Status text:</strong>
|
||||
<pre id="statusText" style="white-space: pre-wrap; word-break: break-all;">Please click on one of the buttons below.</pre>
|
||||
|
||||
<h2>Step 1</h2>
|
||||
<button class="btn btn-secondary" onclick="btnExecuteNFC('get_transport_pk');">
|
||||
[source card] get_transport_pk
|
||||
</button>
|
||||
|
||||
<h2>Step 2</h2>
|
||||
<button class="btn btn-secondary" onclick="btnExecuteNFC('load_transport_pk');">
|
||||
[target card] load_transport_pk
|
||||
</button>
|
||||
|
||||
<h2>Step 3</h2>
|
||||
<button class="btn btn-secondary" onclick="btnExecuteNFC('export_key');">
|
||||
[source card] export_key
|
||||
</button>
|
||||
|
||||
<h2>Step 4</h2>
|
||||
<button class="btn btn-secondary" onclick="btnExecuteNFC('import_key');">
|
||||
[target card] import_key
|
||||
</button>
|
||||
|
||||
<script type="text/javascript">
|
||||
let sourcePK = null;
|
||||
let targetPK = null;
|
||||
let keyCT = null;
|
||||
|
||||
function btnExecuteNFC(method) {
|
||||
let keyNo = document.getElementById('keySlot').value;
|
||||
let password = document.getElementById('password').value;
|
||||
|
||||
let command;
|
||||
|
||||
if (method === 'get_transport_pk') {
|
||||
command = {
|
||||
name: "get_transport_pk"
|
||||
};
|
||||
} else if (method === 'load_transport_pk') {
|
||||
command = {
|
||||
name: "load_transport_pk",
|
||||
data: sourcePK
|
||||
};
|
||||
} else if (method === 'export_key') {
|
||||
command = {
|
||||
name: "export_key",
|
||||
keyNo: keyNo,
|
||||
data: targetPK,
|
||||
password: password
|
||||
};
|
||||
} else if (method === 'import_key') {
|
||||
command = {
|
||||
name: "import_key",
|
||||
keyNo: keyNo,
|
||||
data: keyCT
|
||||
};
|
||||
}
|
||||
|
||||
execHaloCmdWeb(command, {method: 'credential'})
|
||||
.then((res) => {
|
||||
// operation succeeded, display the result to the user
|
||||
document.getElementById('statusText').innerText = JSON.stringify(res, null, 4);
|
||||
|
||||
if (method === 'get_transport_pk') {
|
||||
sourcePK = res.data;
|
||||
} else if (method === 'load_transport_pk') {
|
||||
targetPK = res.data;
|
||||
} else if (method === 'export_key') {
|
||||
keyCT = res.data;
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
// the operation has failed, display the reason to the user
|
||||
console.error('execHaloCmdWeb error', e);
|
||||
document.getElementById('statusText').innerText = e;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user