Merge pull request #1 from RfidResearchGroup/master

Update
This commit is contained in:
Bjoern Kerler 2019-06-25 19:37:59 +02:00 committed by GitHub
commit f68dd76155
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
824 changed files with 203739 additions and 120203 deletions

12
.gitattributes vendored
View file

@ -1,6 +1,16 @@
# .gitattributes
# prevent binary files from CRLF handling, diff and merge:
fpga/fpga.bit -crlf -diff
*.bin -crlf -diff
*.z -crlf -diff
# Force LF
*.c text=auto eol=lf
*.cpp text=auto eol=lf
*.h text=auto eol=lf
*.lua text=auto eol=lf
*.py text=auto eol=lf
*.pl text=auto eol=lf
*.dic text=auto eol=lf
Makefile text=auto eol=lf

View file

@ -1,6 +1,9 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---

View file

@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: "[idea]"
labels: Request, enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

10
.gitignore vendored
View file

@ -2,6 +2,7 @@
# don't push these files to the repository
.history
.bash_history
*.log
*.eml
*.o
@ -19,6 +20,12 @@
*.exe
*.dsym
version.c
*.json
# new build file for add-ons.
Makefile.platform
# Cache for detecting platform def changes
.Makefile.options.cache
!client/hardnested/*.bin
!client/hardnested/tables/*.z
@ -32,6 +39,7 @@ luac
fpga_compress
mfkey32
mfkey64
tools/nonce2key/nonce2key
fpga/*
!fpga/tests
@ -57,6 +65,6 @@ ppls patches/*
*- Copy.*
client/lualibs/mf_default_keys.lua
client/lualibs/usb_cmd.lua
client/lualibs/pm3_cmd.lua
# recompiled
fpga_version_info.c

View file

@ -3,7 +3,199 @@ All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
## [unreleased][unreleased]
- Change: updates to README (@iceman)
- Change: hf mf/mfu dbg => hw dbg (@doegox)
- Change: replace usb_poll_validate_length() by data_available() that supports USART too (@doegox)
- Make sure standalone modes can be launched when connected on USB without client (@doegox)
- Change: cleaner makefile execution, use 'make V=1' if you want to see full lines (@doegox)
- Change: automate make clean when platform definitions are changed (@doegox)
- Add STANDALONE option to Makefile.hal (@Fl0-0)
- Change: mem info - production public key to verify rdv4.0 flash signature (@iceman)
- Fix specify that we need TCP and not UDP connection (@phcoder)
- Change: lf cotag demod - adjusted error trigger (@iceman)
- Add documentation on BT add-on (@iceman/@doegox)
- Change: new button behaviour in bootloader mode, no need to keep it pressed, press again to interrupt (@doegox)
- Change: new keys in dicts, new mem layout to accomodate them (@iceman/various)
- Fix lf sim - if called with empty graphbuffer all strange things happend, like turning on HF field (@iceman)
- Change: hf 14a sim / hf mf sim - check buttonpress/usb frame fewer times in order not to disrupt simulation (@McEloff)
- Change: data convertbitstream - converts bit to max/min in order to facilitate demodulation of simulation data (@iceman)
- Change: lf em 410x_demod - now can demod the simulation data (@iceman)
- Add HC-06 scripts for BT add-on (@doegox)
- Fix lf nedap sim - error when adding parity (@iceman)
- Add documentation on UART and baudrates (@doegox/@iceman)
- Change: prompt now shows which channel is used (@iceman)
- Change: USART baudrates computation, up to 6Mbps (@iceman/@doegox)
- Change: hf mf nack - keep sync if started without card over antenna
- Add usart btfactory - to reset a misconfigured BT add-on (@doegox)
- Change: hw status - now prints number of dictionary keys loaded (@iceman)
- Add home, end, pageup, and pagedown keybinds to the plot GUI. Also fix paged movement in GUI. (@mcd1992)
- Change legic.lua saves data in EML and BIN formats (@iceman)
- Change hf tune - is now synchronous (for BT add-on) and can be interrupted by kbd (@doegox)
- Change: update macOS install instruction (@ Uli Heilmeier)
- Add trace ouput in hexdump format for Wireshark import (@ Uli Heilmeier)
- Add usart btpin - to change BT add-on PIN (@doegox)
- Add reconnection support (@iceman/@doegox)
- Add usart tx/rx/... - USART developer commands (@doegox)
- Add PLATFORM_EXTRAS, WITH_FPC_USART_HOST, BTADDON Makefile configuration (@doegox)
- Fix slow reconfigure on mingw of serial port (@iceman)
- Fix cross thread communictions of timeout variable (@iceman)
- Change: client is now "universal", adapting to Proxmark3 capabilities (@doegox)
- Add disconnect support to Lua (@iceman)
- Change: handles FPC/FLASH FW more gracefully on non-RDV4 pm3 (@doegox)
- Add JTAG support for Shikra (@NinjaStyle82)
- Change: smart color handling: only if linux and on real term (@doegox)
- Change: reconfigure uart timeouts when compiled for FPC and connecting over USB (@iceman)
- Change: fast push for many commands (@iceman/@doegox)
- Add: fast push for Lua (@iceman)
- Add NDEF parser in Lua (@iceman)
- Change: improve NDEF parser (@iceman)
- Change: all commands got migrated to MIX/NG packet format (@iceman/@doegox)
- Fix: Mifare Ultralight read block missing bytes (@doegox)
- Add support new frame format in all Lua scripts (@iceman)
- Add CMD_CAPABILITIES for pm3 to inform dynamically the client (@doegox)
- Change baudrate handling, make it clear it's only indicative for USB-CDC & BT (@doegox)
- Change: new progressive light scheme for 'hw detectreader' (@doegox)
- Add common error definitions system for retvals (@doegox)
- Change USART RX & TX code and fix delays handling to make it more robust, especially over BT (@doegox)
- Add support for new frames format, speedup & huge changes, see doc/new_frame_format.txt (@doegox)
- Change: loadFile* & saveFile* accept filenames with (or still without) extension (@doegox)
- Fix LoadEML to accept final "\n", e.g. from pm3_mfd2eml.py (@doegox)
- Change: rework shell scripts for easy client or flasher (@doegox)
- Fix: stop poking Internet when compiling (@doegox)
- Add support for multiple commands to "-c", e.g. proxmark3 -c "hw ping;hw version" (@doegox)
- Fix external flash writing bitflips issues at 24MHz (@doegox)
- Add color support to Dbprintf & alike and rework Dbprintf flags (@doegox)
- Change: archive (and fix) hid-flasher (@doegox)
- Add standalone placeholder to simplify new standalone integration (@doegox)
- Change: refactor standalone mode info string (@iceman)
- Add iceman skeleton standalone mode for ppl to use as base for their new modes (@iceman)
- Change: move compilation options to Makefile.hal (@doegox)
- Fix compilation under OSX (@iceman)
- Add openocd config files for JLink (@doegox)
- Fix compilation dependencies for recovery (@doegox)
- Fix segfault when loading a file (@doegox)
- Change/Add new dump format for Ultralight/NTAG, counters support, simulation (@mceloff)
- Add 'hf mf sim' full-byte split anticollision support (@mceloff)
- Fix/Add 'hf mf sim' bugs fix, RATS support, etc (@mceloff)
- Fix serial of FPC. (@ryan)
- Fix 'data shiftgraphzero' corrupting end of GraphBuffer (@doegox)
- Fix 'hf legic info' - unsegmented card now uses card size to calc remaining length (@iceman)
- Add 36bit HID format, extend calcWiegand() to include oem bits ((@davidbeauchamp)
- Fix 'hf mf hardnested' - not verify key when reading nonce file (@iceman)
- Change optimizations for ask/bi (@iceman)
- Fix 'hf mf sim' - bugs fix, refactoring (@mceloff)
- Add WRITE and COMPATIBLE_WRITE support to Mifare Ultralight/NTAG simulation (@mceloff)
- Change installation instructions and add video links (@5w0rdfish)
- Change 'hf mf sim' to support more types (@vratiskol)
- Change better strong wave detection for biphase (@iceman)
- Add 'script run test_t55x7' (@iceman)
- Add new lua scripting support for some t55xx commands (@iceman)
- Add FPC USART for BT add-on with pm3 client. (@doegox)
- Add '-b baudrate' option to the pm3 client. (@doegox)
- Change 'lf t55xx info': tell if known configuration block0. (@iceman)
- Fix/Add FPC usart: fix TX, bring RX, full speed. (@doegox)
- Change 'lf t55xx config' options: allow to toggle on/off i/q5/st
- Change 'lf t55xx info': support offline block0, Q5, fix extended, add warns. (@doegox)
- Avoid race condition when flasher finds the not yet closed pm3 port. (@doegox)
- Fix 'lf t55xx trace': read the proper block. (@doegox)
- Fix Indala 64 on T55xx: use PSK1. (@doegox)
- Force proper Linefeed (LF) handling in ProxSpace. (@vratiskol)
- Fix Makefiles race conditions to allow parallel compilation, e.g. 'make -j8'. (@doegox)
- Add - dictionary key file for MFU. (not in use at the moment) (@mazodude)
- Change 'lf fdx demod - better biphase maxerrors. (@MalteHillmann)
- Change 'hf mf sim' - now works better against android (@mceloff)
- Fix 'lf t55xx brute' - now works after aquiredata adaptations (@iceman)
- Fix 'lf t55xx chk' - now works after aquiredata adaptations (@iceman)
- Fix 'lf t55xx recoverpwd' - now works after aquiredata adaptations (@iceman)
- Fix 'data detect p' - reverted bad clock detection (@iceman)
- Change 'data detect a' - better clock detection (@iceman)
- Add 'hf 14a info' - now detects some magic card Gen2 (@iceman)
- Removed 'LCD' code in armsrc compilation (@iceman)
- Change - Generic fixes of codestyle (@doegox) (@iceman)
- Change 'lf indala demod' - refactoring (@iceman)
- Change - handling fault bit markers (7) and partial nibbles in hex printing (@doegox)
- Change - printing of fault bit markers (7) using a dot (@doegox)
- Change 'sc upgrade' - firmware file integrity check (@piwi)
- Fix 'data rawdemod am' - last bit was missing (@doegox)
- Fix 'hf 15 dump f' - also selects tag first (@iceman)
- Fix 'hf iclass clone' - missing fileclose (@iceman)
- Add 'trace list hitag' - old hitag annotations now use the new trace (@iceman)
- Change 'lf hitag sim' - loads bin/eml/json (@iceman)
- Change 'lf hitag reader 21' - saves in bin/eml/json (@iceman)
- Change 'lf hitag' - refactoring (@iceman)
- Change 'lf hitag' - refactoring (@piwi)
- Fix 'lf hitag' - generic fix for missing clock init (@piwi)
- Fix fsk sim operations on deviceside - avoid division by zero (@doegox)
- Fix 'hf mf fchk' - condition always false (@doegox)
- Fix 'lf t55xx recoverpw' - shift as u32 (@doegox)
- Fix 'lf ti demod' - shift as u32 (@doegox)
- Fix 'lf ti read' - shift as u32 (@doegox)
- Fix 'lf t55xx chk' - condition always false (@doegox)
- Change 'lf sim' - ledcontrol refactoring (@doegox)
- Fix 'hf mf nack' - signedness bug (@doegox)
- Fix 'hf epa cnonce' - check return value (@doegox)
- Fix 'lf hitag write' - condition always true (@doegox)
- Fix 'mem write' - added extra check (@doegox)
- Fix 'iso15693' - bad string cpy (@doegox)
- Fix 'make style' - EOF LF support (@doegox)
- Add 'hf 14b raw' - added -t for timeout (@iceman)
- Rename 'lf hitag snoop' - renamed to 'lf hitag sniff' (@iceman)
- Rename 'lf snoop' - renamed to 'lf sniff' (@iceman)
- Rename 'hf snoop' - renamed to 'hf sniff' (@iceman)
- Fix 'hf mfp wrbl' - more blocks available (@merlokk)
- Add 'make platform' - compile for non-rdv4 devices made simpler (@doegox)
- Change Makefiles optimizations when recompiling (@doegox)
- Fix 'data load' - loads TITEST.txt again (@iceman)
- Change 'lf search' - now detects TI (@iceman)
- Change fixing signal cleaning for LF (@doegox)
- Fix 'lf paradox demod' - wrong check (@iceman)
- Change 'lf t55xx' - aquiredata uses getsamples (@iceman)
- Fix 'lf search' - chipset detection restore demod buffer again (@iceman)
- Add 'make style' (@doegox)
- Fix mixed tabs vs spaces. Now only use 4 space as tab. (@doegox)
- Fix 'lf visa2000 read' - too few samples (@iceman)
- Fix 'lf t55xx bruteforce' - infinity loop (@doegox)
- Fix 'analyse nuid' - correct crc (@doegox)
- Add command history not repeating logged commands (@doegox)
- Fix path for aidjson (@doegox)
- Fix missing init i2x (@doegox)
- Fix '14b select card' - (@doegox)
- Add 'hf mf ndef' - parsing of NDEF messages (@merlokk)
- Add 'hf mf mad' - parsing of Mifare Application Directory (@merlokk)
- Rename 'lf snoop' -> 'lf sniff' (@iceman)
- Rename 'hf snoop' -> 'hf sniff' (@iceman)
- Change generally added more colors (@iceman)
- Change 'sc upgrade' updated firmware v3.11 (RDV40) (@sentiprox)
- Change 'data autocorrelate' - better visual representation and added extra peak detection (@iceman)
- Fix 'lf search' - false positive indala identification fixed (@iceman)
- Add 'lf keri' - basic support for Keri tags (@iceman)
- Add 'hf mf list' - re-added it again (@iceman)
- Fix - A lot of bugfixes, like memory leaks (@iceman)
- Change 'hf 14a antifuzz' - original implementation (@asfabw), reworked a bit
- Fix 'hf mf fchk' (@iceman)
- Fix 'usb slow on posix based systems' (@fl0-0)
- Change 'lf pcf7931' - improved read code (@sguerrini97)
- Change 'hf felica list' - started with some FeliCa annotations (@iceman)
- Fix 'hf tune' - now works as expected (@iceman)
- Add 'option to use flash memory to upload dictionary files' (RDV40) (@iceman)
- Fix 'printing percentage now standard compliant' (@fabled)
- Add 'emv roca' - command to test for ROCA vuln in public RSA modulus (@merlokk / @iceman)
- Added TCP ports support (on linux) (@phcoder)
- Added HF sniff standalone mode with optional storing of ULC/NTAG/ULEV1 authentication attempts (@bogiton)
- Fix 'Lining up plot and control window' (@anticat)
- Fix 'annoying focus behaviour' on OSX (@Anticat)
- Implemented AppNap API, fixing #283 and #627 OSX USB comm issues (@AntiCat)
- Added 'sc brute' - a naive SFI bruteforcer for contact smartcards (RDV40) (@iceman)
- Change 'lf t55xx detectconfig' - now optional to persist settings to flashmem (RDV40) (@iceman)
- Change 'hf mf csave' - now saves both EML/BIN formats (@iceman)
- Change 'hf mf esave' - now saves both EML/BIN formats (@iceman)
- Fix 'compiler warning on macos and gcc7.1 or higher' (@TomHarkness)
- Fix 'crash on Bionic libc if CloseProxmark is called twice' (@micolous)
- Change 'lf hid' - got an updated to Kastle format (@xilni)
- Added 'lf t55xx deviceconfig' - enables custom t55xx timing settings. (RDV40) (@iceman)
- Chg adaptations for FPC communications (work in progress) (@iceman)
- Fix 'stand-alone Colin' - remake to benefit from flashmem for persistence. (@cjbrigato)
- Fix 'LEGIC SIM' - remake of legic sim (@drandreas)
- Changed 'proxmark3 client threading' - remake from official repo (@micolous)
- Add 'rem' - new command that adds a line to the log file (@didierStevens)
- Fix 'EM410xdemod empty tag id in lfops.c' (@Defensor7)
@ -65,6 +257,16 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Added to `hf 14a apdu` - apdu and tlv results parser (@merlokk)
- Added 'hf emv' commands (@merlokk)
- lots of bug fixes (many many)
- Changed hf mfp security. Now it works in all the modes. (drHatson)
- Added `hf fido` commands that work with FIDO U2F authenticators (@merlokk)
- Added mbedtls instead of old polarssl (@merlokk)
- Added jansson (@merlokk)
- Added `hf emv scan` - save card's data to json file (@merlokk)
- Added `hf emv` `gpo`, `readrec`, `genac`, `challenge`, `intauth` - separate commands from `hf emc exec` (@merlokk)
- Added `hf fido` `assert` and `make` commands from fido2 protocol (authenticatorMakeCredential and authenticatorGetAssertion) (@merlokk)
- Added trailer block decoding to `hf mf rdbl` and `hf mf cgetbl` (@merlokk)
- Added `hf mf mad` and `hf mfp mad` MAD decode, check and print commands (@merlokk)
### Fixed
- Changed driver file proxmark3.inf to support both old and new Product/Vendor IDs (piwi)
- Changed start sequence in Qt mode (fix: short commands hangs main Qt thread) (Merlok)

273
HACKING.md Normal file
View file

@ -0,0 +1,273 @@
_"Coding styles are like assholes, everyone has one and no one likes anyone elses."_
--Eric Warmenhoven
# Overview
The Proxmark3 codebase is pretty messy and in the process of being cleaned up,
so we don't have clear guidelines on how to place new code just yet. However,
please don't make things worse.
However, we have established a set of coding style guidelines in order to
clean up the code consistently and keep it consistent in the future.
Look around and respect the same style.
Helper script to get some uniformity in the style:
`$ make style`
It makes use of `astyle` so be sure to install it first.
# Indentation
Don't use tabs, editors are messing them up too easily.
Increment unit is four spaces.
If you use `make style`, this will be done for you.
# Width
Try to keep lines to a reasonable length. 80 characters is a good mark; using an
editor that shows a vertical line is a great idea. However, don't break a line
just because you're slightly over, it's not worth it. No 200-character lines,
though.
# Macros
`#define`, function-like or not, are all UPPERCASE unless you're emulating a
well-known function name.
# Identifiers
Functions, local variables, and arguments are all named using
`underscores_as_spaces`. Global variables are Evil and are prepended with `g_` to
distinguish them. Avoid them.
Single-character variables are a bad idea. Exceptions: loop iterators and maybe
simple byte pointers (`*p`) in very obvious places. If you have more than one
such pointer, use a real name. If you have more than a couple nested loops,
complex logic, or indices that differ in interpretation or purpose, use real
names instead of i,j,k.
# Data types
Use `stdint.h` types (`uint32_t` and friends) unless you have a reason not to. Don't
use microsoft-style `DWORD` and the like, we're getting rid of those. Avoid char
for buffers, `uint8_t` is more obvious when you're not working with strings. Use
`const` where things are const. Try to use `size_t` for sizes.
Pointers and reference operators are attached to the variable name:
```
void *ptr;
```
not:
```
void* ptr;
```
otherwise you're tempted to write:
```
void* in, out;
```
and you'll fail.
`make style` will take care of pointers & reference operators.
# Expressions
In general, use whitespace around binary operators - no unspaced blobs of an
expression. `make style` will take care of whitespaces around operators.
For example,
```
if (5 * a < b && some_bool_var)
```
but not
```
if (5*a<b&&some_bool_var)
```
For equality with constants, use `i == 0xF00`, not `0xF00 == i`. The compiler warns
you about `=` vs `==` anyway, and you shouldn't be screwing that one up by now
anyway.
# If / for / while etc
Put the opening brace on the same line, with a space before it.
There should be a space between the construct name (if/for/whatever) and the
opening parenthesis, and there should be a space between the closing parenthesis
and the opening brace, and no space between parenthesis and expression.
`make style` will take care of all that.
If you do split the condition, put the binary operators that join the lines at
the beginning of the following lines, not at the end of the prior lines.
For generic `for()` iterator variables, declare them in-line:
```
for (int i = 0; i < 10; i++) {
...
}
```
Note the spaces after the semicolons.
if/else should be laid out as follows:
```
if (foo) {
...
} else if (bar) {
...
} else {
...
}
```
You can skip braces around 1-line statements but don't mix braces vs. no braces.
# Functions
Put the return type on the same line.
Put a space after a comma in argument lists.
Open the brace after the declaration (after a space).
`make style` will take care of all that.
```
void foo(int a_thing, int something_else) {
...
}
```
Functions with no arguments are declared as `f(void)`, not `f()`.
Use static for functions that aren't exported, and put exported functions
in a header file (one header file per source file with exported functions
usually, no huge headers with all functions).
```
void baz(void) {
foo(bluh, blah);
}
```
Function names should be `separated_with_underscores()`, except for standard
functions (`memcpy`, etc.). It may make sense to break this rule for very common,
generic functions that look like library functions (e.g. `dprintf()`).
Don't use single-character arguments.
Exception: very short functions with one argument that's really obvious:
```
static int ascii(char c) {
if (c < 0x20 || c >= 0x7f)
return '.';
else
return c;
}
```
vs.
```
static void hexdump(void *buf, size_t len) {
...
}
```
As a general guideline, functions shouldn't usually be much more than 30-50
lines. Above, the general algorithm won't be easily apparent, and you're
probably missing some factoring/restructuring opportunity.
# Structs / unions / enums
Use typedefs when defining structs. The type should be named something_t.
```
typedef struct {
blah blah;
} prox_cmd_t;
```
You can use anonymous enums to replace lots of sequential or mostly-sequential
#defines.
# Switch
Indent once for the `case:` labels, then again for the body. Like this:
```
switch(bar) {
case OPTION_A:
do_stuff();
break;
case OPTION_B:
do_other_stuff();
break;
}
```
`make style` will take care of the indentation.
If you fall through into another case, add an explicit comment;
otherwise, it can look confusing.
If your `switch()` is too long or has too many cases, it should be cleaned up.
Split off the cases into functions, break the switch() into parent and children
switches (e.g. command and subcommand), or use an array of function pointers or
the like. In other words, use common sense and your brain.
If you need local scope variables for a case, you can add braces:
```
switch(bar) {
case OPTION_A: {
int baz = 5 * bar;
do_stuff(baz);
break;
}
...
```
But at that point you should probably consider using a separate function.
# Comments
Use //, it's shorter:
```
// this does foo
...
// baz:
// This does blah blah blah .....
// blah blah...
```
`/* */` can be used to comment blocks of code, but you should probably remove
them anyway - we have version control, it's easy to fetch old code if needed,
so avoid committing commented out chunks of code. The same goes for `#if 0`.
# File
Please use common sense and restrain yourself from having a thousands line
file. Functions in a file should have something *specific* in common. Over time
sub-categories can arise and should therefore yield to file splitting.
For these reasons, vague and general filenames (e.g. `util.*`, `global.*`, `misc.*`,
`main.*`, and the like) should be very limited, if not prohibited.
# File headers
License/description header first:
```
//-----------------------------------------------------------------------------
// YOUR COPYRIGHT LINE GOES HERE
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// FILE DESCRIPTION GOES HERE
//-----------------------------------------------------------------------------
```
If you modify a file in any non-trivial way (add code, etc.), add your copyright
to the top with the current year.
# Header files
Use the following include guard format:
```
#ifndef FOOBAR_H__
#define FOOBAR_H__
...
#endif // FOOBAR_H__
```
Keep in mind that `__FOOBAR_H` would be reserved by the implementation and thus
you shouldn't use it (same for `_FOOBAR_H`).
# Whitespace
Avoid trailing whitespace (no line should end in tab or space).
Keep a newline (blank line) at the end of each file.
`make style` will take care of both.

View file

@ -1,291 +0,0 @@
"Coding styles are like assholes, everyone has one and no one likes anyone elses."
--Eric Warmenhoven
The Proxmark3 codebase is pretty messy and in the process of being cleaned up,
so we don't have clear guidelines on how to place new code just yet. However,
please don't make things worse.
However, we have established a set of coding style guidelines in order to
clean up the code consistently and keep it consistent in the future. Use common
sense and good taste. If breaking a rule leads to cleaner code, you can do so,
but laziness is not an excuse.
=== INDENTATION ===
Use tabs for indentation, but use spaces for alignment:
if (foo(this, that, there)
&& bar == baz)
{
dostuff();
}
Notice it's like this (T___ for tab, S for space, for a 4-char tab setting):
T___if (foo(this, that, there)
T___SSSS&& bar == baz)
Another example:
#define THIS 0x10
#define THAT_THING 0x20
#define SOMETHING_ELSE 0x80
These should look good no matter what your editor's tab setting is, so go nuts
and pick whatever you like best.
=== WIDTH ===
Try to keep lines to a reasonable length. 80 characters is a good mark; using an
editor that shows a vertical line is a great idea. However, don't break a line
just because you're slightly over, it's not worth it. No 200-character lines,
though.
=== MACROS ===
#defines, function-like or not, are all UPPERCASE unless you're emulating a
well-known function name.
=== IDENTIFIERS ===
Functions, local variables, and arguments are all named using
underscores_as_spaces. Global variables are Evil and are prepended with g_ to
distinguish them. Avoid them.
Single-character variables are a bad idea. Exceptions: loop iterators and maybe
simple byte pointers (*p) in very obvious places. If you have more than one
such pointer, use a real name. If you have more than a couple nested loops,
complex logic, or indices that differ in interpretation or purpose, use real
names instead of i,j,k.
=== DATA TYPES ===
Use stdint.h types (uint32_t and friends) unless you have a reason not to. Don't
use microsoft-style DWORD and the like, we're getting rid of those. Avoid char
for buffers, uint8_t is more obvious when you're not working with strings. Use
'const' where things are const. Try to use size_t for sizes.
Pointers are:
void *ptr;
not:
void* ptr;
otherwise you're tempted to write:
void* in, out;
and you'll fail.
=== EXPRESSIONS ===
In general, use whitespace around binary operators - no unspaced blobs of an
expression. This rule may be broken if it makes things clearer. For example,
if (5*a < b && some_bool_var)
but not
if (5*a<b&&some_bool_var)
For equality with constants, use i == 0xF00, not 0xF00 == i. The compiler warns
you about = vs == anyway, and you shouldn't be screwing that one up by now
anyway.
=== IF / FOR / WHILE / etc. ===
Put the opening brace on the same line, with a space before it. Exception: if
the if/for/while condition/whatever are split over several lines, it might be
more appealing to put the opening brace on its own line, so use your own
judgement there:
if (foo(this, that, there)
&& bar == baz)
{
dostuff();
}
If you do split the condition, put the binary operators that join the lines at
the beginning of the following lines (as above), not at the end of the prior
lines.
There should be a space between the construct name (if/for/whatever) and the
opening parenthesis, and there should be a space between the closing parenthesis
and the opening brace.
For generic for() iterator variables, declare them in-line:
for (int i = 0; i < 10; i++) {
...
}
Note the spaces after the semicolons.
if/else should be laid out as follows:
if (foo) {
...
} else if (bar) {
...
} else {
...
}
or
if (foo)
...
else if (bar)
...
else
...
Don't mix braces vs. no braces. If any of your bodies are > 1 line, put braces
around them all.
=== FUNCTIONS ===
Functions with no arguments are declared as f(void), not f(). Put the return
type on the same line. Use static for functions that aren't exported, and put
exported functions in a header file (one header file per source file with
exported functions usually, no huge headers with all functions). Put a space
after a comma in argument lists.
void foo(int a_thing, int something_else)
{
...
}
void baz(void)
{
foo(bluh, blah);
}
Function names should be separated_with_underscores(), except for standard
functions (memcpy, etc.). It may make sense to break this rule for very common,
generic functions that look like library functions (e.g. dprintf()).
Don't use single-character arguments. Exception: very short functions with one
argument that's really obvious:
static int ascii(char c)
{
if (c < 0x20 || c >= 0x7f)
return '.';
else
return c;
}
vs.
static void hexdump(void *buf, size_t len)
{
...
}
As a general guideline, functions shouldn't usually be much more than 30-50
lines. Above, the general algorithm won't be easily apparent, and you're
probably missing some factoring/restructuring opportunity.
=== STRUCTS / UNIONS / ENUMS ===
Use typedefs when defining structs. The type should be named something_t.
typedef struct {
blah blah;
} prox_cmd_t;
You can use anonymous enums to replace lots of sequential or mostly-sequential
#defines.
=== SWITCH ===
Indent once for the case: labels, then again for the body. Like this:
switch(bar) {
case OPTION_A:
do_stuff();
break;
case OPTION_B:
do_other_stuff();
break;
}
If you fall through into another case, add an explicit comment; otherwise, it
can look confusing.
If your switch() is too long or has too many cases, it should be cleaned up.
Split off the cases into functions, break the switch() into parent and children
switches (e.g. command and subcommand), or use an array of function pointers or
the like. In other words, use common sense and your brain.
If you need local scope variables for a case, you can add braces:
switch(bar) {
case OPTION_A: {
int baz = 5*bar;
do_stuff(baz);
break;
}
...
But at that point you should probably consider using a separate function.
=== COMMENTS ===
Use //, it's shorter:
// this does foo
...
// baz:
// This does blah blah blah .....
// blah blah...
/* */ can be used to comment blocks of code, but you should probably remove
them anyway - we have version control, it's easy to fetch old code if needed,
so avoid committing commented out chunks of code. The same goes for #if 0.
=== FILE ===
Please use common sense and restrain yourself from having a thousands+++ line
file. Functions in a file should have something *specific* in common. Over time
sub-categories can arise and should therefore yield to file splitting.
For these reasons, vague and general filenames (e.g. util.*, global.*, misc.*,
main.*, and the like) should be very limited, if not prohibited.
=== FILE HEADERS ===
License/description header first:
//-----------------------------------------------------------------------------
// YOUR COPYRIGHT LINE GOES HERE
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// FILE DESCRIPTION GOES HERE
//-----------------------------------------------------------------------------
If you modify a file in any non-trivial way (add code, etc.), add your copyright
to the top.
=== HEADER FILES ===
Use the following include guard format:
#ifndef FOOBAR_H__
#define FOOBAR_H__
...
#endif // FOOBAR_H__
Keep in mind that __FOOBAR_H would be reserved by the implementation and thus
you shouldn't use it (same for _FOOBAR_H).
=== WHITESPACE ===
Avoid trailing whitespace (no line should end in tab or space). People forget
this all the time if their editor doesn't handle it, but don't be surprised if
you see someone fixing it from time to time.
Keep a newline (blank line) at the end of each file.

167
Makefile
View file

@ -1,60 +1,98 @@
# Hide full compilation line:
ifneq ($(V),1)
Q?=@
endif
# To see full command lines, use make V=1
GZIP=gzip
# Windows' echo echos its input verbatim, on Posix there is some
# amount of shell command line parsing going on. echo "" on
# amount of shell command line parsing going on. echo "" on
# Windows yields literal "", on Linux yields an empty line
ifeq ($(shell echo ""),)
# This is probably a proper system, so we can use uname
DELETE=rm -rf
FLASH_TOOL=client/flasher
platform=$(shell uname)
ifneq (,$(findstring MINGW,$(platform)))
FLASH_PORT=com3
PATHSEP=\\#
# This is probably a proper system, so we can use uname
DELETE=rm -rf
FLASH_TOOL=client/flasher
platform=$(shell uname)
ifneq (,$(findstring MINGW,$(platform)))
FLASH_PORT=com3
PATHSEP=\\#
else
FLASH_PORT=/dev/ttyACM0
PATHSEP=/
endif
else
FLASH_PORT=/dev/ttyACM0
PATHSEP=/
endif
else
# Assume that we are running on native Windows
DELETE=del /q
FLASH_TOOL=client/flasher.exe
platform=Windows
FLASH_PORT=com3
PATHSEP=\\#
# Assume that we are running on native Windows
DELETE=del /q
FLASH_TOOL=client/flasher.exe
platform=Windows
FLASH_PORT=com3
PATHSEP=\\#
endif
-include Makefile.platform
-include .Makefile.options.cache
include common/Makefile.hal
all clean: %: client/% bootrom/% armsrc/% recovery/% mfkey/% nonce2key/%
mfkey/%: FORCE
$(MAKE) -C tools/mfkey $(patsubst mfkey/%,%,$@)
$(info [*] MAKE $@)
$(Q)$(MAKE) --no-print-directory -C tools/mfkey $(patsubst mfkey/%,%,$@)
nonce2key/%: FORCE
$(MAKE) -C tools/nonce2key $(patsubst nonce2key/%,%,$@)
bootrom/%: FORCE
$(MAKE) -C bootrom $(patsubst bootrom/%,%,$@)
armsrc/%: FORCE
$(MAKE) -C armsrc $(patsubst armsrc/%,%,$@)
$(info [*] MAKE $@)
$(Q)$(MAKE) --no-print-directory -C tools/nonce2key $(patsubst nonce2key/%,%,$@)
bootrom/%: FORCE cleanifplatformchanged
$(info [*] MAKE $@)
$(Q)$(MAKE) --no-print-directory -C bootrom $(patsubst bootrom/%,%,$@)
armsrc/%: FORCE cleanifplatformchanged
$(info [*] MAKE $@)
$(Q)$(MAKE) --no-print-directory -C armsrc $(patsubst armsrc/%,%,$@)
client/%: FORCE
$(MAKE) -C client $(patsubst client/%,%,$@)
recovery/%: FORCE
$(MAKE) -C recovery $(patsubst recovery/%,%,$@)
$(info [*] MAKE $@)
$(Q)$(MAKE) --no-print-directory -C client $(patsubst client/%,%,$@)
recovery/%: FORCE cleanifplatformchanged bootrom/% armsrc/%
$(info [*] MAKE $@)
$(Q)$(MAKE) --no-print-directory -C recovery $(patsubst recovery/%,%,$@)
FORCE: # Dummy target to force remake in the subdirectories, even if files exist (this Makefile doesn't know about the prerequisites)
.PHONY: all clean help _test flash-bootrom flash-os flash-all FORCE
.PHONY: all clean help _test bootrom flash-bootrom os flash-os flash-all recovery client mfkey nounce2key style checks FORCE udev accessrights cleanifplatformchanged
help:
@echo Multi-OS Makefile, you are running on $(DETECTED_OS)
@echo Possible targets:
@echo + all - Make bootrom, armsrc and the OS-specific host directory
@echo + client - Make only the OS-specific host directory
@echo + flash-bootrom - Make bootrom and flash it
@echo + flash-os - Make armsrc and flash os \(includes fpga\)
@echo + flash-all - Make bootrom and armsrc and flash bootrom and os image
@echo + mfkey - Make tools/mfkey
@echo + nounce2key - Make tools/nounce2key
@echo + clean - Clean in bootrom, armsrc and the OS-specific host directory
@echo "Multi-OS Makefile"
@echo
@echo "Possible targets:"
@echo "+ all - Make all targets: bootrom, armsrc and OS-specific host tools"
@echo "+ clean - Clean in all targets"
@echo
@echo "+ bootrom - Make bootrom"
@echo "+ os - Make armsrc (includes fpga)"
@echo "+ flash-bootrom - Make bootrom and flash it"
@echo "+ flash-os - Make armsrc and flash os image (includes fpga)"
@echo "+ flash-all - Make bootrom and armsrc and flash bootrom and os image"
@echo "+ recovery - Make bootrom and armsrc images for JTAG flashing"
@echo
@echo "+ client - Make only the OS-specific host client"
@echo "+ mfkey - Make tools/mfkey"
@echo "+ nounce2key - Make tools/nounce2key"
@echo
@echo "+ style - Apply some automated source code formatting rules"
@echo "+ checks - Detect various encoding issues in source code"
@echo
@echo "Possible platforms: try \"make PLATFORM=\" for more info, default is PM3RDV4"
@echo "To activate verbose mode, use make V=1"
client: client/all
bootrom: bootrom/all
os: armsrc/all
recovery: recovery/all
mfkey: mfkey/all
nonce2key: nonce2key/all
flash-bootrom: bootrom/obj/bootrom.elf $(FLASH_TOOL)
$(FLASH_TOOL) $(FLASH_PORT) -b $(subst /,$(PATHSEP),$<)
@ -69,24 +107,59 @@ newtarbin:
@touch proxmark3-$(platform)-bin.tar
tarbin: newtarbin client/tarbin armsrc/tarbin bootrom/tarbin
$(GZIP) proxmark3-$(platform)-bin.tar
$(info GEN proxmark3-$(platform)-bin.tar)
$(Q)$(GZIP) proxmark3-$(platform)-bin.tar
# configure system
# - to ignore PM3 device as a modem (blacklist)
# - add user to the dialout group
# you may need to logout, relogin to get this access right correct.
# Finally, you might need to run the proxmark3 client under SUDO on some systems
# detect if there were changes in the platform definitions, requiring a clean
cleanifplatformchanged:
ifeq ($(PLATFORM_CHANGED), true)
$(info [!] Platform definitions changed, cleaning bootrom/armsrc/recovery first...)
$(Q)$(MAKE) --no-print-directory -C bootrom clean
$(Q)$(MAKE) --no-print-directory -C armsrc clean
$(Q)$(MAKE) --no-print-directory -C recovery clean
$(Q)echo CACHED_PLATFORM=$(PLATFORM) > .Makefile.options.cache
$(Q)echo CACHED_PLATFORM_EXTRAS=$(PLATFORM_EXTRAS) >> .Makefile.options.cache
$(Q)echo CACHED_PLATFORM_DEFS=$(PLATFORM_DEFS) >> .Makefile.options.cache
endif
# configure system to ignore PM3 device as a modem (ModemManager blacklist, effective *only* if ModemManager is not using _strict_ policy)
# Read doc/md/ModemManager-Must-Be-Discarded.md for more info
udev:
sudo cp -rf driver/77-pm3-usb-device-blacklist.rules /etc/udev/rules.d/77-pm3-usb-device-blacklist.rules
sudo udevadm control --reload-rules
# configure system to add user to the dialout group
# you need to logout, relogin to get this access right correct.
# Finally, you might need to run the proxmark3 client under SUDO on some systems
accessrights:
ifneq ($(wildcard /etc/arch-release),) #If user is running ArchLinux
sudo usermod -aG uucp $(USER) #Use specific command and group
else
sudo adduser $(USER) dialout
endif
# easy printing of MAKE VARIABLES
print-%: ; @echo $* = $($*)
print-%: ; @echo $* = $($*)
style:
# Make sure astyle is installed
@which astyle >/dev/null || ( echo "Please install 'astyle' package first" ; exit 1 )
# Remove spaces & tabs at EOL, add LF at EOF if needed on *.c, *.h, *.cpp. *.lua, *.py, *.pl, Makefile
find . \( -name "*.[ch]" -or -name "*.cpp" -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "Makefile" \) \
-exec perl -pi -e 's/[ \t]+$$//' {} \; \
-exec sh -c "tail -c1 {} | xxd -p | tail -1 | grep -q -v 0a$$" \; \
-exec sh -c "echo >> {}" \;
# Apply astyle on *.c, *.h, *.cpp
find . \( -name "*.[ch]" -or -name "*.cpp" \) -exec astyle --formatted --mode=c --suffix=none \
--indent=spaces=4 --indent-switches \
--keep-one-line-blocks --max-instatement-indent=60 \
--style=google --pad-oper --unpad-paren --pad-header \
--align-pointer=name {} \;
# Detecting weird codepages.
checks:
find . \( -name "*.[ch]" -or -name "*.cpp" -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "Makefile" \) \
-exec sh -c "cat {} |recode utf8.. >/dev/null || echo {}" \;
# Dummy target to test for GNU make availability
_test:

4
Makefile.platform.sample Normal file
View file

@ -0,0 +1,4 @@
# If you want to use it, copy this file as Makefile.platform and adjust it to your needs
PLATFORM=PM3RDV4
#PLATFORM_EXTRAS=BTADDON
#STANDALONE=LF_SAMYRUN

196
README.md
View file

@ -1,178 +1,76 @@
Proxmark3 RDV40 dedicated repo, based on iceman fork
===============
# Proxmark3 RDV4.0 Dedicated Github
This repo is based on iceman fork for Proxmark3. It is dedicated to bringing the most out of the new features for Proxmark3 RDV4.0 new hardware and design.
[![Build status](https://ci.appveyor.com/api/projects/status/ct5blik2wa96bv0x/branch/master?svg=true)](https://ci.appveyor.com/project/iceman1001/proxmark3-ji4wj/branch/master)
[![Latest release](https://img.shields.io/github/release/RfidResearchGroup/proxmark3.svg)](https://github.com/RfidResearchGroup/proxmark3/releases/latest)
## Notice
This repo is based on iceman fork for proxmark3. It is dedicated to bring the most out of the new features for proxmark3 RDV40 device.
---
## Coverity Scan Config & Run
Download the Coverity Scan Self-buld and install it.
You will need to configure ARM-NON-EABI- Compiler for it to use:
# PROXMARK INSTALLATION AND OVERVIEW
- Configure
| FAQ's & Updates | Installation | Use of the Proxmark |
| ------------------- |:-------------------:| -------------------:|
|[What has changed?](#what-has-changed) | [Setup and build for Linux](/doc/md/Installation_Instructions/Linux-Installation-Instructions.md) | [Compilation Instructions](/doc/md/Use_of_Proxmark/0_Compilation-Instructions.md)|
|[Development](#development) | [Important notes on ModemManager for Linux users](/doc/md/Installation_Instructions/ModemManager-Must-Be-Discarded.md) | [Validating proxmark client functionality](/doc/md/Use_of_Proxmark/1_Validation.md) |
|[Why didn't you base it on official PM3 Master?](#why-didnt-you-base-it-on-official-pm3-master)| [Homebrew (Mac OS X) & Upgrading HomeBrew Tap Formula](/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md) | [First Use and Verification](/doc/md/Use_of_Proxmark/2_Configuration-and-Verification.md)|
|[PM3 GUI](#pm3-gui)|[Setup and build for Windows](/doc/md/Installation_Instructions/Windows-Installation-Instructions.md)|[Commands & Features](/doc/md/Use_of_Proxmark/3_Commands-and-Features.md)|
|[Issues](#issues)|[Blue shark manual](/doc/bt_manual_v10.md) ||
|[Notes on UART](/doc/uart_notes.md)|||
|[Notes on Frame format](/doc/new_frame_format.md)|||
|[Developing standalone mode](/armsrc/Standalone/readme.md)|[Wiki about standalone mode](https://github.com/RfidResearchGroup/proxmark3/wiki/Standalone-mode) ||
|[Donations](#Donations)|||
`cov-configure --comptype gcc --compiler /opt/devkitpro/devkitARM/bin/arm-none-eabi-gcc`
## What has changed?
- Run it (I'm running on Ubuntu)
On the hardware side:
`cov-build --dir cov-int make all`
* added flash memory 256kb.
* added smart card module
* added FPC connector
- Make a tarball
`tar czvf proxmark3.tgz cov-int`
- Upload it to coverity.com
## Whats changed?
* added flash memory 256kb.
* added smart card module
* added FPC connector
---
## Why didn't you based it on offical PM3 Master?
The separation from offical pm3 repo gives us very much freedom to create a firmware/client that suits the RDV40 features. We don't want to mess up the offical pm3 repo with RDV40 specific code.
## Why don't you add this or that functionality?
Give us a hint, and we'll see if we can't merge in the stuff you have.
## PM3 GUI
The official PM3-GUI from Gaucho will not work.
The new universial GUI will work.
On the software side: quite a lot, see the [Changelog file](CHANGELOG.md).
## Development
This fork now compiles just fine on
- Windows/mingw environment with Qt5.6.1 & GCC 4.8
- Ubuntu 1404, 1510, 1604
- Ubuntu 1404, 1510, 1604, 1804, 1904
- Mac OS X / Homebrew
- ParrotOS
- WSL (Windows subsystem linux) on Windows 10
- Docker container
## Setup and build for UBUNTU
GC made updates to allow this to build easily on Ubuntu 14.04.2 LTS, 15.10 or 16.04
See https://github.com/Proxmark/proxmark3/wiki/Ubuntu%20Linux
If you intend to contribute to the code, please read the [coding style notes](HACKING.md) first.
A nice and cool install script made by @daveio is found here:
https://github.com/daveio/attacksurface/blob/master/proxmark3/pm3-setup.sh
I have also added this script to the fork.
https://github.com/RfidResearchGroup/proxmark3/blob/master/install.sh
- Run
`sudo apt-get install p7zip git build-essential libreadline5 libreadline-dev libusb-0.1-4 libusb-dev libqt4-dev perl pkg-config wget libncurses5-dev gcc-arm-none-eabi`
- Clone fork
`git clone https://github.com/RfidResearchGroup/proxmark3.git`
- Get the latest commits
`git pull`
- Install the blacklist rules and add user to dialout group (if you on a Linux/ubuntu/debian). If you do this one, you need to logout and login in again to make sure your rights got changed.
`make udev`
- Clean and complete compilation
`make clean && make all`
- Flash the BOOTROM & FULLIMAGE
`client/flasher /dev/ttyACM0 -b bootrom/obj/bootrom.elf armsrc/obj/fullimage.elf`
- Change into the client folder
`cd client`
- Run the client
`./proxmark3 /dev/ttyACM0`
## Setup and build for ArchLinux
- Run
`sudo pacman -Sy base-devel p7zip libusb readline ncurses arm-none-eabi-newlib --needed`
`yaourt -S termcap`
- Clone fork
`git clone https://github.com/RfidResearchGroup/proxmark3.git`
- Get the latest commits
`git pull`
- Install the blacklist rules and add user to dialout group (if you on a Linux/ubuntu/debian). If you do this one, you need to logout and login in again to make sure your rights got changed.
`make udev`
- Clean and complete compilation
`make clean && make all`
- Flash the BOOTROM & FULLIMAGE
`client/flasher /dev/ttyACM0 -b bootrom/obj/bootrom.elf armsrc/obj/fullimage.elf`
- Change into the client folder
`cd client`
- Run the client
`./proxmark3 /dev/ttyACM0`
## Homebrew (Mac OS X)
These instructions comes from @Chrisfu, where I got the proxmark3.rb scriptfile from.
Further questions about Mac & Homebrew, contact @Chrisfu (https://github.com/chrisfu/)
1. Install homebrew if you haven't yet already done so: http://brew.sh/
2. Tap this repo: `brew tap RfidResearchGroup/proxmark3`
3. Install Proxmark3: `brew install proxmark3` for stable release or `brew install --HEAD proxmark3` for latest non-stable from GitHub.
Upgrading HomeBrew tap formula
-----------------------------
*This method is useful for those looking to run bleeding-edge versions of iceman's client. Keep this in mind when attempting to update your HomeBrew tap formula as this procedure could easily cause a build to break if an update is unstable on macOS.*
Tested on macOS High Sierra 10.13.2
*Note: This assumes you have already installed iceman's fork from HomeBrew as mentioned above*
1. Force HomeBrew to pull the latest source from github
`brew upgrade --fetch-HEAD RfidResearchGroup/proxmark3`
2. Flash the bootloader & fullimage.elf
* With your Proxmark3 unplugged from your machine, press and hold the button on your Proxmark 3 as you plug it into a USB port. Continue to hold the button until after this step is complete and the `proxmark3-flasher` command outputs "Have a nice day!"*
`$ sudo proxmark3-flasher /dev/tty.usbmodem881 -b /usr/local/Cellar/proxmark3/HEAD-6a710ef/share/firmware/bootrom.elf /usr/local/Cellar/proxmark3/HEAD-6a710ef/share/firmware/fullimage.elf`
- Internal notes on [Coverity Scan Config & Run](/doc/md/Development/Coverity-Scan-Config-%26-Run.md).
- Internal notes on UART
- Internal notes on Frame format
- Internal notes on standalone mode
`$ sudo proxmark3-flasher /dev/tty.usbmodem881 `
4. Enjoy the update
## Why didn't you base it on official Proxmark3 Master?
The separation from official Proxmark3 repo gives us a lot of freedom to create a firmware/client that suits the RDV40 features. We don't want to mess up the official Proxmark3 repo with RDV40 specific code.
## Building on Windows
## Proxmark3 GUI
The official PM3-GUI from Gaucho will not work.
The new universal GUI will work. [Proxmark3 Universal GUI](https://github.com/burma69/PM3UniversalGUI) Almost, change needed in order to show helptext when client isn't connected to a device.
### Gator96100 distro
Rather than download and install every one of these packages, a new ProxSpace
environment archive file will be made available for download on the project
page at @Gator96100's repo
## Issues
Afterwards just clone the iceman repo or download someone elses.
Read instructions on @Gator96100 repo page. (https://github.com/Gator96100/ProxSpace/)
Please see the [Proxmark Forum](http://www.proxmark.org/forum/index.php) and see if your issue is listed in the first instance Google is your friend :) Questions will be answered via the forum by Iceman and the team.
Links
- https://github.com/Gator96100/ProxSpace/archive/master.zip
- https://github.com/Gator96100/ProxSpace/releases/tag/v2.2 (release v2.2 with gcc v5.3.0 arm-none-eabi-gcc v7.1.0)
It's needed to have a good USB cable to connect Proxmark3 to USB. If you have stability problems (Proxmark3 resets, firmware hangs, especially firmware hangs just after start, etc.) - check your cable with a USB tester (or try to change it). It needs to have a resistance smaller or equal to 0.3 Ohm.
## The end
### 7. Build and run
- [@herrmann1001](https://mobile.twitter.com/herrmann1001) July 2018
- updated Feb 2019 [@5w0rdfish](https://mobile.twitter.com/5w0rdFish)
- Clone fork
`git clone https://github.com/RfidResearchGroup/proxmark3.git`
# Donations
Nothing says thank you as much as a donation. So if you feel the love, do feel free to become a iceman patron. For some tiers it comes with rewards.
- Get the latest commits
`git pull`
https://www.patreon.com/iceman1001
- CLEAN COMPILE
`make clean && make all`
Assuming you have Proxmark3 Windows drivers installed you can run the Proxmark software where "X" is the com port number assigned to proxmark3 under Windows.
- Flash the BOOTROM & FULLIMAGE
`client/flasher.exe comX -b bootrom/obj/bootrom.elf armsrc/obj/fullimage.elf`
- Change into the client folder
`cd client`
- Run the client
`proxmark3.exe comX`
iceman at host iuse.se
July 2018, Sweden
All support is welcome!

View file

@ -66,9 +66,20 @@ clone_script:
Write-Host "[ OK ]" -ForegroundColor Green
Write-Host "Fill msys\etc\fstab file..." -NoNewLine
Write-Host "Fill msys2\etc\fstab file..." -NoNewLine
New-Item c:\ProxSpace\msys\etc\fstab -type file -force -value "#Win32_Path Mount_Point`nc:\ProxSpace\devkitARM /devkitARM`nc:\ProxSpace\Qt\5.6 /qt `nc:\ProxSpace\pm3 /pm3`n"
New-Item c:\ProxSpace\msys2\etc\fstab -type file -force -value "# For a description of the file format, see the Users Guide`n# http://cygwin.com/cygwin-ug-net/using.html#mount-table`nnone / cygdrive binary,posix=0,noacl,user 0 0 `nC:\ProxSpace\pm3 /pm3 ntfs noacl 0 0 `nC:\ProxSpace\gcc-arm-none-eabi /gcc-arm-none-eabi ntfs noacl 0 0 `n"
Write-Host "[ OK ]" -ForegroundColor Green
Write-Host "Update msys2 packages..." -NoNewLine
$env:Path = "C:\ProxSpace\msys2\usr\bin;C:\ProxSpace\msys2\mingw32\bin;C:\ProxSpace\gcc-arm-none-eabi\bin;$env:Path"
C:\ProxSpace\msys2\msys2_shell.cmd -mingw32 -defterm -no-start /dev/null 1> msys1.txt 2>&1
C:\ProxSpace\msys2\msys2_shell.cmd -mingw32 -defterm -no-start /dev/null 1> msys1.txt 2>&1
Write-Host "[ OK ]" -ForegroundColor Green
install:
@ -84,12 +95,25 @@ install:
}
build_script:
- ps: >-
$env:Path = "C:\ProxSpace\msys\bin;$env:Path"
"C:\ProxSpace\msys2\usr\bin;C:\ProxSpace\msys2\mingw32\bin;C:\ProxSpace\gcc-arm-none-eabi\bin;$env:Path"
$env:MINGW_HOME="C:\ProxSpace\msys2\mingw32"
$env:MSYS_HOME="C:\ProxSpace\msys2"
$env:MSYSTEM="MINGW32"
$env:MINGW_PREFIX="/mingw32"
$env:SHELL="/bin/bash"
$env:MSYSTEM_CHOST="i686-w64-mingw32"
#make
bash -lc -i "pwd;make all"
bash -c -i 'pwd;make clean;make all'
#some checks
@ -136,6 +160,24 @@ build_script:
Copy-Item C:\ProxSpace\pm3\client\hardnested\*.bin C:\ProxSpace\Release\hardnested
Copy-Item C:\ProxSpace\pm3\client\hardnested\tables\*.bin.z C:\ProxSpace\Release\hardnested\tables
# dll files
Copy-Item C:\ProxSpace\msys2\mingw32\bin\libgcc_s_dw2-1.dll C:\ProxSpace\Release
Copy-Item C:\ProxSpace\msys2\mingw32\bin\libstdc++-6.dll C:\ProxSpace\Release
Copy-Item C:\ProxSpace\msys2\mingw32\bin\libwinpthread-1.dll C:\ProxSpace\Release
Copy-Item C:\ProxSpace\msys2\mingw32\bin\Qt5Core.dll C:\ProxSpace\Release
Copy-Item C:\ProxSpace\msys2\mingw32\bin\Qt5Gui.dll C:\ProxSpace\Release
Copy-Item C:\ProxSpace\msys2\mingw32\bin\Qt5Widgets.dll C:\ProxSpace\Release
Copy-Item C:\ProxSpace\msys2\mingw32\bin\libreadline*.dll C:\ProxSpace\Release
Copy-Item C:\ProxSpace\msys2\mingw32\bin\libtermcap-0.dll C:\ProxSpace\Release
Write-Host "[ OK ]" -ForegroundColor Green
@ -232,8 +274,8 @@ test_script:
#--- end Job
[bool]$res=$false
# Wait 60 sec timeout for Job
if(Wait-Job $Job -Timeout 60){
# Wait 180 sec timeout for Job
if(Wait-Job $Job -Timeout 180){
$Results = $Job | Receive-Job
if($Results -like "true"){
$res=$true
@ -268,13 +310,22 @@ test_script:
#proxmark logic tests
ExecTest "proxmark help" "proxmark3 -h" {bash -lc 'cd ~/client;proxmark3 -h | grep -q Execute && echo Passed || echo Failed'}
ExecTest "proxmark help" "proxmark3 -h" {bash -lc 'cd ~/client;./proxmark3 -h | grep -q wait && echo Passed || echo Failed'}
ExecTest "proxmark help hardnested" "proxmark3 -h" {bash -lc 'cd ~/client;proxmark3 -h | grep -q hardnested && echo Passed || echo Failed'}
ExecTest "proxmark help text ISO7816" "proxmark3 -t" {bash -lc 'cd ~/client;./proxmark3 -t 2>&1 | grep -q ISO7816 && echo Passed || echo Failed'}
ExecTest "hf mf offline text" "hf mf" {bash -lc "cd ~/client;proxmark3 comx -c 'hf mf'"} "at_enc"
ExecTest "proxmark help text hardnested" "proxmark3 -t" {bash -lc 'cd ~/client;./proxmark3 -t 2>&1 | grep -q hardnested && echo Passed || echo Failed'}
ExecTest "hf mf offline text" "hf mf" {bash -lc "cd ~/client;./proxmark3 -c 'hf mf'"} "at_enc"
ExecTest "hf mf hardnested" "hf mf hardnested" {bash -lc "cd ~/client;./proxmark3 -c 'hf mf hardnested t 1 000000000000'"} "found:"
#proxmark crypto tests
ExecTest "emv test" "emv test" {bash -lc "cd ~/client;./proxmark3 -c 'emv test'"} "Test?s? ? OK"
ExecTest "hf mf hardnested" "hf mf hardnested" {bash -lc "cd ~/client;proxmark3 comx -c 'hf mf hardnested t 1 000000000000'"} "found:"
if ($global:TestsPassed) {
Write-Host "Tests [ OK ]" -ForegroundColor Green

View file

@ -13,14 +13,14 @@
// BigBuf is the large multi-purpose buffer, typically used to hold A/D samples or traces.
// Also used to hold various smaller buffers and the Mifare Emulator Memory.
// declare it as uint32_t to achieve alignment to 4 Byte boundary
static uint32_t BigBuf[BIGBUF_SIZE/sizeof(uint32_t)];
static uint32_t BigBuf[BIGBUF_SIZE / sizeof(uint32_t)];
/* BigBuf memory layout:
Pointer to highest available memory: BigBuf_hi
high BIGBUF_SIZE
reserved = BigBuf_malloc() subtracts amount from BigBuf_hi,
low 0x00
reserved = BigBuf_malloc() subtracts amount from BigBuf_hi,
low 0x00
*/
// High memory mark
@ -30,105 +30,105 @@ static uint16_t BigBuf_hi = BIGBUF_SIZE;
static uint8_t *emulator_memory = NULL;
// trace related variables
static uint16_t traceLen = 0;
int tracing = 1; //Last global one.. todo static?
static uint32_t traceLen = 0;
static bool tracing = true; //todo static?
// get the address of BigBuf
uint8_t *BigBuf_get_addr(void) {
return (uint8_t *)BigBuf;
return (uint8_t *)BigBuf;
}
// get the address of the emulator memory. Allocate part of Bigbuf for it, if not yet done
uint8_t *BigBuf_get_EM_addr(void) {
// not yet allocated
if (emulator_memory == NULL)
emulator_memory = BigBuf_malloc(CARD_MEMORY_SIZE);
return emulator_memory;
// not yet allocated
if (emulator_memory == NULL)
emulator_memory = BigBuf_malloc(CARD_MEMORY_SIZE);
return emulator_memory;
}
// clear ALL of BigBuf
void BigBuf_Clear(void) {
BigBuf_Clear_ext(true);
BigBuf_Clear_ext(true);
}
// clear ALL of BigBuf
void BigBuf_Clear_ext(bool verbose) {
memset(BigBuf, 0, BIGBUF_SIZE);
if (verbose)
Dbprintf("Buffer cleared (%i bytes)", BIGBUF_SIZE);
memset(BigBuf, 0, BIGBUF_SIZE);
if (verbose)
Dbprintf("Buffer cleared (%i bytes)", BIGBUF_SIZE);
}
void BigBuf_Clear_EM(void) {
memset(BigBuf_get_EM_addr(), 0, CARD_MEMORY_SIZE);
memset(BigBuf_get_EM_addr(), 0, CARD_MEMORY_SIZE);
}
void BigBuf_Clear_keep_EM(void) {
memset(BigBuf, 0, BigBuf_hi);
memset(BigBuf, 0, BigBuf_hi);
}
// allocate a chunk of memory from BigBuf. We allocate high memory first. The unallocated memory
// at the beginning of BigBuf is always for traces/samples
uint8_t *BigBuf_malloc(uint16_t chunksize) {
if (BigBuf_hi - chunksize < 0)
return NULL; // no memory left
if (BigBuf_hi - chunksize < 0)
return NULL; // no memory left
chunksize = (chunksize + 3) & 0xfffc; // round to next multiple of 4
BigBuf_hi -= chunksize; // aligned to 4 Byte boundary
return (uint8_t *)BigBuf + BigBuf_hi;
chunksize = (chunksize + 3) & 0xfffc; // round to next multiple of 4
BigBuf_hi -= chunksize; // aligned to 4 Byte boundary
return (uint8_t *)BigBuf + BigBuf_hi;
}
// free ALL allocated chunks. The whole BigBuf is available for traces or samples again.
void BigBuf_free(void){
BigBuf_hi = BIGBUF_SIZE;
emulator_memory = NULL;
// shouldn't this empty BigBuf also?
void BigBuf_free(void) {
BigBuf_hi = BIGBUF_SIZE;
emulator_memory = NULL;
// shouldn't this empty BigBuf also?
}
// free allocated chunks EXCEPT the emulator memory
void BigBuf_free_keep_EM(void) {
if (emulator_memory != NULL)
BigBuf_hi = emulator_memory - (uint8_t *)BigBuf;
else
BigBuf_hi = BIGBUF_SIZE;
// shouldn't this empty BigBuf also?
if (emulator_memory != NULL)
BigBuf_hi = emulator_memory - (uint8_t *)BigBuf;
else
BigBuf_hi = BIGBUF_SIZE;
// shouldn't this empty BigBuf also?
}
void BigBuf_print_status(void) {
Dbprintf("Memory");
Dbprintf(" BIGBUF_SIZE.............%d", BIGBUF_SIZE);
Dbprintf(" Available memory........%d", BigBuf_hi);
Dbprintf("Tracing");
Dbprintf(" tracing ................%d", tracing);
Dbprintf(" traceLen ...............%d", traceLen);
DbpString(_BLUE_("Memory"));
Dbprintf(" BIGBUF_SIZE.............%d", BIGBUF_SIZE);
Dbprintf(" Available memory........%d", BigBuf_hi);
DbpString(_BLUE_("Tracing"));
Dbprintf(" tracing ................%d", tracing);
Dbprintf(" traceLen ...............%d", traceLen);
}
// return the maximum trace length (i.e. the unallocated size of BigBuf)
uint16_t BigBuf_max_traceLen(void) {
return BigBuf_hi;
return BigBuf_hi;
}
void clear_trace(void) {
traceLen = 0;
traceLen = 0;
}
void set_tracelen(uint16_t value) {
void set_tracelen(uint32_t value) {
traceLen = value;
}
void set_tracing(bool enable) {
tracing = enable;
tracing = enable;
}
bool get_tracing(void) {
return tracing;
return tracing;
}
/**
* Get the number of bytes traced
* @return
*/
uint16_t BigBuf_get_traceLen(void) {
return traceLen;
uint32_t BigBuf_get_traceLen(void) {
return traceLen;
}
/**
@ -138,111 +138,70 @@ uint16_t BigBuf_get_traceLen(void) {
annotation of commands/responses.
**/
bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag) {
if (!tracing) return false;
if (!tracing) return false;
uint8_t *trace = BigBuf_get_addr();
uint8_t *trace = BigBuf_get_addr();
uint16_t num_paritybytes = (iLen-1)/8 + 1; // number of valid paritybytes in *parity
uint16_t duration = timestamp_end - timestamp_start;
uint32_t num_paritybytes = (iLen - 1) / 8 + 1; // number of valid paritybytes in *parity
uint32_t duration = timestamp_end - timestamp_start;
// Return when trace is full
if (traceLen + sizeof(iLen) + sizeof(timestamp_start) + sizeof(duration) + num_paritybytes + iLen >= BigBuf_max_traceLen()) {
tracing = false; // don't trace any more
return false;
}
// Traceformat:
// 32 bits timestamp (little endian)
// 16 bits duration (little endian)
// 16 bits data length (little endian, Highest Bit used as readerToTag flag)
// y Bytes data
// x Bytes parity (one byte per 8 bytes data)
// Return when trace is full
if (traceLen + sizeof(iLen) + sizeof(timestamp_start) + sizeof(duration) + num_paritybytes + iLen >= BigBuf_max_traceLen()) {
tracing = false; // don't trace any more
return false;
}
// Traceformat:
// 32 bits timestamp (little endian)
// 16 bits duration (little endian)
// 16 bits data length (little endian, Highest Bit used as readerToTag flag)
// y Bytes data
// x Bytes parity (one byte per 8 bytes data)
// timestamp (start)
trace[traceLen++] = ((timestamp_start >> 0) & 0xff);
trace[traceLen++] = ((timestamp_start >> 8) & 0xff);
trace[traceLen++] = ((timestamp_start >> 16) & 0xff);
trace[traceLen++] = ((timestamp_start >> 24) & 0xff);
// timestamp (start)
trace[traceLen++] = ((timestamp_start >> 0) & 0xff);
trace[traceLen++] = ((timestamp_start >> 8) & 0xff);
trace[traceLen++] = ((timestamp_start >> 16) & 0xff);
trace[traceLen++] = ((timestamp_start >> 24) & 0xff);
// duration
trace[traceLen++] = ((duration >> 0) & 0xff);
trace[traceLen++] = ((duration >> 8) & 0xff);
// duration
trace[traceLen++] = ((duration >> 0) & 0xff);
trace[traceLen++] = ((duration >> 8) & 0xff);
// data length
trace[traceLen++] = ((iLen >> 0) & 0xff);
trace[traceLen++] = ((iLen >> 8) & 0xff);
// data length
trace[traceLen++] = ((iLen >> 0) & 0xff);
trace[traceLen++] = ((iLen >> 8) & 0xff);
// readerToTag flag
if (!readerToTag) {
trace[traceLen - 1] |= 0x80;
}
// readerToTag flag
if (!readerToTag) {
trace[traceLen - 1] |= 0x80;
}
// data bytes
if (btBytes != NULL && iLen != 0) {
memcpy(trace + traceLen, btBytes, iLen);
}
traceLen += iLen;
// data bytes
if (btBytes != NULL && iLen != 0) {
memcpy(trace + traceLen, btBytes, iLen);
}
traceLen += iLen;
// parity bytes
if (num_paritybytes != 0) {
if (parity != NULL) {
memcpy(trace + traceLen, parity, num_paritybytes);
} else {
memset(trace + traceLen, 0x00, num_paritybytes);
}
}
traceLen += num_paritybytes;
// parity bytes
if (num_paritybytes != 0) {
if (parity != NULL) {
memcpy(trace + traceLen, parity, num_paritybytes);
} else {
memset(trace + traceLen, 0x00, num_paritybytes);
}
}
traceLen += num_paritybytes;
return true;
}
int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwParity, int readerToTag) {
/**
Todo, rewrite the logger to use the generic functionality instead. It should be noted, however,
that this logger takes number of bits as argument, not number of bytes.
**/
if (!tracing) return false;
uint8_t *trace = BigBuf_get_addr();
uint16_t iLen = nbytes(iBits);
// Return when trace is full
if (traceLen + sizeof(rsamples) + sizeof(dwParity) + sizeof(iBits) + iLen > BigBuf_max_traceLen()) return false;
//Hitag traces appear to use this traceformat:
// 32 bits timestamp (little endian,Highest Bit used as readerToTag flag)
// 32 bits parity
// 8 bits size (number of bits in the trace entry, not number of bytes)
// y Bytes data
rsamples += iSamples;
trace[traceLen++] = ((rsamples >> 0) & 0xff);
trace[traceLen++] = ((rsamples >> 8) & 0xff);
trace[traceLen++] = ((rsamples >> 16) & 0xff);
trace[traceLen++] = ((rsamples >> 24) & 0xff);
if (!readerToTag) {
trace[traceLen - 1] |= 0x80;
}
trace[traceLen++] = ((dwParity >> 0) & 0xff);
trace[traceLen++] = ((dwParity >> 8) & 0xff);
trace[traceLen++] = ((dwParity >> 16) & 0xff);
trace[traceLen++] = ((dwParity >> 24) & 0xff);
trace[traceLen++] = iBits;
memcpy(trace + traceLen, btBytes, iLen);
traceLen += iLen;
return true;
return true;
}
// Emulator memory
uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length){
uint8_t* mem = BigBuf_get_EM_addr();
if (offset + length < CARD_MEMORY_SIZE) {
memcpy(mem+offset, data, length);
return 0;
}
Dbprintf("Error, trying to set memory outside of bounds! %d > %d", (offset + length), CARD_MEMORY_SIZE);
return 1;
uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length) {
uint8_t *mem = BigBuf_get_EM_addr();
if (offset + length < CARD_MEMORY_SIZE) {
memcpy(mem + offset, data, length);
return 0;
}
Dbprintf("Error, trying to set memory outside of bounds! %d > %d", (offset + length), CARD_MEMORY_SIZE);
return 1;
}

View file

@ -17,31 +17,30 @@
#include "string.h"
#include "ticks.h"
#define BIGBUF_SIZE 40000
#define MAX_FRAME_SIZE 256 // maximum allowed ISO14443 frame
#define MAX_PARITY_SIZE ((MAX_FRAME_SIZE + 7) / 8)
#define MAX_MIFARE_FRAME_SIZE 18 // biggest Mifare frame is answer to a read (one block = 16 Bytes) + 2 Bytes CRC
#define MAX_MIFARE_PARITY_SIZE 3 // need 18 parity bits for the 18 Byte above. 3 Bytes are enough to store these
#define CARD_MEMORY_SIZE 4096
#define DMA_BUFFER_SIZE 256 //128 (how big is the dma?!?
#define BIGBUF_SIZE 40000
#define MAX_FRAME_SIZE 256 // maximum allowed ISO14443 frame
#define MAX_PARITY_SIZE ((MAX_FRAME_SIZE + 7) / 8)
#define MAX_MIFARE_FRAME_SIZE 18 // biggest Mifare frame is answer to a read (one block = 16 Bytes) + 2 Bytes CRC
#define MAX_MIFARE_PARITY_SIZE 3 // need 18 parity bits for the 18 Byte above. 3 Bytes are enough to store these
#define CARD_MEMORY_SIZE 4096
#define DMA_BUFFER_SIZE 256 //128 (how big is the dma?!?
extern uint8_t *BigBuf_get_addr(void);
extern uint8_t *BigBuf_get_EM_addr(void);
extern uint16_t BigBuf_max_traceLen(void);
extern void BigBuf_Clear(void);
extern void BigBuf_Clear_ext(bool verbose);
extern void BigBuf_Clear_keep_EM(void);
extern void BigBuf_Clear_EM(void);
extern uint8_t *BigBuf_malloc(uint16_t);
extern void BigBuf_free(void);
extern void BigBuf_free_keep_EM(void);
extern void BigBuf_print_status(void);
extern uint16_t BigBuf_get_traceLen(void);
extern void clear_trace(void);
extern void set_tracing(bool enable);
extern void set_tracelen(uint16_t value);
extern bool get_tracing(void);
extern bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag);
extern int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwParity, int bReader);
extern uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length);
uint8_t *BigBuf_get_addr(void);
uint8_t *BigBuf_get_EM_addr(void);
uint16_t BigBuf_max_traceLen(void);
void BigBuf_Clear(void);
void BigBuf_Clear_ext(bool verbose);
void BigBuf_Clear_keep_EM(void);
void BigBuf_Clear_EM(void);
uint8_t *BigBuf_malloc(uint16_t);
void BigBuf_free(void);
void BigBuf_free_keep_EM(void);
void BigBuf_print_status(void);
uint32_t BigBuf_get_traceLen(void);
void clear_trace(void);
void set_tracing(bool enable);
void set_tracelen(uint32_t value);
bool get_tracing(void);
bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag);
uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length);
#endif /* __BIGBUF_H */

View file

@ -7,143 +7,134 @@
//-----------------------------------------------------------------------------
#include "LCD.h"
void LCDSend(unsigned int data)
{
// 9th bit set for data, clear for command
while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0); // wait for the transfer to complete
// For clarity's sake we pass data with 9th bit clear and commands with 9th
// bit set since they're implemented as defines, se we need to invert bit
AT91C_BASE_SPI->SPI_TDR = data^0x100; // Send the data/command
void LCDSend(unsigned int data) {
// 9th bit set for data, clear for command
while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0); // wait for the transfer to complete
// For clarity's sake we pass data with 9th bit clear and commands with 9th
// bit set since they're implemented as defines, se we need to invert bit
AT91C_BASE_SPI->SPI_TDR = data ^ 0x100; // Send the data/command
}
void LCDSetXY(unsigned char x, unsigned char y)
{
LCDSend(PPASET); // page start/end ram
LCDSend(y); // Start Page to display to
LCDSend(131); // End Page to display to
void LCDSetXY(unsigned char x, unsigned char y) {
LCDSend(PPASET); // page start/end ram
LCDSend(y); // Start Page to display to
LCDSend(131); // End Page to display to
LCDSend(PCASET); // column start/end ram
LCDSend(x); // Start Column to display to
LCDSend(131); // End Column to display to
LCDSend(PCASET); // column start/end ram
LCDSend(x); // Start Column to display to
LCDSend(131); // End Column to display to
}
void LCDSetPixel(unsigned char x, unsigned char y, unsigned char color)
{
LCDSetXY(x,y); // Set position
LCDSend(PRAMWR); // Now write the pixel to the display
LCDSend(color); // Write the data in the specified Color
void LCDSetPixel(unsigned char x, unsigned char y, unsigned char color) {
LCDSetXY(x, y); // Set position
LCDSend(PRAMWR); // Now write the pixel to the display
LCDSend(color); // Write the data in the specified Color
}
void LCDFill (unsigned char xs,unsigned char ys,unsigned char width,unsigned char height, unsigned char color)
{
unsigned char i,j;
void LCDFill(unsigned char xs, unsigned char ys, unsigned char width, unsigned char height, unsigned char color) {
unsigned char i, j;
for (i=0;i < height;i++) // Number of horizontal lines
{
LCDSetXY(xs,ys+i); // Goto start of fill area (Top Left)
LCDSend(PRAMWR); // Write to display
for (i = 0; i < height; i++) { // Number of horizontal lines
LCDSetXY(xs, ys + i); // Goto start of fill area (Top Left)
LCDSend(PRAMWR); // Write to display
for (j=0;j < width;j++) // pixels per line
LCDSend(color);
for (j = 0; j < width; j++) // pixels per line
LCDSend(color);
}
}
void LCDString (char *lcd_string, const char *font_style,unsigned char x, unsigned char y, unsigned char fcolor, unsigned char bcolor)
{
unsigned int i;
unsigned char mask=0, px, py, xme, yme, offset;
const char *data;
void LCDString(char *lcd_string, const char *font_style, unsigned char x, unsigned char y, unsigned char fcolor, unsigned char bcolor) {
unsigned int i;
unsigned char mask = 0, px, py, xme, yme, offset;
const char *data;
data = font_style; // point to the start of the font table
data = font_style; // point to the start of the font table
xme = *data; // get font x width
data++;
yme = *data; // get font y length
data++;
offset = *data; // get data bytes per font
xme = *data; // get font x width
data++;
yme = *data; // get font y length
data++;
offset = *data; // get data bytes per font
do
{
// point to data in table to be loaded
data = (font_style + offset) + (offset * (int)(*lcd_string - 32));
do {
// point to data in table to be loaded
data = (font_style + offset) + (offset * (int)(*lcd_string - 32));
for (i=0;i < yme;i++) {
mask |=0x80;
for (i = 0; i < yme; i++) {
mask |= 0x80;
for (px=x; px < (x + xme); px++) {
py= y + i;
for (px = x; px < (x + xme); px++) {
py = y + i;
if (*data & mask) LCDSetPixel (px,py,fcolor);
else LCDSetPixel (px,py,bcolor);
if (*data & mask) LCDSetPixel(px, py, fcolor);
else LCDSetPixel(px, py, bcolor);
mask>>=1;
}
data++;
}
x+=xme;
mask >>= 1;
}
data++;
}
x += xme;
lcd_string++; // next character in string
lcd_string++; // next character in string
} while(*lcd_string !='\0'); // keep spitting chars out until end of string
} while (*lcd_string != '\0'); // keep spitting chars out until end of string
}
void LCDReset(void)
{
LED_A_ON();
SetupSpi(SPI_LCD_MODE);
LOW(GPIO_LRST);
SpinDelay(100);
void LCDReset(void) {
LED_A_ON();
SetupSpi(SPI_LCD_MODE);
LOW(GPIO_LRST);
SpinDelay(100);
HIGH(GPIO_LRST);
SpinDelay(100);
LED_A_OFF();
HIGH(GPIO_LRST);
SpinDelay(100);
LED_A_OFF();
}
void LCDInit(void)
{
int i;
void LCDInit(void) {
int i;
LCDReset();
LCDReset();
LCDSend(PSWRESET); // software reset
SpinDelay(100);
LCDSend(PSLEEPOUT); // exit sleep mode
LCDSend(PBSTRON); // booster on
LCDSend(PDISPON); // display on
LCDSend(PNORON); // normal on
LCDSend(PMADCTL); // rotate display 180 deg
LCDSend(0xC0);
LCDSend(PSWRESET); // software reset
SpinDelay(100);
LCDSend(PSLEEPOUT); // exit sleep mode
LCDSend(PBSTRON); // booster on
LCDSend(PDISPON); // display on
LCDSend(PNORON); // normal on
LCDSend(PMADCTL); // rotate display 180 deg
LCDSend(0xC0);
LCDSend(PCOLMOD); // color mode
LCDSend(0x02); // 8bpp color mode
LCDSend(PCOLMOD); // color mode
LCDSend(0x02); // 8bpp color mode
LCDSend(PSETCON); // set contrast
LCDSend(PSETCON); // set contrast
LCDSend(0xDC);
// clear display
LCDSetXY(0,0);
LCDSend(PRAMWR); // Write to display
i=LCD_XRES*LCD_YRES;
while(i--) LCDSend(WHITE);
// test text on different colored backgrounds
LCDString(" The quick brown fox ", (char *)&FONT6x8,1,1+8*0,WHITE ,BLACK );
LCDString(" jumped over the ", (char *)&FONT6x8,1,1+8*1,BLACK ,WHITE );
LCDString(" lazy dog. ", (char *)&FONT6x8,1,1+8*2,YELLOW ,RED );
LCDString(" AaBbCcDdEeFfGgHhIiJj ", (char *)&FONT6x8,1,1+8*3,RED ,GREEN );
LCDString(" KkLlMmNnOoPpQqRrSsTt ", (char *)&FONT6x8,1,1+8*4,MAGENTA,BLUE );
LCDString("UuVvWwXxYyZz0123456789", (char *)&FONT6x8,1,1+8*5,BLUE ,YELLOW);
LCDString("`-=[]_;',./~!@#$%^&*()", (char *)&FONT6x8,1,1+8*6,BLACK ,CYAN );
LCDString(" _+{}|:\\\"<>? ",(char *)&FONT6x8,1,1+8*7,BLUE ,MAGENTA);
// color bands
LCDFill(0, 1+8* 8, 132, 8, BLACK);
LCDFill(0, 1+8* 9, 132, 8, WHITE);
LCDFill(0, 1+8*10, 132, 8, RED);
LCDFill(0, 1+8*11, 132, 8, GREEN);
LCDFill(0, 1+8*12, 132, 8, BLUE);
LCDFill(0, 1+8*13, 132, 8, YELLOW);
LCDFill(0, 1+8*14, 132, 8, CYAN);
LCDFill(0, 1+8*15, 132, 8, MAGENTA);
// clear display
LCDSetXY(0, 0);
LCDSend(PRAMWR); // Write to display
i = LCD_XRES * LCD_YRES;
while (i--) LCDSend(WHITE);
// test text on different colored backgrounds
LCDString(" The quick brown fox ", (char *)&FONT6x8, 1, 1 + 8 * 0, WHITE, BLACK);
LCDString(" jumped over the ", (char *)&FONT6x8, 1, 1 + 8 * 1, BLACK, WHITE);
LCDString(" lazy dog. ", (char *)&FONT6x8, 1, 1 + 8 * 2, YELLOW, RED);
LCDString(" AaBbCcDdEeFfGgHhIiJj ", (char *)&FONT6x8, 1, 1 + 8 * 3, RED, GREEN);
LCDString(" KkLlMmNnOoPpQqRrSsTt ", (char *)&FONT6x8, 1, 1 + 8 * 4, MAGENTA, BLUE);
LCDString("UuVvWwXxYyZz0123456789", (char *)&FONT6x8, 1, 1 + 8 * 5, BLUE, YELLOW);
LCDString("`-=[]_;',./~!@#$%^&*()", (char *)&FONT6x8, 1, 1 + 8 * 6, BLACK, CYAN);
LCDString(" _+{}|:\\\"<>? ", (char *)&FONT6x8, 1, 1 + 8 * 7, BLUE, MAGENTA);
// color bands
LCDFill(0, 1 + 8 * 8, 132, 8, BLACK);
LCDFill(0, 1 + 8 * 9, 132, 8, WHITE);
LCDFill(0, 1 + 8 * 10, 132, 8, RED);
LCDFill(0, 1 + 8 * 11, 132, 8, GREEN);
LCDFill(0, 1 + 8 * 12, 132, 8, BLUE);
LCDFill(0, 1 + 8 * 13, 132, 8, YELLOW);
LCDFill(0, 1 + 8 * 14, 132, 8, CYAN);
LCDFill(0, 1 + 8 * 15, 132, 8, MAGENTA);
}

View file

@ -14,117 +14,117 @@
#include "fonts.h"
// The resolution of the LCD
#define LCD_XRES 132
#define LCD_YRES 132
#define LCD_XRES 132
#define LCD_YRES 132
// 8bpp Color Mode - Some basic colors defined for ease of use
// remember 8bpp color = 3xRed, 3xGreen & 2xBlue bits
// organised as RRRGGGBB
#define BLACK 0x00
#define BLUE 0x03
#define GREEN 0x1C
#define CYAN 0x1F
#define RED 0xE0
#define MAGENTA 0xE3
#define YELLOW 0xFC
#define WHITE 0xFF
#define BLACK 0x00
#define BLUE 0x03
#define GREEN 0x1C
#define CYAN 0x1F
#define RED 0xE0
#define MAGENTA 0xE3
#define YELLOW 0xFC
#define WHITE 0xFF
// EPSON LCD command set
#define ECASET 0x115
#define EPWRCTR 0x120
#define ENOP 0x125
#define ERAMWR 0x15C
#define ERAMRD 0x15D
#define EPASET 0x175
#define EEPSRRD1 0x17C
#define EEPSRRD2 0x17D
#define EVOLCTR 0x181
#define ETMPGRD 0x182
#define ESLPOUT 0x194
#define ESLPIN 0x195
#define EDISNOR 0x1A6
#define EDISINV 0x1A7
#define EPTLIN 0x1A8
#define EPTLOUT 0x1A9
#define EASCSET 0x1AA
#define ESCSTART 0x1AB
#define EDISOFF 0x1AE
#define EDISON 0x1AF
#define ECOMSCN 0x1BB
#define EDATCTL 0x1BC
#define EDISCTL 0x1CA
#define EEPCOUT 0x1CC
#define EEPCTIN 0x1CD
#define ERGBSET8 0x1CE
#define EOSCON 0x1D1
#define EOSCOFF 0x1D2
#define EVOLUP 0x1D6
#define EVOLDOWN 0x1D7
#define ERMWIN 0x1E0
#define ERMWOUT 0x1EE
#define EEPMWR 0x1FC
#define EEPMRD 0x1FD
#define ECASET 0x115
#define EPWRCTR 0x120
#define ENOP 0x125
#define ERAMWR 0x15C
#define ERAMRD 0x15D
#define EPASET 0x175
#define EEPSRRD1 0x17C
#define EEPSRRD2 0x17D
#define EVOLCTR 0x181
#define ETMPGRD 0x182
#define ESLPOUT 0x194
#define ESLPIN 0x195
#define EDISNOR 0x1A6
#define EDISINV 0x1A7
#define EPTLIN 0x1A8
#define EPTLOUT 0x1A9
#define EASCSET 0x1AA
#define ESCSTART 0x1AB
#define EDISOFF 0x1AE
#define EDISON 0x1AF
#define ECOMSCN 0x1BB
#define EDATCTL 0x1BC
#define EDISCTL 0x1CA
#define EEPCOUT 0x1CC
#define EEPCTIN 0x1CD
#define ERGBSET8 0x1CE
#define EOSCON 0x1D1
#define EOSCOFF 0x1D2
#define EVOLUP 0x1D6
#define EVOLDOWN 0x1D7
#define ERMWIN 0x1E0
#define ERMWOUT 0x1EE
#define EEPMWR 0x1FC
#define EEPMRD 0x1FD
// PHILIPS LCD command set
#define PNOP 0x100
#define PSWRESET 0x101
#define PBSTROFF 0x102
#define PBSTRON 0x103
#define PRDDIDIF 0x104
#define PRDDST 0x109
#define PSLEEPIN 0x110
#define PSLEEPOUT 0x111
#define PPTLON 0x112
#define PNORON 0x113
#define PINVOFF 0x120
#define PINVON 0x121
#define PDALO 0x122
#define PDAL 0x123
#define PSETCON 0x125
#define PDISPOFF 0x128
#define PDISPON 0x129
#define PCASET 0x12A
#define PPASET 0x12B
#define PRAMWR 0x12C
#define PRGBSET 0x12D
#define PPTLAR 0x130
#define PVSCRDEF 0x133
#define PTEOFF 0x134
#define PTEON 0x135
#define PMADCTL 0x136
#define PSEP 0x137
#define PIDMOFF 0x138
#define PIDMON 0x139
#define PCOLMOD 0x13A
#define PSETVOP 0x1B0
#define PBRS 0x1B4
#define PTRS 0x1B6
#define PFINV 0x1B9
#define PDOR 0x1BA
#define PTCDFE 0x1BD
#define PTCVOPE 0x1BF
#define PEC 0x1C0
#define PSETMUL 0x1C2
#define PTCVOPAB 0x1C3
#define PTCVOPCD 0x1C4
#define PTCDF 0x1C5
#define PDF8C 0x1C6
#define PSETBS 0x1C7
#define PRDTEMP 0x1C8
#define PNLI 0x1C9
#define PRDID1 0x1DA
#define PRDID2 0x1DB
#define PRDID3 0x1DC
#define PSFD 0x1EF
#define PECM 0x1F0
#define PNOP 0x100
#define PSWRESET 0x101
#define PBSTROFF 0x102
#define PBSTRON 0x103
#define PRDDIDIF 0x104
#define PRDDST 0x109
#define PSLEEPIN 0x110
#define PSLEEPOUT 0x111
#define PPTLON 0x112
#define PNORON 0x113
#define PINVOFF 0x120
#define PINVON 0x121
#define PDALO 0x122
#define PDAL 0x123
#define PSETCON 0x125
#define PDISPOFF 0x128
#define PDISPON 0x129
#define PCASET 0x12A
#define PPASET 0x12B
#define PRAMWR 0x12C
#define PRGBSET 0x12D
#define PPTLAR 0x130
#define PVSCRDEF 0x133
#define PTEOFF 0x134
#define PTEON 0x135
#define PMADCTL 0x136
#define PSEP 0x137
#define PIDMOFF 0x138
#define PIDMON 0x139
#define PCOLMOD 0x13A
#define PSETVOP 0x1B0
#define PBRS 0x1B4
#define PTRS 0x1B6
#define PFINV 0x1B9
#define PDOR 0x1BA
#define PTCDFE 0x1BD
#define PTCVOPE 0x1BF
#define PEC 0x1C0
#define PSETMUL 0x1C2
#define PTCVOPAB 0x1C3
#define PTCVOPCD 0x1C4
#define PTCDF 0x1C5
#define PDF8C 0x1C6
#define PSETBS 0x1C7
#define PRDTEMP 0x1C8
#define PNLI 0x1C9
#define PRDID1 0x1DA
#define PRDID2 0x1DB
#define PRDID3 0x1DC
#define PSFD 0x1EF
#define PECM 0x1F0
void LCDSend(unsigned int data);
void LCDInit(void);
void LCDReset(void);
void LCDSetXY(unsigned char x, unsigned char y);
void LCDSetPixel(unsigned char x, unsigned char y, unsigned char color);
void LCDString (char *lcd_string, const char *font_style,unsigned char x, unsigned char y, unsigned char fcolor, unsigned char bcolor);
void LCDFill (unsigned char xs,unsigned char ys,unsigned char width,unsigned char height, unsigned char color);
void LCDString(char *lcd_string, const char *font_style, unsigned char x, unsigned char y, unsigned char fcolor, unsigned char bcolor);
void LCDFill(unsigned char xs, unsigned char ys, unsigned char width, unsigned char height, unsigned char color);
#endif

View file

@ -1,4 +1,3 @@
#-----------------------------------------------------------------------------
# This code is licensed to you under the terms of the GNU GPL, version 2 or,
# at your option, any later version. See the LICENSE.txt file for the text of
# the license.
@ -8,103 +7,101 @@
APP_INCLUDES = apps.h
# This Makefile might have been called directly, not via the root Makefile, so:
ifeq ($(PLTNAME),)
-include ../Makefile.platform
-include ../.Makefile.options.cache
include ../common/Makefile.hal
# detect if there were changes in the platform definitions, requiring a clean
ifeq ($(PLATFORM_CHANGED), true)
$(error platform definitions have been changed, please "make clean" at the root of the project)
endif
endif
#remove one of the following defines and comment out the relevant line
#in the next section to remove that particular feature from compilation.
# NO space,TABs after the "\" sign.
APP_CFLAGS = -DWITH_CRC \
-DON_DEVICE \
-DWITH_LF \
-DWITH_HITAG \
-DWITH_ISO15693 \
-DWITH_LEGICRF \
-DWITH_ISO14443b \
-DWITH_ISO14443a \
-DWITH_ICLASS \
-DWITH_FELICA \
-DWITH_FLASH \
-DWITH_SMARTCARD \
-DWITH_HFSNOOP \
-DWITH_LF_SAMYRUN \
-DWITH_FPC \
-fno-strict-aliasing -ffunction-sections -fdata-sections
# NO space,TABs after the "\" sign.
APP_CFLAGS = $(PLATFORM_DEFS) \
-DON_DEVICE \
-fno-strict-aliasing -ffunction-sections -fdata-sections
### IMPORTANT - move the commented variable below this line
# -DWITH_LCD \
# -DWITH_EMV \
# -DWITH_FPC \
#
# Standalone Mods
#-------------------------------------------------------
# -DWITH_LF_ICERUN
# -DWITH_LF_SAMYRUN
# -DWITH_LF_PROXBRUTE
# -DWITH_LF_HIDBRUTE
# -DWITH_HF_YOUNG
# -DWITH_HF_MATTYRUN
# -DWITH_HF_COLIN
SRC_LCD = fonts.c LCD.c
SRC_LF = lfops.c hitag2.c hitagS.c lfsampling.c pcf7931.c lfdemod.c
SRC_LF = lfops.c lfsampling.c pcf7931.c lfdemod.c
SRC_ISO15693 = iso15693.c iso15693tools.c
#SRC_ISO14443a = iso14443a.c mifareutil.c mifarecmd.c epa.c mifaresim.c
SRC_ISO14443a = iso14443a.c mifareutil.c mifarecmd.c epa.c
SRC_ISO14443a = iso14443a.c mifareutil.c mifarecmd.c epa.c mifaresim.c
SRC_ISO14443b = iso14443b.c
SRC_FELICA = felica.c
SRC_CRAPTO1 = crypto1.c des.c aes.c desfire_key.c desfire_crypto.c mifaredesfire.c
SRC_CRC = crc.c crc16.c crc32.c
SRC_CRC = crc.c crc16.c crc32.c
SRC_ICLASS = iclass.c optimized_cipher.c
SRC_LEGIC = legicrf.c legic_prng.c
SRC_BEE = bee.c
SRC_LEGIC = legicrf.c legicrfsim.c legic_prng.c
# SRC_BEE = bee.c
# RDV40 related hardware support
ifneq (,$(findstring WITH_FLASH,$(APP_CFLAGS)))
SRC_FLASH = flashmem.c
SRC_FLASH = flashmem.c
else
SRC_FLASH =
SRC_FLASH =
endif
ifneq (,$(findstring WITH_SMARTCARD,$(APP_CFLAGS)))
SRC_SMARTCARD = i2c.c
SRC_SMARTCARD = i2c.c
else
SRC_SMARTCARD =
SRC_SMARTCARD =
endif
ifneq (,$(findstring WITH_FPC,$(APP_CFLAGS)))
SRC_FPC = usart.c
ifneq (,$(findstring WITH_FPC_USART,$(APP_CFLAGS)))
SRC_FPC = usart.c
else
SRC_FPC =
SRC_FPC =
endif
ifneq (,$(findstring WITH_HITAG,$(APP_CFLAGS)))
SRC_HITAG = hitag2_crypto.c hitag2.c hitagS.c
else
SRC_HITAG =
endif
ifneq (,$(findstring WITH_LCD,$(APP_CFLAGS)))
SRC_LCD = fonts.c LCD.c
else
SRC_LCD =
endif
# Generic standalone Mode injection of source code
SRC_STANDALONE =
# WITH_LF_ICERUN
ifneq (,$(findstring WITH_LF_ICERUN,$(APP_CFLAGS)))
SRC_STANDALONE =
SRC_STANDALONE = placeholder.c
# WITH_STANDALONE_LF_ICERUN
ifneq (,$(findstring WITH_STANDALONE_LF_ICERUN,$(APP_CFLAGS)))
SRC_STANDALONE = lf_icerun.c
endif
# WITH_LF_SAMYRUN
ifneq (,$(findstring WITH_LF_SAMYRUN,$(APP_CFLAGS)))
SRC_STANDALONE = lf_samyrun.c
# WITH_STANDALONE_LF_SAMYRUN
ifneq (,$(findstring WITH_STANDALONE_LF_SAMYRUN,$(APP_CFLAGS)))
SRC_STANDALONE = lf_samyrun.c
endif
# WITH_LF_PROXBRUTE
ifneq (,$(findstring WITH_LF_PROXBRUTE,$(APP_CFLAGS)))
SRC_STANDALONE = lf_proxbrute.c
# WITH_STANDALONE_LF_PROXBRUTE
ifneq (,$(findstring WITH_STANDALONE_LF_PROXBRUTE,$(APP_CFLAGS)))
SRC_STANDALONE = lf_proxbrute.c
endif
# WITH_LF_HIDBRUTE
ifneq (,$(findstring WITH_LF_HIDBRUTE,$(APP_CFLAGS)))
SRC_STANDALONE = lf_hidbrute.c
# WITH_STANDALONE_LF_HIDBRUTE
ifneq (,$(findstring WITH_STANDALONE_LF_HIDBRUTE,$(APP_CFLAGS)))
SRC_STANDALONE = lf_hidbrute.c
endif
# WITH_HF_YOUNG
ifneq (,$(findstring WITH_HF_YOUNG,$(APP_CFLAGS)))
SRC_STANDALONE = hf_young.c
# WITH_STANDALONE_HF_YOUNG
ifneq (,$(findstring WITH_STANDALONE_HF_YOUNG,$(APP_CFLAGS)))
SRC_STANDALONE = hf_young.c
endif
# WITH_HF_MATTYRUN
ifneq (,$(findstring WITH_HF_MATTYRUN,$(APP_CFLAGS)))
SRC_STANDALONE = hf_mattyrun.c
# WITH_STANDALONE_HF_MATTYRUN
ifneq (,$(findstring WITH_STANDALONE_HF_MATTYRUN,$(APP_CFLAGS)))
SRC_STANDALONE = hf_mattyrun.c
endif
# WITH_HF_COLIN
ifneq (,$(findstring WITH_HF_COLIN,$(APP_CFLAGS)))
SRC_STANDALONE = hf_colin.c vtsend.c
# WITH_STANDALONE_HF_COLIN
ifneq (,$(findstring WITH_STANDALONE_HF_COLIN,$(APP_CFLAGS)))
SRC_STANDALONE = vtsend.c hf_colin.c
endif
# WITH_STANDALONE_HF_BOG
ifneq (,$(findstring WITH_STANDALONE_HF_BOG,$(APP_CFLAGS)))
SRC_STANDALONE = hf_bog.c
endif
#the FPGA bitstream files. Note: order matters!
@ -118,109 +115,131 @@ APP_CFLAGS += $(ZLIB_CFLAGS)
# zlib includes:
APP_CFLAGS += -I../zlib
# stdint.h provided locally until GCC 4.5 becomes C99 compliant
APP_CFLAGS += -I.
# stdint.h provided locally until GCC 4.5 becomes C99 compliant,
# stack-protect , no-pie reduces size on Gentoo Hardened 8.2 gcc
APP_CFLAGS += -I. -fno-stack-protector -fno-pie
# Compile these in thumb mode (small size)
THUMBSRC = start.c \
protocols.c \
$(SRC_LCD) \
$(SRC_ISO15693) \
$(SRC_LF) \
$(SRC_ZLIB) \
$(SRC_LEGIC) \
$(SRC_FLASH) \
$(SRC_SMARTCARD) \
$(SRC_FPC) \
appmain.c \
printf.c \
util.c \
string.c \
BigBuf.c \
ticks.c \
random.c \
hfsnoop.c
protocols.c \
$(SRC_LCD) \
$(SRC_ISO15693) \
$(SRC_LF) \
$(SRC_ZLIB) \
$(SRC_LEGIC) \
$(SRC_FLASH) \
$(SRC_SMARTCARD) \
$(SRC_FPC) \
$(SRC_HITAG) \
appmain.c \
printf.c \
commonutil.c \
util.c \
string.c \
BigBuf.c \
ticks.c \
hfsnoop.c
# These are to be compiled in ARM mode
ARMSRC = fpgaloader.c \
$(SRC_ISO14443a) \
$(SRC_ISO14443b) \
$(SRC_CRAPTO1) \
$(SRC_ICLASS) \
$(SRC_EMV) \
$(SRC_CRC) \
$(SRC_FELICA) \
$(SRC_STANDALONE) \
parity.c \
usb_cdc.c \
cmd.c
$(SRC_ISO14443a) \
$(SRC_ISO14443b) \
$(SRC_CRAPTO1) \
$(SRC_ICLASS) \
$(SRC_EMV) \
$(SRC_CRC) \
$(SRC_FELICA) \
$(SRC_STANDALONE) \
parity.c \
usb_cdc.c \
cmd.c
VERSIONSRC = version.c \
fpga_version_info.c
fpga_version_info.c
# Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC
include ../common/Makefile.common
COMMON_FLAGS = -Os
COMMON_FLAGS = -Os
OBJS = $(OBJDIR)/fullimage.s19
OBJS = $(OBJDIR)/fullimage.s19
FPGA_COMPRESSOR = ../client/fpga_compress
all: $(OBJS)
.DELETE_ON_ERROR:
# version.c should be remade on every compilation
.PHONY: version.c
version.c: default_version.c
perl ../tools/mkversion.pl .. > $@ || $(COPY) $^ $@
# version.c should be remade on every time fullimage.stage1.elf should be remade
version.c: default_version.c $(OBJDIR)/fpga_version_info.o $(OBJDIR)/fpga_all.o $(THUMBOBJ) $(ARMOBJ)
$(info [-] GEN $@)
$(Q)perl ../tools/mkversion.pl .. > $@ || $(COPY) $^ $@
fpga_version_info.c: $(FPGA_BITSTREAMS) $(FPGA_COMPRESSOR)
$(FPGA_COMPRESSOR) -v $(filter %.bit,$^) $@
$(info [-] GEN $@)
$(Q)$(FPGA_COMPRESSOR) -v $(filter %.bit,$^) $@
$(OBJDIR)/fpga_all.o: $(OBJDIR)/fpga_all.bit.z
$(OBJCOPY) -O elf32-littlearm -I binary -B arm --prefix-sections=fpga_all_bit $^ $@
$(info [-] GEN $@)
$(Q)$(OBJCOPY) -O elf32-littlearm -I binary -B arm --prefix-sections=fpga_all_bit $^ $@
$(OBJDIR)/fpga_all.bit.z: $(FPGA_BITSTREAMS) $(FPGA_COMPRESSOR)
$(FPGA_COMPRESSOR) $(filter %.bit,$^) $@
$(info [-] GEN $@)
ifeq ($(Q),@)
@$(FPGA_COMPRESSOR) $(filter %.bit,$^) $@ >/dev/null
else
$(FPGA_COMPRESSOR) $(filter %.bit,$^) $@
endif
$(FPGA_COMPRESSOR):
make -C ../client $(notdir $(FPGA_COMPRESSOR))
$(info [*] MAKE $@)
$(Q)$(MAKE) --no-print-directory -C ../client $(notdir $(FPGA_COMPRESSOR))
$(OBJDIR)/fullimage.stage1.elf: $(VERSIONOBJ) $(OBJDIR)/fpga_all.o $(THUMBOBJ) $(ARMOBJ)
$(CC) $(LDFLAGS) -Wl,-T,ldscript,-Map,$(patsubst %.elf,%.map,$@) -o $@ $^ $(LIBS)
$(info [=] LD $@)
$(Q)$(CC) $(LDFLAGS) -Wl,-T,ldscript,-Map,$(patsubst %.elf,%.map,$@) -o $@ $^ $(LIBS)
$(OBJDIR)/fullimage.nodata.bin: $(OBJDIR)/fullimage.stage1.elf
$(OBJCOPY) -O binary -I elf32-littlearm --remove-section .data $^ $@
$(info [-] GEN $@)
$(Q)$(OBJCOPY) -O binary -I elf32-littlearm --remove-section .data $^ $@
$(OBJDIR)/fullimage.nodata.o: $(OBJDIR)/fullimage.nodata.bin
$(OBJCOPY) -O elf32-littlearm -I binary -B arm --rename-section .data=stage1_image $^ $@
$(info [-] GEN $@)
$(Q)$(OBJCOPY) -O elf32-littlearm -I binary -B arm --rename-section .data=stage1_image $^ $@
$(OBJDIR)/fullimage.data.bin: $(OBJDIR)/fullimage.stage1.elf
$(OBJCOPY) -O binary -I elf32-littlearm --only-section .data $^ $@
$(info [-] GEN $@)
$(Q)$(OBJCOPY) -O binary -I elf32-littlearm --only-section .data $^ $@
$(OBJDIR)/fullimage.data.bin.z: $(OBJDIR)/fullimage.data.bin $(FPGA_COMPRESSOR)
$(FPGA_COMPRESSOR) $(filter %.bin,$^) $@
$(info [-] GEN $@)
ifeq ($(Q),@)
@$(FPGA_COMPRESSOR) $(filter %.bin,$^) $@ >/dev/null
else
$(FPGA_COMPRESSOR) $(filter %.bin,$^) $@
endif
$(OBJDIR)/fullimage.data.o: $(OBJDIR)/fullimage.data.bin.z
$(OBJCOPY) -O elf32-littlearm -I binary -B arm --rename-section .data=compressed_data $^ $@
$(info [-] GEN $@)
$(Q)$(OBJCOPY) -O elf32-littlearm -I binary -B arm --rename-section .data=compressed_data $^ $@
$(OBJDIR)/fullimage.elf: $(OBJDIR)/fullimage.nodata.o $(OBJDIR)/fullimage.data.o
$(CC) $(LDFLAGS) -Wl,-T,ldscript,-e,_osimage_entry,-Map,$(patsubst %.elf,%.map,$@) -o $@ $^
$(info [=] LD $@)
$(Q)$(CC) $(LDFLAGS) -Wl,-T,ldscript,-e,_osimage_entry,-Map,$(patsubst %.elf,%.map,$@) -o $@ $^
tarbin: $(OBJS)
$(TAR) $(TARFLAGS) ../proxmark3-$(platform)-bin.tar $(OBJS:%=armsrc/%) $(OBJS:%.s19=armsrc/%.elf)
$(info TAR $@)
$(Q)$(TAR) $(TARFLAGS) ../proxmark3-$(platform)-bin.tar $(OBJS:%=armsrc/%) $(OBJS:%.s19=armsrc/%.elf)
clean:
$(DELETE) $(OBJDIR)$(PATHSEP)*.o
$(DELETE) $(OBJDIR)$(PATHSEP)*.elf
$(DELETE) $(OBJDIR)$(PATHSEP)*.s19
$(DELETE) $(OBJDIR)$(PATHSEP)*.map
$(DELETE) $(OBJDIR)$(PATHSEP)*.d
$(DELETE) $(OBJDIR)$(PATHSEP)*.z
$(DELETE) $(OBJDIR)$(PATHSEP)*.bin
$(DELETE) version.c
$(Q)$(DELETE) $(OBJDIR)$(PATHSEP)*.o
$(Q)$(DELETE) $(OBJDIR)$(PATHSEP)*.elf
$(Q)$(DELETE) $(OBJDIR)$(PATHSEP)*.s19
$(Q)$(DELETE) $(OBJDIR)$(PATHSEP)*.map
$(Q)$(DELETE) $(OBJDIR)$(PATHSEP)*.d
$(Q)$(DELETE) $(OBJDIR)$(PATHSEP)*.z
$(Q)$(DELETE) $(OBJDIR)$(PATHSEP)*.bin
$(Q)$(DELETE) version.c
.PHONY: all clean help
help:

303
armsrc/Standalone/hf_bog.c Normal file
View file

@ -0,0 +1,303 @@
//-----------------------------------------------------------------------------
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// main code for standalone HF Sniff (and ULC/NTAG/ULEV1 pwd storing)
//-----------------------------------------------------------------------------
/*
This can actually be used in two separate ways.
It can either be used to just HF 14a sniff on the go and/or grab the
authentication attempts for ULC/NTAG/ULEV1 into the flash mem (RDV4).
The retrieved sniffing session can be acquired by connecting the device
to a client that supports the reconnect capability and issue 'hf 14a list'.
In order to view the grabbed authentication attempts in the flash mem,
you can simply run 'script run read_pwd_mem' or just 'mem read l 256'
from the client to view the stored quadlets.
*/
#include "hf_bog.h"
#define DELAY_READER_AIR2ARM_AS_SNIFFER (2 + 3 + 8)
#define DELAY_TAG_AIR2ARM_AS_SNIFFER (3 + 14 + 8)
// Maximum number of auth attempts per standalone session
#define MAX_PWDS_PER_SESSION 64
uint8_t FindOffsetInFlash() {
uint8_t mem[4] = { 0x00, 0x00, 0x00, 0x00 };
uint8_t eom[4] = { 0xFF, 0xFF, 0xFF, 0xFF };
uint8_t memcnt = 0;
while (memcnt < 0xFF) {
Flash_ReadData(memcnt, mem, 4);
if (memcmp(mem, eom, 4) == 0) {
return memcnt;
}
memcnt += 4;
}
return 0; // wrap-around
}
void EraseMemory() {
if (!FlashInit()) {
return;
}
Flash_CheckBusy(BUSY_TIMEOUT);
Flash_WriteEnable();
Flash_Erase4k(0, 0);
if (DBGLEVEL > 1) Dbprintf("[!] Erased flash!");
FlashStop();
SpinDelay(100);
}
// This is actually copied from SniffIso14443a
void RAMFUNC SniffAndStore(uint8_t param) {
iso14443a_setup(FPGA_HF_ISO14443A_SNIFFER);
// Allocate memory from BigBuf for some buffers
// free all previous allocations first
BigBuf_free();
BigBuf_Clear_ext(false);
clear_trace();
set_tracing(true);
// Array to store the authpwds
uint8_t *capturedPwds = BigBuf_malloc(4 * MAX_PWDS_PER_SESSION);
// The command (reader -> tag) that we're receiving.
uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE);
uint8_t *receivedCmdPar = BigBuf_malloc(MAX_PARITY_SIZE);
// The response (tag -> reader) that we're receiving.
uint8_t *receivedResp = BigBuf_malloc(MAX_FRAME_SIZE);
uint8_t *receivedRespPar = BigBuf_malloc(MAX_PARITY_SIZE);
// The DMA buffer, used to stream samples from the FPGA
uint8_t *dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE);
uint8_t *data = dmaBuf;
uint8_t previous_data = 0;
int dataLen;
bool TagIsActive = false;
bool ReaderIsActive = false;
// Set up the demodulator for tag -> reader responses.
DemodInit(receivedResp, receivedRespPar);
// Set up the demodulator for the reader -> tag commands
UartInit(receivedCmd, receivedCmdPar);
// Setup and start DMA.
if (!FpgaSetupSscDma((uint8_t *) dmaBuf, DMA_BUFFER_SIZE)) {
if (DBGLEVEL > 1) Dbprintf("FpgaSetupSscDma failed. Exiting");
return;
}
tUart *uart = GetUart();
tDemod *demod = GetDemod();
// We won't start recording the frames that we acquire until we trigger;
// a good trigger condition to get started is probably when we see a
// response from the tag.
// triggered == false -- to wait first for card
bool triggered = !(param & 0x03);
uint32_t my_rsamples = 0;
// Current captured passwords counter
uint8_t auth_attempts = 0;
SpinDelay(50);
// loop and listen
while (!BUTTON_PRESS()) {
WDT_HIT();
LED_A_ON();
int register readBufDataP = data - dmaBuf;
int register dmaBufDataP = DMA_BUFFER_SIZE - AT91C_BASE_PDC_SSC->PDC_RCR;
if (readBufDataP <= dmaBufDataP)
dataLen = dmaBufDataP - readBufDataP;
else
dataLen = DMA_BUFFER_SIZE - readBufDataP + dmaBufDataP;
// test for length of buffer
if (dataLen > DMA_BUFFER_SIZE) { // TODO: Check if this works properly
Dbprintf("[!] blew circular buffer! | datalen %u", dataLen);
break;
}
if (dataLen < 1) continue;
// primary buffer was stopped( <-- we lost data!
if (!AT91C_BASE_PDC_SSC->PDC_RCR) {
AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t) dmaBuf;
AT91C_BASE_PDC_SSC->PDC_RCR = DMA_BUFFER_SIZE;
//Dbprintf("[-] RxEmpty ERROR | data length %d", dataLen); // temporary
}
// secondary buffer sets as primary, secondary buffer was stopped
if (!AT91C_BASE_PDC_SSC->PDC_RNCR) {
AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf;
AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE;
}
LED_A_OFF();
// Need two samples to feed Miller and Manchester-Decoder
if (my_rsamples & 0x01) {
if (!TagIsActive) { // no need to try decoding reader data if the tag is sending
uint8_t readerdata = (previous_data & 0xF0) | (*data >> 4);
if (MillerDecoding(readerdata, (my_rsamples - 1) * 4)) {
LED_C_ON();
// check - if there is a short 7bit request from reader
if ((!triggered) && (param & 0x02) && (uart->len == 1) && (uart->bitCount == 7)) triggered = true;
if (triggered) {
if ((receivedCmd) && ((receivedCmd[0] == MIFARE_ULEV1_AUTH) || (receivedCmd[0] == MIFARE_ULC_AUTH_1))) {
if (DBGLEVEL > 1) Dbprintf("PWD-AUTH KEY: 0x%02x%02x%02x%02x", receivedCmd[1], receivedCmd[2], receivedCmd[3], receivedCmd[4]);
// temporarily save the captured pwd in our array
memcpy(&capturedPwds[4 * auth_attempts], receivedCmd + 1, 4);
auth_attempts++;
}
if (!LogTrace(receivedCmd,
uart->len,
uart->startTime * 16 - DELAY_READER_AIR2ARM_AS_SNIFFER,
uart->endTime * 16 - DELAY_READER_AIR2ARM_AS_SNIFFER,
uart->parity,
true)) break;
}
/* ready to receive another command. */
UartReset();
/* reset the demod code, which might have been */
/* false-triggered by the commands from the reader. */
DemodReset();
LED_B_OFF();
}
ReaderIsActive = (uart->state != STATE_UNSYNCD);
}
// no need to try decoding tag data if the reader is sending - and we cannot afford the time
if (!ReaderIsActive) {
uint8_t tagdata = (previous_data << 4) | (*data & 0x0F);
if (ManchesterDecoding(tagdata, 0, (my_rsamples - 1) * 4)) {
LED_B_ON();
if (!LogTrace(receivedResp,
demod->len,
demod->startTime * 16 - DELAY_TAG_AIR2ARM_AS_SNIFFER,
demod->endTime * 16 - DELAY_TAG_AIR2ARM_AS_SNIFFER,
demod->parity,
false)) break;
if ((!triggered) && (param & 0x01)) triggered = true;
// ready to receive another response.
DemodReset();
// reset the Miller decoder including its (now outdated) input buffer
UartReset();
//UartInit(receivedCmd, receivedCmdPar);
LED_C_OFF();
}
TagIsActive = (demod->state != DEMOD_UNSYNCD);
}
}
previous_data = *data;
my_rsamples++;
data++;
if (data == dmaBuf + DMA_BUFFER_SIZE) {
data = dmaBuf;
}
} // end main loop
FpgaDisableSscDma();
set_tracing(false);
Dbprintf("Stopped sniffing");
SpinDelay(200);
// Write stuff to flash
if (auth_attempts > 0) {
if (DBGLEVEL > 1) Dbprintf("[!] Authentication attempts = %u", auth_attempts);
// Setting the SPI Baudrate to 48MHz to avoid the bit-flip issue (https://github.com/RfidResearchGroup/proxmark3/issues/34)
FlashmemSetSpiBaudrate(48000000);
// Find the offset in flash mem to continue writing the auth attempts
uint8_t memoffset = FindOffsetInFlash();
if (DBGLEVEL > 1) Dbprintf("[!] Memory offset = %u", memoffset);
if ((memoffset + 4 * auth_attempts) > 0xFF) {
// We opt to keep the new data only
memoffset = 0;
if (DBGLEVEL > 1) Dbprintf("[!] Size of total data > 256 bytes. Discarding the old data.");
}
// Get previous data from flash mem
uint8_t *previousdata = BigBuf_malloc(memoffset);
if (memoffset > 0) {
uint16_t readlen = Flash_ReadData(0, previousdata, memoffset);
if (DBGLEVEL > 1) Dbprintf("[!] Read %u bytes from flash mem", readlen);
}
// create new bigbuf to hold all data
size_t total_size = memoffset + 4 * auth_attempts;
uint8_t *total_data = BigBuf_malloc(total_size);
// Add the previousdata array into total_data array
memcpy(total_data, previousdata, memoffset);
// Copy bytes of capturedPwds immediately following bytes of previousdata
memcpy(total_data + memoffset, capturedPwds, 4 * auth_attempts);
// Erase first page of flash mem
EraseMemory();
// Write total data to flash mem
uint16_t writelen = Flash_WriteData(0, total_data, memoffset + 4 * auth_attempts);
if (DBGLEVEL > 1) Dbprintf("[!] Wrote %u bytes into flash mem", writelen);
// If pwd saved successfully, blink led A three times
if (writelen > 0) {
SpinErr(0, 200, 5); // blink led A
}
SpinDelay(100);
// Reset the SPI Baudrate to the default value (24MHz)
FlashmemSetSpiBaudrate(24000000);
}
}
void ModInfo(void) {
DbpString(" HF 14a sniff standalone with ULC/ULEV1/NTAG auth storing in flashmem - aka BogitoRun (Bogito)");
}
void RunMod() {
StandAloneMode();
Dbprintf(">> Bogiton 14a Sniff UL/UL-EV1/NTAG a.k.a BogitoRun Started <<");
Dbprintf("Starting to sniff");
// param:
// bit 0 - trigger from first card answer
// bit 1 - trigger from first reader 7-bit request
SniffAndStore(0);
LEDsoff();
SpinDelay(300);
Dbprintf("- [ End ] -> You can take shell back ...");
Dbprintf("- [ ! ] -> use 'script run read_pwd_mem' to print passwords");
}

View file

@ -0,0 +1,26 @@
//-----------------------------------------------------------------------------
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// StandAlone Mod
//-----------------------------------------------------------------------------
#ifndef __HF_BOG_H
#define __HF_BOG_H
#include "proxmark3.h"
#include "mifareutil.h"
#include "iso14443a.h"
#include "protocols.h"
#include "util.h"
#include "standalone.h" // standalone definitions
#include <stdbool.h> // for bool
#include <stdio.h>
#include <string.h>
#include "apps.h"
#include "printf.h"
#include "parity.h"
#endif /* __HF_BOG_H */

File diff suppressed because it is too large Load diff

View file

@ -16,39 +16,44 @@
#ifndef __HF_COLIN_H
#define __HF_COLIN_H
#include <stdbool.h> // for bool
#include <stdio.h>
#include <string.h>
#include "standalone.h" // standalone definitions
#include "proxmark3.h"
#include "mifaresim.h" // mifare1ksim
#include "mifareutil.h"
#include "iso14443a.h"
#include "protocols.h"
#include "util.h"
#include "standalone.h" // standalone definitions
#include <stdbool.h> // for bool
#include <stdio.h>
#include <string.h>
#include "vtsend.h"
#include "apps.h"
#include "usb_cmd.h" // mifare1ksim flags
#include "printf.h"
#define _RED_ "\x1b[31m"
#define _GREEN_ "\x1b[32m"
#define _YELLOW_ "\x1b[33m"
#define _BLUE_ "\x1b[34m"
#define _MAGENTA_ "\x1b[35m"
#define _CYAN_ "\x1b[36m"
#define _WHITE_ "\x1b[0m"
#define _ORANGE_ _YELLOW_
#define _XRED_ "\x1b[31m"
#define _XGREEN_ "\x1b[32m"
#define _XYELLOW_ "\x1b[33m"
#define _XBLUE_ "\x1b[34m"
#define _XMAGENTA_ "\x1b[35m"
#define _XCYAN_ "\x1b[36m"
#define _XWHITE_ "\x1b[0m"
#define _XORANGE_ _XYELLOW_
int cjat91_saMifareChkKeys(uint8_t blockNo, uint8_t keyType, bool clearTrace, uint8_t keyCount, uint8_t *datain, uint64_t *key);
void e_MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
int e_MifareECardLoad(uint32_t numofsectors, uint8_t keytype);
void saMifareMakeTag(void);
int saMifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void cjPrintBigArray(const char *bigar, int len, uint8_t newlines, uint8_t debug);
void WriteTagToFlash(uint8_t index, size_t size);
const char clearTerm[8] = {0x1b, 0x5b, 0x48, 0x1b, 0x5b, 0x32, 0x4a, '\0'};
#define LOGO logo_kigiv
//void cjPrintBigArray(const char *bigar, int len, uint8_t newlines, uint8_t debug);
//void TestFlashmemSpeed(size_t buffersize, uint32_t spibaudrate);
const char sub_banner[] = " From Vigik : \"20 years of (un)security without a single update\"";
//#define LOGO logo_kigiv
const char sub_banner[] = " From Vigik : \"20 years of (un)security without a single update\"";
/*
const char logo_kigiv[] = {
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35,
0x3b, 0x39, 0x35, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x31, 0x33, 0x37, 0x6d, 0x30, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x39, 0x35,
@ -409,8 +414,9 @@ const char logo_kigiv[] = {
0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x30, 0x1b, 0x5b, 0x33,
0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x31, 0x1b, 0x5b, 0x33, 0x38, 0x3b, 0x35, 0x3b, 0x35, 0x39, 0x6d, 0x31, 0x0d, 0x0a};
unsigned int logo_kigiv_len = 9303;
*/
const char logo_kigiv_nocolor[] = {
/*const char logo_kigiv_nocolor[] = {
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x30, 0x30, 0x30, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
@ -494,6 +500,6 @@ const char logo_kigiv_nocolor[] = {
0x30, 0x31, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x31, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x31, 0x31,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x31, 0x31, 0x30, 0x31, 0x31, 0x0d, 0x0a};
unsigned int logo_kigiv_nocolor_len = 2153;
unsigned int logo_kigiv_nocolor_len = 2153;*/
#endif /* __HF_COLIN_H */

View file

@ -13,7 +13,7 @@
I've personally recoded the image of the ARM in order to automate
the attack and simulation on Mifare cards. I've moved some of the
implementation on the client side to the ARM such as *chk*, *ecfill*, *sim*
and *clone* commands.
and *clone* commands.
### What it does now:
It will check if the keys from the attacked tag are a subset from
@ -35,265 +35,414 @@ on a blank card.
#include "hf_mattyrun.h"
uint8_t uid[10];
uint32_t cuid;
iso14a_card_select_t p_card;
//-----------------------------------------------------------------------------
// Matt's StandAlone mod.
// Work with "magic Chinese" card (email him: ouyangweidaxian@live.cn)
//-----------------------------------------------------------------------------
static int saMifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain) {
// params
uint8_t needWipe = arg0;
// bit 0 - need get UID
// bit 1 - need wupC
// bit 2 - need HALT after sequence
// bit 3 - need init FPGA and field before sequence
// bit 4 - need reset FPGA and LED
uint8_t workFlags = arg1;
uint8_t blockNo = arg2;
// card commands
uint8_t wupC1[] = {0x40};
uint8_t wupC2[] = {0x43};
uint8_t wipeC[] = {0x41};
// variables
uint8_t isOK = 0;
uint8_t d_block[18] = {0x00};
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
// reset FPGA and LED
if (workFlags & 0x08) {
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
set_tracing(false);
}
while (true) {
// get UID from chip
if (workFlags & 0x01) {
if (!iso14443a_select_card(uid, &p_card, &cuid, true, 0, true)) {
DbprintfEx(FLAG_NEWLINE, "Can't select card");
break;
};
if (mifare_classic_halt(NULL, cuid)) {
DbprintfEx(FLAG_NEWLINE, "Halt error");
break;
};
};
// reset chip
if (needWipe) {
ReaderTransmitBitsPar(wupC1, 7, 0, NULL);
if (!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
DbprintfEx(FLAG_NEWLINE, "wupC1 error");
break;
};
ReaderTransmit(wipeC, sizeof(wipeC), NULL);
if (!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
DbprintfEx(FLAG_NEWLINE, "wipeC error");
break;
};
if (mifare_classic_halt(NULL, cuid)) {
DbprintfEx(FLAG_NEWLINE, "Halt error");
break;
};
};
// chaud
// write block
if (workFlags & 0x02) {
ReaderTransmitBitsPar(wupC1, 7, 0, NULL);
if (!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
DbprintfEx(FLAG_NEWLINE, "wupC1 error");
break;
};
ReaderTransmit(wupC2, sizeof(wupC2), NULL);
if (!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
DbprintfEx(FLAG_NEWLINE, "wupC2 errorv");
break;
};
}
if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != 0x0a)) {
DbprintfEx(FLAG_NEWLINE, "write block send command error");
break;
};
memcpy(d_block, datain, 16);
AddCrc14A(d_block, 16);
ReaderTransmit(d_block, sizeof(d_block), NULL);
if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != 0x0a)) {
DbprintfEx(FLAG_NEWLINE, "write block send data error");
break;
};
if (workFlags & 0x04) {
if (mifare_classic_halt(NULL, cuid)) {
DbprintfEx(FLAG_NEWLINE, "Halt error");
break;
};
}
isOK = 1;
break;
}
if ((workFlags & 0x10) || (!isOK)) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
}
return isOK;
}
/* the chk function is a piwied(tm) check that will try all keys for
a particular sector. also no tracing no dbg */
static int saMifareChkKeys(uint8_t blockNo, uint8_t keyType, bool clearTrace, uint8_t keyCount, uint8_t *datain, uint64_t *key) {
DBGLEVEL = DBG_NONE;
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
set_tracing(false);
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
for (int i = 0; i < keyCount; ++i) {
/* no need for anticollision. just verify tag is still here */
// if (!iso14443a_fast_select_card(cjuid, 0)) {
if (!iso14443a_select_card(uid, &p_card, &cuid, true, 0, true)) {
DbprintfEx(FLAG_NEWLINE, "FATAL : E_MF_LOSTTAG");
return -1;
}
uint64_t ui64Key = bytes_to_num(datain + i * 6, 6);
if (mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {
uint8_t dummy_answer = 0;
ReaderTransmit(&dummy_answer, 1, NULL);
// wait for the card to become ready again
SpinDelayUs(AUTHENTICATION_TIMEOUT);
continue;
}
crypto1_destroy(pcs);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
*key = ui64Key;
return i;
}
crypto1_destroy(pcs);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
return -1;
}
void ModInfo(void) {
DbpString(" HF Mifare sniff/clone - aka MattyRun (Matías A. Ré Medina)");
}
void RunMod() {
StandAloneMode();
/*
It will check if the keys from the attacked tag are a subset from
the hardcoded set of keys inside of the ARM. If this is the case
then it will load the keys into the emulator memory and also the
content of the victim tag, to finally simulate it.
Alternatively, it can be dumped into a blank card.
This source code has been tested only in Mifare 1k.
If you're using the proxmark connected to a device that has an OS, and you're not using the proxmark3 client to see the debug
messages, you MUST uncomment usb_disable().
*/
StandAloneMode();
Dbprintf(">> Matty mifare chk/dump/sim a.k.a MattyRun Started <<");
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// usb_disable(); // Comment this line if you want to see debug messages.
/*
Pseudo-configuration block.
It will check if the keys from the attacked tag are a subset from
the hardcoded set of keys inside of the ARM. If this is the case
then it will load the keys into the emulator memory and also the
content of the victim tag, to finally simulate it.
Alternatively, it can be dumped into a blank card.
This source code has been tested only in Mifare 1k.
If you're using the proxmark connected to a device that has an OS, and you're not using the proxmark3 client to see the debug
messages, you MUST uncomment usb_disable().
*/
char keyTypec = '?'; // 'A'/'B' or both keys '?'
bool printKeys = false; // Prints keys
bool transferToEml = true; // Transfer keys to emulator memory
bool ecfill = true; // Fill emulator memory with cards content.
bool simulation = true; // Simulates an exact copy of the target tag
bool fillFromEmulator = false; // Dump emulator memory.
// Comment this line below if you want to see debug messages.
// usb_disable();
/*
Pseudo-configuration block.
*/
bool printKeys = false; // Prints keys
bool transferToEml = true; // Transfer keys to emulator memory
bool simulation = true; // Simulates an exact copy of the target tag
bool fillFromEmulator = false; // Dump emulator memory.
uint16_t mifare_size = 1024; // Mifare 1k (only 1k supported for now)
uint8_t sectorSize = 64; // 1k's sector size is 64 bytes.
uint8_t blockNo = 3; // Security block is number 3 for each sector.
uint8_t sectorsCnt = (mifare_size/sectorSize);
uint8_t keyType; // Keytype buffer
uint64_t key64; // Defines current key
uint8_t *keyBlock = NULL; // Where the keys will be held in memory.
uint8_t stKeyBlock = 20; // Set the quantity of keys in the block.
uint8_t filled = 0; // Used to check if the memory was filled with success.
bool keyFound = false;
uint16_t mifare_size = 1024; // Mifare 1k (only 1k supported for now)
uint8_t sectorSize = 64; // 1k's sector size is 64 bytes.
uint8_t blockNo = 3; // Security block is number 3 for each sector.
uint8_t sectorsCnt = (mifare_size / sectorSize);
uint8_t keyType = 2; // Keytype buffer
uint64_t key64; // Defines current key
uint8_t *keyBlock; // Where the keys will be held in memory.
uint8_t stKeyBlock = 20; // Set the quantity of keys in the block.
bool keyFound = false;
/*
Set of keys to be used.
*/
uint64_t mfKeys[] = {
0xffffffffffff, // Default key
0x000000000000, // Blank key
0xa0a1a2a3a4a5, // NFCForum MAD key
0xb0b1b2b3b4b5,
0xaabbccddeeff,
0x4d3a99c351dd,
0x1a982c7e459a,
0xd3f7d3f7d3f7,
0x714c5c886e97,
0x587ee5f9350f,
0xa0478cc39091,
0x533cb6c723f6,
0x8fd0a4f256e9,
};
/*
Set of keys to be used.
*/
uint64_t mfKeys[] = {
0xffffffffffff, // Default key
0x000000000000, // Blank key
0xa0a1a2a3a4a5, // NFCForum MAD key
0xb0b1b2b3b4b5,
0xaabbccddeeff,
0x4d3a99c351dd,
0x1a982c7e459a,
0xd3f7d3f7d3f7,
0x714c5c886e97,
0x587ee5f9350f,
0xa0478cc39091,
0x533cb6c723f6,
0x8fd0a4f256e9,
};
/*
This part allocates the byte representation of the
keys in keyBlock's memory space .
*/
keyBlock = BigBuf_malloc(stKeyBlock * 6);
int mfKeysCnt = sizeof(mfKeys) / sizeof(uint64_t);
/*
This part allocates the byte representation of the
keys in keyBlock's memory space .
*/
keyBlock = BigBuf_malloc(stKeyBlock * 6);
int mfKeysCnt = sizeof(mfKeys) / sizeof(uint64_t);
for (int mfKeyCounter = 0; mfKeyCounter < mfKeysCnt; mfKeyCounter++) {
num_to_bytes(mfKeys[mfKeyCounter], 6, (uint8_t*)(keyBlock + mfKeyCounter * 6));
}
for (int mfKeyCounter = 0; mfKeyCounter < mfKeysCnt; mfKeyCounter++) {
num_to_bytes(mfKeys[mfKeyCounter], 6, (uint8_t *)(keyBlock + mfKeyCounter * 6));
}
/*
Simple switch just to handle keytpes.
*/
switch (keyTypec) {
case 'a': case 'A':
keyType = !0;
break;
case 'b': case 'B':
keyType = !1;
break;
case '?':
keyType = 2;
break;
default:
Dbprintf("[!] Key type must be A , B or ?");
keyType = 2;
}
/*
Pretty print of the keys to be checked.
*/
if (printKeys) {
Dbprintf("[+] Printing mf keys");
for (uint8_t keycnt = 0; keycnt < mfKeysCnt; keycnt++)
Dbprintf("[-] chk mf key[%2d] %02x%02x%02x%02x%02x%02x", keycnt,
(keyBlock + 6 * keycnt)[0], (keyBlock + 6 * keycnt)[1], (keyBlock + 6 * keycnt)[2],
(keyBlock + 6 * keycnt)[3], (keyBlock + 6 * keycnt)[4], (keyBlock + 6 * keycnt)[5], 6);
DbpString("--------------------------------------------------------");
}
/*
Pretty print of the keys to be checked.
*/
if (printKeys) {
Dbprintf("[+] Printing mf keys");
for (uint8_t keycnt = 0; keycnt < mfKeysCnt; keycnt++)
Dbprintf("[-] chk mf key[%2d] %02x%02x%02x%02x%02x%02x", keycnt,
(keyBlock + 6*keycnt)[0],(keyBlock + 6*keycnt)[1], (keyBlock + 6*keycnt)[2],
(keyBlock + 6*keycnt)[3], (keyBlock + 6*keycnt)[4], (keyBlock + 6*keycnt)[5], 6);
DbpString("--------------------------------------------------------");
}
/*
Initialization of validKeys and foundKeys storages.
- validKey will store whether the sector has a valid A/B key.
- foundKey will store the found A/B key for each sector.
*/
bool validKey[2][40];
uint8_t foundKey[2][40][6];
for (uint16_t t = 0; t < 2; t++) {
for (uint16_t sectorNo = 0; sectorNo < sectorsCnt; sectorNo++) {
validKey[t][sectorNo] = false;
for (uint16_t i = 0; i < 6; i++) {
foundKey[t][sectorNo][i] = 0xff;
}
}
}
/*
Initialization of validKeys and foundKeys storages.
- validKey will store whether the sector has a valid A/B key.
- foundKey will store the found A/B key for each sector.
*/
bool validKey[2][40];
uint8_t foundKey[2][40][6];
for (uint16_t t = 0; t < 2; t++) {
for (uint16_t sectorNo = 0; sectorNo < sectorsCnt; sectorNo++) {
validKey[t][sectorNo] = false;
for (uint16_t i = 0; i < 6; i++) {
foundKey[t][sectorNo][i] = 0xff;
}
}
}
/*
Iterates through each sector checking if there is a correct key.
*/
bool err = 0;
bool allKeysFound = true;
uint32_t size = mfKeysCnt;
/*
Iterates through each sector checking if there is a correct key.
*/
int key = -1;
int block = 0;
bool err = 0;
bool allKeysFound = true;
uint32_t size = mfKeysCnt;
for (int type = !keyType; type < 2 && !err; keyType == 2 ? (type++) : (type = 2)) {
block = blockNo;
for (int sec = 0; sec < sectorsCnt && !err; ++sec) {
Dbprintf("\tCurrent sector:%3d, block:%3d, key type: %c, key count: %i ", sec, block, type ? 'B':'A', mfKeysCnt);
key = saMifareChkKeys(block, type, true, size, &keyBlock[0], &key64);
if (key == -1) {
LED(LED_RED, 50); //red
Dbprintf("\t✕ Key not found for this sector!");
allKeysFound = false;
// break;
} else if (key == -2) {
err = 1; // Can't select card.
break;
} else {
num_to_bytes(key64, 6, foundKey[type][sec]);
validKey[type][sec] = true;
keyFound = true;
Dbprintf("\t✓ Found valid key: [%02x%02x%02x%02x%02x%02x]\n",
(keyBlock + 6*key)[0], (keyBlock + 6*key)[1], (keyBlock + 6*key)[2],
(keyBlock + 6*key)[3], (keyBlock + 6*key)[4], (keyBlock + 6*key)[5]
);
}
block < 127 ? (block += 4) : (block += 16);
}
}
for (int type = !keyType; type < 2 && !err; keyType == 2 ? (type++) : (type = 2)) {
int block = blockNo;
for (int sec = 0; sec < sectorsCnt && !err; ++sec) {
Dbprintf("\tCurrent sector:%3d, block:%3d, key type: %c, key count: %i ", sec, block, type ? 'B' : 'A', mfKeysCnt);
int key = saMifareChkKeys(block, type, true, size, &keyBlock[0], &key64);
if (key == -1) {
LED(LED_RED, 50); //red
Dbprintf("\t✕ Key not found for this sector!");
allKeysFound = false;
// break;
} else if (key == -2) {
err = 1; // Can't select card.
break;
} else {
num_to_bytes(key64, 6, foundKey[type][sec]);
validKey[type][sec] = true;
keyFound = true;
Dbprintf("\t✓ Found valid key: [%02x%02x%02x%02x%02x%02x]\n",
(keyBlock + 6 * key)[0], (keyBlock + 6 * key)[1], (keyBlock + 6 * key)[2],
(keyBlock + 6 * key)[3], (keyBlock + 6 * key)[4], (keyBlock + 6 * key)[5]
);
}
/*
TODO: This.
block < 127 ? (block += 4) : (block += 16);
}
}
- If at least one key was found, start a nested attack based on that key, and continue.
- Get UID from tag and set accordingly in emulator memory and call mifare1ksim with right flags (iceman)
*/
if (!allKeysFound && keyFound) {
Dbprintf("\t✕ There's currently no nested attack in MattyRun, sorry!");
LED_C_ON(); //red
LED_A_ON(); //yellow
// Do nested attack, set allKeysFound = true;
// allKeysFound = true;
} else {
Dbprintf("\t✕ There's nothing I can do without at least a one valid key, sorry!");
LED_C_ON(); //red
}
/*
TODO:
- Get UID from tag and set accordingly in emulator memory and call mifaresim with right flags (iceman)
*/
if (!allKeysFound && keyFound) {
Dbprintf("\t✕ There's currently no nested attack in MattyRun, sorry!");
LED_C_ON(); //red
LED_A_ON(); //yellow
// no room to run nested attack on device (iceman)
// Do nested attack, set allKeysFound = true;
// allKeysFound = true;
} else {
Dbprintf("\t✕ There's nothing I can do without at least a one valid key, sorry!");
LED_C_ON(); //red
}
/*
If enabled, transfers found keys to memory and loads target content in emulator memory. Then it simulates to be the tag it has basically cloned.
*/
if ((transferToEml) && (allKeysFound)) {
emlClearMem();
uint8_t mblock[16];
for (uint16_t sectorNo = 0; sectorNo < sectorsCnt; sectorNo++) {
if (validKey[0][sectorNo] || validKey[1][sectorNo]) {
emlGetMem(mblock, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1); // data, block num, blocks count (max 4)
for (uint16_t t = 0; t < 2; t++) {
if (validKey[t][sectorNo]) {
memcpy(mblock + t*10, foundKey[t][sectorNo], 6);
}
}
emlSetMem(mblock, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1);
}
}
Dbprintf("\t✓ Found keys have been transferred to the emulator memory.");
if (ecfill) {
Dbprintf("\tFilling in with key A.");
MifareECardLoad(sectorsCnt, 0, 0, &filled);
if (filled != 1) {
Dbprintf("\t✕ Failed filling with A.");
}
Dbprintf("\tFilling in with key B.");
MifareECardLoad(sectorsCnt, 1, 0, &filled);
if (filled != 1) {
Dbprintf("\t✕ Failed filling with B.");
}
if ((filled == 1) && simulation) {
Dbprintf("\t✓ Filled, simulation started.");
// This will tell the fpga to emulate using previous keys and current target tag content.
Dbprintf("\t Press button to abort simulation at anytime.");
LED_B_ON(); // green
// assuming arg0==0, use hardcoded uid 0xdeadbeaf
Mifare1ksim( 0, 0, 0, NULL);
LED_B_OFF();
/*
If enabled, transfers found keys to memory and loads target content in emulator memory. Then it simulates to be the tag it has basically cloned.
*/
if ((transferToEml) && (allKeysFound)) {
/*
Needs further testing.
*/
if (fillFromEmulator) {
uint8_t retry = 5, cnt;
Dbprintf("\t Trying to dump into blank card.");
int flags = 0;
LED_A_ON(); //yellow
for (int blockNum = 0; blockNum < 16 * 4; blockNum += 1) {
cnt = 0;
emlGetMem(mblock, blockNum, 1);
// switch on field and send magic sequence
if (blockNum == 0) flags = 0x08 + 0x02;
emlClearMem();
// just write
if (blockNum == 1) flags = 0;
uint8_t mblock[16];
for (uint16_t sectorNo = 0; sectorNo < sectorsCnt; sectorNo++) {
if (validKey[0][sectorNo] || validKey[1][sectorNo]) {
emlGetMem(mblock, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1); // data, block num, blocks count (max 4)
for (uint16_t t = 0; t < 2; t++) {
if (validKey[t][sectorNo]) {
memcpy(mblock + t * 10, foundKey[t][sectorNo], 6);
}
}
emlSetMem(mblock, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1);
}
}
Dbprintf("\t✓ Found keys have been transferred to the emulator memory.");
if (ecfill) {
int filled;
Dbprintf("\tFilling in with key A.");
filled = MifareECardLoad(sectorsCnt, 0);
if (filled != PM3_SUCCESS) {
Dbprintf("\t✕ Failed filling with A.");
}
// Done. Magic Halt and switch off field.
if (blockNum == 16 * 4 - 1) flags = 0x04 + 0x10;
Dbprintf("\tFilling in with key B.");
filled = MifareECardLoad(sectorsCnt, 1);
if (filled != PM3_SUCCESS) {
Dbprintf("\t✕ Failed filling with B.");
}
while (!saMifareCSetBlock(0, flags & 0xFE, blockNum, mblock) && cnt <= retry) {
cnt++;
Dbprintf("\t! Could not write block. Retrying.");
}
if (cnt == retry) {
Dbprintf("\t✕ Retries failed. Aborting.");
break;
}
}
if ((filled == PM3_SUCCESS) && simulation) {
Dbprintf("\t✓ Emulator memory filled, simulation started.");
if (!err) {
LED_B_ON();
} else {
LED_C_ON();
}
// This will tell the fpga to emulate using previous keys and current target tag content.
Dbprintf("\t Press button to abort simulation at anytime.");
}
} else if (filled != 1) {
Dbprintf("\t✕ Memory could not be filled due to errors.");
LED_C_ON();
}
}
}
}
LED_B_ON(); // green
// assuming arg0==0, use hardcoded uid 0xdeadbeaf
uint16_t simflags;
switch (p_card.uidlen) {
case 10:
simflags = FLAG_10B_UID_IN_DATA;
break;
case 7:
simflags = FLAG_7B_UID_IN_DATA;
break;
default:
simflags = FLAG_4B_UID_IN_DATA;
break;
}
Mifare1ksim(simflags | FLAG_MF_1K, 0, uid);
LED_B_OFF();
/*
Needs further testing.
*/
if (fillFromEmulator) {
uint8_t retry = 5;
Dbprintf("\t Trying to dump into blank card.");
int flags = 0;
LED_A_ON(); //yellow
for (int blockNum = 0; blockNum < 16 * 4; blockNum += 1) {
uint8_t cnt = 0;
emlGetMem(mblock, blockNum, 1);
// switch on field and send magic sequence
if (blockNum == 0) flags = 0x08 + 0x02;
// just write
if (blockNum == 1) flags = 0;
// Done. Magic Halt and switch off field.
if (blockNum == 16 * 4 - 1) flags = 0x04 + 0x10;
while (!saMifareCSetBlock(0, flags & 0xFE, blockNum, mblock) && cnt <= retry) {
cnt++;
Dbprintf("\t! Could not write block. Retrying.");
}
if (cnt == retry) {
Dbprintf("\t✕ Retries failed. Aborting.");
break;
}
}
if (!err) {
LED_B_ON();
} else {
LED_C_ON();
}
}
} else if (filled != PM3_SUCCESS) {
Dbprintf("\t✕ Emulator memory could not be filled due to errors.");
LED_C_ON();
}
}
}
}

View file

@ -12,11 +12,12 @@
#ifndef __HF_MATTYRUN_H
#define __HF_MATTYRUN_H
//#include <stdbool.h> // for bool
#include "standalone.h" // standalone definitions
#include "apps.h" // debugstatements, lfops?
#include "usb_cmd.h" // mifare1ksim flags
#include "apps.h" // debugstatements, lfops?
#include "pm3_cmd.h" // mifare1ksim flags
#include "mifaresim.h" // mifare1ksim
#include "mifareutil.h"
#define OPTS 2
#endif /* __HF_MATTYRUN_H */
#endif /* __HF_MATTYRUN_H */

View file

@ -11,251 +11,255 @@
#include "hf_young.h"
typedef struct {
uint8_t uid[10];
uint8_t uidlen;
uint8_t atqa[2];
uint8_t sak;
uint8_t uid[10];
uint8_t uidlen;
uint8_t atqa[2];
uint8_t sak;
} __attribute__((__packed__)) card_clone_t;
void ModInfo(void) {
DbpString(" HF Mifare sniff/simulation - (Craig Young)");
}
void RunMod() {
StandAloneMode();
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
StandAloneMode();
Dbprintf(">> Craig Young Mifare sniff UID/clone uid 2 magic/sim a.k.a YoungRun Started <<");
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
int selected = 0, playing = 0, iGotoRecord = 0, iGotoClone = 0;
int cardRead[OPTS] = {0};
int selected = 0, playing = 0, iGotoRecord = 0, iGotoClone = 0;
int cardRead[OPTS] = {0};
card_clone_t uids[OPTS];
iso14a_card_select_t card[OPTS];
uint8_t params = (MAGIC_SINGLE | MAGIC_DATAIN);
LED(selected + 1, 0);
card_clone_t uids[OPTS];
iso14a_card_select_t card[OPTS];
uint8_t params = (MAGIC_SINGLE | MAGIC_DATAIN);
for (;;) {
WDT_HIT();
// exit from Standalone Mode, send a usbcommand.
if (usb_poll_validate_length()) return;
LED(selected + 1, 0);
SpinDelay(300);
for (;;) {
WDT_HIT();
// exit from Standalone Mode, send a usbcommand.
if (data_available()) return;
if (iGotoRecord == 1 || cardRead[selected] == 0) {
iGotoRecord = 0;
LEDsoff();
LED(selected + 1, 0);
LED(LED_RED2, 0);
SpinDelay(300);
// record
Dbprintf("Enabling iso14443a reader mode for [Bank: %d]...", selected);
/* need this delay to prevent catching some weird data */
SpinDelay(500);
iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
if (iGotoRecord == 1 || cardRead[selected] == 0) {
iGotoRecord = 0;
LEDsoff();
LED(selected + 1, 0);
LED(LED_D, 0);
for (;;) {
// exit from Standalone Mode, send a usbcommand.
if (usb_poll_validate_length()) return;
if (BUTTON_PRESS()) {
if (cardRead[selected]) {
Dbprintf("Button press detected -- replaying card in bank[%d]", selected);
break;
} else if (cardRead[(selected+1) % OPTS]) {
Dbprintf("Button press detected but no card in bank[%d] so playing from bank[%d]", selected, (selected+1)%OPTS);
selected = (selected+1) % OPTS;
break; // playing = 1;
} else {
Dbprintf("Button press detected but no stored tag to play. (Ignoring button)");
SpinDelay(300);
}
}
if (!iso14443a_select_card(NULL, &card[selected], NULL, true, 0, true)) {
continue;
} else {
Dbprintf("Read UID:");
Dbhexdump(card[selected].uidlen, card[selected].uid, 0);
if (memcmp(uids[(selected+1)%OPTS].uid, card[selected].uid, card[selected].uidlen ) == 0 ) {
Dbprintf("Card selected has same UID as what is stored in the other bank. Skipping.");
} else {
uids[selected].sak = card[selected].sak;
uids[selected].uidlen = card[selected].uidlen;
memcpy(uids[selected].uid , card[selected].uid, uids[selected].uidlen);
memcpy(uids[selected].atqa, card[selected].atqa, 2);
if (uids[selected].uidlen > 4)
Dbprintf("Bank[%d] received a 7-byte UID", selected);
else
Dbprintf("Bank[%d] received a 4-byte UID", selected);
break;
}
}
}
Dbprintf("ATQA = %02X%02X", uids[selected].atqa[0], uids[selected].atqa[1]);
Dbprintf("SAK = %02X", uids[selected].sak);
LEDsoff();
LED(LED_GREEN, 200);
LED(LED_ORANGE, 200);
LED(LED_GREEN, 200);
LED(LED_ORANGE, 200);
// record
Dbprintf("Enabling iso14443a reader mode for [Bank: %d]...", selected);
/* need this delay to prevent catching some weird data */
SpinDelay(500);
iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
LEDsoff();
LED(selected + 1, 0);
for (;;) {
// exit from Standalone Mode, send a usbcommand.
if (data_available()) return;
// Next state is replay:
playing = 1;
if (BUTTON_PRESS()) {
if (cardRead[selected]) {
Dbprintf("Button press detected -- replaying card in bank[%d]", selected);
break;
} else if (cardRead[(selected + 1) % OPTS]) {
Dbprintf("Button press detected but no card in bank[%d] so playing from bank[%d]", selected, (selected + 1) % OPTS);
selected = (selected + 1) % OPTS;
break; // playing = 1;
} else {
Dbprintf("Button press detected but no stored tag to play. (Ignoring button)");
SpinDelay(300);
}
}
cardRead[selected] = 1;
}
/* MF Classic UID clone */
else if (iGotoClone==1) {
iGotoClone=0;
LEDsoff();
LED(selected + 1, 0);
LED(LED_ORANGE, 250);
if (!iso14443a_select_card(NULL, &card[selected], NULL, true, 0, true)) {
continue;
} else {
Dbprintf("Read UID:");
Dbhexdump(card[selected].uidlen, card[selected].uid, 0);
// magiccards holds 4bytes uid. *usually*
uint32_t tmpuid = bytes_to_num(uids[selected].uid, 4);
// record
Dbprintf("Preparing to Clone card [Bank: %d]; uid: %08x", selected, tmpuid);
if (memcmp(uids[(selected + 1) % OPTS].uid, card[selected].uid, card[selected].uidlen) == 0) {
Dbprintf("Card selected has same UID as what is stored in the other bank. Skipping.");
} else {
uids[selected].sak = card[selected].sak;
uids[selected].uidlen = card[selected].uidlen;
memcpy(uids[selected].uid, card[selected].uid, uids[selected].uidlen);
memcpy(uids[selected].atqa, card[selected].atqa, 2);
// wait for button to be released
// Delay cloning until card is in place
while (BUTTON_PRESS())
WDT_HIT();
if (uids[selected].uidlen > 4)
Dbprintf("Bank[%d] received a 7-byte UID", selected);
else
Dbprintf("Bank[%d] received a 4-byte UID", selected);
break;
}
}
}
Dbprintf("Starting clone. [Bank: %d]", selected);
// need this delay to prevent catching some weird data
SpinDelay(500);
// Begin clone function here:
/* Example from client/mifarehost.c for commanding a block write for "magic Chinese" cards:
UsbCommand c = {CMD_MIFARE_CSETBLOCK, {params & (0xFE | (uid == NULL ? 0:1)), blockNo, 0}};
memcpy(c.d.asBytes, data, 16);
SendCommand(&c);
Dbprintf("ATQA = %02X%02X", uids[selected].atqa[0], uids[selected].atqa[1]);
Dbprintf("SAK = %02X", uids[selected].sak);
LEDsoff();
LED(LED_B, 200);
LED(LED_A, 200);
LED(LED_B, 200);
LED(LED_A, 200);
Block read is similar:
UsbCommand c = {CMD_MIFARE_CGETBLOCK, {params, blockNo, 0}};
We need to imitate that call with blockNo 0 to set a uid.
LEDsoff();
LED(selected + 1, 0);
The get and set commands are handled in this file:
// Work with "magic Chinese" card
case CMD_MIFARE_CSETBLOCK:
MifareCSetBlock(c->arg[0], c->arg[1], c->d.asBytes);
break;
case CMD_MIFARE_CGETBLOCK:
MifareCGetBlock(c->arg[0], c->arg[1], c->d.asBytes);
break;
// Next state is replay:
playing = 1;
mfCSetUID provides example logic for UID set workflow:
-Read block0 from card in field with MifareCGetBlock()
-Configure new values without replacing reserved bytes
memcpy(block0, uid, 4); // Copy UID bytes from byte array
// Mifare UID BCC
block0[4] = block0[0]^block0[1]^block0[2]^block0[3]; // BCC on byte 5
Bytes 5-7 are reserved SAK and ATQA for mifare classic
-Use mfCSetBlock(0, block0, oldUID, wantWipe, MAGIC_SINGLE) to write it
*/
uint8_t oldBlock0[16] = {0}, newBlock0[16] = {0}, testBlock0[16] = {0};
// arg0 = Flags, arg1=blockNo
MifareCGetBlock(params, 0, oldBlock0);
if (oldBlock0[0] == 0 && oldBlock0[0] == oldBlock0[1] && oldBlock0[1] == oldBlock0[2] && oldBlock0[2] == oldBlock0[3]) {
Dbprintf("No changeable tag detected. Returning to replay mode for bank[%d]", selected);
playing = 1;
} else {
Dbprintf("UID from target tag: %02X%02X%02X%02X", oldBlock0[0], oldBlock0[1], oldBlock0[2], oldBlock0[3]);
memcpy(newBlock0, oldBlock0, 16);
cardRead[selected] = 1;
}
// Copy uid for bank (2nd is for longer UIDs not supported if classic)
memcpy(newBlock0, uids[selected].uid, 4);
newBlock0[4] = newBlock0[0] ^ newBlock0[1] ^ newBlock0[2] ^ newBlock0[3];
/* MF Classic UID clone */
else if (iGotoClone == 1) {
iGotoClone = 0;
LEDsoff();
LED(selected + 1, 0);
LED(LED_A, 250);
// arg0 = workFlags, arg1 = blockNo, datain
MifareCSetBlock(params, 0, newBlock0);
MifareCGetBlock(params, 0, testBlock0);
if (memcmp(testBlock0, newBlock0, 16)==0) {
DbpString("Cloned successfull!");
cardRead[selected] = 0; // Only if the card was cloned successfully should we clear it
playing = 0;
iGotoRecord = 1;
selected = (selected + 1) % OPTS;
} else {
Dbprintf("Clone failed. Back to replay mode on bank[%d]", selected);
playing = 1;
}
}
LEDsoff();
LED(selected + 1, 0);
}
// Change where to record (or begin playing)
// button_pressed == BUTTON_SINGLE_CLICK && cardRead[selected])
else if (playing==1) {
LEDsoff();
LED(selected + 1, 0);
// magiccards holds 4bytes uid. *usually*
uint32_t tmpuid = bytes_to_num(uids[selected].uid, 4);
// Begin transmitting
LED(LED_GREEN, 0);
DbpString("Playing");
for ( ; ; ) {
// exit from Standalone Mode, send a usbcommand.
if (usb_poll_validate_length()) return;
int button_action = BUTTON_HELD(1000);
if ( button_action == 0) { // No button action, proceed with sim
// record
Dbprintf("Preparing to Clone card [Bank: %d]; uid: %08x", selected, tmpuid);
uint8_t flags = FLAG_4B_UID_IN_DATA;
uint8_t data[USB_CMD_DATA_SIZE] = {0}; // in case there is a read command received we shouldn't break
// wait for button to be released
// Delay cloning until card is in place
while (BUTTON_PRESS())
WDT_HIT();
memcpy(data, uids[selected].uid, uids[selected].uidlen);
uint64_t tmpuid = bytes_to_num(uids[selected].uid, uids[selected].uidlen);
if ( uids[selected].uidlen == 7 ) {
flags = FLAG_7B_UID_IN_DATA;
Dbprintf("Simulating ISO14443a tag with uid: %014" PRIx64 " [Bank: %d]", tmpuid, selected);
} else {
Dbprintf("Simulating ISO14443a tag with uid: %08" PRIx64 " [Bank: %d]", tmpuid, selected);
}
if (uids[selected].sak == 0x08 && uids[selected].atqa[0] == 0x04 && uids[selected].atqa[1] == 0) {
DbpString("Mifare Classic 1k");
SimulateIso14443aTag(1, flags, data);
} else if (uids[selected].sak == 0x18 && uids[selected].atqa[0] == 0x02 && uids[selected].atqa[1] == 0) {
DbpString("Mifare Classic 4k (4b uid)");
SimulateIso14443aTag(8, flags, data);
} else if (uids[selected].sak == 0x08 && uids[selected].atqa[0] == 0x44 && uids[selected].atqa[1] == 0) {
DbpString("Mifare Classic 4k (7b uid)");
SimulateIso14443aTag(8, flags, data);
} else if (uids[selected].sak == 0x00 && uids[selected].atqa[0] == 0x44 && uids[selected].atqa[1] == 0) {
DbpString("Mifare Ultralight");
SimulateIso14443aTag(2, flags, data);
} else if (uids[selected].sak == 0x20 && uids[selected].atqa[0] == 0x04 && uids[selected].atqa[1] == 0x03) {
DbpString("Mifare DESFire");
SimulateIso14443aTag(3, flags, data);
} else {
Dbprintf("Unrecognized tag type -- defaulting to Mifare Classic emulation");
SimulateIso14443aTag(1, flags, data);
}
} else if (button_action == BUTTON_SINGLE_CLICK) {
selected = (selected + 1) % OPTS;
Dbprintf("Done playing. Switching to record mode on bank %d", selected);
iGotoRecord = 1;
break;
} else if (button_action == BUTTON_HOLD) {
Dbprintf("Playtime over. Begin cloning...");
iGotoClone = 1;
break;
}
}
Dbprintf("Starting clone. [Bank: %d]", selected);
// need this delay to prevent catching some weird data
SpinDelay(500);
// Begin clone function here:
/* Example from client/mifarehost.c for commanding a block write for "magic Chinese" cards:
SendCommandOLD(CMD_MIFARE_CSETBLOCK, params & (0xFE | (uid == NULL ? 0:1)), blockNo, 0, data, 16);
/* We pressed a button so ignore it here with a delay */
SpinDelay(300);
LEDsoff();
LED(selected + 1, 0);
}
}
}
Block read is similar:
SendCommandOLD(CMD_MIFARE_CGETBLOCK, params, blockNo, 0,...};
We need to imitate that call with blockNo 0 to set a uid.
The get and set commands are handled in this file:
// Work with "magic Chinese" card
case CMD_MIFARE_CSETBLOCK:
MifareCSetBlock(c->arg[0], c->arg[1], c->d.asBytes);
break;
case CMD_MIFARE_CGETBLOCK:
MifareCGetBlock(c->arg[0], c->arg[1], c->d.asBytes);
break;
mfCSetUID provides example logic for UID set workflow:
-Read block0 from card in field with MifareCGetBlock()
-Configure new values without replacing reserved bytes
memcpy(block0, uid, 4); // Copy UID bytes from byte array
// Mifare UID BCC
block0[4] = block0[0]^block0[1]^block0[2]^block0[3]; // BCC on byte 5
Bytes 5-7 are reserved SAK and ATQA for mifare classic
-Use mfCSetBlock(0, block0, oldUID, wantWipe, MAGIC_SINGLE) to write it
*/
uint8_t oldBlock0[16] = {0}, newBlock0[16] = {0};
// arg0 = Flags, arg1=blockNo
MifareCGetBlock(params, 0, oldBlock0);
if (oldBlock0[0] == 0 && oldBlock0[0] == oldBlock0[1] && oldBlock0[1] == oldBlock0[2] && oldBlock0[2] == oldBlock0[3]) {
Dbprintf("No changeable tag detected. Returning to replay mode for bank[%d]", selected);
playing = 1;
} else {
uint8_t testBlock0[16] = {0};
Dbprintf("UID from target tag: %02X%02X%02X%02X", oldBlock0[0], oldBlock0[1], oldBlock0[2], oldBlock0[3]);
memcpy(newBlock0 + 5, oldBlock0 + 5, 11);
// Copy uid for bank (2nd is for longer UIDs not supported if classic)
memcpy(newBlock0, uids[selected].uid, 4);
newBlock0[4] = newBlock0[0] ^ newBlock0[1] ^ newBlock0[2] ^ newBlock0[3];
// arg0 = workFlags, arg1 = blockNo, datain
MifareCSetBlock(params, 0, newBlock0);
MifareCGetBlock(params, 0, testBlock0);
if (memcmp(testBlock0, newBlock0, 16) == 0) {
DbpString("Cloned successfull!");
cardRead[selected] = 0; // Only if the card was cloned successfully should we clear it
playing = 0;
iGotoRecord = 1;
selected = (selected + 1) % OPTS;
} else {
Dbprintf("Clone failed. Back to replay mode on bank[%d]", selected);
playing = 1;
}
}
LEDsoff();
LED(selected + 1, 0);
}
// Change where to record (or begin playing)
// button_pressed == BUTTON_SINGLE_CLICK && cardRead[selected])
else if (playing == 1) {
LEDsoff();
LED(selected + 1, 0);
// Begin transmitting
LED(LED_B, 0);
DbpString("Playing");
for (; ;) {
// exit from Standalone Mode, send a usbcommand.
if (data_available()) return;
int button_action = BUTTON_HELD(1000);
if (button_action == 0) { // No button action, proceed with sim
uint8_t flags = FLAG_4B_UID_IN_DATA;
uint8_t data[PM3_CMD_DATA_SIZE] = {0}; // in case there is a read command received we shouldn't break
memcpy(data, uids[selected].uid, uids[selected].uidlen);
uint64_t tmpuid = bytes_to_num(uids[selected].uid, uids[selected].uidlen);
if (uids[selected].uidlen == 7) {
flags = FLAG_7B_UID_IN_DATA;
Dbprintf("Simulating ISO14443a tag with uid: %014" PRIx64 " [Bank: %d]", tmpuid, selected);
} else {
Dbprintf("Simulating ISO14443a tag with uid: %08" PRIx64 " [Bank: %d]", tmpuid, selected);
}
if (uids[selected].sak == 0x08 && uids[selected].atqa[0] == 0x04 && uids[selected].atqa[1] == 0) {
DbpString("Mifare Classic 1k");
SimulateIso14443aTag(1, flags, data);
} else if (uids[selected].sak == 0x18 && uids[selected].atqa[0] == 0x02 && uids[selected].atqa[1] == 0) {
DbpString("Mifare Classic 4k (4b uid)");
SimulateIso14443aTag(8, flags, data);
} else if (uids[selected].sak == 0x08 && uids[selected].atqa[0] == 0x44 && uids[selected].atqa[1] == 0) {
DbpString("Mifare Classic 4k (7b uid)");
SimulateIso14443aTag(8, flags, data);
} else if (uids[selected].sak == 0x00 && uids[selected].atqa[0] == 0x44 && uids[selected].atqa[1] == 0) {
DbpString("Mifare Ultralight");
SimulateIso14443aTag(2, flags, data);
} else if (uids[selected].sak == 0x20 && uids[selected].atqa[0] == 0x04 && uids[selected].atqa[1] == 0x03) {
DbpString("Mifare DESFire");
SimulateIso14443aTag(3, flags, data);
} else {
Dbprintf("Unrecognized tag type -- defaulting to Mifare Classic emulation");
SimulateIso14443aTag(1, flags, data);
}
} else if (button_action == BUTTON_SINGLE_CLICK) {
selected = (selected + 1) % OPTS;
Dbprintf("Done playing. Switching to record mode on bank %d", selected);
iGotoRecord = 1;
break;
} else if (button_action == BUTTON_HOLD) {
Dbprintf("Playtime over. Begin cloning...");
iGotoClone = 1;
break;
}
}
/* We pressed a button so ignore it here with a delay */
SpinDelay(300);
LEDsoff();
LED(selected + 1, 0);
}
}
}

View file

@ -16,7 +16,7 @@
#include "standalone.h" // standalone definitions
#include "iso14443a.h"
#include "protocols.h"
#define OPTS 2
#endif /* __HF_YOUNG_H */
#endif /* __HF_YOUNG_H */

View file

@ -9,16 +9,16 @@
// the license.
//
// PROXMARK3 - HID CORPORATE 1000 BRUTEFORCER (STAND-ALONE MODE)
//
// This version of Proxmark3 firmware adds one extra stand-alone mode to proxmark3 firmware.
//
// This version of Proxmark3 firmware adds one extra stand-alone mode.
// The new stand-alone mode allows to execute a bruteforce on HID Corporate 1000 readers, by
// reading a specific badge and bruteforcing the Card Number (incrementing and decrementing it),
// mainteining the same Facility Code of the original badge.
//
// Based on an idea of Brad Antoniewicz of McAfee® Foundstone® Professional Services (ProxBrute),
// Based on an idea of Brad Antoniewicz of McAfee® Foundstone® Professional Services (ProxBrute),
// the stand-alone mode has been rewritten in order to overcome some limitations of ProxBrute firmware,
// that does not consider parity bits.
//
//
// https://github.com/federicodotta/proxmark3
//
//-----------------------------------------------------------------------------------
@ -26,297 +26,299 @@
//-----------------------------------------------------------------------------------
#include "lf_hidbrute.h"
void ModInfo(void) {
DbpString(" LF HID corporate 1000 bruteforce - aka Corporatebrute (Federico dotta & Maurizio Agazzini)");
}
// samy's sniff and repeat routine for LF
void RunMod() {
StandAloneMode();
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
StandAloneMode();
Dbprintf(">> LF HID corporate bruteforce a.k.a CorporateBrute Started <<");
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
uint32_t high[OPTS], low[OPTS];
int selected = 0;
int playing = 0;
int cardRead = 0;
uint32_t high[OPTS], low[OPTS];
int selected = 0;
int playing = 0;
int cardRead = 0;
// Turn on selected LED
LED(selected + 1, 0);
// Turn on selected LED
LED(selected + 1, 0);
for (;;) {
WDT_HIT();
// exit from SamyRun, send a usbcommand.
if (usb_poll_validate_length()) break;
for (;;) {
WDT_HIT();
// Was our button held down or pressed?
int button_pressed = BUTTON_HELD(1000);
SpinDelay(300);
// exit from SamyRun, send a usbcommand.
if (data_available()) break;
// Button was held for a second, begin recording
if (button_pressed > 0 && cardRead == 0) {
LEDsoff();
LED(selected + 1, 0);
LED(LED_RED2, 0);
// Was our button held down or pressed?
int button_pressed = BUTTON_HELD(1000);
SpinDelay(300);
// record
DbpString("[=] starting recording");
// Button was held for a second, begin recording
if (button_pressed > 0 && cardRead == 0) {
LEDsoff();
LED(selected + 1, 0);
LED(LED_D, 0);
// wait for button to be released
while(BUTTON_PRESS())
WDT_HIT();
// record
DbpString("[=] starting recording");
/* need this delay to prevent catching some weird data */
SpinDelay(500);
// wait for button to be released
while (BUTTON_PRESS())
WDT_HIT();
CmdHIDdemodFSK(1, &high[selected], &low[selected], 0);
Dbprintf("[=] recorded %x %x %08x", selected, high[selected], low[selected]);
/* need this delay to prevent catching some weird data */
SpinDelay(500);
LEDsoff();
LED(selected + 1, 0);
// Finished recording
// If we were previously playing, set playing off
// so next button push begins playing what we recorded
playing = 0;
cardRead = 1;
}
else if (button_pressed > 0 && cardRead == 1) {
LEDsoff();
LED(selected + 1, 0);
LED(LED_ORANGE, 0);
CmdHIDdemodFSK(1, &high[selected], &low[selected], 0);
Dbprintf("[=] recorded %x %x %08x", selected, high[selected], low[selected]);
// record
Dbprintf("[=] cloning %x %x %08x", selected, high[selected], low[selected]);
LEDsoff();
LED(selected + 1, 0);
// Finished recording
// If we were previously playing, set playing off
// so next button push begins playing what we recorded
playing = 0;
cardRead = 1;
} else if (button_pressed > 0 && cardRead == 1) {
LEDsoff();
LED(selected + 1, 0);
LED(LED_A, 0);
// wait for button to be released
while(BUTTON_PRESS())
WDT_HIT();
// record
Dbprintf("[=] cloning %x %x %08x", selected, high[selected], low[selected]);
/* need this delay to prevent catching some weird data */
SpinDelay(500);
// wait for button to be released
while (BUTTON_PRESS())
WDT_HIT();
CopyHIDtoT55x7(0, high[selected], low[selected], 0);
Dbprintf("[=] cloned %x %x %08x", selected, high[selected], low[selected]);
/* need this delay to prevent catching some weird data */
SpinDelay(500);
LEDsoff();
LED(selected + 1, 0);
// Finished recording
CopyHIDtoT55x7(0, high[selected], low[selected], 0);
Dbprintf("[=] cloned %x %x %08x", selected, high[selected], low[selected]);
// If we were previously playing, set playing off
// so next button push begins playing what we recorded
playing = 0;
cardRead = 0;
}
LEDsoff();
LED(selected + 1, 0);
// Finished recording
// Change where to record (or begin playing)
else if (button_pressed) {
// Next option if we were previously playing
if (playing)
selected = (selected + 1) % OPTS;
playing = !playing;
// If we were previously playing, set playing off
// so next button push begins playing what we recorded
playing = 0;
cardRead = 0;
}
LEDsoff();
LED(selected + 1, 0);
// Change where to record (or begin playing)
else if (button_pressed) {
// Next option if we were previously playing
if (playing)
selected = (selected + 1) % OPTS;
// Begin transmitting
if (playing && selected != 2) {
playing = !playing;
LED(LED_GREEN, 0);
DbpString("[=] playing");
// wait for button to be released
while (BUTTON_PRESS())
WDT_HIT();
Dbprintf("[=] %x %x %08x", selected, high[selected], low[selected]);
CmdHIDsimTAG(high[selected], low[selected], 0);
DbpString("[=] done playing");
if (BUTTON_HELD(1000) > 0)
goto out;
LEDsoff();
LED(selected + 1, 0);
/* We pressed a button so ignore it here with a delay */
SpinDelay(300);
// Begin transmitting
if (playing && selected != 2) {
// when done, we're done playing, move to next option
selected = (selected + 1) % OPTS;
playing = !playing;
LEDsoff();
LED(selected + 1, 0);
}
else if (playing && selected == 2)
{
// Now it work only with HID Corporate 1000 (35bit), but is easily extensible to others RFID.
// It is necessary only to calculate the correct parity.
// Brute force code
// Check if the badge is an HID Corporate 1000
if( (high[selected] & 0xFFFFFFF8) != 0x28 ) {
DbpString("[-] Card is not a HID Corporate 1000. Skipping bruteforce.");
continue;
}
LED(LED_B, 0);
DbpString("[=] playing");
LED(LED_GREEN, 0);
DbpString("[=] entering bruteforce mode");
// wait for button to be released
while (BUTTON_PRESS())
WDT_HIT();
// Calculate Facility Code and Card Number from high and low
uint32_t cardnum = (low[selected] >> 1) & 0xFFFFF;
uint32_t fc = ((high[selected] & 1 ) << 11 ) | (low[selected] >> 21);
uint32_t original_cardnum = cardnum;
// wait for button to be released
while (BUTTON_PRESS())
WDT_HIT();
Dbprintf("[=] Proxbrute - starting decrementing card number");
Dbprintf("[=] %x %x %08x", selected, high[selected], low[selected]);
CmdHIDsimTAG(high[selected], low[selected], 0);
DbpString("[=] done playing");
while (cardnum >= 0) {
// Needed for exiting from proxbrute when button is pressed
if (BUTTON_PRESS()) {
if (BUTTON_HELD(1000) > 0) {
goto out;
} else {
while (BUTTON_PRESS()) {
WDT_HIT();
}
break;
}
}
if (BUTTON_HELD(1000) > 0)
goto out;
// Decrement Card Number
cardnum--;
/* We pressed a button so ignore it here with a delay */
SpinDelay(300);
// Calculate checksum of HID Corporate 1000 and set card number and facility code in high and low variables
hid_corporate_1000_calculate_checksum_and_set(&high[selected], &low[selected], cardnum, fc);
// when done, we're done playing, move to next option
selected = (selected + 1) % OPTS;
playing = !playing;
LEDsoff();
LED(selected + 1, 0);
} else if (playing && selected == 2) {
// Now it work only with HID Corporate 1000 (35bit), but is easily extensible to others RFID.
// It is necessary only to calculate the correct parity.
// Print actual code to brute
Dbprintf("[=] TAG ID: %x%08x (%d) - FC: %u - Card: %u", high[selected], low[selected], (low[selected] >> 1) & 0xFFFF, fc, cardnum);
CmdHIDsimTAGEx(high[selected], low[selected], 1, 50000);
}
// Brute force code
// Check if the badge is an HID Corporate 1000
if ((high[selected] & 0xFFFFFFF8) != 0x28) {
DbpString("[-] Card is not a HID Corporate 1000. Skipping bruteforce.");
continue;
}
cardnum = original_cardnum;
LED(LED_B, 0);
DbpString("[=] entering bruteforce mode");
// wait for button to be released
while (BUTTON_PRESS())
WDT_HIT();
Dbprintf("[=] Proxbrute - starting incrementing card number");
// Calculate Facility Code and Card Number from high and low
uint32_t cardnum = (low[selected] >> 1) & 0xFFFFF;
uint32_t fc = ((high[selected] & 1) << 11) | (low[selected] >> 21);
uint32_t original_cardnum = cardnum;
while (cardnum <= 0xFFFFF) {
// Needed for exiting from proxbrute when button is pressed
if (BUTTON_PRESS()) {
if (BUTTON_HELD(1000) > 0) {
goto out;
} else {
while (BUTTON_PRESS()) { WDT_HIT(); }
break;
}
}
Dbprintf("[=] Proxbrute - starting decrementing card number");
// Decrement Card Number
cardnum++;
while (cardnum > 0) {
// Calculate checksum of HID Corporate 1000 and set card number and facility code in high and low variables
hid_corporate_1000_calculate_checksum_and_set(&high[selected], &low[selected], cardnum, fc);
// Needed for exiting from proxbrute when button is pressed
if (BUTTON_PRESS()) {
if (BUTTON_HELD(1000) > 0) {
goto out;
} else {
while (BUTTON_PRESS()) {
WDT_HIT();
}
break;
}
}
// Print actual code to brute
Dbprintf("[=] TAG ID: %x%08x (%d) - FC: %u - Card: %u", high[selected], low[selected], (low[selected] >> 1) & 0xFFFF, fc, cardnum);
// Decrement Card Number
cardnum--;
CmdHIDsimTAGEx(high[selected], low[selected], 1, 50000);
}
// Calculate checksum of HID Corporate 1000 and set card number and facility code in high and low variables
hid_corporate_1000_calculate_checksum_and_set(&high[selected], &low[selected], cardnum, fc);
DbpString("[=] done bruteforcing");
if (BUTTON_HELD(1000) > 0)
goto out;
// Print actual code to brute
Dbprintf("[=] TAG ID: %x%08x (%d) - FC: %u - Card: %u", high[selected], low[selected], (low[selected] >> 1) & 0xFFFF, fc, cardnum);
/* We pressed a button so ignore it here with a delay */
SpinDelay(300);
CmdHIDsimTAGEx(high[selected], low[selected], 1, 50000);
}
// when done, we're done playing, move to next option
selected = (selected + 1) % OPTS;
playing = !playing;
LEDsoff();
LED(selected + 1, 0);
} else {
while(BUTTON_PRESS())
WDT_HIT();
}
}
}
out:
DbpString("[=] exiting");
LEDsoff();
cardnum = original_cardnum;
Dbprintf("[=] Proxbrute - starting incrementing card number");
while (cardnum <= 0xFFFFF) {
// Needed for exiting from proxbrute when button is pressed
if (BUTTON_PRESS()) {
if (BUTTON_HELD(1000) > 0) {
goto out;
} else {
while (BUTTON_PRESS()) { WDT_HIT(); }
break;
}
}
// Decrement Card Number
cardnum++;
// Calculate checksum of HID Corporate 1000 and set card number and facility code in high and low variables
hid_corporate_1000_calculate_checksum_and_set(&high[selected], &low[selected], cardnum, fc);
// Print actual code to brute
Dbprintf("[=] TAG ID: %x%08x (%d) - FC: %u - Card: %u", high[selected], low[selected], (low[selected] >> 1) & 0xFFFF, fc, cardnum);
CmdHIDsimTAGEx(high[selected], low[selected], 1, 50000);
}
DbpString("[=] done bruteforcing");
if (BUTTON_HELD(1000) > 0)
goto out;
/* We pressed a button so ignore it here with a delay */
SpinDelay(300);
// when done, we're done playing, move to next option
selected = (selected + 1) % OPTS;
playing = !playing;
LEDsoff();
LED(selected + 1, 0);
} else {
while (BUTTON_PRESS())
WDT_HIT();
}
}
}
out:
DbpString("[=] exiting");
LEDsoff();
}
// Function that calculate next value for the brutforce of HID corporate 1000
void hid_corporate_1000_calculate_checksum_and_set( uint32_t *high, uint32_t *low, uint32_t cardnum, uint32_t fc) {
void hid_corporate_1000_calculate_checksum_and_set(uint32_t *high, uint32_t *low, uint32_t cardnum, uint32_t fc) {
uint32_t new_high = 0;
uint32_t new_low = 0;
uint32_t new_high = 0;
uint32_t new_low = 0;
// Calculate new high and low base value from card number and facility code, without parity
new_low = (fc << 21) | (cardnum << 1);
new_high = 0x28 | ((fc >> 11) & 1); // 0x28 is 101000
// Calculate new high and low base value from card number and facility code, without parity
new_low = (fc << 21) | (cardnum << 1);
new_high = 0x28 | ((fc >> 11) & 1); // 0x28 is 101000
int n_ones;
uint32_t i;
// Calculating and setting parity bit 34
// Select only bit used for parity bit 34 in low number (10110110110110110110110110110110)
uint32_t parity_bit_34_low = new_low & 0xB6DB6DB6;
n_ones = 0;
// Calculate number of ones in low number
for ( i = 1; i != 0; i <<= 1) {
if( parity_bit_34_low & i )
n_ones++;
}
// Calculate number of ones in high number
if (new_high & 1)
n_ones++;
// Set parity bit (Even parity)
if (n_ones % 2)
new_high = new_high | 0x2;
int n_ones;
uint32_t i;
// Calculating and setting parity bit 1
// Select only bit used for parity bit 1 in low number (01101101101101101101101101101100)
uint32_t parity_bit_1_low = new_low & 0x6DB6DB6C;
n_ones = 0;
// Calculating and setting parity bit 34
// Select only bit used for parity bit 34 in low number (10110110110110110110110110110110)
uint32_t parity_bit_34_low = new_low & 0xB6DB6DB6;
n_ones = 0;
// Calculate number of ones in low number
for (i = 1; i != 0; i <<= 1) {
if (parity_bit_34_low & i)
n_ones++;
}
// Calculate number of ones in high number
if (new_high & 1)
n_ones++;
// Calculate number of ones in low number
for ( i=1; i != 0; i <<= 1) {
if( parity_bit_1_low & i )
n_ones++;
}
// Calculate number of ones in high number
if ( new_high & 0x1)
n_ones++;
if ( new_high & 0x2)
n_ones++;
// Set parity bit (Odd parity)
if (!(n_ones % 2))
new_low = new_low | 0x1;
// Calculating and setting parity bit 35
n_ones = 0;
// Calculate number of ones in low number (all bit of low, bitmask unnecessary)
for (i = 1; i != 0; i <<= 1) {
if ( new_low & i )
n_ones++;
}
// Calculate number of ones in high number
if ( new_high & 0x1)
n_ones++;
if ( new_high & 0x2)
n_ones++;
// Set parity bit (Even parity)
if (n_ones % 2)
new_high = new_high | 0x2;
// Set parity bit (Odd parity)
if (!(n_ones % 2))
new_high = new_high | 0x4;
// Calculating and setting parity bit 1
// Select only bit used for parity bit 1 in low number (01101101101101101101101101101100)
uint32_t parity_bit_1_low = new_low & 0x6DB6DB6C;
n_ones = 0;
// Setting new calculated values
*low = new_low;
*high = new_high;
// Calculate number of ones in low number
for (i = 1; i != 0; i <<= 1) {
if (parity_bit_1_low & i)
n_ones++;
}
// Calculate number of ones in high number
if (new_high & 0x1)
n_ones++;
if (new_high & 0x2)
n_ones++;
// Set parity bit (Odd parity)
if (!(n_ones % 2))
new_low = new_low | 0x1;
// Calculating and setting parity bit 35
n_ones = 0;
// Calculate number of ones in low number (all bit of low, bitmask unnecessary)
for (i = 1; i != 0; i <<= 1) {
if (new_low & i)
n_ones++;
}
// Calculate number of ones in high number
if (new_high & 0x1)
n_ones++;
if (new_high & 0x2)
n_ones++;
// Set parity bit (Odd parity)
if (!(n_ones % 2))
new_high = new_high | 0x4;
// Setting new calculated values
*low = new_low;
*high = new_high;
}
// prepare a waveform pattern in the buffer based on the ID given then

View file

@ -19,6 +19,6 @@
#define OPTS 3
void hid_corporate_1000_calculate_checksum_and_set( uint32_t *high, uint32_t *low, uint32_t cardnum, uint32_t fc);
void hid_corporate_1000_calculate_checksum_and_set(uint32_t *high, uint32_t *low, uint32_t cardnum, uint32_t fc);
#endif /* __LF_HIDBRUTE_H */
#endif /* __LF_HIDBRUTE_H */

View file

@ -0,0 +1,40 @@
//-----------------------------------------------------------------------------
// Christian Herrmann, 2019
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// main code for skeleton aka IceRun by Iceman
//-----------------------------------------------------------------------------
#include "lf_icerun.h"
void ModInfo(void) {
DbpString(" LF skeleton mode - aka IceRun (iceman)");
}
// samy's sniff and repeat routine for LF
void RunMod() {
StandAloneMode();
Dbprintf("[=] LF skeleton code a.k.a IceRun started");
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
// the main loop for your standalone mode
for (;;) {
WDT_HIT();
// exit from IceRun, send a usbcommand.
if (data_available()) break;
// Was our button held down or pressed?
int button_pressed = BUTTON_HELD(1000);
Dbprintf("button %d", button_pressed);
if (button_pressed)
break;
}
DbpString("[=] exiting");
LEDsoff();
}

View file

@ -1,21 +1,17 @@
//-----------------------------------------------------------------------------
// Micolous Jan 2017
// Iceman Jan 2017
// Iceman, Christian Herrmann, 2019
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// pseudo rng generator. To be used when PM3 simulates Mifare tag.
// i.e. 'hf mf sim'
// 'hf 14a sim'
// StandAlone Mod
//-----------------------------------------------------------------------------
#ifndef __RANDOM_H
#define __RANDOM_H
#ifndef __LF_ICERUN_H
#define __LF_ICERUN_H
#include "common.h"
#include "ticks.h"
void fast_prand();
void fast_prandEx(uint32_t seed);
uint32_t prand();
#endif
#include "standalone.h" // standalone definitions
#include "apps.h" // debugstatements, lfops?
#endif /* __LF_ICERUN_H */

View file

@ -7,162 +7,165 @@
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// main code for LF aka Proxbrute by Brad antoniewicz
// main code for LF aka Proxbrute by Brad antoniewicz
//-----------------------------------------------------------------------------
#include "lf_proxbrute.h"
void ModInfo(void) {
DbpString(" LF HID ProxII bruteforce - aka Proxbrute (Brad Antoniewicz)");
}
// samy's sniff and repeat routine for LF
void RunMod() {
StandAloneMode();
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
StandAloneMode();
Dbprintf(">> LF HID proxII bruteforce a.k.a ProxBrute Started (Brad Antoniewicz) <<");
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
uint32_t high[OPTS], low[OPTS];
int selected = 0;
int playing = 0;
int cardRead = 0;
uint32_t high[OPTS], low[OPTS];
int selected = 0;
int playing = 0;
int cardRead = 0;
// Turn on selected LED
LED(selected + 1, 0);
// Turn on selected LED
LED(selected + 1, 0);
for (;;) {
WDT_HIT();
// exit from SamyRun, send a usbcommand.
if (usb_poll_validate_length()) break;
for (;;) {
WDT_HIT();
// Was our button held down or pressed?
int button_pressed = BUTTON_HELD(1000);
SpinDelay(300);
// exit from SamyRun, send a usbcommand.
if (data_available()) break;
// Button was held for a second, begin recording
if (button_pressed > 0 && cardRead == 0) {
LEDsoff();
LED(selected + 1, 0);
LED(LED_RED2, 0);
// Was our button held down or pressed?
int button_pressed = BUTTON_HELD(1000);
SpinDelay(300);
// record
DbpString("[=] starting recording");
// Button was held for a second, begin recording
if (button_pressed > 0 && cardRead == 0) {
LEDsoff();
LED(selected + 1, 0);
LED(LED_D, 0);
// wait for button to be released
while (BUTTON_PRESS())
WDT_HIT();
// record
DbpString("[=] starting recording");
/* need this delay to prevent catching some weird data */
SpinDelay(500);
// wait for button to be released
while (BUTTON_PRESS())
WDT_HIT();
CmdHIDdemodFSK(1, &high[selected], &low[selected], 0);
Dbprintf("[=] recorded %x %x %08x", selected, high[selected], low[selected]);
/* need this delay to prevent catching some weird data */
SpinDelay(500);
LEDsoff();
LED(selected + 1, 0);
// Finished recording
// If we were previously playing, set playing off
// so next button push begins playing what we recorded
playing = 0;
cardRead = 1;
}
else if (button_pressed > 0 && cardRead == 1) {
LEDsoff();
LED(selected + 1, 0);
LED(LED_ORANGE, 0);
CmdHIDdemodFSK(1, &high[selected], &low[selected], 0);
Dbprintf("[=] recorded %x %x %08x", selected, high[selected], low[selected]);
// record
Dbprintf("[=] cloning %x %x %08x", selected, high[selected], low[selected]);
LEDsoff();
LED(selected + 1, 0);
// Finished recording
// If we were previously playing, set playing off
// so next button push begins playing what we recorded
playing = 0;
cardRead = 1;
} else if (button_pressed > 0 && cardRead == 1) {
LEDsoff();
LED(selected + 1, 0);
LED(LED_A, 0);
// wait for button to be released
while (BUTTON_PRESS())
WDT_HIT();
// record
Dbprintf("[=] cloning %x %x %08x", selected, high[selected], low[selected]);
/* need this delay to prevent catching some weird data */
SpinDelay(500);
// wait for button to be released
while (BUTTON_PRESS())
WDT_HIT();
CopyHIDtoT55x7(0, high[selected], low[selected], 0);
Dbprintf("[=] cloned %x %x %08x", selected, high[selected], low[selected]);
/* need this delay to prevent catching some weird data */
SpinDelay(500);
LEDsoff();
LED(selected + 1, 0);
// Finished recording
CopyHIDtoT55x7(0, high[selected], low[selected], 0);
Dbprintf("[=] cloned %x %x %08x", selected, high[selected], low[selected]);
// If we were previously playing, set playing off
// so next button push begins playing what we recorded
playing = 0;
cardRead = 0;
}
LEDsoff();
LED(selected + 1, 0);
// Finished recording
// Change where to record (or begin playing)
else if (button_pressed) {
// Next option if we were previously playing
if (playing)
selected = (selected + 1) % OPTS;
playing = !playing;
// If we were previously playing, set playing off
// so next button push begins playing what we recorded
playing = 0;
cardRead = 0;
}
LEDsoff();
LED(selected + 1, 0);
// Change where to record (or begin playing)
else if (button_pressed) {
// Next option if we were previously playing
if (playing)
selected = (selected + 1) % OPTS;
playing = !playing;
// Begin transmitting
if (playing) {
LED(LED_GREEN, 0);
DbpString("[=] playing");
// wait for button to be released
while (BUTTON_PRESS())
WDT_HIT();
/* START PROXBRUTE */
LEDsoff();
LED(selected + 1, 0);
/*
ProxBrute - brad a. - foundstone
// Begin transmitting
if (playing) {
LED(LED_B, 0);
DbpString("[=] playing");
// wait for button to be released
while (BUTTON_PRESS())
WDT_HIT();
Following code is a trivial brute forcer once you read a valid tag
the idea is you get a valid tag, then just try and brute force to
another priv level. The problem is that it has no idea if the code
worked or not, so its a crap shoot. One option is to time how long
it takes to get a valid ID then start from scratch every time.
*/
if ( selected == 1 ) {
DbpString("[=] entering ProxBrute Mode");
Dbprintf("[=] current Tag: Selected = %x Facility = %08x ID = %08x", selected, high[selected], low[selected]);
LED(LED_ORANGE, 0);
LED(LED_RED, 0);
for (uint16_t i = low[selected]-1; i > 0; i--) {
if (BUTTON_PRESS()) {
DbpString("[-] told to stop");
break;
}
/* START PROXBRUTE */
Dbprintf("[=] trying Facility = %08x ID %08x", high[selected], i);
CmdHIDsimTAGEx(high[selected], i, 0, 20000);
SpinDelay(500);
}
/*
ProxBrute - brad a. - foundstone
} else {
DbpString("[=] RED is lit, not entering ProxBrute Mode");
Dbprintf("[=] %x %x %x", selected, high[selected], low[selected]);
CmdHIDsimTAGEx(high[selected], low[selected], 0, 20000);
DbpString("[=] done playing");
}
Following code is a trivial brute forcer once you read a valid tag
the idea is you get a valid tag, then just try and brute force to
another priv level. The problem is that it has no idea if the code
worked or not, so its a crap shoot. One option is to time how long
it takes to get a valid ID then start from scratch every time.
*/
if (selected == 1) {
DbpString("[=] entering ProxBrute Mode");
Dbprintf("[=] current Tag: Selected = %x Facility = %08x ID = %08x", selected, high[selected], low[selected]);
LED(LED_A, 0);
LED(LED_C, 0);
for (uint16_t i = low[selected] - 1; i > 0; i--) {
if (BUTTON_PRESS()) {
DbpString("[-] told to stop");
break;
}
/* END PROXBRUTE */
Dbprintf("[=] trying Facility = %08x ID %08x", high[selected], i);
CmdHIDsimTAGEx(high[selected], i, 0, 20000);
SpinDelay(500);
}
if (BUTTON_HELD(1000) > 0)
goto out;
} else {
DbpString("[=] RED is lit, not entering ProxBrute Mode");
Dbprintf("[=] %x %x %x", selected, high[selected], low[selected]);
CmdHIDsimTAGEx(high[selected], low[selected], 0, 20000);
DbpString("[=] done playing");
}
/* We pressed a button so ignore it here with a delay */
SpinDelay(300);
/* END PROXBRUTE */
// when done, we're done playing, move to next option
selected = (selected + 1) % OPTS;
playing = !playing;
LEDsoff();
LED(selected + 1, 0);
}
else {
while (BUTTON_PRESS())
WDT_HIT();
}
}
}
out:
DbpString("[=] exiting");
LEDsoff();
}
if (BUTTON_HELD(1000) > 0)
goto out;
/* We pressed a button so ignore it here with a delay */
SpinDelay(300);
// when done, we're done playing, move to next option
selected = (selected + 1) % OPTS;
playing = !playing;
LEDsoff();
LED(selected + 1, 0);
} else {
while (BUTTON_PRESS())
WDT_HIT();
}
}
}
out:
DbpString("[=] exiting");
LEDsoff();
}

View file

@ -18,4 +18,4 @@
#define OPTS 2
#endif /* __LF_PROXBRUTE_H */
#endif /* __LF_PROXBRUTE_H */

View file

@ -6,137 +6,140 @@
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// main code for LF aka SamyRun by Samy Kamkar
// main code for LF aka SamyRun by Samy Kamkar
//-----------------------------------------------------------------------------
#include "lf_samyrun.h"
void ModInfo(void) {
DbpString(" LF HID26 standalone - aka SamyRun (Samy Kamkar)");
}
// samy's sniff and repeat routine for LF
void RunMod() {
StandAloneMode();
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
StandAloneMode();
Dbprintf(">> LF HID Read/Clone/Sim a.k.a SamyRun Started <<");
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
uint32_t high[OPTS], low[OPTS];
int selected = 0;
int playing = 0;
int cardRead = 0;
bool gotCard;
// Turn on selected LED
LED(selected + 1, 0);
uint32_t high[OPTS], low[OPTS];
int selected = 0;
int playing = 0;
int cardRead = 0;
bool gotCard;
// Turn on selected LED
LED(selected + 1, 0);
for (;;) {
WDT_HIT();
// exit from SamyRun, send a usbcommand.
if (usb_poll_validate_length()) break;
for (;;) {
WDT_HIT();
// Was our button held down or pressed?
int button_pressed = BUTTON_HELD(1000);
Dbprintf("button %d", button_pressed);
SpinDelay(300);
// exit from SamyRun, send a usbcommand.
if (data_available()) break;
// Button was held for a second, begin recording
if (button_pressed > 0 && cardRead == 0) {
LEDsoff();
LED(selected + 1, 0);
LED(LED_RED2, 0);
// Was our button held down or pressed?
int button_pressed = BUTTON_HELD(1000);
// record
DbpString("[=] starting recording");
Dbprintf("button %d", button_pressed);
SpinDelay(300);
// wait for button to be released
while (BUTTON_PRESS())
WDT_HIT();
// Button was held for a second, begin recording
if (button_pressed > 0 && cardRead == 0) {
LEDsoff();
LED(selected + 1, 0);
LED(LED_D, 0);
/* need this delay to prevent catching some weird data */
SpinDelay(500);
// record
DbpString("[=] starting recording");
CmdHIDdemodFSK(1, &high[selected], &low[selected], 0);
Dbprintf("[=] recorded bank %x | %x %08x", selected, high[selected], low[selected]);
// wait for button to be released
while (BUTTON_PRESS())
WDT_HIT();
LEDsoff();
LED(selected + 1, 0);
// Finished recording
// If we were previously playing, set playing off
// so next button push begins playing what we recorded
playing = 0;
cardRead = 1;
/* need this delay to prevent catching some weird data */
SpinDelay(500);
gotCard = true;
}
else if (button_pressed > 0 && cardRead == 1) {
LEDsoff();
LED(selected + 1, 0);
LED(LED_ORANGE, 0);
CmdHIDdemodFSK(1, &high[selected], &low[selected], 0);
Dbprintf("[=] recorded bank %x | %x %08x", selected, high[selected], low[selected]);
// record
Dbprintf("[=] cloning %x %x %08x", selected, high[selected], low[selected]);
LEDsoff();
LED(selected + 1, 0);
// Finished recording
// If we were previously playing, set playing off
// so next button push begins playing what we recorded
playing = 0;
cardRead = 1;
// wait for button to be released
while (BUTTON_PRESS())
WDT_HIT();
gotCard = true;
} else if (button_pressed > 0 && cardRead == 1) {
LEDsoff();
LED(selected + 1, 0);
LED(LED_A, 0);
/* need this delay to prevent catching some weird data */
SpinDelay(500);
// record
Dbprintf("[=] cloning %x %x %08x", selected, high[selected], low[selected]);
CopyHIDtoT55x7(0, high[selected], low[selected], 0);
Dbprintf("[=] cloned %x %x %08x", selected, high[selected], low[selected]);
// wait for button to be released
while (BUTTON_PRESS())
WDT_HIT();
LEDsoff();
LED(selected + 1, 0);
// Finished recording
/* need this delay to prevent catching some weird data */
SpinDelay(500);
// If we were previously playing, set playing off
// so next button push begins playing what we recorded
playing = 0;
cardRead = 0;
}
CopyHIDtoT55x7(0, high[selected], low[selected], 0);
Dbprintf("[=] cloned %x %x %08x", selected, high[selected], low[selected]);
// Change where to record (or begin playing)
else if (button_pressed && gotCard) {
// Next option if we were previously playing
if (playing)
selected = (selected + 1) % OPTS;
playing = !playing;
LEDsoff();
LED(selected + 1, 0);
// Finished recording
LEDsoff();
LED(selected + 1, 0);
// If we were previously playing, set playing off
// so next button push begins playing what we recorded
playing = 0;
cardRead = 0;
}
// Begin transmitting
if (playing) {
LED(LED_GREEN, 0);
DbpString("[=] playing");
// wait for button to be released
while (BUTTON_PRESS())
WDT_HIT();
Dbprintf("[=] %x %x %08x", selected, high[selected], low[selected]);
CmdHIDsimTAG(high[selected], low[selected], false);
DbpString("[=] done playing");
if (BUTTON_HELD(1000) > 0)
goto out;
// Change where to record (or begin playing)
else if (button_pressed && gotCard) {
// Next option if we were previously playing
if (playing)
selected = (selected + 1) % OPTS;
/* We pressed a button so ignore it here with a delay */
SpinDelay(300);
playing = !playing;
// when done, we're done playing, move to next option
selected = (selected + 1) % OPTS;
playing = !playing;
LEDsoff();
LED(selected + 1, 0);
}
else {
while (BUTTON_PRESS())
WDT_HIT();
}
}
}
LEDsoff();
LED(selected + 1, 0);
out:
DbpString("[=] exiting");
LEDsoff();
}
// Begin transmitting
if (playing) {
LED(LED_B, 0);
DbpString("[=] playing");
// wait for button to be released
while (BUTTON_PRESS())
WDT_HIT();
Dbprintf("[=] %x %x %08x", selected, high[selected], low[selected]);
CmdHIDsimTAG(high[selected], low[selected], false);
DbpString("[=] done playing");
if (BUTTON_HELD(1000) > 0)
goto out;
/* We pressed a button so ignore it here with a delay */
SpinDelay(300);
// when done, we're done playing, move to next option
selected = (selected + 1) % OPTS;
playing = !playing;
LEDsoff();
LED(selected + 1, 0);
} else {
while (BUTTON_PRESS())
WDT_HIT();
}
}
}
out:
DbpString("[=] exiting");
LEDsoff();
}

View file

@ -19,4 +19,4 @@
#define OPTS 2
#endif /* __LF_SAMYRUN_H */
#endif /* __LF_SAMYRUN_H */

View file

@ -0,0 +1,9 @@
#include "standalone.h" // standalone definitions
#include "apps.h" // debug statements
void ModInfo(void) {
DbpString(" No standalone mode present");
}
void RunMod() {
}

View file

@ -1,102 +1,138 @@
# StandAlone Modes
# Standalone Modes
This contains functionality for different StandAlone modes. The fullimage will be built given the correct compiler flags used. Build targets for these files are contained in `armsrc/Makefile`.
This contains functionality for different StandAlone modes. The fullimage will be built given the correct compiler flags used. Build targets for these files are contained in `armsrc/Makefile` and `common/Makefile.hal`
If you want to implement a new standalone mode, you need to implement the methods provided in `standalone.h`.
## Implementing a standalone mode
Each standalone mod needs to have its own compiler flag to be added in `armsrc\makefile` and inside the function `AppMain` inside AppMain.c. Inside Appmain a call to RunMod is needed. It looks strange because of what kinds of dependencies your mode will have.
The RunMod function is your "main" function when running. You need to check for Usb commands, in order to let the pm3 client break the standalone mode. See this basic skeleton of main function RunMod().
````
void RunMod() {
// led show
StandAloneMode();
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
// main loop
for (;;) {
WDT_HIT();
// exit from standalone mode, just send a usbcommand
if (usb_poll_validate_length()) break;
// do your standalone stuff..
}
````
Have a look at the skeleton standalone mode called IceRun, in the files `lf_icerun.c lf_icerun.h`.
As it is now, you can only have one standalone mode installed at the time.
## Name
Use HF/LF to denote which frequence your mod is targeting.
Use you own github name/similar for perpetual honour to denote your mod
## Implementing a standalone mode
Samples of directive flag used in the `armsrc\makefile`:
We suggest you keep your standalone code inside the `armsrc/Standalone` folder. And that you name your files according to your standalone mode name.
The `standalone.h` states that you must have two functions implemented.
The ModInfo function, which is your identification of your standalone mode. This string will show when running the command `hw status` on the client.
The RunMod function, which is your "main" function when running. You need to check for Usb commands, in order to let the pm3 client break the standalone mode. See this basic skeleton of main function RunMod() and Modinfo() below.
````
void ModInfo(void) {
DbpString(" LF good description of your mode - aka FooRun (your name)");
}
void RunMod(void) {
// led show
StandAloneMode();
// Do you target LF or HF?
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
// main loop
for (;;) {
WDT_HIT();
// exit from standalone mode, just send a usbcommand
if (data_available()) break;
// do your standalone stuff..
}
````
Each standalone mode needs to have its own compiler flag to be added in `armsrc/Makefile`.
## Naming your standalone mode
We suggest that you follow these guidelines:
- Use HF/LF to denote which frequency your mode is targeting.
- Use you own github name/similar for perpetual honour to denote your mode.
sample:
`LF_FOO`
Which indicates your mode targets LF and is called FOO.
This leads to your next step, your DEFINE name needed in Makefile.
`WITH_STANDALONE_LF_FOO`
## Update COMMON/MAKEFILE.HAL
Add your mode to the `common/Makefile.hal` help and modes list:
```
### -DWITH_LF_ICERUN
### -DWITH_LF_SAMYRUN
### -DWITH_LF_PROXBRUTE
### -DWITH_LF_HIDBRUTE
### -DWITH_HF_COLIN
### -DWITH_HF_YOUNG
### -DWITH_HF_MATTYRUN
+==========================================================+
| STANDALONE | DESCRIPTION |
+==========================================================+
...
+----------------------------------------------------------+
| LF_FOO | My foobar mode will make you coffee |
+----------------------------------------------------------+
STANDALONE_MODES := LF_SAMYRUN LF_ICERUN LF_PROXBRUTE LF_HIDBRUTE LF_FOO
STANDALONE_MODES += HF_YOUNG HF_MATTYRUN HF_COLIN HF_BOG
```
Add your source code file like the following sample in the `armsrc\makefile`
## Update ARMSRC/MAKEFILE
Add your source code files like the following sample in the `armsrc/Makefile`
```
# WITH_HF_COLIN
ifneq (,$(findstring WITH_HF_COLIN,$(APP_CFLAGS)))
SRC_STANDALONE = hf_colin.c vtsend.c
else
SRC_STANDALONE =
# WITH_STANDALONE_LF_ICERUN
ifneq (,$(findstring WITH_STANDALONE_LF_ICERUN,$(APP_CFLAGS)))
SRC_STANDALONE = lf_icerun.c
endif
# WITH_STANDALONE_LF_FOO
ifneq (,$(findstring WITH_STANDALONE_LF_FOO,$(APP_CFLAGS)))
SRC_STANDALONE = lf_foo.c
endif
```
## Adding identification of your mode
Do please add a identification string in the function `printStandAloneModes` inside `armsrc\appmain.c`
This will enable an easy way to detect on client side which standalone mods has been installed on the device.
## Adding identification string of your mode
Do please add a identification string in a function called `ModInfo` inside your source code file.
This will enable an easy way to detect on client side which standalone mode has been installed on the device.
````
void ModInfo(void) {
DbpString(" LF good description of your mode - aka FooRun (your name)");
}
````
## Compiling your standalone mode
Once all this is done, you and others can now easily compile different standalone modes by just selecting one of the standalone modes (list in `common/Makefile.hal` or ) , e.g.:
- rename Makefile.platform.sample -> Makefile.platform
- edit the "STANDALONE" row inside Makefile.platform. You need to uncomment it and add your standalone mode name
Makefile.platform.sample
```
# If you want to use it, copy this file as Makefile.platform and adjust it to your needs
PLATFORM=PM3RDV4
#PLATFORM_EXTRAS=BTADDON
#STANDALONE=LF_SAMYRUN
```
becomes
Makefile.platform
```
# If you want to use it, copy this file as Makefile.platform and adjust it to your needs
PLATFORM=PM3RDV4
#PLATFORM_EXTRAS=BTADDON
STANDALONE=LF_FOO
```
#if defined(WITH_HF_COLIN)
DbpString(" HF Mifare ultra fast sniff/sim/clone - aka VIGIKPWN (Colin Brigato)");
#endif
````
Once all this is done, you and others can now easily compile different standalone modes by just swapping the -D directive in `armsrc\makefile`
Remember only one can be selected at a time for now.
````
#remove one of the following defines and comment out the relevant line
#in the next section to remove that particular feature from compilation.
# NO space,TABs after the "\" sign.
APP_CFLAGS = -DWITH_CRC \
-DON_DEVICE \
-DWITH_LF \
-DWITH_HITAG \
-DWITH_ISO15693 \
-DWITH_LEGICRF \
-DWITH_ISO14443b \
-DWITH_ISO14443a \
-DWITH_ICLASS \
-DWITH_FELICA \
-DWITH_FLASH \
-DWITH_SMARTCARD \
-DWITH_HFSNOOP \
-DWITH_HF_COLIN\
-DWITH_FPC \
-fno-strict-aliasing -ffunction-sections -fdata-sections
The final steps is to
- force recompilation of all code. ```make clean```
- compile ```make -j8```
- flash your device
- connect to your device
- press button long time to trigger ledshow and enter your new standalone mode
- if connected with usb / fpc , you can also see debug statements from your device in standalone mode. Useful for debugging :)
### IMPORTANT - move the commented variable below this line
# -DWITH_LCD \
# -DWITH_EMV \
# -DWITH_FPC \
#
# Standalone Mods
#-------------------------------------------------------
# -DWITH_LF_ICERUN
# -DWITH_LF_SAMYRUN
# -DWITH_LF_PROXBRUTE
# -DWITH_LF_HIDBRUTE
# -DWITH_HF_YOUNG
# -DWITH_HF_MATTYRUN
# -DWITH_HF_COLIN
````
When compiling you will see a header showing what configurations your project compiled with.
Make sure it says your standalone mode name.
Happy hacking!

View file

@ -14,6 +14,7 @@
#include <stdbool.h> // for bool
#include <inttypes.h> // PRIu64
extern void RunMod();
void RunMod();
void ModInfo();
#endif /* __STANDALONE_H */
#endif /* __STANDALONE_H */

View file

@ -672,20 +672,19 @@ static const unsigned int rcon[] = {
((unsigned int)(pt)[3]))
#define PUTU32(ct, st) { (ct)[0] = (unsigned char)((st) >> 24); \
(ct)[1] = (unsigned char)((st) >> 16); \
(ct)[2] = (unsigned char)((st) >> 8); \
(ct)[3] = (unsigned char)(st); }
(ct)[1] = (unsigned char)((st) >> 16); \
(ct)[2] = (unsigned char)((st) >> 8); \
(ct)[3] = (unsigned char)(st); }
/*
* Expand the cipher key into the encryption key schedule and return the
* number of rounds for the given cipher key size.
*/
int aes_setkey_enc(unsigned int rk[], const unsigned char cipherKey[], int keyBytes)
{
int aes_setkey_enc(unsigned int rk[], const unsigned char cipherKey[], int keyBytes) {
int i = 0;
unsigned int temp;
rk[0] = GETU32(cipherKey );
rk[0] = GETU32(cipherKey);
rk[1] = GETU32(cipherKey + 4);
rk[2] = GETU32(cipherKey + 8);
rk[3] = GETU32(cipherKey + 12);
@ -693,11 +692,11 @@ int aes_setkey_enc(unsigned int rk[], const unsigned char cipherKey[], int keyBy
for (;;) {
temp = rk[3];
rk[4] = rk[0] ^
(Te4[(temp >> 16) & 0xff] & 0xff000000) ^
(Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
(Te4[(temp ) & 0xff] & 0x0000ff00) ^
(Te4[(temp >> 24) ] & 0x000000ff) ^
rcon[i];
(Te4[(temp >> 16) & 0xff] & 0xff000000) ^
(Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
(Te4[(temp) & 0xff] & 0x0000ff00) ^
(Te4[(temp >> 24) ] & 0x000000ff) ^
rcon[i];
rk[5] = rk[1] ^ rk[4];
rk[6] = rk[2] ^ rk[5];
rk[7] = rk[3] ^ rk[6];
@ -713,11 +712,11 @@ int aes_setkey_enc(unsigned int rk[], const unsigned char cipherKey[], int keyBy
for (;;) {
temp = rk[ 5];
rk[ 6] = rk[ 0] ^
(Te4[(temp >> 16) & 0xff] & 0xff000000) ^
(Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
(Te4[(temp ) & 0xff] & 0x0000ff00) ^
(Te4[(temp >> 24) ] & 0x000000ff) ^
rcon[i];
(Te4[(temp >> 16) & 0xff] & 0xff000000) ^
(Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
(Te4[(temp) & 0xff] & 0x0000ff00) ^
(Te4[(temp >> 24) ] & 0x000000ff) ^
rcon[i];
rk[ 7] = rk[ 1] ^ rk[ 6];
rk[ 8] = rk[ 2] ^ rk[ 7];
rk[ 9] = rk[ 3] ^ rk[ 8];
@ -735,11 +734,11 @@ int aes_setkey_enc(unsigned int rk[], const unsigned char cipherKey[], int keyBy
for (;;) {
temp = rk[ 7];
rk[ 8] = rk[ 0] ^
(Te4[(temp >> 16) & 0xff] & 0xff000000) ^
(Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
(Te4[(temp ) & 0xff] & 0x0000ff00) ^
(Te4[(temp >> 24) ] & 0x000000ff) ^
rcon[i];
(Te4[(temp >> 16) & 0xff] & 0xff000000) ^
(Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
(Te4[(temp) & 0xff] & 0x0000ff00) ^
(Te4[(temp >> 24) ] & 0x000000ff) ^
rcon[i];
rk[ 9] = rk[ 1] ^ rk[ 8];
rk[10] = rk[ 2] ^ rk[ 9];
rk[11] = rk[ 3] ^ rk[10];
@ -748,10 +747,10 @@ int aes_setkey_enc(unsigned int rk[], const unsigned char cipherKey[], int keyBy
}
temp = rk[11];
rk[12] = rk[ 4] ^
(Te4[(temp >> 24) ] & 0xff000000) ^
(Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^
(Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^
(Te4[(temp ) & 0xff] & 0x000000ff);
(Te4[(temp >> 24) ] & 0xff000000) ^
(Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^
(Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^
(Te4[(temp) & 0xff] & 0x000000ff);
rk[13] = rk[ 5] ^ rk[12];
rk[14] = rk[ 6] ^ rk[13];
rk[15] = rk[ 7] ^ rk[14];
@ -766,8 +765,7 @@ int aes_setkey_enc(unsigned int rk[], const unsigned char cipherKey[], int keyBy
* Expand the cipher key into encryption and decryption key schedule and
* return the number of rounds for the given cipher key size.
*/
int AesGenKeySched(unsigned int rk[], unsigned int rrk[], const unsigned char cipherKey[], int keyBytes)
{
int AesGenKeySched(unsigned int rk[], unsigned int rrk[], const unsigned char cipherKey[], int keyBytes) {
int Nr, i;
// expand the cipher key
@ -779,10 +777,10 @@ int AesGenKeySched(unsigned int rk[], unsigned int rrk[], const unsigned char ci
rrk[2] = rk[2];
rrk[3] = rk[3];
/*
* apply the inverse MixColumn transform to all round keys but the first
* and the last
*/
/*
* apply the inverse MixColumn transform to all round keys but the first
* and the last
*/
for (i = 1; i < Nr; i++) {
rrk -= 4;
rk += 4;
@ -790,22 +788,22 @@ int AesGenKeySched(unsigned int rk[], unsigned int rrk[], const unsigned char ci
Td0[Te4[(rk[0] >> 24) ] & 0xff] ^
Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^
Td2[Te4[(rk[0] >> 8) & 0xff] & 0xff] ^
Td3[Te4[(rk[0] ) & 0xff] & 0xff];
Td3[Te4[(rk[0]) & 0xff] & 0xff];
rrk[1] =
Td0[Te4[(rk[1] >> 24) ] & 0xff] ^
Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^
Td2[Te4[(rk[1] >> 8) & 0xff] & 0xff] ^
Td3[Te4[(rk[1] ) & 0xff] & 0xff];
Td3[Te4[(rk[1]) & 0xff] & 0xff];
rrk[2] =
Td0[Te4[(rk[2] >> 24) ] & 0xff] ^
Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^
Td2[Te4[(rk[2] >> 8) & 0xff] & 0xff] ^
Td3[Te4[(rk[2] ) & 0xff] & 0xff];
Td3[Te4[(rk[2]) & 0xff] & 0xff];
rrk[3] =
Td0[Te4[(rk[3] >> 24) ] & 0xff] ^
Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^
Td2[Te4[(rk[3] >> 8) & 0xff] & 0xff] ^
Td3[Te4[(rk[3] ) & 0xff] & 0xff];
Td3[Te4[(rk[3]) & 0xff] & 0xff];
}
// invert the order of the last round keys
rrk -= 4;
@ -821,8 +819,7 @@ int AesGenKeySched(unsigned int rk[], unsigned int rrk[], const unsigned char ci
/*
* Encrypt the plain text into cipher
*/
void AesEncBlk(AesCtx *pCtx, const unsigned char pt[], unsigned char ct[])
{
void AesEncBlk(AesCtx *pCtx, const unsigned char pt[], unsigned char ct[]) {
unsigned int s0, s1, s2, s3, t0, t1, t2, t3, *iv;
const unsigned int *rk;
int r;
@ -833,7 +830,7 @@ void AesEncBlk(AesCtx *pCtx, const unsigned char pt[], unsigned char ct[])
* map byte array block to cipher state
* and add initial round key:
*/
s0 = GETU32(pt ) ^ rk[0];
s0 = GETU32(pt) ^ rk[0];
s1 = GETU32(pt + 4) ^ rk[1];
s2 = GETU32(pt + 8) ^ rk[2];
s3 = GETU32(pt + 12) ^ rk[3];
@ -852,25 +849,25 @@ void AesEncBlk(AesCtx *pCtx, const unsigned char pt[], unsigned char ct[])
Te0[(s0 >> 24) ] ^
Te1[(s1 >> 16) & 0xff] ^
Te2[(s2 >> 8) & 0xff] ^
Te3[(s3 ) & 0xff] ^
Te3[(s3) & 0xff] ^
rk[4];
t1 =
Te0[(s1 >> 24) ] ^
Te1[(s2 >> 16) & 0xff] ^
Te2[(s3 >> 8) & 0xff] ^
Te3[(s0 ) & 0xff] ^
Te3[(s0) & 0xff] ^
rk[5];
t2 =
Te0[(s2 >> 24) ] ^
Te1[(s3 >> 16) & 0xff] ^
Te2[(s0 >> 8) & 0xff] ^
Te3[(s1 ) & 0xff] ^
Te3[(s1) & 0xff] ^
rk[6];
t3 =
Te0[(s3 >> 24) ] ^
Te1[(s0 >> 16) & 0xff] ^
Te2[(s1 >> 8) & 0xff] ^
Te3[(s2 ) & 0xff] ^
Te3[(s2) & 0xff] ^
rk[7];
rk += 8;
@ -882,25 +879,25 @@ void AesEncBlk(AesCtx *pCtx, const unsigned char pt[], unsigned char ct[])
Te0[(t0 >> 24) ] ^
Te1[(t1 >> 16) & 0xff] ^
Te2[(t2 >> 8) & 0xff] ^
Te3[(t3 ) & 0xff] ^
Te3[(t3) & 0xff] ^
rk[0];
s1 =
Te0[(t1 >> 24) ] ^
Te1[(t2 >> 16) & 0xff] ^
Te2[(t3 >> 8) & 0xff] ^
Te3[(t0 ) & 0xff] ^
Te3[(t0) & 0xff] ^
rk[1];
s2 =
Te0[(t2 >> 24) ] ^
Te1[(t3 >> 16) & 0xff] ^
Te2[(t0 >> 8) & 0xff] ^
Te3[(t1 ) & 0xff] ^
Te3[(t1) & 0xff] ^
rk[2];
s3 =
Te0[(t3 >> 24) ] ^
Te1[(t0 >> 16) & 0xff] ^
Te2[(t1 >> 8) & 0xff] ^
Te3[(t2 ) & 0xff] ^
Te3[(t2) & 0xff] ^
rk[3];
}
/*
@ -911,28 +908,28 @@ void AesEncBlk(AesCtx *pCtx, const unsigned char pt[], unsigned char ct[])
(Te4[(t0 >> 24) ] & 0xff000000) ^
(Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
(Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
(Te4[(t3 ) & 0xff] & 0x000000ff) ^
(Te4[(t3) & 0xff] & 0x000000ff) ^
rk[0];
PUTU32(ct , s0);
PUTU32(ct, s0);
s1 =
(Te4[(t1 >> 24) ] & 0xff000000) ^
(Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
(Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^
(Te4[(t0 ) & 0xff] & 0x000000ff) ^
(Te4[(t0) & 0xff] & 0x000000ff) ^
rk[1];
PUTU32(ct + 4, s1);
s2 =
(Te4[(t2 >> 24) ] & 0xff000000) ^
(Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
(Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
(Te4[(t1 ) & 0xff] & 0x000000ff) ^
(Te4[(t1) & 0xff] & 0x000000ff) ^
rk[2];
PUTU32(ct + 8, s2);
s3 =
(Te4[(t3 >> 24) ] & 0xff000000) ^
(Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
(Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^
(Te4[(t2 ) & 0xff] & 0x000000ff) ^
(Te4[(t2) & 0xff] & 0x000000ff) ^
rk[3];
PUTU32(ct + 12, s3);
@ -947,8 +944,7 @@ void AesEncBlk(AesCtx *pCtx, const unsigned char pt[], unsigned char ct[])
/*
* Decrypt the cipher into plain text
*/
void AesDecBlk(AesCtx *pCtx, const unsigned char ct[], unsigned char pt[])
{
void AesDecBlk(AesCtx *pCtx, const unsigned char ct[], unsigned char pt[]) {
unsigned int s0, s1, s2, s3, t0, t1, t2, t3, v0, v1, v2, v3, *iv;
const unsigned int *rk;
int r;
@ -959,10 +955,14 @@ void AesDecBlk(AesCtx *pCtx, const unsigned char ct[], unsigned char pt[])
* map byte array block to cipher state
* and add initial round key:
*/
v0 = GETU32(ct ); s0 = v0 ^ rk[0];
v1 = GETU32(ct + 4); s1 = v1 ^ rk[1];
v2 = GETU32(ct + 8); s2 = v2 ^ rk[2];
v3 = GETU32(ct + 12); s3 = v3 ^ rk[3];
v0 = GETU32(ct);
s0 = v0 ^ rk[0];
v1 = GETU32(ct + 4);
s1 = v1 ^ rk[1];
v2 = GETU32(ct + 8);
s2 = v2 ^ rk[2];
v3 = GETU32(ct + 12);
s3 = v3 ^ rk[3];
/*
* Nr - 1 full rounds:
*/
@ -972,25 +972,25 @@ void AesDecBlk(AesCtx *pCtx, const unsigned char ct[], unsigned char pt[])
Td0[(s0 >> 24) ] ^
Td1[(s3 >> 16) & 0xff] ^
Td2[(s2 >> 8) & 0xff] ^
Td3[(s1 ) & 0xff] ^
Td3[(s1) & 0xff] ^
rk[4];
t1 =
Td0[(s1 >> 24) ] ^
Td1[(s0 >> 16) & 0xff] ^
Td2[(s3 >> 8) & 0xff] ^
Td3[(s2 ) & 0xff] ^
Td3[(s2) & 0xff] ^
rk[5];
t2 =
Td0[(s2 >> 24) ] ^
Td1[(s1 >> 16) & 0xff] ^
Td2[(s0 >> 8) & 0xff] ^
Td3[(s3 ) & 0xff] ^
Td3[(s3) & 0xff] ^
rk[6];
t3 =
Td0[(s3 >> 24) ] ^
Td1[(s2 >> 16) & 0xff] ^
Td2[(s1 >> 8) & 0xff] ^
Td3[(s0 ) & 0xff] ^
Td3[(s0) & 0xff] ^
rk[7];
rk += 8;
@ -1002,25 +1002,25 @@ void AesDecBlk(AesCtx *pCtx, const unsigned char ct[], unsigned char pt[])
Td0[(t0 >> 24) ] ^
Td1[(t3 >> 16) & 0xff] ^
Td2[(t2 >> 8) & 0xff] ^
Td3[(t1 ) & 0xff] ^
Td3[(t1) & 0xff] ^
rk[0];
s1 =
Td0[(t1 >> 24) ] ^
Td1[(t0 >> 16) & 0xff] ^
Td2[(t3 >> 8) & 0xff] ^
Td3[(t2 ) & 0xff] ^
Td3[(t2) & 0xff] ^
rk[1];
s2 =
Td0[(t2 >> 24) ] ^
Td1[(t1 >> 16) & 0xff] ^
Td2[(t0 >> 8) & 0xff] ^
Td3[(t3 ) & 0xff] ^
Td3[(t3) & 0xff] ^
rk[2];
s3 =
Td0[(t3 >> 24) ] ^
Td1[(t2 >> 16) & 0xff] ^
Td2[(t1 >> 8) & 0xff] ^
Td3[(t0 ) & 0xff] ^
Td3[(t0) & 0xff] ^
rk[3];
}
/*
@ -1031,35 +1031,39 @@ void AesDecBlk(AesCtx *pCtx, const unsigned char ct[], unsigned char pt[])
(Td4[(t0 >> 24) ] & 0xff000000) ^
(Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
(Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
(Td4[(t1 ) & 0xff] & 0x000000ff) ^
(Td4[(t1) & 0xff] & 0x000000ff) ^
rk[0];
s1 =
(Td4[(t1 >> 24) ] & 0xff000000) ^
(Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
(Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^
(Td4[(t2 ) & 0xff] & 0x000000ff) ^
(Td4[(t2) & 0xff] & 0x000000ff) ^
rk[1];
s2 =
(Td4[(t2 >> 24) ] & 0xff000000) ^
(Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
(Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
(Td4[(t3 ) & 0xff] & 0x000000ff) ^
(Td4[(t3) & 0xff] & 0x000000ff) ^
rk[2];
s3 =
(Td4[(t3 >> 24) ] & 0xff000000) ^
(Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
(Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^
(Td4[(t0 ) & 0xff] & 0x000000ff) ^
(Td4[(t0) & 0xff] & 0x000000ff) ^
rk[3];
if (pCtx->Mode) {
s0 = s0 ^ iv[0]; iv[0] = v0;
s1 = s1 ^ iv[1]; iv[1] = v1;
s2 = s2 ^ iv[2]; iv[2] = v2;
s3 = s3 ^ iv[3]; iv[3] = v3;
s0 = s0 ^ iv[0];
iv[0] = v0;
s1 = s1 ^ iv[1];
iv[1] = v1;
s2 = s2 ^ iv[2];
iv[2] = v2;
s3 = s3 ^ iv[3];
iv[3] = v3;
}
PUTU32(pt , s0);
PUTU32(pt, s0);
PUTU32(pt + 4, s1);
PUTU32(pt + 8, s2);
PUTU32(pt + 12, s3);
@ -1072,8 +1076,7 @@ void AesDecBlk(AesCtx *pCtx, const unsigned char ct[], unsigned char pt[])
/*
* initialize AES context
*/
int AesCtxIni(AesCtx *pCtx, unsigned char *pIV, unsigned char *pKey, unsigned int KeyLen, unsigned char Mode)
{
int AesCtxIni(AesCtx *pCtx, unsigned char *pIV, unsigned char *pKey, unsigned int KeyLen, unsigned char Mode) {
if (pKey == 0 || pCtx == 0 || (KeyLen != KEY128 && KeyLen != KEY192 && KeyLen != KEY256))
return -1;
@ -1082,9 +1085,9 @@ int AesCtxIni(AesCtx *pCtx, unsigned char *pIV, unsigned char *pKey, unsigned in
// initialize IV
if (pIV != 0) {
pCtx->Iv[0] = GETU32(pIV );
pCtx->Iv[1] = GETU32(pIV + 4 );
pCtx->Iv[2] = GETU32(pIV + 8 );
pCtx->Iv[0] = GETU32(pIV);
pCtx->Iv[1] = GETU32(pIV + 4);
pCtx->Iv[2] = GETU32(pIV + 8);
pCtx->Iv[3] = GETU32(pIV + 12);
}
@ -1097,8 +1100,7 @@ int AesCtxIni(AesCtx *pCtx, unsigned char *pIV, unsigned char *pKey, unsigned in
/*
* Encrypt plain text
*/
int AesEncrypt(AesCtx *pCtx, unsigned char *pData, unsigned char *pCipher, unsigned int DataLen)
{
int AesEncrypt(AesCtx *pCtx, unsigned char *pData, unsigned char *pCipher, unsigned int DataLen) {
int i;
if (pData == 0 || pCipher == 0 || pCtx == 0 || (DataLen & 0xf) != 0)
@ -1116,8 +1118,7 @@ int AesEncrypt(AesCtx *pCtx, unsigned char *pData, unsigned char *pCipher, unsig
/*
* Decrypt cipher
*/
int AesDecrypt(AesCtx *pCtx, unsigned char *pCipher, unsigned char *pData, unsigned int CipherLen)
{
int AesDecrypt(AesCtx *pCtx, unsigned char *pCipher, unsigned char *pData, unsigned int CipherLen) {
int i;
if (pData == 0 || pCipher == 0 || pCtx == 0 || (CipherLen & 0xf) != 0)
@ -1140,8 +1141,7 @@ int AesDecrypt(AesCtx *pCtx, unsigned char *pCipher, unsigned char *pData, unsig
#include <stdio.h>
int main()
{
int main() {
AesCtx ctx;
unsigned char iv[] = "INI VECTINI VECT";
unsigned char key[] = "This is a sample AESKey";
@ -1149,22 +1149,22 @@ int main()
// initialize context and encrypt data at one end
if( AesCtxIni(&ctx, iv, key, KEY128, CBC) < 0)
if (AesCtxIni(&ctx, iv, key, KEY128, CBC) < 0)
printf("init error\n");
if (AesEncrypt(&ctx, databuf, databuf, sizeof(databuf) ) < 0)
if (AesEncrypt(&ctx, databuf, databuf, sizeof(databuf)) < 0)
printf("error in encryption\n");
// initialize context and decrypt cipher at other end
if( AesCtxIni(&ctx, iv, key, KEY128, CBC) < 0)
if (AesCtxIni(&ctx, iv, key, KEY128, CBC) < 0)
printf("init error\n");
if (AesDecrypt(&ctx, databuf, databuf, sizeof(databuf) ) < 0)
if (AesDecrypt(&ctx, databuf, databuf, sizeof(databuf)) < 0)
printf("error in decryption\n");
printf("%s\n", databuf);
return 0;
}
#endif
#endif

View file

@ -8,11 +8,11 @@
// AES context structure
typedef struct {
unsigned int Ek[60];
unsigned int Dk[60];
unsigned int Iv[4];
unsigned char Nr;
unsigned char Mode;
unsigned int Ek[60];
unsigned int Dk[60];
unsigned int Iv[4];
unsigned char Nr;
unsigned char Mode;
} AesCtx;
// key length in bytes
@ -31,4 +31,4 @@ int AesCtxIni(AesCtx *pCtx, unsigned char *pIV, unsigned char *pKey, unsigned in
int AesEncrypt(AesCtx *pCtx, unsigned char *pData, unsigned char *pCipher, unsigned int DataLen);
int AesDecrypt(AesCtx *pCtx, unsigned char *pCipher, unsigned char *pData, unsigned int CipherLen);
#endif
#endif

File diff suppressed because it is too large Load diff

View file

@ -34,7 +34,6 @@ extern "C" {
extern const uint8_t OddByteParity[256];
extern int rsamples; // = 0;
extern int tracing; // = TRUE;
extern uint8_t trigger;
// This may be used (sparingly) to declare a function to be copied to
@ -46,8 +45,9 @@ void ReadMem(int addr);
void __attribute__((noreturn)) AppMain(void);
//void DbpIntegers(int a, int b, int c);
void DbpString(char *str);
void DbpStringEx(uint32_t flags, char *str);
void Dbprintf(const char *fmt, ...);
void DbprintfEx(uint32_t cmd, const char *fmt, ...);
void DbprintfEx(uint32_t flags, const char *fmt, ...);
void Dbhexdump(int len, uint8_t *d, bool bAsci);
// ADC Vref = 3300mV, and an (10M+1M):1M voltage divider on the HF input can measure voltages up to 36300 mV
@ -59,15 +59,15 @@ void Dbhexdump(int len, uint8_t *d, bool bAsci);
uint16_t AvgAdc(int ch);
void print_result(char *name, uint8_t *buf, size_t len);
void PrintToSendBuffer(void);
//void PrintToSendBuffer(void);
void ToSendStuffBit(int b);
void ToSendReset(void);
void ListenReaderField(int limit);
void ListenReaderField(uint8_t limit);
extern int ToSendMax;
extern uint8_t ToSend[];
extern void StandAloneMode(void);
extern void printStandAloneModes(void);
void StandAloneMode(void);
void printStandAloneModes(void);
/// lfops.h
extern uint8_t decimation;
@ -81,14 +81,17 @@ void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc);
void AcquireTiType(void);
void AcquireRawBitsTI(void);
void SimulateTagLowFrequencyEx(int period, int gap, int ledcontrol, int numcycles);
void SimulateTagLowFrequency(int period, int gap, int ledcontrol);
void SimulateTagLowFrequencyEx(int period, int gap, bool ledcontrol, int numcycles);
void SimulateTagLowFrequency(int period, int gap, bool ledcontrol);
void SimulateTagLowFrequencyBidir(int divisor, int max_bitlen);
void CmdHIDsimTAGEx(uint32_t hi, uint32_t lo, int ledcontrol, int numcycles);
void CmdHIDsimTAG(uint32_t hi, uint32_t lo, int ledcontrol);
void CmdFSKsimTAG(uint16_t arg1, uint16_t arg2, size_t size, uint8_t *BitStream);
void CmdASKsimTag(uint16_t arg1, uint16_t arg2, size_t size, uint8_t *BitStream);
void CmdPSKsimTag(uint16_t arg1, uint16_t arg2, size_t size, uint8_t *BitStream);
void CmdHIDsimTAGEx(uint32_t hi, uint32_t lo, bool ledcontrol, int numcycles);
void CmdHIDsimTAG(uint32_t hi, uint32_t lo, bool ledcontrol);
void CmdFSKsimTAG(uint8_t fchigh, uint8_t fclow, uint8_t separator, uint8_t clk, uint16_t bitslen, uint8_t *bits, bool ledcontrol);
void CmdASKsimTAG(uint8_t encoding, uint8_t invert, uint8_t separator, uint8_t clk, uint16_t size, uint8_t *bits, bool ledcontrol);
void CmdPSKsimTag(uint8_t carrier, uint8_t invert, uint8_t clk, uint16_t size, uint8_t *bits, bool ledcontrol);
void CmdHIDdemodFSK(int findone, uint32_t *high, uint32_t *low, int ledcontrol);
void CmdAWIDdemodFSK(int findone, uint32_t *high, uint32_t *low, int ledcontrol); // Realtime demodulation mode for AWID26
void CmdEM410xdemod(int findone, uint32_t *high, uint64_t *low, int ledcontrol);
@ -100,14 +103,22 @@ void WriteEM410x(uint32_t card, uint32_t id_hi, uint32_t id_lo);
void CopyIndala64toT55x7(uint32_t hi, uint32_t lo); // Clone Indala 64-bit tag by UID to T55x7
void CopyIndala224toT55x7(uint32_t uid1, uint32_t uid2, uint32_t uid3, uint32_t uid4, uint32_t uid5, uint32_t uid6, uint32_t uid7); // Clone Indala 224-bit tag by UID to T55x7
void T55xxResetRead(void);
void T55xxWriteBlock(uint32_t Data, uint8_t Block, uint32_t Pwd, uint8_t PwdMode);
void T55xxWriteBlockExt(uint32_t Data, uint8_t Block, uint32_t Pwd, uint8_t PwdMode);
void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd);
void T55xxWriteBlock(uint8_t *data);
void T55xxWriteBlockExt(uint32_t data, uint8_t blockno, uint32_t pwd, uint8_t flags);
void T55xxReadBlock(uint8_t page, bool pwd_mode, bool brute_mem, uint8_t block, uint32_t pwd);
void T55xxWakeUp(uint32_t Pwd);
void T55xx_ChkPwds(void);
void TurnReadLFOn(uint32_t delay);
void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd);
void EM4xWriteWord(uint32_t flag, uint32_t data, uint32_t pwd);
void EM4xWriteWord(uint8_t addr, uint32_t data, uint32_t pwd, uint8_t usepwd);
void Cotag(uint32_t arg0);
void setT55xxConfig(uint8_t arg0, t55xx_config *c);
t55xx_config *getT55xxConfig(void);
void printT55xxConfig(void);
void loadT55xxConfig(void);
/// iso14443b.h
void SimulateIso14443bTag(uint32_t pupi);
@ -115,132 +126,123 @@ void AcquireRawAdcSamplesIso14443b(uint32_t parameter);
void ReadSTMemoryIso14443b(uint8_t numofblocks);
void RAMFUNC SniffIso14443b(void);
void SendRawCommand14443B(uint32_t, uint32_t, uint8_t, uint8_t[]);
void SendRawCommand14443B_Ex(UsbCommand *c);
void SendRawCommand14443B_Ex(PacketCommandNG *c);
void ClearFpgaShiftingRegisters(void);
// iso14443a.h
void RAMFUNC SniffIso14443a(uint8_t param);
void SimulateIso14443aTag(int tagType, int flags, uint8_t *data);
void ReaderIso14443a(UsbCommand *c);
void ReaderIso14443a(PacketCommandNG *c);
// Also used in iclass.c
//bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t len, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag);
void GetParity(const uint8_t *pbtCmd, uint16_t len, uint8_t *parity);
void GetParity(const uint8_t *pbtCmd, uint16_t len, uint8_t *par);
void iso14a_set_trigger(bool enable);
// also used in emv
bool prepare_allocated_tag_modulation(tag_response_info_t * response_info);
int GetIso14443aCommandFromReader(uint8_t *received, uint8_t *parity, int *len);
//bool prepare_allocated_tag_modulation(tag_response_info_t *response_info);
//int GetIso14443aCommandFromReader(uint8_t *received, uint8_t *parity, int *len);
// epa.h
void EPA_PACE_Collect_Nonce(UsbCommand * c);
void EPA_PACE_Replay(UsbCommand *c);
void EPA_PACE_Collect_Nonce(PacketCommandNG *c);
void EPA_PACE_Replay(PacketCommandNG *c);
// mifarecmd.h
void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *data);
void MifareReadBlock(uint8_t blockNo, uint8_t keyType, uint8_t *datain);
void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain);
void MifareUC_Auth(uint8_t arg0, uint8_t *datain);
void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes);
void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain);
void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t *datain);
void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain);
//void MifareUWriteBlockCompat(uint8_t arg0,uint8_t *datain);
void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain);
void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain);
void MifareAcquireNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain);
void MifareChkKeys(uint16_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
void MifareAcquireNonces(uint32_t arg0, uint32_t flags);
void MifareChkKeys(uint8_t *datain);
void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
void MifareSetDbgLvl(uint16_t arg0);
void MifareEMemClr(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareEMemSet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareEMemGet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareEMemClr(void);
void MifareEMemSet(uint8_t blockno, uint8_t blockcnt, uint8_t blockwidth, uint8_t *datain);
void MifareEMemGet(uint8_t blockno, uint8_t blockcnt);
int MifareECardLoad(uint32_t arg0, uint32_t arg1);
void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain); // Work with "magic Chinese" card
void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain);
void MifareCIdent(); // is "magic chinese" card?
void MifareSetMod(uint8_t mod, uint8_t *key);
void MifareSetMod(uint8_t *datain);
void MifareUSetPwd(uint8_t arg0, uint8_t *datain);
void OnSuccessMagic();
void OnErrorMagic(uint8_t reason);
int32_t dist_nt(uint32_t nt1, uint32_t nt2);
void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype );
void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype);
//void RAMFUNC SniffMifare(uint8_t param);
//desfire
void Mifare_DES_Auth1(uint8_t arg0,uint8_t *datain);
void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain);
void Mifare_DES_Auth1(uint8_t arg0, uint8_t *datain);
void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain);
// mifaredesfire.h
bool InitDesfireCard();
void MifareSendCommand(uint8_t arg0,uint8_t arg1, uint8_t *datain);
void MifareSendCommand(uint8_t arg0, uint8_t arg1, uint8_t *datain);
void MifareDesfireGetInformation();
void MifareDES_Auth1(uint8_t arg0,uint8_t arg1,uint8_t arg2, uint8_t *datain);
void ReaderMifareDES(uint32_t param, uint32_t param2, uint8_t * datain);
void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
void ReaderMifareDES(uint32_t param, uint32_t param2, uint8_t *datain);
int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout);
size_t CreateAPDU( uint8_t *datain, size_t len, uint8_t *dataout);
size_t CreateAPDU(uint8_t *datain, size_t len, uint8_t *dataout);
void OnSuccess();
void OnError(uint8_t reason);
// desfire_crypto.h
void *mifare_cryto_preprocess_data (desfiretag_t tag, void *data, size_t *nbytes, size_t offset, int communication_settings);
void *mifare_cryto_postprocess_data (desfiretag_t tag, void *data, size_t *nbytes, int communication_settings);
void mifare_cypher_single_block (desfirekey_t key, uint8_t *data, uint8_t *ivect, MifareCryptoDirection direction, MifareCryptoOperation operation, size_t block_size);
void mifare_cypher_blocks_chained (desfiretag_t tag, desfirekey_t key, uint8_t *ivect, uint8_t *data, size_t data_size, MifareCryptoDirection direction, MifareCryptoOperation operation);
size_t key_block_size (const desfirekey_t key);
size_t padded_data_length (const size_t nbytes, const size_t block_size);
size_t maced_data_length (const desfirekey_t key, const size_t nbytes);
size_t enciphered_data_length (const desfiretag_t tag, const size_t nbytes, int communication_settings);
void cmac_generate_subkeys (desfirekey_t key);
void cmac (const desfirekey_t key, uint8_t *ivect, const uint8_t *data, size_t len, uint8_t *cmac);
void *mifare_cryto_preprocess_data(desfiretag_t tag, void *data, size_t *nbytes, size_t offset, int communication_settings);
void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes, int communication_settings);
void mifare_cypher_single_block(desfirekey_t key, uint8_t *data, uint8_t *ivect, MifareCryptoDirection direction, MifareCryptoOperation operation, size_t block_size);
void mifare_cypher_blocks_chained(desfiretag_t tag, desfirekey_t key, uint8_t *ivect, uint8_t *data, size_t data_size, MifareCryptoDirection direction, MifareCryptoOperation operation);
size_t key_block_size(const desfirekey_t key);
size_t padded_data_length(const size_t nbytes, const size_t block_size);
size_t maced_data_length(const desfirekey_t key, const size_t nbytes);
size_t enciphered_data_length(const desfiretag_t tag, const size_t nbytes, int communication_settings);
void cmac_generate_subkeys(desfirekey_t key);
void cmac(const desfirekey_t key, uint8_t *ivect, const uint8_t *data, size_t len, uint8_t *cmac);
// iso15693.h
void RecordRawAdcSamplesIso15693(void);
void AcquireRawAdcSamplesIso15693(void);
void ReaderIso15693(uint32_t parameter); // Simulate an ISO15693 reader - greg
void SimTagIso15693(uint32_t parameter, uint8_t *uid); // simulate an ISO15693 tag - greg
void ReaderIso15693(uint32_t parameter); // Simulate an ISO15693 reader - greg
void SimTagIso15693(uint32_t parameter, uint8_t *uid); // simulate an ISO15693 tag - greg
void BruteforceIso15693Afi(uint32_t speed); // find an AFI of a tag - atrox
void DirectTag15693Command(uint32_t datalen,uint32_t speed, uint32_t recv, uint8_t *data); // send arbitrary commands from CLI - atrox
void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint8_t *data); // send arbitrary commands from CLI - atrox
void Iso15693InitReader(void);
// iclass.h
void RAMFUNC SniffIClass(void);
void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void ReaderIClass(uint8_t arg0);
void ReaderIClass_Replay(uint8_t arg0,uint8_t *MAC);
void iClass_Authentication(uint8_t *MAC);
void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac);
void iClass_Authentication(uint8_t *mac);
void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain);
void iClass_WriteBlock(uint8_t blockNo, uint8_t *data);
void iClass_ReadBlk(uint8_t blockNo);
bool iClass_ReadBlock(uint8_t blockNo, uint8_t *data, uint8_t datalen);
void iClass_WriteBlock(uint8_t blockno, uint8_t *data);
void iClass_ReadBlk(uint8_t blockno);
bool iClass_ReadBlock(uint8_t blockno, uint8_t *data, uint8_t len);
void iClass_Dump(uint8_t blockno, uint8_t numblks);
void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data);
void iClass_ReadCheck(uint8_t blockNo, uint8_t keyType);
// hitag2.h
void SnoopHitag(uint32_t type);
void SimulateHitagTag(bool tag_mem_supplied, byte_t* data);
void ReaderHitag(hitag_function htf, hitag_data* htd);
void WriterHitag(hitag_function htf, hitag_data* htd, int page);
//hitagS.h
void SimulateHitagSTag(bool tag_mem_supplied, byte_t* data);
void ReadHitagS(hitag_function htf, hitag_data* htd);
void WritePageHitagS(hitag_function htf, hitag_data* htd,int page);
void check_challenges(bool file_given, byte_t* data);
void iClass_ReadCheck(uint8_t blockno, uint8_t keytype);
// cmd.h
bool cmd_receive(UsbCommand* cmd);
bool cmd_send(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, void* data, size_t len);
int reply_old(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, void *data, size_t len);
int reply_mix(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, void *data, size_t len);
int reply_ng(uint16_t cmd, int16_t status, uint8_t *data, size_t len);
int receive_ng(PacketCommandNG *rx);
// util.h
void HfSnoop(int , int);
void HfSniff(int, int);
//felica.c
extern void felica_sendraw(UsbCommand *c);
extern void felica_sniff(uint32_t samples, uint32_t triggers);
extern void felica_sim_lite(uint64_t uid);
extern void felica_dump_lite_s();
void felica_sendraw(PacketCommandNG *c);
void felica_sniff(uint32_t samplesToSkip, uint32_t triggersToSkip);
void felica_sim_lite(uint64_t uid);
void felica_dump_lite_s();
#ifdef __cplusplus

View file

@ -1,86 +1,86 @@
#include "buzzer.h"
void Ring_BEE_ONCE(uint16_t music_note) {
void Ring_BEE_ONCE(uint16_t music_note) {
BEE_ON();
SpinDelayUs(music_note);
BEE_OFF();
SpinDelayUs(music_note);
SpinDelayUs(music_note);
BEE_OFF();
SpinDelayUs(music_note);
}
void ring_2_7khz(uint16_t count) {
Ring_BEE_TIME(n_2_7khz,count);
Ring_BEE_TIME(n_2_7khz, count);
}
void Ring_BEE_TIME(uint16_t music_note,uint16_t count) {
for(uint16_t i=0 ; i < count; i++)
Ring_BEE_ONCE(music_note);
SpinDelay(9);
void Ring_BEE_TIME(uint16_t music_note, uint16_t count) {
for (uint16_t i = 0 ; i < count; i++)
Ring_BEE_ONCE(music_note);
SpinDelay(9);
}
void Ring_ALL(uint16_t count) {
Ring_BEE_TIME(note_1, count);
Ring_BEE_TIME(note_2, count);
Ring_BEE_TIME(note_3, count);
Ring_BEE_TIME(note_4, count);
Ring_BEE_TIME(note_5, count);
Ring_BEE_TIME(note_6, count);
Ring_BEE_TIME(note_7, count);
SpinDelay(10);
Ring_BEE_TIME(note_1, count);
Ring_BEE_TIME(note_2, count);
Ring_BEE_TIME(note_3, count);
Ring_BEE_TIME(note_4, count);
Ring_BEE_TIME(note_5, count);
Ring_BEE_TIME(note_6, count);
Ring_BEE_TIME(note_7, count);
SpinDelay(10);
}
void Ring_Little_Star(uint16_t count) {
Ring_BEE_TIME(note_1,count);
Ring_BEE_TIME(note_1,count);
Ring_BEE_TIME(note_5,count);
Ring_BEE_TIME(note_5,count);
Ring_BEE_TIME(note_6,count);
Ring_BEE_TIME(note_6,count);
Ring_BEE_TIME(note_5,2*count);
LED_A_ON();
/*
Ring_BEE_TIME(note_4,count);
Ring_BEE_TIME(note_4,count);
Ring_BEE_TIME(note_3,count);
Ring_BEE_TIME(note_3,count);
Ring_BEE_TIME(note_2,count);
Ring_BEE_TIME(note_2,count);
Ring_BEE_TIME(note_1,2*count);
LED_A_OFF();
void Ring_Little_Star(uint16_t count) {
Ring_BEE_TIME(note_1, count);
Ring_BEE_TIME(note_1, count);
Ring_BEE_TIME(note_5, count);
Ring_BEE_TIME(note_5, count);
Ring_BEE_TIME(note_6, count);
Ring_BEE_TIME(note_6, count);
Ring_BEE_TIME(note_5, 2 * count);
LED_A_ON();
/*
Ring_BEE_TIME(note_4,count);
Ring_BEE_TIME(note_4,count);
Ring_BEE_TIME(note_3,count);
Ring_BEE_TIME(note_3,count);
Ring_BEE_TIME(note_2,count);
Ring_BEE_TIME(note_2,count);
Ring_BEE_TIME(note_1,2*count);
LED_A_OFF();
Ring_BEE_TIME(note_5,count);
Ring_BEE_TIME(note_5,count);
Ring_BEE_TIME(note_4,count);
Ring_BEE_TIME(note_4,count);
Ring_BEE_TIME(note_3,count);
Ring_BEE_TIME(note_3,count);
Ring_BEE_TIME(note_2,2*count);
LED_A_ON();
Ring_BEE_TIME(note_5,count);
Ring_BEE_TIME(note_5,count);
Ring_BEE_TIME(note_4,count);
Ring_BEE_TIME(note_4,count);
Ring_BEE_TIME(note_3,count);
Ring_BEE_TIME(note_3,count);
Ring_BEE_TIME(note_2,2*count);
LED_A_ON();
Ring_BEE_TIME(note_5,count);
Ring_BEE_TIME(note_5,count);
Ring_BEE_TIME(note_4,count);
Ring_BEE_TIME(note_4,count);
Ring_BEE_TIME(note_3,count);
Ring_BEE_TIME(note_3,count);
Ring_BEE_TIME(note_2,2*count);
LED_A_OFF();
Ring_BEE_TIME(note_5,count);
Ring_BEE_TIME(note_5,count);
Ring_BEE_TIME(note_4,count);
Ring_BEE_TIME(note_4,count);
Ring_BEE_TIME(note_3,count);
Ring_BEE_TIME(note_3,count);
Ring_BEE_TIME(note_2,2*count);
LED_A_OFF();
Ring_BEE_TIME(note_1,count);
Ring_BEE_TIME(note_1,count);
Ring_BEE_TIME(note_5,count);
Ring_BEE_TIME(note_5,count);
Ring_BEE_TIME(note_6,count);
Ring_BEE_TIME(note_6,count);
Ring_BEE_TIME(note_5,2*count);
LED_A_ON();
Ring_BEE_TIME(note_1,count);
Ring_BEE_TIME(note_1,count);
Ring_BEE_TIME(note_5,count);
Ring_BEE_TIME(note_5,count);
Ring_BEE_TIME(note_6,count);
Ring_BEE_TIME(note_6,count);
Ring_BEE_TIME(note_5,2*count);
LED_A_ON();
Ring_BEE_TIME(note_4,count);
Ring_BEE_TIME(note_4,count);
Ring_BEE_TIME(note_3,count);
Ring_BEE_TIME(note_3,count);
Ring_BEE_TIME(note_2,count);
Ring_BEE_TIME(note_2,count);
Ring_BEE_TIME(note_1,2*count);
LED_B_ON();
*/
}
Ring_BEE_TIME(note_4,count);
Ring_BEE_TIME(note_4,count);
Ring_BEE_TIME(note_3,count);
Ring_BEE_TIME(note_3,count);
Ring_BEE_TIME(note_2,count);
Ring_BEE_TIME(note_2,count);
Ring_BEE_TIME(note_1,2*count);
LED_B_ON();
*/
}

View file

@ -20,11 +20,11 @@
#define note_7 506
#define note_8 0
extern void Ring_BEE_ONCE(uint16_t music_note);
extern void Ring_BEE_TIME(uint16_t music_note,uint16_t count);
extern void ring_2_7khz(uint16_t count);
extern void Ring_ALL(uint16_t count);
extern void Ring_Little_Star(uint16_t count);
void Ring_BEE_ONCE(uint16_t music_note);
void Ring_BEE_TIME(uint16_t music_note, uint16_t count);
void ring_2_7khz(uint16_t count);
void Ring_ALL(uint16_t count);
void Ring_Little_Star(uint16_t count);
#endif

View file

@ -22,161 +22,161 @@
* \email daniel.otte@rub.de
* \date 2007-06-16
* \brief DES and EDE-DES implementation
* \license GPLv3 or later
*
* \license GPLv3 or later
*
*/
#include "des.h"
const uint8_t sbox[256] = {
/* S-box 1 */
0xE4, 0xD1, 0x2F, 0xB8, 0x3A, 0x6C, 0x59, 0x07,
0x0F, 0x74, 0xE2, 0xD1, 0xA6, 0xCB, 0x95, 0x38,
0x41, 0xE8, 0xD6, 0x2B, 0xFC, 0x97, 0x3A, 0x50,
0xFC, 0x82, 0x49, 0x17, 0x5B, 0x3E, 0xA0, 0x6D,
/* S-box 2 */
0xF1, 0x8E, 0x6B, 0x34, 0x97, 0x2D, 0xC0, 0x5A,
0x3D, 0x47, 0xF2, 0x8E, 0xC0, 0x1A, 0x69, 0xB5,
0x0E, 0x7B, 0xA4, 0xD1, 0x58, 0xC6, 0x93, 0x2F,
0xD8, 0xA1, 0x3F, 0x42, 0xB6, 0x7C, 0x05, 0xE9,
/* S-box 3 */
0xA0, 0x9E, 0x63, 0xF5, 0x1D, 0xC7, 0xB4, 0x28,
0xD7, 0x09, 0x34, 0x6A, 0x28, 0x5E, 0xCB, 0xF1,
0xD6, 0x49, 0x8F, 0x30, 0xB1, 0x2C, 0x5A, 0xE7,
0x1A, 0xD0, 0x69, 0x87, 0x4F, 0xE3, 0xB5, 0x2C,
/* S-box 4 */
0x7D, 0xE3, 0x06, 0x9A, 0x12, 0x85, 0xBC, 0x4F,
0xD8, 0xB5, 0x6F, 0x03, 0x47, 0x2C, 0x1A, 0xE9,
0xA6, 0x90, 0xCB, 0x7D, 0xF1, 0x3E, 0x52, 0x84,
0x3F, 0x06, 0xA1, 0xD8, 0x94, 0x5B, 0xC7, 0x2E,
/* S-box 5 */
0x2C, 0x41, 0x7A, 0xB6, 0x85, 0x3F, 0xD0, 0xE9,
0xEB, 0x2C, 0x47, 0xD1, 0x50, 0xFA, 0x39, 0x86,
0x42, 0x1B, 0xAD, 0x78, 0xF9, 0xC5, 0x63, 0x0E,
0xB8, 0xC7, 0x1E, 0x2D, 0x6F, 0x09, 0xA4, 0x53,
/* S-box 6 */
0xC1, 0xAF, 0x92, 0x68, 0x0D, 0x34, 0xE7, 0x5B,
0xAF, 0x42, 0x7C, 0x95, 0x61, 0xDE, 0x0B, 0x38,
0x9E, 0xF5, 0x28, 0xC3, 0x70, 0x4A, 0x1D, 0xB6,
0x43, 0x2C, 0x95, 0xFA, 0xBE, 0x17, 0x60, 0x8D,
/* S-box 7 */
0x4B, 0x2E, 0xF0, 0x8D, 0x3C, 0x97, 0x5A, 0x61,
0xD0, 0xB7, 0x49, 0x1A, 0xE3, 0x5C, 0x2F, 0x86,
0x14, 0xBD, 0xC3, 0x7E, 0xAF, 0x68, 0x05, 0x92,
0x6B, 0xD8, 0x14, 0xA7, 0x95, 0x0F, 0xE2, 0x3C,
/* S-box 8 */
0xD2, 0x84, 0x6F, 0xB1, 0xA9, 0x3E, 0x50, 0xC7,
0x1F, 0xD8, 0xA3, 0x74, 0xC5, 0x6B, 0x0E, 0x92,
0x7B, 0x41, 0x9C, 0xE2, 0x06, 0xAD, 0xF3, 0x58,
0x21, 0xE7, 0x4A, 0x8D, 0xFC, 0x90, 0x35, 0x6B
/* S-box 1 */
0xE4, 0xD1, 0x2F, 0xB8, 0x3A, 0x6C, 0x59, 0x07,
0x0F, 0x74, 0xE2, 0xD1, 0xA6, 0xCB, 0x95, 0x38,
0x41, 0xE8, 0xD6, 0x2B, 0xFC, 0x97, 0x3A, 0x50,
0xFC, 0x82, 0x49, 0x17, 0x5B, 0x3E, 0xA0, 0x6D,
/* S-box 2 */
0xF1, 0x8E, 0x6B, 0x34, 0x97, 0x2D, 0xC0, 0x5A,
0x3D, 0x47, 0xF2, 0x8E, 0xC0, 0x1A, 0x69, 0xB5,
0x0E, 0x7B, 0xA4, 0xD1, 0x58, 0xC6, 0x93, 0x2F,
0xD8, 0xA1, 0x3F, 0x42, 0xB6, 0x7C, 0x05, 0xE9,
/* S-box 3 */
0xA0, 0x9E, 0x63, 0xF5, 0x1D, 0xC7, 0xB4, 0x28,
0xD7, 0x09, 0x34, 0x6A, 0x28, 0x5E, 0xCB, 0xF1,
0xD6, 0x49, 0x8F, 0x30, 0xB1, 0x2C, 0x5A, 0xE7,
0x1A, 0xD0, 0x69, 0x87, 0x4F, 0xE3, 0xB5, 0x2C,
/* S-box 4 */
0x7D, 0xE3, 0x06, 0x9A, 0x12, 0x85, 0xBC, 0x4F,
0xD8, 0xB5, 0x6F, 0x03, 0x47, 0x2C, 0x1A, 0xE9,
0xA6, 0x90, 0xCB, 0x7D, 0xF1, 0x3E, 0x52, 0x84,
0x3F, 0x06, 0xA1, 0xD8, 0x94, 0x5B, 0xC7, 0x2E,
/* S-box 5 */
0x2C, 0x41, 0x7A, 0xB6, 0x85, 0x3F, 0xD0, 0xE9,
0xEB, 0x2C, 0x47, 0xD1, 0x50, 0xFA, 0x39, 0x86,
0x42, 0x1B, 0xAD, 0x78, 0xF9, 0xC5, 0x63, 0x0E,
0xB8, 0xC7, 0x1E, 0x2D, 0x6F, 0x09, 0xA4, 0x53,
/* S-box 6 */
0xC1, 0xAF, 0x92, 0x68, 0x0D, 0x34, 0xE7, 0x5B,
0xAF, 0x42, 0x7C, 0x95, 0x61, 0xDE, 0x0B, 0x38,
0x9E, 0xF5, 0x28, 0xC3, 0x70, 0x4A, 0x1D, 0xB6,
0x43, 0x2C, 0x95, 0xFA, 0xBE, 0x17, 0x60, 0x8D,
/* S-box 7 */
0x4B, 0x2E, 0xF0, 0x8D, 0x3C, 0x97, 0x5A, 0x61,
0xD0, 0xB7, 0x49, 0x1A, 0xE3, 0x5C, 0x2F, 0x86,
0x14, 0xBD, 0xC3, 0x7E, 0xAF, 0x68, 0x05, 0x92,
0x6B, 0xD8, 0x14, 0xA7, 0x95, 0x0F, 0xE2, 0x3C,
/* S-box 8 */
0xD2, 0x84, 0x6F, 0xB1, 0xA9, 0x3E, 0x50, 0xC7,
0x1F, 0xD8, 0xA3, 0x74, 0xC5, 0x6B, 0x0E, 0x92,
0x7B, 0x41, 0x9C, 0xE2, 0x06, 0xAD, 0xF3, 0x58,
0x21, 0xE7, 0x4A, 0x8D, 0xFC, 0x90, 0x35, 0x6B
};
const uint8_t e_permtab[] ={
4, 6, /* 4 bytes in 6 bytes out*/
32, 1, 2, 3, 4, 5,
4, 5, 6, 7, 8, 9,
8, 9, 10, 11, 12, 13,
12, 13, 14, 15, 16, 17,
16, 17, 18, 19, 20, 21,
20, 21, 22, 23, 24, 25,
24, 25, 26, 27, 28, 29,
28, 29, 30, 31, 32, 1
const uint8_t e_permtab[] = {
4, 6, /* 4 bytes in 6 bytes out*/
32, 1, 2, 3, 4, 5,
4, 5, 6, 7, 8, 9,
8, 9, 10, 11, 12, 13,
12, 13, 14, 15, 16, 17,
16, 17, 18, 19, 20, 21,
20, 21, 22, 23, 24, 25,
24, 25, 26, 27, 28, 29,
28, 29, 30, 31, 32, 1
};
const uint8_t p_permtab[] ={
4, 4, /* 32 bit -> 32 bit */
16, 7, 20, 21,
29, 12, 28, 17,
1, 15, 23, 26,
5, 18, 31, 10,
2, 8, 24, 14,
32, 27, 3, 9,
19, 13, 30, 6,
22, 11, 4, 25
const uint8_t p_permtab[] = {
4, 4, /* 32 bit -> 32 bit */
16, 7, 20, 21,
29, 12, 28, 17,
1, 15, 23, 26,
5, 18, 31, 10,
2, 8, 24, 14,
32, 27, 3, 9,
19, 13, 30, 6,
22, 11, 4, 25
};
const uint8_t ip_permtab[] ={
8, 8, /* 64 bit -> 64 bit */
58, 50, 42, 34, 26, 18, 10, 2,
60, 52, 44, 36, 28, 20, 12, 4,
62, 54, 46, 38, 30, 22, 14, 6,
64, 56, 48, 40, 32, 24, 16, 8,
57, 49, 41, 33, 25, 17, 9, 1,
59, 51, 43, 35, 27, 19, 11, 3,
61, 53, 45, 37, 29, 21, 13, 5,
63, 55, 47, 39, 31, 23, 15, 7
const uint8_t ip_permtab[] = {
8, 8, /* 64 bit -> 64 bit */
58, 50, 42, 34, 26, 18, 10, 2,
60, 52, 44, 36, 28, 20, 12, 4,
62, 54, 46, 38, 30, 22, 14, 6,
64, 56, 48, 40, 32, 24, 16, 8,
57, 49, 41, 33, 25, 17, 9, 1,
59, 51, 43, 35, 27, 19, 11, 3,
61, 53, 45, 37, 29, 21, 13, 5,
63, 55, 47, 39, 31, 23, 15, 7
};
const uint8_t inv_ip_permtab[] ={
8, 8, /* 64 bit -> 64 bit */
40, 8, 48, 16, 56, 24, 64, 32,
39, 7, 47, 15, 55, 23, 63, 31,
38, 6, 46, 14, 54, 22, 62, 30,
37, 5, 45, 13, 53, 21, 61, 29,
36, 4, 44, 12, 52, 20, 60, 28,
35, 3, 43, 11, 51, 19, 59, 27,
34, 2, 42, 10, 50, 18, 58, 26,
33, 1, 41, 9, 49, 17, 57, 25
const uint8_t inv_ip_permtab[] = {
8, 8, /* 64 bit -> 64 bit */
40, 8, 48, 16, 56, 24, 64, 32,
39, 7, 47, 15, 55, 23, 63, 31,
38, 6, 46, 14, 54, 22, 62, 30,
37, 5, 45, 13, 53, 21, 61, 29,
36, 4, 44, 12, 52, 20, 60, 28,
35, 3, 43, 11, 51, 19, 59, 27,
34, 2, 42, 10, 50, 18, 58, 26,
33, 1, 41, 9, 49, 17, 57, 25
};
const uint8_t pc1_permtab[] ={
8, 7, /* 64 bit -> 56 bit*/
57, 49, 41, 33, 25, 17, 9,
1, 58, 50, 42, 34, 26, 18,
10, 2, 59, 51, 43, 35, 27,
19, 11, 3, 60, 52, 44, 36,
63, 55, 47, 39, 31, 23, 15,
7, 62, 54, 46, 38, 30, 22,
14, 6, 61, 53, 45, 37, 29,
21, 13, 5, 28, 20, 12, 4
const uint8_t pc1_permtab[] = {
8, 7, /* 64 bit -> 56 bit*/
57, 49, 41, 33, 25, 17, 9,
1, 58, 50, 42, 34, 26, 18,
10, 2, 59, 51, 43, 35, 27,
19, 11, 3, 60, 52, 44, 36,
63, 55, 47, 39, 31, 23, 15,
7, 62, 54, 46, 38, 30, 22,
14, 6, 61, 53, 45, 37, 29,
21, 13, 5, 28, 20, 12, 4
};
const uint8_t pc2_permtab[] ={
7, 6, /* 56 bit -> 48 bit */
14, 17, 11, 24, 1, 5,
3, 28, 15, 6, 21, 10,
23, 19, 12, 4, 26, 8,
16, 7, 27, 20, 13, 2,
41, 52, 31, 37, 47, 55,
30, 40, 51, 45, 33, 48,
44, 49, 39, 56, 34, 53,
46, 42, 50, 36, 29, 32
const uint8_t pc2_permtab[] = {
7, 6, /* 56 bit -> 48 bit */
14, 17, 11, 24, 1, 5,
3, 28, 15, 6, 21, 10,
23, 19, 12, 4, 26, 8,
16, 7, 27, 20, 13, 2,
41, 52, 31, 37, 47, 55,
30, 40, 51, 45, 33, 48,
44, 49, 39, 56, 34, 53,
46, 42, 50, 36, 29, 32
};
const uint8_t splitin6bitword_permtab[] = {
8, 8, /* 64 bit -> 64 bit */
64, 64, 1, 6, 2, 3, 4, 5,
64, 64, 7, 12, 8, 9, 10, 11,
64, 64, 13, 18, 14, 15, 16, 17,
64, 64, 19, 24, 20, 21, 22, 23,
64, 64, 25, 30, 26, 27, 28, 29,
64, 64, 31, 36, 32, 33, 34, 35,
64, 64, 37, 42, 38, 39, 40, 41,
64, 64, 43, 48, 44, 45, 46, 47
8, 8, /* 64 bit -> 64 bit */
64, 64, 1, 6, 2, 3, 4, 5,
64, 64, 7, 12, 8, 9, 10, 11,
64, 64, 13, 18, 14, 15, 16, 17,
64, 64, 19, 24, 20, 21, 22, 23,
64, 64, 25, 30, 26, 27, 28, 29,
64, 64, 31, 36, 32, 33, 34, 35,
64, 64, 37, 42, 38, 39, 40, 41,
64, 64, 43, 48, 44, 45, 46, 47
};
const uint8_t shiftkey_permtab[] = {
7, 7, /* 56 bit -> 56 bit */
2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 1,
30, 31, 32, 33, 34, 35, 36, 37,
38, 39, 40, 41, 42, 43, 44, 45,
46, 47, 48, 49, 50, 51, 52, 53,
54, 55, 56, 29
7, 7, /* 56 bit -> 56 bit */
2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 1,
30, 31, 32, 33, 34, 35, 36, 37,
38, 39, 40, 41, 42, 43, 44, 45,
46, 47, 48, 49, 50, 51, 52, 53,
54, 55, 56, 29
};
const uint8_t shiftkeyinv_permtab[] = {
7, 7,
28, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27,
56, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43,
44, 45, 46, 47, 48, 49, 50, 51,
52, 53, 54, 55
7, 7,
28, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27,
56, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43,
44, 45, 46, 47, 48, 49, 50, 51,
52, 53, 54, 55
};
/*
@ -198,247 +198,245 @@ const uint8_t shiftkeyinv_permtab[] = {
2 1
1 0
*/
#define ROTTABLE 0x7EFC
#define ROTTABLE 0x7EFC
#define ROTTABLE_INV 0x3F7E
/******************************************************************************/
void permute(const uint8_t *ptable, const uint8_t *in, uint8_t *out){
uint8_t ob; /* in-bytes and out-bytes */
uint8_t byte, bit; /* counter for bit and byte */
ob = ptable[1];
ptable = &(ptable[2]);
for(byte=0; byte<ob; ++byte){
uint8_t x,t=0;
for(bit=0; bit<8; ++bit){
x = *ptable++ - 1;
t<<=1;
if((in[x/8]) & (0x80>>(x%8)) ){
t|=0x01;
}
}
out[byte]=t;
}
void permute(const uint8_t *ptable, const uint8_t *in, uint8_t *out) {
uint8_t ob; /* in-bytes and out-bytes */
uint8_t byte, bit; /* counter for bit and byte */
ob = ptable[1];
ptable = &(ptable[2]);
for (byte = 0; byte < ob; ++byte) {
uint8_t t = 0;
for (bit = 0; bit < 8; ++bit) {
uint8_t x = *ptable++ - 1;
t <<= 1;
if ((in[x / 8]) & (0x80 >> (x % 8))) {
t |= 0x01;
}
}
out[byte] = t;
}
}
/******************************************************************************/
void changeendian32(uint32_t * a){
*a = (*a & 0x000000FF) << 24 |
(*a & 0x0000FF00) << 8 |
(*a & 0x00FF0000) >> 8 |
(*a & 0xFF000000) >> 24;
void changeendian32(uint32_t *a) {
*a = (*a & 0x000000FF) << 24 |
(*a & 0x0000FF00) << 8 |
(*a & 0x00FF0000) >> 8 |
(*a & 0xFF000000) >> 24;
}
/******************************************************************************/
static inline
void shiftkey(uint8_t *key){
uint8_t k[7];
memcpy(k, key, 7);
permute((uint8_t*)shiftkey_permtab, k, key);
void shiftkey(uint8_t *key) {
uint8_t k[7];
memcpy(k, key, 7);
permute((uint8_t *)shiftkey_permtab, k, key);
}
/******************************************************************************/
static inline
void shiftkey_inv(uint8_t *key){
uint8_t k[7];
memcpy(k, key, 7);
permute((uint8_t*)shiftkeyinv_permtab, k, key);
void shiftkey_inv(uint8_t *key) {
uint8_t k[7];
memcpy(k, key, 7);
permute((uint8_t *)shiftkeyinv_permtab, k, key);
}
/******************************************************************************/
static inline
uint64_t splitin6bitwords(uint64_t a){
uint64_t ret=0;
a &= 0x0000ffffffffffffLL;
permute((uint8_t*)splitin6bitword_permtab, (uint8_t*)&a, (uint8_t*)&ret);
return ret;
uint64_t splitin6bitwords(uint64_t a) {
uint64_t ret = 0;
a &= 0x0000ffffffffffffLL;
permute((uint8_t *)splitin6bitword_permtab, (uint8_t *)&a, (uint8_t *)&ret);
return ret;
}
/******************************************************************************/
static inline
uint8_t substitute(uint8_t a, uint8_t * sbp){
uint8_t x;
x = sbp[a>>1];
x = (a&1)?x&0x0F:x>>4;
return x;
uint8_t substitute(uint8_t a, uint8_t *sbp) {
uint8_t x;
x = sbp[a >> 1];
x = (a & 1) ? x & 0x0F : x >> 4;
return x;
}
/******************************************************************************/
uint32_t des_f(uint32_t r, uint8_t* kr){
uint8_t i;
uint32_t t=0,ret;
uint64_t data;
uint8_t *sbp; /* sboxpointer */
permute((uint8_t*)e_permtab, (uint8_t*)&r, (uint8_t*)&data);
for(i=0; i<6; ++i)
((uint8_t*)&data)[i] ^= kr[i];
/* Sbox substitution */
data = splitin6bitwords(data);
sbp=(uint8_t*)sbox;
for(i=0; i<8; ++i){
uint8_t x;
x = substitute(((uint8_t*)&data)[i], sbp);
t<<=4;
t |= x;
sbp += 32;
}
changeendian32(&t);
permute((uint8_t*)p_permtab,(uint8_t*)&t, (uint8_t*)&ret);
uint32_t des_f(uint32_t r, uint8_t *kr) {
uint8_t i;
uint32_t t = 0, ret;
uint64_t data;
uint8_t *sbp; /* sboxpointer */
permute((uint8_t *)e_permtab, (uint8_t *)&r, (uint8_t *)&data);
for (i = 0; i < 6; ++i)
((uint8_t *)&data)[i] ^= kr[i];
return ret;
/* Sbox substitution */
data = splitin6bitwords(data);
sbp = (uint8_t *)sbox;
for (i = 0; i < 8; ++i) {
uint8_t x;
x = substitute(((uint8_t *)&data)[i], sbp);
t <<= 4;
t |= x;
sbp += 32;
}
changeendian32(&t);
permute((uint8_t *)p_permtab, (uint8_t *)&t, (uint8_t *)&ret);
return ret;
}
/******************************************************************************/
typedef struct {
union {
uint8_t v8[8];
uint32_t v32[2];
} d;
union {
uint8_t v8[8];
uint32_t v32[2];
} d;
} data_t;
#define R (data.d.v32[1])
#define L (data.d.v32[0])
void des_enc(void* out, const void* in, const void* key){
void des_enc(void *out, const void *in, const void *key) {
uint8_t kr[6], k[7];
uint8_t i;
data_t data;
permute((uint8_t*)ip_permtab, (uint8_t*)in, data.d.v8);
permute((uint8_t*)pc1_permtab, (const uint8_t*)key, k);
uint8_t kr[6], k[7];
uint8_t i;
data_t data;
for(i=0; i<8; ++i){
shiftkey(k);
if(ROTTABLE&((1<<((i<<1)+0))) )
shiftkey(k);
permute((uint8_t*)pc2_permtab, k, kr);
L ^= des_f(R, kr);
shiftkey(k);
if(ROTTABLE&((1<<((i<<1)+1))) )
shiftkey(k);
permute((uint8_t*)pc2_permtab, k, kr);
R ^= des_f(L, kr);
permute((uint8_t *)ip_permtab, (uint8_t *)in, data.d.v8);
permute((uint8_t *)pc1_permtab, (const uint8_t *)key, k);
}
/* L <-> R*/
R ^= L;
L ^= R;
R ^= L;
permute((uint8_t*)inv_ip_permtab, data.d.v8, (uint8_t*)out);
for (i = 0; i < 8; ++i) {
shiftkey(k);
if (ROTTABLE & ((1 << ((i << 1) + 0))))
shiftkey(k);
permute((uint8_t *)pc2_permtab, k, kr);
L ^= des_f(R, kr);
shiftkey(k);
if (ROTTABLE & ((1 << ((i << 1) + 1))))
shiftkey(k);
permute((uint8_t *)pc2_permtab, k, kr);
R ^= des_f(L, kr);
}
/* L <-> R*/
R ^= L;
L ^= R;
R ^= L;
permute((uint8_t *)inv_ip_permtab, data.d.v8, (uint8_t *)out);
}
/******************************************************************************/
void des_dec(void* out, const void* in, const uint8_t* key){
void des_dec(void *out, const void *in, const uint8_t *key) {
uint8_t kr[6],k[7];
int8_t i;
data_t data;
permute((uint8_t*)ip_permtab, (uint8_t*)in, data.d.v8);
permute((uint8_t*)pc1_permtab, (const uint8_t*)key, k);
for(i=7; i>=0; --i){
permute((uint8_t*)pc2_permtab, k, kr);
L ^= des_f(R, kr);
shiftkey_inv(k);
if(ROTTABLE&((1<<((i<<1)+1))) ){
shiftkey_inv(k);
}
uint8_t kr[6], k[7];
int8_t i;
data_t data;
permute((uint8_t*)pc2_permtab, k, kr);
R ^= des_f(L, kr);
shiftkey_inv(k);
if(ROTTABLE&((1<<((i<<1)+0))) ){
shiftkey_inv(k);
}
permute((uint8_t *)ip_permtab, (uint8_t *)in, data.d.v8);
permute((uint8_t *)pc1_permtab, (const uint8_t *)key, k);
for (i = 7; i >= 0; --i) {
}
/* L <-> R*/
R ^= L;
L ^= R;
R ^= L;
permute((uint8_t*)inv_ip_permtab, data.d.v8, (uint8_t*)out);
permute((uint8_t *)pc2_permtab, k, kr);
L ^= des_f(R, kr);
shiftkey_inv(k);
if (ROTTABLE & ((1 << ((i << 1) + 1)))) {
shiftkey_inv(k);
}
permute((uint8_t *)pc2_permtab, k, kr);
R ^= des_f(L, kr);
shiftkey_inv(k);
if (ROTTABLE & ((1 << ((i << 1) + 0)))) {
shiftkey_inv(k);
}
}
/* L <-> R*/
R ^= L;
L ^= R;
R ^= L;
permute((uint8_t *)inv_ip_permtab, data.d.v8, (uint8_t *)out);
}
/******************************************************************************/
void tdes_enc(void* out, void* in, const void* key){
des_enc(out, in, (uint8_t*)key + 0);
des_dec(out, out, (uint8_t*)key + 8);
des_enc(out, out, (uint8_t*)key +16);
void tdes_enc(void *out, void *in, const void *key) {
des_enc(out, in, (uint8_t *)key + 0);
des_dec(out, out, (uint8_t *)key + 8);
des_enc(out, out, (uint8_t *)key + 16);
}
/******************************************************************************/
void tdes_dec(void* out, void* in, const uint8_t* key){
des_dec(out, in, (uint8_t*)key +16);
des_enc(out, out, (uint8_t*)key + 8);
des_dec(out, out, (uint8_t*)key + 0);
void tdes_dec(void *out, void *in, const uint8_t *key) {
des_dec(out, in, (uint8_t *)key + 16);
des_enc(out, out, (uint8_t *)key + 8);
des_dec(out, out, (uint8_t *)key + 0);
}
void tdes_2key_enc(void* out, const void* in, size_t length, const void* key, unsigned char iv[8]){
void tdes_2key_enc(void *out, const void *in, size_t length, const void *key, unsigned char iv[8]) {
if( length % 8 ) return;
if (length % 8) return;
uint8_t i;
uint8_t* tin = (uint8_t*) in;
uint8_t* tout = (uint8_t*) out;
while( length > 0 )
{
for( i = 0; i < 8; i++ )
tout[i] = (unsigned char)( tin[i] ^ iv[i] );
des_enc(tout, tin, (uint8_t*)key + 0);
des_dec(tout, tout, (uint8_t*)key + 8);
des_enc(tout, tout, (uint8_t*)key + 0);
memcpy( iv, tout, 8 );
tin += 8;
tout += 8;
length -= 8;
}
}
void tdes_2key_dec(void* out, const void* in, size_t length, const void* key, unsigned char iv[8]){
if( length % 8 ) return;
uint8_t i;
uint8_t *tin = (uint8_t *) in;
uint8_t *tout = (uint8_t *) out;
uint8_t i;
unsigned char temp[8];
uint8_t* tin = (uint8_t*) in;
uint8_t* tout = (uint8_t*) out;
while( length > 0 )
{
memcpy( temp, tin, 8 );
des_dec(tout, tin, (uint8_t*)key + 0);
des_enc(tout, tout, (uint8_t*)key + 8);
des_dec(tout, tout, (uint8_t*)key + 0);
while (length > 0) {
for (i = 0; i < 8; i++)
tout[i] = (unsigned char)(tin[i] ^ iv[i]);
for( i = 0; i < 8; i++ )
tout[i] = (unsigned char)( tout[i] ^ iv[i] );
des_enc(tout, tin, (uint8_t *)key + 0);
des_dec(tout, tout, (uint8_t *)key + 8);
des_enc(tout, tout, (uint8_t *)key + 0);
memcpy( iv, temp, 8 );
tin += 8;
tout += 8;
length -= 8;
}
}
memcpy(iv, tout, 8);
tin += 8;
tout += 8;
length -= 8;
}
}
void tdes_2key_dec(void *out, const void *in, size_t length, const void *key, unsigned char iv[8]) {
if (length % 8) return;
uint8_t i;
unsigned char temp[8];
uint8_t *tin = (uint8_t *) in;
uint8_t *tout = (uint8_t *) out;
while (length > 0) {
memcpy(temp, tin, 8);
des_dec(tout, tin, (uint8_t *)key + 0);
des_enc(tout, tout, (uint8_t *)key + 8);
des_dec(tout, tout, (uint8_t *)key + 0);
for (i = 0; i < 8; i++)
tout[i] = (unsigned char)(tout[i] ^ iv[i]);
memcpy(iv, temp, 8);
tin += 8;
tout += 8;
length -= 8;
}
}
/******************************************************************************/

View file

@ -17,12 +17,12 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* \file des.h
* \author Daniel Otte
* \date 2007-06-16
* \brief des and tdes declarations
* \license GPLv3 or later
*
* \file des.h
* \author Daniel Otte
* \date 2007-06-16
* \brief des and tdes declarations
* \license GPLv3 or later
*
*/
#ifndef __DES_H_
#define __DES_H_
@ -46,65 +46,65 @@
/** \fn void des_enc(void* out, const void* in, const void* key)
* \brief encrypt a block with DES
*
*
* This function encrypts a block of 64 bits (8 bytes) with the DES algorithm.
* Key expansion is done automatically. The key is 64 bits long, but note that
* only 56 bits are used (the LSB of each byte is dropped). The input and output
* blocks may overlap.
*
*
* \param out pointer to the block (64 bit = 8 byte) where the ciphertext is written to
* \param in pointer to the block (64 bit = 8 byte) where the plaintext is read from
* \param key pointer to the key (64 bit = 8 byte)
*/
void des_enc(void* out, const void* in, const void* key);
void des_enc(void *out, const void *in, const void *key);
/** \fn void des_dec(void* out, const void* in, const void* key)
* \brief decrypt a block with DES
*
*
* This function decrypts a block of 64 bits (8 bytes) with the DES algorithm.
* Key expansion is done automatically. The key is 64 bits long, but note that
* only 56 bits are used (the LSB of each byte is dropped). The input and output
* blocks may overlap.
*
*
* \param out pointer to the block (64 bit = 8 byte) where the plaintext is written to
* \param in pointer to the block (64 bit = 8 byte) where the ciphertext is read from
* \param key pointer to the key (64 bit = 8 byte)
*/
//void des_dec(void* out, const void* in, const void* key);
void des_dec(void* out, const void* in, const uint8_t* key);
void des_dec(void *out, const void *in, const uint8_t *key);
/** \fn void tdes_enc(void* out, const void* in, const void* key)
* \brief encrypt a block with Tripple-DES
*
*
* This function encrypts a block of 64 bits (8 bytes) with the Tripple-DES (EDE)
* algorithm. Key expansion is done automatically. The key is 192 bits long, but
* note that only 178 bits are used (the LSB of each byte is dropped). The input
* and output blocks may overlap.
*
*
* \param out pointer to the block (64 bit = 8 byte) where the ciphertext is written to
* \param in pointer to the block (64 bit = 8 byte) where the plaintext is read from
* \param key pointer to the key (192 bit = 24 byte)
*/
//void tdes_enc(void* out, const void* in, const void* key);
void tdes_enc(void* out, void* in, const void* key);
void tdes_enc(void *out, void *in, const void *key);
/** \fn void tdes_dec(void* out, const void* in, const void* key)
* \brief decrypt a block with Tripple-DES
*
*
* This function decrypts a block of 64 bits (8 bytes) with the Tripple-DES (EDE)
* algorithm. Key expansion is done automatically. The key is 192 bits long, but
* note that only 178 bits are used (the LSB of each byte is dropped). The input
* and output blocks may overlap.
*
*
* \param out pointer to the block (64 bit = 8 byte) where the plaintext is written to
* \param in pointer to the block (64 bit = 8 byte) where the ciphertext is read from
* \param key pointer to the key (192 bit = 24 byte)
*/
//void tdes_dec(void* out, const void* in, const void* key);
void tdes_dec(void* out, void* in, const uint8_t* key);
void tdes_2key_enc(void* out, const void* in, size_t length, const void* key, unsigned char iv[8]);
void tdes_2key_dec(void* out, const void* in, size_t length, const void* key, unsigned char iv[8]);
//void tdes_dec(void* out, const void* in, const void* key);
void tdes_dec(void *out, void *in, const uint8_t *key);
void tdes_2key_enc(void *out, const void *in, size_t length, const void *key, unsigned char iv[8]);
void tdes_2key_dec(void *out, const void *in, size_t length, const void *key, unsigned char iv[8]);
// Copied from des.h in desfire imp.
typedef unsigned long DES_KS[16][2]; /* Single-key DES key schedule */

File diff suppressed because it is too large Load diff

View file

@ -1,11 +1,11 @@
/*-
* Copyright (C) 2010, Romain Tartiere.
*
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
@ -13,88 +13,88 @@
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*
* $Id$
*/
#include "desfire_key.h"
static inline void update_key_schedules (desfirekey_t key);
static inline void update_key_schedules(desfirekey_t key);
static inline void update_key_schedules (desfirekey_t key) {
static inline void update_key_schedules(desfirekey_t key) {
// DES_set_key ((DES_cblock *)key->data, &(key->ks1));
// DES_set_key ((DES_cblock *)(key->data + 8), &(key->ks2));
// if (T_3K3DES == key->type) {
// DES_set_key ((DES_cblock *)(key->data + 16), &(key->ks3));
// DES_set_key ((DES_cblock *)(key->data + 16), &(key->ks3));
// }
}
void Desfire_des_key_new (const uint8_t value[8], desfirekey_t key) {
void Desfire_des_key_new(const uint8_t value[8], desfirekey_t key) {
uint8_t data[8];
memcpy (data, value, 8);
for (int n=0; n < 8; n++)
memcpy(data, value, 8);
for (int n = 0; n < 8; n++)
data[n] &= 0xfe;
Desfire_des_key_new_with_version (data, key);
Desfire_des_key_new_with_version(data, key);
}
void Desfire_des_key_new_with_version (const uint8_t value[8], desfirekey_t key) {
if ( key != NULL) {
key->type = T_DES;
memcpy (key->data, value, 8);
memcpy (key->data+8, value, 8);
update_key_schedules (key);
}
void Desfire_des_key_new_with_version(const uint8_t value[8], desfirekey_t key) {
if (key != NULL) {
key->type = T_DES;
memcpy(key->data, value, 8);
memcpy(key->data + 8, value, 8);
update_key_schedules(key);
}
}
void Desfire_3des_key_new (const uint8_t value[16], desfirekey_t key) {
void Desfire_3des_key_new(const uint8_t value[16], desfirekey_t key) {
uint8_t data[16];
memcpy (data, value, 16);
for (int n=0; n < 8; n++)
memcpy(data, value, 16);
for (int n = 0; n < 8; n++)
data[n] &= 0xfe;
for (int n=8; n < 16; n++)
for (int n = 8; n < 16; n++)
data[n] |= 0x01;
Desfire_3des_key_new_with_version (data, key);
Desfire_3des_key_new_with_version(data, key);
}
void Desfire_3des_key_new_with_version (const uint8_t value[16], desfirekey_t key) {
if ( key != NULL ){
key->type = T_3DES;
memcpy (key->data, value, 16);
memcpy (key->data + 16, value, 8);
update_key_schedules (key);
}
void Desfire_3des_key_new_with_version(const uint8_t value[16], desfirekey_t key) {
if (key != NULL) {
key->type = T_3DES;
memcpy(key->data, value, 16);
memcpy(key->data + 16, value, 8);
update_key_schedules(key);
}
}
void Desfire_3k3des_key_new (const uint8_t value[24], desfirekey_t key) {
void Desfire_3k3des_key_new(const uint8_t value[24], desfirekey_t key) {
uint8_t data[24];
memcpy (data, value, 24);
for (int n=0; n < 8; n++)
memcpy(data, value, 24);
for (int n = 0; n < 8; n++)
data[n] &= 0xfe;
Desfire_3k3des_key_new_with_version (data, key);
Desfire_3k3des_key_new_with_version(data, key);
}
void Desfire_3k3des_key_new_with_version (const uint8_t value[24], desfirekey_t key) {
if ( key != NULL){
key->type = T_3K3DES;
memcpy (key->data, value, 24);
update_key_schedules (key);
}
void Desfire_3k3des_key_new_with_version(const uint8_t value[24], desfirekey_t key) {
if (key != NULL) {
key->type = T_3K3DES;
memcpy(key->data, value, 24);
update_key_schedules(key);
}
}
void Desfire_aes_key_new (const uint8_t value[16], desfirekey_t key) {
Desfire_aes_key_new_with_version (value, 0, key);
void Desfire_aes_key_new(const uint8_t value[16], desfirekey_t key) {
Desfire_aes_key_new_with_version(value, 0, key);
}
void Desfire_aes_key_new_with_version (const uint8_t value[16], uint8_t version, desfirekey_t key) {
void Desfire_aes_key_new_with_version(const uint8_t value[16], uint8_t version, desfirekey_t key) {
if (key != NULL) {
memcpy (key->data, value, 16);
key->type = T_AES;
key->aes_version = version;
}
if (key != NULL) {
memcpy(key->data, value, 16);
key->type = T_AES;
key->aes_version = version;
}
}
uint8_t Desfire_key_get_version (desfirekey_t key) {
uint8_t Desfire_key_get_version(desfirekey_t key) {
uint8_t version = 0;
for (int n = 0; n < 8; n++) {
@ -103,54 +103,53 @@ uint8_t Desfire_key_get_version (desfirekey_t key) {
return version;
}
void Desfire_key_set_version (desfirekey_t key, uint8_t version)
{
void Desfire_key_set_version(desfirekey_t key, uint8_t version) {
for (int n = 0; n < 8; n++) {
uint8_t version_bit = ((version & (1 << (7-n))) >> (7-n));
uint8_t version_bit = ((version & (1 << (7 - n))) >> (7 - n));
key->data[n] &= 0xfe;
key->data[n] |= version_bit;
if (key->type == T_DES) {
key->data[n+8] = key->data[n];
key->data[n + 8] = key->data[n];
} else {
// Write ~version to avoid turning a 3DES key into a DES key
key->data[n+8] &= 0xfe;
key->data[n+8] |= ~version_bit;
key->data[n + 8] &= 0xfe;
key->data[n + 8] |= ~version_bit;
}
}
}
void Desfire_session_key_new (const uint8_t rnda[], const uint8_t rndb[], desfirekey_t authkey, desfirekey_t key) {
void Desfire_session_key_new(const uint8_t rnda[], const uint8_t rndb[], desfirekey_t authkey, desfirekey_t key) {
uint8_t buffer[24];
switch (authkey->type) {
case T_DES:
memcpy (buffer, rnda, 4);
memcpy (buffer+4, rndb, 4);
Desfire_des_key_new_with_version (buffer, key);
break;
case T_3DES:
memcpy (buffer, rnda, 4);
memcpy (buffer+4, rndb, 4);
memcpy (buffer+8, rnda+4, 4);
memcpy (buffer+12, rndb+4, 4);
Desfire_3des_key_new_with_version (buffer, key);
break;
case T_3K3DES:
memcpy (buffer, rnda, 4);
memcpy (buffer+4, rndb, 4);
memcpy (buffer+8, rnda+6, 4);
memcpy (buffer+12, rndb+6, 4);
memcpy (buffer+16, rnda+12, 4);
memcpy (buffer+20, rndb+12, 4);
Desfire_3k3des_key_new (buffer, key);
break;
case T_AES:
memcpy (buffer, rnda, 4);
memcpy (buffer+4, rndb, 4);
memcpy (buffer+8, rnda+12, 4);
memcpy (buffer+12, rndb+12, 4);
Desfire_aes_key_new (buffer, key);
break;
case T_DES:
memcpy(buffer, rnda, 4);
memcpy(buffer + 4, rndb, 4);
Desfire_des_key_new_with_version(buffer, key);
break;
case T_3DES:
memcpy(buffer, rnda, 4);
memcpy(buffer + 4, rndb, 4);
memcpy(buffer + 8, rnda + 4, 4);
memcpy(buffer + 12, rndb + 4, 4);
Desfire_3des_key_new_with_version(buffer, key);
break;
case T_3K3DES:
memcpy(buffer, rnda, 4);
memcpy(buffer + 4, rndb, 4);
memcpy(buffer + 8, rnda + 6, 4);
memcpy(buffer + 12, rndb + 6, 4);
memcpy(buffer + 16, rnda + 12, 4);
memcpy(buffer + 20, rndb + 12, 4);
Desfire_3k3des_key_new(buffer, key);
break;
case T_AES:
memcpy(buffer, rnda, 4);
memcpy(buffer + 4, rndb, 4);
memcpy(buffer + 8, rnda + 12, 4);
memcpy(buffer + 12, rndb + 12, 4);
Desfire_aes_key_new(buffer, key);
break;
}
}
}

View file

@ -6,15 +6,15 @@
#include "iso14443a.h"
#include "desfire.h"
//#include "mifare.h" // iso14a_card_select_t struct
void Desfire_des_key_new (const uint8_t value[8], desfirekey_t key);
void Desfire_3des_key_new (const uint8_t value[16], desfirekey_t key);
void Desfire_des_key_new_with_version (const uint8_t value[8], desfirekey_t key);
void Desfire_3des_key_new_with_version (const uint8_t value[16], desfirekey_t key);
void Desfire_3k3des_key_new (const uint8_t value[24], desfirekey_t key);
void Desfire_3k3des_key_new_with_version (const uint8_t value[24], desfirekey_t key);
void Desfire_aes_key_new (const uint8_t value[16], desfirekey_t key);
void Desfire_aes_key_new_with_version (const uint8_t value[16], uint8_t version,desfirekey_t key);
uint8_t Desfire_key_get_version (desfirekey_t key);
void Desfire_key_set_version (desfirekey_t key, uint8_t version);
void Desfire_session_key_new (const uint8_t rnda[], const uint8_t rndb[], desfirekey_t authkey, desfirekey_t key);
#endif
void Desfire_des_key_new(const uint8_t value[8], desfirekey_t key);
void Desfire_3des_key_new(const uint8_t value[16], desfirekey_t key);
void Desfire_des_key_new_with_version(const uint8_t value[8], desfirekey_t key);
void Desfire_3des_key_new_with_version(const uint8_t value[16], desfirekey_t key);
void Desfire_3k3des_key_new(const uint8_t value[24], desfirekey_t key);
void Desfire_3k3des_key_new_with_version(const uint8_t value[24], desfirekey_t key);
void Desfire_aes_key_new(const uint8_t value[16], desfirekey_t key);
void Desfire_aes_key_new_with_version(const uint8_t value[16], uint8_t version, desfirekey_t key);
uint8_t Desfire_key_get_version(desfirekey_t key);
void Desfire_key_set_version(desfirekey_t key, uint8_t version);
void Desfire_session_key_new(const uint8_t rnda[], const uint8_t rndb[], desfirekey_t authkey, desfirekey_t key);
#endif

View file

@ -21,41 +21,41 @@ static const uint8_t pps[] = {0xD0, 0x11, 0x00, 0x52, 0xA6};
// General Authenticate (request encrypted nonce) WITHOUT the Le at the end
static const uint8_t apdu_general_authenticate_pace_get_nonce[] = {
0x10, // CLA
0x86, // INS
0x00, // P1
0x00, // P2
0x02, // Lc
0x7C, // Type: Dynamic Authentication Data
0x00, // Length: 0 bytes
0x10, // CLA
0x86, // INS
0x00, // P1
0x00, // P2
0x02, // Lc
0x7C, // Type: Dynamic Authentication Data
0x00, // Length: 0 bytes
};
// MSE: Set AT (only CLA, INS, P1 and P2)
static const uint8_t apdu_mse_set_at_start[] = {
0x00, // CLA
0x22, // INS
0xC1, // P1
0xA4, // P2
0x00, // CLA
0x22, // INS
0xC1, // P1
0xA4, // P2
};
// SELECT BINARY with the ID for EF.CardAccess
static const uint8_t apdu_select_binary_cardaccess[] = {
0x00, // CLA
0xA4, // INS
0x02, // P1
0x0C, // P2
0x02, // Lc
0x01, // ID
0x1C // ID
0x00, // CLA
0xA4, // INS
0x02, // P1
0x0C, // P2
0x02, // Lc
0x01, // ID
0x1C // ID
};
// READ BINARY
static const uint8_t apdu_read_binary[] = {
0x00, // CLA
0xB0, // INS
0x00, // P1
0x00, // P2
0x38 // Le
0x00, // CLA
0xB0, // INS
0x00, // P1
0x00, // P2
0x38 // Le
};
@ -84,14 +84,14 @@ static uint8_t apdu_replay_general_authenticate_pace_mutual_authenticate[75];
static uint8_t apdu_replay_general_authenticate_pace_perform_key_agreement[18];
// pointers to the APDUs (for iterations)
static struct {
uint8_t len;
uint8_t *data;
uint8_t len;
uint8_t *data;
} const apdus_replay[] = {
{sizeof(apdu_replay_mse_set_at_pace), apdu_replay_mse_set_at_pace},
{sizeof(apdu_replay_general_authenticate_pace_get_nonce), apdu_replay_general_authenticate_pace_get_nonce},
{sizeof(apdu_replay_general_authenticate_pace_map_nonce), apdu_replay_general_authenticate_pace_map_nonce},
{sizeof(apdu_replay_general_authenticate_pace_mutual_authenticate), apdu_replay_general_authenticate_pace_mutual_authenticate},
{sizeof(apdu_replay_general_authenticate_pace_perform_key_agreement), apdu_replay_general_authenticate_pace_perform_key_agreement}
{sizeof(apdu_replay_mse_set_at_pace), apdu_replay_mse_set_at_pace},
{sizeof(apdu_replay_general_authenticate_pace_get_nonce), apdu_replay_general_authenticate_pace_get_nonce},
{sizeof(apdu_replay_general_authenticate_pace_map_nonce), apdu_replay_general_authenticate_pace_map_nonce},
{sizeof(apdu_replay_general_authenticate_pace_mutual_authenticate), apdu_replay_general_authenticate_pace_mutual_authenticate},
{sizeof(apdu_replay_general_authenticate_pace_perform_key_agreement), apdu_replay_general_authenticate_pace_perform_key_agreement}
};
// lengths of the replay APDUs
@ -103,30 +103,27 @@ static char iso_type = 0;
//-----------------------------------------------------------------------------
// Wrapper for sending APDUs to type A and B cards
//-----------------------------------------------------------------------------
int EPA_APDU(uint8_t *apdu, size_t length, uint8_t *response)
{
switch(iso_type)
{
case 'a':
return iso14_apdu(apdu, (uint16_t) length, response);
break;
case 'b':
return iso14443b_apdu(apdu, length, response);
break;
default:
return 0;
break;
}
int EPA_APDU(uint8_t *apdu, size_t length, uint8_t *response) {
switch (iso_type) {
case 'a':
return iso14_apdu(apdu, (uint16_t) length, false, response, NULL);
break;
case 'b':
return iso14443b_apdu(apdu, length, response);
break;
default:
return 0;
break;
}
}
//-----------------------------------------------------------------------------
// Closes the communication channel and turns off the field
//-----------------------------------------------------------------------------
void EPA_Finish()
{
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
iso_type = 0;
void EPA_Finish() {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
iso_type = 0;
}
//-----------------------------------------------------------------------------
@ -144,70 +141,65 @@ void EPA_Finish()
//-----------------------------------------------------------------------------
size_t EPA_Parse_CardAccess(uint8_t *data,
size_t length,
pace_version_info_t *pace_info)
{
size_t index = 0;
pace_version_info_t *pace_info) {
size_t index = 0;
while (index <= length - 2) {
// determine type of element
// SET or SEQUENCE
if (data[index] == 0x31 || data[index] == 0x30) {
// enter the set (skip tag + length)
index += 2;
// check for extended length
if ((data[index - 1] & 0x80) != 0) {
index += (data[index-1] & 0x7F);
}
}
// OID
else if (data[index] == 0x06) {
// is this a PACE OID?
if (data[index + 1] == 0x0A // length matches
&& memcmp(data + index + 2,
oid_pace_start,
sizeof(oid_pace_start)) == 0 // content matches
&& pace_info != NULL)
{
// first, clear the pace_info struct
memset(pace_info, 0, sizeof(pace_version_info_t));
memcpy(pace_info->oid, data + index + 2, sizeof(pace_info->oid));
// a PACE OID is followed by the version
index += data[index + 1] + 2;
if (data[index] == 02 && data[index + 1] == 01) {
pace_info->version = data[index + 2];
index += 3;
}
else {
return index;
}
// after that there might(!) be the parameter ID
if (data[index] == 02 && data[index + 1] == 01) {
pace_info->parameter_id = data[index + 2];
index += 3;
}
}
else {
// skip this OID
index += 2 + data[index + 1];
}
}
// if the length is 0, something is wrong
// TODO: This needs to be extended to support long tags
else if (data[index + 1] == 0) {
return index;
}
else {
// skip this part
// TODO: This needs to be extended to support long tags
// TODO: This needs to be extended to support unknown elements with
// a size > 0x7F
index += 2 + data[index + 1];
}
}
while (index <= length - 2) {
// determine type of element
// SET or SEQUENCE
if (data[index] == 0x31 || data[index] == 0x30) {
// enter the set (skip tag + length)
index += 2;
// check for extended length
if ((data[index - 1] & 0x80) != 0) {
index += (data[index - 1] & 0x7F);
}
}
// OID
else if (data[index] == 0x06) {
// is this a PACE OID?
if (data[index + 1] == 0x0A // length matches
&& memcmp(data + index + 2,
oid_pace_start,
sizeof(oid_pace_start)) == 0 // content matches
&& pace_info != NULL) {
// first, clear the pace_info struct
memset(pace_info, 0, sizeof(pace_version_info_t));
memcpy(pace_info->oid, data + index + 2, sizeof(pace_info->oid));
// a PACE OID is followed by the version
index += data[index + 1] + 2;
if (data[index] == 02 && data[index + 1] == 01) {
pace_info->version = data[index + 2];
index += 3;
} else {
return index;
}
// after that there might(!) be the parameter ID
if (data[index] == 02 && data[index + 1] == 01) {
pace_info->parameter_id = data[index + 2];
index += 3;
}
} else {
// skip this OID
index += 2 + data[index + 1];
}
}
// if the length is 0, something is wrong
// TODO: This needs to be extended to support long tags
else if (data[index + 1] == 0) {
return index;
} else {
// skip this part
// TODO: This needs to be extended to support long tags
// TODO: This needs to be extended to support unknown elements with
// a size > 0x7F
index += 2 + data[index + 1];
}
}
// TODO: We should check whether we reached the end in error, but for that
// we need a better parser (e.g. with states like IN_SET or IN_PACE_INFO)
return 0;
// TODO: We should check whether we reached the end in error, but for that
// we need a better parser (e.g. with states like IN_SET or IN_PACE_INFO)
return 0;
}
//-----------------------------------------------------------------------------
@ -215,126 +207,125 @@ size_t EPA_Parse_CardAccess(uint8_t *data,
// Returns -1 on failure or the length of the data on success
// TODO: for the moment this sends only 1 APDU regardless of the requested length
//-----------------------------------------------------------------------------
int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length)
{
// the response APDU of the card
// since the card doesn't always care for the expected length we send it,
// we reserve 262 bytes here just to be safe (256-byte APDU + SW + ISO frame)
uint8_t response_apdu[262];
int rapdu_length = 0;
int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length) {
// the response APDU of the card
// since the card doesn't always care for the expected length we send it,
// we reserve 262 bytes here just to be safe (256-byte APDU + SW + ISO frame)
uint8_t response_apdu[262];
int rapdu_length = 0;
// select the file EF.CardAccess
rapdu_length = EPA_APDU((uint8_t *)apdu_select_binary_cardaccess,
sizeof(apdu_select_binary_cardaccess),
response_apdu);
if (rapdu_length < 6
|| response_apdu[rapdu_length - 4] != 0x90
|| response_apdu[rapdu_length - 3] != 0x00)
{
DbpString("Failed to select EF.CardAccess!");
return -1;
}
// select the file EF.CardAccess
rapdu_length = EPA_APDU((uint8_t *)apdu_select_binary_cardaccess,
sizeof(apdu_select_binary_cardaccess),
response_apdu);
if (rapdu_length < 6
|| response_apdu[rapdu_length - 4] != 0x90
|| response_apdu[rapdu_length - 3] != 0x00) {
DbpString("Failed to select EF.CardAccess!");
return -1;
}
// read the file
rapdu_length = EPA_APDU((uint8_t *)apdu_read_binary,
sizeof(apdu_read_binary),
response_apdu);
if (rapdu_length <= 6
|| response_apdu[rapdu_length - 4] != 0x90
|| response_apdu[rapdu_length - 3] != 0x00)
{
Dbprintf("Failed to read EF.CardAccess!");
return -1;
}
// read the file
rapdu_length = EPA_APDU((uint8_t *)apdu_read_binary,
sizeof(apdu_read_binary),
response_apdu);
if (rapdu_length <= 6
|| response_apdu[rapdu_length - 4] != 0x90
|| response_apdu[rapdu_length - 3] != 0x00) {
Dbprintf("Failed to read EF.CardAccess!");
return -1;
}
// copy the content into the buffer
// length of data available: apdu_length - 4 (ISO frame) - 2 (SW)
size_t to_copy = rapdu_length - 6;
to_copy = to_copy < max_length ? to_copy : max_length;
memcpy(buffer, response_apdu+2, to_copy);
return to_copy;
// copy the content into the buffer
// length of data available: apdu_length - 4 (ISO frame) - 2 (SW)
size_t to_copy = rapdu_length - 6;
to_copy = to_copy < max_length ? to_copy : max_length;
memcpy(buffer, response_apdu + 2, to_copy);
return to_copy;
}
//-----------------------------------------------------------------------------
// Abort helper function for EPA_PACE_Collect_Nonce
// sets relevant data in ack, sends the response
//-----------------------------------------------------------------------------
static void EPA_PACE_Collect_Nonce_Abort(uint8_t step, int func_return)
{
// power down the field
EPA_Finish();
static void EPA_PACE_Collect_Nonce_Abort(uint8_t step, int func_return) {
// power down the field
EPA_Finish();
// send the USB packet
cmd_send(CMD_ACK,step,func_return,0,0,0);
// send the USB packet
reply_old(CMD_ACK, step, func_return, 0, 0, 0);
}
//-----------------------------------------------------------------------------
// Acquire one encrypted PACE nonce
//-----------------------------------------------------------------------------
void EPA_PACE_Collect_Nonce(UsbCommand *c)
{
/*
* ack layout:
* arg:
* 1. element
* step where the error occured or 0 if no error occured
void EPA_PACE_Collect_Nonce(PacketCommandNG *c) {
/*
* ack layout:
* arg:
* 1. element
* step where the error occured or 0 if no error occured
* 2. element
* return code of the last executed function
* d:
* Encrypted nonce
*/
* d:
* Encrypted nonce
*/
// return value of a function
int func_return = 0;
// return value of a function
int func_return = 0;
// set up communication
func_return = EPA_Setup();
if (func_return != 0) {
EPA_PACE_Collect_Nonce_Abort(1, func_return);
return;
}
// set up communication
func_return = EPA_Setup();
if (func_return != 0) {
EPA_PACE_Collect_Nonce_Abort(1, func_return);
return;
}
// read the CardAccess file
// this array will hold the CardAccess file
uint8_t card_access[256] = {0};
int card_access_length = EPA_Read_CardAccess(card_access, 256);
// the response has to be at least this big to hold the OID
if (card_access_length < 18) {
EPA_PACE_Collect_Nonce_Abort(2, card_access_length);
return;
}
// read the CardAccess file
// this array will hold the CardAccess file
uint8_t card_access[256] = {0};
int card_access_length = EPA_Read_CardAccess(card_access, 256);
// the response has to be at least this big to hold the OID
if (card_access_length < 18) {
EPA_PACE_Collect_Nonce_Abort(2, card_access_length);
return;
}
// this will hold the PACE info of the card
pace_version_info_t pace_version_info;
// search for the PACE OID
func_return = EPA_Parse_CardAccess(card_access,
card_access_length,
&pace_version_info);
if (func_return != 0 || pace_version_info.version == 0) {
EPA_PACE_Collect_Nonce_Abort(3, func_return);
return;
}
// this will hold the PACE info of the card
pace_version_info_t pace_version_info;
// search for the PACE OID
func_return = EPA_Parse_CardAccess(card_access,
card_access_length,
&pace_version_info);
if (func_return != 0 || pace_version_info.version == 0) {
EPA_PACE_Collect_Nonce_Abort(3, func_return);
return;
}
// initiate the PACE protocol
// use the CAN for the password since that doesn't change
func_return = EPA_PACE_MSE_Set_AT(pace_version_info, 2);
// initiate the PACE protocol
// use the CAN for the password since that doesn't change
func_return = EPA_PACE_MSE_Set_AT(pace_version_info, 2);
// check if the command succeeded
if (func_return != 0) {
EPA_PACE_Collect_Nonce_Abort(4, func_return);
return;
}
// now get the nonce
uint8_t nonce[256] = {0};
uint8_t requested_size = (uint8_t)c->arg[0];
func_return = EPA_PACE_Get_Nonce(requested_size, nonce);
// check if the command succeeded
if (func_return < 0)
{
EPA_PACE_Collect_Nonce_Abort(4, func_return);
return;
}
// now get the nonce
uint8_t nonce[256] = {0};
uint8_t requested_size = (uint8_t)c->oldarg[0];
func_return = EPA_PACE_Get_Nonce(requested_size, nonce);
// check if the command succeeded
if (func_return < 0) {
EPA_PACE_Collect_Nonce_Abort(5, func_return);
return;
}
// all done, return
EPA_Finish();
// all done, return
EPA_Finish();
// save received information
cmd_send(CMD_ACK,0,func_return,0,nonce,func_return);
// save received information
reply_old(CMD_ACK, 0, func_return, 0, nonce, func_return);
}
//-----------------------------------------------------------------------------
@ -345,210 +336,199 @@ void EPA_PACE_Collect_Nonce(UsbCommand *c)
// Returns the actual size of the nonce on success or a less-than-zero error
// code on failure.
//-----------------------------------------------------------------------------
int EPA_PACE_Get_Nonce(uint8_t requested_length, uint8_t *nonce)
{
// build the APDU
uint8_t apdu[sizeof(apdu_general_authenticate_pace_get_nonce) + 1];
// copy the constant part
memcpy(apdu,
apdu_general_authenticate_pace_get_nonce,
sizeof(apdu_general_authenticate_pace_get_nonce));
// append Le (requested length + 2 due to tag/length taking 2 bytes) in RAPDU
apdu[sizeof(apdu_general_authenticate_pace_get_nonce)] = requested_length + 4;
int EPA_PACE_Get_Nonce(uint8_t requested_length, uint8_t *nonce) {
// build the APDU
uint8_t apdu[sizeof(apdu_general_authenticate_pace_get_nonce) + 1];
// copy the constant part
memcpy(apdu,
apdu_general_authenticate_pace_get_nonce,
sizeof(apdu_general_authenticate_pace_get_nonce));
// append Le (requested length + 2 due to tag/length taking 2 bytes) in RAPDU
apdu[sizeof(apdu_general_authenticate_pace_get_nonce)] = requested_length + 4;
// send it
uint8_t response_apdu[262];
int send_return = EPA_APDU(apdu,
sizeof(apdu),
response_apdu);
// check if the command succeeded
if (send_return < 6
|| response_apdu[send_return - 4] != 0x90
|| response_apdu[send_return - 3] != 0x00)
{
return -1;
}
// send it
uint8_t response_apdu[262];
int send_return = EPA_APDU(apdu,
sizeof(apdu),
response_apdu);
// check if the command succeeded
if (send_return < 6
|| response_apdu[send_return - 4] != 0x90
|| response_apdu[send_return - 3] != 0x00) {
return -1;
}
// if there is no nonce in the RAPDU, return here
if (send_return < 10)
{
// no error
return 0;
}
// get the actual length of the nonce
uint8_t nonce_length = response_apdu[5];
if (nonce_length > send_return - 10)
{
nonce_length = send_return - 10;
}
// copy the nonce
memcpy(nonce, response_apdu + 6, nonce_length);
// if there is no nonce in the RAPDU, return here
if (send_return < 10) {
// no error
return 0;
}
// get the actual length of the nonce
uint8_t nonce_length = response_apdu[5];
if (nonce_length > send_return - 10) {
nonce_length = send_return - 10;
}
// copy the nonce
memcpy(nonce, response_apdu + 6, nonce_length);
return nonce_length;
return nonce_length;
}
//-----------------------------------------------------------------------------
// Initializes the PACE protocol by performing the "MSE: Set AT" step
// Returns 0 on success or a non-zero error code on failure
//-----------------------------------------------------------------------------
int EPA_PACE_MSE_Set_AT(pace_version_info_t pace_version_info, uint8_t password)
{
// create the MSE: Set AT APDU
uint8_t apdu[23];
// the minimum length (will be increased as more data is added)
size_t apdu_length = 20;
// copy the constant part
memcpy(apdu,
apdu_mse_set_at_start,
sizeof(apdu_mse_set_at_start));
// type: OID
apdu[5] = 0x80;
// length of the OID
apdu[6] = sizeof(pace_version_info.oid);
// copy the OID
memcpy(apdu + 7,
pace_version_info.oid,
sizeof(pace_version_info.oid));
// type: password
apdu[17] = 0x83;
// length: 1
apdu[18] = 1;
// password
apdu[19] = password;
// if standardized domain parameters are used, copy the ID
if (pace_version_info.parameter_id != 0) {
apdu_length += 3;
// type: domain parameter
apdu[20] = 0x84;
// length: 1
apdu[21] = 1;
// copy the parameter ID
apdu[22] = pace_version_info.parameter_id;
}
// now set Lc to the actual length
apdu[4] = apdu_length - 5;
// send it
uint8_t response_apdu[6];
int send_return = EPA_APDU(apdu,
apdu_length,
response_apdu);
// check if the command succeeded
if (send_return != 6
|| response_apdu[send_return - 4] != 0x90
|| response_apdu[send_return - 3] != 0x00)
{
return 1;
}
return 0;
int EPA_PACE_MSE_Set_AT(pace_version_info_t pace_version_info, uint8_t password) {
// create the MSE: Set AT APDU
uint8_t apdu[23];
// the minimum length (will be increased as more data is added)
size_t apdu_length = 20;
// copy the constant part
memcpy(apdu,
apdu_mse_set_at_start,
sizeof(apdu_mse_set_at_start));
// type: OID
apdu[5] = 0x80;
// length of the OID
apdu[6] = sizeof(pace_version_info.oid);
// copy the OID
memcpy(apdu + 7,
pace_version_info.oid,
sizeof(pace_version_info.oid));
// type: password
apdu[17] = 0x83;
// length: 1
apdu[18] = 1;
// password
apdu[19] = password;
// if standardized domain parameters are used, copy the ID
if (pace_version_info.parameter_id != 0) {
apdu_length += 3;
// type: domain parameter
apdu[20] = 0x84;
// length: 1
apdu[21] = 1;
// copy the parameter ID
apdu[22] = pace_version_info.parameter_id;
}
// now set Lc to the actual length
apdu[4] = apdu_length - 5;
// send it
uint8_t response_apdu[6];
int send_return = EPA_APDU(apdu,
apdu_length,
response_apdu);
// check if the command succeeded
if (send_return != 6
|| response_apdu[send_return - 4] != 0x90
|| response_apdu[send_return - 3] != 0x00) {
return 1;
}
return 0;
}
//-----------------------------------------------------------------------------
// Perform the PACE protocol by replaying given APDUs
//-----------------------------------------------------------------------------
void EPA_PACE_Replay(UsbCommand *c)
{
uint32_t timings[sizeof(apdu_lengths_replay) / sizeof(apdu_lengths_replay[0])] = {0};
void EPA_PACE_Replay(PacketCommandNG *c) {
uint32_t timings[ARRAYLEN(apdu_lengths_replay)] = {0};
// if an APDU has been passed, save it
if (c->arg[0] != 0) {
// make sure it's not too big
if(c->arg[2] > apdus_replay[c->arg[0] - 1].len)
{
cmd_send(CMD_ACK, 1, 0, 0, NULL, 0);
}
memcpy(apdus_replay[c->arg[0] - 1].data + c->arg[1],
c->d.asBytes,
c->arg[2]);
// save/update APDU length
if (c->arg[1] == 0) {
apdu_lengths_replay[c->arg[0] - 1] = c->arg[2];
} else {
apdu_lengths_replay[c->arg[0] - 1] += c->arg[2];
}
cmd_send(CMD_ACK, 0, 0, 0, NULL, 0);
return;
}
// if an APDU has been passed, save it
if (c->oldarg[0] != 0) {
// make sure it's not too big
if (c->oldarg[2] > apdus_replay[c->oldarg[0] - 1].len) {
reply_old(CMD_ACK, 1, 0, 0, NULL, 0);
}
memcpy(apdus_replay[c->oldarg[0] - 1].data + c->oldarg[1],
c->data.asBytes,
c->oldarg[2]);
// save/update APDU length
if (c->oldarg[1] == 0) {
apdu_lengths_replay[c->oldarg[0] - 1] = c->oldarg[2];
} else {
apdu_lengths_replay[c->oldarg[0] - 1] += c->oldarg[2];
}
reply_old(CMD_ACK, 0, 0, 0, NULL, 0);
return;
}
// return value of a function
int func_return;
// return value of a function
int func_return;
// set up communication
func_return = EPA_Setup();
if (func_return != 0) {
EPA_Finish();
cmd_send(CMD_ACK, 2, func_return, 0, NULL, 0);
return;
}
// set up communication
func_return = EPA_Setup();
if (func_return != 0) {
EPA_Finish();
reply_old(CMD_ACK, 2, func_return, 0, NULL, 0);
return;
}
// increase the timeout (at least some cards really do need this!)/////////////
// iso14a_set_timeout(0x0003FFFF);
// increase the timeout (at least some cards really do need this!)/////////////
// iso14a_set_timeout(0x0003FFFF);
// response APDU
uint8_t response_apdu[300] = {0};
// response APDU
uint8_t response_apdu[300] = {0};
// now replay the data and measure the timings
for (int i = 0; i < sizeof(apdu_lengths_replay); i++) {
StartCountUS();
func_return = EPA_APDU(apdus_replay[i].data,
apdu_lengths_replay[i],
response_apdu);
timings[i] = GetCountUS();
// every step but the last one should succeed
if (i < sizeof(apdu_lengths_replay) - 1
&& (func_return < 6
|| response_apdu[func_return - 4] != 0x90
|| response_apdu[func_return - 3] != 0x00))
{
EPA_Finish();
cmd_send(CMD_ACK, 3 + i, func_return, 0, timings, 20);
return;
}
}
EPA_Finish();
cmd_send(CMD_ACK,0,0,0,timings,20);
return;
// now replay the data and measure the timings
for (int i = 0; i < sizeof(apdu_lengths_replay); i++) {
StartCountUS();
func_return = EPA_APDU(apdus_replay[i].data,
apdu_lengths_replay[i],
response_apdu);
timings[i] = GetCountUS();
// every step but the last one should succeed
if (i < sizeof(apdu_lengths_replay) - 1
&& (func_return < 6
|| response_apdu[func_return - 4] != 0x90
|| response_apdu[func_return - 3] != 0x00)) {
EPA_Finish();
reply_old(CMD_ACK, 3 + i, func_return, 0, timings, 20);
return;
}
}
EPA_Finish();
reply_old(CMD_ACK, 0, 0, 0, timings, 20);
return;
}
//-----------------------------------------------------------------------------
// Set up a communication channel (Card Select, PPS)
// Returns 0 on success or a non-zero error code on failure
//-----------------------------------------------------------------------------
int EPA_Setup()
{
int return_code = 0;
uint8_t uid[10];
uint8_t pps_response[3];
uint8_t pps_response_par[1];
iso14a_card_select_t card_a_info;
iso14b_card_select_t card_b_info;
int EPA_Setup() {
uint8_t uid[10];
iso14a_card_select_t card_a_info;
// first, look for type A cards
// power up the field
iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
// select the card
return_code = iso14443a_select_card(uid, &card_a_info, NULL, true, 0, false);
if (return_code == 1) {
// send the PPS request
ReaderTransmit((uint8_t *)pps, sizeof(pps), NULL);
return_code = ReaderReceive(pps_response, pps_response_par);
if (return_code != 3 || pps_response[0] != 0xD0) {
return return_code == 0 ? 2 : return_code;
}
Dbprintf("ISO 14443 Type A");
iso_type = 'a';
return 0;
}
// first, look for type A cards
// power up the field
iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
// select the card
int return_code = iso14443a_select_card(uid, &card_a_info, NULL, true, 0, false);
if (return_code == 1) {
uint8_t pps_response[3];
uint8_t pps_response_par[1];
// send the PPS request
ReaderTransmit((uint8_t *)pps, sizeof(pps), NULL);
return_code = ReaderReceive(pps_response, pps_response_par);
if (return_code != 3 || pps_response[0] != 0xD0) {
return return_code == 0 ? 2 : return_code;
}
Dbprintf("ISO 14443 Type A");
iso_type = 'a';
return 0;
}
// if we're here, there is no type A card, so we look for type B
// power up the field
iso14443b_setup();
// select the card
return_code = iso14443b_select_card( &card_b_info );
if (return_code == 1) {
Dbprintf("ISO 14443 Type B");
iso_type = 'b';
return 0;
}
Dbprintf("No card found.");
return 1;
// if we're here, there is no type A card, so we look for type B
// power up the field
iso14443b_setup();
iso14b_card_select_t card_b_info;
// select the card
return_code = iso14443b_select_card(&card_b_info);
if (return_code == 0) {
Dbprintf("ISO 14443 Type B");
iso_type = 'b';
return 0;
}
Dbprintf("No card found.");
return 1;
}

View file

@ -18,9 +18,9 @@
// this struct is used by EPA_Parse_CardAccess and contains info about the
// PACE protocol supported by the chip
typedef struct {
uint8_t oid[10];
uint8_t version;
uint8_t parameter_id;
uint8_t oid[10];
uint8_t version;
uint8_t parameter_id;
} pace_version_info_t;
// note: EPA_PACE_Collect_Nonce and EPA_PACE_Replay are declared in apps.h

File diff suppressed because it is too large Load diff

View file

@ -1,88 +1,140 @@
#include "flashmem.h"
/* here: use NCPS2 @ PA10: */
#define SPI_CSR_NUM 2 // Chip Select register[] 0,1,2,3 (at91samv512 has 4)
/* PCS_0 for NPCS0, PCS_1 for NPCS1 ... */
#define PCS_0 ((0<<0)|(1<<1)|(1<<2)|(1<<3)) // 0xE - 1110
#define PCS_1 ((1<<0)|(0<<1)|(1<<2)|(1<<3)) // 0xD - 1101
#define PCS_2 ((1<<0)|(1<<1)|(0<<2)|(1<<3)) // 0xB - 1011
#define PCS_3 ((1<<0)|(1<<1)|(1<<2)|(0<<3)) // 0x7 - 0111
// TODO
#if (SPI_CSR_NUM == 0)
#define SPI_MR_PCS PCS_0
#elif (SPI_CSR_NUM == 1)
#define SPI_MR_PCS PCS_1
#elif (SPI_CSR_NUM == 2)
#define SPI_MR_PCS PCS_2
#elif (SPI_CSR_NUM == 3)
#define SPI_MR_PCS PCS_3
#else
#error "SPI_CSR_NUM invalid"
// not realy - when using an external address decoder...
// but this code takes over the complete SPI-interace anyway
#endif
#define SPI_CSR_NUM 2
#define SPI_PCS(npcs) ((~(1 << (npcs)) & 0xF) << 16)
/// Calculates the value of the CSR SCBR field given the baudrate and MCK.
#define SPI_SCBR(baudrate, masterClock) ((uint32_t) ((masterClock) / (baudrate)) << 8)
/// Calculates the value of the CSR DLYBS field given the desired delay (in ns)
#define SPI_DLYBS(delay, masterClock) ((uint32_t) ((((masterClock) / 1000000) * (delay)) / 1000) << 16)
/// Calculates the value of the CSR DLYBCT field given the desired delay (in ns)
#define SPI_DLYBCT(delay, masterClock) ((uint32_t) ((((masterClock) / 1000000) * (delay)) / 32000) << 24)
/*
1-256256
CS拉高
*/
uint32_t FLASHMEM_SPIBAUDRATE = FLASH_BAUD;
void FlashSetup(void) {
// PA1 -> SPI_NCS3 chip select (MEM)
// PA10 -> SPI_NCS2 chip select (LCD)
// PA11 -> SPI_NCS0 chip select (FPGA)
// PA12 -> SPI_MISO Master-In Slave-Out
// PA13 -> SPI_MOSI Master-Out Slave-In
// PA14 -> SPI_SPCK Serial Clock
void FlashmemSetSpiBaudrate(uint32_t baudrate) {
FLASHMEM_SPIBAUDRATE = baudrate;
Dbprintf("Spi Baudrate : %dMhz", FLASHMEM_SPIBAUDRATE / 1000000);
}
// Disable PIO control of the following pins, allows use by the SPI peripheral
AT91C_BASE_PIOA->PIO_PDR |= (GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK | GPIO_NCS2);
// initialize
bool FlashInit() {
FlashSetup(FLASHMEM_SPIBAUDRATE);
// Pull-up Enable
AT91C_BASE_PIOA->PIO_PPUER |= (GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK | GPIO_NCS2);
StartTicks();
// Peripheral A
AT91C_BASE_PIOA->PIO_ASR |= (GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK);
if (Flash_CheckBusy(BUSY_TIMEOUT)) {
StopTicks();
return false;
}
// Peripheral B
AT91C_BASE_PIOA->PIO_BSR |= GPIO_NCS2;
return true;
}
//enable the SPI Peripheral clock
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SPI);
void FlashSetup(uint32_t baudrate) {
//WDT_DISABLE
AT91C_BASE_WDTC->WDTC_WDMR = AT91C_WDTC_WDDIS;
// Enable SPI
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIEN;
// PA10 -> SPI_NCS2 chip select (FLASHMEM)
// PA11 -> SPI_NCS0 chip select (FPGA)
// PA12 -> SPI_MISO Master-In Slave-Out
// PA13 -> SPI_MOSI Master-Out Slave-In
// PA14 -> SPI_SPCK Serial Clock
// NPCS2 Mode 0
AT91C_BASE_SPI->SPI_MR =
( 0 << 24) | // Delay between chip selects (take default: 6 MCK periods)
(0xB << 16) | // Peripheral Chip Select (selects SPI_NCS2 or PA10)
( 0 << 7) | // Local Loopback Disabled
( 1 << 4) | // Mode Fault Detection disabled
( 0 << 2) | // Chip selects connected directly to peripheral
( 0 << 1) | // Fixed Peripheral Select
( 1 << 0); // Master Mode
// Disable PIO control of the following pins, allows use by the SPI peripheral
AT91C_BASE_PIOA->PIO_PDR |= (GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK | GPIO_NCS2);
// 8 bit
AT91C_BASE_SPI->SPI_CSR[2] =
( 0 << 24) | // Delay between Consecutive Transfers (32 MCK periods)
( 0 << 16) | // Delay Before SPCK (1 MCK period)
( 6 << 8) | // Serial Clock Baud Rate (baudrate = MCK/6 = 24Mhz/6 = 4M baud
( 0 << 4) | // Bits per Transfer (8 bits)
( 1 << 3) | // Chip Select inactive after transfer
( 1 << 1) | // Clock Phase data captured on leading edge, changes on following edge
( 0 << 0); // Clock Polarity inactive state is logic 0
// Pull-up Enable
AT91C_BASE_PIOA->PIO_PPUER |= (GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK | GPIO_NCS2);
// read first, empty buffer
if (AT91C_BASE_SPI->SPI_RDR == 0) {};
// Peripheral A
AT91C_BASE_PIOA->PIO_ASR |= (GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK);
// Peripheral B
AT91C_BASE_PIOA->PIO_BSR |= GPIO_NCS2;
//enable the SPI Peripheral clock
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SPI);
//reset spi needs double SWRST, see atmel's errata on this case
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST;
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST;
// Enable SPI
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIEN;
// NPCS2 Mode 0
AT91C_BASE_SPI->SPI_MR =
(0 << 24) | // Delay between chip selects = DYLBCS/MCK BUT:
// If DLYBCS is less than or equal to six, six MCK periods
// will be inserted by default.
SPI_PCS(SPI_CSR_NUM) | // Peripheral Chip Select (selects SPI_NCS2 or PA10)
(0 << 7) | // Disable LLB (1=MOSI2MISO test mode)
(1 << 4) | // Disable ModeFault Protection
(0 << 3) | // makes spi operate at MCK (1 is MCK/2)
(0 << 2) | // Chip selects connected directly to peripheral
AT91C_SPI_PS_FIXED | // Fixed Peripheral Select
AT91C_SPI_MSTR; // Master Mode
uint8_t csaat = 1;
uint32_t dlybct = 0;
uint8_t ncpha = 1;
uint8_t cpol = 0;
if (baudrate > FLASH_MINFAST) {
baudrate = FLASH_FASTBAUD;
//csaat = 0;
dlybct = 1500;
ncpha = 0;
cpol = 0;
}
AT91C_BASE_SPI->SPI_CSR[2] =
SPI_DLYBCT(dlybct, MCK) | // Delay between Consecutive Transfers (32 MCK periods)
SPI_DLYBS(0, MCK) | // Delay Beforce SPCK CLock
SPI_SCBR(baudrate, MCK) | // SPI Baudrate Selection
AT91C_SPI_BITS_8 | // Bits per Transfer (8 bits)
//AT91C_SPI_CSAAT | // Chip Select inactive after transfer
// 40.4.6.2 SPI: Bad tx_ready Behavior when CSAAT = 1 and SCBR = 1
// If the SPI is programmed with CSAAT = 1, SCBR(baudrate) = 1 and two transfers are performed consecutively on
// the same slave with an IDLE state between them, the tx_ready signal does not rise after the second data has been
// transferred in the shifter. This can imply for example, that the second data is sent twice.
// COLIN :: For now we STILL use CSAAT=1 to avoid having to (de)assert NPCS manually via PIO lines and we deal with delay
(csaat << 3) |
/* Spi modes:
Mode CPOL CPHA NCPHA
0 0 0 1 clock normally low read on rising edge
1 0 1 0 clock normally low read on falling edge
2 1 0 1 clock normally high read on falling edge
3 1 1 0 clock normally high read on rising edge
However, page 512 of the AT91SAM7Sx datasheet say "Note that in SPI
master mode the ATSAM7S512/256/128/64/321/32 does not sample the data
(MISO) on the opposite edge where data clocks out (MOSI) but the same
edge is used as shown in Figure 36-3 and Figure 36-4." Figure 36-3
shows that CPOL=NCPHA=0 or CPOL=NCPHA=1 samples on the rising edge and
that the data changes sometime after the rising edge (about 2 ns). To
be consistent with normal SPI operation, it is probably safe to say
that the data changes on the falling edge and should be sampled on the
rising edge. Therefore, it appears that NCPHA should be treated the
same as CPHA. Thus:
Mode CPOL CPHA NCPHA
0 0 0 0 clock normally low read on rising edge
1 0 1 1 clock normally low read on falling edge
2 1 0 0 clock normally high read on falling edge
3 1 1 1 clock normally high read on rising edge
Update: for 24MHz, writing is more stable with ncpha=1, else bitflips occur.
*/
(ncpha << 1) | // Clock Phase data captured on leading edge, changes on following edge
(cpol << 0); // Clock Polarity inactive state is logic 0
// read first, empty buffer
if (AT91C_BASE_SPI->SPI_RDR == 0) {};
}
void FlashStop(void) {
//* Reset all the Chip Select register
//Bof
//* Reset all the Chip Select register
AT91C_BASE_SPI->SPI_CSR[0] = 0;
AT91C_BASE_SPI->SPI_CSR[1] = 0;
AT91C_BASE_SPI->SPI_CSR[2] = 0;
@ -93,252 +145,348 @@ void FlashStop(void) {
// Disable all interrupts
AT91C_BASE_SPI->SPI_IDR = 0xFFFFFFFF;
// SPI disable
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIDIS;
if ( MF_DBGLEVEL > 3 ) Dbprintf("FlashStop");
StopTicks();
// SPI disable
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIDIS;
if (DBGLEVEL > 3) Dbprintf("FlashStop");
StopTicks();
}
// send one byte over SPI
uint16_t FlashSendByte(uint32_t data) {
uint16_t incoming = 0;
// send one byte over SPI
uint16_t FlashSendByte(uint32_t data) {
WDT_HIT();
// wait until SPI is ready for transfer
//if you are checking for incoming data returned then the TXEMPTY flag is redundant
//while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0) {};
// wait until SPI is ready for transfer
while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0) {};
// send the data
AT91C_BASE_SPI->SPI_TDR = data;
// send the data
AT91C_BASE_SPI->SPI_TDR = data;
//while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TDRE) == 0){};
// wait recive transfer is complete
while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_RDRF) == 0)
WDT_HIT();
// wait recive transfer is complete
while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_RDRF) == 0) {};
// reading incoming data
incoming = ((AT91C_BASE_SPI->SPI_RDR) & 0xFFFF);
return incoming;
// reading incoming data
return ((AT91C_BASE_SPI->SPI_RDR) & 0xFFFF);
}
// send last byte over SPI
// send last byte over SPI
uint16_t FlashSendLastByte(uint32_t data) {
return FlashSendByte(data | AT91C_SPI_LASTXFER);
return FlashSendByte(data | AT91C_SPI_LASTXFER);
}
// read state register 1
// read state register 1
uint8_t Flash_ReadStat1(void) {
FlashSendByte(READSTAT1);
uint8_t stat1 = FlashSendLastByte(0xFF);
// if ( MF_DBGLEVEL > 3 ) Dbprintf("stat1 [%02x]", stat1);
return stat1;
FlashSendByte(READSTAT1);
return FlashSendLastByte(0xFF);
}
// read state register 2
uint8_t Flash_ReadStat2(void) {
FlashSendByte(READSTAT2);
uint8_t stat2 = FlashSendLastByte(0xFF);
// if ( MF_DBGLEVEL > 3 ) Dbprintf("stat2 [%02x]", stat2);
return stat2;
}
bool Flash_CheckBusy(uint32_t timeout) {
WaitUS(WINBOND_WRITE_DELAY);
StartCountUS();
uint32_t _time = GetCountUS();
// determine whether FLASHMEM is busy
bool Flash_CheckBusy(uint16_t times) {
bool ret = (Flash_ReadStat1() & BUSY);
if (DBGLEVEL > 3) Dbprintf("Checkbusy in...");
if (!ret || !times || !(times--))
return ret;
do {
if (!(Flash_ReadStat1() & BUSY)) {
return false;
}
} while ((GetCountUS() - _time) < timeout);
while (times) {
WDT_HIT();
SpinDelay(1);
ret = (Flash_ReadStat1() & BUSY);
if (!ret)
break;
times--;
}
return ret;
if (timeout <= (GetCountUS() - _time)) {
return true;
}
return false;
}
// read ID out
uint8_t Flash_ReadID(void) {
if (Flash_CheckBusy(100)) return 0;
if (Flash_CheckBusy(BUSY_TIMEOUT)) return 0;
// Manufacture ID / device ID
FlashSendByte(ID);
FlashSendByte(0x00);
FlashSendByte(0x00);
FlashSendByte(0x00);
// Manufacture ID / device ID
FlashSendByte(ID);
FlashSendByte(0x00);
FlashSendByte(0x00);
FlashSendByte(0x00);
uint8_t man_id = FlashSendByte(0xFF);
uint8_t dev_id = FlashSendLastByte(0xFF);
uint8_t dev_id = FlashSendLastByte(0xFF);
if ( MF_DBGLEVEL > 3 ) Dbprintf("Flash ReadID | Man ID %02x | Device ID %02x", man_id, dev_id);
if ( (man_id == WINBOND_MANID ) && (dev_id == WINBOND_DEVID) )
return dev_id;
if (DBGLEVEL > 3) Dbprintf("Flash ReadID | Man ID %02x | Device ID %02x", man_id, dev_id);
return 0;
if ((man_id == WINBOND_MANID) && (dev_id == WINBOND_DEVID))
return dev_id;
return 0;
}
// read unique id for chip.
void Flash_UniqueID(uint8_t *uid) {
if (Flash_CheckBusy(100)) return;
if (Flash_CheckBusy(BUSY_TIMEOUT)) return;
// reading unique serial number
FlashSendByte(UNIQUE_ID);
FlashSendByte(0xFF);
FlashSendByte(0xFF);
FlashSendByte(0xFF);
FlashSendByte(0xFF);
// reading unique serial number
FlashSendByte(UNIQUE_ID);
FlashSendByte(0xFF);
FlashSendByte(0xFF);
FlashSendByte(0xFF);
FlashSendByte(0xFF);
uid[7] = FlashSendByte(0xFF);
uid[6] = FlashSendByte(0xFF);
uid[5] = FlashSendByte(0xFF);
uid[4] = FlashSendByte(0xFF);
uid[7] = FlashSendByte(0xFF);
uid[6] = FlashSendByte(0xFF);
uid[5] = FlashSendByte(0xFF);
uid[4] = FlashSendByte(0xFF);
uid[3] = FlashSendByte(0xFF);
uid[2] = FlashSendByte(0xFF);
uid[1] = FlashSendByte(0xFF);
uid[0] = FlashSendLastByte(0xFF);
uid[2] = FlashSendByte(0xFF);
uid[1] = FlashSendByte(0xFF);
uid[0] = FlashSendLastByte(0xFF);
}
uint16_t Flash_ReadData(uint32_t address, uint8_t *out, uint16_t len) {
if (!FlashInit()) return 0;
Flash_ReadStat1();
// length should never be zero
if (!len || Flash_CheckBusy(100)) return 0;
FlashSendByte(READDATA);
FlashSendByte((address >> 16) & 0xFF);
FlashSendByte((address >> 8) & 0xFF);
FlashSendByte((address >> 0) & 0xFF);
if (!FlashInit()) return 0;
uint16_t i = 0;
for (; i < (len - 1); i++)
out[i] = FlashSendByte(0xFF);
// length should never be zero
if (!len || Flash_CheckBusy(BUSY_TIMEOUT)) return 0;
out[i] = FlashSendLastByte(0xFF);
FlashStop();
return len;
uint8_t cmd = (FASTFLASH) ? FASTREAD : READDATA;
FlashSendByte(cmd);
Flash_TransferAdresse(address);
if (FASTFLASH) {
FlashSendByte(DUMMYBYTE);
}
uint16_t i = 0;
for (; i < (len - 1); i++)
out[i] = FlashSendByte(0xFF);
out[i] = FlashSendLastByte(0xFF);
FlashStop();
return len;
}
// Write data can only program one page. A page has 256 bytes.
void Flash_TransferAdresse(uint32_t address) {
FlashSendByte((address >> 16) & 0xFF);
FlashSendByte((address >> 8) & 0xFF);
FlashSendByte((address >> 0) & 0xFF);
}
/* This ensure we can ReadData without having to cycle through initialization everytime */
uint16_t Flash_ReadDataCont(uint32_t address, uint8_t *out, uint16_t len) {
// length should never be zero
if (!len) return 0;
uint8_t cmd = (FASTFLASH) ? FASTREAD : READDATA;
FlashSendByte(cmd);
Flash_TransferAdresse(address);
if (FASTFLASH) {
FlashSendByte(DUMMYBYTE);
}
uint16_t i = 0;
for (; i < (len - 1); i++)
out[i] = FlashSendByte(0xFF);
out[i] = FlashSendLastByte(0xFF);
return len;
}
////////////////////////////////////////
// Write data can only program one page. A page has 256 bytes.
// if len > 256, it might wrap around and overwrite pos 0.
uint16_t Flash_WriteData(uint32_t address, uint8_t *in, uint16_t len) {
// length should never be zero
if (!len)
return 0;
// Max 256 bytes write
if (((address & 0xFF) + len) > 256) {
Dbprintf("Flash_WriteData 256 fail [ 0x%02x ] [ %u ]", (address & 0xFF)+len, len );
return 0;
}
// out-of-range
if ( (( address >> 16 ) & 0xFF ) > MAX_BLOCKS) {
Dbprintf("Flash_WriteData, block out-of-range");
return 0;
}
// length should never be zero
if (!len)
return 0;
if (!FlashInit()) {
if ( MF_DBGLEVEL > 3 ) Dbprintf("Flash_WriteData init fail");
return 0;
}
Flash_ReadStat1();
// Max 256 bytes write
if (((address & 0xFF) + len) > 256) {
Dbprintf("Flash_WriteData 256 fail [ 0x%02x ] [ %u ]", (address & 0xFF) + len, len);
return 0;
}
Flash_WriteEnable();
FlashSendByte(PAGEPROG);
FlashSendByte((address >> 16) & 0xFF);
FlashSendByte((address >> 8) & 0xFF);
FlashSendByte((address >> 0) & 0xFF);
// out-of-range
if (((address >> 16) & 0xFF) > MAX_BLOCKS) {
Dbprintf("Flash_WriteData, block out-of-range");
return 0;
}
uint16_t i = 0;
for (; i < (len - 1); i++)
FlashSendByte(in[i]);
if (!FlashInit()) {
if (DBGLEVEL > 3) Dbprintf("Flash_WriteData init fail");
return 0;
}
FlashSendLastByte(in[i]);
Flash_CheckBusy(BUSY_TIMEOUT);
FlashStop();
return len;
Flash_WriteEnable();
FlashSendByte(PAGEPROG);
FlashSendByte((address >> 16) & 0xFF);
FlashSendByte((address >> 8) & 0xFF);
FlashSendByte((address >> 0) & 0xFF);
uint16_t i = 0;
for (; i < (len - 1); i++)
FlashSendByte(in[i]);
FlashSendLastByte(in[i]);
FlashStop();
return len;
}
bool Flash_WipeMemoryPage(uint8_t page) {
if (!FlashInit()) {
if ( MF_DBGLEVEL > 3 ) Dbprintf("Flash_WriteData init fail");
return false;
}
Flash_ReadStat1();
// Each block is 64Kb. One block erase takes 1s ( 1000ms )
Flash_WriteEnable(); Flash_Erase64k(page); Flash_CheckBusy(1000);
FlashStop();
return true;
// length should never be zero
// Max 256 bytes write
// out-of-range
uint16_t Flash_WriteDataCont(uint32_t address, uint8_t *in, uint16_t len) {
if (!len)
return 0;
if (((address & 0xFF) + len) > 256) {
Dbprintf("Flash_WriteDataCont 256 fail [ 0x%02x ] [ %u ]", (address & 0xFF) + len, len);
return 0;
}
if (((address >> 16) & 0xFF) > MAX_BLOCKS) {
Dbprintf("Flash_WriteDataCont, block out-of-range");
return 0;
}
FlashSendByte(PAGEPROG);
FlashSendByte((address >> 16) & 0xFF);
FlashSendByte((address >> 8) & 0xFF);
FlashSendByte((address >> 0) & 0xFF);
uint16_t i = 0;
for (; i < (len - 1); i++)
FlashSendByte(in[i]);
FlashSendLastByte(in[i]);
return len;
}
// assumes valid start 256 based 00 address
//
uint16_t Flash_Write(uint32_t address, uint8_t *in, uint16_t len) {
bool isok;
uint16_t res, bytes_sent = 0, bytes_remaining = len;
uint8_t buf[FLASH_MEM_BLOCK_SIZE];
while (bytes_remaining > 0) {
Flash_CheckBusy(BUSY_TIMEOUT);
Flash_WriteEnable();
uint32_t bytes_in_packet = MIN(FLASH_MEM_BLOCK_SIZE, bytes_remaining);
memcpy(buf, in + bytes_sent, bytes_in_packet);
res = Flash_WriteDataCont(address + bytes_sent, buf, bytes_in_packet);
bytes_remaining -= bytes_in_packet;
bytes_sent += bytes_in_packet;
isok = (res == bytes_in_packet);
if (!isok)
goto out;
}
out:
FlashStop();
return len;
}
bool Flash_WipeMemoryPage(uint8_t page) {
if (!FlashInit()) {
if (DBGLEVEL > 3) Dbprintf("Flash_WriteData init fail");
return false;
}
Flash_ReadStat1();
// Each block is 64Kb. One block erase takes 1s ( 1000ms )
Flash_WriteEnable();
Flash_Erase64k(page);
Flash_CheckBusy(BUSY_TIMEOUT);
FlashStop();
return true;
}
// Wipes flash memory completely, fills with 0xFF
bool Flash_WipeMemory() {
if (!FlashInit()) {
if ( MF_DBGLEVEL > 3 ) Dbprintf("Flash_WriteData init fail");
return false;
}
Flash_ReadStat1();
// Each block is 64Kb. Four blocks
// one block erase takes 1s ( 1000ms )
Flash_WriteEnable(); Flash_Erase64k(0); Flash_CheckBusy(1000);
Flash_WriteEnable(); Flash_Erase64k(1); Flash_CheckBusy(1000);
Flash_WriteEnable(); Flash_Erase64k(2); Flash_CheckBusy(1000);
Flash_WriteEnable(); Flash_Erase64k(3); Flash_CheckBusy(1000);
FlashStop();
return true;
if (!FlashInit()) {
if (DBGLEVEL > 3) Dbprintf("Flash_WriteData init fail");
return false;
}
Flash_ReadStat1();
// Each block is 64Kb. Four blocks
// one block erase takes 1s ( 1000ms )
Flash_WriteEnable();
Flash_Erase64k(0);
Flash_CheckBusy(BUSY_TIMEOUT);
Flash_WriteEnable();
Flash_Erase64k(1);
Flash_CheckBusy(BUSY_TIMEOUT);
Flash_WriteEnable();
Flash_Erase64k(2);
Flash_CheckBusy(BUSY_TIMEOUT);
Flash_WriteEnable();
Flash_Erase64k(3);
Flash_CheckBusy(BUSY_TIMEOUT);
FlashStop();
return true;
}
// enable the flash write
// enable the flash write
void Flash_WriteEnable() {
FlashSendLastByte(WRITEENABLE);
if ( MF_DBGLEVEL > 3 ) Dbprintf("Flash Write enabled");
FlashSendLastByte(WRITEENABLE);
if (DBGLEVEL > 3) Dbprintf("Flash Write enabled");
}
// erase 4K at one time
// erase 4K at one time
// execution time: 0.8ms / 800us
bool Flash_Erase4k(uint8_t block, uint8_t sector) {
if (block > MAX_BLOCKS || sector > MAX_SECTORS) return false;
if (block > MAX_BLOCKS || sector > MAX_SECTORS) return false;
FlashSendByte(SECTORERASE);
FlashSendByte(block);
FlashSendByte(sector << 4);
FlashSendLastByte(00);
return true;
FlashSendByte(SECTORERASE);
FlashSendByte(block);
FlashSendByte(sector << 4);
FlashSendLastByte(00);
return true;
}
/*
// erase 32K at one time
// erase 32K at one time
// execution time: 0,3s / 300ms
bool Flash_Erase32k(uint32_t address) {
if (address & (32*1024 - 1)) {
if ( MF_DBGLEVEL > 1 ) Dbprintf("Flash_Erase32k : Address is not align at 4096");
return false;
}
FlashSendByte(BLOCK32ERASE);
FlashSendByte((address >> 16) & 0xFF);
FlashSendByte((address >> 8) & 0xFF);
FlashSendLastByte((address >> 0) & 0xFF);
return true;
if (address & (32*1024 - 1)) {
if ( DBGLEVEL > 1 ) Dbprintf("Flash_Erase32k : Address is not align at 4096");
return false;
}
FlashSendByte(BLOCK32ERASE);
FlashSendByte((address >> 16) & 0xFF);
FlashSendByte((address >> 8) & 0xFF);
FlashSendLastByte((address >> 0) & 0xFF);
return true;
}
*/
@ -351,67 +499,90 @@ bool Flash_Erase32k(uint32_t address) {
// 0x02 00 00 -- 0x 02 FF FF == block 2
// 0x03 00 00 -- 0x 03 FF FF == block 3
bool Flash_Erase64k(uint8_t block) {
if (block > MAX_BLOCKS) return false;
FlashSendByte(BLOCK64ERASE);
FlashSendByte(block);
FlashSendByte(0x00);
FlashSendLastByte(0x00);
return true;
if (block > MAX_BLOCKS) return false;
FlashSendByte(BLOCK64ERASE);
FlashSendByte(block);
FlashSendByte(0x00);
FlashSendLastByte(0x00);
return true;
}
// Erase chip
/*
// Erase chip
void Flash_EraseChip(void) {
FlashSendLastByte(CHIPERASE);
}
// initialize
bool FlashInit(void) {
FlashSetup();
StartTicks();
if (Flash_CheckBusy(100)) {
StopTicks();
return false;
}
if ( MF_DBGLEVEL > 3 ) Dbprintf("FlashInit OK");
return true;
FlashSendLastByte(CHIPERASE);
}
*/
void Flashmem_print_status(void) {
DbpString("Flash memory");
DbpString(_BLUE_("Flash memory"));
Dbprintf(" Baudrate................" _GREEN_("%d MHz"), FLASHMEM_SPIBAUDRATE / 1000000);
if (!FlashInit()) {
DbpString(" Init...................." _RED_("FAILED"));
return;
}
DbpString(" Init...................." _GREEN_("OK"));
uint8_t dev_id = Flash_ReadID();
switch (dev_id) {
case 0x11 :
DbpString(" Memory size............." _YELLOW_("2 mbits / 256 kb"));
break;
case 0x10 :
DbpString(" Memory size..... ......." _YELLOW_("1 mbits / 128 kb"));
break;
case 0x05 :
DbpString(" Memory size............." _YELLOW_("512 kbits / 64 kb"));
break;
default :
DbpString(" Device ID..............." _YELLOW_(" --> Unknown <--"));
break;
}
uint8_t uid[8] = {0, 0, 0, 0, 0, 0, 0, 0};
Flash_UniqueID(uid);
Dbprintf(" Unique ID...............0x%02X%02X%02X%02X%02X%02X%02X%02X",
uid[7], uid[6], uid[5], uid[4],
uid[3], uid[2], uid[1], uid[0]
);
FlashStop();
}
void Flashmem_print_info(void) {
if (!FlashInit()) return;
DbpString(_BLUE_("Flash memory dictionary loaded"));
// load dictionary offsets.
uint8_t keysum[2];
uint16_t num;
uint16_t isok = Flash_ReadDataCont(DEFAULT_MF_KEYS_OFFSET, keysum, 2);
if (isok == 2) {
num = ((keysum[1] << 8) | keysum[0]);
if (num != 0xFFFF && num != 0x0)
Dbprintf(" Mifare................"_YELLOW_("%d")"keys", num);
}
isok = Flash_ReadDataCont(DEFAULT_T55XX_KEYS_OFFSET, keysum, 2);
if (isok == 2) {
num = ((keysum[1] << 8) | keysum[0]);
if (num != 0xFFFF && num != 0x0)
Dbprintf(" T55x7................."_YELLOW_("%d")"keys", num);
}
isok = Flash_ReadDataCont(DEFAULT_ICLASS_KEYS_OFFSET, keysum, 2);
if (isok == 2) {
num = ((keysum[1] << 8) | keysum[0]);
if (num != 0xFFFF && num != 0x0)
Dbprintf(" iClass................"_YELLOW_("%d")"keys", num);
}
FlashStop();
}
if (!FlashInit()) {
DbpString(" init....................FAIL");
return;
}
DbpString(" init....................OK");
uint8_t dev_id = Flash_ReadID();
switch (dev_id) {
case 0x11 :
DbpString(" Memory size.............2 mbits / 256kb");
break;
case 0x10 :
DbpString(" Memory size..... .......1 mbits / 128kb");
break;
case 0x05 :
DbpString(" Memory size.............512 kbits / 64kb");
break;
default :
DbpString(" Device ID............... --> Unknown <--");
break;
}
uint8_t uid[8] = {0,0,0,0,0,0,0,0};
Flash_UniqueID(uid);
Dbprintf(" Unique ID...............0x%02x%02x%02x%02x%02x%02x%02x%02x",
uid[7], uid[6], uid[5], uid[4],
uid[3], uid[2], uid[1], uid[0]
);
FlashStop();
}

View file

@ -23,7 +23,7 @@
* <http://www.gnu.org/licenses/>.
*/
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// Common Instructions //
// Common Instructions //
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
#ifndef __FLASHMEM_H
#define __FLASHMEM_H
@ -32,94 +32,99 @@
#include "apps.h"
#include "ticks.h"
// Used Command
#define ID 0x90
#define MANID 0x90
#define JEDECID 0x9F
// Used Command
#define ID 0x90
#define MANID 0x90
#define JEDECID 0x9F
#define READSTAT1 0x05
#define READSTAT2 0x35
#define WRITESTAT 0x01
#define READSTAT1 0x05
#define READSTAT2 0x35
#define WRITESTAT 0x01
#define WRITEDISABLE 0x04
#define WRITEENABLE 0x06
#define WRITEDISABLE 0x04
#define WRITEENABLE 0x06
#define READDATA 0x03
#define PAGEPROG 0x02
#define READDATA 0x03
#define FASTREAD 0x0B
#define PAGEPROG 0x02
#define SECTORERASE 0x20
#define BLOCK32ERASE 0x52
#define BLOCK64ERASE 0xD8
#define CHIPERASE 0xC7
#define SECTORERASE 0x20
#define BLOCK32ERASE 0x52
#define BLOCK64ERASE 0xD8
#define CHIPERASE 0xC7
#define UNIQUE_ID 0x4B
#define UNIQUE_ID 0x4B
// Not used or not support command
#define RELEASE 0xAB
#define POWERDOWN 0xB9
#define FASTREAD 0x0B
#define SUSPEND 0x75
#define RESUME 0x7A
// Not used or not support command
#define RELEASE 0xAB
#define POWERDOWN 0xB9
#define SUSPEND 0x75
#define RESUME 0x7A
// Flash busy timeout: 20ms is the strict minimum when writing 256kb
#define BUSY_TIMEOUT 50000L
#define WINBOND_MANID 0xEF
#define WINBOND_DEVID 0x11
#define PAGESIZE 0x100
#define WINBOND_WRITE_DELAY 0x02
#define SPI_CLK 48000000
#define BUSY 0x01
#define WRTEN 0x02
#define SUS 0x40
#define DUMMYBYTE 0xEE
#define NULLBYTE 0x00
#define NULLINT 0x0000
#define NO_CONTINUE 0x00
#define PASS 0x01
#define FAIL 0x00
#define maxAddress capacity
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// Chip specific instructions //
// List of Error codes //
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~ Winbond ~~~~~~~~~~~~~~~~~~~~~~~~~//
#define WINBOND_MANID 0xEF
#define WINBOND_DEVID 0x11
#define PAGESIZE 0x100
//~~~~~~~~~~~~~~~~~~~~~~~~ Microchip ~~~~~~~~~~~~~~~~~~~~~~~~//
#define MICROCHIP_MANID 0xBF
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// Definitions //
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
#define SPI_CLK 75000000 //Hex equivalent of 75MHz
#define BUSY 0x01
#define WRTEN 0x02
#define SUS 0x40
#define DUMMYBYTE 0xEE
#define NULLBYTE 0x00
#define NULLINT 0x0000
#define NO_CONTINUE 0x00
#define PASS 0x01
#define FAIL 0x00
#define maxAddress capacity
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// List of Error codes //
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
#define SUCCESS 0x00
#define CALLBEGIN 0x01
#define UNKNOWNCHIP 0x02
#define UNKNOWNCAP 0x03
#define CHIPBUSY 0x04
#define OUTOFBOUNDS 0x05
#define CANTENWRITE 0x06
#define PREVWRITTEN 0x07
#define LOWRAM 0x08
#define NOSUSPEND 0x09
#define UNKNOWNERROR 0xFF
#define SUCCESS 0x00
#define CALLBEGIN 0x01
#define UNKNOWNCHIP 0x02
#define UNKNOWNCAP 0x03
#define CHIPBUSY 0x04
#define OUTOFBOUNDS 0x05
#define CANTENWRITE 0x06
#define PREVWRITTEN 0x07
#define LOWRAM 0x08
#define NOSUSPEND 0x09
#define UNKNOWNERROR 0xFF
// List of blocks
#define MAX_BLOCKS 4
#define MAX_SECTORS 16
#define MAX_BLOCKS 4
#define MAX_SECTORS 16
#define MCK 48000000
//#define FLASH_BAUD 24000000
#define FLASH_MINFAST 24000000 //33000000
#define FLASH_BAUD MCK/2
#define FLASH_FASTBAUD MCK
#define FLASH_MINBAUD FLASH_FASTBAUD
#define FASTFLASH (FLASHMEM_SPIBAUDRATE > FLASH_MINFAST)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
extern void Dbprintf(const char *fmt, ...);
void Dbprintf(const char *fmt, ...);
void FlashSetup(void);
void FlashmemSetSpiBaudrate(uint32_t baudrate);
bool FlashInit();
void FlashSetup(uint32_t baudrate);
void FlashStop(void);
bool Flash_WaitIdle(void);
uint8_t Flash_ReadStat1(void);
uint8_t Flash_ReadStat2(void);
uint16_t FlashSendByte(uint32_t data);
void Flash_TransferAdresse(uint32_t address);
bool Flash_CheckBusy(uint32_t timeout);
void Flash_WriteEnable();
bool Flash_WipeMemoryPage(uint8_t page);
@ -128,12 +133,14 @@ bool Flash_Erase4k(uint8_t block, uint8_t sector);
//bool Flash_Erase32k(uint32_t address);
bool Flash_Erase64k(uint8_t block);
bool FlashInit();
void Flash_UniqueID(uint8_t *uid);
uint8_t Flash_ReadID(void);
uint16_t Flash_ReadData(uint32_t address, uint8_t *out, uint16_t len);
uint16_t Flash_ReadDataCont(uint32_t address, uint8_t *out, uint16_t len);
uint16_t Flash_Write(uint32_t address, uint8_t *in, uint16_t len);
uint16_t Flash_WriteData(uint32_t address, uint8_t *in, uint16_t len);
uint16_t Flash_WriteDataCont(uint32_t address, uint8_t *in, uint16_t len);
void Flashmem_print_status(void);
void Flashmem_print_info(void);
#endif
#endif

View file

@ -7,302 +7,302 @@
//-----------------------------------------------------------------------------
const char FONT6x8[97][8] = {
{0x06,0x08,0x08,0x00,0x00,0x00,0x00,0x00}, // columns, rows, bytes per char
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // space
{0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00}, // !
{0x50,0x50,0x50,0x00,0x00,0x00,0x00,0x00}, // "
{0x50,0x50,0xF8,0x50,0xF8,0x50,0x50,0x00}, // #
{0x20,0x78,0xA0,0x70,0x28,0xF0,0x20,0x00}, // $
{0xC0,0xC8,0x10,0x20,0x40,0x98,0x18,0x00}, // %
{0x40,0xA0,0xA0,0x40,0xA8,0x90,0x68,0x00}, // &
{0x30,0x30,0x20,0x40,0x00,0x00,0x00,0x00}, // '
{0x10,0x20,0x40,0x40,0x40,0x20,0x10,0x00}, // (
{0x40,0x20,0x10,0x10,0x10,0x20,0x40,0x00}, // )
{0x00,0x20,0xA8,0x70,0x70,0xA8,0x20,0x00}, // *
{0x00,0x20,0x20,0xF8,0x20,0x20,0x00,0x00}, // +
{0x00,0x00,0x00,0x00,0x30,0x30,0x20,0x40}, // ,
{0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00}, // -
{0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00}, // .
{0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00}, // /
{0x70,0x88,0x88,0xA8,0x88,0x88,0x70,0x00}, // 0
{0x20,0x60,0x20,0x20,0x20,0x20,0x70,0x00}, // 1
{0x70,0x88,0x08,0x70,0x80,0x80,0xF8,0x00}, // 2
{0xF8,0x08,0x10,0x30,0x08,0x88,0x70,0x00}, // 3
{0x10,0x30,0x50,0x90,0xF8,0x10,0x10,0x00}, // 4
{0xF8,0x80,0xF0,0x08,0x08,0x88,0x70,0x00}, // 5
{0x38,0x40,0x80,0xF0,0x88,0x88,0x70,0x00}, // 6
{0xF8,0x08,0x08,0x10,0x20,0x40,0x80,0x00}, // 7
{0x70,0x88,0x88,0x70,0x88,0x88,0x70,0x00}, // 8
{0x70,0x88,0x88,0x78,0x08,0x10,0xE0,0x00}, // 9
{0x00,0x00,0x20,0x00,0x20,0x00,0x00,0x00}, // :
{0x00,0x00,0x20,0x00,0x20,0x20,0x40,0x00}, // ;
{0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x00}, // <
{0x00,0x00,0xF8,0x00,0xF8,0x00,0x00,0x00}, // =
{0x40,0x20,0x10,0x08,0x10,0x20,0x40,0x00}, // >
{0x70,0x88,0x08,0x30,0x20,0x00,0x20,0x00}, // ?
{0x70,0x88,0xA8,0xB8,0xB0,0x80,0x78,0x00}, // @
{0x20,0x50,0x88,0x88,0xF8,0x88,0x88,0x00}, // A
{0xF0,0x88,0x88,0xF0,0x88,0x88,0xF0,0x00}, // B
{0x70,0x88,0x80,0x80,0x80,0x88,0x70,0x00}, // C
{0xF0,0x88,0x88,0x88,0x88,0x88,0xF0,0x00}, // D
{0xF8,0x80,0x80,0xF0,0x80,0x80,0xF8,0x00}, // E
{0xF8,0x80,0x80,0xF0,0x80,0x80,0x80,0x00}, // F
{0x78,0x88,0x80,0x80,0x98,0x88,0x78,0x00}, // G
{0x88,0x88,0x88,0xF8,0x88,0x88,0x88,0x00}, // H
{0x70,0x20,0x20,0x20,0x20,0x20,0x70,0x00}, // I
{0x38,0x10,0x10,0x10,0x10,0x90,0x60,0x00}, // J
{0x88,0x90,0xA0,0xC0,0xA0,0x90,0x88,0x00}, // K
{0x80,0x80,0x80,0x80,0x80,0x80,0xF8,0x00}, // L
{0x88,0xD8,0xA8,0xA8,0xA8,0x88,0x88,0x00}, // M
{0x88,0x88,0xC8,0xA8,0x98,0x88,0x88,0x00}, // N
{0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00}, // O
{0xF0,0x88,0x88,0xF0,0x80,0x80,0x80,0x00}, // P
{0x70,0x88,0x88,0x88,0xA8,0x90,0x68,0x00}, // Q
{0xF0,0x88,0x88,0xF0,0xA0,0x90,0x88,0x00}, // R
{0x70,0x88,0x80,0x70,0x08,0x88,0x70,0x00}, // S
{0xF8,0xA8,0x20,0x20,0x20,0x20,0x20,0x00}, // T
{0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00}, // U
{0x88,0x88,0x88,0x88,0x88,0x50,0x20,0x00}, // V
{0x88,0x88,0x88,0xA8,0xA8,0xA8,0x50,0x00}, // W
{0x88,0x88,0x50,0x20,0x50,0x88,0x88,0x00}, // X
{0x88,0x88,0x50,0x20,0x20,0x20,0x20,0x00}, // Y
{0xF8,0x08,0x10,0x70,0x40,0x80,0xF8,0x00}, // Z
{0x78,0x40,0x40,0x40,0x40,0x40,0x78,0x00}, // [
{0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00}, // backslash
{0x78,0x08,0x08,0x08,0x08,0x08,0x78,0x00}, // ]
{0x20,0x50,0x88,0x00,0x00,0x00,0x00,0x00}, // ^
{0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00}, // _
{0x60,0x60,0x20,0x10,0x00,0x00,0x00,0x00}, // `
{0x00,0x00,0x60,0x10,0x70,0x90,0x78,0x00}, // a
{0x80,0x80,0xB0,0xC8,0x88,0xC8,0xB0,0x00}, // b
{0x00,0x00,0x70,0x88,0x80,0x88,0x70,0x00}, // c
{0x08,0x08,0x68,0x98,0x88,0x98,0x68,0x00}, // d
{0x00,0x00,0x70,0x88,0xF8,0x80,0x70,0x00}, // e
{0x10,0x28,0x20,0x70,0x20,0x20,0x20,0x00}, // f
{0x00,0x00,0x70,0x98,0x98,0x68,0x08,0x70}, // g
{0x80,0x80,0xB0,0xC8,0x88,0x88,0x88,0x00}, // h
{0x20,0x00,0x60,0x20,0x20,0x20,0x70,0x00}, // i
{0x10,0x00,0x10,0x10,0x10,0x90,0x60,0x00}, // j
{0x80,0x80,0x90,0xA0,0xC0,0xA0,0x90,0x00}, // k
{0x60,0x20,0x20,0x20,0x20,0x20,0x70,0x00}, // l
{0x00,0x00,0xD0,0xA8,0xA8,0xA8,0xA8,0x00}, // m
{0x00,0x00,0xB0,0xC8,0x88,0x88,0x88,0x00}, // n
{0x00,0x00,0x70,0x88,0x88,0x88,0x70,0x00}, // o
{0x00,0x00,0xB0,0xC8,0xC8,0xB0,0x80,0x80}, // p
{0x00,0x00,0x68,0x98,0x98,0x68,0x08,0x08}, // q
{0x00,0x00,0xB0,0xC8,0x80,0x80,0x80,0x00}, // r
{0x00,0x00,0x78,0x80,0x70,0x08,0xF0,0x00}, // s
{0x20,0x20,0xF8,0x20,0x20,0x28,0x10,0x00}, // t
{0x00,0x00,0x88,0x88,0x88,0x98,0x68,0x00}, // u
{0x00,0x00,0x88,0x88,0x88,0x50,0x20,0x00}, // v
{0x00,0x00,0x88,0x88,0xA8,0xA8,0x50,0x00}, // w
{0x00,0x00,0x88,0x50,0x20,0x50,0x88,0x00}, // x
{0x00,0x00,0x88,0x88,0x78,0x08,0x88,0x70}, // y
{0x00,0x00,0xF8,0x10,0x20,0x40,0xF8,0x00}, // z
{0x10,0x20,0x20,0x40,0x20,0x20,0x10,0x00}, // {
{0x20,0x20,0x20,0x00,0x20,0x20,0x20,0x00}, // |
{0x40,0x20,0x20,0x10,0x20,0x20,0x40,0x00}, // }
{0x40,0xA8,0x10,0x00,0x00,0x00,0x00,0x00}, // ~
{0x70,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00} // DEL
{0x06, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00}, // columns, rows, bytes per char
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // space
{0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x20, 0x00}, // !
{0x50, 0x50, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00}, // "
{0x50, 0x50, 0xF8, 0x50, 0xF8, 0x50, 0x50, 0x00}, // #
{0x20, 0x78, 0xA0, 0x70, 0x28, 0xF0, 0x20, 0x00}, // $
{0xC0, 0xC8, 0x10, 0x20, 0x40, 0x98, 0x18, 0x00}, // %
{0x40, 0xA0, 0xA0, 0x40, 0xA8, 0x90, 0x68, 0x00}, // &
{0x30, 0x30, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00}, // '
{0x10, 0x20, 0x40, 0x40, 0x40, 0x20, 0x10, 0x00}, // (
{0x40, 0x20, 0x10, 0x10, 0x10, 0x20, 0x40, 0x00}, // )
{0x00, 0x20, 0xA8, 0x70, 0x70, 0xA8, 0x20, 0x00}, // *
{0x00, 0x20, 0x20, 0xF8, 0x20, 0x20, 0x00, 0x00}, // +
{0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x20, 0x40}, // ,
{0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00}, // -
{0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00}, // .
{0x00, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00}, // /
{0x70, 0x88, 0x88, 0xA8, 0x88, 0x88, 0x70, 0x00}, // 0
{0x20, 0x60, 0x20, 0x20, 0x20, 0x20, 0x70, 0x00}, // 1
{0x70, 0x88, 0x08, 0x70, 0x80, 0x80, 0xF8, 0x00}, // 2
{0xF8, 0x08, 0x10, 0x30, 0x08, 0x88, 0x70, 0x00}, // 3
{0x10, 0x30, 0x50, 0x90, 0xF8, 0x10, 0x10, 0x00}, // 4
{0xF8, 0x80, 0xF0, 0x08, 0x08, 0x88, 0x70, 0x00}, // 5
{0x38, 0x40, 0x80, 0xF0, 0x88, 0x88, 0x70, 0x00}, // 6
{0xF8, 0x08, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00}, // 7
{0x70, 0x88, 0x88, 0x70, 0x88, 0x88, 0x70, 0x00}, // 8
{0x70, 0x88, 0x88, 0x78, 0x08, 0x10, 0xE0, 0x00}, // 9
{0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00}, // :
{0x00, 0x00, 0x20, 0x00, 0x20, 0x20, 0x40, 0x00}, // ;
{0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x00}, // <
{0x00, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0x00, 0x00}, // =
{0x40, 0x20, 0x10, 0x08, 0x10, 0x20, 0x40, 0x00}, // >
{0x70, 0x88, 0x08, 0x30, 0x20, 0x00, 0x20, 0x00}, // ?
{0x70, 0x88, 0xA8, 0xB8, 0xB0, 0x80, 0x78, 0x00}, // @
{0x20, 0x50, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x00}, // A
{0xF0, 0x88, 0x88, 0xF0, 0x88, 0x88, 0xF0, 0x00}, // B
{0x70, 0x88, 0x80, 0x80, 0x80, 0x88, 0x70, 0x00}, // C
{0xF0, 0x88, 0x88, 0x88, 0x88, 0x88, 0xF0, 0x00}, // D
{0xF8, 0x80, 0x80, 0xF0, 0x80, 0x80, 0xF8, 0x00}, // E
{0xF8, 0x80, 0x80, 0xF0, 0x80, 0x80, 0x80, 0x00}, // F
{0x78, 0x88, 0x80, 0x80, 0x98, 0x88, 0x78, 0x00}, // G
{0x88, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x88, 0x00}, // H
{0x70, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x00}, // I
{0x38, 0x10, 0x10, 0x10, 0x10, 0x90, 0x60, 0x00}, // J
{0x88, 0x90, 0xA0, 0xC0, 0xA0, 0x90, 0x88, 0x00}, // K
{0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xF8, 0x00}, // L
{0x88, 0xD8, 0xA8, 0xA8, 0xA8, 0x88, 0x88, 0x00}, // M
{0x88, 0x88, 0xC8, 0xA8, 0x98, 0x88, 0x88, 0x00}, // N
{0x70, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00}, // O
{0xF0, 0x88, 0x88, 0xF0, 0x80, 0x80, 0x80, 0x00}, // P
{0x70, 0x88, 0x88, 0x88, 0xA8, 0x90, 0x68, 0x00}, // Q
{0xF0, 0x88, 0x88, 0xF0, 0xA0, 0x90, 0x88, 0x00}, // R
{0x70, 0x88, 0x80, 0x70, 0x08, 0x88, 0x70, 0x00}, // S
{0xF8, 0xA8, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00}, // T
{0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00}, // U
{0x88, 0x88, 0x88, 0x88, 0x88, 0x50, 0x20, 0x00}, // V
{0x88, 0x88, 0x88, 0xA8, 0xA8, 0xA8, 0x50, 0x00}, // W
{0x88, 0x88, 0x50, 0x20, 0x50, 0x88, 0x88, 0x00}, // X
{0x88, 0x88, 0x50, 0x20, 0x20, 0x20, 0x20, 0x00}, // Y
{0xF8, 0x08, 0x10, 0x70, 0x40, 0x80, 0xF8, 0x00}, // Z
{0x78, 0x40, 0x40, 0x40, 0x40, 0x40, 0x78, 0x00}, // [
{0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x00, 0x00}, // backslash
{0x78, 0x08, 0x08, 0x08, 0x08, 0x08, 0x78, 0x00}, // ]
{0x20, 0x50, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00}, // ^
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00}, // _
{0x60, 0x60, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00}, // `
{0x00, 0x00, 0x60, 0x10, 0x70, 0x90, 0x78, 0x00}, // a
{0x80, 0x80, 0xB0, 0xC8, 0x88, 0xC8, 0xB0, 0x00}, // b
{0x00, 0x00, 0x70, 0x88, 0x80, 0x88, 0x70, 0x00}, // c
{0x08, 0x08, 0x68, 0x98, 0x88, 0x98, 0x68, 0x00}, // d
{0x00, 0x00, 0x70, 0x88, 0xF8, 0x80, 0x70, 0x00}, // e
{0x10, 0x28, 0x20, 0x70, 0x20, 0x20, 0x20, 0x00}, // f
{0x00, 0x00, 0x70, 0x98, 0x98, 0x68, 0x08, 0x70}, // g
{0x80, 0x80, 0xB0, 0xC8, 0x88, 0x88, 0x88, 0x00}, // h
{0x20, 0x00, 0x60, 0x20, 0x20, 0x20, 0x70, 0x00}, // i
{0x10, 0x00, 0x10, 0x10, 0x10, 0x90, 0x60, 0x00}, // j
{0x80, 0x80, 0x90, 0xA0, 0xC0, 0xA0, 0x90, 0x00}, // k
{0x60, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x00}, // l
{0x00, 0x00, 0xD0, 0xA8, 0xA8, 0xA8, 0xA8, 0x00}, // m
{0x00, 0x00, 0xB0, 0xC8, 0x88, 0x88, 0x88, 0x00}, // n
{0x00, 0x00, 0x70, 0x88, 0x88, 0x88, 0x70, 0x00}, // o
{0x00, 0x00, 0xB0, 0xC8, 0xC8, 0xB0, 0x80, 0x80}, // p
{0x00, 0x00, 0x68, 0x98, 0x98, 0x68, 0x08, 0x08}, // q
{0x00, 0x00, 0xB0, 0xC8, 0x80, 0x80, 0x80, 0x00}, // r
{0x00, 0x00, 0x78, 0x80, 0x70, 0x08, 0xF0, 0x00}, // s
{0x20, 0x20, 0xF8, 0x20, 0x20, 0x28, 0x10, 0x00}, // t
{0x00, 0x00, 0x88, 0x88, 0x88, 0x98, 0x68, 0x00}, // u
{0x00, 0x00, 0x88, 0x88, 0x88, 0x50, 0x20, 0x00}, // v
{0x00, 0x00, 0x88, 0x88, 0xA8, 0xA8, 0x50, 0x00}, // w
{0x00, 0x00, 0x88, 0x50, 0x20, 0x50, 0x88, 0x00}, // x
{0x00, 0x00, 0x88, 0x88, 0x78, 0x08, 0x88, 0x70}, // y
{0x00, 0x00, 0xF8, 0x10, 0x20, 0x40, 0xF8, 0x00}, // z
{0x10, 0x20, 0x20, 0x40, 0x20, 0x20, 0x10, 0x00}, // {
{0x20, 0x20, 0x20, 0x00, 0x20, 0x20, 0x20, 0x00}, // |
{0x40, 0x20, 0x20, 0x10, 0x20, 0x20, 0x40, 0x00}, // }
{0x40, 0xA8, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}, // ~
{0x70, 0xD8, 0xD8, 0x70, 0x00, 0x00, 0x00, 0x00} // DEL
};
/*
const char FONT8x8F[97][8] = {
{0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00}, // columns, rows, bytes per char
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // space
{0x30,0x78,0x78,0x30,0x30,0x00,0x30,0x00}, // !
{0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00}, // "
{0x6C,0x6C,0xFE,0x6C,0xFE,0x6C,0x6C,0x00}, // #
{0x18,0x3E,0x60,0x3C,0x06,0x7C,0x18,0x00}, // $
{0x00,0x63,0x66,0x0C,0x18,0x33,0x63,0x00}, // %
{0x1C,0x36,0x1C,0x3B,0x6E,0x66,0x3B,0x00}, // &
{0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00}, // '
{0x0C,0x18,0x30,0x30,0x30,0x18,0x0C,0x00}, // (
{0x30,0x18,0x0C,0x0C,0x0C,0x18,0x30,0x00}, // )
{0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00}, // *
{0x00,0x30,0x30,0xFC,0x30,0x30,0x00,0x00}, // +
{0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30}, // ,
{0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00}, // -
{0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00}, // .
{0x03,0x06,0x0C,0x18,0x30,0x60,0x40,0x00}, // /
{0x3E,0x63,0x63,0x6B,0x63,0x63,0x3E,0x00}, // 0
{0x18,0x38,0x58,0x18,0x18,0x18,0x7E,0x00}, // 1
{0x3C,0x66,0x06,0x1C,0x30,0x66,0x7E,0x00}, // 2
{0x3C,0x66,0x06,0x1C,0x06,0x66,0x3C,0x00}, // 3
{0x0E,0x1E,0x36,0x66,0x7F,0x06,0x0F,0x00}, // 4
{0x7E,0x60,0x7C,0x06,0x06,0x66,0x3C,0x00}, // 5
{0x1C,0x30,0x60,0x7C,0x66,0x66,0x3C,0x00}, // 6
{0x7E,0x66,0x06,0x0C,0x18,0x18,0x18,0x00}, // 7
{0x3C,0x66,0x66,0x3C,0x66,0x66,0x3C,0x00}, // 8
{0x3C,0x66,0x66,0x3E,0x06,0x0C,0x38,0x00}, // 9
{0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x00}, // :
{0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x30}, // ;
{0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00}, // <
{0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00}, // =
{0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00}, // >
{0x3C,0x66,0x06,0x0C,0x18,0x00,0x18,0x00}, // ?
{0x3E,0x63,0x6F,0x69,0x6F,0x60,0x3E,0x00}, // @
{0x18,0x3C,0x66,0x66,0x7E,0x66,0x66,0x00}, // A
{0x7E,0x33,0x33,0x3E,0x33,0x33,0x7E,0x00}, // B
{0x1E,0x33,0x60,0x60,0x60,0x33,0x1E,0x00}, // C
{0x7C,0x36,0x33,0x33,0x33,0x36,0x7C,0x00}, // D
{0x7F,0x31,0x34,0x3C,0x34,0x31,0x7F,0x00}, // E
{0x7F,0x31,0x34,0x3C,0x34,0x30,0x78,0x00}, // F
{0x1E,0x33,0x60,0x60,0x67,0x33,0x1F,0x00}, // G
{0x66,0x66,0x66,0x7E,0x66,0x66,0x66,0x00}, // H
{0x3C,0x18,0x18,0x18,0x18,0x18,0x3C,0x00}, // I
{0x0F,0x06,0x06,0x06,0x66,0x66,0x3C,0x00}, // J
{0x73,0x33,0x36,0x3C,0x36,0x33,0x73,0x00}, // K
{0x78,0x30,0x30,0x30,0x31,0x33,0x7F,0x00}, // L
{0x63,0x77,0x7F,0x7F,0x6B,0x63,0x63,0x00}, // M
{0x63,0x73,0x7B,0x6F,0x67,0x63,0x63,0x00}, // N
{0x3E,0x63,0x63,0x63,0x63,0x63,0x3E,0x00}, // O
{0x7E,0x33,0x33,0x3E,0x30,0x30,0x78,0x00}, // P
{0x3C,0x66,0x66,0x66,0x6E,0x3C,0x0E,0x00}, // Q
{0x7E,0x33,0x33,0x3E,0x36,0x33,0x73,0x00}, // R
{0x3C,0x66,0x30,0x18,0x0C,0x66,0x3C,0x00}, // S
{0x7E,0x5A,0x18,0x18,0x18,0x18,0x3C,0x00}, // T
{0x66,0x66,0x66,0x66,0x66,0x66,0x7E,0x00}, // U
{0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00}, // V
{0x63,0x63,0x63,0x6B,0x7F,0x77,0x63,0x00}, // W
{0x63,0x63,0x36,0x1C,0x1C,0x36,0x63,0x00}, // X
{0x66,0x66,0x66,0x3C,0x18,0x18,0x3C,0x00}, // Y
{0x7F,0x63,0x46,0x0C,0x19,0x33,0x7F,0x00}, // Z
{0x3C,0x30,0x30,0x30,0x30,0x30,0x3C,0x00}, // [
{0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x00}, // backslash
{0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00}, // ]
{0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00}, // ^
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF}, // _
{0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00}, // `
{0x00,0x00,0x3C,0x06,0x3E,0x66,0x3B,0x00}, // a
{0x70,0x30,0x3E,0x33,0x33,0x33,0x6E,0x00}, // b
{0x00,0x00,0x3C,0x66,0x60,0x66,0x3C,0x00}, // c
{0x0E,0x06,0x3E,0x66,0x66,0x66,0x3B,0x00}, // d
{0x00,0x00,0x3C,0x66,0x7E,0x60,0x3C,0x00}, // e
{0x1C,0x36,0x30,0x78,0x30,0x30,0x78,0x00}, // f
{0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x7C}, // g
{0x70,0x30,0x36,0x3B,0x33,0x33,0x73,0x00}, // h
{0x18,0x00,0x38,0x18,0x18,0x18,0x3C,0x00}, // i
{0x06,0x00,0x06,0x06,0x06,0x66,0x66,0x3C}, // j
{0x70,0x30,0x33,0x36,0x3C,0x36,0x73,0x00}, // k
{0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00}, // l
{0x00,0x00,0x66,0x7F,0x7F,0x6B,0x63,0x00}, // m
{0x00,0x00,0x7C,0x66,0x66,0x66,0x66,0x00}, // n
{0x00,0x00,0x3C,0x66,0x66,0x66,0x3C,0x00}, // o
{0x00,0x00,0x6E,0x33,0x33,0x3E,0x30,0x78}, // p
{0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x0F}, // q
{0x00,0x00,0x6E,0x3B,0x33,0x30,0x78,0x00}, // r
{0x00,0x00,0x3E,0x60,0x3C,0x06,0x7C,0x00}, // s
{0x08,0x18,0x3E,0x18,0x18,0x1A,0x0C,0x00}, // t
{0x00,0x00,0x66,0x66,0x66,0x66,0x3B,0x00}, // u
{0x00,0x00,0x66,0x66,0x66,0x3C,0x18,0x00}, // v
{0x00,0x00,0x63,0x6B,0x7F,0x7F,0x36,0x00}, // w
{0x00,0x00,0x63,0x36,0x1C,0x36,0x63,0x00}, // x
{0x00,0x00,0x66,0x66,0x66,0x3E,0x06,0x7C}, // y
{0x00,0x00,0x7E,0x4C,0x18,0x32,0x7E,0x00}, // z
{0x0E,0x18,0x18,0x70,0x18,0x18,0x0E,0x00}, // {
{0x0C,0x0C,0x0C,0x00,0x0C,0x0C,0x0C,0x00}, // |
{0x70,0x18,0x18,0x0E,0x18,0x18,0x70,0x00}, // }
{0x3B,0x6E,0x00,0x00,0x00,0x00,0x00,0x00}, // ~
{0x1C,0x36,0x36,0x1C,0x00,0x00,0x00,0x00} // DEL
{0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00}, // columns, rows, bytes per char
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // space
{0x30,0x78,0x78,0x30,0x30,0x00,0x30,0x00}, // !
{0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00}, // "
{0x6C,0x6C,0xFE,0x6C,0xFE,0x6C,0x6C,0x00}, // #
{0x18,0x3E,0x60,0x3C,0x06,0x7C,0x18,0x00}, // $
{0x00,0x63,0x66,0x0C,0x18,0x33,0x63,0x00}, // %
{0x1C,0x36,0x1C,0x3B,0x6E,0x66,0x3B,0x00}, // &
{0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00}, // '
{0x0C,0x18,0x30,0x30,0x30,0x18,0x0C,0x00}, // (
{0x30,0x18,0x0C,0x0C,0x0C,0x18,0x30,0x00}, // )
{0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00}, // *
{0x00,0x30,0x30,0xFC,0x30,0x30,0x00,0x00}, // +
{0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30}, // ,
{0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00}, // -
{0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00}, // .
{0x03,0x06,0x0C,0x18,0x30,0x60,0x40,0x00}, // /
{0x3E,0x63,0x63,0x6B,0x63,0x63,0x3E,0x00}, // 0
{0x18,0x38,0x58,0x18,0x18,0x18,0x7E,0x00}, // 1
{0x3C,0x66,0x06,0x1C,0x30,0x66,0x7E,0x00}, // 2
{0x3C,0x66,0x06,0x1C,0x06,0x66,0x3C,0x00}, // 3
{0x0E,0x1E,0x36,0x66,0x7F,0x06,0x0F,0x00}, // 4
{0x7E,0x60,0x7C,0x06,0x06,0x66,0x3C,0x00}, // 5
{0x1C,0x30,0x60,0x7C,0x66,0x66,0x3C,0x00}, // 6
{0x7E,0x66,0x06,0x0C,0x18,0x18,0x18,0x00}, // 7
{0x3C,0x66,0x66,0x3C,0x66,0x66,0x3C,0x00}, // 8
{0x3C,0x66,0x66,0x3E,0x06,0x0C,0x38,0x00}, // 9
{0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x00}, // :
{0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x30}, // ;
{0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00}, // <
{0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00}, // =
{0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00}, // >
{0x3C,0x66,0x06,0x0C,0x18,0x00,0x18,0x00}, // ?
{0x3E,0x63,0x6F,0x69,0x6F,0x60,0x3E,0x00}, // @
{0x18,0x3C,0x66,0x66,0x7E,0x66,0x66,0x00}, // A
{0x7E,0x33,0x33,0x3E,0x33,0x33,0x7E,0x00}, // B
{0x1E,0x33,0x60,0x60,0x60,0x33,0x1E,0x00}, // C
{0x7C,0x36,0x33,0x33,0x33,0x36,0x7C,0x00}, // D
{0x7F,0x31,0x34,0x3C,0x34,0x31,0x7F,0x00}, // E
{0x7F,0x31,0x34,0x3C,0x34,0x30,0x78,0x00}, // F
{0x1E,0x33,0x60,0x60,0x67,0x33,0x1F,0x00}, // G
{0x66,0x66,0x66,0x7E,0x66,0x66,0x66,0x00}, // H
{0x3C,0x18,0x18,0x18,0x18,0x18,0x3C,0x00}, // I
{0x0F,0x06,0x06,0x06,0x66,0x66,0x3C,0x00}, // J
{0x73,0x33,0x36,0x3C,0x36,0x33,0x73,0x00}, // K
{0x78,0x30,0x30,0x30,0x31,0x33,0x7F,0x00}, // L
{0x63,0x77,0x7F,0x7F,0x6B,0x63,0x63,0x00}, // M
{0x63,0x73,0x7B,0x6F,0x67,0x63,0x63,0x00}, // N
{0x3E,0x63,0x63,0x63,0x63,0x63,0x3E,0x00}, // O
{0x7E,0x33,0x33,0x3E,0x30,0x30,0x78,0x00}, // P
{0x3C,0x66,0x66,0x66,0x6E,0x3C,0x0E,0x00}, // Q
{0x7E,0x33,0x33,0x3E,0x36,0x33,0x73,0x00}, // R
{0x3C,0x66,0x30,0x18,0x0C,0x66,0x3C,0x00}, // S
{0x7E,0x5A,0x18,0x18,0x18,0x18,0x3C,0x00}, // T
{0x66,0x66,0x66,0x66,0x66,0x66,0x7E,0x00}, // U
{0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00}, // V
{0x63,0x63,0x63,0x6B,0x7F,0x77,0x63,0x00}, // W
{0x63,0x63,0x36,0x1C,0x1C,0x36,0x63,0x00}, // X
{0x66,0x66,0x66,0x3C,0x18,0x18,0x3C,0x00}, // Y
{0x7F,0x63,0x46,0x0C,0x19,0x33,0x7F,0x00}, // Z
{0x3C,0x30,0x30,0x30,0x30,0x30,0x3C,0x00}, // [
{0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x00}, // backslash
{0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00}, // ]
{0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00}, // ^
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF}, // _
{0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00}, // `
{0x00,0x00,0x3C,0x06,0x3E,0x66,0x3B,0x00}, // a
{0x70,0x30,0x3E,0x33,0x33,0x33,0x6E,0x00}, // b
{0x00,0x00,0x3C,0x66,0x60,0x66,0x3C,0x00}, // c
{0x0E,0x06,0x3E,0x66,0x66,0x66,0x3B,0x00}, // d
{0x00,0x00,0x3C,0x66,0x7E,0x60,0x3C,0x00}, // e
{0x1C,0x36,0x30,0x78,0x30,0x30,0x78,0x00}, // f
{0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x7C}, // g
{0x70,0x30,0x36,0x3B,0x33,0x33,0x73,0x00}, // h
{0x18,0x00,0x38,0x18,0x18,0x18,0x3C,0x00}, // i
{0x06,0x00,0x06,0x06,0x06,0x66,0x66,0x3C}, // j
{0x70,0x30,0x33,0x36,0x3C,0x36,0x73,0x00}, // k
{0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00}, // l
{0x00,0x00,0x66,0x7F,0x7F,0x6B,0x63,0x00}, // m
{0x00,0x00,0x7C,0x66,0x66,0x66,0x66,0x00}, // n
{0x00,0x00,0x3C,0x66,0x66,0x66,0x3C,0x00}, // o
{0x00,0x00,0x6E,0x33,0x33,0x3E,0x30,0x78}, // p
{0x00,0x00,0x3B,0x66,0x66,0x3E,0x06,0x0F}, // q
{0x00,0x00,0x6E,0x3B,0x33,0x30,0x78,0x00}, // r
{0x00,0x00,0x3E,0x60,0x3C,0x06,0x7C,0x00}, // s
{0x08,0x18,0x3E,0x18,0x18,0x1A,0x0C,0x00}, // t
{0x00,0x00,0x66,0x66,0x66,0x66,0x3B,0x00}, // u
{0x00,0x00,0x66,0x66,0x66,0x3C,0x18,0x00}, // v
{0x00,0x00,0x63,0x6B,0x7F,0x7F,0x36,0x00}, // w
{0x00,0x00,0x63,0x36,0x1C,0x36,0x63,0x00}, // x
{0x00,0x00,0x66,0x66,0x66,0x3E,0x06,0x7C}, // y
{0x00,0x00,0x7E,0x4C,0x18,0x32,0x7E,0x00}, // z
{0x0E,0x18,0x18,0x70,0x18,0x18,0x0E,0x00}, // {
{0x0C,0x0C,0x0C,0x00,0x0C,0x0C,0x0C,0x00}, // |
{0x70,0x18,0x18,0x0E,0x18,0x18,0x70,0x00}, // }
{0x3B,0x6E,0x00,0x00,0x00,0x00,0x00,0x00}, // ~
{0x1C,0x36,0x36,0x1C,0x00,0x00,0x00,0x00} // DEL
};
const char FONT8x16[97][16] = {
{0x08,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // columns, rows, bytes per char
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // space
{0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00}, // !
{0x00,0x63,0x63,0x63,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // "
{0x00,0x00,0x00,0x36,0x36,0x7F,0x36,0x36,0x36,0x7F,0x36,0x36,0x00,0x00,0x00,0x00}, // #
{0x0C,0x0C,0x3E,0x63,0x61,0x60,0x3E,0x03,0x03,0x43,0x63,0x3E,0x0C,0x0C,0x00,0x00}, // $
{0x00,0x00,0x00,0x00,0x00,0x61,0x63,0x06,0x0C,0x18,0x33,0x63,0x00,0x00,0x00,0x00}, // %
{0x00,0x00,0x00,0x1C,0x36,0x36,0x1C,0x3B,0x6E,0x66,0x66,0x3B,0x00,0x00,0x00,0x00}, // &
{0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // '
{0x00,0x00,0x0C,0x18,0x18,0x30,0x30,0x30,0x30,0x18,0x18,0x0C,0x00,0x00,0x00,0x00}, // (
{0x00,0x00,0x18,0x0C,0x0C,0x06,0x06,0x06,0x06,0x0C,0x0C,0x18,0x00,0x00,0x00,0x00}, // )
{0x00,0x00,0x00,0x00,0x42,0x66,0x3C,0xFF,0x3C,0x66,0x42,0x00,0x00,0x00,0x00,0x00}, // *
{0x00,0x00,0x00,0x00,0x18,0x18,0x18,0xFF,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00}, // +
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00}, // ,
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // -
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00}, // .
{0x00,0x00,0x01,0x03,0x07,0x0E,0x1C,0x38,0x70,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00}, // /
{0x00,0x00,0x3E,0x63,0x63,0x63,0x6B,0x6B,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // 0
{0x00,0x00,0x0C,0x1C,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3F,0x00,0x00,0x00,0x00}, // 1
{0x00,0x00,0x3E,0x63,0x03,0x06,0x0C,0x18,0x30,0x61,0x63,0x7F,0x00,0x00,0x00,0x00}, // 2
{0x00,0x00,0x3E,0x63,0x03,0x03,0x1E,0x03,0x03,0x03,0x63,0x3E,0x00,0x00,0x00,0x00}, // 3
{0x00,0x00,0x06,0x0E,0x1E,0x36,0x66,0x66,0x7F,0x06,0x06,0x0F,0x00,0x00,0x00,0x00}, // 4
{0x00,0x00,0x7F,0x60,0x60,0x60,0x7E,0x03,0x03,0x63,0x73,0x3E,0x00,0x00,0x00,0x00}, // 5
{0x00,0x00,0x1C,0x30,0x60,0x60,0x7E,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // 6
{0x00,0x00,0x7F,0x63,0x03,0x06,0x06,0x0C,0x0C,0x18,0x18,0x18,0x00,0x00,0x00,0x00}, // 7
{0x00,0x00,0x3E,0x63,0x63,0x63,0x3E,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // 8
{0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x3F,0x03,0x03,0x06,0x3C,0x00,0x00,0x00,0x00}, // 9
{0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00}, // :
{0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00}, // ;
{0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00}, // <
{0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00}, // =
{0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00}, // >
{0x00,0x00,0x3E,0x63,0x63,0x06,0x0C,0x0C,0x0C,0x00,0x0C,0x0C,0x00,0x00,0x00,0x00}, // ?
{0x00,0x00,0x3E,0x63,0x63,0x6F,0x6B,0x6B,0x6E,0x60,0x60,0x3E,0x00,0x00,0x00,0x00}, // @
{0x00,0x00,0x08,0x1C,0x36,0x63,0x63,0x63,0x7F,0x63,0x63,0x63,0x00,0x00,0x00,0x00}, // A
{0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x33,0x33,0x33,0x33,0x7E,0x00,0x00,0x00,0x00}, // B
{0x00,0x00,0x1E,0x33,0x61,0x60,0x60,0x60,0x60,0x61,0x33,0x1E,0x00,0x00,0x00,0x00}, // C
{0x00,0x00,0x7C,0x36,0x33,0x33,0x33,0x33,0x33,0x33,0x36,0x7C,0x00,0x00,0x00,0x00}, // D
{0x00,0x00,0x7F,0x33,0x31,0x34,0x3C,0x34,0x30,0x31,0x33,0x7F,0x00,0x00,0x00,0x00}, // E
{0x00,0x00,0x7F,0x33,0x31,0x34,0x3C,0x34,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, // F
{0x00,0x00,0x1E,0x33,0x61,0x60,0x60,0x6F,0x63,0x63,0x37,0x1D,0x00,0x00,0x00,0x00}, // G
{0x00,0x00,0x63,0x63,0x63,0x63,0x7F,0x63,0x63,0x63,0x63,0x63,0x00,0x00,0x00,0x00}, // H
{0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}, // I
{0x00,0x00,0x0F,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00,0x00,0x00,0x00}, // J
{0x00,0x00,0x73,0x33,0x36,0x36,0x3C,0x36,0x36,0x33,0x33,0x73,0x00,0x00,0x00,0x00}, // K
{0x00,0x00,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x33,0x7F,0x00,0x00,0x00,0x00}, // L
{0x00,0x00,0x63,0x77,0x7F,0x6B,0x63,0x63,0x63,0x63,0x63,0x63,0x00,0x00,0x00,0x00}, // M
{0x00,0x00,0x63,0x63,0x73,0x7B,0x7F,0x6F,0x67,0x63,0x63,0x63,0x00,0x00,0x00,0x00}, // N
{0x00,0x00,0x1C,0x36,0x63,0x63,0x63,0x63,0x63,0x63,0x36,0x1C,0x00,0x00,0x00,0x00}, // O
{0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, // P
{0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x63,0x63,0x6B,0x6F,0x3E,0x06,0x07,0x00,0x00}, // Q
{0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x36,0x36,0x33,0x33,0x73,0x00,0x00,0x00,0x00}, // R
{0x00,0x00,0x3E,0x63,0x63,0x30,0x1C,0x06,0x03,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // S
{0x00,0x00,0xFF,0xDB,0x99,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}, // T
{0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // U
{0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x36,0x1C,0x08,0x00,0x00,0x00,0x00}, // V
{0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x6B,0x6B,0x7F,0x36,0x36,0x00,0x00,0x00,0x00}, // W
{0x00,0x00,0xC3,0xC3,0x66,0x3C,0x18,0x18,0x3C,0x66,0xC3,0xC3,0x00,0x00,0x00,0x00}, // X
{0x00,0x00,0xC3,0xC3,0xC3,0x66,0x3C,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}, // Y
{0x00,0x00,0x7F,0x63,0x43,0x06,0x0C,0x18,0x30,0x61,0x63,0x7F,0x00,0x00,0x00,0x00}, // Z
{0x00,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00}, // [
{0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0x0E,0x07,0x03,0x01,0x00,0x00,0x00,0x00}, // backslash
{0x00,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00}, // ]
{0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // ^
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00}, // _
{0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // `
{0x00,0x00,0x00,0x00,0x00,0x3C,0x46,0x06,0x3E,0x66,0x66,0x3B,0x00,0x00,0x00,0x00}, // a
{0x00,0x00,0x70,0x30,0x30,0x3C,0x36,0x33,0x33,0x33,0x33,0x6E,0x00,0x00,0x00,0x00}, // b
{0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x60,0x60,0x60,0x63,0x3E,0x00,0x00,0x00,0x00}, // c
{0x00,0x00,0x0E,0x06,0x06,0x1E,0x36,0x66,0x66,0x66,0x66,0x3B,0x00,0x00,0x00,0x00}, // d
{0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x63,0x7E,0x60,0x63,0x3E,0x00,0x00,0x00,0x00}, // e
{0x00,0x00,0x1C,0x36,0x32,0x30,0x7C,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, // f
{0x00,0x00,0x00,0x00,0x00,0x3B,0x66,0x66,0x66,0x66,0x3E,0x06,0x66,0x3C,0x00,0x00}, // g
{0x00,0x00,0x70,0x30,0x30,0x36,0x3B,0x33,0x33,0x33,0x33,0x73,0x00,0x00,0x00,0x00}, // h
{0x00,0x00,0x0C,0x0C,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00}, // i
{0x00,0x00,0x06,0x06,0x00,0x0E,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00,0x00}, // j
{0x00,0x00,0x70,0x30,0x30,0x33,0x33,0x36,0x3C,0x36,0x33,0x73,0x00,0x00,0x00,0x00}, // k
{0x00,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00}, // l
{0x00,0x00,0x00,0x00,0x00,0x6E,0x7F,0x6B,0x6B,0x6B,0x6B,0x6B,0x00,0x00,0x00,0x00}, // m
{0x00,0x00,0x00,0x00,0x00,0x6E,0x33,0x33,0x33,0x33,0x33,0x33,0x00,0x00,0x00,0x00}, // n
{0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // o
{0x00,0x00,0x00,0x00,0x00,0x6E,0x33,0x33,0x33,0x33,0x3E,0x30,0x30,0x78,0x00,0x00}, // p
{0x00,0x00,0x00,0x00,0x00,0x3B,0x66,0x66,0x66,0x66,0x3E,0x06,0x06,0x0F,0x00,0x00}, // q
{0x00,0x00,0x00,0x00,0x00,0x6E,0x3B,0x33,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, // r
{0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x38,0x0E,0x03,0x63,0x3E,0x00,0x00,0x00,0x00}, // s
{0x00,0x00,0x08,0x18,0x18,0x7E,0x18,0x18,0x18,0x18,0x1B,0x0E,0x00,0x00,0x00,0x00}, // t
{0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x3B,0x00,0x00,0x00,0x00}, // u
{0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x36,0x36,0x1C,0x1C,0x08,0x00,0x00,0x00,0x00}, // v
{0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x63,0x6B,0x6B,0x7F,0x36,0x00,0x00,0x00,0x00}, // w
{0x00,0x00,0x00,0x00,0x00,0x63,0x36,0x1C,0x1C,0x1C,0x36,0x63,0x00,0x00,0x00,0x00}, // x
{0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x3F,0x03,0x06,0x3C,0x00,0x00}, // y
{0x00,0x00,0x00,0x00,0x00,0x7F,0x66,0x0C,0x18,0x30,0x63,0x7F,0x00,0x00,0x00,0x00}, // z
{0x00,0x00,0x0E,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00}, // {
{0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00}, // |
{0x00,0x00,0x70,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00}, // }
{0x00,0x00,0x3B,0x6E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // ~
{0x00,0x70,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // DEL
{0x08,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // columns, rows, bytes per char
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // space
{0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00}, // !
{0x00,0x63,0x63,0x63,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // "
{0x00,0x00,0x00,0x36,0x36,0x7F,0x36,0x36,0x36,0x7F,0x36,0x36,0x00,0x00,0x00,0x00}, // #
{0x0C,0x0C,0x3E,0x63,0x61,0x60,0x3E,0x03,0x03,0x43,0x63,0x3E,0x0C,0x0C,0x00,0x00}, // $
{0x00,0x00,0x00,0x00,0x00,0x61,0x63,0x06,0x0C,0x18,0x33,0x63,0x00,0x00,0x00,0x00}, // %
{0x00,0x00,0x00,0x1C,0x36,0x36,0x1C,0x3B,0x6E,0x66,0x66,0x3B,0x00,0x00,0x00,0x00}, // &
{0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // '
{0x00,0x00,0x0C,0x18,0x18,0x30,0x30,0x30,0x30,0x18,0x18,0x0C,0x00,0x00,0x00,0x00}, // (
{0x00,0x00,0x18,0x0C,0x0C,0x06,0x06,0x06,0x06,0x0C,0x0C,0x18,0x00,0x00,0x00,0x00}, // )
{0x00,0x00,0x00,0x00,0x42,0x66,0x3C,0xFF,0x3C,0x66,0x42,0x00,0x00,0x00,0x00,0x00}, // *
{0x00,0x00,0x00,0x00,0x18,0x18,0x18,0xFF,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00}, // +
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00}, // ,
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // -
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00}, // .
{0x00,0x00,0x01,0x03,0x07,0x0E,0x1C,0x38,0x70,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00}, // /
{0x00,0x00,0x3E,0x63,0x63,0x63,0x6B,0x6B,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // 0
{0x00,0x00,0x0C,0x1C,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3F,0x00,0x00,0x00,0x00}, // 1
{0x00,0x00,0x3E,0x63,0x03,0x06,0x0C,0x18,0x30,0x61,0x63,0x7F,0x00,0x00,0x00,0x00}, // 2
{0x00,0x00,0x3E,0x63,0x03,0x03,0x1E,0x03,0x03,0x03,0x63,0x3E,0x00,0x00,0x00,0x00}, // 3
{0x00,0x00,0x06,0x0E,0x1E,0x36,0x66,0x66,0x7F,0x06,0x06,0x0F,0x00,0x00,0x00,0x00}, // 4
{0x00,0x00,0x7F,0x60,0x60,0x60,0x7E,0x03,0x03,0x63,0x73,0x3E,0x00,0x00,0x00,0x00}, // 5
{0x00,0x00,0x1C,0x30,0x60,0x60,0x7E,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // 6
{0x00,0x00,0x7F,0x63,0x03,0x06,0x06,0x0C,0x0C,0x18,0x18,0x18,0x00,0x00,0x00,0x00}, // 7
{0x00,0x00,0x3E,0x63,0x63,0x63,0x3E,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // 8
{0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x3F,0x03,0x03,0x06,0x3C,0x00,0x00,0x00,0x00}, // 9
{0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00}, // :
{0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00}, // ;
{0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00}, // <
{0x00,0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00}, // =
{0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00}, // >
{0x00,0x00,0x3E,0x63,0x63,0x06,0x0C,0x0C,0x0C,0x00,0x0C,0x0C,0x00,0x00,0x00,0x00}, // ?
{0x00,0x00,0x3E,0x63,0x63,0x6F,0x6B,0x6B,0x6E,0x60,0x60,0x3E,0x00,0x00,0x00,0x00}, // @
{0x00,0x00,0x08,0x1C,0x36,0x63,0x63,0x63,0x7F,0x63,0x63,0x63,0x00,0x00,0x00,0x00}, // A
{0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x33,0x33,0x33,0x33,0x7E,0x00,0x00,0x00,0x00}, // B
{0x00,0x00,0x1E,0x33,0x61,0x60,0x60,0x60,0x60,0x61,0x33,0x1E,0x00,0x00,0x00,0x00}, // C
{0x00,0x00,0x7C,0x36,0x33,0x33,0x33,0x33,0x33,0x33,0x36,0x7C,0x00,0x00,0x00,0x00}, // D
{0x00,0x00,0x7F,0x33,0x31,0x34,0x3C,0x34,0x30,0x31,0x33,0x7F,0x00,0x00,0x00,0x00}, // E
{0x00,0x00,0x7F,0x33,0x31,0x34,0x3C,0x34,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, // F
{0x00,0x00,0x1E,0x33,0x61,0x60,0x60,0x6F,0x63,0x63,0x37,0x1D,0x00,0x00,0x00,0x00}, // G
{0x00,0x00,0x63,0x63,0x63,0x63,0x7F,0x63,0x63,0x63,0x63,0x63,0x00,0x00,0x00,0x00}, // H
{0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}, // I
{0x00,0x00,0x0F,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00,0x00,0x00,0x00}, // J
{0x00,0x00,0x73,0x33,0x36,0x36,0x3C,0x36,0x36,0x33,0x33,0x73,0x00,0x00,0x00,0x00}, // K
{0x00,0x00,0x78,0x30,0x30,0x30,0x30,0x30,0x30,0x31,0x33,0x7F,0x00,0x00,0x00,0x00}, // L
{0x00,0x00,0x63,0x77,0x7F,0x6B,0x63,0x63,0x63,0x63,0x63,0x63,0x00,0x00,0x00,0x00}, // M
{0x00,0x00,0x63,0x63,0x73,0x7B,0x7F,0x6F,0x67,0x63,0x63,0x63,0x00,0x00,0x00,0x00}, // N
{0x00,0x00,0x1C,0x36,0x63,0x63,0x63,0x63,0x63,0x63,0x36,0x1C,0x00,0x00,0x00,0x00}, // O
{0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, // P
{0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x63,0x63,0x6B,0x6F,0x3E,0x06,0x07,0x00,0x00}, // Q
{0x00,0x00,0x7E,0x33,0x33,0x33,0x3E,0x36,0x36,0x33,0x33,0x73,0x00,0x00,0x00,0x00}, // R
{0x00,0x00,0x3E,0x63,0x63,0x30,0x1C,0x06,0x03,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // S
{0x00,0x00,0xFF,0xDB,0x99,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}, // T
{0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // U
{0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x63,0x63,0x36,0x1C,0x08,0x00,0x00,0x00,0x00}, // V
{0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x6B,0x6B,0x7F,0x36,0x36,0x00,0x00,0x00,0x00}, // W
{0x00,0x00,0xC3,0xC3,0x66,0x3C,0x18,0x18,0x3C,0x66,0xC3,0xC3,0x00,0x00,0x00,0x00}, // X
{0x00,0x00,0xC3,0xC3,0xC3,0x66,0x3C,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00}, // Y
{0x00,0x00,0x7F,0x63,0x43,0x06,0x0C,0x18,0x30,0x61,0x63,0x7F,0x00,0x00,0x00,0x00}, // Z
{0x00,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00}, // [
{0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0x0E,0x07,0x03,0x01,0x00,0x00,0x00,0x00}, // backslash
{0x00,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00}, // ]
{0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // ^
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00}, // _
{0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // `
{0x00,0x00,0x00,0x00,0x00,0x3C,0x46,0x06,0x3E,0x66,0x66,0x3B,0x00,0x00,0x00,0x00}, // a
{0x00,0x00,0x70,0x30,0x30,0x3C,0x36,0x33,0x33,0x33,0x33,0x6E,0x00,0x00,0x00,0x00}, // b
{0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x60,0x60,0x60,0x63,0x3E,0x00,0x00,0x00,0x00}, // c
{0x00,0x00,0x0E,0x06,0x06,0x1E,0x36,0x66,0x66,0x66,0x66,0x3B,0x00,0x00,0x00,0x00}, // d
{0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x63,0x7E,0x60,0x63,0x3E,0x00,0x00,0x00,0x00}, // e
{0x00,0x00,0x1C,0x36,0x32,0x30,0x7C,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, // f
{0x00,0x00,0x00,0x00,0x00,0x3B,0x66,0x66,0x66,0x66,0x3E,0x06,0x66,0x3C,0x00,0x00}, // g
{0x00,0x00,0x70,0x30,0x30,0x36,0x3B,0x33,0x33,0x33,0x33,0x73,0x00,0x00,0x00,0x00}, // h
{0x00,0x00,0x0C,0x0C,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00}, // i
{0x00,0x00,0x06,0x06,0x00,0x0E,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00,0x00}, // j
{0x00,0x00,0x70,0x30,0x30,0x33,0x33,0x36,0x3C,0x36,0x33,0x73,0x00,0x00,0x00,0x00}, // k
{0x00,0x00,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00}, // l
{0x00,0x00,0x00,0x00,0x00,0x6E,0x7F,0x6B,0x6B,0x6B,0x6B,0x6B,0x00,0x00,0x00,0x00}, // m
{0x00,0x00,0x00,0x00,0x00,0x6E,0x33,0x33,0x33,0x33,0x33,0x33,0x00,0x00,0x00,0x00}, // n
{0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x63,0x63,0x63,0x63,0x3E,0x00,0x00,0x00,0x00}, // o
{0x00,0x00,0x00,0x00,0x00,0x6E,0x33,0x33,0x33,0x33,0x3E,0x30,0x30,0x78,0x00,0x00}, // p
{0x00,0x00,0x00,0x00,0x00,0x3B,0x66,0x66,0x66,0x66,0x3E,0x06,0x06,0x0F,0x00,0x00}, // q
{0x00,0x00,0x00,0x00,0x00,0x6E,0x3B,0x33,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00}, // r
{0x00,0x00,0x00,0x00,0x00,0x3E,0x63,0x38,0x0E,0x03,0x63,0x3E,0x00,0x00,0x00,0x00}, // s
{0x00,0x00,0x08,0x18,0x18,0x7E,0x18,0x18,0x18,0x18,0x1B,0x0E,0x00,0x00,0x00,0x00}, // t
{0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x3B,0x00,0x00,0x00,0x00}, // u
{0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x36,0x36,0x1C,0x1C,0x08,0x00,0x00,0x00,0x00}, // v
{0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x63,0x6B,0x6B,0x7F,0x36,0x00,0x00,0x00,0x00}, // w
{0x00,0x00,0x00,0x00,0x00,0x63,0x36,0x1C,0x1C,0x1C,0x36,0x63,0x00,0x00,0x00,0x00}, // x
{0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x3F,0x03,0x06,0x3C,0x00,0x00}, // y
{0x00,0x00,0x00,0x00,0x00,0x7F,0x66,0x0C,0x18,0x30,0x63,0x7F,0x00,0x00,0x00,0x00}, // z
{0x00,0x00,0x0E,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00}, // {
{0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00}, // |
{0x00,0x00,0x70,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00}, // }
{0x00,0x00,0x3B,0x6E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // ~
{0x00,0x70,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} // DEL
};
*/

View file

@ -21,15 +21,15 @@ extern uint8_t _binary_obj_fpga_all_bit_z_start, _binary_obj_fpga_all_bit_z_end;
static uint8_t *fpga_image_ptr = NULL;
static uint32_t uncompressed_bytes_cnt;
#define OUTPUT_BUFFER_LEN 80
#define OUTPUT_BUFFER_LEN 80
//-----------------------------------------------------------------------------
// Set up the Serial Peripheral Interface as master
// Used to write the FPGA config word
// May also be used to write to other SPI attached devices like an LCD
//-----------------------------------------------------------------------------
static void DisableSpi(void) {
//* Reset all the Chip Select register
static void DisableSpi(void) {
//* Reset all the Chip Select register
AT91C_BASE_SPI->SPI_CSR[0] = 0;
AT91C_BASE_SPI->SPI_CSR[1] = 0;
AT91C_BASE_SPI->SPI_CSR[2] = 0;
@ -40,121 +40,116 @@ static void DisableSpi(void) {
// Disable all interrupts
AT91C_BASE_SPI->SPI_IDR = 0xFFFFFFFF;
// SPI disable
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIDIS;
// SPI disable
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIDIS;
}
void SetupSpi(int mode) {
// PA1 -> SPI_NCS3 chip select (MEM)
// PA10 -> SPI_NCS2 chip select (LCD)
// PA11 -> SPI_NCS0 chip select (FPGA)
// PA12 -> SPI_MISO Master-In Slave-Out
// PA13 -> SPI_MOSI Master-Out Slave-In
// PA14 -> SPI_SPCK Serial Clock
// PA1 -> SPI_NCS3 chip select (MEM)
// PA10 -> SPI_NCS2 chip select (LCD)
// PA11 -> SPI_NCS0 chip select (FPGA)
// PA12 -> SPI_MISO Master-In Slave-Out
// PA13 -> SPI_MOSI Master-Out Slave-In
// PA14 -> SPI_SPCK Serial Clock
// Disable PIO control of the following pins, allows use by the SPI peripheral
AT91C_BASE_PIOA->PIO_PDR = GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK;
// Disable PIO control of the following pins, allows use by the SPI peripheral
AT91C_BASE_PIOA->PIO_PDR = GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK;
// Peripheral A
AT91C_BASE_PIOA->PIO_ASR = GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK;
// Peripheral A
AT91C_BASE_PIOA->PIO_ASR = GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK;
// Peripheral B
//AT91C_BASE_PIOA->PIO_BSR |= GPIO_NCS2;
// Peripheral B
//AT91C_BASE_PIOA->PIO_BSR |= GPIO_NCS2;
//enable the SPI Peripheral clock
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SPI);
// Enable SPI
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIEN;
//enable the SPI Peripheral clock
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SPI);
// Enable SPI
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIEN;
switch (mode) {
case SPI_FPGA_MODE:
AT91C_BASE_SPI->SPI_MR =
( 0 << 24) | // Delay between chip selects (take default: 6 MCK periods)
(0xE << 16) | // Peripheral Chip Select (selects FPGA SPI_NCS0 or PA11)
( 0 << 7) | // Local Loopback Disabled
AT91C_SPI_MODFDIS | // Mode Fault Detection disabled
( 0 << 2) | // Chip selects connected directly to peripheral
AT91C_SPI_PS_FIXED | // Fixed Peripheral Select
AT91C_SPI_MSTR; // Master Mode
AT91C_BASE_SPI->SPI_CSR[0] =
( 1 << 24) | // Delay between Consecutive Transfers (32 MCK periods)
( 1 << 16) | // Delay Before SPCK (1 MCK period)
( 6 << 8) | // Serial Clock Baud Rate (baudrate = MCK/6 = 24Mhz/6 = 4M baud
AT91C_SPI_BITS_16 | // Bits per Transfer (16 bits)
( 0 << 3) | // Chip Select inactive after transfer
AT91C_SPI_NCPHA | // Clock Phase data captured on leading edge, changes on following edge
( 0 << 0); // Clock Polarity inactive state is logic 0
break;
/*
case SPI_LCD_MODE:
AT91C_BASE_SPI->SPI_MR =
( 0 << 24) | // Delay between chip selects (take default: 6 MCK periods)
(0xB << 16) | // Peripheral Chip Select (selects LCD SPI_NCS2 or PA10)
( 0 << 7) | // Local Loopback Disabled
( 1 << 4) | // Mode Fault Detection disabled
( 0 << 2) | // Chip selects connected directly to peripheral
( 0 << 1) | // Fixed Peripheral Select
( 1 << 0); // Master Mode
AT91C_BASE_SPI->SPI_CSR[2] =
( 1 << 24) | // Delay between Consecutive Transfers (32 MCK periods)
( 1 << 16) | // Delay Before SPCK (1 MCK period)
( 6 << 8) | // Serial Clock Baud Rate (baudrate = MCK/6 = 24Mhz/6 = 4M baud
AT91C_SPI_BITS_9 | // Bits per Transfer (9 bits)
( 0 << 3) | // Chip Select inactive after transfer
( 1 << 1) | // Clock Phase data captured on leading edge, changes on following edge
( 0 << 0); // Clock Polarity inactive state is logic 0
break;
*/
default:
DisableSpi();
break;
}
switch (mode) {
case SPI_FPGA_MODE:
AT91C_BASE_SPI->SPI_MR =
(0 << 24) | // Delay between chip selects (take default: 6 MCK periods)
(0xE << 16) | // Peripheral Chip Select (selects FPGA SPI_NCS0 or PA11)
(0 << 7) | // Local Loopback Disabled
AT91C_SPI_MODFDIS | // Mode Fault Detection disabled
(0 << 2) | // Chip selects connected directly to peripheral
AT91C_SPI_PS_FIXED | // Fixed Peripheral Select
AT91C_SPI_MSTR; // Master Mode
AT91C_BASE_SPI->SPI_CSR[0] =
(1 << 24) | // Delay between Consecutive Transfers (32 MCK periods)
(1 << 16) | // Delay Before SPCK (1 MCK period)
(6 << 8) | // Serial Clock Baud Rate (baudrate = MCK/6 = 24Mhz/6 = 4M baud
AT91C_SPI_BITS_16 | // Bits per Transfer (16 bits)
(0 << 3) | // Chip Select inactive after transfer
AT91C_SPI_NCPHA | // Clock Phase data captured on leading edge, changes on following edge
(0 << 0); // Clock Polarity inactive state is logic 0
break;
/*
case SPI_LCD_MODE:
AT91C_BASE_SPI->SPI_MR =
( 0 << 24) | // Delay between chip selects (take default: 6 MCK periods)
(0xB << 16) | // Peripheral Chip Select (selects LCD SPI_NCS2 or PA10)
( 0 << 7) | // Local Loopback Disabled
( 1 << 4) | // Mode Fault Detection disabled
( 0 << 2) | // Chip selects connected directly to peripheral
( 0 << 1) | // Fixed Peripheral Select
( 1 << 0); // Master Mode
AT91C_BASE_SPI->SPI_CSR[2] =
( 1 << 24) | // Delay between Consecutive Transfers (32 MCK periods)
( 1 << 16) | // Delay Before SPCK (1 MCK period)
( 6 << 8) | // Serial Clock Baud Rate (baudrate = MCK/6 = 24Mhz/6 = 4M baud
AT91C_SPI_BITS_9 | // Bits per Transfer (9 bits)
( 0 << 3) | // Chip Select inactive after transfer
( 1 << 1) | // Clock Phase data captured on leading edge, changes on following edge
( 0 << 0); // Clock Polarity inactive state is logic 0
break;
*/
default:
DisableSpi();
break;
}
}
//-----------------------------------------------------------------------------
// Set up the synchronous serial port, with the one set of options that we
// always use when we are talking to the FPGA. Both RX and TX are enabled.
//-----------------------------------------------------------------------------
void FpgaSetupSscExt(uint8_t clearPCER) {
// First configure the GPIOs, and get ourselves a clock.
AT91C_BASE_PIOA->PIO_ASR =
GPIO_SSC_FRAME |
GPIO_SSC_DIN |
GPIO_SSC_DOUT |
GPIO_SSC_CLK;
AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DOUT;
if ( clearPCER )
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SSC);
else
AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_SSC);
// Now set up the SSC proper, starting from a known state.
AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST;
// RX clock comes from TX clock, RX starts when TX starts, data changes
// on RX clock rising edge, sampled on falling edge
AT91C_BASE_SSC->SSC_RCMR = SSC_CLOCK_MODE_SELECT(1) | SSC_CLOCK_MODE_START(1);
// 8 bits per transfer, no loopback, MSB first, 1 transfer per sync
// pulse, no output sync
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
// clock comes from TK pin, no clock output, outputs change on falling
// edge of TK, sample on rising edge of TK, start on positive-going edge of sync
AT91C_BASE_SSC->SSC_TCMR = SSC_CLOCK_MODE_SELECT(2) | SSC_CLOCK_MODE_START(5);
// tx framing is the same as the rx framing
AT91C_BASE_SSC->SSC_TFMR = AT91C_BASE_SSC->SSC_RFMR;
AT91C_BASE_SSC->SSC_CR = AT91C_SSC_RXEN | AT91C_SSC_TXEN;
}
void FpgaSetupSsc(void) {
FpgaSetupSscExt(true);
// First configure the GPIOs, and get ourselves a clock.
AT91C_BASE_PIOA->PIO_ASR =
GPIO_SSC_FRAME |
GPIO_SSC_DIN |
GPIO_SSC_DOUT |
GPIO_SSC_CLK;
AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DOUT;
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SSC);
// Now set up the SSC proper, starting from a known state.
AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST;
// RX clock comes from TX clock, RX starts when TX starts, data changes
// on RX clock rising edge, sampled on falling edge
AT91C_BASE_SSC->SSC_RCMR = SSC_CLOCK_MODE_SELECT(1) | SSC_CLOCK_MODE_START(1);
// 8 bits per transfer, no loopback, MSB first, 1 transfer per sync
// pulse, no output sync
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
// clock comes from TK pin, no clock output, outputs change on falling
// edge of TK, sample on rising edge of TK, start on positive-going edge of sync
AT91C_BASE_SSC->SSC_TCMR = SSC_CLOCK_MODE_SELECT(2) | SSC_CLOCK_MODE_START(5);
// tx framing is the same as the rx framing
AT91C_BASE_SSC->SSC_TFMR = AT91C_BASE_SSC->SSC_RFMR;
AT91C_BASE_SSC->SSC_CR = AT91C_SSC_RXEN | AT91C_SSC_TXEN;
}
//-----------------------------------------------------------------------------
// Set up DMA to receive samples from the FPGA. We will use the PDC, with
// a single buffer as a circular buffer (so that we just chain back to
@ -162,15 +157,15 @@ void FpgaSetupSsc(void) {
// is in apps.h, because it should be inlined, for speed.
//-----------------------------------------------------------------------------
bool FpgaSetupSscDma(uint8_t *buf, int len) {
if (buf == NULL) return false;
if (buf == NULL) return false;
FpgaDisableSscDma();
AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t) buf; // transfer to this memory address
AT91C_BASE_PDC_SSC->PDC_RCR = len; // transfer this many bytes
AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) buf; // next transfer to same memory address
AT91C_BASE_PDC_SSC->PDC_RNCR = len; // ... with same number of bytes
FpgaEnableSscDma();
return true;
FpgaDisableSscDma();
AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t) buf; // transfer to this memory address
AT91C_BASE_PDC_SSC->PDC_RCR = len; // transfer this many bytes
AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) buf; // next transfer to same memory address
AT91C_BASE_PDC_SSC->PDC_RNCR = len; // ... with same number of bytes
FpgaEnableSscDma();
return true;
}
//----------------------------------------------------------------------------
@ -178,20 +173,20 @@ bool FpgaSetupSscDma(uint8_t *buf, int len) {
// each call.
//----------------------------------------------------------------------------
static int get_from_fpga_combined_stream(z_streamp compressed_fpga_stream, uint8_t *output_buffer) {
if (fpga_image_ptr == compressed_fpga_stream->next_out) { // need more data
compressed_fpga_stream->next_out = output_buffer;
compressed_fpga_stream->avail_out = OUTPUT_BUFFER_LEN;
fpga_image_ptr = output_buffer;
int res = inflate(compressed_fpga_stream, Z_SYNC_FLUSH);
if (fpga_image_ptr == compressed_fpga_stream->next_out) { // need more data
compressed_fpga_stream->next_out = output_buffer;
compressed_fpga_stream->avail_out = OUTPUT_BUFFER_LEN;
fpga_image_ptr = output_buffer;
int res = inflate(compressed_fpga_stream, Z_SYNC_FLUSH);
if (res != Z_OK)
Dbprintf("inflate returned: %d, %s", res, compressed_fpga_stream->msg);
if (res != Z_OK)
Dbprintf("inflate returned: %d, %s", res, compressed_fpga_stream->msg);
if (res < 0)
return res;
}
uncompressed_bytes_cnt++;
return *fpga_image_ptr++;
if (res < 0)
return res;
}
uncompressed_bytes_cnt++;
return *fpga_image_ptr++;
}
//----------------------------------------------------------------------------
@ -200,140 +195,143 @@ static int get_from_fpga_combined_stream(z_streamp compressed_fpga_stream, uint8
// 288 bytes from FPGA file 1, followed by 288 bytes from FGPA file 2, etc.
//----------------------------------------------------------------------------
static int get_from_fpga_stream(int bitstream_version, z_streamp compressed_fpga_stream, uint8_t *output_buffer) {
while((uncompressed_bytes_cnt / FPGA_INTERLEAVE_SIZE) % fpga_bitstream_num != (bitstream_version - 1)) {
// skip undesired data belonging to other bitstream_versions
get_from_fpga_combined_stream(compressed_fpga_stream, output_buffer);
}
while ((uncompressed_bytes_cnt / FPGA_INTERLEAVE_SIZE) % fpga_bitstream_num != (bitstream_version - 1)) {
// skip undesired data belonging to other bitstream_versions
get_from_fpga_combined_stream(compressed_fpga_stream, output_buffer);
}
return get_from_fpga_combined_stream(compressed_fpga_stream, output_buffer);
return get_from_fpga_combined_stream(compressed_fpga_stream, output_buffer);
}
static voidpf fpga_inflate_malloc(voidpf opaque, uInt items, uInt size) {
return BigBuf_malloc(items*size);
return BigBuf_malloc(items * size);
}
// free eventually allocated BigBuf memory
static void fpga_inflate_free(voidpf opaque, voidpf address) {
BigBuf_free(); BigBuf_Clear_ext(false);
BigBuf_free();
BigBuf_Clear_ext(false);
}
//----------------------------------------------------------------------------
// Initialize decompression of the respective (HF or LF) FPGA stream
//----------------------------------------------------------------------------
static bool reset_fpga_stream(int bitstream_version, z_streamp compressed_fpga_stream, uint8_t *output_buffer) {
uint8_t header[FPGA_BITSTREAM_FIXED_HEADER_SIZE];
uint8_t header[FPGA_BITSTREAM_FIXED_HEADER_SIZE];
uncompressed_bytes_cnt = 0;
uncompressed_bytes_cnt = 0;
// initialize z_stream structure for inflate:
compressed_fpga_stream->next_in = &_binary_obj_fpga_all_bit_z_start;
compressed_fpga_stream->avail_in = &_binary_obj_fpga_all_bit_z_end - &_binary_obj_fpga_all_bit_z_start;
compressed_fpga_stream->next_out = output_buffer;
compressed_fpga_stream->avail_out = OUTPUT_BUFFER_LEN;
compressed_fpga_stream->zalloc = &fpga_inflate_malloc;
compressed_fpga_stream->zfree = &fpga_inflate_free;
// initialize z_stream structure for inflate:
compressed_fpga_stream->next_in = &_binary_obj_fpga_all_bit_z_start;
compressed_fpga_stream->avail_in = &_binary_obj_fpga_all_bit_z_end - &_binary_obj_fpga_all_bit_z_start;
compressed_fpga_stream->next_out = output_buffer;
compressed_fpga_stream->avail_out = OUTPUT_BUFFER_LEN;
compressed_fpga_stream->zalloc = &fpga_inflate_malloc;
compressed_fpga_stream->zfree = &fpga_inflate_free;
inflateInit2(compressed_fpga_stream, 0);
int res = inflateInit2(compressed_fpga_stream, 0);
if (res < 0)
return false;
fpga_image_ptr = output_buffer;
fpga_image_ptr = output_buffer;
for (uint16_t i = 0; i < FPGA_BITSTREAM_FIXED_HEADER_SIZE; i++)
header[i] = get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer);
for (uint16_t i = 0; i < FPGA_BITSTREAM_FIXED_HEADER_SIZE; i++)
header[i] = get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer);
// Check for a valid .bit file (starts with bitparse_fixed_header)
if (memcmp(bitparse_fixed_header, header, FPGA_BITSTREAM_FIXED_HEADER_SIZE) == 0)
return true;
// Check for a valid .bit file (starts with bitparse_fixed_header)
if (memcmp(bitparse_fixed_header, header, FPGA_BITSTREAM_FIXED_HEADER_SIZE) == 0)
return true;
return false;
return false;
}
static void DownloadFPGA_byte(unsigned char w) {
static void DownloadFPGA_byte(uint8_t w) {
#define SEND_BIT(x) { if(w & (1<<x) ) HIGH(GPIO_FPGA_DIN); else LOW(GPIO_FPGA_DIN); HIGH(GPIO_FPGA_CCLK); LOW(GPIO_FPGA_CCLK); }
SEND_BIT(7);
SEND_BIT(6);
SEND_BIT(5);
SEND_BIT(4);
SEND_BIT(3);
SEND_BIT(2);
SEND_BIT(1);
SEND_BIT(0);
SEND_BIT(7);
SEND_BIT(6);
SEND_BIT(5);
SEND_BIT(4);
SEND_BIT(3);
SEND_BIT(2);
SEND_BIT(1);
SEND_BIT(0);
}
// Download the fpga image starting at current stream position with length FpgaImageLen bytes
static void DownloadFPGA(int bitstream_version, int FpgaImageLen, z_streamp compressed_fpga_stream, uint8_t *output_buffer) {
int i = 0;
int i = 0;
AT91C_BASE_PIOA->PIO_OER = GPIO_FPGA_ON;
AT91C_BASE_PIOA->PIO_PER = GPIO_FPGA_ON;
HIGH(GPIO_FPGA_ON); // ensure everything is powered on
AT91C_BASE_PIOA->PIO_OER = GPIO_FPGA_ON;
AT91C_BASE_PIOA->PIO_PER = GPIO_FPGA_ON;
HIGH(GPIO_FPGA_ON); // ensure everything is powered on
SpinDelay(50);
SpinDelay(50);
LED_D_ON();
LED_D_ON();
// These pins are inputs
// These pins are inputs
AT91C_BASE_PIOA->PIO_ODR =
GPIO_FPGA_NINIT |
GPIO_FPGA_DONE;
// PIO controls the following pins
GPIO_FPGA_NINIT |
GPIO_FPGA_DONE;
// PIO controls the following pins
AT91C_BASE_PIOA->PIO_PER =
GPIO_FPGA_NINIT |
GPIO_FPGA_DONE;
// Enable pull-ups
AT91C_BASE_PIOA->PIO_PPUER =
GPIO_FPGA_NINIT |
GPIO_FPGA_DONE;
GPIO_FPGA_NINIT |
GPIO_FPGA_DONE;
// Enable pull-ups
AT91C_BASE_PIOA->PIO_PPUER =
GPIO_FPGA_NINIT |
GPIO_FPGA_DONE;
// setup initial logic state
HIGH(GPIO_FPGA_NPROGRAM);
LOW(GPIO_FPGA_CCLK);
LOW(GPIO_FPGA_DIN);
// These pins are outputs
AT91C_BASE_PIOA->PIO_OER =
GPIO_FPGA_NPROGRAM |
GPIO_FPGA_CCLK |
GPIO_FPGA_DIN;
// setup initial logic state
HIGH(GPIO_FPGA_NPROGRAM);
LOW(GPIO_FPGA_CCLK);
LOW(GPIO_FPGA_DIN);
// These pins are outputs
AT91C_BASE_PIOA->PIO_OER =
GPIO_FPGA_NPROGRAM |
GPIO_FPGA_CCLK |
GPIO_FPGA_DIN;
// enter FPGA configuration mode
LOW(GPIO_FPGA_NPROGRAM);
SpinDelay(50);
HIGH(GPIO_FPGA_NPROGRAM);
// enter FPGA configuration mode
LOW(GPIO_FPGA_NPROGRAM);
SpinDelay(50);
HIGH(GPIO_FPGA_NPROGRAM);
i = 100000;
// wait for FPGA ready to accept data signal
while ((i) && ( !(AT91C_BASE_PIOA->PIO_PDSR & GPIO_FPGA_NINIT ) ) ) {
i--;
}
i = 100000;
// wait for FPGA ready to accept data signal
while ((i) && (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_FPGA_NINIT))) {
i--;
}
// crude error indicator, leave both red LEDs on and return
if (i==0){
LED_C_ON();
LED_D_ON();
return;
}
// crude error indicator, leave both red LEDs on and return
if (i == 0) {
LED_C_ON();
LED_D_ON();
return;
}
for (i = 0; i < FpgaImageLen; i++) {
int b = get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer);
if (b < 0) {
Dbprintf("Error %d during FpgaDownload", b);
break;
}
DownloadFPGA_byte(b);
}
for (i = 0; i < FpgaImageLen; i++) {
int b = get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer);
if (b < 0) {
Dbprintf("Error %d during FpgaDownload", b);
break;
}
DownloadFPGA_byte(b);
}
// continue to clock FPGA until ready signal goes high
i = 100000;
while ( (i--) && ( !(AT91C_BASE_PIOA->PIO_PDSR & GPIO_FPGA_DONE ) ) ) {
HIGH(GPIO_FPGA_CCLK);
LOW(GPIO_FPGA_CCLK);
}
// crude error indicator, leave both red LEDs on and return
if (i==0){
LED_C_ON();
LED_D_ON();
return;
}
LED_D_OFF();
// continue to clock FPGA until ready signal goes high
i = 100000;
while ((i--) && (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_FPGA_DONE))) {
HIGH(GPIO_FPGA_CCLK);
LOW(GPIO_FPGA_CCLK);
}
// crude error indicator, leave both red LEDs on and return
if (i == 0) {
LED_C_ON();
LED_D_ON();
return;
}
LED_D_OFF();
}
/* Simple Xilinx .bit parser. The file starts with the fixed opaque byte sequence
@ -343,48 +341,48 @@ static void DownloadFPGA(int bitstream_version, int FpgaImageLen, z_streamp comp
* length.
*/
static int bitparse_find_section(int bitstream_version, char section_name, uint32_t *section_length, z_streamp compressed_fpga_stream, uint8_t *output_buffer) {
int result = 0;
#define MAX_FPGA_BIT_STREAM_HEADER_SEARCH 100 // maximum number of bytes to search for the requested section
uint16_t numbytes = 0;
while(numbytes < MAX_FPGA_BIT_STREAM_HEADER_SEARCH) {
char current_name = get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer);
numbytes++;
uint32_t current_length = 0;
if (current_name < 'a' || current_name > 'e') {
/* Strange section name, abort */
break;
}
current_length = 0;
switch (current_name) {
case 'e':
/* Four byte length field */
current_length += get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer) << 24;
current_length += get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer) << 16;
numbytes += 2;
default: /* Fall through, two byte length field */
current_length += get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer) << 8;
current_length += get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer) << 0;
numbytes += 2;
}
int result = 0;
#define MAX_FPGA_BIT_STREAM_HEADER_SEARCH 100 // maximum number of bytes to search for the requested section
uint16_t numbytes = 0;
while (numbytes < MAX_FPGA_BIT_STREAM_HEADER_SEARCH) {
char current_name = get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer);
numbytes++;
uint32_t current_length = 0;
if (current_name < 'a' || current_name > 'e') {
/* Strange section name, abort */
break;
}
current_length = 0;
switch (current_name) {
case 'e':
/* Four byte length field */
current_length += get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer) << 24;
current_length += get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer) << 16;
numbytes += 2;
default: /* Fall through, two byte length field */
current_length += get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer) << 8;
current_length += get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer) << 0;
numbytes += 2;
}
if (current_name != 'e' && current_length > 255) {
/* Maybe a parse error */
break;
}
if (current_name != 'e' && current_length > 255) {
/* Maybe a parse error */
break;
}
if (current_name == section_name) {
/* Found it */
*section_length = current_length;
result = 1;
break;
}
if (current_name == section_name) {
/* Found it */
*section_length = current_length;
result = 1;
break;
}
for (uint16_t i = 0; i < current_length && numbytes < MAX_FPGA_BIT_STREAM_HEADER_SEARCH; i++) {
get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer);
numbytes++;
}
}
return result;
for (uint16_t i = 0; i < current_length && numbytes < MAX_FPGA_BIT_STREAM_HEADER_SEARCH; i++) {
get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer);
numbytes++;
}
}
return result;
}
//----------------------------------------------------------------------------
@ -393,34 +391,36 @@ static int bitparse_find_section(int bitstream_version, char section_name, uint3
//----------------------------------------------------------------------------
void FpgaDownloadAndGo(int bitstream_version) {
// check whether or not the bitstream is already loaded
if (downloaded_bitstream == bitstream_version)
return;
z_stream compressed_fpga_stream;
uint8_t output_buffer[OUTPUT_BUFFER_LEN] = {0x00};
// check whether or not the bitstream is already loaded
if (downloaded_bitstream == bitstream_version)
return;
bool verbose = (MF_DBGLEVEL > 3);
// make sure that we have enough memory to decompress
BigBuf_free(); BigBuf_Clear_ext(verbose);
z_stream compressed_fpga_stream;
uint8_t output_buffer[OUTPUT_BUFFER_LEN] = {0x00};
if (!reset_fpga_stream(bitstream_version, &compressed_fpga_stream, output_buffer))
return;
bool verbose = (DBGLEVEL > 3);
uint32_t bitstream_length;
if (bitparse_find_section(bitstream_version, 'e', &bitstream_length, &compressed_fpga_stream, output_buffer)) {
DownloadFPGA(bitstream_version, bitstream_length, &compressed_fpga_stream, output_buffer);
downloaded_bitstream = bitstream_version;
}
// make sure that we have enough memory to decompress
BigBuf_free();
BigBuf_Clear_ext(verbose);
inflateEnd(&compressed_fpga_stream);
if (!reset_fpga_stream(bitstream_version, &compressed_fpga_stream, output_buffer))
return;
// turn off antenna
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
// free eventually allocated BigBuf memory
BigBuf_free(); BigBuf_Clear_ext(false);
uint32_t bitstream_length;
if (bitparse_find_section(bitstream_version, 'e', &bitstream_length, &compressed_fpga_stream, output_buffer)) {
DownloadFPGA(bitstream_version, bitstream_length, &compressed_fpga_stream, output_buffer);
downloaded_bitstream = bitstream_version;
}
inflateEnd(&compressed_fpga_stream);
// turn off antenna
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
// free eventually allocated BigBuf memory
BigBuf_free();
BigBuf_Clear_ext(false);
}
//-----------------------------------------------------------------------------
@ -429,10 +429,10 @@ void FpgaDownloadAndGo(int bitstream_version) {
// where C is the 4 bit command and D is the 12 bit data
//-----------------------------------------------------------------------------
void FpgaSendCommand(uint16_t cmd, uint16_t v) {
SetupSpi(SPI_FPGA_MODE);
while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0); // wait for the transfer to complete
AT91C_BASE_SPI->SPI_TDR = AT91C_SPI_LASTXFER | cmd | v; // send the data
while (!(AT91C_BASE_SPI->SPI_SR & AT91C_SPI_RDRF)) {}; // wait till transfer is complete
SetupSpi(SPI_FPGA_MODE);
while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0); // wait for the transfer to complete
AT91C_BASE_SPI->SPI_TDR = AT91C_SPI_LASTXFER | cmd | v; // send the data
while (!(AT91C_BASE_SPI->SPI_SR & AT91C_SPI_RDRF)) {}; // wait till transfer is complete
}
//-----------------------------------------------------------------------------
// Write the FPGA setup word (that determines what mode the logic is in, read
@ -440,7 +440,7 @@ void FpgaSendCommand(uint16_t cmd, uint16_t v) {
// avoid changing this function's occurence everywhere in the source code.
//-----------------------------------------------------------------------------
void FpgaWriteConfWord(uint8_t v) {
FpgaSendCommand(FPGA_CMD_SET_CONFREG, v);
FpgaSendCommand(FPGA_CMD_SET_CONFREG, v);
}
//-----------------------------------------------------------------------------
@ -449,46 +449,57 @@ void FpgaWriteConfWord(uint8_t v) {
// the samples from the ADC always flow through the FPGA.
//-----------------------------------------------------------------------------
void SetAdcMuxFor(uint32_t whichGpio) {
AT91C_BASE_PIOA->PIO_OER =
GPIO_MUXSEL_HIPKD |
GPIO_MUXSEL_LOPKD |
GPIO_MUXSEL_LORAW |
GPIO_MUXSEL_HIRAW;
AT91C_BASE_PIOA->PIO_PER =
GPIO_MUXSEL_HIPKD |
GPIO_MUXSEL_LOPKD |
GPIO_MUXSEL_LORAW |
GPIO_MUXSEL_HIRAW;
#ifndef WITH_FPC_USART
// When compiled without FPC USART support
AT91C_BASE_PIOA->PIO_OER =
GPIO_MUXSEL_HIPKD |
GPIO_MUXSEL_LOPKD |
GPIO_MUXSEL_LORAW |
GPIO_MUXSEL_HIRAW;
LOW(GPIO_MUXSEL_HIPKD);
LOW(GPIO_MUXSEL_LOPKD);
#ifndef WITH_FPC
LOW(GPIO_MUXSEL_HIRAW);
LOW(GPIO_MUXSEL_LORAW);
#endif
AT91C_BASE_PIOA->PIO_PER =
GPIO_MUXSEL_HIPKD |
GPIO_MUXSEL_LOPKD |
GPIO_MUXSEL_LORAW |
GPIO_MUXSEL_HIRAW;
LOW(GPIO_MUXSEL_HIPKD);
LOW(GPIO_MUXSEL_LOPKD);
LOW(GPIO_MUXSEL_HIRAW);
LOW(GPIO_MUXSEL_LORAW);
HIGH(whichGpio);
#else
if ((whichGpio == GPIO_MUXSEL_LORAW) || (whichGpio == GPIO_MUXSEL_HIRAW))
return;
// FPC USART uses HIRAW/LOWRAW pins, so they are excluded here.
AT91C_BASE_PIOA->PIO_OER = GPIO_MUXSEL_HIPKD | GPIO_MUXSEL_LOPKD;
AT91C_BASE_PIOA->PIO_PER = GPIO_MUXSEL_HIPKD | GPIO_MUXSEL_LOPKD;
LOW(GPIO_MUXSEL_HIPKD);
LOW(GPIO_MUXSEL_LOPKD);
HIGH(whichGpio);
#endif
HIGH(whichGpio);
}
void Fpga_print_status(void) {
Dbprintf("Currently loaded FPGA image");
Dbprintf(" mode....................%s", fpga_version_information[downloaded_bitstream-1]);
DbpString(_BLUE_("Currently loaded FPGA image"));
Dbprintf(" mode....................%s", fpga_version_information[downloaded_bitstream - 1]);
}
int FpgaGetCurrent(void) {
return downloaded_bitstream;
return downloaded_bitstream;
}
// Turns off the antenna,
// Turns off the antenna,
// log message
// if HF, Disable SSC DMA
// turn off trace and leds off.
void switch_off(void) {
if (MF_DBGLEVEL > 3) Dbprintf("switch_off");
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
if (downloaded_bitstream == FPGA_BITSTREAM_HF )
FpgaDisableSscDma();
set_tracing(false);
LEDsoff();
void switch_off(void) {
if (DBGLEVEL > 3) Dbprintf("switch_off");
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
if (downloaded_bitstream == FPGA_BITSTREAM_HF)
FpgaDisableSscDma();
set_tracing(false);
LEDsoff();
}

View file

@ -16,29 +16,28 @@
#include <stdbool.h>
#include "apps.h"
#include "fpga.h"
#include "common.h" // standard definitions
#include "proxmark3.h" // common area
#include "common.h" // standard definitions
#include "proxmark3.h" // common area
#include "string.h"
#include "BigBuf.h" // bigbuf mem
#include "zlib.h" // uncompress
#include "BigBuf.h" // bigbuf mem
#include "zlib.h" // uncompress
void FpgaSendCommand(uint16_t cmd, uint16_t v);
void FpgaWriteConfWord(uint8_t v);
void FpgaDownloadAndGo(int bitstream_version);
// void FpgaGatherVersion(int bitstream_version, char *dst, int len);
void FpgaSetupSscExt(uint8_t clearPCER);
void FpgaSetupSsc(void);
void SetupSpi(int mode);
bool FpgaSetupSscDma(uint8_t *buf, int len);
void Fpga_print_status(void);
int FpgaGetCurrent(void);
#define FpgaDisableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;
#define FpgaDisableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;
#define FpgaEnableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN;
void SetAdcMuxFor(uint32_t whichGpio);
// extern and generel turn off the antenna method
extern void switch_off(void);
void switch_off(void);
// definitions for multiple FPGA config files support
#define FPGA_BITSTREAM_LF 1
@ -46,54 +45,56 @@ extern void switch_off(void);
//#define FPGA_BITSTREAM_FELICA 3
// Definitions for the FPGA commands.
#define FPGA_CMD_SET_CONFREG (1<<12)
#define FPGA_CMD_SET_DIVISOR (2<<12)
#define FPGA_CMD_SET_USER_BYTE1 (3<<12)
#define FPGA_CMD_SET_CONFREG (1<<12)
#define FPGA_CMD_SET_DIVISOR (2<<12)
#define FPGA_CMD_SET_USER_BYTE1 (3<<12)
// Definitions for the FPGA configuration word.
// LF
#define FPGA_MAJOR_MODE_LF_ADC (0<<5)
#define FPGA_MAJOR_MODE_LF_EDGE_DETECT (1<<5)
#define FPGA_MAJOR_MODE_LF_PASSTHRU (2<<5)
#define FPGA_MAJOR_MODE_LF_ADC (0<<5)
#define FPGA_MAJOR_MODE_LF_EDGE_DETECT (1<<5)
#define FPGA_MAJOR_MODE_LF_PASSTHRU (2<<5)
// HF
#define FPGA_MAJOR_MODE_HF_READER_TX (0<<5)
#define FPGA_MAJOR_MODE_HF_READER_RX_XCORR (1<<5)
#define FPGA_MAJOR_MODE_HF_SIMULATOR (2<<5)
#define FPGA_MAJOR_MODE_HF_ISO14443A (3<<5)
#define FPGA_MAJOR_MODE_HF_SNOOP (4<<5)
#define FPGA_MAJOR_MODE_HF_FELICA (5<<5)
#define FPGA_MAJOR_MODE_HF_READER_TX (0<<5)
#define FPGA_MAJOR_MODE_HF_READER_RX_XCORR (1<<5)
#define FPGA_MAJOR_MODE_HF_SIMULATOR (2<<5)
#define FPGA_MAJOR_MODE_HF_ISO14443A (3<<5)
#define FPGA_MAJOR_MODE_HF_SNOOP (4<<5)
#define FPGA_MAJOR_MODE_HF_FELICA (5<<5)
// BOTH
#define FPGA_MAJOR_MODE_OFF (7<<5)
#define FPGA_MAJOR_MODE_OFF_LF (6<<5)
#define FPGA_MAJOR_MODE_OFF (7<<5)
// Options for LF_ADC
#define FPGA_LF_ADC_READER_FIELD (1<<0)
#define FPGA_LF_ADC_READER_FIELD (1<<0)
// Options for LF_EDGE_DETECT
#define FPGA_CMD_SET_EDGE_DETECT_THRESHOLD FPGA_CMD_SET_USER_BYTE1
#define FPGA_LF_EDGE_DETECT_READER_FIELD (1<<0)
#define FPGA_LF_EDGE_DETECT_TOGGLE_MODE (1<<1)
#define FPGA_CMD_SET_EDGE_DETECT_THRESHOLD FPGA_CMD_SET_USER_BYTE1
#define FPGA_LF_EDGE_DETECT_READER_FIELD (1<<0)
#define FPGA_LF_EDGE_DETECT_TOGGLE_MODE (1<<1)
// Options for the HF reader, tx to tag
#define FPGA_HF_READER_TX_SHALLOW_MOD (1<<0)
#define FPGA_HF_READER_TX_SHALLOW_MOD (1<<0)
// Options for the HF reader, correlating against rx from tag
#define FPGA_HF_READER_RX_XCORR_848_KHZ (1<<0)
#define FPGA_HF_READER_RX_XCORR_SNOOP (1<<1)
#define FPGA_HF_READER_RX_XCORR_QUARTER (1<<2)
#define FPGA_HF_READER_RX_XCORR_848_KHZ (1<<0)
#define FPGA_HF_READER_RX_XCORR_SNOOP (1<<1)
#define FPGA_HF_READER_RX_XCORR_QUARTER (1<<2)
// Options for the HF simulated tag, how to modulate
#define FPGA_HF_SIMULATOR_NO_MODULATION (0<<0) // 0000
#define FPGA_HF_SIMULATOR_MODULATE_BPSK (1<<0) // 0001
#define FPGA_HF_SIMULATOR_MODULATE_212K (2<<0) // 0010
#define FPGA_HF_SIMULATOR_MODULATE_424K (4<<0) // 0100
#define FPGA_HF_SIMULATOR_MODULATE_424K_8BIT 0x5 // 0101
// no 848K
#define FPGA_HF_SIMULATOR_NO_MODULATION 0x0 // 0000
#define FPGA_HF_SIMULATOR_MODULATE_BPSK 0x1 // 0001
#define FPGA_HF_SIMULATOR_MODULATE_212K 0x2 // 0010
#define FPGA_HF_SIMULATOR_MODULATE_424K 0x4 // 0100
#define FPGA_HF_SIMULATOR_MODULATE_424K_8BIT 0x5 // 0101
// no 848K
// Options for ISO14443A
#define FPGA_HF_ISO14443A_SNIFFER (0<<0)
#define FPGA_HF_ISO14443A_TAGSIM_LISTEN (1<<0)
#define FPGA_HF_ISO14443A_TAGSIM_MOD (2<<0)
#define FPGA_HF_ISO14443A_READER_LISTEN (3<<0)
#define FPGA_HF_ISO14443A_READER_MOD (4<<0)
#define FPGA_HF_ISO14443A_SNIFFER (0<<0)
#define FPGA_HF_ISO14443A_TAGSIM_LISTEN (1<<0)
#define FPGA_HF_ISO14443A_TAGSIM_MOD (2<<0)
#define FPGA_HF_ISO14443A_READER_LISTEN (3<<0)
#define FPGA_HF_ISO14443A_READER_MOD (4<<0)
//options for Felica.
#define FPGA_MAJOR_MODE_ISO18092 (5<<5) // 01010 0000
//options for Felica.
#define FPGA_MAJOR_MODE_ISO18092 (5<<5) // 01010 0000
#define FPGA_HF_ISO18092_FLAG_NOMOD (1<<0) // 0001 disable modulation module
#define FPGA_HF_ISO18092_FLAG_424K (2<<0) // 0010 should enable 414k mode (untested). No autodetect
#define FPGA_HF_ISO18092_FLAG_READER (4<<0) // 0100 enables antenna power, to act as a reader instead of tag
#endif
#define FPGA_HF_ISO18092_FLAG_READER (4<<0) // 0100 enables antenna power, to act as a reader instead of tag
#endif

View file

@ -2,79 +2,78 @@
#include "apps.h"
#include "BigBuf.h"
#include "util.h"
#include "usb_cdc.h" // for usb_poll_validate_length
#include "usb_cdc.h" // for usb_poll_validate_length
static void RAMFUNC optimizedSnoop(void);
static void RAMFUNC optimizedSniff(void);
static void RAMFUNC optimizedSnoop(void)
{
int n = BigBuf_max_traceLen() / sizeof(uint16_t); // take all memory
static void RAMFUNC optimizedSniff(void) {
int n = BigBuf_max_traceLen() / sizeof(uint16_t); // take all memory
uint16_t *dest = (uint16_t *)BigBuf_get_addr();
uint16_t *destend = dest + n-1;
uint16_t *dest = (uint16_t *)BigBuf_get_addr();
uint16_t *destend = dest + n - 1;
// Reading data loop
while(dest <= destend) {
if(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
*dest = (uint16_t)(AT91C_BASE_SSC->SSC_RHR);
dest++;
}
}
//setting tracelen - importsnt! it was set by buffer overflow before
set_tracelen( BigBuf_max_traceLen());
// Reading data loop
while (dest <= destend) {
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
*dest = (uint16_t)(AT91C_BASE_SSC->SSC_RHR);
dest++;
}
}
//setting tracelen - important! it was set by buffer overflow before
set_tracelen(BigBuf_max_traceLen());
}
void HfSnoop(int samplesToSkip, int triggersToSkip)
{
BigBuf_free(); BigBuf_Clear();
Dbprintf("Skipping first %d sample pairs, Skipping %d triggers.\n", samplesToSkip, triggersToSkip);
int trigger_cnt = 0;
void HfSniff(int samplesToSkip, int triggersToSkip) {
BigBuf_free();
BigBuf_Clear();
LED_D_ON();
Dbprintf("Skipping first %d sample pairs, Skipping %d triggers.\n", samplesToSkip, triggersToSkip);
int trigger_cnt = 0;
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
// Set up the synchronous serial port
FpgaSetupSsc();
LED_D_ON();
// Setting Frame Mode For better performance on high speed data transfer.
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(16);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SNOOP);
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
// Set up the synchronous serial port
FpgaSetupSsc();
// Setting Frame Mode For better performance on high speed data transfer.
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(16);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SNOOP);
SpinDelay(100);
uint16_t r = 0;
while (!BUTTON_PRESS() && !usb_poll_validate_length() ) {
WDT_HIT();
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
r = (uint16_t)AT91C_BASE_SSC->SSC_RHR;
r = MAX(r & 0xff, r >> 8);
uint16_t r = 0;
while (!BUTTON_PRESS() && !data_available()) {
WDT_HIT();
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
r = (uint16_t)AT91C_BASE_SSC->SSC_RHR;
r = MAX(r & 0xff, r >> 8);
if (r >= 180) { // 0xB4 ??
if (++trigger_cnt > triggersToSkip)
break;
}
}
}
break;
}
}
}
if (!BUTTON_PRESS()) {
int waitcount = samplesToSkip; // lets wait 40000 ticks of pck0
while(waitcount != 0) {
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY))
waitcount--;
}
optimizedSnoop();
Dbprintf("Trigger kicked! Value: %d, Dumping Samples Hispeed now.", r);
}
if (!BUTTON_PRESS()) {
int waitcount = samplesToSkip; // lets wait 40000 ticks of pck0
while (waitcount != 0) {
//Resetting Frame mode (First set in fpgaloader.c)
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY))
waitcount--;
}
optimizedSniff();
Dbprintf("Trigger kicked! Value: %d, Dumping Samples Hispeed now.", r);
}
DbpString("HF Snoop end");
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_D_OFF();
//Resetting Frame mode (First set in fpgaloader.c)
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
DbpString("HF Sniffing end");
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_D_OFF();
}

File diff suppressed because it is too large Load diff

View file

@ -1,19 +1,23 @@
//-----------------------------------------------------------------------------
// (c) 2012 Roel Verdult
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// ISO14443 CRC calculation code.
// Hitag2 type prototyping
//-----------------------------------------------------------------------------
#ifndef __ISO14443CRC_H
#define __ISO14443CRC_H
#include "common.h"
#ifndef _HITAG2_H_
#define _HITAG2_H_
//-----------------------------------------------------------------------------
// Routines to compute the CRCs (two different flavours, just for confusion)
// required for ISO 14443, swiped directly from the spec.
#include <stdint.h>
#include <stdbool.h>
#include "hitag.h"
uint16_t UpdateCrc14443(uint8_t b, uint16_t *crc);
void SniffHitag(void);
void SimulateHitagTag(bool tag_mem_supplied, uint8_t *data);
void ReaderHitag(hitag_function htf, hitag_data *htd);
void WriterHitag(hitag_function htf, hitag_data *htd, int page);
#endif

116
armsrc/hitag2_crypto.c Normal file
View file

@ -0,0 +1,116 @@
//-----------------------------------------------------------------------------
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Hitag2 Crypto
//
// (c) 2009 Henryk Plötz <henryk@ploetzli.ch>
// (c) 2012 Roel Verdult
// (c) 2019 Iceman
//-----------------------------------------------------------------------------
#include "hitag2_crypto.h"
/* Following is a modified version of cryptolib.com/ciphers/hitag2/ */
// Software optimized 48-bit Philips/NXP Mifare Hitag2 PCF7936/46/47/52 stream cipher algorithm by I.C. Wiener 2006-2007.
// For educational purposes only.
// No warranties or guarantees of any kind.
// This code is released into the public domain by its author.
// Single bit Hitag2 functions:
#ifndef i4
#define i4(x,a,b,c,d) ((uint32_t)((((x)>>(a))&1)+(((x)>>(b))&1)*2+(((x)>>(c))&1)*4+(((x)>>(d))&1)*8))
#endif
static const uint32_t ht2_f4a = 0x2C79; // 0010 1100 0111 1001
static const uint32_t ht2_f4b = 0x6671; // 0110 0110 0111 0001
static const uint32_t ht2_f5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011
uint32_t _f20(const uint64_t x) {
uint32_t i5;
i5 = ((ht2_f4a >> i4(x, 1, 2, 4, 5)) & 1) * 1
+ ((ht2_f4b >> i4(x, 7, 11, 13, 14)) & 1) * 2
+ ((ht2_f4b >> i4(x, 16, 20, 22, 25)) & 1) * 4
+ ((ht2_f4b >> i4(x, 27, 28, 30, 32)) & 1) * 8
+ ((ht2_f4a >> i4(x, 33, 42, 43, 45)) & 1) * 16;
return (ht2_f5c >> i5) & 1;
}
uint64_t _hitag2_init(const uint64_t key, const uint32_t serial, const uint32_t IV) {
uint32_t i;
uint64_t x = ((key & 0xFFFF) << 32) + serial;
for (i = 0; i < 32; i++) {
x >>= 1;
x += (uint64_t)(_f20(x) ^ (((IV >> i) ^ (key >> (i + 16))) & 1)) << 47;
}
return x;
}
uint64_t _hitag2_round(uint64_t *state) {
uint64_t x = *state;
x = (x >> 1) +
((((x >> 0) ^ (x >> 2) ^ (x >> 3) ^ (x >> 6)
^ (x >> 7) ^ (x >> 8) ^ (x >> 16) ^ (x >> 22)
^ (x >> 23) ^ (x >> 26) ^ (x >> 30) ^ (x >> 41)
^ (x >> 42) ^ (x >> 43) ^ (x >> 46) ^ (x >> 47)) & 1) << 47);
*state = x;
return _f20(x);
}
// "MIKRON" = O N M I K R
// Key = 4F 4E 4D 49 4B 52 - Secret 48-bit key
// Serial = 49 43 57 69 - Serial number of the tag, transmitted in clear
// Random = 65 6E 45 72 - Random IV, transmitted in clear
//~28~DC~80~31 = D7 23 7F CE - Authenticator value = inverted first 4 bytes of the keystream
// The code below must print out "D7 23 7F CE 8C D0 37 A9 57 49 C1 E6 48 00 8A B6".
// The inverse of the first 4 bytes is sent to the tag to authenticate.
// The rest is encrypted by XORing it with the subsequent keystream.
uint32_t _hitag2_byte(uint64_t *x) {
uint32_t i, c;
for (i = 0, c = 0; i < 8; i++) {
c += (uint32_t) _hitag2_round(x) << (i ^ 7);
}
return c;
}
void hitag2_cipher_reset(struct hitag2_tag *tag, const uint8_t *iv) {
uint64_t key = ((uint64_t)tag->sectors[2][2]) |
((uint64_t)tag->sectors[2][3] << 8) |
((uint64_t)tag->sectors[1][0] << 16) |
((uint64_t)tag->sectors[1][1] << 24) |
((uint64_t)tag->sectors[1][2] << 32) |
((uint64_t)tag->sectors[1][3] << 40);
uint32_t uid = ((uint32_t)tag->sectors[0][0]) |
((uint32_t)tag->sectors[0][1] << 8) |
((uint32_t)tag->sectors[0][2] << 16) |
((uint32_t)tag->sectors[0][3] << 24);
uint32_t iv_ = (((uint32_t)(iv[0]))) |
(((uint32_t)(iv[1])) << 8) |
(((uint32_t)(iv[2])) << 16) |
(((uint32_t)(iv[3])) << 24);
tag->cs = _hitag2_init(REV64(key), REV32(uid), REV32(iv_));
}
int hitag2_cipher_authenticate(uint64_t *cs, const uint8_t *authenticator_is) {
uint8_t authenticator_should[4];
authenticator_should[0] = ~_hitag2_byte(cs);
authenticator_should[1] = ~_hitag2_byte(cs);
authenticator_should[2] = ~_hitag2_byte(cs);
authenticator_should[3] = ~_hitag2_byte(cs);
return (memcmp(authenticator_should, authenticator_is, 4) == 0);
}
int hitag2_cipher_transcrypt(uint64_t *cs, uint8_t *data, uint16_t bytes, uint16_t bits) {
int i;
for (i = 0; i < bytes; i++) data[i] ^= _hitag2_byte(cs);
for (i = 0; i < bits; i++) data[bytes] ^= _hitag2_round(cs) << (7 - i);
return 0;
}

36
armsrc/hitag2_crypto.h Normal file
View file

@ -0,0 +1,36 @@
#ifndef __HITAG2_CRYPTO_H
#define __HITAG2_CRYPTO_H
#ifdef __cplusplus
extern "C" {
#endif
#include "string.h"
#include "util.h"
struct hitag2_tag {
uint32_t uid;
enum {
TAG_STATE_RESET = 0x01, // Just powered up, awaiting GetSnr
TAG_STATE_ACTIVATING = 0x02, // In activation phase (password mode), sent UID, awaiting reader password
TAG_STATE_ACTIVATED = 0x03, // Activation complete, awaiting read/write commands
TAG_STATE_WRITING = 0x04, // In write command, awaiting sector contents to be written
} state;
uint16_t active_sector;
uint8_t crypto_active;
uint64_t cs;
uint8_t sectors[12][4];
};
uint32_t _f20(const uint64_t x);
uint64_t _hitag2_init(const uint64_t key, const uint32_t serial, const uint32_t IV);
uint64_t _hitag2_round(uint64_t *state);
uint32_t _hitag2_byte(uint64_t *x);
void hitag2_cipher_reset(struct hitag2_tag *tag, const uint8_t *iv);
int hitag2_cipher_authenticate(uint64_t *cs, const uint8_t *authenticator_is);
int hitag2_cipher_transcrypt(uint64_t *cs, uint8_t *data, uint16_t bytes, uint16_t bits) ;
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load diff

31
armsrc/hitagS.h Normal file
View file

@ -0,0 +1,31 @@
//-----------------------------------------------------------------------------
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// HitagS emulation (preliminary test version)
//
// (c) 2016 Oguzhan Cicek, Hendrik Schwartke, Ralf Spenneberg
// <info@os-s.de>
//-----------------------------------------------------------------------------
#ifndef _HITAGS_H_
#define _HITAGS_H_
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include "hitag2_crypto.h"
#include "hitag.h"
#include "proxmark3.h"
#include "apps.h"
#include "util.h"
#include "string.h"
#include "BigBuf.h"
void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data);
void ReadHitagS(hitag_function htf, hitag_data *htd);
void WritePageHitagS(hitag_function htf, hitag_data *htd, int page);
void check_challenges(bool file_given, uint8_t *data);
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -16,8 +16,8 @@
#ifdef __cplusplus
extern "C" {
#endif
#include "usb_cmd.h"
#include "pm3_cmd.h"
#include "cmd.h"
#include "apps.h"
#include "util.h"
@ -27,115 +27,131 @@ extern "C" {
#include "crapto1/crapto1.h"
#include "mifareutil.h"
#include "parity.h"
#include "random.h"
#include "mifare.h" // structs
// When the PM acts as tag and is receiving it takes
// 2 ticks delay in the RF part (for the first falling edge),
// 3 ticks for the A/D conversion,
// 8 ticks on average until the start of the SSC transfer,
// 8 ticks until the SSC samples the first data
// 7*16 ticks to complete the transfer from FPGA to ARM
// 8 ticks until the next ssp_clk rising edge
// 4*16 ticks until we measure the time
// - 8*16 ticks because we measure the time of the previous transfer
#define DELAY_AIR2ARM_AS_TAG (2 + 3 + 8 + 8 + 7*16 + 8 + 4*16 - 8*16)
typedef struct {
enum {
DEMOD_UNSYNCD,
// DEMOD_HALF_SYNCD,
// DEMOD_MOD_FIRST_HALF,
// DEMOD_NOMOD_FIRST_HALF,
DEMOD_MANCHESTER_DATA
} state;
uint16_t twoBits;
uint16_t highCnt;
uint16_t bitCount;
uint16_t collisionPos;
uint16_t syncBit;
uint8_t parityBits;
uint8_t parityLen;
uint16_t shiftReg;
uint16_t samples;
uint16_t len;
uint32_t startTime, endTime;
uint8_t *output;
uint8_t *parity;
enum {
DEMOD_UNSYNCD,
// DEMOD_HALF_SYNCD,
// DEMOD_MOD_FIRST_HALF,
// DEMOD_NOMOD_FIRST_HALF,
DEMOD_MANCHESTER_DATA
} state;
uint16_t twoBits;
uint16_t highCnt;
uint16_t bitCount;
uint16_t collisionPos;
uint16_t syncBit;
uint8_t parityBits;
uint8_t parityLen;
uint16_t shiftReg;
uint16_t samples;
uint16_t len;
uint32_t startTime, endTime;
uint8_t *output;
uint8_t *parity;
} tDemod;
/*
typedef enum {
MOD_NOMOD = 0,
MOD_SECOND_HALF,
MOD_FIRST_HALF,
MOD_BOTH_HALVES
} Modulation_t;
MOD_NOMOD = 0,
MOD_SECOND_HALF,
MOD_FIRST_HALF,
MOD_BOTH_HALVES
} Modulation_t;
*/
typedef struct {
enum {
STATE_UNSYNCD,
STATE_START_OF_COMMUNICATION,
STATE_MILLER_X,
STATE_MILLER_Y,
STATE_MILLER_Z,
// DROP_NONE,
// DROP_FIRST_HALF,
} state;
uint16_t shiftReg;
int16_t bitCount;
uint16_t len;
//uint16_t byteCntMax;
uint16_t posCnt;
uint16_t syncBit;
uint8_t parityBits;
uint8_t parityLen;
uint32_t fourBits;
uint32_t startTime, endTime;
enum {
STATE_UNSYNCD,
STATE_START_OF_COMMUNICATION,
STATE_MILLER_X,
STATE_MILLER_Y,
STATE_MILLER_Z,
// DROP_NONE,
// DROP_FIRST_HALF,
} state;
uint16_t shiftReg;
int16_t bitCount;
uint16_t len;
//uint16_t byteCntMax;
uint16_t posCnt;
uint16_t syncBit;
uint8_t parityBits;
uint8_t parityLen;
uint32_t fourBits;
uint32_t startTime, endTime;
uint8_t *output;
uint8_t *parity;
uint8_t *parity;
} tUart;
#ifndef AddCrc14A
# define AddCrc14A(data, len) compute_crc(CRC_14443_A, (data), (len), (data)+(len), (data)+(len)+1)
# define AddCrc14A(data, len) compute_crc(CRC_14443_A, (data), (len), (data)+(len), (data)+(len)+1)
#endif
#ifndef AddCrc14B
# define AddCrc14B(data, len) compute_crc(CRC_14443_B, (data), (len), (data)+(len), (data)+(len)+1)
# define AddCrc14B(data, len) compute_crc(CRC_14443_B, (data), (len), (data)+(len), (data)+(len)+1)
#endif
extern void GetParity(const uint8_t *pbtCmd, uint16_t len, uint8_t *par);
#ifndef CheckCrc14A
# define CheckCrc14A(data, len) check_crc(CRC_14443_A, (data), (len))
#endif
extern tDemod* GetDemod(void);
extern void DemodReset(void);
extern void DemodInit(uint8_t *data, uint8_t *parity);
extern tUart* GetUart(void);
extern void UartReset(void);
extern void UartInit(uint8_t *data, uint8_t *parity);
extern RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time);
extern RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non_real_time);
void GetParity(const uint8_t *pbtCmd, uint16_t len, uint8_t *par);
extern void RAMFUNC SniffIso14443a(uint8_t param);
extern void SimulateIso14443aTag(int tagType, int flags, uint8_t *data);
extern void iso14443a_antifuzz(uint32_t flags);
extern void ReaderIso14443a(UsbCommand *c);
extern void ReaderTransmit(uint8_t *frame, uint16_t len, uint32_t *timing);
extern void ReaderTransmitBitsPar(uint8_t *frame, uint16_t bits, uint8_t *par, uint32_t *timing);
extern void ReaderTransmitPar(uint8_t *frame, uint16_t len, uint8_t *par, uint32_t *timing);
extern int ReaderReceive(uint8_t *receivedAnswer, uint8_t *par);
tDemod *GetDemod(void);
void DemodReset(void);
void DemodInit(uint8_t *data, uint8_t *par);
tUart *GetUart(void);
void UartReset(void);
void UartInit(uint8_t *data, uint8_t *par);
RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time);
RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non_real_time);
extern void iso14443a_setup(uint8_t fpga_minor_mode);
extern int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data);
extern int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *resp_data, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats);
extern int iso14443a_fast_select_card(uint8_t *uid_ptr, uint8_t num_cascades);
extern void iso14a_set_trigger(bool enable);
void RAMFUNC SniffIso14443a(uint8_t param);
void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data);
void iso14443a_antifuzz(uint32_t flags);
void ReaderIso14443a(PacketCommandNG *c);
void ReaderTransmit(uint8_t *frame, uint16_t len, uint32_t *timing);
void ReaderTransmitBitsPar(uint8_t *frame, uint16_t bits, uint8_t *par, uint32_t *timing);
void ReaderTransmitPar(uint8_t *frame, uint16_t len, uint8_t *par, uint32_t *timing);
int ReaderReceive(uint8_t *receivedAnswer, uint8_t *par);
extern int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen);
extern int EmSend4bit(uint8_t resp);
extern int EmSendCmd(uint8_t *resp, uint16_t respLen);
extern int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *parity);
extern int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par);
extern int EmSendPrecompiledCmd(tag_response_info_t *response_info);
void iso14443a_setup(uint8_t fpga_minor_mode);
int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, uint8_t *res);
int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats);
int iso14443a_fast_select_card(uint8_t *uid_ptr, uint8_t num_cascades);
void iso14a_set_trigger(bool enable);
int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen);
int EmSend4bit(uint8_t resp);
int EmSendCmd(uint8_t *resp, uint16_t respLen);
int EmSendCmdEx(uint8_t *resp, uint16_t respLen, bool collision);
int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *par);
int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par);
int EmSendCmdParEx(uint8_t *resp, uint16_t respLen, uint8_t *par, bool collision);
int EmSendPrecompiledCmd(tag_response_info_t *p_response);
bool prepare_allocated_tag_modulation(tag_response_info_t *response_info, uint8_t **buffer, size_t *max_buffer_size);
bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_StartTime, uint32_t reader_EndTime, uint8_t *reader_Parity,
uint8_t *tag_data, uint16_t tag_len, uint32_t tag_StartTime, uint32_t tag_EndTime, uint8_t *tag_Parity);
uint8_t *tag_data, uint16_t tag_len, uint32_t tag_StartTime, uint32_t tag_EndTime, uint8_t *tag_Parity);
//extern bool prepare_allocated_tag_modulation(tag_response_info_t *response_info, uint8_t **buffer, size_t *buffer_size);
void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype );
void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype);
void DetectNACKbug();
#ifdef __cplusplus
}
#endif
#endif
#endif /* __ISO14443A_H */

File diff suppressed because it is too large Load diff

View file

@ -18,7 +18,7 @@ extern "C" {
#endif
#include "proxmark3.h"
#include "common.h" // access to global variable: MF_DBGLEVEL
#include "common.h" // access to global variable: DBGLEVEL
#include "apps.h"
#include "util.h"
#include "string.h"
@ -27,31 +27,31 @@ extern "C" {
#include "protocols.h"
#ifndef AddCrc14A
# define AddCrc14A(data, len) compute_crc(CRC_14443_A, (data), (len), (data)+(len), (data)+(len)+1)
# define AddCrc14A(data, len) compute_crc(CRC_14443_A, (data), (len), (data)+(len), (data)+(len)+1)
#endif
#ifndef AddCrc14B
# define AddCrc14B(data, len) compute_crc(CRC_14443_B, (data), (len), (data)+(len), (data)+(len)+1)
# define AddCrc14B(data, len) compute_crc(CRC_14443_B, (data), (len), (data)+(len), (data)+(len)+1)
#endif
extern void SendRawCommand14443B_Ex(UsbCommand *c);
extern void iso14443b_setup();
extern uint8_t iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response);
extern uint8_t iso14443b_select_card(iso14b_card_select_t* card);
extern uint8_t iso14443b_select_card_srx(iso14b_card_select_t* card);
void SendRawCommand14443B_Ex(PacketCommandNG *c);
void iso14443b_setup();
uint8_t iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response);
uint8_t iso14443b_select_card(iso14b_card_select_t *card);
uint8_t iso14443b_select_card_srx(iso14b_card_select_t *card);
// testfunctions
extern void WaitForFpgaDelayQueueIsEmpty( uint16_t delay );
extern void ClearFpgaShiftingRegisters(void);
void WaitForFpgaDelayQueueIsEmpty(uint16_t delay);
void ClearFpgaShiftingRegisters(void);
// States for 14B SIM command
#define SIM_NOFIELD 0
#define SIM_IDLE 1
#define SIM_HALTED 2
#define SIM_SELECTING 3
#define SIM_HALTING 4
#define SIM_NOFIELD 0
#define SIM_IDLE 1
#define SIM_HALTED 2
#define SIM_SELECTING 3
#define SIM_HALTING 4
#define SIM_ACKNOWLEDGE 5
#define SIM_WORK 6
#define SIM_WORK 6
#ifdef __cplusplus
}

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
//-----------------------------------------------------------------------------
// (c) 2009 Henryk Plötz <henryk@ploetzli.ch>
// 2016 Iceman
// 2018 AntiCat (rwd rewritten)
// 2018 AntiCat
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
@ -16,7 +16,7 @@
#include "legic_prng.h" /* legic PRNG impl */
#include "legic.h" /* legic_card_select_t struct */
static uint8_t* legic_mem; /* card memory, used for read, write and sim */
static uint8_t *legic_mem; /* card memory, used for read, write */
static legic_card_select_t card;/* metadata of currently selected card */
static crc_t legic_crc;
@ -50,21 +50,21 @@ static uint32_t last_frame_end; /* ts of last bit of previews rx or tx frame */
#define WRITE_LOWERLIMIT 4 /* UID and MCC are not writable */
#define INPUT_THRESHOLD 8 /* heuristically determined, lower values */
/* lead to detecting false ack during write */
/* lead to detecting false ack during write */
//-----------------------------------------------------------------------------
// I/O interface abstraction (FPGA -> ARM)
//-----------------------------------------------------------------------------
static inline uint8_t rx_byte_from_fpga() {
for(;;) {
WDT_HIT();
for (;;) {
WDT_HIT();
// wait for byte be become available in rx holding register
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
return AT91C_BASE_SSC->SSC_RHR;
// wait for byte be become available in rx holding register
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
return AT91C_BASE_SSC->SSC_RHR;
}
}
}
}
//-----------------------------------------------------------------------------
@ -81,13 +81,15 @@ static inline uint8_t rx_byte_from_fpga() {
// To reduce CPU time the amplitude is approximated by using linear functions:
// am = MAX(ABS(i),ABS(q)) + 1/2*MIN(ABS(i),ABSq))
//
// Note: The SSC receiver is never synchronized the calculation my be performed
// Note: The SSC receiver is never synchronized the calculation may be performed
// on a i/q pair from two subsequent correlations, but does not matter.
static inline int32_t sample_power() {
int32_t q = (int8_t)rx_byte_from_fpga(); q = ABS(q);
int32_t i = (int8_t)rx_byte_from_fpga(); i = ABS(i);
int32_t q = (int8_t)rx_byte_from_fpga();
q = ABS(q);
int32_t i = (int8_t)rx_byte_from_fpga();
i = ABS(i);
return MAX(i, q) + (MIN(i, q) >> 1);
return MAX(i, q) + (MIN(i, q) >> 1);
}
// Returns a demedulated bit
@ -98,13 +100,13 @@ static inline int32_t sample_power() {
// Note: The demodulator would be drifting (18.9us * 5 != 100us), rx_frame
// has a delay loop that aligns rx_bit calls to the TAG tx timeslots.
static inline bool rx_bit() {
int32_t power;
int32_t power;
for(size_t i = 0; i<5; ++i) {
power = sample_power();
}
for (size_t i = 0; i < 5; ++i) {
power = sample_power();
}
return (power > INPUT_THRESHOLD);
return (power > INPUT_THRESHOLD);
}
//-----------------------------------------------------------------------------
@ -117,15 +119,15 @@ static inline bool rx_bit() {
//-----------------------------------------------------------------------------
static inline void tx_bit(bool bit) {
// insert pause
LOW(GPIO_SSC_DOUT);
last_frame_end += RWD_TIME_PAUSE;
while(GET_TICKS < last_frame_end) { };
HIGH(GPIO_SSC_DOUT);
// insert pause
LOW(GPIO_SSC_DOUT);
last_frame_end += RWD_TIME_PAUSE;
while (GET_TICKS < last_frame_end) { };
HIGH(GPIO_SSC_DOUT);
// return to high, wait for bit periode to end
last_frame_end += (bit ? RWD_TIME_1 : RWD_TIME_0) - RWD_TIME_PAUSE;
while(GET_TICKS < last_frame_end) { };
// return to high, wait for bit periode to end
last_frame_end += (bit ? RWD_TIME_1 : RWD_TIME_0) - RWD_TIME_PAUSE;
while (GET_TICKS < last_frame_end) { };
}
//-----------------------------------------------------------------------------
@ -139,162 +141,162 @@ static inline void tx_bit(bool bit) {
//-----------------------------------------------------------------------------
static void tx_frame(uint32_t frame, uint8_t len) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX);
// wait for next tx timeslot
last_frame_end += RWD_FRAME_WAIT;
while(GET_TICKS < last_frame_end) { };
// wait for next tx timeslot
last_frame_end += RWD_FRAME_WAIT;
while (GET_TICKS < last_frame_end) { };
// backup ts for trace log
uint32_t last_frame_start = last_frame_end;
// backup ts for trace log
uint32_t last_frame_start = last_frame_end;
// transmit frame, MSB first
for(uint8_t i = 0; i < len; ++i) {
bool bit = (frame >> i) & 0x01;
tx_bit(bit ^ legic_prng_get_bit());
legic_prng_forward(1);
};
// transmit frame, MSB first
for (uint8_t i = 0; i < len; ++i) {
bool bit = (frame >> i) & 0x01;
tx_bit(bit ^ legic_prng_get_bit());
legic_prng_forward(1);
};
// add pause to mark end of the frame
LOW(GPIO_SSC_DOUT);
last_frame_end += RWD_TIME_PAUSE;
while(GET_TICKS < last_frame_end) { };
HIGH(GPIO_SSC_DOUT);
// add pause to mark end of the frame
LOW(GPIO_SSC_DOUT);
last_frame_end += RWD_TIME_PAUSE;
while (GET_TICKS < last_frame_end) { };
HIGH(GPIO_SSC_DOUT);
// log
uint8_t cmdbytes[] = {len, BYTEx(frame, 0), BYTEx(frame, 1), BYTEx(frame, 2)};
LogTrace(cmdbytes, sizeof(cmdbytes), last_frame_start, last_frame_end, NULL, true);
// log
uint8_t cmdbytes[] = {len, BYTEx(frame, 0), BYTEx(frame, 1), BYTEx(frame, 2)};
LogTrace(cmdbytes, sizeof(cmdbytes), last_frame_start, last_frame_end, NULL, true);
}
static uint32_t rx_frame(uint8_t len) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR
| FPGA_HF_READER_RX_XCORR_848_KHZ
| FPGA_HF_READER_RX_XCORR_QUARTER);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR
| FPGA_HF_READER_RX_XCORR_848_KHZ
| FPGA_HF_READER_RX_XCORR_QUARTER);
// hold sampling until card is expected to respond
last_frame_end += TAG_FRAME_WAIT;
while(GET_TICKS < last_frame_end) { };
// hold sampling until card is expected to respond
last_frame_end += TAG_FRAME_WAIT;
while (GET_TICKS < last_frame_end) { };
// backup ts for trace log
uint32_t last_frame_start = last_frame_end;
// backup ts for trace log
uint32_t last_frame_start = last_frame_end;
uint32_t frame = 0;
for(uint8_t i = 0; i < len; i++) {
frame |= (rx_bit() ^ legic_prng_get_bit()) << i;
legic_prng_forward(1);
uint32_t frame = 0;
for (uint8_t i = 0; i < len; ++i) {
frame |= (rx_bit() ^ legic_prng_get_bit()) << i;
legic_prng_forward(1);
// rx_bit runs only 95us, resync to TAG_BIT_PERIOD
last_frame_end += TAG_BIT_PERIOD;
while(GET_TICKS < last_frame_end) { };
}
// rx_bit runs only 95us, resync to TAG_BIT_PERIOD
last_frame_end += TAG_BIT_PERIOD;
while (GET_TICKS < last_frame_end) { };
}
// log
uint8_t cmdbytes[] = {len, BYTEx(frame, 0), BYTEx(frame, 1)};
LogTrace(cmdbytes, sizeof(cmdbytes), last_frame_start, last_frame_end, NULL, false);
// log
uint8_t cmdbytes[] = {len, BYTEx(frame, 0), BYTEx(frame, 1)};
LogTrace(cmdbytes, sizeof(cmdbytes), last_frame_start, last_frame_end, NULL, false);
return frame;
return frame;
}
static bool rx_ack() {
// change fpga into rx mode
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR
| FPGA_HF_READER_RX_XCORR_848_KHZ
| FPGA_HF_READER_RX_XCORR_QUARTER);
// change fpga into rx mode
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR
| FPGA_HF_READER_RX_XCORR_848_KHZ
| FPGA_HF_READER_RX_XCORR_QUARTER);
// hold sampling until card is expected to respond
last_frame_end += TAG_FRAME_WAIT;
while(GET_TICKS < last_frame_end) { };
// hold sampling until card is expected to respond
last_frame_end += TAG_FRAME_WAIT;
while (GET_TICKS < last_frame_end) { };
// backup ts for trace log
uint32_t last_frame_start = last_frame_end;
// backup ts for trace log
uint32_t last_frame_start = last_frame_end;
uint32_t ack = 0;
for(uint8_t i = 0; i < TAG_WRITE_TIMEOUT; ++i) {
// sample bit
ack = rx_bit();
legic_prng_forward(1);
uint32_t ack = 0;
for (uint8_t i = 0; i < TAG_WRITE_TIMEOUT; ++i) {
// sample bit
ack = rx_bit();
legic_prng_forward(1);
// rx_bit runs only 95us, resync to TAG_BIT_PERIOD
last_frame_end += TAG_BIT_PERIOD;
while(GET_TICKS < last_frame_end) { };
// rx_bit runs only 95us, resync to TAG_BIT_PERIOD
last_frame_end += TAG_BIT_PERIOD;
while (GET_TICKS < last_frame_end) { };
// check if it was an ACK
if(ack) {
break;
// check if it was an ACK
if (ack) {
break;
}
}
}
// log
uint8_t cmdbytes[] = {1, BYTEx(ack, 0)};
LogTrace(cmdbytes, sizeof(cmdbytes), last_frame_start, last_frame_end, NULL, false);
// log
uint8_t cmdbytes[] = {1, BYTEx(ack, 0)};
LogTrace(cmdbytes, sizeof(cmdbytes), last_frame_start, last_frame_end, NULL, false);
return ack;
return ack;
}
//-----------------------------------------------------------------------------
// Legic Reader
//-----------------------------------------------------------------------------
int init_card(uint8_t cardtype, legic_card_select_t *p_card) {
p_card->tagtype = cardtype;
static int init_card(uint8_t cardtype, legic_card_select_t *p_card) {
p_card->tagtype = cardtype;
switch(p_card->tagtype) {
case 0x0d:
p_card->cmdsize = 6;
p_card->addrsize = 5;
p_card->cardsize = 22;
break;
case 0x1d:
p_card->cmdsize = 9;
p_card->addrsize = 8;
p_card->cardsize = 256;
break;
case 0x3d:
p_card->cmdsize = 11;
p_card->addrsize = 10;
p_card->cardsize = 1024;
break;
default:
p_card->cmdsize = 0;
p_card->addrsize = 0;
p_card->cardsize = 0;
return 2;
}
return 0;
switch (p_card->tagtype) {
case 0x0d:
p_card->cmdsize = 6;
p_card->addrsize = 5;
p_card->cardsize = 22;
break;
case 0x1d:
p_card->cmdsize = 9;
p_card->addrsize = 8;
p_card->cardsize = 256;
break;
case 0x3d:
p_card->cmdsize = 11;
p_card->addrsize = 10;
p_card->cardsize = 1024;
break;
default:
p_card->cmdsize = 0;
p_card->addrsize = 0;
p_card->cardsize = 0;
return 2;
}
return 0;
}
static void init_reader(bool clear_mem) {
// configure FPGA
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR
| FPGA_HF_READER_RX_XCORR_848_KHZ
| FPGA_HF_READER_RX_XCORR_QUARTER);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
LED_A_ON();
// configure FPGA
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR
| FPGA_HF_READER_RX_XCORR_848_KHZ
| FPGA_HF_READER_RX_XCORR_QUARTER);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
LED_A_ON();
// configure SSC with defaults
FpgaSetupSsc();
// configure SSC with defaults
FpgaSetupSsc();
// re-claim GPIO_SSC_DOUT as GPIO and enable output
AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT;
HIGH(GPIO_SSC_DOUT);
// re-claim GPIO_SSC_DOUT as GPIO and enable output
AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT;
HIGH(GPIO_SSC_DOUT);
// reserve a cardmem, meaning we can use the tracelog function in bigbuff easier.
legic_mem = BigBuf_get_EM_addr();
if(legic_mem) {
memset(legic_mem, 0x00, LEGIC_CARD_MEMSIZE);
}
// reserve a cardmem, meaning we can use the tracelog function in bigbuff easier.
legic_mem = BigBuf_get_EM_addr();
if (legic_mem) {
memset(legic_mem, 0x00, LEGIC_CARD_MEMSIZE);
}
// start trace
clear_trace();
set_tracing(true);
// start trace
clear_trace();
set_tracing(true);
// init crc calculator
crc_init(&legic_crc, 4, 0x19 >> 1, 0x05, 0);
// init crc calculator
crc_init(&legic_crc, 4, 0x19 >> 1, 0x05, 0);
// start us timer
StartTicks();
// start us timer
StartTicks();
}
// Setup reader to card connection
@ -302,90 +304,90 @@ static void init_reader(bool clear_mem) {
// The setup consists of a three way handshake:
// - Transmit initialisation vector 7 bits
// - Receive card type 6 bits
// - Acknowledge frame 6 bits
static uint32_t setup_phase_reader(uint8_t iv) {
// init coordination timestamp
last_frame_end = GET_TICKS;
// - Transmit Acknowledge 6 bits
static uint32_t setup_phase(uint8_t iv) {
// init coordination timestamp
last_frame_end = GET_TICKS;
// Switch on carrier and let the card charge for 5ms.
last_frame_end += 7500;
while(GET_TICKS < last_frame_end) { };
// Switch on carrier and let the card charge for 5ms.
last_frame_end += 7500;
while (GET_TICKS < last_frame_end) { };
legic_prng_init(0);
tx_frame(iv, 7);
legic_prng_init(0);
tx_frame(iv, 7);
// configure iv
legic_prng_init(iv);
legic_prng_forward(2);
// configure prng
legic_prng_init(iv);
legic_prng_forward(2);
// receive card type
int32_t card_type = rx_frame(6);
legic_prng_forward(3);
// receive card type
int32_t card_type = rx_frame(6);
legic_prng_forward(3);
// send obsfuscated acknowledgment frame
switch (card_type) {
case 0x0D:
tx_frame(0x19, 6); // MIM22 | READCMD = 0x18 | 0x01
break;
case 0x1D:
case 0x3D:
tx_frame(0x39, 6); // MIM256 | READCMD = 0x38 | 0x01
break;
}
// send obsfuscated acknowledgment frame
switch (card_type) {
case 0x0D:
tx_frame(0x19, 6); // MIM22 | READCMD = 0x18 | 0x01
break;
case 0x1D:
case 0x3D:
tx_frame(0x39, 6); // MIM256 | READCMD = 0x38 | 0x01
break;
}
return card_type;
return card_type;
}
static uint8_t calc_crc4(uint16_t cmd, uint8_t cmd_sz, uint8_t value) {
crc_clear(&legic_crc);
crc_update(&legic_crc, (value << cmd_sz) | cmd, 8 + cmd_sz);
return crc_finish(&legic_crc);
crc_clear(&legic_crc);
crc_update(&legic_crc, (value << cmd_sz) | cmd, 8 + cmd_sz);
return crc_finish(&legic_crc);
}
static int16_t read_byte(uint16_t index, uint8_t cmd_sz) {
uint16_t cmd = (index << 1) | LEGIC_READ;
uint16_t cmd = (index << 1) | LEGIC_READ;
// read one byte
LED_B_ON();
legic_prng_forward(2);
tx_frame(cmd, cmd_sz);
legic_prng_forward(2);
uint32_t frame = rx_frame(12);
LED_B_OFF();
// read one byte
LED_B_ON();
legic_prng_forward(2);
tx_frame(cmd, cmd_sz);
legic_prng_forward(2);
uint32_t frame = rx_frame(12);
LED_B_OFF();
// split frame into data and crc
uint8_t byte = BYTEx(frame, 0);
uint8_t crc = BYTEx(frame, 1);
// split frame into data and crc
uint8_t byte = BYTEx(frame, 0);
uint8_t crc = BYTEx(frame, 1);
// check received against calculated crc
uint8_t calc_crc = calc_crc4(cmd, cmd_sz, byte);
if(calc_crc != crc) {
Dbprintf("!!! crc mismatch: %x != %x !!!", calc_crc, crc);
return -1;
}
// check received against calculated crc
uint8_t calc_crc = calc_crc4(cmd, cmd_sz, byte);
if (calc_crc != crc) {
Dbprintf("!!! crc mismatch: %x != %x !!!", calc_crc, crc);
return -1;
}
legic_prng_forward(1);
legic_prng_forward(1);
return byte;
return byte;
}
// Transmit write command, wait until (3.6ms) the tag sends back an unencrypted
// ACK ('1' bit) and forward the prng time based.
bool write_byte(uint16_t index, uint8_t byte, uint8_t addr_sz) {
uint32_t cmd = index << 1 | LEGIC_WRITE; // prepare command
uint8_t crc = calc_crc4(cmd, addr_sz + 1, byte); // calculate crc
cmd |= byte << (addr_sz + 1); // append value
cmd |= (crc & 0xF) << (addr_sz + 1 + 8); // and crc
uint32_t cmd = index << 1 | LEGIC_WRITE; // prepare command
uint8_t crc = calc_crc4(cmd, addr_sz + 1, byte); // calculate crc
cmd |= byte << (addr_sz + 1); // append value
cmd |= (crc & 0xF) << (addr_sz + 1 + 8); // and crc
// send write command
LED_C_ON();
legic_prng_forward(2);
tx_frame(cmd, addr_sz + 1 + 8 + 4); // cmd_sz = addr_sz + cmd + data + crc
legic_prng_forward(3);
LED_C_OFF();
// send write command
LED_C_ON();
legic_prng_forward(2);
tx_frame(cmd, addr_sz + 1 + 8 + 4); // cmd_sz = addr_sz + cmd + data + crc
legic_prng_forward(3);
LED_C_OFF();
// wait for ack
return rx_ack();
// wait for ack
return rx_ack();
}
//-----------------------------------------------------------------------------
@ -394,114 +396,110 @@ bool write_byte(uint16_t index, uint8_t byte, uint8_t addr_sz) {
// Only this functions are public / called from appmain.c
//-----------------------------------------------------------------------------
void LegicRfInfo(void) {
// configure ARM and FPGA
init_reader(false);
// configure ARM and FPGA
init_reader(false);
// establish shared secret and detect card type
uint8_t card_type = setup_phase_reader(0x01);
if(init_card(card_type, &card) != 0) {
cmd_send(CMD_ACK, 0, 0, 0, 0, 0);
goto OUT;
}
// read UID
for(uint8_t i = 0; i < sizeof(card.uid); ++i) {
int16_t byte = read_byte(i, card.cmdsize);
if(byte == -1) {
cmd_send(CMD_ACK, 0, 0, 0, 0, 0);
goto OUT;
// establish shared secret and detect card type
uint8_t card_type = setup_phase(0x01);
if (init_card(card_type, &card) != 0) {
reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
goto OUT;
}
card.uid[i] = byte & 0xFF;
}
// read MCC and check against UID
int16_t mcc = read_byte(4, card.cmdsize);
int16_t calc_mcc = CRC8Legic(card.uid, 4);;
if(mcc != calc_mcc) {
cmd_send(CMD_ACK, 0, 0, 0, 0, 0);
goto OUT;
}
// read UID
for (uint8_t i = 0; i < sizeof(card.uid); ++i) {
int16_t byte = read_byte(i, card.cmdsize);
if (byte == -1) {
reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
goto OUT;
}
card.uid[i] = byte & 0xFF;
}
// OK
cmd_send(CMD_ACK, 1, 0, 0, (uint8_t*)&card, sizeof(legic_card_select_t));
// read MCC and check against UID
int16_t mcc = read_byte(4, card.cmdsize);
int16_t calc_mcc = CRC8Legic(card.uid, 4);;
if (mcc != calc_mcc) {
reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
goto OUT;
}
// OK
reply_old(CMD_ACK, 1, 0, 0, (uint8_t *)&card, sizeof(legic_card_select_t));
OUT:
switch_off();
StopTicks();
switch_off();
StopTicks();
}
void LegicRfReader(uint16_t offset, uint16_t len, uint8_t iv) {
// configure ARM and FPGA
init_reader(false);
// configure ARM and FPGA
init_reader(false);
// establish shared secret and detect card type
uint8_t card_type = setup_phase_reader(iv);
if(init_card(card_type, &card) != 0) {
cmd_send(CMD_ACK, 0, 0, 0, 0, 0);
goto OUT;
}
// do not read beyond card memory
if(len + offset > card.cardsize) {
len = card.cardsize - offset;
}
for(uint16_t i = 0; i < len; ++i) {
int16_t byte = read_byte(offset + i, card.cmdsize);
if(byte == -1) {
cmd_send(CMD_ACK, 0, 0, 0, 0, 0);
goto OUT;
// establish shared secret and detect card type
uint8_t card_type = setup_phase(iv);
if (init_card(card_type, &card) != 0) {
reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
goto OUT;
}
legic_mem[i] = byte;
}
// OK
cmd_send(CMD_ACK, 1, len, 0, legic_mem, len);
// do not read beyond card memory
if (len + offset > card.cardsize) {
len = card.cardsize - offset;
}
for (uint16_t i = 0; i < len; ++i) {
int16_t byte = read_byte(offset + i, card.cmdsize);
if (byte == -1) {
reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
goto OUT;
}
legic_mem[i] = byte;
}
// OK
reply_old(CMD_ACK, 1, len, 0, legic_mem, len);
OUT:
switch_off();
StopTicks();
switch_off();
StopTicks();
}
void LegicRfWriter(uint16_t offset, uint16_t len, uint8_t iv, uint8_t *data) {
// configure ARM and FPGA
init_reader(false);
// configure ARM and FPGA
init_reader(false);
// uid is not writeable
if(offset <= WRITE_LOWERLIMIT) {
cmd_send(CMD_ACK, 0, 0, 0, 0, 0);
goto OUT;
}
// establish shared secret and detect card type
uint8_t card_type = setup_phase_reader(iv);
if(init_card(card_type, &card) != 0) {
cmd_send(CMD_ACK, 0, 0, 0, 0, 0);
goto OUT;
}
// do not write beyond card memory
if(len + offset > card.cardsize) {
len = card.cardsize - offset;
}
// write in reverse order, only then is DCF (decremental field) writable
while(len-- > 0 && !BUTTON_PRESS()) {
if(!write_byte(len + offset, data[len], card.addrsize)) {
Dbprintf("operation failed | %02X | %02X | %02X", len + offset, len, data[len]);
cmd_send(CMD_ACK, 0, 0, 0, 0, 0);
goto OUT;
// uid is not writeable
if (offset <= WRITE_LOWERLIMIT) {
reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
goto OUT;
}
}
// OK
cmd_send(CMD_ACK, 1, len, 0, legic_mem, len);
// establish shared secret and detect card type
uint8_t card_type = setup_phase(iv);
if (init_card(card_type, &card) != 0) {
reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
goto OUT;
}
// do not write beyond card memory
if (len + offset > card.cardsize) {
len = card.cardsize - offset;
}
// write in reverse order, only then is DCF (decremental field) writable
while (len-- > 0 && !BUTTON_PRESS()) {
if (!write_byte(len + offset, data[len], card.addrsize)) {
Dbprintf("operation failed | %02X | %02X | %02X", len + offset, len, data[len]);
reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
goto OUT;
}
}
// OK
reply_old(CMD_ACK, 1, len, 0, legic_mem, len);
OUT:
switch_off();
StopTicks();
}
void LegicRfSimulate(int phase, int frame, int reqresp) {
cmd_send(CMD_ACK, 0, 0, 0, 0, 0); //TODO Implement
switch_off();
StopTicks();
}

View file

@ -1,5 +1,6 @@
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// (c) 2009 Henryk Plötz <henryk@ploetzli.ch>
// 2018 AntiCat
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
@ -13,9 +14,8 @@
#include "proxmark3.h"
extern void LegicRfInfo(void);
extern void LegicRfReader(uint16_t offset, uint16_t len, uint8_t iv);
extern void LegicRfWriter(uint16_t offset, uint16_t byte, uint8_t iv, uint8_t *data);
extern void LegicRfSimulate(int phase, int frame, int reqresp);
void LegicRfInfo(void);
void LegicRfReader(uint16_t offset, uint16_t len, uint8_t iv);
void LegicRfWriter(uint16_t offset, uint16_t len, uint8_t iv, uint8_t *data);
#endif /* __LEGICRF_H */

485
armsrc/legicrfsim.c Normal file
View file

@ -0,0 +1,485 @@
//-----------------------------------------------------------------------------
// (c) 2009 Henryk Plötz <henryk@ploetzli.ch>
// 2016 Iceman
// 2018 AntiCat
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// LEGIC RF simulation code
//-----------------------------------------------------------------------------
#include "legicrf.h"
#include "ticks.h" /* timers */
#include "crc.h" /* legic crc-4 */
#include "legic_prng.h" /* legic PRNG impl */
#include "legic.h" /* legic_card_select_t struct */
static uint8_t *legic_mem; /* card memory, used for sim */
static legic_card_select_t card;/* metadata of currently selected card */
static crc_t legic_crc;
//-----------------------------------------------------------------------------
// Frame timing and pseudorandom number generator
//
// The Prng is forwarded every 99.1us (TAG_BIT_PERIOD), except when the reader is
// transmitting. In that case the prng has to be forwarded every bit transmitted:
// - 31.3us for a 0 (RWD_TIME_0)
// - 99.1us for a 1 (RWD_TIME_1)
//
// The data dependent timing makes writing comprehensible code significantly
// harder. The current aproach forwards the prng data based if there is data on
// air and time based, using GetCountSspClk(), during computational and wait
// periodes. SSP Clock is clocked by the FPGA at 212 kHz (subcarrier frequency).
//
// To not have the necessity to calculate/guess exection time dependend timeouts
// tx_frame and rx_frame use a shared timestamp to coordinate tx and rx timeslots.
//-----------------------------------------------------------------------------
static uint32_t last_frame_end; /* ts of last bit of previews rx or tx frame */
#define TAG_FRAME_WAIT 70 /* 330us from READER frame end to TAG frame start */
#define TAG_ACK_WAIT 758 /* 3.57ms from READER frame end to TAG write ACK */
#define TAG_BIT_PERIOD 21 /* 99.1us */
#define RWD_TIME_PAUSE 4 /* 18.9us */
#define RWD_TIME_1 21 /* RWD_TIME_PAUSE 18.9us off + 80.2us on = 99.1us */
#define RWD_TIME_0 13 /* RWD_TIME_PAUSE 18.9us off + 42.4us on = 61.3us */
#define RWD_CMD_TIMEOUT 120 /* 120 * 99.1us (arbitrary value) */
#define RWD_MIN_FRAME_LEN 6 /* Shortest frame is 6 bits */
#define RWD_MAX_FRAME_LEN 23 /* Longest frame is 23 bits */
#define RWD_PULSE 1 /* Pulse is signaled with GPIO_SSC_DIN high */
#define RWD_PAUSE 0 /* Pause is signaled with GPIO_SSC_DIN low */
//-----------------------------------------------------------------------------
// Demodulation
//-----------------------------------------------------------------------------
// Returns true if a pulse/pause is received within timeout
static inline bool wait_for(bool value, const uint32_t timeout) {
while ((bool)(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_DIN) != value) {
if (GetCountSspClk() > timeout) {
return false;
}
}
return true;
}
// Returns a demedulated bit or -1 on code violation
//
// rx_bit decodes bits using a thresholds. rx_bit has to be called by as soon as
// a frame starts (first pause is received). rx_bit checks for a pause up to
// 18.9us followed by a pulse of 80.2us or 42.4us:
// - A bit length <18.9us is a code violation
// - A bit length >80.2us is a 1
// - A bit length <80.2us is a 0
// - A bit length >148.6us is a code violation
static inline int8_t rx_bit() {
// backup ts for threshold calculation
uint32_t bit_start = last_frame_end;
// wait for pause to end
if (!wait_for(RWD_PULSE, bit_start + RWD_TIME_1 * 3 / 2)) {
return -1;
}
// wait for next pause
if (!wait_for(RWD_PAUSE, bit_start + RWD_TIME_1 * 3 / 2)) {
return -1;
}
// update bit and frame end
last_frame_end = GetCountSspClk();
// check for code violation (bit to short)
if (last_frame_end - bit_start < RWD_TIME_PAUSE) {
return -1;
}
// apply threshold (average of RWD_TIME_0 and )
return (last_frame_end - bit_start > (RWD_TIME_0 + RWD_TIME_1) / 2);
}
//-----------------------------------------------------------------------------
// Modulation
//
// LEGIC RF uses a very basic load modulation from card to reader:
// - Subcarrier on for a 1
// - Subcarrier off for for a 0
//
// The 212kHz subcarrier is generated by the FPGA as well as a mathcing ssp clk.
// Each bit is transfered in a 99.1us slot and the first timeslot starts 330us
// after the final 20us pause generated by the reader.
//-----------------------------------------------------------------------------
// Transmits a bit
//
// Note: The Subcarrier is not disabled during bits to prevent glitches. This is
// not mandatory but results in a cleaner signal. tx_frame will disable
// the subcarrier when the frame is done.
static inline void tx_bit(bool bit) {
LED_C_ON();
if (bit) {
// modulate subcarrier
HIGH(GPIO_SSC_DOUT);
} else {
// do not modulate subcarrier
LOW(GPIO_SSC_DOUT);
}
// wait for tx timeslot to end
last_frame_end += TAG_BIT_PERIOD;
while (GetCountSspClk() < last_frame_end) { };
LED_C_OFF();
}
//-----------------------------------------------------------------------------
// Frame Handling
//
// The LEGIC RF protocol from reader to card does not include explicit frame
// start/stop information or length information. The tag detects end of frame
// trough an extended pulse (>99.1us) without a pause.
// In reverse direction (card to reader) the number of bites is well known
// and depends only the command received (IV, ACK, READ or WRITE).
//-----------------------------------------------------------------------------
static void tx_frame(uint32_t frame, uint8_t len) {
// wait for next tx timeslot
last_frame_end += TAG_FRAME_WAIT;
legic_prng_forward(TAG_FRAME_WAIT / TAG_BIT_PERIOD - 1);
while (GetCountSspClk() < last_frame_end) { };
// backup ts for trace log
uint32_t last_frame_start = last_frame_end;
// transmit frame, MSB first
for (uint8_t i = 0; i < len; ++i) {
bool bit = (frame >> i) & 0x01;
tx_bit(bit ^ legic_prng_get_bit());
legic_prng_forward(1);
};
// disable subcarrier
LOW(GPIO_SSC_DOUT);
// log
uint8_t cmdbytes[] = {len, BYTEx(frame, 0), BYTEx(frame, 1)};
LogTrace(cmdbytes, sizeof(cmdbytes), last_frame_start, last_frame_end, NULL, false);
}
static void tx_ack() {
// wait for ack timeslot
last_frame_end += TAG_ACK_WAIT;
legic_prng_forward(TAG_ACK_WAIT / TAG_BIT_PERIOD - 1);
while (GetCountSspClk() < last_frame_end) { };
// backup ts for trace log
uint32_t last_frame_start = last_frame_end;
// transmit ack (ack is not encrypted)
tx_bit(true);
legic_prng_forward(1);
// disable subcarrier
LOW(GPIO_SSC_DOUT);
// log
uint8_t cmdbytes[] = {1, 1};
LogTrace(cmdbytes, sizeof(cmdbytes), last_frame_start, last_frame_end, NULL, false);
}
// Returns a demedulated frame or -1 on code violation
//
// Since TX to RX delay is arbitrary rx_frame has to:
// - detect start of frame (first pause)
// - forward prng based on ts/TAG_BIT_PERIOD
// - receive the frame
// - detect end of frame (last pause)
static int32_t rx_frame(uint8_t *len) {
int32_t frame = 0;
// add 2 SSP clock cycles (1 for tx and 1 for rx pipeline delay)
// those will be substracted at the end of the rx phase
last_frame_end -= 2;
// wait for first pause (start of frame)
for (uint8_t i = 0; true; ++i) {
// increment prng every TAG_BIT_PERIOD
last_frame_end += TAG_BIT_PERIOD;
legic_prng_forward(1);
// if start of frame was received exit delay loop
if (wait_for(RWD_PAUSE, last_frame_end)) {
last_frame_end = GetCountSspClk();
break;
}
// check for code violation
if (i > RWD_CMD_TIMEOUT) {
return -1;
}
}
// backup ts for trace log
uint32_t last_frame_start = last_frame_end;
// receive frame
for (*len = 0; true; ++(*len)) {
// receive next bit
LED_B_ON();
int8_t bit = rx_bit();
LED_B_OFF();
// check for code violation and to short / long frame
if ((bit < 0) && ((*len < RWD_MIN_FRAME_LEN) || (*len > RWD_MAX_FRAME_LEN))) {
return -1;
}
// check for code violation caused by end of frame
if (bit < 0) {
break;
}
// append bit
frame |= (bit ^ legic_prng_get_bit()) << (*len);
legic_prng_forward(1);
}
// rx_bit sets coordination timestamp to start of pause, append pause duration
// and substract 2 SSP clock cycles (1 for rx and 1 for tx pipeline delay) to
// obtain exact end of frame.
last_frame_end += RWD_TIME_PAUSE - 2;
// log
uint8_t cmdbytes[] = {*len, BYTEx(frame, 0), BYTEx(frame, 1), BYTEx(frame, 2)};
LogTrace(cmdbytes, sizeof(cmdbytes), last_frame_start, last_frame_end, NULL, true);
return frame;
}
//-----------------------------------------------------------------------------
// Legic Simulator
//-----------------------------------------------------------------------------
static int32_t init_card(uint8_t cardtype, legic_card_select_t *p_card) {
p_card->tagtype = cardtype;
switch (p_card->tagtype) {
case 0:
p_card->cmdsize = 6;
p_card->addrsize = 5;
p_card->cardsize = 22;
break;
case 1:
p_card->cmdsize = 9;
p_card->addrsize = 8;
p_card->cardsize = 256;
break;
case 2:
p_card->cmdsize = 11;
p_card->addrsize = 10;
p_card->cardsize = 1024;
break;
default:
p_card->cmdsize = 0;
p_card->addrsize = 0;
p_card->cardsize = 0;
return 2;
}
return 0;
}
static void init_tag() {
// configure FPGA
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR
| FPGA_HF_SIMULATOR_MODULATE_212K);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
// configure SSC with defaults
FpgaSetupSsc();
// first pull output to low to prevent glitches then re-claim GPIO_SSC_DOUT
LOW(GPIO_SSC_DOUT);
AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT;
// reserve a cardmem, meaning we can use the tracelog function in bigbuff easier.
legic_mem = BigBuf_get_EM_addr();
// start trace
clear_trace();
set_tracing(true);
// init crc calculator
crc_init(&legic_crc, 4, 0x19 >> 1, 0x05, 0);
// start 212kHz timer (running from SSP Clock)
StartCountSspClk();
}
// Setup reader to card connection
//
// The setup consists of a three way handshake:
// - Receive initialisation vector 7 bits
// - Transmit card type 6 bits
// - Receive Acknowledge 6 bits
static int32_t setup_phase(legic_card_select_t *p_card) {
uint8_t len = 0;
// init coordination timestamp
last_frame_end = GetCountSspClk();
// reset prng
legic_prng_init(0);
// wait for iv
int32_t iv = rx_frame(&len);
if ((len != 7) || (iv < 0)) {
return -1;
}
// configure prng
legic_prng_init(iv);
// reply with card type
switch (p_card->tagtype) {
case 0:
tx_frame(0x0D, 6);
break;
case 1:
tx_frame(0x1D, 6);
break;
case 2:
tx_frame(0x3D, 6);
break;
}
// wait for ack
int32_t ack = rx_frame(&len);
if ((len != 6) || (ack < 0)) {
return -1;
}
// validate data
switch (p_card->tagtype) {
case 0:
if (ack != 0x19) return -1;
break;
case 1:
if (ack != 0x39) return -1;
break;
case 2:
if (ack != 0x39) return -1;
break;
}
// During rx the prng is clocked using the variable reader period.
// Since rx_frame detects end of frame by detecting a code violation,
// the prng is off by one bit period after each rx phase. Hence, tx
// code advances the prng by (TAG_FRAME_WAIT/TAG_BIT_PERIOD - 1).
// This is not possible for back to back rx, so this quirk reduces
// the gap by one period.
last_frame_end += TAG_BIT_PERIOD;
return 0;
}
static uint8_t calc_crc4(uint16_t cmd, uint8_t cmd_sz, uint8_t value) {
crc_clear(&legic_crc);
crc_update(&legic_crc, (value << cmd_sz) | cmd, 8 + cmd_sz);
return crc_finish(&legic_crc);
}
static int32_t connected_phase(legic_card_select_t *p_card) {
uint8_t len = 0;
// wait for command
int32_t cmd = rx_frame(&len);
if (cmd < 0) {
return -1;
}
// check if command is LEGIC_READ
if (len == p_card->cmdsize) {
// prepare data
uint8_t byte = legic_mem[cmd >> 1];
uint8_t crc = calc_crc4(cmd, p_card->cmdsize, byte);
// transmit data
tx_frame((crc << 8) | byte, 12);
return 0;
}
// check if command is LEGIC_WRITE
if (len == p_card->cmdsize + 8 + 4) {
// decode data
uint16_t mask = (1 << p_card->addrsize) - 1;
uint16_t addr = (cmd >> 1) & mask;
uint8_t byte = (cmd >> p_card->cmdsize) & 0xff;
uint8_t crc = (cmd >> (p_card->cmdsize + 8)) & 0xf;
// check received against calculated crc
uint8_t calc_crc = calc_crc4(addr << 1, p_card->cmdsize, byte);
if (calc_crc != crc) {
Dbprintf("!!! crc mismatch: %x != %x !!!", calc_crc, crc);
return -1;
}
// store data
legic_mem[addr] = byte;
// transmit ack
tx_ack();
return 0;
}
return -1;
}
//-----------------------------------------------------------------------------
// Command Line Interface
//
// Only this function is public / called from appmain.c
//-----------------------------------------------------------------------------
void LegicRfSimulate(uint8_t cardtype) {
// configure ARM and FPGA
init_tag();
// verify command line input
if (init_card(cardtype, &card) != 0) {
DbpString("Unknown tagtype.");
goto OUT;
}
LED_A_ON();
DbpString("Starting Legic emulator, press button to end");
while (!BUTTON_PRESS() && !data_available()) {
WDT_HIT();
// wait for carrier, restart after timeout
if (!wait_for(RWD_PULSE, GetCountSspClk() + TAG_BIT_PERIOD)) {
continue;
}
// wait for connection, restart on error
if (setup_phase(&card)) {
continue;
}
// conection is established, process commands until one fails
while (!connected_phase(&card)) {
WDT_HIT();
}
}
OUT:
DbpString("Stopped");
switch_off();
StopTicks();
}

19
armsrc/legicrfsim.h Normal file
View file

@ -0,0 +1,19 @@
//-----------------------------------------------------------------------------
// (c) 2009 Henryk Plötz <henryk@ploetzli.ch>
// 2018 AntiCat
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// LEGIC RF emulation public interface
//-----------------------------------------------------------------------------
#ifndef __LEGICRFSIM_H
#define __LEGICRFSIM_H
#include "proxmark3.h"
void LegicRfSimulate(uint8_t tagtype);
#endif /* __LEGICRFSIM_H */

File diff suppressed because it is too large Load diff

View file

@ -10,26 +10,26 @@
/*
Default LF config is set to:
decimation = 1 (we keep 1 out of 1 samples)
bits_per_sample = 8
averaging = YES
divisor = 95 (125khz)
trigger_threshold = 0
*/
decimation = 1 (we keep 1 out of 1 samples)
bits_per_sample = 8
averaging = YES
divisor = 95 (125khz)
trigger_threshold = 0
*/
sample_config config = { 1, 8, 1, 95, 0 } ;
void printConfig() {
Dbprintf("LF Sampling config");
Dbprintf(" [q] divisor.............%d (%d KHz)", config.divisor, 12000 / (config.divisor+1));
Dbprintf(" [b] bps.................%d", config.bits_per_sample);
Dbprintf(" [d] decimation..........%d", config.decimation);
Dbprintf(" [a] averaging...........%s", (config.averaging) ? "Yes" : "No");
Dbprintf(" [t] trigger threshold...%d", config.trigger_threshold);
DbpString(_BLUE_("LF Sampling config"));
Dbprintf(" [q] divisor.............%d ( "_GREEN_("%d kHz")")", config.divisor, 12000 / (config.divisor + 1));
Dbprintf(" [b] bps.................%d", config.bits_per_sample);
Dbprintf(" [d] decimation..........%d", config.decimation);
Dbprintf(" [a] averaging...........%s", (config.averaging) ? "Yes" : "No");
Dbprintf(" [t] trigger threshold...%d", config.trigger_threshold);
}
/**
* Called from the USB-handler to set the sampling configuration
* The sampling config is used for std reading and snooping.
* The sampling config is used for std reading and sniffing.
*
* Other functions may read samples and ignore the sampling config,
* such as functions to read the UID from a prox tag or similar.
@ -39,25 +39,25 @@ void printConfig() {
* @param sc
*/
void setSamplingConfig(sample_config *sc) {
if(sc->divisor != 0) config.divisor = sc->divisor;
if(sc->bits_per_sample != 0) config.bits_per_sample = sc->bits_per_sample;
if(sc->trigger_threshold != -1) config.trigger_threshold = sc->trigger_threshold;
config.decimation = (sc->decimation != 0) ? sc->decimation : 1;
config.averaging = sc->averaging;
if(config.bits_per_sample > 8) config.bits_per_sample = 8;
if (sc->divisor != 0) config.divisor = sc->divisor;
if (sc->bits_per_sample != 0) config.bits_per_sample = sc->bits_per_sample;
if (sc->trigger_threshold != -1) config.trigger_threshold = sc->trigger_threshold;
printConfig();
config.decimation = (sc->decimation != 0) ? sc->decimation : 1;
config.averaging = sc->averaging;
if (config.bits_per_sample > 8) config.bits_per_sample = 8;
printConfig();
}
sample_config* getSamplingConfig() {
return &config;
sample_config *getSamplingConfig() {
return &config;
}
struct BitstreamOut {
uint8_t * buffer;
uint32_t numbits;
uint32_t position;
uint8_t *buffer;
uint32_t numbits;
uint32_t position;
};
/**
@ -65,40 +65,40 @@ struct BitstreamOut {
* @param stream
* @param bit
*/
void pushBit( BitstreamOut* stream, uint8_t bit) {
int bytepos = stream->position >> 3; // divide by 8
int bitpos = stream->position & 7;
*(stream->buffer+bytepos) |= (bit > 0) << (7 - bitpos);
stream->position++;
stream->numbits++;
void pushBit(BitstreamOut *stream, uint8_t bit) {
int bytepos = stream->position >> 3; // divide by 8
int bitpos = stream->position & 7;
*(stream->buffer + bytepos) |= (bit > 0) << (7 - bitpos);
stream->position++;
stream->numbits++;
}
/**
* Setup the FPGA to listen for samples. This method downloads the FPGA bitstream
* if not already loaded, sets divisor and starts up the antenna.
* @param divisor : 1, 88> 255 or negative ==> 134.8 KHz
* 0 or 95 ==> 125 KHz
* @param divisor : 1, 88> 255 or negative ==> 134.8 kHz
* 0 or 95 ==> 125 kHz
*
**/
void LFSetupFPGAForADC(int divisor, bool lf_field) {
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
if ( (divisor == 1) || (divisor < 0) || (divisor > 255) )
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz
else if (divisor == 0)
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
else
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor);
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
if ((divisor == 1) || (divisor < 0) || (divisor > 255))
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 88); //134.8Khz
else if (divisor == 0)
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
else
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor);
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | (lf_field ? FPGA_LF_ADC_READER_FIELD : 0));
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | (lf_field ? FPGA_LF_ADC_READER_FIELD : 0));
// Connect the A/D to the peak-detected low-frequency path.
SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
// 50ms for the resonant antenna to settle.
SpinDelay(50);
// Now set up the SSC to get the ADC samples that are now streaming at us.
FpgaSetupSsc();
// start a 1.5ticks is 1us
StartTicks();
// Connect the A/D to the peak-detected low-frequency path.
SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
// 50ms for the resonant antenna to settle.
SpinDelay(50);
// Now set up the SSC to get the ADC samples that are now streaming at us.
FpgaSetupSsc();
// start a 1.5ticks is 1us
StartTicks();
}
/**
@ -117,96 +117,109 @@ void LFSetupFPGAForADC(int divisor, bool lf_field) {
* @return the number of bits occupied by the samples.
*/
uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averaging, int trigger_threshold, bool silent, int bufsize, uint32_t cancel_after) {
//bigbuf, to hold the aquired raw data signal
uint8_t *dest = BigBuf_get_addr();
uint8_t *dest = BigBuf_get_addr();
bufsize = (bufsize > 0 && bufsize < BigBuf_max_traceLen()) ? bufsize : BigBuf_max_traceLen();
if (bits_per_sample < 1) bits_per_sample = 1;
if (bits_per_sample > 8) bits_per_sample = 8;
if (bits_per_sample < 1) bits_per_sample = 1;
if (bits_per_sample > 8) bits_per_sample = 8;
if (decimation < 1) decimation = 1;
if (decimation < 1) decimation = 1;
// use a bit stream to handle the output
BitstreamOut data = { dest, 0, 0};
int sample_counter = 0;
uint8_t sample;
// Use a bit stream to handle the output
BitstreamOut data = { dest , 0, 0};
int sample_counter = 0;
uint8_t sample = 0;
//If we want to do averaging
uint32_t sample_sum =0 ;
uint32_t sample_total_numbers = 0;
uint32_t sample_total_saved = 0;
uint32_t cancel_counter = 0;
while (!BUTTON_PRESS() && !usb_poll_validate_length() ) {
WDT_HIT();
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
AT91C_BASE_SSC->SSC_THR = 0x43;
LED_D_ON();
}
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
LED_D_OFF();
// threshold either high or low values 128 = center 0. if trigger = 178
if ((trigger_threshold > 0) && (sample < (trigger_threshold + 128)) && (sample > (128 - trigger_threshold))) {
if (cancel_after > 0) {
cancel_counter++;
if (cancel_after == cancel_counter)
break;
}
continue;
}
trigger_threshold = 0;
sample_total_numbers++;
// if we want to do averaging
uint32_t sample_sum = 0 ;
uint32_t sample_total_numbers = 0;
uint32_t sample_total_saved = 0;
uint32_t cancel_counter = 0;
uint16_t checker = 0;
while (true) {
if ( checker == 1000 ) {
if (BUTTON_PRESS() || data_available())
break;
else
checker = 0;
} else {
++checker;
}
WDT_HIT();
if (averaging)
sample_sum += sample;
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
//Check decimation
if (decimation > 1) {
sample_counter++;
if (sample_counter < decimation) continue;
sample_counter = 0;
}
//Averaging
if (averaging && decimation > 1) {
sample = sample_sum / decimation;
sample_sum =0;
}
//Store the sample
sample_total_saved ++;
if (bits_per_sample == 8){
dest[sample_total_saved-1] = sample;
data.numbits = sample_total_saved << 3;//Get the return value correct
if (sample_total_saved >= bufsize) break;
} else {
pushBit(&data, sample & 0x80);
if (bits_per_sample > 1) pushBit(&data, sample & 0x40);
if (bits_per_sample > 2) pushBit(&data, sample & 0x20);
if (bits_per_sample > 3) pushBit(&data, sample & 0x10);
if (bits_per_sample > 4) pushBit(&data, sample & 0x08);
if (bits_per_sample > 5) pushBit(&data, sample & 0x04);
if (bits_per_sample > 6) pushBit(&data, sample & 0x02);
//Not needed, 8bps is covered above
//if (bits_per_sample > 7) pushBit(&data, sample & 0x01);
if ((data.numbits >> 3) +1 >= bufsize) break;
}
}
}
// Testpoint 8 (TP8) can be used to trigger oscilliscope
LED_D_OFF();
if (!silent) {
Dbprintf("Done, saved %d out of %d seen samples at %d bits/sample", sample_total_saved, sample_total_numbers, bits_per_sample);
Dbprintf("buffer samples: %02x %02x %02x %02x %02x %02x %02x %02x ...",
dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]);
}
// Ensure that noise check is performed for any device-side processing
justNoise(dest, bufsize);
return data.numbits;
// threshold either high or low values 128 = center 0. if trigger = 178
if ((trigger_threshold > 0) && (sample < (trigger_threshold + 128)) && (sample > (128 - trigger_threshold))) {
if (cancel_after > 0) {
cancel_counter++;
if (cancel_after == cancel_counter)
break;
}
continue;
}
trigger_threshold = 0;
sample_total_numbers++;
if (averaging)
sample_sum += sample;
// check decimation
if (decimation > 1) {
sample_counter++;
if (sample_counter < decimation) continue;
sample_counter = 0;
}
// averaging
if (averaging && decimation > 1) {
sample = sample_sum / decimation;
sample_sum = 0;
}
// store the sample
sample_total_saved ++;
if (bits_per_sample == 8) {
dest[sample_total_saved - 1] = sample;
// Get the return value correct
data.numbits = sample_total_saved << 3;
if (sample_total_saved >= bufsize) break;
} else {
pushBit(&data, sample & 0x80);
if (bits_per_sample > 1) pushBit(&data, sample & 0x40);
if (bits_per_sample > 2) pushBit(&data, sample & 0x20);
if (bits_per_sample > 3) pushBit(&data, sample & 0x10);
if (bits_per_sample > 4) pushBit(&data, sample & 0x08);
if (bits_per_sample > 5) pushBit(&data, sample & 0x04);
if (bits_per_sample > 6) pushBit(&data, sample & 0x02);
if ((data.numbits >> 3) + 1 >= bufsize) break;
}
}
}
if (!silent) {
Dbprintf("Done, saved " _YELLOW_("%d")"out of " _YELLOW_("%d")"seen samples at " _YELLOW_("%d")"bits/sample", sample_total_saved, sample_total_numbers, bits_per_sample);
Dbprintf("buffer samples: %02x %02x %02x %02x %02x %02x %02x %02x ...",
dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]);
}
// Ensure that DC offset removal and noise check is performed for any device-side processing
removeSignalOffset(dest, bufsize);
computeSignalProperties(dest, bufsize);
return data.numbits;
}
/**
* @brief Does sample acquisition, ignoring the config values set in the sample_config.
@ -217,48 +230,46 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag
* @return number of bits sampled
*/
uint32_t DoAcquisition_default(int trigger_threshold, bool silent) {
return DoAcquisition(1, 8, 0,trigger_threshold, silent, 0, 0);
return DoAcquisition(1, 8, 0, trigger_threshold, silent, 0, 0);
}
uint32_t DoAcquisition_config( bool silent, int sample_size) {
return DoAcquisition(config.decimation
,config.bits_per_sample
,config.averaging
,config.trigger_threshold
,silent
,sample_size
,0);
uint32_t DoAcquisition_config(bool silent, int sample_size) {
return DoAcquisition(config.decimation
, config.bits_per_sample
, config.averaging
, config.trigger_threshold
, silent
, sample_size
, 0);
}
uint32_t DoPartialAcquisition(int trigger_threshold, bool silent, int sample_size, uint32_t cancel_after) {
return DoAcquisition(1, 8, 0, trigger_threshold, silent, sample_size, cancel_after);
return DoAcquisition(1, 8, 0, trigger_threshold, silent, sample_size, cancel_after);
}
uint32_t ReadLF(bool activeField, bool silent, int sample_size) {
if (!silent)
printConfig();
LFSetupFPGAForADC(config.divisor, activeField);
return DoAcquisition_config(silent, sample_size);
if (!silent)
printConfig();
LFSetupFPGAForADC(config.divisor, activeField);
uint32_t ret = DoAcquisition_config(silent, sample_size);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
return ret;
}
/**
* Initializes the FPGA for reader-mode (field on), and acquires the samples.
* @return number of bits sampled
**/
uint32_t SampleLF(bool printCfg, int sample_size) {
BigBuf_Clear_ext(false);
uint32_t ret = ReadLF(true, printCfg, sample_size);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
return ret;
uint32_t SampleLF(bool silent, int sample_size) {
BigBuf_Clear_ext(false);
return ReadLF(true, silent, sample_size);
}
/**
* Initializes the FPGA for snoop-mode (field off), and acquires the samples.
* Initializes the FPGA for sniffer-mode (field off), and acquires the samples.
* @return number of bits sampled
**/
uint32_t SnoopLF() {
BigBuf_Clear_ext(false);
uint32_t ret = ReadLF(false, true, 0);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
return ret;
uint32_t SniffLF() {
BigBuf_Clear_ext(false);
return ReadLF(false, true, 0);
}
/**
@ -267,63 +278,72 @@ uint32_t SnoopLF() {
**/
void doT55x7Acquisition(size_t sample_size) {
#define T55xx_READ_UPPER_THRESHOLD 128+60 // 60 grph
#define T55xx_READ_LOWER_THRESHOLD 128-60 // -60 grph
#define T55xx_READ_TOL 5
uint8_t *dest = BigBuf_get_addr();
uint16_t bufsize = BigBuf_max_traceLen();
if ( bufsize > sample_size )
bufsize = sample_size;
#define T55xx_READ_UPPER_THRESHOLD 128+60 // 60 grph
#define T55xx_READ_LOWER_THRESHOLD 128-60 // -60 grph
#define T55xx_READ_TOL 5
uint8_t curSample = 0, lastSample = 0;
uint16_t i = 0, skipCnt = 0;
bool startFound = false;
bool highFound = false;
bool lowFound = false;
while(!BUTTON_PRESS() && !usb_poll_validate_length() && skipCnt < 1000 && (i < bufsize) ) {
WDT_HIT();
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
AT91C_BASE_SSC->SSC_THR = 0x43; //43
LED_D_ON();
}
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
curSample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
LED_D_OFF();
// skip until the first high sample above threshold
if (!startFound && curSample > T55xx_READ_UPPER_THRESHOLD) {
//if (curSample > lastSample)
// lastSample = curSample;
highFound = true;
} else if (!highFound) {
skipCnt++;
continue;
}
// skip until the first low sample below threshold
if (!startFound && curSample < T55xx_READ_LOWER_THRESHOLD) {
//if (curSample > lastSample)
lastSample = curSample;
lowFound = true;
} else if (!lowFound) {
skipCnt++;
continue;
}
uint8_t *dest = BigBuf_get_addr();
uint16_t bufsize = BigBuf_max_traceLen();
// skip until first high samples begin to change
if (startFound || curSample > T55xx_READ_LOWER_THRESHOLD + T55xx_READ_TOL){
// if just found start - recover last sample
if (!startFound) {
dest[i++] = lastSample;
startFound = true;
}
// collect samples
dest[i++] = curSample;
}
}
}
if (bufsize > sample_size)
bufsize = sample_size;
uint8_t curSample, lastSample = 0;
uint16_t i = 0, skipCnt = 0;
bool startFound = false;
bool highFound = false;
bool lowFound = false;
uint16_t checker = 0;
while ( skipCnt < 1000 && (i < bufsize)) {
if ( checker == 1000 ) {
if (BUTTON_PRESS() || data_available())
break;
else
checker = 0;
} else {
++checker;
}
WDT_HIT();
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
curSample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
LED_D_OFF();
// skip until the first high sample above threshold
if (!startFound && curSample > T55xx_READ_UPPER_THRESHOLD) {
//if (curSample > lastSample)
// lastSample = curSample;
highFound = true;
} else if (!highFound) {
skipCnt++;
continue;
}
// skip until the first low sample below threshold
if (!startFound && curSample < T55xx_READ_LOWER_THRESHOLD) {
//if (curSample > lastSample)
lastSample = curSample;
lowFound = true;
} else if (!lowFound) {
skipCnt++;
continue;
}
// skip until first high samples begin to change
if (startFound || curSample > T55xx_READ_LOWER_THRESHOLD + T55xx_READ_TOL) {
// if just found start - recover last sample
if (!startFound) {
dest[i++] = lastSample;
startFound = true;
}
// collect samples
dest[i++] = curSample;
}
}
}
}
/**
* acquisition of Cotag LF signal. Similart to other LF, since the Cotag has such long datarate RF/384
@ -339,125 +359,134 @@ void doT55x7Acquisition(size_t sample_size) {
#endif
void doCotagAcquisition(size_t sample_size) {
uint8_t *dest = BigBuf_get_addr();
uint16_t bufsize = BigBuf_max_traceLen();
if ( bufsize > sample_size )
bufsize = sample_size;
uint8_t *dest = BigBuf_get_addr();
uint16_t bufsize = BigBuf_max_traceLen();
dest[0] = 0;
uint8_t sample = 0, firsthigh = 0, firstlow = 0;
uint16_t i = 0;
uint16_t noise_counter = 0;
while (!BUTTON_PRESS() && !usb_poll_validate_length() && (i < bufsize) && (noise_counter < (COTAG_T1 << 1)) ) {
WDT_HIT();
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
AT91C_BASE_SSC->SSC_THR = 0x43;
LED_D_ON();
}
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
LED_D_OFF();
// find first peak
if ( !firsthigh ) {
if (sample < COTAG_ONE_THRESHOLD) {
noise_counter++;
continue;
}
noise_counter = 0;
firsthigh = 1;
}
if ( !firstlow ){
if (sample > COTAG_ZERO_THRESHOLD ) {
noise_counter++;
continue;
}
noise_counter = 0;
firstlow = 1;
}
if (bufsize > sample_size)
bufsize = sample_size;
++i;
if ( sample > COTAG_ONE_THRESHOLD)
dest[i] = 255;
else if ( sample < COTAG_ZERO_THRESHOLD)
dest[i] = 0;
else
dest[i] = dest[i-1];
}
}
dest[0] = 0;
uint8_t sample, firsthigh = 0, firstlow = 0;
uint16_t i = 0;
uint16_t noise_counter = 0;
uint16_t checker = 0;
while ((i < bufsize) && (noise_counter < (COTAG_T1 << 1))) {
if ( checker == 1000 ) {
if (BUTTON_PRESS() || data_available())
break;
else
checker = 0;
} else {
++checker;
}
WDT_HIT();
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
// find first peak
if (!firsthigh) {
if (sample < COTAG_ONE_THRESHOLD) {
noise_counter++;
continue;
}
noise_counter = 0;
firsthigh = 1;
}
if (!firstlow) {
if (sample > COTAG_ZERO_THRESHOLD) {
noise_counter++;
continue;
}
noise_counter = 0;
firstlow = 1;
}
++i;
if (sample > COTAG_ONE_THRESHOLD)
dest[i] = 255;
else if (sample < COTAG_ZERO_THRESHOLD)
dest[i] = 0;
else
dest[i] = dest[i - 1];
}
}
}
uint32_t doCotagAcquisitionManchester() {
uint8_t *dest = BigBuf_get_addr();
uint16_t bufsize = BigBuf_max_traceLen();
if ( bufsize > COTAG_BITS )
bufsize = COTAG_BITS;
uint8_t *dest = BigBuf_get_addr();
uint16_t bufsize = BigBuf_max_traceLen();
dest[0] = 0;
uint8_t sample = 0, firsthigh = 0, firstlow = 0;
uint16_t sample_counter = 0, period = 0;
uint8_t curr = 0, prev = 0;
uint16_t noise_counter = 0;
if (bufsize > COTAG_BITS)
bufsize = COTAG_BITS;
while (!BUTTON_PRESS() && !usb_poll_validate_length() && (sample_counter < bufsize) && (noise_counter < (COTAG_T1 << 1)) ) {
WDT_HIT();
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
AT91C_BASE_SSC->SSC_THR = 0x43;
LED_D_ON();
}
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
LED_D_OFF();
// find first peak
if ( !firsthigh ) {
if (sample < COTAG_ONE_THRESHOLD) {
noise_counter++;
continue;
}
noise_counter = 0;
firsthigh = 1;
}
if ( !firstlow ){
if (sample > COTAG_ZERO_THRESHOLD ) {
noise_counter++;
continue;
}
noise_counter = 0;
firstlow = 1;
}
// set sample 255, 0, or previous
if ( sample > COTAG_ONE_THRESHOLD){
prev = curr;
curr = 1;
}
else if ( sample < COTAG_ZERO_THRESHOLD) {
prev = curr;
curr = 0;
}
else {
curr = prev;
}
dest[0] = 0;
uint8_t sample, firsthigh = 0, firstlow = 0;
uint16_t sample_counter = 0, period = 0;
uint8_t curr = 0, prev = 0;
uint16_t noise_counter = 0;
uint16_t checker = 0;
while ((sample_counter < bufsize) && (noise_counter < (COTAG_T1 << 1))) {
if ( checker == 1000 ) {
if (BUTTON_PRESS() || data_available())
break;
else
checker = 0;
} else {
++checker;
}
// full T1 periods,
if ( period > 0 ) {
--period;
continue;
}
dest[sample_counter] = curr;
++sample_counter;
period = COTAG_T1;
}
}
return sample_counter;
}
WDT_HIT();
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
// find first peak
if (!firsthigh) {
if (sample < COTAG_ONE_THRESHOLD) {
noise_counter++;
continue;
}
noise_counter = 0;
firsthigh = 1;
}
if (!firstlow) {
if (sample > COTAG_ZERO_THRESHOLD) {
noise_counter++;
continue;
}
noise_counter = 0;
firstlow = 1;
}
// set sample 255, 0, or previous
if (sample > COTAG_ONE_THRESHOLD) {
prev = curr;
curr = 1;
} else if (sample < COTAG_ZERO_THRESHOLD) {
prev = curr;
curr = 0;
} else {
curr = prev;
}
// full T1 periods,
if (period > 0) {
--period;
continue;
}
dest[sample_counter] = curr;
++sample_counter;
period = COTAG_T1;
}
}
return sample_counter;
}

View file

@ -5,8 +5,8 @@
#include "apps.h"
#include "util.h"
#include "string.h"
#include "usb_cdc.h" // for usb_poll_validate_length
#include "ticks.h" // for StartTicks
#include "usb_cdc.h" // for usb_poll_validate_length
#include "ticks.h" // for StartTicks
typedef struct BitstreamOut BitstreamOut;
@ -30,10 +30,10 @@ void doT55x7Acquisition(size_t sample_size);
uint32_t SampleLF(bool silent, int sample_size);
/**
* Initializes the FPGA for snoop-mode (field off), and acquires the samples.
* Initializes the FPGA for sniff-mode (field off), and acquires the samples.
* @return number of bits sampled
**/
uint32_t SnoopLF();
uint32_t SniffLF();
// adds sample size to default options
uint32_t DoPartialAcquisition(int trigger_threshold, bool silent, int sample_size, uint32_t cancel_after);
@ -59,15 +59,15 @@ uint32_t DoAcquisition_config(bool silent, int sample_size);
/**
* Setup the FPGA to listen for samples. This method downloads the FPGA bitstream
* if not already loaded, sets divisor and starts up the antenna.
* @param divisor : 1, 88> 255 or negative ==> 134.8 KHz
* 0 or 95 ==> 125 KHz
* @param divisor : 1, 88> 255 or negative ==> 134.8 kHz
* 0 or 95 ==> 125 kHz
*
**/
void LFSetupFPGAForADC(int divisor, bool lf_field);
/**
* Called from the USB-handler to set the sampling configuration
* The sampling config is used for std reading and snooping.
* The sampling config is used for std reading and sniffing.
*
* Other functions may read samples and ignore the sampling config,
* such as functions to read the UID from a prox tag or similar.
@ -78,7 +78,7 @@ void LFSetupFPGAForADC(int divisor, bool lf_field);
*/
void setSamplingConfig(sample_config *sc);
sample_config * getSamplingConfig();
sample_config *getSamplingConfig();
void printConfig();

File diff suppressed because it is too large Load diff

View file

@ -1,28 +1,27 @@
//-----------------------------------------------------------------------------
// Merlok - June 2011
// Gerhard de Koning Gans - May 2008
// Hagen Fritsch - June 2010
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Routines to support ISO 14443 type A.
//-----------------------------------------------------------------------------
#ifndef __MIFARECMD_H
#define __MIFARECMD_H
#include "proxmark3.h"
#include "apps.h"
#include "util.h"
#include "string.h"
#include "iso14443crc.h"
#include "iso14443a.h"
#include "crapto1/crapto1.h"
#include "mifareutil.h"
#include "common.h"
#include "crc.h"
#include "protocols.h"
#include "parity.h"
#endif
//-----------------------------------------------------------------------------
// Merlok - June 2011
// Gerhard de Koning Gans - May 2008
// Hagen Fritsch - June 2010
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Routines to support ISO 14443 type A.
//-----------------------------------------------------------------------------
#ifndef __MIFARECMD_H
#define __MIFARECMD_H
#include "proxmark3.h"
#include "apps.h"
#include "util.h"
#include "string.h"
#include "iso14443a.h"
#include "crapto1/crapto1.h"
#include "mifareutil.h"
#include "common.h"
#include "crc.h"
#include "protocols.h"
#include "parity.h"
#endif

View file

@ -10,304 +10,303 @@
// the block number for the ISO14443-4 PCB
uint8_t pcb_blocknum = 0;
// Deselect card by sending a s-block. the crc is precalced for speed
static uint8_t deselect_cmd[] = {0xc2,0xe0,0xb4};
static uint8_t deselect_cmd[] = {0xc2, 0xe0, 0xb4};
//static uint8_t __msg[MAX_FRAME_SIZE] = { 0x0A, 0x00, 0x00, /* ..., */ 0x00 };
/* PCB CID CMD PAYLOAD */
//static uint8_t __res[MAX_FRAME_SIZE];
bool InitDesfireCard(){
bool InitDesfireCard() {
iso14a_card_select_t card;
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
set_tracing(true);
iso14a_card_select_t card;
if (!iso14443a_select_card(NULL, &card, NULL, true, 0, false)) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) DbpString("Can't select card");
OnError(1);
return false;
}
return true;
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
set_tracing(true);
if (!iso14443a_select_card(NULL, &card, NULL, true, 0, false)) {
if (DBGLEVEL >= DBG_ERROR) DbpString("Can't select card");
OnError(1);
return false;
}
return true;
}
// ARG0 flag enums
enum {
NONE = 0x00,
INIT = 0x01,
DISCONNECT = 0x02,
CLEARTRACE = 0x04,
BAR = 0x08,
NONE = 0x00,
INIT = 0x01,
DISCONNECT = 0x02,
CLEARTRACE = 0x04,
BAR = 0x08,
} CmdOptions ;
void MifareSendCommand(uint8_t arg0, uint8_t arg1, uint8_t *datain){
/* ARG0 contains flags.
0x01 = init card.
0x02 = Disconnect
0x03
*/
uint8_t flags = arg0;
size_t datalen = arg1;
uint8_t resp[RECEIVE_SIZE];
memset(resp,0,sizeof(resp));
if (MF_DBGLEVEL >= 4) {
Dbprintf(" flags : %02X", flags);
Dbprintf(" len : %02X", datalen);
print_result(" RX : ", datain, datalen);
}
if ( flags & CLEARTRACE )
clear_trace();
if ( flags & INIT ){
if ( !InitDesfireCard() )
return;
}
int len = DesfireAPDU(datain, datalen, resp);
if (MF_DBGLEVEL >= 4)
print_result("ERR <--: ", resp, len);
void MifareSendCommand(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
if ( !len ) {
OnError(2);
return;
}
// reset the pcb_blocknum,
pcb_blocknum = 0;
if ( flags & DISCONNECT )
OnSuccess();
cmd_send(CMD_ACK,1,len,0,resp,len);
/* ARG0 contains flags.
0x01 = init card.
0x02 = Disconnect
0x03
*/
uint8_t flags = arg0;
size_t datalen = arg1;
uint8_t resp[RECEIVE_SIZE];
memset(resp, 0, sizeof(resp));
if (DBGLEVEL >= 4) {
Dbprintf(" flags : %02X", flags);
Dbprintf(" len : %02X", datalen);
print_result(" RX : ", datain, datalen);
}
if (flags & CLEARTRACE)
clear_trace();
if (flags & INIT) {
if (!InitDesfireCard())
return;
}
int len = DesfireAPDU(datain, datalen, resp);
if (DBGLEVEL >= 4)
print_result("ERR <--: ", resp, len);
if (!len) {
OnError(2);
return;
}
// reset the pcb_blocknum,
pcb_blocknum = 0;
if (flags & DISCONNECT)
OnSuccess();
reply_old(CMD_ACK, 1, len, 0, resp, len);
}
void MifareDesfireGetInformation(){
int len = 0;
iso14a_card_select_t card;
uint8_t resp[USB_CMD_DATA_SIZE] = {0x00};
uint8_t dataout[USB_CMD_DATA_SIZE] = {0x00};
/*
1 = PCB 1
2 = cid 2
3 = desfire command 3
4-5 = crc 4 key
5-6 crc
PCB == 0x0A because sending CID byte.
CID == 0x00 first card?
*/
clear_trace();
set_tracing(true);
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
void MifareDesfireGetInformation() {
// card select - information
if ( !iso14443a_select_card(NULL, &card, NULL, true, 0, false) ) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) DbpString("Can't select card");
OnError(1);
return;
}
if ( card.uidlen != 7 ) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Wrong UID size. Expected 7byte got %d", card.uidlen);
OnError(2);
return;
}
memcpy(dataout, card.uid, 7);
int len = 0;
iso14a_card_select_t card;
uint8_t resp[PM3_CMD_DATA_SIZE] = {0x00};
uint8_t dataout[PM3_CMD_DATA_SIZE] = {0x00};
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
uint8_t cmd[] = {GET_VERSION};
size_t cmd_len = sizeof(cmd);
len = DesfireAPDU(cmd, cmd_len, resp);
if ( !len ) {
print_result("ERROR <--: ", resp, len);
OnError(3);
return;
}
LED_A_OFF();
LED_B_ON();
memcpy(dataout+7,resp+3,7);
// ADDITION_FRAME 1
cmd[0] = ADDITIONAL_FRAME;
len = DesfireAPDU(cmd, cmd_len, resp);
if ( !len ) {
print_result("ERROR <--: ", resp, len);
OnError(3);
return;
}
LED_B_OFF();
LED_C_ON();
memcpy(dataout+7+7,resp+3,7);
/*
1 = PCB 1
2 = cid 2
3 = desfire command 3
4-5 = crc 4 key
5-6 crc
PCB == 0x0A because sending CID byte.
CID == 0x00 first card?
*/
clear_trace();
set_tracing(true);
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
// ADDITION_FRAME 2
len = DesfireAPDU(cmd, cmd_len, resp);
if ( !len ) {
print_result("ERROR <--: ", resp, len);
OnError(3);
return;
}
memcpy(dataout+7+7+7,resp+3,14);
cmd_send(CMD_ACK,1,0,0,dataout,sizeof(dataout));
// reset the pcb_blocknum,
pcb_blocknum = 0;
OnSuccess();
// card select - information
if (!iso14443a_select_card(NULL, &card, NULL, true, 0, false)) {
if (DBGLEVEL >= DBG_ERROR) DbpString("Can't select card");
OnError(1);
return;
}
if (card.uidlen != 7) {
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Wrong UID size. Expected 7byte got %d", card.uidlen);
OnError(2);
return;
}
memcpy(dataout, card.uid, 7);
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
uint8_t cmd[] = {GET_VERSION};
size_t cmd_len = sizeof(cmd);
len = DesfireAPDU(cmd, cmd_len, resp);
if (!len) {
print_result("ERROR <--: ", resp, len);
OnError(3);
return;
}
LED_A_OFF();
LED_B_ON();
memcpy(dataout + 7, resp + 3, 7);
// ADDITION_FRAME 1
cmd[0] = ADDITIONAL_FRAME;
len = DesfireAPDU(cmd, cmd_len, resp);
if (!len) {
print_result("ERROR <--: ", resp, len);
OnError(3);
return;
}
LED_B_OFF();
LED_C_ON();
memcpy(dataout + 7 + 7, resp + 3, 7);
// ADDITION_FRAME 2
len = DesfireAPDU(cmd, cmd_len, resp);
if (!len) {
print_result("ERROR <--: ", resp, len);
OnError(3);
return;
}
memcpy(dataout + 7 + 7 + 7, resp + 3, 14);
reply_old(CMD_ACK, 1, 0, 0, dataout, sizeof(dataout));
// reset the pcb_blocknum,
pcb_blocknum = 0;
OnSuccess();
}
void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain){
void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) {
// mode = arg0
// algo = arg1
// keyno = arg2
int len = 0;
//uint8_t PICC_MASTER_KEY8[8] = { 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47};
uint8_t PICC_MASTER_KEY16[16] = { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f };
//uint8_t null_key_data16[16] = {0x00};
//uint8_t new_key_data8[8] = { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77};
//uint8_t new_key_data16[16] = { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF};
int len = 0;
//uint8_t PICC_MASTER_KEY8[8] = { 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47};
uint8_t PICC_MASTER_KEY16[16] = { 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f };
uint8_t null_key_data8[8] = {0x00};
//uint8_t null_key_data16[16] = {0x00};
//uint8_t new_key_data8[8] = { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77};
//uint8_t new_key_data16[16] = { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF};
uint8_t resp[256] = {0x00};
uint8_t resp[256] = {0x00};
uint8_t IV[16] = {0x00};
size_t datalen = datain[0];
size_t datalen = datain[0];
uint8_t cmd[40] = {0x00};
uint8_t encRndB[16] = {0x00};
uint8_t decRndB[16] = {0x00};
uint8_t nonce[16] = {0x00};
uint8_t both[32] = {0x00};
uint8_t encBoth[32] = {0x00};
uint8_t cmd[40] = {0x00};
uint8_t encRndB[16] = {0x00};
uint8_t decRndB[16] = {0x00};
uint8_t both[32] = {0x00};
InitDesfireCard();
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
// 3 olika sätt att authenticera. AUTH (CRC16) , AUTH_ISO (CRC32) , AUTH_AES (CRC32)
// 4 olika crypto algo DES, 3DES, 3K3DES, AES
// 3 olika kommunikations sätt, PLAIN,MAC,CRYPTO
// des, nyckel 0,
switch (mode){
case 1:{
InitDesfireCard();
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
// 3 different way to authenticate AUTH (CRC16) , AUTH_ISO (CRC32) , AUTH_AES (CRC32)
// 4 different crypto arg1 DES, 3DES, 3K3DES, AES
// 3 different communication modes, PLAIN,MAC,CRYPTO
// des, key 0,
switch (arg0) {
case 1: {
uint8_t keybytes[16];
uint8_t RndA[8] = {0x00};
uint8_t RndB[8] = {0x00};
if (algo == 2) {
if (datain[1] == 0xff){
memcpy(keybytes,PICC_MASTER_KEY16,16);
if (arg1 == 2) {
if (datain[1] == 0xff) {
memcpy(keybytes, PICC_MASTER_KEY16, 16);
} else {
memcpy(keybytes, datain+1, datalen);
memcpy(keybytes, datain + 1, datalen);
}
} else {
if (algo == 1) {
if (datain[1] == 0xff){
memcpy(keybytes,null_key_data8,8);
} else{
memcpy(keybytes, datain+1, datalen);
}
if (arg1 == 1) {
if (datain[1] == 0xff) {
uint8_t null_key_data8[8] = {0x00};
memcpy(keybytes, null_key_data8, 8);
} else {
memcpy(keybytes, datain + 1, datalen);
}
}
}
struct desfire_key defaultkey = {0};
desfirekey_t key = &defaultkey;
if (algo == 2)
if (arg1 == 2)
Desfire_3des_key_new_with_version(keybytes, key);
else if (algo ==1)
Desfire_des_key_new(keybytes, key);
else if (arg1 == 1)
Desfire_des_key_new(keybytes, key);
cmd[0] = AUTHENTICATE;
cmd[1] = keyno; //keynumber
cmd[1] = arg2; //keynumber
len = DesfireAPDU(cmd, 2, resp);
if ( !len ) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) {
if (!len) {
if (DBGLEVEL >= DBG_ERROR) {
DbpString("Authentication failed. Card timeout.");
}
OnError(3);
return;
}
if ( resp[2] == 0xaf ){
if (resp[2] == 0xaf) {
} else {
DbpString("Authentication failed. Invalid key number.");
OnError(3);
return;
}
memcpy( encRndB, resp+3, 8);
if (algo == 2)
memcpy(encRndB, resp + 3, 8);
if (arg1 == 2)
tdes_dec(&decRndB, &encRndB, key->data);
else if (algo == 1)
des_dec(&decRndB, &encRndB, key->data);
else if (arg1 == 1)
des_dec(&decRndB, &encRndB, key->data);
memcpy(RndB, decRndB, 8);
rol(decRndB,8);
rol(decRndB, 8);
// This should be random
uint8_t decRndA[8] = {0x00};
memcpy(RndA, decRndA, 8);
uint8_t encRndA[8] = {0x00};
if (algo == 2)
if (arg1 == 2)
tdes_dec(&encRndA, &decRndA, key->data);
else if (algo == 1)
des_dec(&encRndA, &decRndA, key->data);
else if (arg1 == 1)
des_dec(&encRndA, &decRndA, key->data);
memcpy(both, encRndA, 8);
for (int x = 0; x < 8; x++) {
decRndB[x] = decRndB[x] ^ encRndA[x];
}
if (algo == 2)
if (arg1 == 2)
tdes_dec(&encRndB, &decRndB, key->data);
else if (algo == 1)
des_dec(&encRndB, &decRndB, key->data);
else if (arg1 == 1)
des_dec(&encRndB, &decRndB, key->data);
memcpy(both + 8, encRndB, 8);
cmd[0] = ADDITIONAL_FRAME;
memcpy(cmd+1, both, 16 );
memcpy(cmd + 1, both, 16);
len = DesfireAPDU(cmd, 17, resp);
if ( !len ) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) {
if (!len) {
if (DBGLEVEL >= DBG_ERROR) {
DbpString("Authentication failed. Card timeout.");
}
OnError(3);
return;
}
if ( resp[2] == 0x00 ){
if (resp[2] == 0x00) {
struct desfire_key sessionKey = {0};
desfirekey_t skey = &sessionKey;
Desfire_session_key_new( RndA, RndB , key, skey );
Desfire_session_key_new(RndA, RndB, key, skey);
//print_result("SESSION : ", skey->data, 8);
memcpy(encRndA, resp+3, 8);
if (algo == 2)
memcpy(encRndA, resp + 3, 8);
if (arg1 == 2)
tdes_dec(&encRndA, &encRndA, key->data);
else if (algo == 1)
des_dec(&encRndA, &encRndA, key->data);
rol(decRndA,8);
else if (arg1 == 1)
des_dec(&encRndA, &encRndA, key->data);
rol(decRndA, 8);
for (int x = 0; x < 8; x++) {
if (decRndA[x] != encRndA[x]) {
DbpString("Authentication failed. Cannot varify PICC.");
@ -315,86 +314,86 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain
return;
}
}
//Change the selected key to a new value.
/*
// Current key is a 3DES key, change it to a DES key
if (algo == 2) {
if (arg1 == 2) {
cmd[0] = CHANGE_KEY;
cmd[1] = keyno;
cmd[1] = arg2;
uint8_t newKey[16] = {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77};
uint8_t first, second;
uint8_t buff1[8] = {0x00};
uint8_t buff2[8] = {0x00};
uint8_t buff3[8] = {0x00};
memcpy(buff1,newKey, 8);
memcpy(buff2,newKey + 8, 8);
compute_crc(CRC_14443_A, newKey, 16, &first, &second);
memcpy(buff3, &first, 1);
memcpy(buff3 + 1, &second, 1);
tdes_dec(&buff1, &buff1, skey->data);
memcpy(cmd+2,buff1,8);
for (int x = 0; x < 8; x++) {
buff2[x] = buff2[x] ^ buff1[x];
}
tdes_dec(&buff2, &buff2, skey->data);
memcpy(cmd+10,buff2,8);
for (int x = 0; x < 8; x++) {
buff3[x] = buff3[x] ^ buff2[x];
}
tdes_dec(&buff3, &buff3, skey->data);
memcpy(cmd+18,buff3,8);
// The command always times out on the first attempt, this will retry until a response
// is recieved.
len = 0;
while(!len) {
len = DesfireAPDU(cmd,26,resp);
}
} else {
// Current key is a DES key, change it to a 3DES key
if (algo == 1) {
if (arg1 == 1) {
cmd[0] = CHANGE_KEY;
cmd[1] = keyno;
cmd[1] = arg2;
uint8_t newKey[16] = {0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f};
uint8_t first, second;
uint8_t buff1[8] = {0x00};
uint8_t buff2[8] = {0x00};
uint8_t buff3[8] = {0x00};
memcpy(buff1,newKey, 8);
memcpy(buff2,newKey + 8, 8);
compute_crc(CRC_14443_A, newKey, 16, &first, &second);
memcpy(buff3, &first, 1);
memcpy(buff3 + 1, &second, 1);
des_dec(&buff1, &buff1, skey->data);
memcpy(cmd+2,buff1,8);
for (int x = 0; x < 8; x++) {
buff2[x] = buff2[x] ^ buff1[x];
}
des_dec(&buff2, &buff2, skey->data);
memcpy(cmd+10,buff2,8);
for (int x = 0; x < 8; x++) {
buff3[x] = buff3[x] ^ buff2[x];
}
des_dec(&buff3, &buff3, skey->data);
memcpy(cmd+18,buff3,8);
// The command always times out on the first attempt, this will retry until a response
// is recieved.
len = 0;
@ -404,168 +403,170 @@ void MifareDES_Auth1(uint8_t mode, uint8_t algo, uint8_t keyno, uint8_t *datain
}
}
*/
OnSuccess();
if (algo == 2)
cmd_send(CMD_ACK,1,0,0,skey->data,16);
else if (algo == 1)
cmd_send(CMD_ACK,1,0,0,skey->data,8);
if (arg1 == 2)
reply_old(CMD_ACK, 1, 0, 0, skey->data, 16);
else if (arg1 == 1)
reply_old(CMD_ACK, 1, 0, 0, skey->data, 8);
} else {
DbpString("Authentication failed.");
OnError(6);
return;
}
}
break;
case 2:
//SendDesfireCommand(AUTHENTICATE_ISO, &arg2, resp);
break;
case 3: {
//defaultkey
uint8_t keybytes[16] = {0x00};
if (datain[1] == 0xff) {
memcpy(keybytes, PICC_MASTER_KEY16, 16);
} else {
memcpy(keybytes, datain + 1, datalen);
}
break;
case 2:
//SendDesfireCommand(AUTHENTICATE_ISO, &keyno, resp);
break;
case 3:{
//defaultkey
uint8_t keybytes[16] = {0x00};
if (datain[1] == 0xff){
memcpy(keybytes,PICC_MASTER_KEY16,16);
} else{
memcpy(keybytes, datain+1, datalen);
}
struct desfire_key defaultkey = {0x00};
desfirekey_t key = &defaultkey;
Desfire_aes_key_new( keybytes, key);
AesCtx ctx;
if ( AesCtxIni(&ctx, IV, key->data, KEY128, CBC) < 0 ){
if( MF_DBGLEVEL >= 4) {
DbpString("AES context failed to init");
}
OnError(7);
return;
}
cmd[0] = AUTHENTICATE_AES;
cmd[1] = 0x00; //keynumber
len = DesfireAPDU(cmd, 2, resp);
if ( !len ) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) {
DbpString("Authentication failed. Card timeout.");
}
OnError(3);
return;
}
memcpy( encRndB, resp+3, 16);
// dekryptera tagnonce.
AesDecrypt(&ctx, encRndB, decRndB, 16);
rol(decRndB,16);
memcpy(both, nonce,16);
memcpy(both+16, decRndB ,16 );
AesEncrypt(&ctx, both, encBoth, 32 );
cmd[0] = ADDITIONAL_FRAME;
memcpy(cmd+1, encBoth, 32 );
len = DesfireAPDU(cmd, 33, resp); // 1 + 32 == 33
if ( !len ) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) {
DbpString("Authentication failed. Card timeout.");
}
struct desfire_key defaultkey = {0x00};
desfirekey_t key = &defaultkey;
Desfire_aes_key_new(keybytes, key);
AesCtx ctx;
uint8_t IV[16] = {0x00};
if (AesCtxIni(&ctx, IV, key->data, KEY128, CBC) < 0) {
if (DBGLEVEL >= 4) {
DbpString("AES context failed to init");
}
OnError(7);
return;
}
cmd[0] = AUTHENTICATE_AES;
cmd[1] = 0x00; //keynumber
len = DesfireAPDU(cmd, 2, resp);
if (!len) {
if (DBGLEVEL >= DBG_ERROR) {
DbpString("Authentication failed. Card timeout.");
}
OnError(3);
return;
}
if ( resp[2] == 0x00 ){
// Create AES Session key
struct desfire_key sessionKey = {0};
desfirekey_t skey = &sessionKey;
Desfire_session_key_new( nonce, decRndB , key, skey );
print_result("SESSION : ", skey->data, 16);
} else {
DbpString("Authentication failed.");
OnError(7);
return;
}
break;
}
}
OnSuccess();
cmd_send(CMD_ACK,1,len,0,resp,len);
return;
}
memcpy(encRndB, resp + 3, 16);
// dekryptera tagnonce.
AesDecrypt(&ctx, encRndB, decRndB, 16);
rol(decRndB, 16);
uint8_t nonce[16] = {0x00};
memcpy(both, nonce, 16);
memcpy(both + 16, decRndB, 16);
uint8_t encBoth[32] = {0x00};
AesEncrypt(&ctx, both, encBoth, 32);
cmd[0] = ADDITIONAL_FRAME;
memcpy(cmd + 1, encBoth, 32);
len = DesfireAPDU(cmd, 33, resp); // 1 + 32 == 33
if (!len) {
if (DBGLEVEL >= DBG_ERROR) {
DbpString("Authentication failed. Card timeout.");
}
OnError(3);
return;
}
if (resp[2] == 0x00) {
// Create AES Session key
struct desfire_key sessionKey = {0};
desfirekey_t skey = &sessionKey;
Desfire_session_key_new(nonce, decRndB, key, skey);
print_result("SESSION : ", skey->data, 16);
} else {
DbpString("Authentication failed.");
OnError(7);
return;
}
break;
}
}
OnSuccess();
reply_old(CMD_ACK, 1, len, 0, resp, len);
}
// 3 olika ISO sätt att skicka data till DESFIRE (direkt, inkapslat, inkapslat ISO)
// 3 different ISO ways to send data to a DESFIRE (direct, capsuled, capsuled ISO)
// cmd = cmd bytes to send
// cmd_len = length of cmd
// dataout = pointer to response data array
int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout){
int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout) {
size_t len = 0;
size_t wrappedLen = 0;
uint8_t wCmd[USB_CMD_DATA_SIZE] = {0x00};
uint8_t resp[MAX_FRAME_SIZE];
size_t len = 0;
size_t wrappedLen = 0;
uint8_t wCmd[PM3_CMD_DATA_SIZE] = {0x00};
uint8_t resp[MAX_FRAME_SIZE];
uint8_t par[MAX_PARITY_SIZE];
wrappedLen = CreateAPDU( cmd, cmd_len, wCmd);
if (MF_DBGLEVEL >= 4)
print_result("WCMD <--: ", wCmd, wrappedLen);
ReaderTransmit( wCmd, wrappedLen, NULL);
wrappedLen = CreateAPDU(cmd, cmd_len, wCmd);
len = ReaderReceive(resp, par);
if ( !len ) {
if (MF_DBGLEVEL >= 4) Dbprintf("fukked");
return false; //DATA LINK ERROR
}
// if we received an I- or R(ACK)-Block with a block number equal to the
// current block number, toggle the current block number
else if (len >= 4 // PCB+CID+CRC = 4 bytes
&& ((resp[0] & 0xC0) == 0 // I-Block
|| (resp[0] & 0xD0) == 0x80) // R-Block with ACK bit set to 0
&& (resp[0] & 0x01) == pcb_blocknum) // equal block numbers
{
pcb_blocknum ^= 1; //toggle next block
}
if (DBGLEVEL >= 4)
print_result("WCMD <--: ", wCmd, wrappedLen);
memcpy(dataout, resp, len);
return len;
}
ReaderTransmit(wCmd, wrappedLen, NULL);
len = ReaderReceive(resp, par);
if (!len) {
if (DBGLEVEL >= 4) Dbprintf("fukked");
return false; //DATA LINK ERROR
}
// if we received an I- or R(ACK)-Block with a block number equal to the
// current block number, toggle the current block number
else if (len >= 4 // PCB+CID+CRC = 4 bytes
&& ((resp[0] & 0xC0) == 0 // I-Block
|| (resp[0] & 0xD0) == 0x80) // R-Block with ACK bit set to 0
&& (resp[0] & 0x01) == pcb_blocknum) { // equal block numbers
pcb_blocknum ^= 1; //toggle next block
}
memcpy(dataout, resp, len);
return len;
}
// CreateAPDU
size_t CreateAPDU( uint8_t *datain, size_t len, uint8_t *dataout){
size_t cmdlen = MIN(len+4, USB_CMD_DATA_SIZE-1);
size_t CreateAPDU(uint8_t *datain, size_t len, uint8_t *dataout) {
uint8_t cmd[cmdlen];
memset(cmd, 0, cmdlen);
cmd[0] = 0x0A; // 0x0A = skicka cid, 0x02 = ingen cid. Särskilda bitar //
cmd[0] |= pcb_blocknum; // OR the block number into the PCB
cmd[1] = 0x00; // CID: 0x00 //TODO: allow multiple selected cards
memcpy(cmd+2, datain, len);
AddCrc14A(cmd, len+2);
memcpy(dataout, cmd, cmdlen);
return cmdlen;
size_t cmdlen = MIN(len + 4, PM3_CMD_DATA_SIZE - 1);
uint8_t cmd[cmdlen];
memset(cmd, 0, cmdlen);
cmd[0] = 0x0A; // 0x0A = send cid, 0x02 = no cid.
cmd[0] |= pcb_blocknum; // OR the block number into the PCB
cmd[1] = 0x00; // CID: 0x00 //TODO: allow multiple selected cards
memcpy(cmd + 2, datain, len);
AddCrc14A(cmd, len + 2);
memcpy(dataout, cmd, cmdlen);
return cmdlen;
}
// crc_update(&desfire_crc32, 0, 1); /* CMD_WRITE */
// crc_update(&desfire_crc32, addr, addr_sz);
// crc_update(&desfire_crc32, byte, 8);
// uint32_t crc = crc_finish(&desfire_crc32);
// crc_update(&desfire_crc32, 0, 1); /* CMD_WRITE */
// crc_update(&desfire_crc32, addr, addr_sz);
// crc_update(&desfire_crc32, byte, 8);
// uint32_t crc = crc_finish(&desfire_crc32);
void OnSuccess(){
pcb_blocknum = 0;
ReaderTransmit(deselect_cmd, 3 , NULL);
mifare_ultra_halt();
switch_off();
void OnSuccess() {
pcb_blocknum = 0;
ReaderTransmit(deselect_cmd, 3, NULL);
mifare_ultra_halt();
switch_off();
}
void OnError(uint8_t reason){
cmd_send(CMD_ACK,0,reason,0,0,0);
OnSuccess();
void OnError(uint8_t reason) {
reply_old(CMD_ACK, 0, reason, 0, 0, 0);
OnSuccess();
}

View file

@ -6,7 +6,6 @@
#include "apps.h"
#include "string.h"
#include "BigBuf.h"
#include "iso14443crc.h"
#include "iso14443a.h"
#include "desfire_key.h"
#include "mifareutil.h"

1199
armsrc/mifaresim.c Normal file

File diff suppressed because it is too large Load diff

39
armsrc/mifaresim.h Normal file
View file

@ -0,0 +1,39 @@
//-----------------------------------------------------------------------------
// Merlok - June 2011, 2012
// Gerhard de Koning Gans - May 2008
// Hagen Fritsch - June 2010
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Mifare Classic Card Simulation
//-----------------------------------------------------------------------------
#ifndef __MIFARESIM_H
#define __MIFARESIM_H
#include <stdint.h>
#ifndef CheckCrc14A
# define CheckCrc14A(data, len) check_crc(CRC_14443_A, (data), (len))
#endif
void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain);
#define AC_DATA_READ 0
#define AC_DATA_WRITE 1
#define AC_DATA_INC 2
#define AC_DATA_DEC_TRANS_REST 3
#define AC_KEYA_READ 0
#define AC_KEYA_WRITE 1
#define AC_KEYB_READ 2
#define AC_KEYB_WRITE 3
#define AC_AC_READ 4
#define AC_AC_WRITE 5
#define AUTHKEYA 0
#define AUTHKEYB 1
#define AUTHKEYNONE 0xff
#endif

View file

@ -1,324 +1,327 @@
//-----------------------------------------------------------------------------
// Merlok - 2012
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Routines to support mifare classic sniffer.
//-----------------------------------------------------------------------------
#include "mifaresniff.h"
//static int sniffState = SNF_INIT;
static uint8_t sniffUIDType = 0;
static uint8_t sniffUID[10] = {0,0,0,0,0,0,0,0,0,0};
static uint8_t sniffATQA[2] = {0,0};
static uint8_t sniffSAK = 0;
static uint8_t sniffBuf[17];
static uint32_t timerData = 0;
//-----------------------------------------------------------------------------
// MIFARE sniffer.
//
// if no activity for 2sec, it sends the collected data to the client.
//-----------------------------------------------------------------------------
// "hf mf sniff"
void RAMFUNC SniffMifare(uint8_t param) {
// param:
// bit 0 - trigger from first card answer
// bit 1 - trigger from first reader 7-bit request
// C(red) A(yellow) B(green)
LEDsoff();
iso14443a_setup(FPGA_HF_ISO14443A_SNIFFER);
// Allocate memory from BigBuf for some buffers
// free all previous allocations first
BigBuf_free(); BigBuf_Clear_ext(false);
clear_trace();
set_tracing(true);
// The command (reader -> tag) that we're receiving.
uint8_t receivedCmd[MAX_MIFARE_FRAME_SIZE] = {0x00};
uint8_t receivedCmdPar[MAX_MIFARE_PARITY_SIZE] = {0x00};
// The response (tag -> reader) that we're receiving.
uint8_t receivedResp[MAX_MIFARE_FRAME_SIZE] = {0x00};
uint8_t receivedRespPar[MAX_MIFARE_PARITY_SIZE] = {0x00};
// allocate the DMA buffer, used to stream samples from the FPGA
uint8_t *dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE);
uint8_t *data = dmaBuf;
uint8_t previous_data = 0;
int maxDataLen = 0;
int dataLen = 0;
bool ReaderIsActive = false;
bool TagIsActive = false;
// We won't start recording the frames that we acquire until we trigger;
// a good trigger condition to get started is probably when we see a
// response from the tag.
// triggered == false -- to wait first for card
//bool triggered = !(param & 0x03);
// Set up the demodulator for tag -> reader responses.
DemodInit(receivedResp, receivedRespPar);
// Set up the demodulator for the reader -> tag commands
UartInit(receivedCmd, receivedCmdPar);
// Setup and start DMA.
// set transfer address and number of bytes. Start transfer.
if ( !FpgaSetupSscDma(dmaBuf, DMA_BUFFER_SIZE) ){
if (MF_DBGLEVEL > 1) Dbprintf("[!] FpgaSetupSscDma failed. Exiting");
return;
}
tUart* uart = GetUart();
tDemod* demod = GetDemod();
MfSniffInit();
uint32_t sniffCounter = 0;
// loop and listen
while (!BUTTON_PRESS()) {
WDT_HIT();
LED_A_ON();
/*
if ((sniffCounter & 0x0000FFFF) == 0) { // from time to time
// check if a transaction is completed (timeout after 2000ms).
// if yes, stop the DMA transfer and send what we have so far to the client
if (BigBuf_get_traceLen()) {
MfSniffSend();
// Reset everything - we missed some sniffed data anyway while the DMA was stopped
sniffCounter = 0;
dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE);
data = dmaBuf;
maxDataLen = 0;
ReaderIsActive = false;
TagIsActive = false;
FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE); // set transfer address and number of bytes. Start transfer.
}
}
*/
// number of bytes we have processed so far
int register readBufDataP = data - dmaBuf;
// number of bytes already transferred
int register dmaBufDataP = DMA_BUFFER_SIZE - AT91C_BASE_PDC_SSC->PDC_RCR;
if (readBufDataP <= dmaBufDataP) // we are processing the same block of data which is currently being transferred
dataLen = dmaBufDataP - readBufDataP; // number of bytes still to be processed
else
dataLen = DMA_BUFFER_SIZE - readBufDataP + dmaBufDataP; // number of bytes still to be processed
// test for length of buffer
if (dataLen > maxDataLen) { // we are more behind than ever...
maxDataLen = dataLen;
if (dataLen > (9 * DMA_BUFFER_SIZE / 10)) {
Dbprintf("[!] blew circular buffer! | datalen %u", dataLen);
break;
}
}
if (dataLen < 1) continue;
// primary buffer was stopped ( <-- we lost data!
if (!AT91C_BASE_PDC_SSC->PDC_RCR) {
AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t)dmaBuf;
AT91C_BASE_PDC_SSC->PDC_RCR = DMA_BUFFER_SIZE;
Dbprintf("[-] RxEmpty ERROR | data length %d", dataLen); // temporary
}
// secondary buffer sets as primary, secondary buffer was stopped
if (!AT91C_BASE_PDC_SSC->PDC_RNCR) {
AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t)dmaBuf;
AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE;
}
LED_A_OFF();
// Need two samples to feed Miller and Manchester-Decoder
if (sniffCounter & 0x01) {
// no need to try decoding tag data if the reader is sending
if (!TagIsActive) {
uint8_t readerbyte = (previous_data & 0xF0) | (*data >> 4);
if (MillerDecoding(readerbyte, (sniffCounter-1)*4)) {
LogTrace(receivedCmd, uart->len, 0, 0, NULL, true);
DemodReset();
UartReset();
}
ReaderIsActive = (uart->state != STATE_UNSYNCD);
}
// no need to try decoding tag data if the reader is sending
if (!ReaderIsActive) {
uint8_t tagbyte = (previous_data << 4) | (*data & 0x0F);
if (ManchesterDecoding(tagbyte, 0, (sniffCounter-1)*4)) {
LogTrace(receivedResp, demod->len, 0, 0, NULL, false);
DemodReset();
UartReset();
}
TagIsActive = (demod->state != DEMOD_UNSYNCD);
}
}
previous_data = *data;
sniffCounter++;
data++;
if (data == dmaBuf + DMA_BUFFER_SIZE)
data = dmaBuf;
} // main cycle
MfSniffEnd();
switch_off();
}
void MfSniffInit(void){
memset(sniffUID, 0x00, sizeof(sniffUID));
memset(sniffATQA, 0x00, sizeof(sniffATQA));
memset(sniffBuf, 0x00, sizeof(sniffBuf));
sniffSAK = 0;
sniffUIDType = SNF_UID_4;
timerData = 0;
}
void MfSniffEnd(void){
LED_B_ON();
cmd_send(CMD_ACK,0,0,0,0,0);
LED_B_OFF();
}
/*
bool RAMFUNC MfSniffLogic(const uint8_t *data, uint16_t len, uint8_t *parity, uint16_t bitCnt, bool reader) {
// reset on 7-Bit commands from reader
if (reader && (len == 1) && (bitCnt == 7)) {
sniffState = SNF_INIT;
}
switch (sniffState) {
case SNF_INIT:{
// REQA,WUPA or MAGICWUP from reader
if ((len == 1) && (reader) && (bitCnt == 7) ) {
MfSniffInit();
sniffState = (data[0] == MIFARE_MAGICWUPC1) ? SNF_MAGIC_WUPC2 : SNF_ATQA;
}
break;
}
case SNF_MAGIC_WUPC2: {
if ((len == 1) && (reader) && (data[0] == MIFARE_MAGICWUPC2) ) {
sniffState = SNF_CARD_IDLE;
}
break;
}
case SNF_ATQA:{
// ATQA from tag
if ((!reader) && (len == 2)) {
sniffATQA[0] = data[0];
sniffATQA[1] = data[1];
sniffState = SNF_UID;
}
break;
}
case SNF_UID: {
if ( !reader ) break;
if ( len != 9 ) break;
if ( !CheckCrc14443(CRC_14443_A, data, 9)) break;
if ( data[1] != 0x70 ) break;
Dbprintf("[!] UID | %x", data[0]);
if ((data[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT)) {
// UID_4 - select 4 Byte UID from reader
memcpy(sniffUID, data+2, 4);
sniffUIDType = SNF_UID_4;
sniffState = SNF_SAK;
} else if ((data[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2)) {
// UID_7 - Select 2nd part of 7 Byte UID
// get rid of 0x88
sniffUID[0] = sniffUID[1];
sniffUID[1] = sniffUID[2];
sniffUID[2] = sniffUID[3];
//new uid bytes
memcpy(sniffUID+3, data+2, 4);
sniffUIDType = SNF_UID_7;
sniffState = SNF_SAK;
} else if ((data[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_3)) {
// UID_10 - Select 3nd part of 10 Byte UID
// 3+3+4 = 10.
// get ride of previous 0x88
sniffUID[3] = sniffUID[4];
sniffUID[4] = sniffUID[5];
sniffUID[5] = sniffUID[6];
// new uid bytes
memcpy(sniffUID+6, data+2, 4);
sniffUIDType = SNF_UID_10;
sniffState = SNF_SAK;
}
break;
}
case SNF_SAK:{
// SAK from card?
if ((!reader) && (len == 3) && (CheckCrc14443(CRC_14443_A, data, 3))) {
sniffSAK = data[0];
// CL2 UID part to be expected
if (( sniffSAK == 0x04) && (sniffUIDType == SNF_UID_4)) {
sniffState = SNF_UID;
// CL3 UID part to be expected
} else if ((sniffSAK == 0x04) && (sniffUIDType == SNF_UID_7)) {
sniffState = SNF_UID;
} else {
// select completed
sniffState = SNF_CARD_IDLE;
}
}
break;
}
case SNF_CARD_IDLE:{ // trace the card select sequence
sniffBuf[0] = 0xFF;
sniffBuf[1] = 0xFF;
memcpy(sniffBuf + 2, sniffUID, sizeof(sniffUID));
memcpy(sniffBuf + 12, sniffATQA, sizeof(sniffATQA));
sniffBuf[14] = sniffSAK;
sniffBuf[15] = 0xFF;
sniffBuf[16] = 0xFF;
LogTrace(sniffBuf, sizeof(sniffBuf), 0, 0, NULL, true);
sniffState = SNF_CARD_CMD;
} // intentionally no break;
case SNF_CARD_CMD:{
LogTrace(data, len, 0, 0, NULL, reader);
timerData = GetTickCount();
break;
}
default:
sniffState = SNF_INIT;
break;
}
return false;
}
*/
void RAMFUNC MfSniffSend() {
uint16_t tracelen = BigBuf_get_traceLen();
uint16_t chunksize = 0;
int packlen = tracelen; // total number of bytes to send
uint8_t *data = BigBuf_get_addr();
while (packlen > 0) {
LED_B_ON();
chunksize = MIN(USB_CMD_DATA_SIZE, packlen); // chunk size 512
cmd_send(CMD_ACK, 1, tracelen, chunksize, data + tracelen - packlen, chunksize);
packlen -= chunksize;
LED_B_OFF();
}
LED_B_ON();
cmd_send(CMD_ACK, 2, 0, 0, 0, 0); // 2 == data transfer finished.
LED_B_OFF();
}
//-----------------------------------------------------------------------------
// Merlok - 2012
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Routines to support mifare classic sniffer.
//-----------------------------------------------------------------------------
#include "mifaresniff.h"
#ifndef CheckCrc14A
# define CheckCrc14A(data, len) check_crc(CRC_14443_A, (data), (len))
#endif
//static int sniffState = SNF_INIT;
static uint8_t sniffUIDType = 0;
static uint8_t sniffUID[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static uint8_t sniffATQA[2] = {0, 0};
static uint8_t sniffSAK = 0;
static uint8_t sniffBuf[17];
static uint32_t timerData = 0;
//-----------------------------------------------------------------------------
// MIFARE sniffer.
//
// if no activity for 2sec, it sends the collected data to the client.
//-----------------------------------------------------------------------------
// "hf mf sniff"
void RAMFUNC SniffMifare(uint8_t param) {
// param:
// bit 0 - trigger from first card answer
// bit 1 - trigger from first reader 7-bit request
// C(red) A(yellow) B(green)
LEDsoff();
iso14443a_setup(FPGA_HF_ISO14443A_SNIFFER);
// Allocate memory from BigBuf for some buffers
// free all previous allocations first
BigBuf_free();
BigBuf_Clear_ext(false);
clear_trace();
set_tracing(true);
// The command (reader -> tag) that we're receiving.
uint8_t receivedCmd[MAX_MIFARE_FRAME_SIZE] = {0x00};
uint8_t receivedCmdPar[MAX_MIFARE_PARITY_SIZE] = {0x00};
// The response (tag -> reader) that we're receiving.
uint8_t receivedResp[MAX_MIFARE_FRAME_SIZE] = {0x00};
uint8_t receivedRespPar[MAX_MIFARE_PARITY_SIZE] = {0x00};
// allocate the DMA buffer, used to stream samples from the FPGA
uint8_t *dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE);
uint8_t *data = dmaBuf;
uint8_t previous_data = 0;
int dataLen, maxDataLen = 0;
bool ReaderIsActive = false;
bool TagIsActive = false;
// We won't start recording the frames that we acquire until we trigger;
// a good trigger condition to get started is probably when we see a
// response from the tag.
// triggered == false -- to wait first for card
//bool triggered = !(param & 0x03);
// Set up the demodulator for tag -> reader responses.
DemodInit(receivedResp, receivedRespPar);
// Set up the demodulator for the reader -> tag commands
UartInit(receivedCmd, receivedCmdPar);
// Setup and start DMA.
// set transfer address and number of bytes. Start transfer.
if (!FpgaSetupSscDma(dmaBuf, DMA_BUFFER_SIZE)) {
if (DBGLEVEL > 1) Dbprintf("[!] FpgaSetupSscDma failed. Exiting");
return;
}
tUart *uart = GetUart();
tDemod *demod = GetDemod();
MfSniffInit();
uint32_t sniffCounter = 0;
// loop and listen
while (!BUTTON_PRESS()) {
WDT_HIT();
LED_A_ON();
/*
if ((sniffCounter & 0x0000FFFF) == 0) { // from time to time
// check if a transaction is completed (timeout after 2000ms).
// if yes, stop the DMA transfer and send what we have so far to the client
if (BigBuf_get_traceLen()) {
MfSniffSend();
// Reset everything - we missed some sniffed data anyway while the DMA was stopped
sniffCounter = 0;
dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE);
data = dmaBuf;
maxDataLen = 0;
ReaderIsActive = false;
TagIsActive = false;
FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE); // set transfer address and number of bytes. Start transfer.
}
}
*/
// number of bytes we have processed so far
int register readBufDataP = data - dmaBuf;
// number of bytes already transferred
int register dmaBufDataP = DMA_BUFFER_SIZE - AT91C_BASE_PDC_SSC->PDC_RCR;
if (readBufDataP <= dmaBufDataP) // we are processing the same block of data which is currently being transferred
dataLen = dmaBufDataP - readBufDataP; // number of bytes still to be processed
else
dataLen = DMA_BUFFER_SIZE - readBufDataP + dmaBufDataP; // number of bytes still to be processed
// test for length of buffer
if (dataLen > maxDataLen) { // we are more behind than ever...
maxDataLen = dataLen;
if (dataLen > (9 * DMA_BUFFER_SIZE / 10)) {
Dbprintf("[!] blew circular buffer! | datalen %u", dataLen);
break;
}
}
if (dataLen < 1) continue;
// primary buffer was stopped ( <-- we lost data!
if (!AT91C_BASE_PDC_SSC->PDC_RCR) {
AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t)dmaBuf;
AT91C_BASE_PDC_SSC->PDC_RCR = DMA_BUFFER_SIZE;
Dbprintf("[-] RxEmpty ERROR | data length %d", dataLen); // temporary
}
// secondary buffer sets as primary, secondary buffer was stopped
if (!AT91C_BASE_PDC_SSC->PDC_RNCR) {
AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t)dmaBuf;
AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE;
}
LED_A_OFF();
// Need two samples to feed Miller and Manchester-Decoder
if (sniffCounter & 0x01) {
// no need to try decoding tag data if the reader is sending
if (!TagIsActive) {
uint8_t readerbyte = (previous_data & 0xF0) | (*data >> 4);
if (MillerDecoding(readerbyte, (sniffCounter - 1) * 4)) {
LogTrace(receivedCmd, uart->len, 0, 0, NULL, true);
DemodReset();
UartReset();
}
ReaderIsActive = (uart->state != STATE_UNSYNCD);
}
// no need to try decoding tag data if the reader is sending
if (!ReaderIsActive) {
uint8_t tagbyte = (previous_data << 4) | (*data & 0x0F);
if (ManchesterDecoding(tagbyte, 0, (sniffCounter - 1) * 4)) {
LogTrace(receivedResp, demod->len, 0, 0, NULL, false);
DemodReset();
UartReset();
}
TagIsActive = (demod->state != DEMOD_UNSYNCD);
}
}
previous_data = *data;
sniffCounter++;
data++;
if (data == dmaBuf + DMA_BUFFER_SIZE)
data = dmaBuf;
} // main cycle
MfSniffEnd();
switch_off();
}
void MfSniffInit(void) {
memset(sniffUID, 0x00, sizeof(sniffUID));
memset(sniffATQA, 0x00, sizeof(sniffATQA));
memset(sniffBuf, 0x00, sizeof(sniffBuf));
sniffSAK = 0;
sniffUIDType = SNF_UID_4;
timerData = 0;
}
void MfSniffEnd(void) {
LED_B_ON();
reply_old(CMD_ACK, 0, 0, 0, 0, 0);
LED_B_OFF();
}
/*
bool RAMFUNC MfSniffLogic(const uint8_t *data, uint16_t len, uint8_t *parity, uint16_t bitCnt, bool reader) {
// reset on 7-Bit commands from reader
if (reader && (len == 1) && (bitCnt == 7)) {
sniffState = SNF_INIT;
}
switch (sniffState) {
case SNF_INIT:{
// REQA,WUPA or MAGICWUP from reader
if ((len == 1) && (reader) && (bitCnt == 7) ) {
MfSniffInit();
sniffState = (data[0] == MIFARE_MAGICWUPC1) ? SNF_MAGIC_WUPC2 : SNF_ATQA;
}
break;
}
case SNF_MAGIC_WUPC2: {
if ((len == 1) && (reader) && (data[0] == MIFARE_MAGICWUPC2) ) {
sniffState = SNF_CARD_IDLE;
}
break;
}
case SNF_ATQA:{
// ATQA from tag
if ((!reader) && (len == 2)) {
sniffATQA[0] = data[0];
sniffATQA[1] = data[1];
sniffState = SNF_UID;
}
break;
}
case SNF_UID: {
if ( !reader ) break;
if ( len != 9 ) break;
if ( !CheckCrc14A(data, 9)) break;
if ( data[1] != 0x70 ) break;
Dbprintf("[!] UID | %x", data[0]);
if ((data[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT)) {
// UID_4 - select 4 Byte UID from reader
memcpy(sniffUID, data+2, 4);
sniffUIDType = SNF_UID_4;
sniffState = SNF_SAK;
} else if ((data[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2)) {
// UID_7 - Select 2nd part of 7 Byte UID
// get rid of 0x88
sniffUID[0] = sniffUID[1];
sniffUID[1] = sniffUID[2];
sniffUID[2] = sniffUID[3];
//new uid bytes
memcpy(sniffUID+3, data+2, 4);
sniffUIDType = SNF_UID_7;
sniffState = SNF_SAK;
} else if ((data[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_3)) {
// UID_10 - Select 3nd part of 10 Byte UID
// 3+3+4 = 10.
// get ride of previous 0x88
sniffUID[3] = sniffUID[4];
sniffUID[4] = sniffUID[5];
sniffUID[5] = sniffUID[6];
// new uid bytes
memcpy(sniffUID+6, data+2, 4);
sniffUIDType = SNF_UID_10;
sniffState = SNF_SAK;
}
break;
}
case SNF_SAK:{
// SAK from card?
if ((!reader) && (len == 3) && (CheckCrc14A(data, 3))) {
sniffSAK = data[0];
// CL2 UID part to be expected
if (( sniffSAK == 0x04) && (sniffUIDType == SNF_UID_4)) {
sniffState = SNF_UID;
// CL3 UID part to be expected
} else if ((sniffSAK == 0x04) && (sniffUIDType == SNF_UID_7)) {
sniffState = SNF_UID;
} else {
// select completed
sniffState = SNF_CARD_IDLE;
}
}
break;
}
case SNF_CARD_IDLE:{ // trace the card select sequence
sniffBuf[0] = 0xFF;
sniffBuf[1] = 0xFF;
memcpy(sniffBuf + 2, sniffUID, sizeof(sniffUID));
memcpy(sniffBuf + 12, sniffATQA, sizeof(sniffATQA));
sniffBuf[14] = sniffSAK;
sniffBuf[15] = 0xFF;
sniffBuf[16] = 0xFF;
LogTrace(sniffBuf, sizeof(sniffBuf), 0, 0, NULL, true);
sniffState = SNF_CARD_CMD;
} // intentionally no break;
case SNF_CARD_CMD:{
LogTrace(data, len, 0, 0, NULL, reader);
timerData = GetTickCount();
break;
}
default:
sniffState = SNF_INIT;
break;
}
return false;
}
*/
void RAMFUNC MfSniffSend() {
uint16_t tracelen = BigBuf_get_traceLen();
int packlen = tracelen; // total number of bytes to send
uint8_t *data = BigBuf_get_addr();
while (packlen > 0) {
LED_B_ON();
uint16_t chunksize = MIN(PM3_CMD_DATA_SIZE, packlen); // chunk size 512
reply_old(CMD_ACK, 1, tracelen, chunksize, data + tracelen - packlen, chunksize);
packlen -= chunksize;
LED_B_OFF();
}
LED_B_ON();
reply_old(CMD_ACK, 2, 0, 0, 0, 0); // 2 == data transfer finished.
LED_B_OFF();
}

View file

@ -1,42 +1,41 @@
//-----------------------------------------------------------------------------
// Merlok - June 2012
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Routines to support mifare classic sniffer.
//-----------------------------------------------------------------------------
#ifndef __MIFARESNIFF_H
#define __MIFARESNIFF_H
#include "proxmark3.h"
#include "apps.h"
#include "util.h"
#include "string.h"
#include "iso14443crc.h"
#include "iso14443a.h"
#include "crapto1/crapto1.h"
#include "mifareutil.h"
#include "common.h"
#define SNF_INIT 0
#define SNF_NO_FIELD 1
#define SNF_ATQA 2
#define SNF_UID 3
#define SNF_SAK 4
#define SNF_CARD_IDLE 5
#define SNF_CARD_CMD 6
#define SNF_MAGIC_WUPC2 7
#define SNF_UID_4 0
#define SNF_UID_7 0
#define SNF_UID_10 0
void MfSniffInit(void);
bool RAMFUNC MfSniffLogic(const uint8_t *data, uint16_t len, uint8_t *parity, uint16_t bitCnt, bool reader);
void RAMFUNC MfSniffSend(void);
void MfSniffEnd(void);
#endif
//-----------------------------------------------------------------------------
// Merlok - June 2012
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Routines to support mifare classic sniffer.
//-----------------------------------------------------------------------------
#ifndef __MIFARESNIFF_H
#define __MIFARESNIFF_H
#include "proxmark3.h"
#include "apps.h"
#include "util.h"
#include "string.h"
#include "iso14443a.h"
#include "crapto1/crapto1.h"
#include "mifareutil.h"
#include "common.h"
#define SNF_INIT 0
#define SNF_NO_FIELD 1
#define SNF_ATQA 2
#define SNF_UID 3
#define SNF_SAK 4
#define SNF_CARD_IDLE 5
#define SNF_CARD_CMD 6
#define SNF_MAGIC_WUPC2 7
#define SNF_UID_4 0
#define SNF_UID_7 0
#define SNF_UID_10 0
void MfSniffInit(void);
bool RAMFUNC MfSniffLogic(const uint8_t *data, uint16_t len, uint8_t *parity, uint16_t bitCnt, bool reader);
void RAMFUNC MfSniffSend(void);
void MfSniffEnd(void);
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,106 +1,116 @@
//-----------------------------------------------------------------------------
// Merlok, May 2011
// Many authors, that makes it possible
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// code for work with mifare cards.
//-----------------------------------------------------------------------------
#ifndef __MIFAREUTIL_H
#define __MIFAREUTIL_H
#include "proxmark3.h"
#include "apps.h"
#include "parity.h"
#include "util.h"
#include "string.h"
#include "iso14443crc.h"
#include "iso14443a.h"
#include "crapto1/crapto1.h"
#include "des.h"
#include "random.h" // fast_prand, prand
// mifare authentication
#define CRYPT_NONE 0
#define CRYPT_ALL 1
#define CRYPT_REQUEST 2
#define AUTH_FIRST 0
#define AUTH_NESTED 2
#define AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation)
#define PRE_AUTHENTICATION_LEADTIME 400 // some (non standard) cards need a pause after select before they are ready for first authentication
// mifare 4bit card answers
#define CARD_ACK 0x0A // 1010 - ACK
#define CARD_NACK_NA 0x04 // 0100 - NACK, not allowed (command not allowed)
#define CARD_NACK_TR 0x05 // 0101 - NACK, transmission error
//mifare emulator states
#define MFEMUL_NOFIELD 0
#define MFEMUL_IDLE 1
#define MFEMUL_SELECT1 2
#define MFEMUL_SELECT2 3
#define MFEMUL_SELECT3 4
#define MFEMUL_AUTH1 5
#define MFEMUL_AUTH2 6
#define MFEMUL_WORK 7
#define MFEMUL_WRITEBL2 8
#define MFEMUL_INTREG_INC 9
#define MFEMUL_INTREG_DEC 10
#define MFEMUL_INTREG_REST 11
#define MFEMUL_HALTED 12
#define cardSTATE_TO_IDLE() cardSTATE = MFEMUL_IDLE; LED_B_OFF(); LED_C_OFF();
//functions
int mifare_sendcmd(uint8_t cmd, uint8_t *data, uint8_t data_size, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing);
int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing);
//-----------------------------------------------------------------------------
// Merlok, May 2011
// Many authors, that makes it possible
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// code for work with mifare cards.
//-----------------------------------------------------------------------------
// mifare classic
int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested);
int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t * ntptr, uint32_t *timing);
int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData);
int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid);
int mifare_classic_halt_ex(struct Crypto1State *pcs);
int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData);
// Ultralight/NTAG...
int mifare_ul_ev1_auth(uint8_t *key, uint8_t *pack);
int mifare_ultra_auth(uint8_t *key);
int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData);
#ifndef __MIFAREUTIL_H
#define __MIFAREUTIL_H
#include "proxmark3.h"
#include "apps.h"
#include "parity.h"
#include "util.h"
#include "string.h"
#include "iso14443a.h"
#include "crapto1/crapto1.h"
#include "des.h"
// mifare authentication
#define CRYPT_NONE 0
#define CRYPT_ALL 1
#define CRYPT_REQUEST 2
#define AUTH_FIRST 0
#define AUTH_NESTED 2
#define AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation)
#define PRE_AUTHENTICATION_LEADTIME 400 // some (non standard) cards need a pause after select before they are ready for first authentication
// reader voltage field detector
#define MF_MINFIELDV 4000
// Mifare 4k/2k/1k/mini Max Block / Max Sector
#define MIFARE_4K_MAXBLOCK 256
#define MIFARE_2K_MAXBLOCK 128
#define MIFARE_1K_MAXBLOCK 64
#define MIFARE_MINI_MAXBLOCK 20
#define MIFARE_MINI_MAXSECTOR 5
#define MIFARE_1K_MAXSECTOR 16
#define MIFARE_2K_MAXSECTOR 32
#define MIFARE_4K_MAXSECTOR 40
//mifare emulator states
#define MFEMUL_NOFIELD 0
#define MFEMUL_IDLE 1
#define MFEMUL_SELECT 2
#define MFEMUL_AUTH1 3
#define MFEMUL_WORK 4
#define MFEMUL_WRITEBL2 5
#define MFEMUL_INTREG_INC 6
#define MFEMUL_INTREG_DEC 7
#define MFEMUL_INTREG_REST 8
#define MFEMUL_HALTED 9
#define cardSTATE_TO_IDLE() cardSTATE = MFEMUL_IDLE; LED_B_OFF(); LED_C_OFF();
#ifndef MifareBlockToSector
#define MifareBlockToSector(block) (block < 128 ? block / 4 : (block - 128) / 16 + 32)
#endif
//functions
int mifare_sendcmd(uint8_t cmd, uint8_t *data, uint8_t data_size, uint8_t *answer, uint8_t *answer_parity, uint32_t *timing);
int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t *answer, uint8_t *answer_parity, uint32_t *timing);
// mifare classic
int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested);
int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing);
int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData);
int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid);
int mifare_classic_halt_ex(struct Crypto1State *pcs);
int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData);
// Ultralight/NTAG...
int mifare_ul_ev1_auth(uint8_t *keybytes, uint8_t *pack);
int mifare_ultra_auth(uint8_t *keybytes);
int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData);
//int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData);
int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData);
int mifare_ultra_halt();
// desfire
int mifare_sendcmd_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t* data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing);
int mifare_sendcmd_special2(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t* data, uint8_t* answer,uint8_t *answer_parity, uint32_t *timing);
int mifare_desfire_des_auth1(uint32_t uid, uint8_t *blockData);
int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData);
// desfire
int mifare_sendcmd_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t *answer, uint8_t *answer_parity, uint32_t *timing);
int mifare_sendcmd_special2(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t *data, uint8_t *answer, uint8_t *answer_parity, uint32_t *timing);
int mifare_desfire_des_auth1(uint32_t uid, uint8_t *blockData);
int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData);
// crypto functions
void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *receivedCmd, int len);
void mf_crypto1_decryptEx(struct Crypto1State *pcs, uint8_t *data_in, int len, uint8_t *data_out);
void mf_crypto1_encrypt(struct Crypto1State *pcs, uint8_t *data, uint16_t len, uint8_t *par);
uint8_t mf_crypto1_encrypt4bit(struct Crypto1State *pcs, uint8_t data);
// Mifare memory structure
uint8_t NumBlocksPerSector(uint8_t sectorNo);
uint8_t FirstBlockOfSector(uint8_t sectorNo);
// emulator functions
void emlClearMem(void);
void emlSetMem(uint8_t *data, int blockNum, int blocksCount);
void emlSetMem_xt(uint8_t *data, int blockNum, int blocksCount, int blockBtWidth);
void emlGetMem(uint8_t *data, int blockNum, int blocksCount);
void emlGetMemBt(uint8_t *data, int bytePtr, int byteCount);
uint64_t emlGetKey(int sectorNum, int keyType);
int emlGetValBl(uint32_t *blReg, uint8_t *blBlock, int blockNum);
void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len);
void mf_crypto1_decryptEx(struct Crypto1State *pcs, uint8_t *data_in, int len, uint8_t *data_out);
void mf_crypto1_encrypt(struct Crypto1State *pcs, uint8_t *data, uint16_t len, uint8_t *par);
void mf_crypto1_encryptEx(struct Crypto1State *pcs, uint8_t *data_in, uint8_t *keystream, uint8_t *data_out, uint16_t len, uint8_t *par);
uint8_t mf_crypto1_encrypt4bit(struct Crypto1State *pcs, uint8_t data);
// Mifare memory structure
uint8_t NumBlocksPerSector(uint8_t sectorNo);
uint8_t FirstBlockOfSector(uint8_t sectorNo);
bool IsSectorTrailer(uint8_t blockNo);
uint8_t SectorTrailer(uint8_t blockNo);
// emulator functions
void emlClearMem(void);
void emlSetMem(uint8_t *data, int blockNum, int blocksCount);
void emlSetMem_xt(uint8_t *data, int blockNum, int blocksCount, int blockBtWidth);
void emlGetMem(uint8_t *data, int blockNum, int blocksCount);
void emlGetMemBt(uint8_t *data, int offset, int byteCount);
uint64_t emlGetKey(int sectorNum, int keyType);
int emlGetValBl(uint32_t *blReg, uint8_t *blBlock, int blockNum);
int emlSetValBl(uint32_t blReg, uint8_t blBlock, int blockNum);
int emlCheckValBl(int blockNum);

View file

@ -1,13 +1,13 @@
/*****************************************************************************
* WARNING
*
* THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY.
*
* USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL
* PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL,
* AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES.
*
* THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS.
* THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY.
*
* USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL
* PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL,
* AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES.
*
* THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS.
*
*****************************************************************************
*
@ -22,7 +22,7 @@
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
* by the Free Software Foundation, or, at your option, any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@ -31,9 +31,9 @@
*
* You should have received a copy of the GNU General Public License
* along with loclass. If not, see <http://www.gnu.org/licenses/>.
*
*
*
*
*
*
****************************************************************************/
/**
@ -41,8 +41,8 @@
This file contains an optimized version of the MAC-calculation algorithm. Some measurements on
a std laptop showed it runs in about 1/3 of the time:
Std: 0.428962
Opt: 0.151609
Std: 0.428962
Opt: 0.151609
Additionally, it is self-reliant, not requiring e.g. bitstreams from the cipherutils, thus can
be easily dropped into a code base.
@ -67,162 +67,159 @@
#define opt_B(s) (((s->b >> 6) ^ (s->b >> 5) ^ (s->b >> 4) ^ (s->b)) & 0x1)
#define opt__select(x,y,r) (4 & (((r & (r << 2)) >> 5) ^ ((r & ~(r << 2)) >> 4) ^ ( (r | r << 2) >> 3)))\
|(2 & (((r | r << 2) >> 6) ^ ( (r | r << 2) >> 1) ^ (r >> 5) ^ r ^ ((x^y) << 1)))\
|(1 & (((r & ~(r << 2)) >> 4) ^ ((r & (r << 2)) >> 3) ^ r ^ x))
|(2 & (((r | r << 2) >> 6) ^ ( (r | r << 2) >> 1) ^ (r >> 5) ^ r ^ ((x^y) << 1)))\
|(1 & (((r & ~(r << 2)) >> 4) ^ ((r & (r << 2)) >> 3) ^ r ^ x))
/*
* Some background on the expression above can be found here...
uint8_t xopt__select(bool x, bool y, uint8_t r)
{
uint8_t r_ls2 = r << 2;
uint8_t r_and_ls2 = r & r_ls2;
uint8_t r_or_ls2 = r | r_ls2;
uint8_t r_ls2 = r << 2;
uint8_t r_and_ls2 = r & r_ls2;
uint8_t r_or_ls2 = r | r_ls2;
//r: r0 r1 r2 r3 r4 r5 r6 r7
//r_ls2: r2 r3 r4 r5 r6 r7 0 0
// z0
// z1
//r: r0 r1 r2 r3 r4 r5 r6 r7
//r_ls2: r2 r3 r4 r5 r6 r7 0 0
// z0
// z1
// uint8_t z0 = (r0 & r2) ^ (r1 & ~r3) ^ (r2 | r4); // <-- original
uint8_t z0 = (r_and_ls2 >> 5) ^ ((r & ~r_ls2) >> 4) ^ ( r_or_ls2 >> 3);
// uint8_t z0 = (r0 & r2) ^ (r1 & ~r3) ^ (r2 | r4); // <-- original
uint8_t z0 = (r_and_ls2 >> 5) ^ ((r & ~r_ls2) >> 4) ^ ( r_or_ls2 >> 3);
// uint8_t z1 = (r0 | r2) ^ ( r5 | r7) ^ r1 ^ r6 ^ x ^ y; // <-- original
uint8_t z1 = (r_or_ls2 >> 6) ^ ( r_or_ls2 >> 1) ^ (r >> 5) ^ r ^ ((x^y) << 1);
// uint8_t z1 = (r0 | r2) ^ ( r5 | r7) ^ r1 ^ r6 ^ x ^ y; // <-- original
uint8_t z1 = (r_or_ls2 >> 6) ^ ( r_or_ls2 >> 1) ^ (r >> 5) ^ r ^ ((x^y) << 1);
// uint8_t z2 = (r3 & ~r5) ^ (r4 & r6 ) ^ r7 ^ x; // <-- original
uint8_t z2 = ((r & ~r_ls2) >> 4) ^ (r_and_ls2 >> 3) ^ r ^ x;
// uint8_t z2 = (r3 & ~r5) ^ (r4 & r6 ) ^ r7 ^ x; // <-- original
uint8_t z2 = ((r & ~r_ls2) >> 4) ^ (r_and_ls2 >> 3) ^ r ^ x;
return (z0 & 4) | (z1 & 2) | (z2 & 1);
return (z0 & 4) | (z1 & 2) | (z2 & 1);
}
*/
void opt_successor(const uint8_t* k, State *s, bool y, State* successor) {
uint8_t Tt = 1 & opt_T(s);
void opt_successor(const uint8_t *k, State *s, bool y, State *successor) {
uint8_t Tt = 1 & opt_T(s);
successor->t = (s->t >> 1);
successor->t |= (Tt ^ (s->r >> 7 & 0x1) ^ (s->r >> 3 & 0x1)) << 15;
successor->t = (s->t >> 1);
successor->t |= (Tt ^ (s->r >> 7 & 0x1) ^ (s->r >> 3 & 0x1)) << 15;
successor->b = s->b >> 1;
successor->b |= (opt_B(s) ^ (s->r & 0x1)) << 7;
successor->b = s->b >> 1;
successor->b |= (opt_B(s) ^ (s->r & 0x1)) << 7;
successor->r = (k[opt__select(Tt,y,s->r)] ^ successor->b) + s->l ;
successor->l = successor->r+s->r;
successor->r = (k[opt__select(Tt, y, s->r)] ^ successor->b) + s->l ;
successor->l = successor->r + s->r;
}
void opt_suc(const uint8_t* k,State* s, uint8_t *in, uint8_t length, bool add32Zeroes) {
State x2;
int i;
uint8_t head = 0;
for (i = 0; i < length; i++) {
head = 1 & (in[i] >> 7);
opt_successor(k, s, head, &x2);
void opt_suc(const uint8_t *k, State *s, uint8_t *in, uint8_t length, bool add32Zeroes) {
State x2;
for (int i = 0; i < length; i++) {
uint8_t head;
head = 1 & (in[i] >> 7);
opt_successor(k, s, head, &x2);
head = 1 & (in[i] >> 6);
opt_successor(k, &x2, head, s);
head = 1 & (in[i] >> 6);
opt_successor(k, &x2, head, s);
head = 1 & (in[i] >> 5);
opt_successor(k, s, head, &x2);
head = 1 & (in[i] >> 5);
opt_successor(k, s, head, &x2);
head = 1 & (in[i] >> 4);
opt_successor(k, &x2, head, s);
head = 1 & (in[i] >> 4);
opt_successor(k, &x2, head, s);
head = 1 & (in[i] >> 3);
opt_successor(k, s, head, &x2);
head = 1 & (in[i] >> 3);
opt_successor(k, s, head, &x2);
head = 1 & (in[i] >> 2);
opt_successor(k, &x2, head, s);
head = 1 & (in[i] >> 2);
opt_successor(k, &x2, head, s);
head = 1 & (in[i] >> 1);
opt_successor(k, s, head, &x2);
head = 1 & (in[i] >> 1);
opt_successor(k, s, head, &x2);
head = 1 & in[i];
opt_successor(k, &x2, head, s);
}
//For tag MAC, an additional 32 zeroes
if (add32Zeroes) {
for (i = 0; i < 16; i++) {
opt_successor(k, s, 0, &x2);
opt_successor(k, &x2, 0, s);
}
}
head = 1 & in[i];
opt_successor(k, &x2, head, s);
}
//For tag MAC, an additional 32 zeroes
if (add32Zeroes) {
for (int i = 0; i < 16; i++) {
opt_successor(k, s, 0, &x2);
opt_successor(k, &x2, 0, s);
}
}
}
void opt_output(const uint8_t* k,State* s, uint8_t *buffer) {
uint8_t times = 0;
uint8_t bout = 0;
State temp = {0,0,0,0};
for ( ; times < 4; times++) {
bout =0;
bout |= (s->r & 0x4) << 5;
opt_successor(k, s, 0, &temp);
bout |= (temp.r & 0x4) << 4;
opt_successor(k, &temp, 0, s);
bout |= (s->r & 0x4) << 3;
opt_successor(k, s, 0, &temp);
bout |= (temp.r & 0x4) << 2;
opt_successor(k, &temp, 0, s);
bout |= (s->r & 0x4) << 1;
opt_successor(k, s, 0, &temp);
bout |= (temp.r & 0x4) ;
opt_successor(k, &temp, 0, s);
bout |= (s->r & 0x4) >> 1;
opt_successor(k, s, 0, &temp);
bout |= (temp.r & 0x4) >> 2;
opt_successor(k, &temp, 0, s);
buffer[times] = bout;
}
void opt_output(const uint8_t *k, State *s, uint8_t *buffer) {
State temp = {0, 0, 0, 0};
for (uint8_t times = 0; times < 4; times++) {
uint8_t bout = 0;
bout |= (s->r & 0x4) << 5;
opt_successor(k, s, 0, &temp);
bout |= (temp.r & 0x4) << 4;
opt_successor(k, &temp, 0, s);
bout |= (s->r & 0x4) << 3;
opt_successor(k, s, 0, &temp);
bout |= (temp.r & 0x4) << 2;
opt_successor(k, &temp, 0, s);
bout |= (s->r & 0x4) << 1;
opt_successor(k, s, 0, &temp);
bout |= (temp.r & 0x4) ;
opt_successor(k, &temp, 0, s);
bout |= (s->r & 0x4) >> 1;
opt_successor(k, s, 0, &temp);
bout |= (temp.r & 0x4) >> 2;
opt_successor(k, &temp, 0, s);
buffer[times] = bout;
}
}
void opt_MAC(uint8_t* k, uint8_t* input, uint8_t* out) {
State _init = {
((k[0] ^ 0x4c) + 0xEC) & 0xFF,// l
((k[0] ^ 0x4c) + 0x21) & 0xFF,// r
0x4c, // b
0xE012 // t
};
void opt_MAC(uint8_t *k, uint8_t *input, uint8_t *out) {
State _init = {
((k[0] ^ 0x4c) + 0xEC) & 0xFF,// l
((k[0] ^ 0x4c) + 0x21) & 0xFF,// r
0x4c, // b
0xE012 // t
};
opt_suc(k,&_init,input,12, false);
opt_output(k,&_init, out);
opt_suc(k, &_init, input, 12, false);
opt_output(k, &_init, out);
}
uint8_t rev_byte(uint8_t b) {
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
return b;
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
return b;
}
void opt_reverse_arraybytecpy(uint8_t* dest, uint8_t *src, size_t len) {
uint8_t i;
for ( i =0; i< len ; i++)
dest[i] = rev_byte(src[i]);
void opt_reverse_arraybytecpy(uint8_t *dest, uint8_t *src, size_t len) {
uint8_t i;
for (i = 0; i < len ; i++)
dest[i] = rev_byte(src[i]);
}
void opt_doReaderMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4]) {
static uint8_t cc_nr[12];
opt_reverse_arraybytecpy(cc_nr, cc_nr_p, 12);
uint8_t dest [] = {0,0,0,0,0,0,0,0};
opt_MAC(div_key_p, cc_nr, dest);
//The output MAC must also be reversed
opt_reverse_arraybytecpy(mac, dest, 4);
return;
static uint8_t cc_nr[12];
opt_reverse_arraybytecpy(cc_nr, cc_nr_p, 12);
uint8_t dest [] = {0, 0, 0, 0, 0, 0, 0, 0};
opt_MAC(div_key_p, cc_nr, dest);
//The output MAC must also be reversed
opt_reverse_arraybytecpy(mac, dest, 4);
return;
}
void opt_doTagMAC(uint8_t *cc_p, const uint8_t *div_key_p, uint8_t mac[4]) {
static uint8_t cc_nr[8+4+4];
opt_reverse_arraybytecpy(cc_nr, cc_p, 12);
State _init = {
((div_key_p[0] ^ 0x4c) + 0xEC) & 0xFF,// l
((div_key_p[0] ^ 0x4c) + 0x21) & 0xFF,// r
0x4c, // b
0xE012 // t
};
opt_suc(div_key_p, &_init, cc_nr, 12, true);
uint8_t dest [] = {0,0,0,0};
opt_output(div_key_p, &_init, dest);
//The output MAC must also be reversed
opt_reverse_arraybytecpy(mac, dest,4);
return;
static uint8_t cc_nr[8 + 4 + 4];
opt_reverse_arraybytecpy(cc_nr, cc_p, 12);
State _init = {
((div_key_p[0] ^ 0x4c) + 0xEC) & 0xFF,// l
((div_key_p[0] ^ 0x4c) + 0x21) & 0xFF,// r
0x4c, // b
0xE012 // t
};
opt_suc(div_key_p, &_init, cc_nr, 12, true);
uint8_t dest [] = {0, 0, 0, 0};
opt_output(div_key_p, &_init, dest);
//The output MAC must also be reversed
opt_reverse_arraybytecpy(mac, dest, 4);
return;
}
/**
@ -234,16 +231,16 @@ void opt_doTagMAC(uint8_t *cc_p, const uint8_t *div_key_p, uint8_t mac[4]) {
* @return the cipher state
*/
State opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p) {
static uint8_t cc_nr[8];
opt_reverse_arraybytecpy(cc_nr, cc_p, 8);
State _init = {
((div_key_p[0] ^ 0x4c) + 0xEC) & 0xFF,// l
((div_key_p[0] ^ 0x4c) + 0x21) & 0xFF,// r
0x4c, // b
0xE012 // t
};
opt_suc(div_key_p, &_init, cc_nr, 8, false);
return _init;
static uint8_t cc_nr[8];
opt_reverse_arraybytecpy(cc_nr, cc_p, 8);
State _init = {
((div_key_p[0] ^ 0x4c) + 0xEC) & 0xFF,// l
((div_key_p[0] ^ 0x4c) + 0x21) & 0xFF,// r
0x4c, // b
0xE012 // t
};
opt_suc(div_key_p, &_init, cc_nr, 8, false);
return _init;
}
/**
* The second part of the tag MAC calculation, since the CC is already calculated into the state,
@ -254,14 +251,14 @@ State opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p) {
* @param mac - where to store the MAC
* @param div_key_p - the key to use
*/
void opt_doTagMAC_2(State _init, uint8_t* nr, uint8_t mac[4], const uint8_t* div_key_p) {
static uint8_t _nr[4];
opt_reverse_arraybytecpy(_nr, nr, 4);
opt_suc(div_key_p, &_init,_nr, 4, true);
void opt_doTagMAC_2(State _init, uint8_t *nr, uint8_t mac[4], const uint8_t *div_key_p) {
static uint8_t _nr[4];
opt_reverse_arraybytecpy(_nr, nr, 4);
opt_suc(div_key_p, &_init, _nr, 4, true);
uint8_t dest [] = {0,0,0,0};
opt_output(div_key_p, &_init, dest);
//The output MAC must also be reversed
opt_reverse_arraybytecpy(mac, dest,4);
return;
uint8_t dest [] = {0, 0, 0, 0};
opt_output(div_key_p, &_init, dest);
//The output MAC must also be reversed
opt_reverse_arraybytecpy(mac, dest, 4);
return;
}

View file

@ -8,16 +8,16 @@
/**
* Definition 1 (Cipher state). A cipher state of iClass s is an element of F 40/2
* consisting of the following four components:
* 1. the left register l = (l 0 . . . l 7 ) F 8/2 ;
* 2. the right register r = (r 0 . . . r 7 ) F 8/2 ;
* 3. the top register t = (t 0 . . . t 15 ) F 16/2 .
* 4. the bottom register b = (b 0 . . . b 7 ) F 8/2 .
* 1. the left register l = (l 0 . . . l 7 ) F 8/2 ;
* 2. the right register r = (r 0 . . . r 7 ) F 8/2 ;
* 3. the top register t = (t 0 . . . t 15 ) F 16/2 .
* 4. the bottom register b = (b 0 . . . b 7 ) F 8/2 .
**/
typedef struct {
uint8_t l;
uint8_t r;
uint8_t b;
uint16_t t;
uint8_t l;
uint8_t r;
uint8_t b;
uint16_t t;
} State;
/** The reader MAC is MAC(key, CC * NR )
@ -46,6 +46,6 @@ State opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p);
* @param mac - where to store the MAC
* @param div_key_p - the key to use
*/
void opt_doTagMAC_2(State _init, uint8_t* nr, uint8_t mac[4], const uint8_t* div_key_p);
void opt_doTagMAC_2(State _init, uint8_t *nr, uint8_t mac[4], const uint8_t *div_key_p);
#endif // OPTIMIZED_CIPHER_H

View file

@ -3,488 +3,503 @@
#define T0_PCF 8 //period for the pcf7931 in us
#define ALLOC 16
int DemodPCF7931(uint8_t **outBlocks) {
size_t DemodPCF7931(uint8_t **outBlocks) {
uint8_t bits[256] = {0x00};
uint8_t blocks[8][16];
uint8_t blocks[8][16];
uint8_t *dest = BigBuf_get_addr();
int GraphTraceLen = BigBuf_max_traceLen();
if ( GraphTraceLen > 18000 )
GraphTraceLen = 18000;
int i, j, lastval, bitidx, half_switch;
int clock = 64;
int tolerance = clock / 8;
int pmc, block_done;
int lc, warnings = 0;
int num_blocks = 0;
int lmin=128, lmax=128;
uint8_t dir;
//clear read buffer
BigBuf_Clear_keep_EM();
LFSetupFPGAForADC(95, true);
DoAcquisition_default(0, true);
int GraphTraceLen = BigBuf_max_traceLen();
if (GraphTraceLen > 18000)
GraphTraceLen = 18000;
lmin = 64;
lmax = 192;
int i = 2, j, lastval, bitidx, half_switch;
int clock = 64;
int tolerance = clock / 8;
int pmc, block_done;
int lc, warnings = 0;
size_t num_blocks = 0;
int lmin = 64, lmax = 192;
uint8_t dir;
i = 2;
BigBuf_Clear_keep_EM();
LFSetupFPGAForADC(95, true);
DoAcquisition_default(0, true);
/* Find first local max/min */
if(dest[1] > dest[0]) {
while(i < GraphTraceLen) {
if( !(dest[i] > dest[i-1]) && dest[i] > lmax)
break;
i++;
}
dir = 0;
}
else {
while(i < GraphTraceLen) {
if( !(dest[i] < dest[i-1]) && dest[i] < lmin)
break;
i++;
}
dir = 1;
}
/* Find first local max/min */
if (dest[1] > dest[0]) {
while (i < GraphTraceLen) {
if (!(dest[i] > dest[i - 1]) && dest[i] > lmax)
break;
i++;
}
dir = 0;
} else {
while (i < GraphTraceLen) {
if (!(dest[i] < dest[i - 1]) && dest[i] < lmin)
break;
i++;
}
dir = 1;
}
lastval = i++;
half_switch = 0;
pmc = 0;
block_done = 0;
lastval = i++;
half_switch = 0;
pmc = 0;
block_done = 0;
for (bitidx = 0; i < GraphTraceLen; i++)
{
if ( (dest[i-1] > dest[i] && dir == 1 && dest[i] > lmax) || (dest[i-1] < dest[i] && dir == 0 && dest[i] < lmin))
{
lc = i - lastval;
lastval = i;
for (bitidx = 0; i < GraphTraceLen; i++) {
if ((dest[i - 1] > dest[i] && dir == 1 && dest[i] > lmax) || (dest[i - 1] < dest[i] && dir == 0 && dest[i] < lmin)) {
lc = i - lastval;
lastval = i;
// Switch depending on lc length:
// Tolerance is 1/8 of clock rate (arbitrary)
if (ABS(lc-clock/4) < tolerance) {
// 16T0
if((i - pmc) == lc) { /* 16T0 was previous one */
/* It's a PMC ! */
i += (128+127+16+32+33+16)-1;
lastval = i;
pmc = 0;
block_done = 1;
}
else {
pmc = i;
}
} else if (ABS(lc-clock/2) < tolerance) {
// 32TO
if((i - pmc) == lc) { /* 16T0 was previous one */
/* It's a PMC ! */
i += (128+127+16+32+33)-1;
lastval = i;
pmc = 0;
block_done = 1;
}
else if(half_switch == 1) {
// Switch depending on lc length:
// Tolerance is 1/8 of clock rate (arbitrary)
if (ABS(lc - clock / 4) < tolerance) {
// 16T0
if ((i - pmc) == lc) { /* 16T0 was previous one */
/* It's a PMC ! */
i += (128 + 127 + 16 + 32 + 33 + 16) - 1;
lastval = i;
pmc = 0;
block_done = 1;
} else {
pmc = i;
}
} else if (ABS(lc - clock / 2) < tolerance) {
// 32TO
if ((i - pmc) == lc) { /* 16T0 was previous one */
/* It's a PMC ! */
i += (128 + 127 + 16 + 32 + 33) - 1;
lastval = i;
pmc = 0;
block_done = 1;
} else if (half_switch == 1) {
bits[bitidx++] = 0;
half_switch = 0;
}
else
half_switch++;
} else if (ABS(lc-clock) < tolerance) {
// 64TO
half_switch = 0;
} else
half_switch++;
} else if (ABS(lc - clock) < tolerance) {
// 64TO
bits[bitidx++] = 1;
} else {
// Error
warnings++;
if (warnings > 10)
{
Dbprintf("Error: too many detection errors, aborting...");
return 0;
}
}
} else {
// Error
if (++warnings > 10) {
Dbprintf("Error: too many detection errors, aborting.");
return 0;
}
}
if(block_done == 1) {
if(bitidx == 128) {
for(j=0; j<16; j++) {
blocks[num_blocks][j] = 128*bits[j*8+7]+
64*bits[j*8+6]+
32*bits[j*8+5]+
16*bits[j*8+4]+
8*bits[j*8+3]+
4*bits[j*8+2]+
2*bits[j*8+1]+
bits[j*8];
}
num_blocks++;
}
bitidx = 0;
block_done = 0;
half_switch = 0;
}
if(i < GraphTraceLen)
dir =(dest[i-1] > dest[i]) ? 0 : 1;
}
if(bitidx==255)
bitidx=0;
warnings = 0;
if(num_blocks == 4) break;
}
memcpy(outBlocks, blocks, 16*num_blocks);
return num_blocks;
if (block_done == 1) {
if (bitidx == 128) {
for (j = 0; j < 16; ++j) {
blocks[num_blocks][j] =
128 * bits[j * 8 + 7] +
64 * bits[j * 8 + 6] +
32 * bits[j * 8 + 5] +
16 * bits[j * 8 + 4] +
8 * bits[j * 8 + 3] +
4 * bits[j * 8 + 2] +
2 * bits[j * 8 + 1] +
bits[j * 8]
;
}
num_blocks++;
}
bitidx = 0;
block_done = 0;
half_switch = 0;
}
if (i < GraphTraceLen)
dir = (dest[i - 1] > dest[i]) ? 0 : 1;
}
if (bitidx == 255)
bitidx = 0;
warnings = 0;
if (num_blocks == 4) break;
}
memcpy(outBlocks, blocks, 16 * num_blocks);
return num_blocks;
}
int IsBlock0PCF7931(uint8_t *Block) {
// Assume RFU means 0 :)
if((memcmp(Block, "\x00\x00\x00\x00\x00\x00\x00\x01", 8) == 0) && memcmp(Block+9, "\x00\x00\x00\x00\x00\x00\x00", 7) == 0) // PAC enabled
return 1;
if((memcmp(Block+9, "\x00\x00\x00\x00\x00\x00\x00", 7) == 0) && Block[7] == 0) // PAC disabled, can it *really* happen ?
return 1;
return 0;
bool IsBlock0PCF7931(uint8_t *block) {
// assuming all RFU bits are set to 0
// if PAC is enabled password is set to 0
if (block[7] == 0x01) {
if (!memcmp(block, "\x00\x00\x00\x00\x00\x00\x00", 7) && !memcmp(block + 9, "\x00\x00\x00\x00\x00\x00\x00", 7))
return true;
} else if (block[7] == 0x00) {
if (!memcmp(block + 9, "\x00\x00\x00\x00\x00\x00\x00", 7))
return true;
}
return false;
}
int IsBlock1PCF7931(uint8_t *Block) {
// Assume RFU means 0 :)
if( Block[10] == 0 &&
Block[11] == 0 &&
Block[12] == 0 &&
Block[13] == 0)
if ( (Block[14] & 0x7f) <= 9 && Block[15] <= 9)
return 1;
return 0;
bool IsBlock1PCF7931(uint8_t *block) {
// assuming all RFU bits are set to 0
if (block[10] == 0
&& block[11] == 0
&& block[12] == 0
&& block[13] == 0) {
if ((block[14] & 0x7f) <= 9
&& block[15] <= 9) {
return true;
}
}
return false;
}
void ReadPCF7931() {
uint8_t Blocks[8][17];
uint8_t tmpBlocks[4][16];
int i, j, ind, ind2, n;
int num_blocks = 0;
int max_blocks = 8;
int ident = 0;
int error = 0;
int tries = 0;
int found_blocks = 0; // successfully read blocks
int max_blocks = 8; // readable blocks
uint8_t memory_blocks[8][17]; // PCF content
uint8_t single_blocks[8][17]; // PFC blocks with unknown position
int single_blocks_cnt = 0;
memset(Blocks, 0, 8*17*sizeof(uint8_t));
size_t n = 0; // transmitted blocks
uint8_t tmp_blocks[4][16]; // temporary read buffer
do {
memset(tmpBlocks, 0, 4*16*sizeof(uint8_t));
n = DemodPCF7931((uint8_t**)tmpBlocks);
if(!n)
error++;
if(error==10 && num_blocks == 0) {
Dbprintf("Error, no tag or bad tag");
return;
}
else if (tries==20 || error==10) {
Dbprintf("Error reading the tag");
Dbprintf("Here is the partial content");
goto end;
}
uint8_t found_0_1 = 0; // flag: blocks 0 and 1 were found
int errors = 0; // error counter
int tries = 0; // tries counter
for(i=0; i<n; i++)
Dbprintf("(dbg) %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
tmpBlocks[i][0], tmpBlocks[i][1], tmpBlocks[i][2], tmpBlocks[i][3], tmpBlocks[i][4], tmpBlocks[i][5], tmpBlocks[i][6], tmpBlocks[i][7],
tmpBlocks[i][8], tmpBlocks[i][9], tmpBlocks[i][10], tmpBlocks[i][11], tmpBlocks[i][12], tmpBlocks[i][13], tmpBlocks[i][14], tmpBlocks[i][15]);
if(!ident) {
for(i=0; i<n; i++) {
if(IsBlock0PCF7931(tmpBlocks[i])) {
// Found block 0 ?
if(i < n-1 && IsBlock1PCF7931(tmpBlocks[i+1])) {
// Found block 1!
// \o/
ident = 1;
memcpy(Blocks[0], tmpBlocks[i], 16);
Blocks[0][ALLOC] = 1;
memcpy(Blocks[1], tmpBlocks[i+1], 16);
Blocks[1][ALLOC] = 1;
max_blocks = MAX((Blocks[1][14] & 0x7f), Blocks[1][15]) + 1;
// Debug print
Dbprintf("(dbg) Max blocks: %d", max_blocks);
num_blocks = 2;
// Handle following blocks
for(j=i+2, ind2=2; j!=i; j++, ind2++, num_blocks++) {
if(j==n) j=0;
if(j==i) break;
memcpy(Blocks[ind2], tmpBlocks[j], 16);
Blocks[ind2][ALLOC] = 1;
}
break;
}
}
}
}
else {
for(i=0; i<n; i++) { // Look for identical block in known blocks
if(memcmp(tmpBlocks[i], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) { // Block is not full of 00
for(j=0; j<max_blocks; j++) {
if(Blocks[j][ALLOC] == 1 && !memcmp(tmpBlocks[i], Blocks[j], 16)) {
// Found an identical block
for(ind=i-1,ind2=j-1; ind >= 0; ind--,ind2--) {
if(ind2 < 0)
ind2 = max_blocks;
if(!Blocks[ind2][ALLOC]) { // Block ind2 not already found
// Dbprintf("Tmp %d -> Block %d", ind, ind2);
memcpy(Blocks[ind2], tmpBlocks[ind], 16);
Blocks[ind2][ALLOC] = 1;
num_blocks++;
if(num_blocks == max_blocks) goto end;
}
}
for(ind=i+1,ind2=j+1; ind < n; ind++,ind2++) {
if(ind2 > max_blocks)
ind2 = 0;
if(!Blocks[ind2][ALLOC]) { // Block ind2 not already found
// Dbprintf("Tmp %d -> Block %d", ind, ind2);
memcpy(Blocks[ind2], tmpBlocks[ind], 16);
Blocks[ind2][ALLOC] = 1;
num_blocks++;
if(num_blocks == max_blocks) goto end;
}
}
}
}
}
}
}
tries++;
if (BUTTON_PRESS()) return;
} while (num_blocks != max_blocks);
end:
Dbprintf("-----------------------------------------");
Dbprintf("Memory content:");
Dbprintf("-----------------------------------------");
for(i=0; i<max_blocks; i++) {
if(Blocks[i][ALLOC]==1)
Dbprintf("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
Blocks[i][0], Blocks[i][1], Blocks[i][2], Blocks[i][3], Blocks[i][4], Blocks[i][5], Blocks[i][6], Blocks[i][7],
Blocks[i][8], Blocks[i][9], Blocks[i][10], Blocks[i][11], Blocks[i][12], Blocks[i][13], Blocks[i][14], Blocks[i][15]);
else
Dbprintf("<missing block %d>", i);
}
Dbprintf("-----------------------------------------");
memset(memory_blocks, 0, 8 * 17 * sizeof(uint8_t));
memset(single_blocks, 0, 8 * 17 * sizeof(uint8_t));
cmd_send(CMD_ACK,0,0,0,0,0);
int i = 0, j = 0;
do {
i = 0;
memset(tmp_blocks, 0, 4 * 16 * sizeof(uint8_t));
n = DemodPCF7931((uint8_t **)tmp_blocks);
if (!n)
++errors;
// exit if no block is received
if (errors >= 10 && found_blocks == 0 && single_blocks_cnt == 0) {
Dbprintf("Error, no tag or bad tag");
return;
}
// exit if too many errors during reading
if (tries > 50 && (2 * errors > tries)) {
Dbprintf("Error reading the tag");
Dbprintf("Here is the partial content");
goto end;
}
// our logic breaks if we don't get at least two blocks
if (n < 2) {
if (n == 0 || !memcmp(tmp_blocks[0], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16))
continue;
if (single_blocks_cnt < max_blocks) {
for (i = 0; i < single_blocks_cnt; ++i) {
if (!memcmp(single_blocks[i], tmp_blocks[0], 16)) {
j = 1;
break;
}
}
if (j != 1) {
memcpy(single_blocks[single_blocks_cnt], tmp_blocks[0], 16);
single_blocks_cnt++;
}
j = 0;
}
++tries;
continue;
}
Dbprintf("(dbg) got %d blocks (%d/%d found) (%d tries, %d errors)", n, found_blocks, (max_blocks == 0 ? found_blocks : max_blocks), tries, errors);
i = 0;
if (!found_0_1) {
while (i < n - 1) {
if (IsBlock0PCF7931(tmp_blocks[i]) && IsBlock1PCF7931(tmp_blocks[i + 1])) {
found_0_1 = 1;
memcpy(memory_blocks[0], tmp_blocks[i], 16);
memcpy(memory_blocks[1], tmp_blocks[i + 1], 16);
memory_blocks[0][ALLOC] = memory_blocks[1][ALLOC] = 1;
// block 1 tells how many blocks are going to be sent
max_blocks = MAX((memory_blocks[1][14] & 0x7f), memory_blocks[1][15]) + 1;
found_blocks = 2;
Dbprintf("Found blocks 0 and 1. PCF is transmitting %d blocks.", max_blocks);
// handle the following blocks
for (j = i + 2; j < n; ++j) {
memcpy(memory_blocks[found_blocks], tmp_blocks[j], 16);
memory_blocks[found_blocks][ALLOC] = 1;
++found_blocks;
}
break;
}
++i;
}
} else {
// Trying to re-order blocks
// Look for identical block in memory blocks
while (i < n - 1) {
// skip all zeroes blocks
if (memcmp(tmp_blocks[i], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) {
for (j = 1; j < max_blocks - 1; ++j) {
if (!memcmp(tmp_blocks[i], memory_blocks[j], 16) && !memory_blocks[j + 1][ALLOC]) {
memcpy(memory_blocks[j + 1], tmp_blocks[i + 1], 16);
memory_blocks[j + 1][ALLOC] = 1;
if (++found_blocks >= max_blocks) goto end;
}
}
}
if (memcmp(tmp_blocks[i + 1], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) {
for (j = 0; j < max_blocks; ++j) {
if (!memcmp(tmp_blocks[i + 1], memory_blocks[j], 16) && !memory_blocks[(j == 0 ? max_blocks : j) - 1][ALLOC]) {
if (j == 0) {
memcpy(memory_blocks[max_blocks - 1], tmp_blocks[i], 16);
memory_blocks[max_blocks - 1][ALLOC] = 1;
} else {
memcpy(memory_blocks[j - 1], tmp_blocks[i], 16);
memory_blocks[j - 1][ALLOC] = 1;
}
if (++found_blocks >= max_blocks) goto end;
}
}
}
++i;
}
}
++tries;
if (BUTTON_PRESS()) {
Dbprintf("Button pressed, stopping.");
goto end;
}
} while (found_blocks != max_blocks);
end:
Dbprintf("-----------------------------------------");
Dbprintf("Memory content:");
Dbprintf("-----------------------------------------");
for (i = 0; i < max_blocks; ++i) {
if (memory_blocks[i][ALLOC])
print_result("Block", memory_blocks[i], 16);
else
Dbprintf("<missing block %d>", i);
}
Dbprintf("-----------------------------------------");
if (found_blocks < max_blocks) {
Dbprintf("-----------------------------------------");
Dbprintf("Blocks with unknown position:");
Dbprintf("-----------------------------------------");
for (i = 0; i < single_blocks_cnt; ++i)
print_result("Block", single_blocks[i], 16);
Dbprintf("-----------------------------------------");
}
reply_old(CMD_ACK, 0, 0, 0, 0, 0);
}
static void RealWritePCF7931(uint8_t *pass, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data) {
uint32_t tab[1024] = {0}; // data times frame
uint32_t u = 0;
uint8_t parity = 0;
bool comp = 0;
//BUILD OF THE DATA FRAME
//alimentation of the tag (time for initializing)
AddPatternPCF7931(init_delay, 0, 8192 / 2 * T0_PCF, tab);
AddPatternPCF7931(8192 / 2 * T0_PCF + 319 * T0_PCF + 70, 3 * T0_PCF, 29 * T0_PCF, tab);
//password indication bit
AddBitPCF7931(1, tab, l, p);
//password (on 56 bits)
AddBytePCF7931(pass[0], tab, l, p);
AddBytePCF7931(pass[1], tab, l, p);
AddBytePCF7931(pass[2], tab, l, p);
AddBytePCF7931(pass[3], tab, l, p);
AddBytePCF7931(pass[4], tab, l, p);
AddBytePCF7931(pass[5], tab, l, p);
AddBytePCF7931(pass[6], tab, l, p);
//programming mode (0 or 1)
AddBitPCF7931(0, tab, l, p);
//block adress on 6 bits
for (u = 0; u < 6; ++u) {
if (address & (1 << u)) { // bit 1
++parity;
AddBitPCF7931(1, tab, l, p);
} else { // bit 0
AddBitPCF7931(0, tab, l, p);
}
}
//byte address on 4 bits
for (u = 0; u < 4; ++u) {
if (byte & (1 << u)) { // bit 1
parity++;
AddBitPCF7931(1, tab, l, p);
} else // bit 0
AddBitPCF7931(0, tab, l, p);
}
//data on 8 bits
for (u = 0; u < 8; u++) {
if (data & (1 << u)) { // bit 1
parity++;
AddBitPCF7931(1, tab, l, p);
} else //bit 0
AddBitPCF7931(0, tab, l, p);
}
//parity bit
if ((parity % 2) == 0)
AddBitPCF7931(0, tab, l, p); //even parity
else
AddBitPCF7931(1, tab, l, p);//odd parity
//time access memory
AddPatternPCF7931(5120 + 2680, 0, 0, tab);
//conversion of the scale time
for (u = 0; u < 500; ++u)
tab[u] = (tab[u] * 3) / 2;
//compensation of the counter reload
while (!comp) {
comp = 1;
for (u = 0; tab[u] != 0; ++u)
if (tab[u] > 0xFFFF) {
tab[u] -= 0xFFFF;
comp = 0;
}
}
SendCmdPCF7931(tab);
}
/* Write on a byte of a PCF7931 tag
* @param address : address of the block to write
@param byte : address of the byte to write
@param data : data to write
*/
void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data)
{
uint32_t tab[1024] = {0}; // data times frame
uint32_t u = 0;
uint8_t parity = 0;
bool comp = 0;
void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data) {
Dbprintf("Initialization delay : %d us", init_delay);
Dbprintf("Offsets : %d us on the low pulses width, %d us on the low pulses positions", l, p);
Dbprintf("Password (LSB first on each byte): %02x %02x %02x %02x %02x %02x %02x", pass1, pass2, pass3, pass4, pass5, pass6, pass7);
Dbprintf("Block address : %02x", address);
Dbprintf("Byte address : %02x", byte);
Dbprintf("Data : %02x", data);
//BUILD OF THE DATA FRAME
uint8_t password[7] = {pass1, pass2, pass3, pass4, pass5, pass6, pass7};
//alimentation of the tag (time for initializing)
AddPatternPCF7931(init_delay, 0, 8192/2*T0_PCF, tab);
//PMC
Dbprintf("Initialization delay : %d us", init_delay);
AddPatternPCF7931(8192/2*T0_PCF + 319*T0_PCF+70, 3*T0_PCF, 29*T0_PCF, tab);
Dbprintf("Offsets : %d us on the low pulses width, %d us on the low pulses positions", l, p);
//password indication bit
AddBitPCF7931(1, tab, l, p);
//password (on 56 bits)
Dbprintf("Password (LSB first on each byte) : %02x %02x %02x %02x %02x %02x %02x", pass1,pass2,pass3,pass4,pass5,pass6,pass7);
AddBytePCF7931(pass1, tab, l, p);
AddBytePCF7931(pass2, tab, l, p);
AddBytePCF7931(pass3, tab, l, p);
AddBytePCF7931(pass4, tab, l, p);
AddBytePCF7931(pass5, tab, l, p);
AddBytePCF7931(pass6, tab, l, p);
AddBytePCF7931(pass7, tab, l, p);
//programming mode (0 or 1)
AddBitPCF7931(0, tab, l, p);
//block adress on 6 bits
Dbprintf("Block address : %02x", address);
for (u=0; u<6; u++)
{
if (address&(1<<u)) { // bit 1
parity++;
AddBitPCF7931(1, tab, l, p);
} else{ // bit 0
AddBitPCF7931(0, tab, l, p);
}
}
//byte address on 4 bits
Dbprintf("Byte address : %02x", byte);
for (u=0; u<4; u++)
{
if (byte&(1<<u)) { // bit 1
parity++;
AddBitPCF7931(1, tab, l, p);
} else{ // bit 0
AddBitPCF7931(0, tab, l, p);
}
}
//data on 8 bits
Dbprintf("Data : %02x", data);
for (u=0; u<8; u++)
{
if (data&(1<<u)) { // bit 1
parity++;
AddBitPCF7931(1, tab, l, p);
} else{ //bit 0
AddBitPCF7931(0, tab, l, p);
}
}
//parity bit
if((parity%2)==0){
AddBitPCF7931(0, tab, l, p); //even parity
}else{
AddBitPCF7931(1, tab, l, p);//odd parity
}
//time access memory
AddPatternPCF7931(5120+2680, 0, 0, tab);
//conversion of the scale time
for(u=0;u<500;u++){
tab[u]=(tab[u] * 3)/2;
}
//compensation of the counter reload
while (!comp){
comp = 1;
for(u=0;tab[u]!=0;u++){
if(tab[u] > 0xFFFF){
tab[u] -= 0xFFFF;
comp = 0;
}
}
}
SendCmdPCF7931(tab);
RealWritePCF7931(password, init_delay, l, p, address, byte, data);
}
/* Send a trame to a PCF7931 tags
* @param tab : array of the data frame
*/
void SendCmdPCF7931(uint32_t * tab){
uint16_t u=0, tempo=0;
void SendCmdPCF7931(uint32_t *tab) {
uint16_t u = 0, tempo = 0;
Dbprintf("Sending data frame...");
Dbprintf("Sending data frame...");
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU);
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
LED_A_ON();
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU );
LED_A_ON();
// steal this pin from the SSP and use it to control the modulation
AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT;
AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
// steal this pin from the SSP and use it to control the modulation
AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT;
AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
//initialization of the timer
AT91C_BASE_PMC->PMC_PCER |= (0x1 << AT91C_ID_TC0);
AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE;
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK; //clock at 48/32 MHz
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN;
AT91C_BASE_TCB->TCB_BCR = 1;
//initialization of the timer
AT91C_BASE_PMC->PMC_PCER |= (0x1 << AT91C_ID_TC0);
AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE;
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK; //clock at 48/32 MHz
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN;
AT91C_BASE_TCB->TCB_BCR = 1;
tempo = AT91C_BASE_TC0->TC_CV;
for (u = 0; tab[u] != 0; u += 3) {
// modulate antenna
HIGH(GPIO_SSC_DOUT);
while (tempo != tab[u])
tempo = AT91C_BASE_TC0->TC_CV;
// stop modulating antenna
LOW(GPIO_SSC_DOUT);
while (tempo != tab[u + 1])
tempo = AT91C_BASE_TC0->TC_CV;
tempo = AT91C_BASE_TC0->TC_CV;
for( u = 0; tab[u] != 0; u += 3){
// modulate antenna
HIGH(GPIO_SSC_DOUT);
while (tempo != tab[u + 2])
tempo = AT91C_BASE_TC0->TC_CV;
}
// modulate antenna
HIGH(GPIO_SSC_DOUT);
while(tempo != tab[u]) tempo = AT91C_BASE_TC0->TC_CV;
LED_A_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(200);
// stop modulating antenna
LOW(GPIO_SSC_DOUT);
while(tempo != tab[u+1]) tempo = AT91C_BASE_TC0->TC_CV;
// modulate antenna
HIGH(GPIO_SSC_DOUT);
while(tempo != tab[u+2]) tempo = AT91C_BASE_TC0->TC_CV;
}
LED_A_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(200);
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable
LED(0xFFFF, 1000);
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable
LED(0xFFFF, 1000);
}
/* Add a byte for building the data frame of PCF7931 tags
/* Add a byte for building the data frame of PCF7931 tags
* @param b : byte to add
* @param tab : array of the data frame
* @param l : offset on low pulse width
* @param p : offset on low pulse positioning
*/
bool AddBytePCF7931(uint8_t byte, uint32_t *tab, int32_t l, int32_t p) {
uint32_t u;
for (u = 0; u < 8; ++u) {
if (byte & (1 << u)) { //bit is 1
if (AddBitPCF7931(1, tab, l, p) == 1) return 1;
} else { //bit is 0
if (AddBitPCF7931(0, tab, l, p) == 1) return 1;
}
}
bool AddBytePCF7931(uint8_t byte, uint32_t * tab, int32_t l, int32_t p){
uint32_t u;
for ( u=0; u<8; u++)
{
if (byte&(1<<u)) { //bit à 1
if( AddBitPCF7931(1, tab, l, p)==1) return 1;
} else { //bit à 0
if (AddBitPCF7931(0, tab, l, p)==1) return 1;
}
}
return 0;
return 0;
}
/* Add a bits for building the data frame of PCF7931 tags
/* Add a bits for building the data frame of PCF7931 tags
* @param b : bit to add
* @param tab : array of the data frame
* @param l : offset on low pulse width
* @param p : offset on low pulse positioning
*/
bool AddBitPCF7931(bool b, uint32_t * tab, int32_t l, int32_t p){
uint8_t u = 0;
bool AddBitPCF7931(bool b, uint32_t *tab, int32_t l, int32_t p) {
uint8_t u = 0;
//we put the cursor at the last value of the array
for ( u = 0; tab[u] != 0; u += 3 ) { }
if ( b == 1 ) { //add a bit 1
if ( u == 0 )
tab[u] = 34 * T0_PCF + p;
else
tab[u] = 34 * T0_PCF + tab[u-1] + p;
//we put the cursor at the last value of the array
for (u = 0; tab[u] != 0; u += 3) { }
tab[u+1] = 6 * T0_PCF + tab[u] + l;
tab[u+2] = 88 * T0_PCF + tab[u+1] - l - p;
return 0;
} else { //add a bit 0
if (b == 1) { //add a bit 1
if (u == 0)
tab[u] = 34 * T0_PCF + p;
else
tab[u] = 34 * T0_PCF + tab[u - 1] + p;
if ( u == 0 )
tab[u] = 98 * T0_PCF + p;
else
tab[u] = 98 * T0_PCF + tab[u-1] + p;
tab[u + 1] = 6 * T0_PCF + tab[u] + l;
tab[u + 2] = 88 * T0_PCF + tab[u + 1] - l - p;
return 0;
} else { //add a bit 0
tab[u+1] = 6 * T0_PCF + tab[u] + l;
tab[u+2] = 24 * T0_PCF + tab[u+1] - l - p;
return 0;
}
return 1;
if (u == 0)
tab[u] = 98 * T0_PCF + p;
else
tab[u] = 98 * T0_PCF + tab[u - 1] + p;
tab[u + 1] = 6 * T0_PCF + tab[u] + l;
tab[u + 2] = 24 * T0_PCF + tab[u + 1] - l - p;
return 0;
}
return 1;
}
/* Add a custom pattern in the data frame
@ -493,13 +508,13 @@ bool AddBitPCF7931(bool b, uint32_t * tab, int32_t l, int32_t p){
* @param c : delay of the last high pulse
* @param tab : array of the data frame
*/
bool AddPatternPCF7931(uint32_t a, uint32_t b, uint32_t c, uint32_t * tab){
uint32_t u = 0;
for(u = 0; tab[u] != 0; u += 3){} //we put the cursor at the last value of the array
bool AddPatternPCF7931(uint32_t a, uint32_t b, uint32_t c, uint32_t *tab) {
uint32_t u = 0;
for (u = 0; tab[u] != 0; u += 3) {} //we put the cursor at the last value of the array
tab[u] = (u == 0) ? a : a + tab[u-1];
tab[u+1] = b + tab[u];
tab[u+2] = c + tab[u+1];
tab[u] = (u == 0) ? a : a + tab[u - 1];
tab[u + 1] = b + tab[u];
tab[u + 2] = c + tab[u + 1];
return 0;
}
return 0;
}

View file

@ -7,14 +7,14 @@
#include "pcf7931.h"
#include "string.h"
int DemodPCF7931(uint8_t **outBlocks);
int IsBlock0PCF7931(uint8_t *Block);
int IsBlock1PCF7931(uint8_t *Block);
size_t DemodPCF7931(uint8_t **outBlocks);
bool IsBlock0PCF7931(uint8_t *block);
bool IsBlock1PCF7931(uint8_t *block);
void ReadPCF7931();
void SendCmdPCF7931(uint32_t * tab);
bool AddBytePCF7931(uint8_t byte, uint32_t * tab, int32_t l, int32_t p);
bool AddBitPCF7931(bool b, uint32_t * tab, int32_t l, int32_t p);
bool AddPatternPCF7931(uint32_t a, uint32_t b, uint32_t c, uint32_t * tab);
void SendCmdPCF7931(uint32_t *tab);
bool AddBytePCF7931(uint8_t byte, uint32_t *tab, int32_t l, int32_t p);
bool AddBitPCF7931(bool b, uint32_t *tab, int32_t l, int32_t p);
bool AddPatternPCF7931(uint32_t a, uint32_t b, uint32_t c, uint32_t *tab);
void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data);
#endif
#endif

View file

@ -1,6 +1,6 @@
/*-
* Copyright (c) 1986, 1988, 1991, 1993
* The Regents of the University of California. All rights reserved.
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
@ -31,7 +31,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)subr_prf.c 8.3 (Berkeley) 1/21/94
* @(#)subr_prf.c 8.3 (Berkeley) 1/21/94
*/
#include "printf.h"
@ -50,7 +50,7 @@ char const hex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz";
#define toupper(c) ((c) - 0x20 * (((c) >= 'a') && ((c) <= 'z')))
/* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */
#define MAXNBUF (sizeof(intmax_t) * NBBY + 1)
#define MAXNBUF (sizeof(intmax_t) * NBBY + 1)
/*
* Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
@ -59,19 +59,16 @@ char const hex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz";
* The buffer pointed to by `nbuf' must have length >= MAXNBUF.
*/
static char *
ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
{
char *p, c;
p = nbuf;
*p = '\0';
do {
c = hex2ascii(num % base);
*++p = upper ? toupper(c) : c;
} while (num /= base);
if (lenp)
*lenp = p - nbuf;
return (p);
ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper) {
char *p = nbuf;
*p = '\0';
do {
char c = hex2ascii(num % base);
*++p = upper ? toupper(c) : c;
} while (num /= base);
if (lenp)
*lenp = p - nbuf;
return (p);
}
/*
@ -82,7 +79,7 @@ ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
* The format %b is supported to decode error registers.
* Its usage is:
*
* printf("reg=%b\n", regval, "*");
* printf("reg=%b\n", regval, "*");
*
* where is the output base expressed as a control character, e.g.
* \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
@ -90,340 +87,356 @@ ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
* the next characters (up to a control character, i.e. a character <= 32),
* give the name of the register. Thus:
*
* kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
* kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
*
* would produce output:
*
* reg=3
* reg=3
*
* XXX: %D -- Hexdump, takes pointer and separator string:
* ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX
* ("%*D", len, ptr, " " -> XX XX XX XX ...
* ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX
* ("%*D", len, ptr, " " -> XX XX XX XX ...
*/
int
kvsprintf(char const *fmt, void *arg, int radix, va_list ap)
{
kvsprintf(char const *fmt, void *arg, int radix, va_list ap) {
#define PCHAR(c) {int cc=(c); *d++ = cc; retval++; }
char nbuf[MAXNBUF];
char *d;
const char *p, *percent, *q;
u_char *up;
int ch, n;
uintmax_t num;
int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
int cflag, hflag, jflag, tflag, zflag;
int dwidth, upper;
char padc;
int stop = 0, retval = 0;
char nbuf[MAXNBUF];
char *d;
const char *p, *percent, *q;
u_char *up;
int ch, n;
uintmax_t num;
int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
int cflag, hflag, jflag, tflag, zflag;
int dwidth, upper;
char padc;
int stop = 0, retval = 0;
num = 0;
d = (char *) arg;
num = 0;
d = (char *) arg;
if (fmt == NULL)
fmt = "(fmt null)\n";
if (fmt == NULL)
fmt = "(fmt null)\n";
if (radix < 2 || radix > 36)
radix = 10;
if (radix < 2 || radix > 36)
radix = 10;
for (;;) {
padc = ' ';
width = 0;
while ((ch = (u_char)*fmt++) != '%' || stop) {
PCHAR(ch);
if (ch == '\0')
return (retval);
}
percent = fmt - 1;
qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
sign = 0; dot = 0; dwidth = 0; upper = 0;
cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
reswitch: switch (ch = (u_char)*fmt++) {
case '.':
dot = 1;
goto reswitch;
case '#':
sharpflag = 1;
goto reswitch;
case '+':
sign = 1;
goto reswitch;
case '-':
ladjust = 1;
goto reswitch;
case '%':
PCHAR(ch);
break;
case '*':
if (!dot) {
width = va_arg(ap, int);
if (width < 0) {
ladjust = !ladjust;
width = -width;
}
} else {
dwidth = va_arg(ap, int);
}
goto reswitch;
case '0':
if (!dot) {
padc = '0';
goto reswitch;
}
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
for (n = 0;; ++fmt) {
n = n * 10 + ch - '0';
ch = *fmt;
if (ch < '0' || ch > '9')
break;
}
if (dot)
dwidth = n;
else
width = n;
goto reswitch;
case 'b':
num = (u_int)va_arg(ap, int);
p = va_arg(ap, char *);
for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
PCHAR(*q--);
for (;;) {
padc = ' ';
width = 0;
while ((ch = (u_char) * fmt++) != '%' || stop) {
PCHAR(ch);
if (ch == '\0')
return (retval);
}
percent = fmt - 1;
qflag = 0;
lflag = 0;
ladjust = 0;
sharpflag = 0;
neg = 0;
sign = 0;
dot = 0;
dwidth = 0;
upper = 0;
cflag = 0;
hflag = 0;
jflag = 0;
tflag = 0;
zflag = 0;
reswitch:
switch (ch = (u_char) * fmt++) {
case '.':
dot = 1;
goto reswitch;
case '#':
sharpflag = 1;
goto reswitch;
case '+':
sign = 1;
goto reswitch;
case '-':
ladjust = 1;
goto reswitch;
case '%':
PCHAR(ch);
break;
case '*':
if (!dot) {
width = va_arg(ap, int);
if (width < 0) {
ladjust = !ladjust;
width = -width;
}
} else {
dwidth = va_arg(ap, int);
}
goto reswitch;
case '0':
if (!dot) {
padc = '0';
goto reswitch;
}
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
for (n = 0;; ++fmt) {
n = n * 10 + ch - '0';
ch = *fmt;
if (ch < '0' || ch > '9')
break;
}
if (dot)
dwidth = n;
else
width = n;
goto reswitch;
case 'b':
num = (u_int)va_arg(ap, int);
p = va_arg(ap, char *);
for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
PCHAR(*q--);
if (num == 0)
break;
if (num == 0)
break;
for (tmp = 0; *p;) {
n = *p++;
if (num & (1 << (n - 1))) {
PCHAR(tmp ? ',' : '<');
for (; (n = *p) > ' '; ++p)
PCHAR(n);
tmp = 1;
} else
for (; *p > ' '; ++p)
continue;
}
if (tmp)
PCHAR('>');
break;
case 'c':
PCHAR(va_arg(ap, int));
break;
case 'D':
up = va_arg(ap, u_char *);
p = va_arg(ap, char *);
if (!width)
width = 16;
while(width--) {
PCHAR(hex2ascii(*up >> 4));
PCHAR(hex2ascii(*up & 0x0f));
up++;
if (width)
for (q=p;*q;q++)
PCHAR(*q);
}
break;
case 'd':
case 'i':
base = 10;
sign = 1;
goto handle_sign;
case 'h':
if (hflag) {
hflag = 0;
cflag = 1;
} else
hflag = 1;
goto reswitch;
case 'j':
jflag = 1;
goto reswitch;
case 'l':
if (lflag) {
lflag = 0;
qflag = 1;
} else
lflag = 1;
goto reswitch;
case 'n':
if (jflag)
*(va_arg(ap, intmax_t *)) = retval;
else if (qflag)
*(va_arg(ap, quad_t *)) = retval;
else if (lflag)
*(va_arg(ap, long *)) = retval;
else if (zflag)
*(va_arg(ap, size_t *)) = retval;
else if (hflag)
*(va_arg(ap, short *)) = retval;
else if (cflag)
*(va_arg(ap, char *)) = retval;
else
*(va_arg(ap, int *)) = retval;
break;
case 'o':
base = 8;
goto handle_nosign;
case 'p':
base = 16;
sharpflag = (width == 0);
sign = 0;
num = (uintptr_t)va_arg(ap, void *);
goto number;
case 'q':
qflag = 1;
goto reswitch;
case 'r':
base = radix;
if (sign)
goto handle_sign;
goto handle_nosign;
case 's':
p = va_arg(ap, char *);
if (p == NULL)
p = "(null)";
if (!dot)
n = strlen (p);
else
for (n = 0; n < dwidth && p[n]; n++)
continue;
for (tmp = 0; *p;) {
n = *p++;
if (num & (1 << (n - 1))) {
PCHAR(tmp ? ',' : '<');
for (; (n = *p) > ' '; ++p)
PCHAR(n);
tmp = 1;
} else
for (; *p > ' '; ++p)
continue;
}
if (tmp)
PCHAR('>');
break;
case 'c':
PCHAR(va_arg(ap, int));
break;
case 'D':
up = va_arg(ap, u_char *);
p = va_arg(ap, char *);
if (!width)
width = 16;
while (width--) {
PCHAR(hex2ascii(*up >> 4));
PCHAR(hex2ascii(*up & 0x0f));
up++;
if (width)
for (q = p; *q; q++)
PCHAR(*q);
}
break;
case 'd':
case 'i':
base = 10;
sign = 1;
goto handle_sign;
case 'h':
if (hflag) {
hflag = 0;
cflag = 1;
} else
hflag = 1;
goto reswitch;
case 'j':
jflag = 1;
goto reswitch;
case 'l':
if (lflag) {
lflag = 0;
qflag = 1;
} else
lflag = 1;
goto reswitch;
case 'n':
if (jflag)
*(va_arg(ap, intmax_t *)) = retval;
else if (qflag)
*(va_arg(ap, quad_t *)) = retval;
else if (lflag)
*(va_arg(ap, long *)) = retval;
else if (zflag)
*(va_arg(ap, size_t *)) = retval;
else if (hflag)
*(va_arg(ap, short *)) = retval;
else if (cflag)
*(va_arg(ap, char *)) = retval;
else
*(va_arg(ap, int *)) = retval;
break;
case 'o':
base = 8;
goto handle_nosign;
case 'p':
base = 16;
sharpflag = (width == 0);
sign = 0;
num = (uintptr_t)va_arg(ap, void *);
goto number;
case 'q':
qflag = 1;
goto reswitch;
case 'r':
base = radix;
if (sign)
goto handle_sign;
goto handle_nosign;
case 's':
p = va_arg(ap, char *);
if (p == NULL)
p = "(null)";
if (!dot)
n = strlen(p);
else
for (n = 0; n < dwidth && p[n]; n++)
continue;
width -= n;
width -= n;
if (!ladjust && width > 0)
while (width--)
PCHAR(padc);
while (n--)
PCHAR(*p++);
if (ladjust && width > 0)
while (width--)
PCHAR(padc);
break;
case 't':
tflag = 1;
goto reswitch;
case 'u':
base = 10;
goto handle_nosign;
case 'X':
upper = 1;
case 'x':
base = 16;
goto handle_nosign;
case 'y':
base = 16;
sign = 1;
goto handle_sign;
case 'z':
zflag = 1;
goto reswitch;
if (!ladjust && width > 0)
while (width--)
PCHAR(padc);
while (n--)
PCHAR(*p++);
if (ladjust && width > 0)
while (width--)
PCHAR(padc);
break;
case 't':
tflag = 1;
goto reswitch;
case 'u':
base = 10;
goto handle_nosign;
case 'X':
upper = 1;
case 'x':
base = 16;
goto handle_nosign;
case 'y':
base = 16;
sign = 1;
goto handle_sign;
case 'z':
zflag = 1;
goto reswitch;
handle_nosign:
sign = 0;
if (jflag)
num = va_arg(ap, uintmax_t);
else if (qflag)
num = va_arg(ap, u_quad_t);
else if (tflag)
num = va_arg(ap, ptrdiff_t);
else if (lflag)
num = va_arg(ap, u_long);
else if (zflag)
num = va_arg(ap, size_t);
else if (hflag)
num = (u_short)va_arg(ap, int);
else if (cflag)
num = (u_char)va_arg(ap, int);
else
num = va_arg(ap, u_int);
goto number;
sign = 0;
if (jflag)
num = va_arg(ap, uintmax_t);
else if (qflag)
num = va_arg(ap, u_quad_t);
else if (tflag)
num = va_arg(ap, ptrdiff_t);
else if (lflag)
num = va_arg(ap, u_long);
else if (zflag)
num = va_arg(ap, size_t);
else if (hflag)
num = (u_short)va_arg(ap, int);
else if (cflag)
num = (u_char)va_arg(ap, int);
else
num = va_arg(ap, u_int);
goto number;
handle_sign:
if (jflag)
num = va_arg(ap, intmax_t);
else if (qflag)
num = va_arg(ap, quad_t);
else if (tflag)
num = va_arg(ap, ptrdiff_t);
else if (lflag)
num = va_arg(ap, long);
else if (zflag)
num = va_arg(ap, ssize_t);
else if (hflag)
num = (short)va_arg(ap, int);
else if (cflag)
num = (char)va_arg(ap, int);
else
num = va_arg(ap, int);
if (jflag)
num = va_arg(ap, intmax_t);
else if (qflag)
num = va_arg(ap, quad_t);
else if (tflag)
num = va_arg(ap, ptrdiff_t);
else if (lflag)
num = va_arg(ap, long);
else if (zflag)
num = va_arg(ap, ssize_t);
else if (hflag)
num = (short)va_arg(ap, int);
else if (cflag)
num = (char)va_arg(ap, int);
else
num = va_arg(ap, int);
number:
if (sign && (intmax_t)num < 0) {
neg = 1;
num = -(intmax_t)num;
}
p = ksprintn(nbuf, num, base, &tmp, upper);
if (sharpflag && num != 0) {
if (base == 8)
tmp++;
else if (base == 16)
tmp += 2;
}
if (neg)
tmp++;
if (sign && (intmax_t)num < 0) {
neg = 1;
num = -(intmax_t)num;
}
p = ksprintn(nbuf, num, base, &tmp, upper);
if (sharpflag && num != 0) {
if (base == 8)
tmp++;
else if (base == 16)
tmp += 2;
}
if (neg)
tmp++;
if (!ladjust && padc != '0' && width
&& (width -= tmp) > 0)
while (width--)
PCHAR(padc);
if (neg)
PCHAR('-');
if (sharpflag && num != 0) {
if (base == 8) {
PCHAR('0');
} else if (base == 16) {
PCHAR('0');
PCHAR('x');
}
}
if (!ladjust && width && (width -= tmp) > 0)
while (width--)
PCHAR(padc);
if (!ladjust && padc != '0' && width
&& (width -= tmp) > 0)
while (width--)
PCHAR(padc);
if (neg)
PCHAR('-');
if (sharpflag && num != 0) {
if (base == 8) {
PCHAR('0');
} else if (base == 16) {
PCHAR('0');
PCHAR('x');
}
}
if (!ladjust && width && (width -= tmp) > 0)
while (width--)
PCHAR(padc);
while (*p)
PCHAR(*p--);
while (*p)
PCHAR(*p--);
if (ladjust && width && (width -= tmp) > 0)
while (width--)
PCHAR(padc);
if (ladjust && width && (width -= tmp) > 0)
while (width--)
PCHAR(padc);
break;
default:
while (percent < fmt)
PCHAR(*percent++);
/*
* Since we ignore an formatting argument it is no
* longer safe to obey the remaining formatting
* arguments as the arguments will no longer match
* the format specs.
*/
stop = 1;
break;
}
}
PCHAR(0);
return retval;
break;
default:
while (percent < fmt)
PCHAR(*percent++);
/*
* Since we ignore an formatting argument it is no
* longer safe to obey the remaining formatting
* arguments as the arguments will no longer match
* the format specs.
*/
stop = 1;
break;
}
}
PCHAR(0);
return retval;
#undef PCHAR
}
int vsprintf(char *dest, const char *fmt, va_list ap)
{
return kvsprintf(fmt, dest, 10, ap);
int vsprintf(char *dest, const char *fmt, va_list ap) {
return kvsprintf(fmt, dest, 10, ap);
}
int
sprintf(char *dest, const char *fmt, ...)
{
/* http://www.pagetable.com/?p=298 */
int retval;
va_list ap;
va_start(ap, fmt);
retval = kvsprintf(fmt, dest, 10, ap);
va_end(ap);
return retval;
sprintf(char *dest, const char *fmt, ...) {
/* http://www.pagetable.com/?p=298 */
int retval;
va_list ap;
va_start(ap, fmt);
retval = kvsprintf(fmt, dest, 10, ap);
va_end(ap);
return retval;
}

View file

@ -15,8 +15,8 @@
#include <stddef.h>
#include "string.h"
int kvsprintf(const char *format, void *arg, int radix, va_list ap) __attribute__ ((format (printf, 1, 0)));
int vsprintf(char *str, const char *format, va_list ap) __attribute__ ((format (printf, 2, 0)));
int sprintf(char *str, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
int kvsprintf(const char *fmt, void *arg, int radix, va_list ap) __attribute__((format(printf, 1, 0)));
int vsprintf(char *dest, const char *fmt, va_list ap) __attribute__((format(printf, 2, 0)));
int sprintf(char *dest, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
#endif

View file

@ -21,64 +21,62 @@ static uint8_t *next_free_memory;
extern struct common_area common_area;
extern char __data_src_start__, __data_start__, __data_end__, __bss_start__, __bss_end__;
static voidpf inflate_malloc(voidpf opaque, uInt items, uInt size)
{
uint8_t *allocated_memory;
allocated_memory = next_free_memory;
next_free_memory += items*size;
return allocated_memory;
static voidpf inflate_malloc(voidpf opaque, uInt items, uInt size) {
uint8_t *allocated_memory;
allocated_memory = next_free_memory;
next_free_memory += items * size;
return allocated_memory;
}
static void inflate_free(voidpf opaque, voidpf address)
{
// nothing to do
static void inflate_free(voidpf opaque, voidpf address) {
// nothing to do
}
static void uncompress_data_section(void)
{
z_stream data_section;
static void uncompress_data_section(void) {
z_stream data_section;
next_free_memory = BigBuf_get_addr();
// initialize zstream structure
data_section.next_in = (uint8_t *) &__data_src_start__;
data_section.avail_in = &__data_end__ - &__data_start__; // uncompressed size. Wrong but doesn't matter.
data_section.next_out = (uint8_t *) &__data_start__;
data_section.avail_out = &__data_end__ - &__data_start__; // uncompressed size. Correct.
data_section.zalloc = &inflate_malloc;
data_section.zfree = &inflate_free;
data_section.opaque = NULL;
next_free_memory = BigBuf_get_addr();
// initialize zlib for inflate
inflateInit2(&data_section, 15);
// initialize zstream structure
data_section.next_in = (uint8_t *) &__data_src_start__;
data_section.avail_in = &__data_end__ - &__data_start__; // uncompressed size. Wrong but doesn't matter.
data_section.next_out = (uint8_t *) &__data_start__;
data_section.avail_out = &__data_end__ - &__data_start__; // uncompressed size. Correct.
data_section.zalloc = &inflate_malloc;
data_section.zfree = &inflate_free;
data_section.opaque = NULL;
// uncompress data segment to RAM
inflate(&data_section, Z_FINISH);
// save the size of the compressed data section
common_area.arg1 = data_section.total_in;
// initialize zlib for inflate
int res = inflateInit2(&data_section, 15);
if (res < 0)
return;
// uncompress data segment to RAM
inflate(&data_section, Z_FINISH);
// save the size of the compressed data section
common_area.arg1 = data_section.total_in;
}
void __attribute__((section(".startos"))) Vector(void)
{
/* Stack should have been set up by the bootloader */
// char *src;
char *dst, *end;
uncompress_data_section();
void __attribute__((section(".startos"))) Vector(void) {
/* Stack should have been set up by the bootloader */
// char *src;
char *dst, *end;
/* Set up (that is: clear) BSS. */
dst = &__bss_start__;
end = &__bss_end__;
while(dst < end) *dst++ = 0;
uncompress_data_section();
// Set up data segment: Copy from flash to ram
// src = &__data_src_start__;
// dst = &__data_start__;
// end = &__data_end__;
// while(dst < end) *dst++ = *src++;
/* Set up (that is: clear) BSS. */
dst = &__bss_start__;
end = &__bss_end__;
while (dst < end) *dst++ = 0;
AppMain();
// Set up data segment: Copy from flash to ram
// src = &__data_src_start__;
// dst = &__data_start__;
// end = &__data_end__;
// while(dst < end) *dst++ = *src++;
AppMain();
}
#endif
#endif

View file

@ -9,98 +9,88 @@
//-----------------------------------------------------------------------------
#include "string.h"
void *memcpy(void *dest, const void *src, int len)
{
uint8_t *d = dest;
const uint8_t *s = src;
while((len--) > 0) {
*d = *s;
d++;
s++;
}
return dest;
void *memcpy(void *dest, const void *src, int len) {
uint8_t *d = dest;
const uint8_t *s = src;
while ((len--) > 0) {
*d = *s;
d++;
s++;
}
return dest;
}
void *memset(void *dest, int c, int len)
{
uint8_t *d = dest;
while((len--) > 0) {
*d = c;
d++;
}
return dest;
void *memset(void *dest, int c, int len) {
uint8_t *d = dest;
while ((len--) > 0) {
*d = c;
d++;
}
return dest;
}
int memcmp(const void *av, const void *bv, int len)
{
const uint8_t *a = av;
const uint8_t *b = bv;
int memcmp(const void *av, const void *bv, int len) {
const uint8_t *a = av;
const uint8_t *b = bv;
while((len--) > 0) {
if(*a != *b) {
return *a - *b;
}
a++;
b++;
}
return 0;
while ((len--) > 0) {
if (*a != *b) {
return *a - *b;
}
a++;
b++;
}
return 0;
}
void memxor(uint8_t * dest, uint8_t * src, size_t len) {
for( ; len > 0; len--,dest++,src++)
*dest ^= *src;
void memxor(uint8_t *dest, uint8_t *src, size_t len) {
for (; len > 0; len--, dest++, src++)
*dest ^= *src;
}
int strlen(const char *str)
{
int l = 0;
while(*str) {
l++;
str++;
}
return l;
int strlen(const char *str) {
const char *p;
for (p = str; *p != '\0'; ++p) {
}
return p - str;
}
char* strncat(char *dest, const char *src, unsigned int n)
{
unsigned int dest_len = strlen(dest);
unsigned int i;
char *strncat(char *dest, const char *src, unsigned int n) {
unsigned int dest_len = strlen(dest);
unsigned int i;
for (i = 0 ; i < n && src[i] != '\0' ; i++)
dest[dest_len + i] = src[i];
dest[dest_len + i] = '\0';
for (i = 0 ; i < n && src[i] != '\0' ; i++)
dest[dest_len + i] = src[i];
dest[dest_len + i] = '\0';
return dest;
return dest;
}
char* strcat(char *dest, const char *src)
{
unsigned int dest_len = strlen(dest);
unsigned int i;
char *strcat(char *dest, const char *src) {
unsigned int dest_len = strlen(dest);
unsigned int i;
for (i = 0 ; src[i] != '\0' ; i++)
dest[dest_len + i] = src[i];
dest[dest_len + i] = '\0';
for (i = 0 ; src[i] != '\0' ; i++)
dest[dest_len + i] = src[i];
dest[dest_len + i] = '\0';
return dest;
return dest;
}
////////////////////////////////////////// code to do 'itoa'
/* reverse: reverse string s in place */
void strreverse(char s[])
{
int c, i, j;
void strreverse(char s[]) {
int j = strlen(s) - 1;
for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
c = s[i];
for (int i = 0; i < j; i++, j--) {
int c = s[i];
s[i] = s[j];
s[j] = c;
}
}
/* itoa: convert n to characters in s */
void itoa(int n, char s[])
{
void itoa(int n, char s[]) {
int i, sign;
if ((sign = n) < 0) /* record sign */

View file

@ -18,10 +18,10 @@ int strlen(const char *str);
void *memcpy(void *dest, const void *src, int len);
void *memset(void *dest, int c, int len);
int memcmp(const void *av, const void *bv, int len);
void memxor(uint8_t * dest, uint8_t * src, size_t len);
void memxor(uint8_t *dest, uint8_t *src, size_t len);
char *strncat(char *dest, const char *src, unsigned int n);
char *strcat(char *dest, const char *src);
void strreverse(char s[]);
void itoa(int n, char s[]);
#endif /* __STRING_H */
#endif /* __STRING_H */

View file

@ -12,229 +12,236 @@
// attempt at high resolution microsecond timer
// beware: timer counts in 21.3uS increments (1024/48Mhz)
void SpinDelayUs(int us) {
int ticks = (48 * us) >> 10;
int ticks = (48 * us) >> 10;
// Borrow a PWM unit for my real-time clock
AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0);
// 48 MHz / 1024 gives 46.875 kHz
AT91C_BASE_PWMC_CH0->PWMC_CMR = PWM_CH_MODE_PRESCALER(10); // Channel Mode Register
AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0; // Channel Duty Cycle Register
AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xffff; // Channel Period Register
// Borrow a PWM unit for my real-time clock
AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0);
uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
// 48 MHz / 1024 gives 46.875 kHz
AT91C_BASE_PWMC_CH0->PWMC_CMR = PWM_CH_MODE_PRESCALER(10); // Channel Mode Register
AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0; // Channel Duty Cycle Register
AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xffff; // Channel Period Register
for(;;) {
uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
if (now == (uint16_t)(start + ticks))
return;
uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
WDT_HIT();
}
for (;;) {
uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
if (now == (uint16_t)(start + ticks))
return;
WDT_HIT();
}
}
void SpinDelay(int ms) {
// convert to uS and call microsecond delay function
SpinDelayUs(ms*1000);
// convert to uS and call microsecond delay function
SpinDelayUs(ms * 1000);
}
// -------------------------------------------------------------------------
// timer lib
// -------------------------------------------------------------------------
// test procedure:
//
// ti = GetTickCount();
// SpinDelay(1000);
// ti = GetTickCount() - ti;
// Dbprintf("timer(1s): %d t=%d", ti, GetTickCount());
// ti = GetTickCount();
// SpinDelay(1000);
// ti = GetTickCount() - ti;
// Dbprintf("timer(1s): %d t=%d", ti, GetTickCount());
void StartTickCount(void) {
// This timer is based on the slow clock. The slow clock frequency is between 22kHz and 40kHz.
// We can determine the actual slow clock frequency by looking at the Main Clock Frequency Register.
uint16_t mainf = AT91C_BASE_PMC->PMC_MCFR & 0xffff; // = 16 * main clock frequency (16MHz) / slow clock frequency
// set RealTimeCounter divider to count at 1kHz:
AT91C_BASE_RTTC->RTTC_RTMR = AT91C_RTTC_RTTRST | ((256000 + (mainf/2)) / mainf);
// note: worst case precision is approx 2.5%
// This timer is based on the slow clock. The slow clock frequency is between 22kHz and 40kHz.
// We can determine the actual slow clock frequency by looking at the Main Clock Frequency Register.
uint16_t mainf = AT91C_BASE_PMC->PMC_MCFR & 0xffff; // = 16 * main clock frequency (16MHz) / slow clock frequency
// set RealTimeCounter divider to count at 1kHz:
AT91C_BASE_RTTC->RTTC_RTMR = AT91C_RTTC_RTTRST | ((256000 + (mainf / 2)) / mainf);
// note: worst case precision is approx 2.5%
}
/*
* Get the current count.
*/
uint32_t RAMFUNC GetTickCount(void){
return AT91C_BASE_RTTC->RTTC_RTVR;// was * 2;
uint32_t RAMFUNC GetTickCount(void) {
return AT91C_BASE_RTTC->RTTC_RTVR;// was * 2;
}
uint32_t RAMFUNC GetTickCountDelta(uint32_t start_ticks) {
uint32_t stop_ticks = AT91C_BASE_RTTC->RTTC_RTVR;
if (stop_ticks > start_ticks)
return stop_ticks - start_ticks;
return (UINT32_MAX - start_ticks) + stop_ticks;
}
// -------------------------------------------------------------------------
// microseconds timer
// microseconds timer
// -------------------------------------------------------------------------
void StartCountUS(void) {
AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1);
AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE;
AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1);
AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE;
// fast clock
// tick=1.5mks
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK | // MCK(48MHz) / 32
AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO | AT91C_TC_ACPA_CLEAR |
AT91C_TC_ACPC_SET | AT91C_TC_ASWTRG_SET;
AT91C_BASE_TC0->TC_RA = 1;
AT91C_BASE_TC0->TC_RC = 0xBFFF + 1; // 0xC000
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // timer disable
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_XC1; // from timer 0
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
AT91C_BASE_TCB->TCB_BCR = 1;
while (AT91C_BASE_TC1->TC_CV > 0);
// fast clock
// tick=1.5mks
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK | // MCK(48MHz) / 32
AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO | AT91C_TC_ACPA_CLEAR |
AT91C_TC_ACPC_SET | AT91C_TC_ASWTRG_SET;
AT91C_BASE_TC0->TC_RA = 1;
AT91C_BASE_TC0->TC_RC = 0xBFFF + 1; // 0xC000
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // timer disable
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_XC1; // from timer 0
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
AT91C_BASE_TCB->TCB_BCR = 1;
while (AT91C_BASE_TC1->TC_CV > 0);
}
uint32_t RAMFUNC GetCountUS(void){
//return (AT91C_BASE_TC1->TC_CV * 0x8000) + ((AT91C_BASE_TC0->TC_CV / 15) * 10);
// By suggestion from PwPiwi, http://www.proxmark.org/forum/viewtopic.php?pid=17548#p17548
return ((uint32_t)AT91C_BASE_TC1->TC_CV) * 0x8000 + (((uint32_t)AT91C_BASE_TC0->TC_CV) * 2) / 3;
uint32_t RAMFUNC GetCountUS(void) {
//return (AT91C_BASE_TC1->TC_CV * 0x8000) + ((AT91C_BASE_TC0->TC_CV / 15) * 10);
// By suggestion from PwPiwi, http://www.proxmark.org/forum/viewtopic.php?pid=17548#p17548
return ((uint32_t)AT91C_BASE_TC1->TC_CV) * 0x8000 + (((uint32_t)AT91C_BASE_TC0->TC_CV) * 2) / 3;
}
// -------------------------------------------------------------------------
// Timer for iso14443 commands. Uses ssp_clk from FPGA
// Timer for iso14443 commands. Uses ssp_clk from FPGA
// -------------------------------------------------------------------------
void StartCountSspClk(void) {
AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1) | (1 << AT91C_ID_TC2); // Enable Clock to all timers
AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_TIOA1 // XC0 Clock = TIOA1
| AT91C_TCB_TC1XC1S_NONE // XC1 Clock = none
| AT91C_TCB_TC2XC2S_TIOA0; // XC2 Clock = TIOA0
AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1) | (1 << AT91C_ID_TC2); // Enable Clock to all timers
AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_TIOA1 // XC0 Clock = TIOA1
| AT91C_TCB_TC1XC1S_NONE // XC1 Clock = none
| AT91C_TCB_TC2XC2S_TIOA0; // XC2 Clock = TIOA0
// configure TC1 to create a short pulse on TIOA1 when a rising edge on TIOB1 (= ssp_clk from FPGA) occurs:
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // disable TC1
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK // TC1 Clock = MCK(48MHz)/2 = 24MHz
| AT91C_TC_CPCSTOP // Stop clock on RC compare
| AT91C_TC_EEVTEDG_RISING // Trigger on rising edge of Event
| AT91C_TC_EEVT_TIOB // Event-Source: TIOB1 (= ssp_clk from FPGA = 13,56MHz/16)
| AT91C_TC_ENETRG // Enable external trigger event
| AT91C_TC_WAVESEL_UP // Upmode without automatic trigger on RC compare
| AT91C_TC_WAVE // Waveform Mode
| AT91C_TC_AEEVT_SET // Set TIOA1 on external event
| AT91C_TC_ACPC_CLEAR; // Clear TIOA1 on RC Compare
AT91C_BASE_TC1->TC_RC = 0x04; // RC Compare value = 0x04
// configure TC1 to create a short pulse on TIOA1 when a rising edge on TIOB1 (= ssp_clk from FPGA) occurs:
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // disable TC1
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK // TC1 Clock = MCK(48MHz)/2 = 24MHz
| AT91C_TC_CPCSTOP // Stop clock on RC compare
| AT91C_TC_EEVTEDG_RISING // Trigger on rising edge of Event
| AT91C_TC_EEVT_TIOB // Event-Source: TIOB1 (= ssp_clk from FPGA = 13,56MHz/16)
| AT91C_TC_ENETRG // Enable external trigger event
| AT91C_TC_WAVESEL_UP // Upmode without automatic trigger on RC compare
| AT91C_TC_WAVE // Waveform Mode
| AT91C_TC_AEEVT_SET // Set TIOA1 on external event
| AT91C_TC_ACPC_CLEAR; // Clear TIOA1 on RC Compare
AT91C_BASE_TC1->TC_RC = 0x04; // RC Compare value = 0x04
// use TC0 to count TIOA1 pulses
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // disable TC0
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_XC0 // TC0 clock = XC0 clock = TIOA1
| AT91C_TC_WAVE // Waveform Mode
| AT91C_TC_WAVESEL_UP // just count
| AT91C_TC_ACPA_CLEAR // Clear TIOA0 on RA Compare
| AT91C_TC_ACPC_SET; // Set TIOA0 on RC Compare
AT91C_BASE_TC0->TC_RA = 1; // RA Compare value = 1; pulse width to TC2
AT91C_BASE_TC0->TC_RC = 0; // RC Compare value = 0; increment TC2 on overflow
// use TC0 to count TIOA1 pulses
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // disable TC0
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_XC0 // TC0 clock = XC0 clock = TIOA1
| AT91C_TC_WAVE // Waveform Mode
| AT91C_TC_WAVESEL_UP // just count
| AT91C_TC_ACPA_CLEAR // Clear TIOA0 on RA Compare
| AT91C_TC_ACPC_SET; // Set TIOA0 on RC Compare
AT91C_BASE_TC0->TC_RA = 1; // RA Compare value = 1; pulse width to TC2
AT91C_BASE_TC0->TC_RC = 0; // RC Compare value = 0; increment TC2 on overflow
// use TC2 to count TIOA0 pulses (giving us a 32bit counter (TC0/TC2) clocked by ssp_clk)
AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKDIS; // disable TC2
AT91C_BASE_TC2->TC_CMR = AT91C_TC_CLKS_XC2 // TC2 clock = XC2 clock = TIOA0
| AT91C_TC_WAVE // Waveform Mode
| AT91C_TC_WAVESEL_UP; // just count
// use TC2 to count TIOA0 pulses (giving us a 32bit counter (TC0/TC2) clocked by ssp_clk)
AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKDIS; // disable TC2
AT91C_BASE_TC2->TC_CMR = AT91C_TC_CLKS_XC2 // TC2 clock = XC2 clock = TIOA0
| AT91C_TC_WAVE // Waveform Mode
| AT91C_TC_WAVESEL_UP; // just count
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // enable and reset TC0
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // enable and reset TC1
AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // enable and reset TC2
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // enable and reset TC0
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // enable and reset TC1
AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // enable and reset TC2
// synchronize the counter with the ssp_frame signal.
// Note: FPGA must be in any iso14443 mode, otherwise the frame signal would not be present
while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME)); // wait for ssp_frame to go high (start of frame)
while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME); // wait for ssp_frame to be low
while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high
// synchronize the counter with the ssp_frame signal.
// Note: FPGA must be in any iso14443 mode, otherwise the frame signal would not be present
while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME)); // wait for ssp_frame to go high (start of frame)
while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME); // wait for ssp_frame to be low
while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high
// note: up to now two ssp_clk rising edges have passed since the rising edge of ssp_frame
// it is now safe to assert a sync signal. This sets all timers to 0 on next active clock edge
AT91C_BASE_TCB->TCB_BCR = 1; // assert Sync (set all timers to 0 on next active clock edge)
// at the next (3rd) ssp_clk rising edge, TC1 will be reset (and not generate a clock signal to TC0)
// at the next (4th) ssp_clk rising edge, TC0 (the low word of our counter) will be reset. From now on,
// whenever the last three bits of our counter go 0, we can be sure to be in the middle of a frame transfer.
// (just started with the transfer of the 4th Bit).
// note: up to now two ssp_clk rising edges have passed since the rising edge of ssp_frame
// it is now safe to assert a sync signal. This sets all timers to 0 on next active clock edge
AT91C_BASE_TCB->TCB_BCR = 1; // assert Sync (set all timers to 0 on next active clock edge)
// at the next (3rd) ssp_clk rising edge, TC1 will be reset (and not generate a clock signal to TC0)
// at the next (4th) ssp_clk rising edge, TC0 (the low word of our counter) will be reset. From now on,
// whenever the last three bits of our counter go 0, we can be sure to be in the middle of a frame transfer.
// (just started with the transfer of the 4th Bit).
// The high word of the counter (TC2) will not reset until the low word (TC0) overflows.
// Therefore need to wait quite some time before we can use the counter.
while (AT91C_BASE_TC2->TC_CV > 0);
// The high word of the counter (TC2) will not reset until the low word (TC0) overflows.
// Therefore need to wait quite some time before we can use the counter.
while (AT91C_BASE_TC2->TC_CV > 0);
}
void ResetSspClk(void) {
//enable clock of timer and software trigger
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
while (AT91C_BASE_TC2->TC_CV > 0);
void ResetSspClk(void) {
//enable clock of timer and software trigger
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
while (AT91C_BASE_TC2->TC_CV > 0);
}
uint32_t RAMFUNC GetCountSspClk(void) {
uint32_t tmp_count = (AT91C_BASE_TC2->TC_CV << 16) | AT91C_BASE_TC0->TC_CV;
if ((tmp_count & 0x0000ffff) == 0) //small chance that we may have missed an increment in TC2
return (AT91C_BASE_TC2->TC_CV << 16);
return tmp_count;
uint32_t tmp_count = (AT91C_BASE_TC2->TC_CV << 16) | AT91C_BASE_TC0->TC_CV;
if ((tmp_count & 0x0000ffff) == 0) //small chance that we may have missed an increment in TC2
return (AT91C_BASE_TC2->TC_CV << 16);
return tmp_count;
}
// -------------------------------------------------------------------------
// Timer for bitbanging, or LF stuff when you need a very precis timer
// 1us = 1.5ticks
// -------------------------------------------------------------------------
void StartTicks(void){
// initialization of the timer
AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1);
AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE;
void StartTicks(void) {
// initialization of the timer
AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1);
AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE;
// disable TC0 and TC1 for re-configuration
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
// disable TC0 and TC1 for re-configuration
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
// first configure TC1 (higher, 0xFFFF0000) 16 bit counter
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_XC1; // just connect to TIOA0 from TC0
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // re-enable timer and wait for TC0
// first configure TC1 (higher, 0xFFFF0000) 16 bit counter
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_XC1; // just connect to TIOA0 from TC0
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // re-enable timer and wait for TC0
// second configure TC0 (lower, 0x0000FFFF) 16 bit counter
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK | // MCK(48MHz) / 32
AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO |
AT91C_TC_ACPA_CLEAR | // RA comperator clears TIOA (carry bit)
AT91C_TC_ACPC_SET | // RC comperator sets TIOA (carry bit)
AT91C_TC_ASWTRG_SET; // SWTriger sets TIOA (carry bit)
AT91C_BASE_TC0->TC_RC = 0; // set TIOA (carry bit) on overflow, return to zero
AT91C_BASE_TC0->TC_RA = 1; // clear carry bit on next clock cycle
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // reset and re-enable timer
// second configure TC0 (lower, 0x0000FFFF) 16 bit counter
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK | // MCK(48MHz) / 32
AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO |
AT91C_TC_ACPA_CLEAR | // RA comperator clears TIOA (carry bit)
AT91C_TC_ACPC_SET | // RC comperator sets TIOA (carry bit)
AT91C_TC_ASWTRG_SET; // SWTriger sets TIOA (carry bit)
AT91C_BASE_TC0->TC_RC = 0; // set TIOA (carry bit) on overflow, return to zero
AT91C_BASE_TC0->TC_RA = 1; // clear carry bit on next clock cycle
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // reset and re-enable timer
// synchronized startup procedure
while (AT91C_BASE_TC0->TC_CV > 0); // wait until TC0 returned to zero
while (AT91C_BASE_TC0->TC_CV < 2); // and has started (TC_CV > TC_RA, now TC1 is cleared)
// synchronized startup procedure
while (AT91C_BASE_TC0->TC_CV > 0); // wait until TC0 returned to zero
while (AT91C_BASE_TC0->TC_CV < 2); // and has started (TC_CV > TC_RA, now TC1 is cleared)
// return to zero
AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG;
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
while (AT91C_BASE_TC0->TC_CV > 0);
// return to zero
AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG;
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
while (AT91C_BASE_TC0->TC_CV > 0);
}
uint32_t GetTicks(void) {
uint32_t hi, lo;
uint32_t hi, lo;
do {
hi = AT91C_BASE_TC1->TC_CV;
lo = AT91C_BASE_TC0->TC_CV;
} while(hi != AT91C_BASE_TC1->TC_CV);
do {
hi = AT91C_BASE_TC1->TC_CV;
lo = AT91C_BASE_TC0->TC_CV;
} while (hi != AT91C_BASE_TC1->TC_CV);
return (hi << 16) | lo;
return (hi << 16) | lo;
}
// Wait - Spindelay in ticks.
// if called with a high number, this will trigger the WDT...
void WaitTicks(uint32_t ticks){
if ( ticks == 0 ) return;
ticks += GetTicks();
while (GetTicks() < ticks);
void WaitTicks(uint32_t ticks) {
if (ticks == 0) return;
ticks += GetTicks();
while (GetTicks() < ticks);
}
// Wait / Spindelay in us (microseconds)
// Wait / Spindelay in us (microseconds)
// 1us = 1.5ticks.
void WaitUS(uint16_t us){
WaitTicks( (uint32_t)us * 3/2 );
void WaitUS(uint16_t us) {
WaitTicks((uint32_t)us * 3 / 2);
}
void WaitMS(uint16_t ms){
WaitTicks( (uint32_t)ms * 1500 );
void WaitMS(uint16_t ms) {
WaitTicks((uint32_t)ms * 1500);
}
// stop clock
void StopTicks(void){
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
void StopTicks(void) {
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
}

View file

@ -27,6 +27,7 @@ void SpinDelayUs(int us);
void StartTickCount(void);
uint32_t RAMFUNC GetTickCount(void);
uint32_t RAMFUNC GetTickCountDelta(uint32_t start_ticks);
void StartCountUS(void);
uint32_t RAMFUNC GetCountUS(void);
@ -37,11 +38,11 @@ void StartCountSspClk();
void ResetSspClk(void);
uint32_t RAMFUNC GetCountSspClk();
extern void StartTicks(void);
extern uint32_t GetTicks(void);
extern void WaitTicks(uint32_t ticks);
extern void WaitUS(uint16_t us);
extern void WaitMS(uint16_t ms);
void StartTicks(void);
uint32_t GetTicks(void);
void WaitTicks(uint32_t ticks);
void WaitUS(uint16_t us);
void WaitMS(uint16_t ms);
extern void StopTicks(void);
#endif
void StopTicks(void);
#endif

View file

@ -1,77 +0,0 @@
#include <tlv.h>
int decode_ber_tlv_item(uint8_t* data, tlvtag* returnedtag)
{
uint8_t tag[TAG_LENGTH] = {0x00,0x00};
uint16_t length = 0;
//uint8_t value[VALUE_LENGTH];
uint8_t lenlen = 0;
int i = 0;
int z = 0;
//decode tag
tag[0] = data[0];
if((tag[0] & TLV_TAG_NUMBER_MASK) == TLV_TAG_NUMBER_MASK) { //see subsequent bytes
i++;
tag[i] = data[i];
//assume tag is only two bytes long for now
/*
while((data[i] & TLV_TAG_MASK) == TLV_TAG_MASK){
i++;
tag[i] = data[i];
}
*/
}
i++;
//decode length
if((data[i] & TLV_LENGTH_MASK) == TLV_LENGTH_MASK) {
lenlen = data[i] ^ TLV_LENGTH_MASK;
i++;
length = (uint16_t)data[i];
z = 1;
while(z < lenlen){
i++;
z++;
length <<= 8;
length += (uint16_t)data[i];
}
i++;
}
else {
length = (uint16_t)data[i];
i++;
}
//copy results into the structure and return
memcpy(returnedtag->tag, tag, TAG_LENGTH);
(*returnedtag).valuelength = length; //return length of tag value
(*returnedtag).fieldlength = length + i + 1; //return length of total field
memcpy(returnedtag->value, &(data[i]), length);
return 0;
}
//generate a TLV tag off input data
int encode_ber_tlv_item(uint8_t* tag, uint8_t taglen, uint8_t* data, uint32_t datalen, uint8_t* outputtag, uint32_t* outputtaglen)
{
if(!tag || !data || !outputtag || !outputtaglen) //null pointer check
return 0;
uint8_t datafieldlen = (datalen / 128) + 1; //field length of the tag
uint8_t tlvtotallen = taglen + datafieldlen + datalen; //total length of the tag
uint8_t returnedtag[tlvtotallen]; //buffer for the returned tag
uint8_t counter = 0;
memcpy(returnedtag, tag, taglen); //copy tag into buffer
counter += taglen;
if(datalen < 128){ // 1 byte length value
returnedtag[counter++] = datalen;
}
else{
returnedtag[counter++] = datafieldlen | 0x80; //high bit set and number of length bytes
for(uint8_t i=datafieldlen; i !=0; i--){
returnedtag[counter++] = (datalen >> (i * 8)) & 0xFF; //get current byte
}
}
memcpy(&returnedtag[counter], data, datalen);
*outputtaglen = tlvtotallen;
memcpy(outputtag, returnedtag,tlvtotallen);
return 0;
}

View file

@ -1,33 +0,0 @@
#ifndef __TLV_H
#define __TLV_H
#include <stdint.h>
#include <string.h>
#include <stddef.h>
//structure buffer definitions
#define TAG_LENGTH 2
#define VALUE_LENGTH 1024
//masks
//if TLV_TAG_NUMBER_MASK bits are set, refer to the next byte for the tag number
//otherwise its located in bits 1-5
#define TLV_TAG_NUMBER_MASK 0x1f
//if TLV_DATA_MASK set then its a 'constructed data object'
//otherwise a 'primitive data object'
#define TLV_DATA_MASK 0x20
#define TLV_TAG_MASK 0x80
#define TLV_LENGTH_MASK 0x80
//tlv tag structure, tag can be max of 2 bytes, length up to 65535 and value 1024 bytes long
typedef struct {
uint8_t tag[TAG_LENGTH];
uint16_t fieldlength;
uint16_t valuelength;
uint8_t value[VALUE_LENGTH];
}tlvtag;
//decode a BER TLV
extern int decode_ber_tlv_item(uint8_t* data, tlvtag* returnedtag);
extern int encode_ber_tlv_item(uint8_t* tag, uint8_t taglen, uint8_t*data, uint32_t datalen, uint8_t* outputtag, uint32_t* outputtaglen);
#endif //__TLV_H

View file

@ -10,251 +10,261 @@
#include "util.h"
size_t nbytes(size_t nbits) {
return (nbits >> 3)+((nbits % 8) > 0);
}
/*
ref http://www.csm.ornl.gov/~dunigan/crc.html
Returns the value v with the bottom b [0,32] bits reflected.
Example: reflect(0x3e23L,3) == 0x3e26
*/
uint32_t reflect(uint32_t v, int b) {
uint32_t t = v;
for ( int i = 0; i < b; ++i) {
if (t & 1)
v |= BITMASK((b-1)-i);
else
v &= ~BITMASK((b-1)-i);
t>>=1;
}
return v;
}
uint8_t reflect8(uint8_t b) {
return ((b * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32;
}
uint16_t reflect16(uint16_t b) {
uint16_t v = 0;
v |= (b & 0x8000) >> 15;
v |= (b & 0x4000) >> 13;
v |= (b & 0x2000) >> 11;
v |= (b & 0x1000) >> 9;
v |= (b & 0x0800) >> 7;
v |= (b & 0x0400) >> 5;
v |= (b & 0x0200) >> 3;
v |= (b & 0x0100) >> 1;
v |= (b & 0x0080) << 1;
v |= (b & 0x0040) << 3;
v |= (b & 0x0020) << 5;
v |= (b & 0x0010) << 7;
v |= (b & 0x0008) << 9;
v |= (b & 0x0004) << 11;
v |= (b & 0x0002) << 13;
v |= (b & 0x0001) << 15;
return v;
}
void num_to_bytes(uint64_t n, size_t len, uint8_t* dest) {
while (len--) {
dest[len] = (uint8_t) n;
n >>= 8;
}
}
uint64_t bytes_to_num(uint8_t* src, size_t len) {
uint64_t num = 0;
while (len--) {
num = (num << 8) | (*src);
src++;
}
return num;
}
// RotateLeft - Ultralight, Desfire
void rol(uint8_t *data, const size_t len) {
uint8_t first = data[0];
for (size_t i = 0; i < len-1; i++) {
data[i] = data[i+1];
}
data[len-1] = first;
}
void lsl (uint8_t *data, size_t len) {
for (size_t n = 0; n < len - 1; n++) {
data[n] = (data[n] << 1) | (data[n+1] >> 7);
}
data[len - 1] <<= 1;
}
int32_t le24toh (uint8_t data[3]) {
return (data[2] << 16) | (data[1] << 8) | data[0];
return (nbits >> 3) + ((nbits % 8) > 0);
}
//convert hex digit to integer
uint8_t hex2int(char hexchar){
switch(hexchar){
case '0': return 0; break;
case '1': return 1; break;
case '2': return 2; break;
case '3': return 3; break;
case '4': return 4; break;
case '5': return 5; break;
case '6': return 6; break;
case '7': return 7; break;
case '8': return 8; break;
case '9': return 9; break;
uint8_t hex2int(char hexchar) {
switch (hexchar) {
case '0':
return 0;
break;
case '1':
return 1;
break;
case '2':
return 2;
break;
case '3':
return 3;
break;
case '4':
return 4;
break;
case '5':
return 5;
break;
case '6':
return 6;
break;
case '7':
return 7;
break;
case '8':
return 8;
break;
case '9':
return 9;
break;
case 'a':
case 'A': return 10; break;
case 'A':
return 10;
break;
case 'b':
case 'B': return 11; break;
case 'B':
return 11;
break;
case 'c':
case 'C': return 12; break;
case 'C':
return 12;
break;
case 'd':
case 'D': return 13; break;
case 'D':
return 13;
break;
case 'e':
case 'E': return 14; break;
case 'E':
return 14;
break;
case 'f':
case 'F': return 15; break;
case 'F':
return 15;
break;
default:
return 0;
}
}
void LEDsoff() {
LED_A_OFF();
LED_B_OFF();
LED_C_OFF();
LED_D_OFF();
LED_A_OFF();
LED_B_OFF();
LED_C_OFF();
LED_D_OFF();
}
// LEDs: R(C) O(A) G(B) -- R(D) [1, 2, 4 and 8]
void LED(int led, int ms) {
if (led & LED_RED)
LED_C_ON();
if (led & LED_ORANGE)
LED_A_ON();
if (led & LED_GREEN)
LED_B_ON();
if (led & LED_RED2)
LED_D_ON();
if (led & LED_A) // Proxmark3 historical mapping: LED_ORANGE
LED_A_ON();
if (led & LED_B) // Proxmark3 historical mapping: LED_GREEN
LED_B_ON();
if (led & LED_C) // Proxmark3 historical mapping: LED_RED
LED_C_ON();
if (led & LED_D) // Proxmark3 historical mapping: LED_RED2
LED_D_ON();
if (!ms)
return;
if (!ms)
return;
SpinDelay(ms);
SpinDelay(ms);
if (led & LED_RED)
LED_C_OFF();
if (led & LED_ORANGE)
LED_A_OFF();
if (led & LED_GREEN)
LED_B_OFF();
if (led & LED_RED2)
LED_D_OFF();
if (led & LED_A)
LED_A_OFF();
if (led & LED_B)
LED_B_OFF();
if (led & LED_C)
LED_C_OFF();
if (led & LED_D)
LED_D_OFF();
}
void SpinOff(uint32_t pause) {
LED_A_OFF();
LED_B_OFF();
LED_C_OFF();
LED_D_OFF();
SpinDelay(pause);
}
// 0=A, 1=B, 2=C, 3=D
void SpinErr(uint8_t led, uint32_t speed, uint8_t times) {
SpinOff(speed);
NTIME(times) {
switch (led) {
case 0:
LED_A_INV();
break;
case 1:
LED_B_INV();
break;
case 2:
LED_C_INV();
break;
case 3:
LED_D_INV();
break;
}
SpinDelay(speed);
}
}
void SpinDown(uint32_t speed) {
SpinOff(speed);
LED_D_ON();
SpinDelay(speed);
LED_D_OFF();
LED_C_ON();
SpinDelay(speed);
LED_C_OFF();
LED_B_ON();
SpinDelay(speed);
LED_B_OFF();
LED_A_ON();
SpinDelay(speed);
LED_A_OFF();
}
void SpinUp(uint32_t speed) {
SpinOff(speed);
LED_A_ON();
SpinDelay(speed);
LED_A_OFF();
LED_B_ON();
SpinDelay(speed);
LED_B_OFF();
LED_C_ON();
SpinDelay(speed);
LED_C_OFF();
LED_D_ON();
SpinDelay(speed);
LED_D_OFF();
}
// Determine if a button is double clicked, single clicked,
// not clicked, or held down (for ms || 1sec)
// In general, don't use this function unless you expect a
// double click, otherwise it will waste 500ms -- use BUTTON_HELD instead
int BUTTON_CLICKED(int ms) {
// Up to 500ms in between clicks to mean a double click
int ticks = (48000 * (ms ? ms : 1000)) >> 10;
// Up to 500ms in between clicks to mean a double click
int ticks = (48000 * (ms ? ms : 1000)) >> 10;
// If we're not even pressed, forget about it!
if (!BUTTON_PRESS())
return BUTTON_NO_CLICK;
// If we're not even pressed, forget about it!
if (!BUTTON_PRESS())
return BUTTON_NO_CLICK;
// Borrow a PWM unit for my real-time clock
AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0);
// 48 MHz / 1024 gives 46.875 kHz
AT91C_BASE_PWMC_CH0->PWMC_CMR = PWM_CH_MODE_PRESCALER(10);
AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0;
AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xffff;
// Borrow a PWM unit for my real-time clock
AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0);
// 48 MHz / 1024 gives 46.875 kHz
AT91C_BASE_PWMC_CH0->PWMC_CMR = PWM_CH_MODE_PRESCALER(10);
AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0;
AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xffff;
uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
int letoff = 0;
for(;;)
{
uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
int letoff = 0;
for (;;) {
uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
// We haven't let off the button yet
if (!letoff)
{
// We just let it off!
if (!BUTTON_PRESS())
{
letoff = 1;
// We haven't let off the button yet
if (!letoff) {
// We just let it off!
if (!BUTTON_PRESS()) {
letoff = 1;
// reset our timer for 500ms
start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
ticks = (48000 * (500)) >> 10;
}
// reset our timer for 500ms
start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
ticks = (48000 * (500)) >> 10;
}
// Still haven't let it off
else
// Have we held down a full second?
if (now == (uint16_t)(start + ticks))
return BUTTON_HOLD;
}
// Still haven't let it off
else
// Have we held down a full second?
if (now == (uint16_t)(start + ticks))
return BUTTON_HOLD;
}
// We already let off, did we click again?
else
// Sweet, double click!
if (BUTTON_PRESS())
return BUTTON_DOUBLE_CLICK;
// We already let off, did we click again?
else
// Sweet, double click!
if (BUTTON_PRESS())
return BUTTON_DOUBLE_CLICK;
// Have we ran out of time to double click?
else
if (now == (uint16_t)(start + ticks))
// At least we did a single click
return BUTTON_SINGLE_CLICK;
// Have we ran out of time to double click?
else if (now == (uint16_t)(start + ticks))
// At least we did a single click
return BUTTON_SINGLE_CLICK;
WDT_HIT();
}
WDT_HIT();
}
// We should never get here
return BUTTON_ERROR;
// We should never get here
return BUTTON_ERROR;
}
// Determine if a button is held down
int BUTTON_HELD(int ms) {
// If button is held for one second
int ticks = (48000 * (ms ? ms : 1000)) >> 10;
// If button is held for one second
int ticks = (48000 * (ms ? ms : 1000)) >> 10;
// If we're not even pressed, forget about it!
if (!BUTTON_PRESS())
return BUTTON_NO_CLICK;
// If we're not even pressed, forget about it!
if (!BUTTON_PRESS())
return BUTTON_NO_CLICK;
// Borrow a PWM unit for my real-time clock
AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0);
// 48 MHz / 1024 gives 46.875 kHz
AT91C_BASE_PWMC_CH0->PWMC_CMR = PWM_CH_MODE_PRESCALER(10);
AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0;
AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xffff;
// Borrow a PWM unit for my real-time clock
AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0);
// 48 MHz / 1024 gives 46.875 kHz
AT91C_BASE_PWMC_CH0->PWMC_CMR = PWM_CH_MODE_PRESCALER(10);
AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0;
AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xffff;
uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
for(;;)
{
uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
for (;;) {
uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
// As soon as our button let go, we didn't hold long enough
if (!BUTTON_PRESS())
return BUTTON_SINGLE_CLICK;
// As soon as our button let go, we didn't hold long enough
if (!BUTTON_PRESS())
return BUTTON_SINGLE_CLICK;
// Have we waited the full second?
else
if (now == (uint16_t)(start + ticks))
return BUTTON_HOLD;
// Have we waited the full second?
else if (now == (uint16_t)(start + ticks))
return BUTTON_HOLD;
WDT_HIT();
}
WDT_HIT();
}
// We should never get here
return BUTTON_ERROR;
// We should never get here
return BUTTON_ERROR;
}
/* Similar to FpgaGatherVersion this formats stored version information
@ -263,30 +273,38 @@ int BUTTON_HELD(int ms) {
* prefix in dst.
*/
void FormatVersionInformation(char *dst, int len, const char *prefix, void *version_information) {
struct version_information *v = (struct version_information*)version_information;
dst[0] = 0;
strncat(dst, prefix, len-1);
if (v->magic != VERSION_INFORMATION_MAGIC) {
strncat(dst, "Missing/Invalid version information\n", len - strlen(dst) - 1);
return;
}
if (v->versionversion != 1) {
strncat(dst, "Version information not understood\n", len - strlen(dst) - 1);
return;
}
if (!v->present) {
strncat(dst, "Version information not available\n", len - strlen(dst) - 1);
return;
}
struct version_information *v = (struct version_information *)version_information;
dst[0] = 0;
strncat(dst, prefix, len - 1);
if (v->magic != VERSION_INFORMATION_MAGIC) {
strncat(dst, "Missing/Invalid version information\n", len - strlen(dst) - 1);
return;
}
if (v->versionversion != 1) {
strncat(dst, "Version information not understood\n", len - strlen(dst) - 1);
return;
}
if (!v->present) {
strncat(dst, "Version information not available\n", len - strlen(dst) - 1);
return;
}
strncat(dst, v->gitversion, len - strlen(dst) - 1);
if (v->clean == 0) {
strncat(dst, "-unclean", len - strlen(dst) - 1);
} else if (v->clean == 2) {
strncat(dst, "-suspect", len - strlen(dst) - 1);
}
strncat(dst, v->gitversion, len - strlen(dst) - 1);
if (v->clean == 0) {
strncat(dst, "-unclean", len - strlen(dst) - 1);
} else if (v->clean == 2) {
strncat(dst, "-suspect", len - strlen(dst) - 1);
}
strncat(dst, " ", len - strlen(dst) - 1);
strncat(dst, v->buildtime, len - strlen(dst) - 1);
strncat(dst, "\n", len - strlen(dst) - 1);
strncat(dst, " ", len - strlen(dst) - 1);
strncat(dst, v->buildtime, len - strlen(dst) - 1);
strncat(dst, "\n", len - strlen(dst) - 1);
}
bool data_available(void) {
#ifdef WITH_FPC_USART_HOST
return usb_poll_validate_length() || (usart_rxdata_available() > 0);
#else
return usb_poll_validate_length();
#endif
}

View file

@ -12,50 +12,86 @@
#define __UTIL_H
#include "common.h"
#include "commonutil.h"
#include "proxmark3.h"
#include "string.h"
#include "BigBuf.h"
#include "ticks.h"
#define BYTEx(x, n) (((x) >> (n * 8)) & 0xff )
// Basic macros
#ifndef SHORT_COIL
#define SHORT_COIL() LOW(GPIO_SSC_DOUT)
#endif
#ifndef OPEN_COIL
#define OPEN_COIL() HIGH(GPIO_SSC_DOUT)
#endif
#ifndef BYTEx
#define BYTEx(x, n) (((x) >> (n * 8)) & 0xff )
#endif
// Proxmark3 RDV4.0 LEDs
#define LED_A 1
#define LED_B 2
#define LED_C 4
#define LED_D 8
// Proxmark3 historical LEDs
#define LED_ORANGE LED_A
#define LED_GREEN LED_B
#define LED_RED LED_C
#define LED_RED2 LED_D
#define LED_RED 1
#define LED_ORANGE 2
#define LED_GREEN 4
#define LED_RED2 8
#define BUTTON_HOLD 1
#define BUTTON_NO_CLICK 0
#define BUTTON_SINGLE_CLICK -1
#define BUTTON_DOUBLE_CLICK -2
#define BUTTON_ERROR -99
#ifndef BSWAP_16
# define BSWAP_16(x) ((( ((x) & 0xFF00 ) >> 8))| ( (((x) & 0x00FF) << 8)))
#ifndef REV8
#define REV8(x) ((((x)>>7)&1)+((((x)>>6)&1)<<1)+((((x)>>5)&1)<<2)+((((x)>>4)&1)<<3)+((((x)>>3)&1)<<4)+((((x)>>2)&1)<<5)+((((x)>>1)&1)<<6)+(((x)&1)<<7))
#endif
#ifndef BITMASK
# define BITMASK(X) (1 << (X))
#ifndef REV16
#define REV16(x) (REV8(x) + (REV8 (x >> 8) << 8))
#endif
#ifndef ARRAYLEN
# define ARRAYLEN(x) (sizeof(x)/sizeof((x)[0]))
#ifndef REV32
#define REV32(x) (REV16(x) + (REV16(x >> 16) << 16))
#endif
#ifndef REV64
#define REV64(x) (REV32(x) + (REV32(x >> 32) << 32))
#endif
#ifndef BIT32
#define BIT32(x,n) ((((x)[(n)>>5])>>((n)))&1)
#endif
#ifndef INV32
#define INV32(x,i,n) ((x)[(i)>>5]^=((uint32_t)(n))<<((i)&31))
#endif
#ifndef ROTL64
#define ROTL64(x, n) ((((uint64_t)(x))<<((n)&63))+(((uint64_t)(x))>>((0-(n))&63)))
#endif
size_t nbytes(size_t nbits);
extern uint32_t reflect(uint32_t v, int b); // used in crc.c ...
extern uint8_t reflect8(uint8_t b); // dedicated 8bit reversal
extern uint16_t reflect16(uint16_t b); // dedicated 16bit reversal
void num_to_bytes(uint64_t n, size_t len, uint8_t* dest);
uint64_t bytes_to_num(uint8_t* src, size_t len);
void rol(uint8_t *data, const size_t len);
void lsl (uint8_t *data, size_t len);
int32_t le24toh (uint8_t data[3]);
uint8_t hex2int(char hexchar);
void LED(int led, int ms);
void LEDsoff();
void LEDsoff(void);
void SpinOff(uint32_t pause);
void SpinErr(uint8_t led, uint32_t speed, uint8_t times);
void SpinDown(uint32_t speed);
void SpinUp(uint32_t speed);
int BUTTON_CLICKED(int ms);
int BUTTON_HELD(int ms);
void FormatVersionInformation(char *dst, int len, const char *prefix, void *version_information);
bool data_available(void);
#endif

View file

@ -78,11 +78,11 @@ int vtsend_set_cursor(vtsend_t *p, const int visible);
int vtsend_reset(vtsend_t *p);
int vtsend_draw_box(
vtsend_t *p,
const int x1, const int y1, const int x2, const int y2);
vtsend_t *p,
const int x1, const int y1, const int x2, const int y2);
int vtsend_fill_box(
vtsend_t *p,
const int x1, const int y1, const int x2, const int y2);
vtsend_t *p,
const int x1, const int y1, const int x2, const int y2);
#ifdef __cplusplus
}

Some files were not shown because too many files have changed in this diff Show more