diff --git a/iccard/aime.c b/iccard/aime.c index 5d2b1cd..9957dd3 100644 --- a/iccard/aime.c +++ b/iccard/aime.c @@ -4,6 +4,7 @@ #include "iccard/aime.h" #include "iccard/mifare.h" +#include "iccard/solitaire.h" #include "util/dprintf.h" @@ -14,6 +15,9 @@ HRESULT aime_card_populate( { uint8_t b; size_t i; + char accessCode[21]; + char hashed_id_wrk[9]; + char id_wrk[9]; assert(mifare != NULL); assert(luid != NULL); @@ -36,12 +40,30 @@ HRESULT aime_card_populate( mifare->sectors[0].blocks[2].bytes[6 + i] = b; } + + // Set the card ID, nothing else matters in the first block + mifare->sectors[0].blocks[0].bytes[0] = luid[0]; + mifare->sectors[0].blocks[0].bytes[1] = luid[1]; + mifare->sectors[0].blocks[0].bytes[2] = luid[2]; + mifare->sectors[0].blocks[0].bytes[3] = luid[3]; - /* TODO An authentic Aime pass has a checksum of the LUID in the last few - bytes of block 1. The output of this function fails authenticity check - in its current form. */ + sprintf_s(accessCode, sizeof accessCode, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + luid[0], luid[1], luid[2], luid[3], luid[4], luid[5], luid[6], luid[7], luid[8], luid[9]); - dprintf("AiMe IC: WARNING: Authenticity hash not yet implemented!\n"); + memcpy_s(hashed_id_wrk, sizeof(hashed_id_wrk), &accessCode[5], + 8); + + hashed_id_wrk[8] = '\0'; + + SolitaireCipherDecode(&accessCode[13], hashed_id_wrk, id_wrk); + + + DWORD nSerial = atoi(id_wrk); + + mifare->sectors[0].blocks[1].bytes[12] = (nSerial >> 24) & 0xff; + mifare->sectors[0].blocks[1].bytes[13] = (nSerial >> 16) & 0xff; + mifare->sectors[0].blocks[1].bytes[14] = (nSerial >> 8) & 0xff; + mifare->sectors[0].blocks[1].bytes[15] = nSerial & 0xff; return S_OK; } diff --git a/iccard/meson.build b/iccard/meson.build index e068ae0..6cad0a0 100644 --- a/iccard/meson.build +++ b/iccard/meson.build @@ -12,5 +12,7 @@ iccard_lib = static_library( 'felica.c', 'felica.h', 'mifare.h', + 'solitaire.c', + 'solitaire.h', ], ) diff --git a/iccard/solitaire.c b/iccard/solitaire.c new file mode 100644 index 0000000..cfe3da3 --- /dev/null +++ b/iccard/solitaire.c @@ -0,0 +1,143 @@ +#include "solitaire.h" + +#include + +#define DECK_SIZE 22 +#define JOKER_A 21 +#define JOKER_B 22 + +typedef struct { + char m_Deck[DECK_SIZE]; +} DECK, *PDECK; + +static DECK SOL_INIT_DECK = { + .m_Deck = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 }, +}; + +#define char2num(c) ((c) - '0' + 1) +static inline char num2char(char num) { + while (num < 1) num = num + 10; + return (num - 1) % 10 + '0'; +} + +static void SolMoveCard(PDECK lpDeck, char card) { + int p = 0; + + for (int i = 0; i < DECK_SIZE; i++) { + if (lpDeck->m_Deck[i] == card) { + p = i; + break; + } + } + + if (p < DECK_SIZE - 1) { + lpDeck->m_Deck[p] = lpDeck->m_Deck[p + 1]; + lpDeck->m_Deck[p + 1] = card; + } else { + for (int i = DECK_SIZE - 1; i > 1; i--) lpDeck->m_Deck[i] = lpDeck->m_Deck[i - 1]; + lpDeck->m_Deck[1] = card; + } +} + +static void SolCutDeck(PDECK lpDeck, char point) { + DECK tmp; + + memcpy(tmp.m_Deck, &lpDeck->m_Deck[(size_t)point], DECK_SIZE - point - 1); + memcpy(&tmp.m_Deck[DECK_SIZE - point - 1], lpDeck->m_Deck, point); + memcpy(lpDeck->m_Deck, tmp.m_Deck, DECK_SIZE - 1); +} + +static void SolSwapOutsideJoker(PDECK lpDeck) { + int j1 = -1; + int j2 = -1; + DECK tmp; + + for (int i = 0; i < DECK_SIZE; i++) { + if (lpDeck->m_Deck[i] == JOKER_A || lpDeck->m_Deck[i] == JOKER_B) { + if (j1 == -1) { + j1 = i; + } else { + j2 = i; + } + } + } + + if (0 < DECK_SIZE - j2 - 1) memcpy(tmp.m_Deck, &lpDeck->m_Deck[j2 + 1], DECK_SIZE - j2 - 1); + tmp.m_Deck[DECK_SIZE - j2 - 1] = lpDeck->m_Deck[j1]; + if (0 < j2 - j1 - 1) memcpy(&tmp.m_Deck[DECK_SIZE - j2], &lpDeck->m_Deck[j1 + 1], j2 - j1 - 1); + tmp.m_Deck[DECK_SIZE - j1 - 1] = lpDeck->m_Deck[j2]; + if (0 < j1) memcpy(&tmp.m_Deck[DECK_SIZE - j1], lpDeck->m_Deck, j1); + memcpy(lpDeck->m_Deck, tmp.m_Deck, DECK_SIZE); +} + +static void SolCutByBottomCard(PDECK lpDeck) { + char p = lpDeck->m_Deck[DECK_SIZE - 1]; + if (p == JOKER_B) p = JOKER_A; + SolCutDeck(lpDeck, p); +} + +static char SolGetTopCardNum(PDECK lpDeck) { + char p = lpDeck->m_Deck[0]; + if (p == JOKER_B) p = JOKER_A; + return lpDeck->m_Deck[(size_t)p]; +} + +static void SolDeckHash(PDECK lpDeck) { + char p; + + do { + SolMoveCard(lpDeck, JOKER_A); + SolMoveCard(lpDeck, JOKER_B); + SolMoveCard(lpDeck, JOKER_B); + SolSwapOutsideJoker(lpDeck); + SolCutByBottomCard(lpDeck); + + p = SolGetTopCardNum(lpDeck); + } while (p == JOKER_A || p == JOKER_B); +} + +static void SolCreateDeck(PDECK lpDeck, const char *key) { + memcpy_s(lpDeck, sizeof *lpDeck, &SOL_INIT_DECK, sizeof SOL_INIT_DECK); + int p = 0; + while (key[p] != '\0') { + SolDeckHash(lpDeck); + char c = char2num(key[p]); + SolCutDeck(lpDeck, c); + p++; + } +} + +void SolitaireCipherEncode(const char *szKey, const char *szSrc, char *szDst) { + DECK deck; + SolCreateDeck(&deck, szKey); + + int i = 0; + while (szSrc[i] != '\0') { + SolDeckHash(&deck); + char p = SolGetTopCardNum(&deck); + szDst[i] = num2char(char2num(szSrc[i]) + p); + i++; + } + szDst[i] = '\0'; +} + +void SolitaireCipherDecode(const char *szKey, const char *szSrc, char *szDst) { + DECK deck; + SolCreateDeck(&deck, szKey); + + int i = 0; + while (szSrc[i] != '\0') { + SolDeckHash(&deck); + char p = SolGetTopCardNum(&deck); + szDst[i] = num2char(char2num(szSrc[i]) - p); + i++; + } + szDst[i] = '\0'; +} + +void SolitaireCipher(int nMode, const char *szKey, const char *szSrc, char *szDst) { + if (nMode == 0) + SolitaireCipherEncode(szKey, szSrc, szDst); + else if (nMode == 1) + SolitaireCipherDecode(szKey, szSrc, szDst); +} diff --git a/iccard/solitaire.h b/iccard/solitaire.h new file mode 100644 index 0000000..34ea802 --- /dev/null +++ b/iccard/solitaire.h @@ -0,0 +1,3 @@ +void SolitaireCipherDecode(const char *szKey, const char *szSrc, char *szDst); +void SolitaireCipherEncode(const char *szKey, const char *szSrc, char *szDst); +void SolitaireCipher(int mode, const char *key, const char *src_str, char *dest_str);