diff --git a/0xcafec0de.bin b/0xcafec0de.bin deleted file mode 100644 index 8139d18..0000000 Binary files a/0xcafec0de.bin and /dev/null differ diff --git a/Makefile b/Makefile index 08bf9b9..12943ef 100755 --- a/Makefile +++ b/Makefile @@ -22,44 +22,5 @@ holycard_collect: holycard_solve: $(CC) $(CFLAGS) $@.c $(CRYPTO1_BS) $(CRAPTO1) ${CRAPTEV1} -o $@ -lpthread -lm $(LDFLAGS) -solve_bs: - $(CC) $(CFLAGS) $@.c $(CRYPTO1_BS) $(CRAPTO1) ${CRAPTEV1} -o $@ -lpthread -lm $(LDFLAGS) - -solve_piwi_bs: - $(CC) $(CFLAGS) $@.c $(CRYPTO1_BS) $(CRAPTO1) ${CRAPTEV1} -o $@ -lpthread -lm $(LDFLAGS) - -solve_piwi: - $(CC) $(CFLAGS) $@.c $(CRYPTO1_BS) $(CRAPTO1) ${CRAPTEV1} -o $@ -lpthread $(LDFLAGS) - -libnfc_crypto1_crack: - $(CC) $(CFLAGS) $@.c $(CRYPTO1_BS) $(CRAPTO1) ${CRAPTEV1} -o $@ -lpthread -lnfc -lm $(LDFLAGS) - clean: - rm -f solve.so solve_bs solve_piwi_bs solve_piwi libnfc_crypto1_crack holycard_collect holycard_solve - -# Windows cross compilation -MINGW32 = i686-w64-mingw32-gcc -MINGW64 = x86_64-w64-mingw32-gcc -# solve.c code cannot be compiled on windows without patching the includes - -WIN32EXES = solve_piwi_bs32.exe solve_piwi32.exe libnfc_crypto1_crack32.exe -win32: $(WIN32EXES) -win32_clean: - rm -f $(WIN32EXES) - -WIN64EXES = solve_piwi_bs64.exe solve_piwi64.exe libnfc_crypto1_crack64.exe -win64: $(WIN64EXES) -win64_clean: - rm -f $(WIN64EXES) - -solve_piwi_bs32.exe: - $(MINGW32) $(CFLAGS) solve_piwi_bs.c $(CRYPTO1_BS) $(CRAPTO1) ${CRAPTEV1} -static -m32 -o $@ -lpthread - -solve_piwi_bs64.exe: - $(MINGW64) $(CFLAGS) solve_piwi_bs.c $(CRYPTO1_BS) $(CRAPTO1) ${CRAPTEV1} -static -o $@ -lpthread - -solve_piwi32.exe: - $(MINGW32) $(CFLAGS) solve_piwi.c $(CRYPTO1_BS) $(CRAPTO1) ${CRAPTEV1} -static -m32 -o $@ -lpthread - -solve_piwi64.exe: - $(MINGW64) $(CFLAGS) solve_piwi.c $(CRYPTO1_BS) $(CRAPTO1) ${CRAPTEV1} -static -o $@ -lpthread + rm -f solve.so holycard_collect holycard_solve diff --git a/bintotxt.py b/bintotxt.py deleted file mode 100644 index 7631e07..0000000 --- a/bintotxt.py +++ /dev/null @@ -1,16 +0,0 @@ -import sys -data = file(sys.argv[1], 'rb').read() -uid = data[0:4] - -def parity(x): - return ("{0:08b}".format(x).count('1') & 1) - -for idx in range(6, len(data), 9): - n = data[idx:idx+8] - p = data[idx+8] - nonce_string = [ "%02x" % ord(n[i]) - + (' ' if int(x)^parity(ord(n[i])) else '! ') - for i, x in enumerate(("{0:08b}".format(ord(p)))) - ] - print ''.join(nonce_string[:4]) - print ''.join(nonce_string[4:]) diff --git a/libnfc_crypto1_crack.c b/libnfc_crypto1_crack.c deleted file mode 100755 index 2015dcb..0000000 --- a/libnfc_crypto1_crack.c +++ /dev/null @@ -1,738 +0,0 @@ -// Copyright (C) 2016 Aram Verstegen -/* - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "crypto1_bs_crack.h" -#define llu PRIu64 - -extern uint64_t * crypto1_create(uint64_t key); -extern uint32_t crypto1_word(uint64_t *, uint32_t, int); -extern uint8_t crypto1_byte(uint64_t*, uint8_t, int); -extern uint32_t prng_successor(uint32_t x, uint32_t n); -extern void crypto1_destroy(uint64_t*); - -#define MC_AUTH_A 0x60 -#define MC_AUTH_B 0x61 - -nfc_device* pnd; -nfc_target target; -typedef uint8_t byte_t; - -uint8_t oddparity(const uint8_t bt) -{ - // cf http://graphics.stanford.edu/~seander/bithacks.html#ParityParallel - return (0x9669 >> ((bt ^(bt >> 4)) & 0xF)) & 1; -} - - -long long unsigned int bytes_to_num(uint8_t *src, uint32_t len) -{ - uint64_t num = 0; - while (len--) { - num = (num << 8) | (*src); - src++; - } - return num; -} - -// Sectors 0 to 31 have 4 blocks per sector. -// Sectors 32 to 39 have 16 blocks per sector. -uint8_t block_to_sector(uint8_t block) -{ - uint8_t sector; - if(block < 128) { - return block >> 2; - } - block -= 128; - return 32 + (block >> 4); -} - -static nfc_context *context; - -#define MAX_FRAME_LEN 264 - -uint64_t *nonces = NULL; -size_t nonces_collected; - -enum { - OK, - ERROR, - KEY_WRONG, -}; - -#define VT100_cleareol "\r\33[2K" - -// Almost entirely based on code from Mifare Offline Cracker (MFOC) by Nethemba, cheers guys! :) -int nested_auth(uint32_t uid, uint64_t known_key, uint8_t ab_key, uint8_t for_block, uint8_t target_block, uint8_t target_key, FILE* fp) -{ - uint64_t *pcs; - - // Possible key counter, just continue with a previous "session" - uint8_t Nr[4] = { 0x00, 0x00, 0x00, 0x00 }; // Reader nonce - uint8_t Cmd[4] = { 0x00, 0x00, 0x00, 0x00 }; - - uint8_t ArEnc[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - uint8_t ArEncPar[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - - uint8_t Rx[MAX_FRAME_LEN]; // Tag response - uint8_t RxPar[MAX_FRAME_LEN]; // Tag response - - uint32_t Nt; - - int i; - - // Prepare AUTH command - Cmd[0] = ab_key; - Cmd[1] = for_block; - iso14443a_crc_append(Cmd, 2); - - // We need full control over the CRC - if (nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, false) < 0) { - nfc_perror(pnd, "nfc_device_set_property_bool crc"); - return ERROR; - } - - // Request plain tag-nonce - // TODO: Set NP_EASY_FRAMING option only once if possible - if (nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, false) < 0) { - nfc_perror(pnd, "nfc_device_set_property_bool framing"); - return ERROR; - } - - if (nfc_initiator_transceive_bytes(pnd, Cmd, 4, Rx, sizeof(Rx), 0) < 0) { - fprintf(stdout, "Error while requesting plain tag-nonce "); - return ERROR; - } - - if (nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, true) < 0) { - nfc_perror(pnd, "nfc_device_set_property_bool"); - return ERROR; - } - - // Save the tag nonce (Nt) - Nt = bytes_to_num(Rx, 4); - - // Init the cipher with key {0..47} bits - pcs = crypto1_create(known_key); - - // Load (plain) uid^nt into the cipher {48..79} bits - crypto1_word(pcs, bytes_to_num(Rx, 4) ^ uid, 0); - - // Generate (encrypted) nr+parity by loading it into the cipher - for (i = 0; i < 4; i++) { - // Load in, and encrypt the reader nonce (Nr) - ArEnc[i] = crypto1_byte(pcs, Nr[i], 0) ^ Nr[i]; - ArEncPar[i] = filter(*pcs) ^ oddparity(Nr[i]); - } - - // Skip 32 bits in the pseudo random generator - Nt = prng_successor(Nt, 32); - - // Generate reader-answer from tag-nonce - for (i = 4; i < 8; i++) { - // Get the next random byte - Nt = prng_successor(Nt, 8); - // Encrypt the reader-answer (Nt' = suc2(Nt)) - ArEnc[i] = crypto1_byte(pcs, 0x00, 0) ^(Nt & 0xff); - ArEncPar[i] = filter(*pcs) ^ oddparity(Nt); - } - - // Finally we want to send arbitrary parity bits - if (nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, false) < 0) { - nfc_perror(pnd, "nfc_device_set_property_bool parity "); - return 1; - } - - // Transmit reader-answer - int res; - if (((res = nfc_initiator_transceive_bits(pnd, ArEnc, 64, ArEncPar, Rx, sizeof(Rx), RxPar)) < 0) || (res != 32)) { - fprintf(stderr, "Reader-answer transfer error, exiting.. "); - return KEY_WRONG; - } - - // Decrypt the tag answer and verify that suc3(Nt) is At - Nt = prng_successor(Nt, 32); - - if (!((crypto1_word(pcs, 0x00, 0) ^ bytes_to_num(Rx, 4)) == (Nt & 0xFFFFFFFF))) { - fprintf(stderr, "[At] is not Suc3(Nt), something is wrong, exiting.. "); - return ERROR; - } - - Cmd[0] = target_key; - Cmd[1] = target_block; - iso14443a_crc_append(Cmd, 2); - - for (i = 0; i < 4; i++) { - ArEnc[i] = crypto1_byte(pcs, 0, 0) ^ Cmd[i]; - ArEncPar[i] = filter(*pcs) ^ oddparity(Cmd[i]); - } - if (((res = nfc_initiator_transceive_bits(pnd, ArEnc, 32, ArEncPar, Rx, sizeof(Rx), RxPar)) < 0) || (res != 32)) { - fprintf(stderr, "Reader-answer transfer error, exiting.. "); - return ERROR; - } - - if(fp){ - for(i = 0; i < 4; i++){ - fprintf(fp,"%02x", Rx[i]); - if(RxPar[i] != oddparity(Rx[i])){ - fprintf(fp,"! "); - } else { - fprintf(fp," "); - } - } - fprintf(fp, "\n"); - } - if(nonces){ - nonces[nonces_collected] = 0; - for(i = 0; i < 4; i++){ - nonces[nonces_collected] |= ((uint64_t) Rx[i]) << (8*i); - nonces[nonces_collected] |= ((uint64_t) !RxPar[i]) << (32 + (8*i)); - } - nonces_collected++; - } - - crypto1_destroy(pcs); - return OK; -} - -uint32_t uid; -uint32_t **space; -uint64_t found_key; -size_t thread_count; -void* crack_states_thread(void* x){ - const size_t thread_id = (size_t)x; - int j; - for(j = thread_id; space[j * 5]; j += thread_count) { - const uint64_t key = crack_states_bitsliced(space + j * 5); - if(key != -1){ - found_key = key; - break; - } - } - return NULL; -} - -bool stop_collection = false; -#define CUTOFF ((uint64_t) 1<<39) - -void * update_predictions_thread(void* p){ - while(!stop_collection){ - if(nonces && uid){ - if(space){ - craptev1_destroy_space(space); - space = NULL; - } - space = craptev1_get_space(nonces, 95, uid); - } - if(space){ - total_states = craptev1_sizeof_space(space); - } - sleep(1); // We don't need to check this more often than once per second - } - return NULL; -} - -void notify_status_offline(int sig){ - printf(VT100_cleareol "Cracking... %6.02f%%", (100.0*total_states_tested/(total_states))); - alarm(1); - fflush(stdout); - signal(SIGALRM, notify_status_offline); -} - -void notify_status_online(int sig){ - if(!total_states){ - printf(VT100_cleareol "Collected %zu nonces... ", nonces_collected); - } else { - printf(VT100_cleareol "Collected %zu nonces... leftover complexity %"llu" (~2^%0.2f)", nonces_collected, total_states, log(total_states) / log(2)); - char c; - if(scanf("%c", &c) == 1 || total_states < CUTOFF){ - printf(" - initializing brute-force phase...\n"); - alarm(0); - stop_collection = true; - return; - } else { - printf(" - press enter to start brute-force phase"); - } - } - alarm(1); - fflush(stdout); - signal(SIGALRM, notify_status_online); -} - -uint64_t known_key; -uint8_t for_block; -uint8_t ab_key; -uint8_t target_block; -uint8_t target_key; -FILE* fp; - -const nfc_modulation nmMifare = { - .nmt = NMT_ISO14443A, - .nbr = NBR_106, -}; - -void * update_nonces_thread(void* v){ - while(!stop_collection){ - // Configure the CRC and Parity settings - nfc_device_set_property_bool(pnd,NP_HANDLE_CRC,true); - nfc_device_set_property_bool(pnd,NP_HANDLE_PARITY,true); - // Poll for a ISO14443A (MIFARE) tag - if (nfc_initiator_select_passive_target(pnd,nmMifare,NULL,0,&target)) { - nested_auth(uid, known_key, ab_key, for_block, target_block, target_key, fp); - } else { - printf(VT100_cleareol "Don't move the tag!"); - fflush(stdout); - } - } - return NULL; -} - -int main (int argc, const char * argv[]) { - nfc_init(&context); - pnd = nfc_open(context, NULL); - - if (pnd == NULL) { - fprintf(stderr, "No NFC device connection\n"); - return 1; - } - - nfc_initiator_init(pnd); - - nfc_device_set_property_bool(pnd,NP_ACTIVATE_FIELD,false); - // Let the reader only try once to find a tag - nfc_device_set_property_bool(pnd,NP_INFINITE_SELECT,false); - nfc_device_set_property_bool(pnd,NP_HANDLE_CRC,true); - nfc_device_set_property_bool(pnd,NP_HANDLE_PARITY,true); - nfc_device_set_property_bool(pnd,NP_AUTO_ISO14443_4, false); - - uid = 0; - - // Enable field so more power consuming cards can power themselves up - nfc_device_set_property_bool(pnd,NP_ACTIVATE_FIELD,true); - if (nfc_initiator_select_passive_target(pnd,nmMifare,NULL,0,&target)) { - uid = bytes_to_num(target.nti.nai.abtUid,target.nti.nai.szUidLen); - } - - if(!uid){ - fprintf(stderr, "No tag detected!\n"); - // Disconnect from NFC device - nfc_close(pnd); - return 1; - } - - if(argc < 6){ - printf("%s \n", argv[0]); - nfc_close(pnd); - return 1; - } - - known_key = strtoull(argv[1], 0, 16); - for_block = atoi(argv[2]); - ab_key = MC_AUTH_A; - if(argv[3][0] == 'b' || argv[3][0] == 'B'){ - ab_key = MC_AUTH_B; - } - target_block = atoi(argv[4]); - target_key = MC_AUTH_A; - if(argv[5][0] == 'b' || argv[5][0] == 'B'){ - target_key = MC_AUTH_B; - } - switch(nested_auth(uid, known_key, ab_key, for_block, target_block, target_key, NULL)){ - case KEY_WRONG: - printf("%012"PRIx64" doesn't look like the right key %s for block %u (sector %u)\n", known_key, ab_key == MC_AUTH_A ? "A" : "B", for_block, block_to_sector(for_block)); - return 1; - case OK: - break; - case ERROR: - default: - printf("Some other error occurred.\n"); - break; - } - - char filename[21]; - sprintf(filename, "0x%08x_%03u%s.txt", uid, target_block, target_key == MC_AUTH_A ? "A" : "B"); - fp = fopen(filename, "wb"); - - printf("Found tag with uid %04x, collecting nonces for key %s of block %u (sector %u) using known key %s %012"PRIx64" for block %u (sector %u)\n", - uid, target_key == MC_AUTH_A ? "A" : "B", target_block, block_to_sector(target_block), ab_key == MC_AUTH_A ? "A" : "B", known_key, for_block, block_to_sector(for_block)); - nonces_collected = 0; - nonces = malloc(sizeof (uint64_t) << 24); - memset(nonces, 0xff, sizeof (uint64_t) << 24); - - fcntl(0, F_SETFL, O_NONBLOCK); - signal(SIGALRM, notify_status_online); - alarm(1); - pthread_t prediction_thread, nonce_gathering_thread; - pthread_create(&nonce_gathering_thread, NULL, update_nonces_thread, NULL); - pthread_create(&prediction_thread, NULL, update_predictions_thread, NULL); - pthread_join(nonce_gathering_thread, 0); - pthread_join(prediction_thread, 0); - alarm(0); - - if(fp){ - fclose(fp); - } - nfc_close(pnd); - - if(!space){ - space = craptev1_get_space(nonces, 95, uid); - } - if(space){ - total_states = craptev1_sizeof_space(space); - } else { - total_states = 0; - } - if(!total_states){ - fprintf(stderr, "No solution found :(\n"); - return 1; - } - -#ifndef __WIN32 - thread_count = sysconf(_SC_NPROCESSORS_CONF); -#else - thread_count = 1; -#endif - // append some zeroes to the end of the space to make sure threads don't go off into the wild - size_t j = 0; - for(j = 0; space[j]; j+=5){ - } - size_t fill = j + (5*thread_count); - for(; j < fill; j++) { - space[j] = 0; - } - pthread_t threads[thread_count]; - - crypto1_bs_init(); - - uint8_t rollback_byte = **space; - // convert to 32 bit little-endian - crypto1_bs_bitslice_value32(rev32((rollback_byte)), bitsliced_rollback_byte, 8); - - for(size_t tests = 0; tests < NONCE_TESTS; tests++){ - // pre-xor the uid into the decrypted nonces, and also pre-xor the uid parity into the encrypted parity bits - otherwise an exta xor is required in the decryption routine - uint32_t test_nonce = uid^rev32(nonces[tests]); - uint32_t test_parity = (nonces[tests]>>32)^rev32(uid); - test_parity = ((parity(test_parity >> 24 & 0xff) & 1) | (parity(test_parity>>16 & 0xff) & 1)<<1 | (parity(test_parity>>8 & 0xff) & 1)<<2 | (parity(test_parity & 0xff) & 1) << 3); - crypto1_bs_bitslice_value32(test_nonce, bitsliced_encrypted_nonces[tests], 32); - // convert to 32 bit little-endian - crypto1_bs_bitslice_value32(~(test_parity)<<24, bitsliced_encrypted_parity_bits[tests], 4); - } - - printf("Starting %zu threads to test %"llu" states using %u-way bitslicing\n", thread_count, total_states, MAX_BITSLICES); - total_states_tested = 0; - keys_found = 0; - signal(SIGALRM, notify_status_offline); - - notify_status_offline(0); - alarm(1); - - size_t i; - for(i = 0; i < thread_count; i++){ - pthread_create(&threads[i], NULL, crack_states_thread, (void*) i); - } - for(i = 0; i < thread_count; i++){ - pthread_join(threads[i], 0); - } - alarm(0); - printf("\n"); - if(!keys_found){ - fprintf(stderr, "No solution found :(\n"); - return 1; - } else { - printf("Found key: %012"PRIx64"\n", found_key); - } - printf("Tested %"llu" states\n", total_states_tested); - - craptev1_destroy_space(space); - return 0; -} diff --git a/pwpiwi_proxmark3_hard_nested.patch b/pwpiwi_proxmark3_hard_nested.patch deleted file mode 100644 index f4e29c8..0000000 --- a/pwpiwi_proxmark3_hard_nested.patch +++ /dev/null @@ -1,632 +0,0 @@ -Just thought I'd make it clear that this code is GPLv2 licensed here - -- Aram Verstegen - - - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS -diff --git a/client/Makefile b/client/Makefile -index 91e595d..dc3557f 100644 ---- a/client/Makefile -+++ b/client/Makefile -@@ -107,6 +107,7 @@ CMDSRCS = nonce2key/crapto1.c\ - aes.c\ - protocols.c\ - sha1.c\ -+ crypto1_bs.c \ - - ZLIBSRCS = deflate.c adler32.c trees.c zutil.c inflate.c inffast.c inftrees.c - ZLIB_FLAGS = -DZ_SOLO -DZ_PREFIX -DNO_GZIP -DZLIB_PM3_TUNED -diff --git a/client/cmdhfmfhard.c b/client/cmdhfmfhard.c -index b3893ea..bf71a08 100644 ---- a/client/cmdhfmfhard.c -+++ b/client/cmdhfmfhard.c -@@ -20,12 +20,15 @@ - #include - #include - #include -+#include -+#include - #include "proxmark3.h" - #include "cmdmain.h" - #include "ui.h" - #include "util.h" - #include "nonce2key/crapto1.h" - #include "parity.h" -+#include "crypto1_bs.h" - - // uint32_t test_state_odd = 0; - // uint32_t test_state_even = 0; -@@ -88,6 +91,8 @@ typedef struct noncelist { - } noncelist_t; - - -+static size_t nonces_to_bruteforce = 0; -+static noncelistentry_t *brute_force_nonces[256]; - static uint32_t cuid; - static noncelist_t nonces[256]; - static uint8_t best_first_bytes[256]; -@@ -169,6 +174,11 @@ static int add_nonce(uint32_t nonce_enc, uint8_t par_enc) - p2->nonce_enc = nonce_enc; - p2->par_enc = par_enc; - -+ if(nonces_to_bruteforce < 256){ -+ brute_force_nonces[nonces_to_bruteforce] = p2; -+ nonces_to_bruteforce++; -+ } -+ - nonces[first_byte].num++; - nonces[first_byte].Sum += evenparity32((nonce_enc & 0x00ff0000) | (par_enc & 0x04)); - nonces[first_byte].updated = true; // indicates that we need to recalculate the Sum(a8) probability for this first byte -@@ -1376,6 +1386,236 @@ static void free_statelist_cache(void) - } - } - -+size_t keys_found = 0; -+size_t bucket_count = 0; -+statelist_t* buckets[128]; -+size_t total_states_tested = 0; -+size_t thread_count = 4; -+ -+// these bitsliced states will hold identical states in all slices -+bitslice_t bitsliced_rollback_byte[ROLLBACK_SIZE]; -+ -+// arrays of bitsliced states with identical values in all slices -+bitslice_t bitsliced_encrypted_nonces[NONCE_TESTS][STATE_SIZE]; -+bitslice_t bitsliced_encrypted_parity_bits[NONCE_TESTS][ROLLBACK_SIZE]; -+ -+#define EXACT_COUNT -+ -+static const uint64_t crack_states_bitsliced(statelist_t *p){ -+ // the idea to roll back the half-states before combining them was suggested/explained to me by bla -+ // first we pre-bitslice all the even state bits and roll them back, then bitslice the odd bits and combine the two in the inner loop -+ uint64_t key = -1; -+#ifdef EXACT_COUNT -+ size_t bucket_states_tested = 0; -+ size_t bucket_size[p->len[EVEN_STATE]/MAX_BITSLICES]; -+#else -+ const size_t bucket_states_tested = (p->len[EVEN_STATE])*(p->len[ODD_STATE]); -+#endif -+ bitslice_t *bitsliced_even_states[p->len[EVEN_STATE]/MAX_BITSLICES]; -+ size_t bitsliced_blocks = 0; -+ uint32_t const * restrict even_end = p->states[EVEN_STATE]+p->len[EVEN_STATE]; -+ // bitslice all the even states -+ for(uint32_t * restrict p_even = p->states[EVEN_STATE]; p_even < even_end; p_even+=MAX_BITSLICES){ -+ bitslice_t * restrict lstate_p = memalign(sizeof(bitslice_t), (STATE_SIZE+ROLLBACK_SIZE)*sizeof(bitslice_t)); -+ memset(lstate_p+1, 0x0, (STATE_SIZE-1)*sizeof(bitslice_t)); // zero even bits -+ // bitslice even half-states -+ const size_t max_slices = (even_end-p_even) < MAX_BITSLICES ? even_end-p_even : MAX_BITSLICES; -+#ifdef EXACT_COUNT -+ bucket_size[bitsliced_blocks] = max_slices; -+#endif -+ for(size_t slice_idx = 0; slice_idx < max_slices; ++slice_idx){ -+ uint32_t e = *(p_even+slice_idx); -+ for(size_t bit_idx = 1; bit_idx < STATE_SIZE; bit_idx+=2, e >>= 1){ -+ // set even bits -+ if(e&1){ -+ lstate_p[bit_idx].bytes64[slice_idx>>6] |= 1ull << (slice_idx&63); -+ } -+ } -+ } -+ // compute the rollback bits -+ for(size_t rollback = 0; rollback < ROLLBACK_SIZE; ++rollback){ -+ // inlined crypto1_bs_lfsr_rollback -+ const bitslice_value_t feedout = lstate_p[0].value; -+ ++lstate_p; -+ const bitslice_value_t ks_bits = crypto1_bs_f20(lstate_p); -+ const bitslice_value_t feedback = (feedout ^ ks_bits ^ lstate_p[47- 5].value ^ lstate_p[47- 9].value ^ -+ lstate_p[47-10].value ^ lstate_p[47-12].value ^ lstate_p[47-14].value ^ -+ lstate_p[47-15].value ^ lstate_p[47-17].value ^ lstate_p[47-19].value ^ -+ lstate_p[47-24].value ^ lstate_p[47-25].value ^ lstate_p[47-27].value ^ -+ lstate_p[47-29].value ^ lstate_p[47-35].value ^ lstate_p[47-39].value ^ -+ lstate_p[47-41].value ^ lstate_p[47-42].value ^ lstate_p[47-43].value); -+ lstate_p[47].value = feedback ^ bitsliced_rollback_byte[rollback].value; -+ } -+ bitsliced_even_states[bitsliced_blocks++] = lstate_p; -+ } -+ // bitslice every odd state to every block of even half-states with half-finished rollback -+ for(uint32_t const * restrict p_odd = p->states[ODD_STATE]; p_odd < p->states[ODD_STATE]+p->len[ODD_STATE]; ++p_odd){ -+ // early abort -+ if(keys_found){ -+ goto out; -+ } -+ -+ // set the odd bits and compute rollback -+ uint64_t o = (uint64_t) *p_odd; -+ lfsr_rollback_byte((struct Crypto1State*) &o, 0, 1); -+ // pre-compute part of the odd feedback bits (minus rollback) -+ bool odd_feedback_bit = parity(o&0x9ce5c); -+ -+ crypto1_bs_rewind_a0(); -+ // set odd bits -+ for(size_t state_idx = 0; state_idx < STATE_SIZE-ROLLBACK_SIZE; o >>= 1, state_idx+=2){ -+ if(o & 1){ -+ state_p[state_idx] = bs_ones; -+ } else { -+ state_p[state_idx] = bs_zeroes; -+ } -+ } -+ const bitslice_value_t odd_feedback = odd_feedback_bit ? bs_ones.value : bs_zeroes.value; -+ -+ for(size_t block_idx = 0; block_idx < bitsliced_blocks; ++block_idx){ -+ const bitslice_t const * restrict bitsliced_even_state = bitsliced_even_states[block_idx]; -+ size_t state_idx; -+ // set even bits -+ for(state_idx = 0; state_idx < STATE_SIZE-ROLLBACK_SIZE; state_idx+=2){ -+ state_p[1+state_idx] = bitsliced_even_state[1+state_idx]; -+ } -+ // set rollback bits -+ uint64_t lo = o; -+ for(; state_idx < STATE_SIZE; lo >>= 1, state_idx+=2){ -+ // set the odd bits and take in the odd rollback bits from the even states -+ if(lo & 1){ -+ state_p[state_idx].value = ~bitsliced_even_state[state_idx].value; -+ } else { -+ state_p[state_idx] = bitsliced_even_state[state_idx]; -+ } -+ -+ // set the even bits and take in the even rollback bits from the odd states -+ if((lo >> 32) & 1){ -+ state_p[1+state_idx].value = ~bitsliced_even_state[1+state_idx].value; -+ } else { -+ state_p[1+state_idx] = bitsliced_even_state[1+state_idx]; -+ } -+ } -+ -+#ifdef EXACT_COUNT -+ bucket_states_tested += bucket_size[block_idx]; -+#endif -+ // pre-compute first keystream and feedback bit vectors -+ const bitslice_value_t ksb = crypto1_bs_f20(state_p); -+ const bitslice_value_t fbb = (odd_feedback ^ state_p[47- 0].value ^ state_p[47- 5].value ^ // take in the even and rollback bits -+ state_p[47-10].value ^ state_p[47-12].value ^ state_p[47-14].value ^ -+ state_p[47-24].value ^ state_p[47-42].value); -+ -+ // vector to contain test results (1 = passed, 0 = failed) -+ bitslice_t results = bs_ones; -+ -+ for(size_t tests = 0; tests < NONCE_TESTS; ++tests){ -+ size_t parity_bit_idx = 0; -+ bitslice_value_t fb_bits = fbb; -+ bitslice_value_t ks_bits = ksb; -+ state_p = &states[KEYSTREAM_SIZE-1]; -+ bitslice_value_t parity_bit_vector = bs_zeroes.value; -+ -+ // highest bit is transmitted/received first -+ for(int32_t ks_idx = KEYSTREAM_SIZE-1; ks_idx >= 0; --ks_idx, --state_p){ -+ // decrypt nonce bits -+ const bitslice_value_t encrypted_nonce_bit_vector = bitsliced_encrypted_nonces[tests][ks_idx].value; -+ const bitslice_value_t decrypted_nonce_bit_vector = (encrypted_nonce_bit_vector ^ ks_bits); -+ -+ // compute real parity bits on the fly -+ parity_bit_vector ^= decrypted_nonce_bit_vector; -+ -+ // update state -+ state_p[0].value = (fb_bits ^ decrypted_nonce_bit_vector); -+ -+ // compute next keystream bit -+ ks_bits = crypto1_bs_f20(state_p); -+ -+ // for each byte: -+ if((ks_idx&7) == 0){ -+ // get encrypted parity bits -+ const bitslice_value_t encrypted_parity_bit_vector = bitsliced_encrypted_parity_bits[tests][parity_bit_idx++].value; -+ -+ // decrypt parity bits -+ const bitslice_value_t decrypted_parity_bit_vector = (encrypted_parity_bit_vector ^ ks_bits); -+ -+ // compare actual parity bits with decrypted parity bits and take count in results vector -+ results.value &= (parity_bit_vector ^ decrypted_parity_bit_vector); -+ -+ // make sure we still have a match in our set -+ // if(memcmp(&results, &bs_zeroes, sizeof(bitslice_t)) == 0){ -+ -+ // this is much faster on my gcc, because somehow a memcmp needlessly spills/fills all the xmm registers to/from the stack - ??? -+ // the short-circuiting also helps -+ if(results.bytes64[0] == 0 -+#if MAX_BITSLICES > 64 -+ && results.bytes64[1] == 0 -+#endif -+#if MAX_BITSLICES > 128 -+ && results.bytes64[2] == 0 -+ && results.bytes64[3] == 0 -+#endif -+ ){ -+ goto stop_tests; -+ } -+ // this is about as fast but less portable (requires -std=gnu99) -+ // asm goto ("ptest %1, %0\n\t" -+ // "jz %l2" :: "xm" (results.value), "xm" (bs_ones.value) : "cc" : stop_tests); -+ parity_bit_vector = bs_zeroes.value; -+ } -+ // compute next feedback bit vector -+ fb_bits = (state_p[47- 0].value ^ state_p[47- 5].value ^ state_p[47- 9].value ^ -+ state_p[47-10].value ^ state_p[47-12].value ^ state_p[47-14].value ^ -+ state_p[47-15].value ^ state_p[47-17].value ^ state_p[47-19].value ^ -+ state_p[47-24].value ^ state_p[47-25].value ^ state_p[47-27].value ^ -+ state_p[47-29].value ^ state_p[47-35].value ^ state_p[47-39].value ^ -+ state_p[47-41].value ^ state_p[47-42].value ^ state_p[47-43].value); -+ } -+ } -+ // all nonce tests were successful: we've found the key in this block! -+ state_t keys[MAX_BITSLICES]; -+ crypto1_bs_convert_states(&states[KEYSTREAM_SIZE], keys); -+ for(size_t results_idx = 0; results_idx < MAX_BITSLICES; ++results_idx){ -+ if(get_vector_bit(results_idx, results)){ -+ key = keys[results_idx].value; -+ goto out; -+ } -+ } -+stop_tests: -+ // prepare to set new states -+ crypto1_bs_rewind_a0(); -+ continue; -+ } -+ } -+out: -+ for(size_t block_idx = 0; block_idx < bitsliced_blocks; ++block_idx){ -+ free(bitsliced_even_states[block_idx]-ROLLBACK_SIZE); -+ } -+ __sync_fetch_and_add(&total_states_tested, bucket_states_tested); -+ return key; -+} -+ -+static void* crack_states_thread(void* x){ -+ const size_t thread_id = (size_t)x; -+ size_t current_bucket = thread_id; -+ while(current_bucket < bucket_count){ -+ statelist_t * bucket = buckets[current_bucket]; -+ if(bucket){ -+ const uint64_t key = crack_states_bitsliced(bucket); -+ if(key != -1){ -+ printf("Found key: %012lx\n", key); -+ __sync_fetch_and_add(&keys_found, 1); -+ break; -+ } else if(keys_found){ -+ break; -+ } else { -+ printf("Cracking... %6.02f%%\n", (100.0*total_states_tested/(maximum_states))); -+ } -+ } -+ current_bucket += thread_count; -+ } -+ return NULL; -+} - - static void brute_force(void) - { -@@ -1383,7 +1623,56 @@ static void brute_force(void) - PrintAndLog("Looking for known target key in remaining key space..."); - TestIfKeyExists(known_target_key); - } else { -- PrintAndLog("Brute Force phase is not implemented."); -+ PrintAndLog("Brute force phase starting."); -+ time_t start, end; -+ time(&start); -+ keys_found = 0; -+ -+ crypto1_bs_init(); -+ -+ PrintAndLog("Using %u-bit bitslices", MAX_BITSLICES); -+ PrintAndLog("Bitslicing best_first_byte^uid[3] (rollback byte): %02x...", best_first_bytes[0]^(cuid>>24)); -+ // convert to 32 bit little-endian -+ crypto1_bs_bitslice_value32((best_first_bytes[0]<<24)^cuid, bitsliced_rollback_byte, 8); -+ -+ PrintAndLog("Bitslicing nonces..."); -+ for(size_t tests = 0; tests < NONCE_TESTS; tests++){ -+ uint32_t test_nonce = brute_force_nonces[tests]->nonce_enc; -+ uint8_t test_parity = brute_force_nonces[tests]->par_enc; -+ // pre-xor the uid into the decrypted nonces, and also pre-xor the cuid parity into the encrypted parity bits - otherwise an exta xor is required in the decryption routine -+ crypto1_bs_bitslice_value32(cuid^test_nonce, bitsliced_encrypted_nonces[tests], 32); -+ // convert to 32 bit little-endian -+ crypto1_bs_bitslice_value32(rev32( ~(test_parity ^ ~(parity(cuid>>24 & 0xff)<<3 | parity(cuid>>16 & 0xff)<<2 | parity(cuid>>8 & 0xff)<<1 | parity(cuid&0xff)))), bitsliced_encrypted_parity_bits[tests], 4); -+ } -+ total_states_tested = 0; -+ -+ // count number of states to go -+ bucket_count = 0; -+ for (statelist_t *p = candidates; p != NULL; p = p->next) { -+ buckets[bucket_count] = p; -+ bucket_count++; -+ } -+ -+ // enumerate states using all hardware threads, each thread handles one bucket -+ thread_count = sysconf(_SC_NPROCESSORS_CONF); -+ PrintAndLog("Starting %u cracking threads to search %u buckets containing a total of %lu states...", thread_count, bucket_count, maximum_states); -+ pthread_t threads[thread_count]; -+ for(size_t i = 0; i < thread_count; i++){ -+ pthread_create(&threads[i], NULL, crack_states_thread, (void*) i); -+ } -+ for(size_t i = 0; i < thread_count; i++){ -+ pthread_join(threads[i], 0); -+ } -+ -+ time(&end); -+ unsigned long elapsed_time = difftime(end, start); -+ PrintAndLog("Tested %lu states, found %u keys after %u seconds", total_states_tested, keys_found, elapsed_time); -+ if(!keys_found){ -+ assert(total_states_tested == maximum_states); -+ } -+ // reset this counter for the next call -+ -+ nonces_to_bruteforce = 0; - } - - } diff --git a/solve_bs.c b/solve_bs.c deleted file mode 100644 index bf14d9a..0000000 --- a/solve_bs.c +++ /dev/null @@ -1,145 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "craptev1.h" -#include "crypto1_bs.h" -#include "crypto1_bs_crack.h" -#include -#include -#define __STDC_FORMAT_MACROS -#define llx PRIx64 -#define lli PRIi64 -#define llu PRIu64 -#define lu PRIu32 -#define VT100_cleareol "\r\33[2K" - -uint32_t **space; -uint8_t thread_count = 1; - -uint64_t *readnonces(char* fname) { - int i, j; - FILE *f = fopen(fname, "r"); - if (f == NULL) { - fprintf(stderr, "Cannot open file.\n"); - exit(EXIT_FAILURE); - } - uint64_t *nonces = malloc(sizeof (uint64_t) << 24); - uint32_t nt; - char par; - - i = 0; - while(!feof(f)){ - nonces[i] = 0; - for(j = 0; j < 32; j += 8) { - if(2 != fscanf(f, "%02x%c ", &nt, &par)) { - fprintf(stderr, "Input format error at line:%d\n", i); - fflush(stderr); - exit(EXIT_FAILURE); - } - nonces[i] |= nt << j | (uint64_t)((par == '!') ^ parity(nt)) << (32 + j); - } - i++; - } - nonces[i] = -1; - fclose(f); - return nonces; -} - -void* crack_states_thread(void* x){ - const size_t thread_id = (size_t)x; - int j; - for(j = thread_id; space[j * 5]; j += thread_count) { - const uint64_t key = crack_states_bitsliced(space + j * 5); - if(key != -1){ - printf("Found key: %012"llx"\n", key); - break; - } else if(keys_found){ - break; - } - } - return NULL; -} - -void notify_status_offline(int sig){ - printf(VT100_cleareol "Cracking... %6.02f%%", (100.0*total_states_tested/(total_states))); - alarm(1); - fflush(stdout); - signal(SIGALRM, notify_status_offline); -} - -int main(int argc, char* argv[]){ - if(argc != 3){ - printf("Usage: %s \n", argv[0]); - return -1; - } - printf("Reading nonces...\n"); - uint64_t *nonces = readnonces(argv[1]); - uint32_t uid = strtoul(argv[2], NULL, 16); - printf("Deriving search space...\n"); - space = craptev1_get_space(nonces, 95, uid); - total_states = craptev1_sizeof_space(space); - -#ifndef __WIN32 - thread_count = sysconf(_SC_NPROCESSORS_CONF); -#else - thread_count = 1; -#endif - // append some zeroes to the end of the space to make sure threads don't go off into the wild - size_t j = 0; - for(j = 0; space[j]; j+=5){ - } - size_t fill = j + (5*thread_count); - for(; j < fill; j++) { - space[j] = 0; - } - pthread_t threads[thread_count]; - size_t i; - - printf("Initializing BS crypto-1\n"); - crypto1_bs_init(); - printf("Using %u-bit bitslices\n", MAX_BITSLICES); - - uint8_t rollback_byte = **space; - printf("Bitslicing rollback byte: %02x...\n", rollback_byte); - // convert to 32 bit little-endian - crypto1_bs_bitslice_value32(rev32((rollback_byte)), bitsliced_rollback_byte, 8); - - printf("Bitslicing nonces...\n"); - for(size_t tests = 0; tests < NONCE_TESTS; tests++){ - // pre-xor the uid into the decrypted nonces, and also pre-xor the uid parity into the encrypted parity bits - otherwise an exta xor is required in the decryption routine - uint32_t test_nonce = uid^rev32(nonces[tests]); - uint32_t test_parity = (nonces[tests]>>32)^rev32(uid); - test_parity = ((parity(test_parity >> 24 & 0xff) & 1) | (parity(test_parity>>16 & 0xff) & 1)<<1 | (parity(test_parity>>8 & 0xff) & 1)<<2 | (parity(test_parity & 0xff) & 1) << 3); - crypto1_bs_bitslice_value32(test_nonce, bitsliced_encrypted_nonces[tests], 32); - // convert to 32 bit little-endian - crypto1_bs_bitslice_value32(~(test_parity)<<24, bitsliced_encrypted_parity_bits[tests], 4); - } - - total_states_tested = 0; - keys_found = 0; - - printf("Starting %u threads to test %"llu" (~2^%0.2f) states\n", thread_count, total_states, log(total_states) / log(2)); - - signal(SIGALRM, notify_status_offline); - alarm(1); - - for(i = 0; i < thread_count; i++){ - pthread_create(&threads[i], NULL, crack_states_thread, (void*) i); - } - for(i = 0; i < thread_count; i++){ - pthread_join(threads[i], 0); - } - - alarm(0); - - printf("\nTested %"llu" states\n", total_states_tested); - - if(!keys_found) fprintf(stderr, "No solution found :(\n"); - - craptev1_destroy_space(space); - return 0; -} - diff --git a/solve_piwi.c b/solve_piwi.c deleted file mode 100644 index acc1bc5..0000000 --- a/solve_piwi.c +++ /dev/null @@ -1,101 +0,0 @@ -#include -#include -#include -#include -#include -#include "craptev1.h" -#include -#define __STDC_FORMAT_MACROS -#define llx PRIx64 -#define lli PRIi64 -#define llu PRIu64 -#define lu PRIu32 - -#define rev32(word) (((word & 0xff) << 24) | (((word >> 8) & 0xff) << 16) | (((word >> 16) & 0xff) << 8) | (((word >> 24) & 0xff))) - -uint64_t split(uint8_t p){ - return (((p & 0x8) >>3 )| ((p & 0x4) >> 2) << 8 | ((p & 0x2) >> 1) << 16 | (p & 0x1) << 24 ); -} - -uint32_t uid; -uint64_t *readnonces(char* fname){ - int i; - FILE *f = fopen(fname, "rb"); - uint64_t *nonces = malloc(sizeof (uint64_t) << 24); - if(fread(&uid, 1, 4, f)){ - uid = rev32(uid); - } - fseek(f, 6, SEEK_SET); - i = 0; - uint32_t nt_enc1, nt_enc2; - uint8_t par_enc; - while(!feof(f)){ - if(fread(&nt_enc1, 1, 4, f) && fread(&nt_enc2, 1, 4, f) && fread(&par_enc, 1, 1, f)){ - nonces[i ] = split(~(par_enc >> 4)) << 32 | nt_enc1; - nonces[i+1] = split(~(par_enc & 0xff)) << 32 | nt_enc2; - i += 2; - } - } - nonces[i] = -1; - fclose(f); - return nonces; -} - -uint32_t **space; -uint8_t thread_count = 1; -uint64_t states_tested = 0; -uint64_t total_states; - -void* crack_states_thread(void* x){ - const size_t thread_id = (size_t)x; - int j; - for(j = thread_id; space[j * 5]; j += thread_count) { - uint64_t key = craptev1_search_partition(space + j * 5); - states_tested = total_states - craptev1_sizeof_space(space+j*5); - printf("Cracking... %6.02f%%\n", (100.0*states_tested/(total_states))); - if(key != -1){ - printf("Found key: %012"llx"\n", key); - exit(0); - } - } - return NULL; -} - -int main(int argc, char* argv[]){ - if(argc != 2){ - printf("Usage: %s \n", argv[0]); - return -1; - } - uint64_t *nonces = readnonces(argv[1]); - space = craptev1_get_space(nonces, 95, uid); - total_states = craptev1_sizeof_space(space); - -#ifndef __WIN32 - thread_count = sysconf(_SC_NPROCESSORS_CONF); -#else - thread_count = 1; -#endif - // append some zeroes to the end of the space to make sure threads don't go off into the wild - size_t j = 0; - for(j = 0; space[j]; j+=5){ - } - size_t fill = j + (5*thread_count); - for(; j < fill; j++) { - space[j] = 0; - } - pthread_t threads[thread_count]; - printf("Starting %u threads to test %"llu" states\n", thread_count, total_states); - size_t i; - states_tested = 0; - for(i = 0; i < thread_count; i++){ - pthread_create(&threads[i], NULL, crack_states_thread, (void*) i); - } - for(i = 0; i < thread_count; i++){ - pthread_join(threads[i], 0); - } - printf("Tested %"llu" states\n", states_tested); - - craptev1_destroy_space(space); - return 0; -} - diff --git a/solve_piwi_bs.c b/solve_piwi_bs.c deleted file mode 100644 index 1d149e7..0000000 --- a/solve_piwi_bs.c +++ /dev/null @@ -1,147 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "craptev1.h" -#include "crypto1_bs.h" -#include "crypto1_bs_crack.h" -#include -#include -#define __STDC_FORMAT_MACROS -#define llx PRIx64 -#define lli PRIi64 -#define llu PRIu64 -#define lu PRIu32 -#define VT100_cleareol "\r\33[2K" - -uint64_t split(uint8_t p){ - return (((p & 0x8) >>3 )| ((p & 0x4) >> 2) << 8 | ((p & 0x2) >> 1) << 16 | (p & 0x1) << 24 ); -} - -uint32_t uid; -uint64_t *readnonces(char* fname){ - int i; - FILE *f = fopen(fname, "rb"); - if (f == NULL) { - fprintf(stderr, "Cannot open file.\n"); - exit(EXIT_FAILURE); - } - uint64_t *nonces = malloc(sizeof (uint64_t) << 24); - if(fread(&uid, 1, 4, f)){ - uid = rev32(uid); - } - fseek(f, 6, SEEK_SET); - i = 0; - while(!feof(f)){ - uint32_t nt_enc1, nt_enc2; - uint8_t par_enc; - if(fread(&nt_enc1, 1, 4, f) && fread(&nt_enc2, 1, 4, f) && fread(&par_enc, 1, 1, f)){ - nonces[i ] = split(~(par_enc >> 4)) << 32 | nt_enc1; - nonces[i+1] = split(~(par_enc & 0xff)) << 32 | nt_enc2; - i += 2; - } - } - nonces[i] = -1; - fclose(f); - return nonces; -} - -uint32_t **space; -uint8_t thread_count = 1; - -void* crack_states_thread(void* x){ - const size_t thread_id = (size_t)x; - int j; - for(j = thread_id; space[j * 5]; j += thread_count) { - const uint64_t key = crack_states_bitsliced(space + j * 5); - if(key != -1){ - printf("Found key: %012"llx"\n", key); - break; - } else if(keys_found){ - break; - } - } - return NULL; -} - -void notify_status_offline(int sig){ - printf(VT100_cleareol "Cracking... %6.02f%%", (100.0*total_states_tested/(total_states))); - alarm(1); - fflush(stdout); - signal(SIGALRM, notify_status_offline); -} - -int main(int argc, char* argv[]){ - if(argc != 2){ - printf("Usage: %s \n", argv[0]); - return -1; - } - printf("Reading nonces...\n"); - uint64_t *nonces = readnonces(argv[1]); - printf("Deriving search space...\n"); - space = craptev1_get_space(nonces, 95, uid); - total_states = craptev1_sizeof_space(space); - -#ifndef __WIN32 - thread_count = sysconf(_SC_NPROCESSORS_CONF); -#else - thread_count = 1; -#endif - - // append some zeroes to the end of the space to make sure threads don't go off into the wild - size_t j = 0; - for(j = 0; space[j]; j+=5){ - } - size_t fill = j + (5*thread_count); - for(; j < fill; j++) { - space[j] = 0; - } - pthread_t threads[thread_count]; - size_t i; - - printf("Initializing BS crypto-1\n"); - crypto1_bs_init(); - printf("Using %u-bit bitslices\n", MAX_BITSLICES); - - uint8_t rollback_byte = **space; - printf("Bitslicing rollback byte: %02x...\n", rollback_byte); - // convert to 32 bit little-endian - crypto1_bs_bitslice_value32(rev32((rollback_byte)), bitsliced_rollback_byte, 8); - - printf("Bitslicing nonces...\n"); - for(size_t tests = 0; tests < NONCE_TESTS; tests++){ - // pre-xor the uid into the decrypted nonces, and also pre-xor the uid parity into the encrypted parity bits - otherwise an exta xor is required in the decryption routine - uint32_t test_nonce = uid^rev32(nonces[tests]); - uint32_t test_parity = (nonces[tests]>>32)^rev32(uid); - test_parity = ((parity(test_parity >> 24 & 0xff) & 1) | (parity(test_parity>>16 & 0xff) & 1)<<1 | (parity(test_parity>>8 & 0xff) & 1)<<2 | (parity(test_parity &0xff) & 1) << 3); - crypto1_bs_bitslice_value32(test_nonce, bitsliced_encrypted_nonces[tests], 32); - // convert to 32 bit little-endian - crypto1_bs_bitslice_value32(~(test_parity)<<24, bitsliced_encrypted_parity_bits[tests], 4); - } - - total_states_tested = 0; - keys_found = 0; - - printf("Starting %u threads to test %"llu" (~2^%0.2f) states\n", thread_count, total_states, log(total_states) / log(2)); - - signal(SIGALRM, notify_status_offline); - alarm(1); - - for(i = 0; i < thread_count; i++){ - pthread_create(&threads[i], NULL, crack_states_thread, (void*) i); - } - for(i = 0; i < thread_count; i++){ - pthread_join(threads[i], 0); - } - - alarm(0); - - printf("Tested %"llu" states\n", total_states_tested); - - craptev1_destroy_space(space); - return 0; -} - - diff --git a/txttobin.py b/txttobin.py deleted file mode 100644 index ac53400..0000000 --- a/txttobin.py +++ /dev/null @@ -1,29 +0,0 @@ -import sys -data = file(sys.argv[1], 'rb').readlines() -if sys.argv[1].endswith('.txt'): - uid = sys.argv[1][:-4] - -def parity(x): - return ("{0:08b}".format(x).count('1') & 1) - -uid=raw_input("uid> ") -fp = file(uid+'_generated.bin','wb') -fp.write(uid.decode('hex')+"\x00"*2) -bits = 0 -pbits = 0 -for l in data: - if bits == 8: - fp.write(chr(pbits)) - bits = 0 - pbits = 0 - hexbytes = filter(None, l.strip().split(' ')) - bits += 4 - for x in hexbytes: - b = int(x.replace('!', ''), 16) - p = parity(b) - if '!' not in x: - p^=1 - pbits <<= 1 - pbits |= p - fp.write(chr(b)) -