Initial commit

This commit is contained in:
Kai Jan Kriegel 2022-03-09 03:41:06 +01:00
commit c171d3bdda
11 changed files with 916 additions and 0 deletions

22
.gitignore vendored Normal file
View File

@ -0,0 +1,22 @@
# Created by https://www.toptal.com/developers/gitignore/api/rust
# Edit at https://www.toptal.com/developers/gitignore?templates=rust
### Rust ###
# Generated by Cargo
# will have compiled files and executables
debug/
target/
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
#Cargo.lock
# These are backup files generated by rustfmt
**/*.rs.bk
# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb
# End of https://www.toptal.com/developers/gitignore/api/rust

8
.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

7
.idea/discord.xml generated Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DiscordProjectSettings">
<option name="show" value="ASK" />
<option name="description" value="" />
</component>
</project>

11
.idea/fabfire_provision.iml generated Normal file
View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="CPP_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

8
.idea/modules.xml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/fabfire_provision.iml" filepath="$PROJECT_DIR$/.idea/fabfire_provision.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

543
Cargo.lock generated Normal file
View File

@ -0,0 +1,543 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aes"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8"
dependencies = [
"cfg-if",
"cipher",
"cpufeatures",
"opaque-debug",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "block-modes"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cb03d1bed155d89dce0f845b7899b18a9a163e148fd004e1c28421a783e2d8e"
dependencies = [
"block-padding",
"cipher",
]
[[package]]
name = "block-padding"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae"
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cipher"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7"
dependencies = [
"generic-array",
]
[[package]]
name = "clap"
version = "3.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8c93436c21e4698bacadf42917db28b23017027a4deccb35dbe47a7e7840123"
dependencies = [
"atty",
"bitflags",
"clap_derive",
"indexmap",
"lazy_static",
"os_str_bytes",
"strsim",
"termcolor",
"textwrap",
]
[[package]]
name = "clap_derive"
version = "3.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da95d038ede1a964ce99f49cbe27a7fb538d1da595e4b4f70b8c8f338d17bf16"
dependencies = [
"heck",
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "cpufeatures"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469"
dependencies = [
"libc",
]
[[package]]
name = "des"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac41dd49fb554432020d52c875fc290e110113f864c6b1b525cd62c7e7747a5d"
dependencies = [
"byteorder",
"cipher",
"opaque-debug",
]
[[package]]
name = "desfire"
version = "0.1.0"
dependencies = [
"aes",
"block-modes",
"des",
"hex",
"num-derive",
"num-traits",
"rand",
"simple-error",
]
[[package]]
name = "fabfire_provision"
version = "0.1.0"
dependencies = [
"clap",
"desfire",
"hex",
"pcsc",
"rand",
"serde",
"serde_json",
"uriparse",
"urlencoding",
"urn",
"uuid",
]
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "generic-array"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]]
name = "heck"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "indexmap"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "itoa"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.119"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
[[package]]
name = "memchr"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "num-derive"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "num-traits"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
dependencies = [
"autocfg",
]
[[package]]
name = "opaque-debug"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "os_str_bytes"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
dependencies = [
"memchr",
]
[[package]]
name = "pcsc"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e29e4de78a433aeecd06fb5bd55a0f9fde11dc85a14c22d482972c7edc4fdc4"
dependencies = [
"bitflags",
"pcsc-sys",
]
[[package]]
name = "pcsc-sys"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1b7bfecba2c0f1b5efb0e7caf7533ab1c295024165bcbb066231f60d33e23ea"
dependencies = [
"pkg-config",
]
[[package]]
name = "pkg-config"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
[[package]]
name = "ppv-lite86"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]]
name = "proc-macro2"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
dependencies = [
"getrandom",
]
[[package]]
name = "ryu"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
[[package]]
name = "serde"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "simple-error"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc47a29ce97772ca5c927f75bac34866b16d64e07f330c3248e2d7226623901b"
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "termcolor"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
dependencies = [
"winapi-util",
]
[[package]]
name = "textwrap"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
[[package]]
name = "typenum"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "uriparse"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e515b1ada404168e145ac55afba3c42f04cf972201a8552d42e2abb17c1b7221"
dependencies = [
"fnv",
"lazy_static",
]
[[package]]
name = "urlencoding"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68b90931029ab9b034b300b797048cf23723400aa757e8a2bfb9d748102f9821"
[[package]]
name = "urn"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fdd17e2f5f885834e8b89d0b10c77fbcef55281f18e6859b6bda7249fa7ce1a"
[[package]]
name = "uuid"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
dependencies = [
"getrandom",
]
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

19
Cargo.toml Normal file
View File

@ -0,0 +1,19 @@
[package]
name = "fabfire_provision"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
clap = { version = "3.1.3", features = ["derive"] }
desfire = { path = "../nfc_rs"}
serde = { version = "1.0.136", features = ["derive"] }
serde_json = "1.0.79"
hex = "0.4.3"
pcsc = "2.7.0"
rand = "0.8.5"
urn = "0.4.0"
urlencoding = "2.1.0"
uriparse = "0.6.3"
uuid = { version = "0.8.2", features = ["v4"] }

15
README.md Normal file
View File

@ -0,0 +1,15 @@
FabFire Provisioning Tool
===
# Usage
## Provisioning
```shell
cargo run -- --space "innovisionlab" --instance fabaccess.innovisionlab.de --contact https://innovisionlab.de/lostandfound
```
Replace `--space`, `--instance` and `--contact` with your own values.
You can supply your own keys and Application ID with the appropriate cmdline arguments, view `--help` for more information.
## Formating Card
```shell
cargo run -- --format
```
Formats the card, deleting all files and keys.

81
src/card.rs Normal file
View File

@ -0,0 +1,81 @@
use std::ffi::CString;
use desfire::Card as CardTrait;
use desfire::error::Error;
use desfire::error::Error::CardError;
use desfire::iso7816_4::apducommand::APDUCommand;
use desfire::iso7816_4::apduresponse::APDUResponse;
use pcsc::{Card, Context, MAX_BUFFER_SIZE, Protocols, Scope, ShareMode};
pub struct PCSCCard {
ctx: Context,
reader: CString,
card: Option<Card>,
}
impl PCSCCard {
pub fn new() -> Result<PCSCCard, pcsc::Error> {
// Establish a PC/SC context.
let ctx = match Context::establish(Scope::User) {
Ok(ctx) => ctx,
Err(err) => {
return Err(err);
}
};
// List available readers.
let mut readers_buf = [0; 2048];
let mut readers = match ctx.list_readers(&mut readers_buf) {
Ok(readers) => readers,
Err(err) => {
return Err(err)
}
};
// Use the first reader.
let reader = match readers.next() {
Some(reader) => reader,
None => {
return Err(pcsc::Error::NoReadersAvailable);
}
};
Ok(PCSCCard {
ctx,
reader: CString::from(reader),
card: None
})
}
}
impl CardTrait for PCSCCard {
fn connect(&mut self) -> Result<(), Error> {
self.card = match self.ctx.connect(&self.reader, ShareMode::Shared, Protocols::ANY) {
Ok(card) => Some(card),
Err(err) => {
eprintln!("Failed to connect to card: {}", err);
return Err(CardError)
}
};
return Ok(())
}
fn disconnect(&mut self) -> Result<(), Error> {
Ok(())
}
fn transmit(&self, apdu_cmd: APDUCommand) -> Result<APDUResponse, Error> {
println!("{}", apdu_cmd);
let apdu = Vec::<u8>::try_from(apdu_cmd).unwrap();
let mut rapdu_buf = [0; MAX_BUFFER_SIZE];
let rapdu = match self.card.as_ref().as_ref().unwrap().transmit(apdu.as_slice(), &mut rapdu_buf) {
Ok(rapdu) => rapdu,
Err(err) => {
eprintln!("Failed to transmit APDU command to card: {}", err);
return Err(CardError)
}
};
return Ok(APDUResponse::new(rapdu))
}
}

196
src/main.rs Normal file
View File

@ -0,0 +1,196 @@
mod card;
use std::ffi::CString;
use std::ops::Deref;
use clap::Parser;
use desfire::Card;
use desfire::crypto::cipher_key::CipherKey;
use desfire::crypto::cipher_type::CipherType;
use desfire::desfire::{ChangeApplicationKey, ChangeMasterKey, ChangeMasterKeySettings, CreateDeleteFile, CryptoOperationsType, Desfire, FileAccessRights, FileCommunication, FileDirectoryAccess, FileIdentifiers};
use desfire::desfire::desfire::{generate_file_access_rights, generate_keysetting1, generate_keysetting2, MAX_BYTES_PER_TRANSACTION};
use pcsc::{Context, Scope};
use uriparse::{Authority, Path, Scheme, Segment, UnregisteredScheme, URI};
use urn::UrnBuilder;
use uuid::Uuid;
use crate::card::PCSCCard;
/// Simple program to greet a person
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Args {
/// Application id to use
#[clap(long = "id", default_value = "1")]
app_id: u32,
/// Masterkey for the PICC
#[clap(long)]
picc_masterkey: Option<String>,
/// Masterkey for the Application
#[clap(long)]
app_masterkey: Option<String>,
/// user authentication key
#[clap(long)]
app_authkey: Option<String>,
/// Magic string to identify cards
#[clap(short, long, default_value = "FABACCESS\0DESFIRE\01.0\0")]
magic: String,
/// Name of the issuing space
#[clap(short, long, required_unless_present = "format")]
space: Option<String>,
/// BFFHd Instance for the space
#[clap(short, long, required_unless_present = "format")]
instance: Option<String>,
/// Contact option for lost cards
#[clap(short, long, required_unless_present = "format")]
contact: Option<String>,
/// User token (will be generated for you if not given)
#[clap(short, long)]
token: Option<String>,
/// Whether to format the card
#[clap(short, long)]
format: bool,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let args = Args::parse();
println!("{:?}", args);
// connect to the card
let mut card = PCSCCard::new()?;
card.connect()?;
let mut desfire = Desfire {
card: Some(Box::new(card)),
cbc_iv: None,
session_key: None
};
// store the provided keys or generate new ones
let master_key = match args.picc_masterkey {
Some(key) => CipherKey::new_from_str(&key, CipherType::TDES, 0x00)?,
None => CipherKey::new_empty(CipherType::TDES)?,
};
let app_key = match args.app_masterkey {
Some(key) => CipherKey::new_from_str(&key, CipherType::AES, 0x10)?,
None => CipherKey::new_empty(CipherType::AES)?,
};
let user_key = match args.app_authkey {
Some(key) => CipherKey::new_from_str(&key, CipherType::AES, 0x10)?,
None => CipherKey::new(&rand::random::<[u8; 16]>(), CipherType::AES, 0x10)?,
};
// format the card if requested
if args.format {
desfire.select_application(0x000000);
desfire.authenticate_iso_des(0x00, master_key.key.as_ref(), None)?;
desfire.format_picc()?;
return Ok(())
} else {
let space = match args.space {
Some(ref space) => space,
None => { return Err(Box::new(std::io::Error::new(std::io::ErrorKind::Other, "No space name provided"))) }
};
let instance = match args.instance {
Some(ref instance) => instance,
None => { return Err(Box::new(std::io::Error::new(std::io::ErrorKind::Other, "No instance name provided"))) }
};
let contact = match args.contact {
Some(ref contact) => contact,
None => { return Err(Box::new(std::io::Error::new(std::io::ErrorKind::Other, "No contact info provided"))) }
};
// encode the space info
let space_urn = UrnBuilder::new("fabaccess", &format!("lab:{}", urlencoding::encode(space)))
.build()?;
println!("Space URN: {}", space_urn);
let instance_uri = URI::builder()
.with_scheme(Scheme::Unregistered(UnregisteredScheme::try_from("fabaccess")?))
.with_authority(Some(Authority::try_from(instance.deref())?))
.with_path(Path::try_from("")?)
.build()?;
println!("Instance URI: {}", instance_uri);
let contact_uri = URI::try_from(contact.deref())?;
println!("Contact URI: {}", contact_uri);
let token = match args.token {
Some(token) => token,
None => {
Uuid::new_v4().to_string()
}
};
println!("Token: {}", token);
// authenticate against picc
desfire.authenticate_iso_des(0x00, master_key.key.as_ref(), None)?;
// generate a new application
let ks1 = generate_keysetting1(ChangeApplicationKey::MASTERKEY as u8,
ChangeMasterKeySettings::WITHMASTERKEY,
CreateDeleteFile::ONLYMASTERKEY,
FileDirectoryAccess::NOKEY,
ChangeMasterKey::CHANGEABLE)?;
let ks2 = generate_keysetting2(CryptoOperationsType::AES, FileIdentifiers::NOTUSED, 0x02)?;
desfire.create_application(args.app_id, ks1, ks2)?;
// select the application
desfire.select_application(args.app_id);
println!("generated application");
// change the application master key
desfire.authenticate_iso_aes(0x00, CipherKey::new_empty(CipherType::AES)?.key.as_ref(), None)?;
desfire.change_key_aes(0x00, app_key.key.as_ref(), app_key.key_version)?;
println!("changed application master key");
// authenticate with new application master key
desfire.authenticate_iso_aes(0x00, app_key.key.as_ref(), None)?;
println!("authenticated with new application master key");
// set the user authentication key
desfire.change_other_key_aes(0x01, user_key.key.as_ref(), CipherKey::new_empty(CipherType::AES)?.key.as_ref(), user_key.key_version)?;
println!("changed user authentication key");
println!("creating magic file with size {}", args.magic.len());
// create file with magic
let magic_accessrights = generate_file_access_rights(FileAccessRights::FREE as u8, 0x00, 0x00, 0x00)?;
desfire.create_file_standard(0x01, FileCommunication::PLAIN, magic_accessrights, args.magic.as_bytes().len() as u32)?;
println!("created magic file");
desfire.write_data(0x01, 0x00, args.magic.as_bytes())?;
println!("wrote magic");
// create file with space info
let space_accessrights = generate_file_access_rights(FileAccessRights::FREE as u8, 0x00, 0x00, 0x00)?;
desfire.create_file_standard(0x02, FileCommunication::PLAIN, space_accessrights, (MAX_BYTES_PER_TRANSACTION * 3) as u32)?;
desfire.write_data(0x02, 0x00, space_urn.as_bytes())?;
desfire.write_data(0x02, MAX_BYTES_PER_TRANSACTION as u32, instance_uri.to_string().as_bytes())?;
desfire.write_data(0x02, (MAX_BYTES_PER_TRANSACTION * 2) as u32, contact_uri.to_string().as_bytes())?;
println!("created space info file");
// create file with token
let token_accessrights = generate_file_access_rights(0x01, 0x00, 0x00, 0x00)?;
desfire.create_file_standard(0x03, FileCommunication::PLAIN, token_accessrights, token.as_bytes().len() as u32)?;
desfire.write_data(0x03, 0x00, token.as_bytes())?;
println!("created token file");
Ok(())
}
}