summaryrefslogtreecommitdiff
path: root/src/rfid_access_mifare_classic.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rfid_access_mifare_classic.c')
-rw-r--r--src/rfid_access_mifare_classic.c232
1 files changed, 232 insertions, 0 deletions
diff --git a/src/rfid_access_mifare_classic.c b/src/rfid_access_mifare_classic.c
new file mode 100644
index 0000000..bd362e1
--- /dev/null
+++ b/src/rfid_access_mifare_classic.c
@@ -0,0 +1,232 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <librfid/rfid.h>
+#include <librfid/rfid_access_mifare_classic.h>
+
+/* parse encoded data structure into c1/c2/c3 */
+int mfcl_compile_access(u_int8_t *encoded,
+ const struct mfcl_access_sect *ac)
+{
+ int b;
+ u_int8_t c1, c2, c3;
+
+ c1 = c2 = c3 = 0;
+
+ for (b = 0; b < 4; b++) {
+ if (ac->block[b] & 0x01)
+ c1 |= (1 << b);
+ if (ac->block[b] & 0x02)
+ c2 |= (1 << b);
+ if (ac->block[b] & 0x04)
+ c3 |= (1 << b);
+ }
+
+ DEBUGP("compile: c1=%u c2=%u c3=%u\n", c1, c2, c3);
+
+ encoded[3] = 0x00;
+ encoded[2] = c2 | (c3 << 4);
+ encoded[1] = (~c3 & 0xf) | (c1 << 4);
+ encoded[0] = (~c1 & 0xf) | ((~c2 & 0xf) << 4);
+
+ return 0;
+}
+
+/* parse mifare classic access conditions from card */
+int mfcl_parse_access(struct mfcl_access_sect *ac, u_int8_t *encoded)
+{
+ int b;
+
+ u_int8_t c1, c2, c3;
+
+ DEBUGP("encoded: %s\n", rfid_hexdump(encoded, 4));
+
+ c1 = encoded[1] >> 4;
+ c2 = encoded[2] & 0xf;
+ c3 = encoded[2] >> 4;
+
+ DEBUGP("c1=0x%x, c2=0x%x, c3=0x%x\n", c1, c2, c3);
+
+ memset(ac, 0, sizeof(*ac));
+ for (b = 0; b < 4; b++) {
+ if (c1 & (1 << b))
+ ac->block[b] = 0x1;
+ if (c2 & (1 << b))
+ ac->block[b] |= 0x2;
+ if (c3 & (1 << b))
+ ac->block[b] |= 0x4;
+ };
+
+ /* FIXME: verify the inverted access bits */
+
+ return 0;
+}
+
+
+/* functions below here are for our own internal decoded (orthogonal)
+ * format of access bits */
+
+/* In the order of the table 3.7.3 in MFCL Product Specification Rev. 5.1 */
+static const struct mfcl_access_exp_block mfcl_exp_data[] = {
+ [0] = {
+ .read = MFCL_ACCESS_KEY_A | MFCL_ACCESS_KEY_B,
+ .write = MFCL_ACCESS_KEY_A | MFCL_ACCESS_KEY_B,
+ .inc = MFCL_ACCESS_KEY_A | MFCL_ACCESS_KEY_B,
+ .dec = MFCL_ACCESS_KEY_A | MFCL_ACCESS_KEY_B,
+ },
+ [2] = {
+ .read = MFCL_ACCESS_KEY_A | MFCL_ACCESS_KEY_B,
+ .write = MFCL_ACCESS_NEVER,
+ .inc = MFCL_ACCESS_NEVER,
+ .dec = MFCL_ACCESS_NEVER,
+ },
+ [1] = {
+ .read = MFCL_ACCESS_KEY_A | MFCL_ACCESS_KEY_B,
+ .write = MFCL_ACCESS_KEY_B,
+ .inc = MFCL_ACCESS_NEVER,
+ .dec = MFCL_ACCESS_NEVER,
+ },
+ [3] = {
+ .read = MFCL_ACCESS_KEY_A | MFCL_ACCESS_KEY_B,
+ .write = MFCL_ACCESS_KEY_B,
+ .inc = MFCL_ACCESS_KEY_B,
+ .dec = MFCL_ACCESS_KEY_A | MFCL_ACCESS_KEY_B,
+ },
+ [4] = {
+ .read = MFCL_ACCESS_KEY_A | MFCL_ACCESS_KEY_B,
+ .write = MFCL_ACCESS_NEVER,
+ .inc = MFCL_ACCESS_NEVER,
+ .dec = MFCL_ACCESS_KEY_A | MFCL_ACCESS_KEY_B,
+ },
+ [6] = {
+ .read = MFCL_ACCESS_KEY_B,
+ .write = MFCL_ACCESS_KEY_B,
+ .inc = MFCL_ACCESS_NEVER,
+ .dec = MFCL_ACCESS_NEVER,
+ },
+ [5] = {
+ .read = MFCL_ACCESS_KEY_B,
+ .write = MFCL_ACCESS_NEVER,
+ .inc = MFCL_ACCESS_NEVER,
+ .dec = MFCL_ACCESS_NEVER,
+ },
+ [7] = {
+ .read = MFCL_ACCESS_NEVER,
+ .write = MFCL_ACCESS_NEVER,
+ .inc = MFCL_ACCESS_NEVER,
+ .dec = MFCL_ACCESS_NEVER,
+ },
+};
+
+static const struct mfcl_access_exp_acc mfcl_exp_trailer[] = {
+ [0] = {
+ .key_a_rd = MFCL_ACCESS_NEVER,
+ .key_a_wr = MFCL_ACCESS_KEY_A,
+ .acc_rd = MFCL_ACCESS_KEY_A,
+ .acc_wr = MFCL_ACCESS_NEVER,
+ .key_b_rd = MFCL_ACCESS_KEY_A,
+ .key_b_wr = MFCL_ACCESS_KEY_A,
+ },
+ [2] = {
+ .key_a_rd = MFCL_ACCESS_NEVER,
+ .key_a_wr = MFCL_ACCESS_NEVER,
+ .acc_rd = MFCL_ACCESS_KEY_A,
+ .acc_wr = MFCL_ACCESS_NEVER,
+ .key_b_rd = MFCL_ACCESS_KEY_A,
+ .key_b_wr = MFCL_ACCESS_NEVER,
+ },
+ [1] = {
+ .key_a_rd = MFCL_ACCESS_NEVER,
+ .key_a_wr = MFCL_ACCESS_KEY_B,
+ .acc_rd = MFCL_ACCESS_KEY_A | MFCL_ACCESS_KEY_B,
+ .acc_wr = MFCL_ACCESS_NEVER,
+ .key_b_rd = MFCL_ACCESS_NEVER,
+ .key_b_wr = MFCL_ACCESS_KEY_B,
+ },
+ [3] = {
+ .key_a_rd = MFCL_ACCESS_NEVER,
+ .key_a_wr = MFCL_ACCESS_NEVER,
+ .acc_rd = MFCL_ACCESS_KEY_A | MFCL_ACCESS_KEY_B,
+ .acc_wr = MFCL_ACCESS_NEVER,
+ .key_b_rd = MFCL_ACCESS_NEVER,
+ .key_b_wr = MFCL_ACCESS_NEVER,
+ },
+ [4] = {
+ .key_a_rd = MFCL_ACCESS_NEVER,
+ .key_a_wr = MFCL_ACCESS_KEY_A,
+ .acc_rd = MFCL_ACCESS_KEY_A,
+ .acc_wr = MFCL_ACCESS_KEY_A,
+ .key_b_rd = MFCL_ACCESS_KEY_A,
+ .key_b_wr = MFCL_ACCESS_KEY_A,
+ },
+ [6] = {
+ .key_a_rd = MFCL_ACCESS_NEVER,
+ .key_a_wr = MFCL_ACCESS_KEY_B,
+ .acc_rd = MFCL_ACCESS_KEY_A | MFCL_ACCESS_KEY_B,
+ .acc_wr = MFCL_ACCESS_KEY_B,
+ .key_b_rd = MFCL_ACCESS_NEVER,
+ .key_b_wr = MFCL_ACCESS_KEY_B,
+ },
+ [5] = {
+ .key_a_rd = MFCL_ACCESS_NEVER,
+ .key_a_wr = MFCL_ACCESS_NEVER,
+ .acc_rd = MFCL_ACCESS_KEY_A | MFCL_ACCESS_KEY_B,
+ .acc_wr = MFCL_ACCESS_KEY_B,
+ .key_b_rd = MFCL_ACCESS_NEVER,
+ .key_b_wr = MFCL_ACCESS_NEVER,
+ },
+ [7] = {
+ .key_a_rd = MFCL_ACCESS_NEVER,
+ .key_a_wr = MFCL_ACCESS_NEVER,
+ .acc_rd = MFCL_ACCESS_KEY_A | MFCL_ACCESS_KEY_B,
+ .acc_wr = MFCL_ACCESS_NEVER,
+ .key_b_rd = MFCL_ACCESS_NEVER,
+ .key_b_wr = MFCL_ACCESS_NEVER,
+ },
+};
+
+const char *mfcl_access_str[] = {
+ [MFCL_ACCESS_NEVER] = "NEVER",
+ [MFCL_ACCESS_KEY_A] = "A",
+ [MFCL_ACCESS_KEY_B] = "B",
+ [MFCL_ACCESS_KEY_A|MFCL_ACCESS_KEY_B] = "A|B",
+};
+
+void mfcl_access_to_exp(struct mfcl_access_exp_sect *exp,
+ const struct mfcl_access_sect *sect)
+{
+ int b;
+ for (b = 0; b < 3; b++)
+ exp->block[b] = mfcl_exp_data[sect->block[b]];
+ exp->acc = mfcl_exp_trailer[sect->block[3]];
+}
+
+char *mfcl_access_exp_stringify(const struct mfcl_access_exp_block *exp)
+{
+ static char buf[80];
+
+ sprintf(buf, "READ: %s, WRITE: %s, INC: %s, DEC: %s",
+ mfcl_access_str[exp->read],
+ mfcl_access_str[exp->write],
+ mfcl_access_str[exp->inc],
+ mfcl_access_str[exp->dec]);
+ return buf;
+}
+
+char *mfcl_access_exp_acc_stringify(const struct mfcl_access_exp_acc *acc)
+{
+ static char buf[80];
+
+ sprintf(buf, "KEY_A_RD: %s, KEY_A_WR: %s, ACC_RD: %s, ACC_WR: %s, "
+ "KEY_B_RD: %s, KEY_B_WR: %s",
+ mfcl_access_str[acc->key_a_rd],
+ mfcl_access_str[acc->key_a_wr],
+ mfcl_access_str[acc->acc_rd],
+ mfcl_access_str[acc->acc_wr],
+ mfcl_access_str[acc->key_b_rd],
+ mfcl_access_str[acc->key_b_wr]);
+ return buf;
+}
+
personal git repositories of Harald Welte. Your mileage may vary