client/deps/id48/TECHNICAL.md
This is a collection of random notes and thoughts from the original development process. Much may be rambling. Information herein was not validated before release, and errors are likely.
The Usenix security conference 2013 was going to have a presentation documenting the internals fully (as well as crytpanalysis). This disclosure was delayed for two years. When it was released, the paper omitted a non-linear output filter function at definition 3.8.
This omitted function takes a 20-bit input, and returns a single bit.
All other details of the cipher appeared to have been fully disclosed (even if
some errors existed). The largest error is that text description of
the successor function for g register was incorrect. However, the
diagram version showed the correct operation.
K ==> a 96-bit shared key, known to both vehicle and transponderN ==> a 56-bit nonce value, generated by the vehicle,
and sent in cleartext to the transponderAᵥ ==> a 28-bit authenticator value generated by a reader
(often a vehicle), and sent in cleartext to the
tag. (aka frn)Aₜ ==> a 20-bit authenticator value generated by a tag
and sent in cleartext to the reader (aka grn)frn ==> an alternate name for Aᵥgrn ==> an alternate name for Aₜg ==> a 23-bit Galois linear feedback shift registerh ==> a 13-bit non-linear feedback shift registerl ==> a 7-bit feedback registerm ==> a 7-bit feedback registerr ==> a 7-bit feedback registersₙ ==> a 57-bit internal state of the cipher === <g, h, l, m, r> at iteration `n` (where `0 ≤ n ≤ 55`)
s₀ ==> cipher initial stateFor our purposes, the finite field F will always refer to
a binary finite field (each element ∈ {0,1}). Thus, as is useful
for current computers, we can treat these as bitstrings.
| Symbol | Meaning |
|---|---|
^ | bitwise exclusive-or (XOR); the paper used ⊕ |
ε | the empty bitstring |
0ⁿ | bitstring of n zero-bits |
xⁿ | a bitstring of length n |
x₀ | the first bit of a bitstring |
xᵢ | the ith bit of a bitstring xⁿ (where i<n) |
xₙ₋₁ | the last bit of a bitstring xⁿ |
xₙ | the nth bit of the bitstring xꟲ (where C>n) |
x·y | concatenation of bitstrings x and y |
~x | bitwise complement of bitstring x (paper uses x̄) |
&& | logical AND (conjunction) (research paper uses ∧) |
| ` | |
x[i..j] | The contiguous bits of x from subscript i to j |
If the value is stored in Given:
x⁸ = 00000011Then:
x⁸ === x₇ · x₆ · x₅ · x₄ · x₃ · x₂ · x₁ · x₀x[7..4] = 0000x[3..0] = 0011x[2..1] = 01Evaluating the bits that influence the initial state, s₀₀,
as described in section 3.5:
p ==> 56-bit value, depends only on N and K[95..40]
q ==> 44-bit value, depends only on p
t ==> 43-bit value, depends only on q
Thus, all three of those variables depend only
upon N and K[95..40].
Notably, the input i to the successor function
for g is hard-coded to zero for the initialization.
As reproduced below, the full initial state is shown
to depend only on three variables (p, q, t):
g : t(0..22)
h : 0 · p(0..11)
l : t(23..29)
m : t(30..36)
r : t(37..42) · q(43)
Therefore, s₀₀ depends only on N
and K[95..40]. Stated differently, the low
40 bits of key K (aka K[39..0]) have
no effect on the calculation of s₀₀.
Generally, K remains constant, and N is
a random value generated by the reader. It
appears these presumptions were accepted as
always true in the creation of this cipher.
However, the value of N can be fully controlled
during research, including choosing to make N
constant. Moreover, with a writable tag, K can
be modified to have specific relationships with
known-good authentication traces. Taken together,
these properties will (as to be described later)
enable recovery of an equivalent to the output
filter function.
As noted earlier, the initial cipher state s₀₀
depends only upon K[95..40] and N.
Therefore, if N is held constant, then the
the initial cipher state s₀₀ will depend solely
upon K[95..40]. Put another way, this means
that all keys which share the most significant 56
bits (or differ only in the least significant 40 bits)
will share the same initial state s₀₀.
NOTE: This has utility (value) when K is known,
even when the mapping of the output filter function
is not yet known for all 2²⁰ potential inputs.
TLDR: With a fixed N...
s₀ <-- K[40..95]s₁ <-- K[39..95]s₂ <-- K[38..95]sₙ <-- s(N-1) + K[40-N]sₙ <-- K[(40-N)..95]Here's an exhaustive table that maps which bit of the key influences a given output bit. Start state + key bit --> output
| Start state | Key bit | Output | Notes |
|---|---|---|---|
s₀₀ | K₃₉ | << hidden >> | Seven ... |
s₀₁ | K₃₈ | << hidden >> | .. iterations ... |
s₀₂ | K₃₇ | << hidden >> | .. before ... |
s₀₃ | K₃₆ | << hidden >> | .. any ... |
s₀₄ | K₃₅ | << hidden >> | .. output ... |
s₀₅ | K₃₄ | << hidden >> | .. bits ... |
s₀₆ | K₃₃ | << hidden >> | .. seen. |
s₀₇ | K₃₂ | O₀₀ == frn₀₀ | |
s₀₈ | K₃₁ | O₀₁ == frn₀₁ | |
s₀₉ | K₃₀ | O₀₂ == frn₀₂ | |
s₁₀ | K₂₉ | O₀₃ == frn₀₃ | |
s₁₁ | K₂₈ | O₀₄ == frn₀₄ | |
s₁₂ | K₂₇ | O₀₅ == frn₀₅ | |
s₁₃ | K₂₆ | O₀₆ == frn₀₆ | |
s₁₄ | K₂₅ | O₀₇ == frn₀₇ | |
s₁₅ | K₂₄ | O₀₈ == frn₀₈ | |
s₁₆ | K₂₃ | O₀₉ == frn₀₉ | |
s₁₇ | K₂₂ | O₁₀ == frn₁₀ | |
s₁₈ | K₂₁ | O₁₁ == frn₁₁ | |
s₁₉ | K₂₀ | O₁₂ == frn₁₂ | |
s₂₀ | K₁₉ | O₁₃ == frn₁₃ | |
s₂₁ | K₁₈ | O₁₄ == frn₁₄ | |
s₂₂ | K₁₇ | O₁₅ == frn₁₅ | |
s₂₃ | K₁₆ | O₁₆ == frn₁₆ | |
s₂₄ | K₁₅ | O₁₇ == frn₁₇ | |
s₂₅ | K₁₄ | O₁₈ == frn₁₈ | |
s₂₆ | K₁₃ | O₁₉ == frn₁₉ | |
s₂₇ | K₁₂ | O₂₀ == frn₂₀ | |
s₂₈ | K₁₁ | O₂₁ == frn₂₁ | |
s₂₉ | K₁₀ | O₂₂ == frn₂₂ | |
s₃₀ | K₀₉ | O₂₃ == frn₂₃ | |
s₃₁ | K₀₈ | O₂₄ == frn₂₄ | |
s₃₂ | K₀₇ | O₂₅ == frn₂₅ | |
s₃₃ | K₀₆ | O₂₆ == frn₂₆ | |
s₃₄ | K₀₅ | O₂₇ == frn₂₇ | Last key bit that affects frn |
s₃₅ | K₀₄ | O₂₈ == grn₀₀ | Five bits of key affect grn |
s₃₆ | K₀₃ | O₂₉ == grn₀₁ | |
s₃₇ | K₀₂ | O₃₀ == grn₀₂ | |
s₃₈ | K₀₁ | O₃₁ == grn₀₃ | |
s₃₉ | K₀₀ | O₃₂ == grn₀₄ | |
s₄₀ | 0₁₄ | O₃₃ == grn₀₅ | Zero-fill start |
s₄₁ | 0₁₃ | O₃₄ == grn₀₆ | |
s₄₂ | 0₁₂ | O₃₅ == grn₀₇ | |
s₄₃ | 0₁₁ | O₃₆ == grn₀₈ | |
s₄₄ | 0₁₀ | O₃₇ == grn₀₉ | |
s₄₅ | 0₀₉ | O₃₈ == grn₁₀ | |
s₄₆ | 0₀₈ | O₃₉ == grn₁₁ | |
s₄₇ | 0₀₇ | O₄₀ == grn₁₂ | |
s₄₈ | 0₀₆ | O₄₁ == grn₁₃ | |
s₄₉ | 0₀₅ | O₄₂ == grn₁₄ | |
s₅₀ | 0₀₄ | O₄₃ == grn₁₅ | |
s₅₁ | 0₀₃ | O₄₄ == grn₁₆ | |
s₅₂ | 0₀₂ | O₄₅ == grn₁₇ | |
s₅₃ | 0₀₁ | O₄₆ == grn₁₈ | |
s₅₄ | 0₀₀ | O₄₇ == grn₁₉ |
Given the ability to control the nonce N, and
in particular to use a constant N, it becomes
possible to generate many valid authentication
sequences (with different keys) from just a
single valid authentication with a known key.
With a static nonce value, an astute observer may
have noticed that frn does not rely on the least
significant five bits of the key ... those bits
influence grn₀₀..grn₀₄.
Therefore, so long as the only bits of K that
differ are K₀₄..K₀₀, the frn value will remain
constant for a given nonce.
This allows a single known-good key + nonce + frn
to be trivially expanded to 32x known-good sets,
for "nearby" consecutive keys. Another way to state
this is that each block of 32 consecutive keys will
share the same Aᵥ value.
More formally, where (K' ^ K) <= 0x1F,
then Aᵥ' = Aᵥ.
REM using the key and auth values from the research paper
lf em 4x70 setkey --key A090A0A02080000000000000
REM expect a tag response of `60 9D 6`
lf em 4x70 auth --rnd 3FFE1FB6CC513F --frn F355F1A0
REM repeat using 31 additional keys in the same "block"
lf em 4x70 setkey --key A090A0A02080000000000001
lf em 4x70 auth --rnd 3FFE1FB6CC513F --frn F355F1A0
lf em 4x70 setkey --key A090A0A02080000000000002
lf em 4x70 auth --rnd 3FFE1FB6CC513F --frn F355F1A0
lf em 4x70 setkey --key A090A0A02080000000000003
lf em 4x70 auth --rnd 3FFE1FB6CC513F --frn F355F1A0
REM ... and so on, for a total of 31 more keys
lf em 4x70 setkey --key A090A0A0208000000000001E
lf em 4x70 auth --rnd 3FFE1FB6CC513F --frn F355F1A0
lf em 4x70 setkey --key A090A0A0208000000000001F
lf em 4x70 auth --rnd 3FFE1FB6CC513F --frn F355F1A0
The tag will respond to all 32 authentications,
although its grn responses may differ for each key.
Walking the sequence backwards one additional bit,
where the last six bits of the key change,
what happens to Aᵥ?
It turns out that Aᵥ will either remain identical,
or that the least significant bit of Aᵥ will flip.
Thus, there are exactly two possible values that
need to be tested for Aᵥ, and the tag will respond
to exactly one of them.
Formally, where (K' ^ K) <= 0x3F,
then Aᵥ' ^ Aᵥ <= 0x1.
REM using the key and auth values from the research paper
lf em 4x70 setkey --key A090A0A02080000000000000
REM expect a tag response of `60 9D 6`
lf em 4x70 auth --rnd 3FFE1FB6CC513F --frn F355F1A0
REM repeat using 31 additional keys in the same "block"
lf em 4x70 setkey --key A090A0A02080000000000020
REM 50% chance that this is the correct FRN value
lf em 4x70 auth --rnd 3FFE1FB6CC513F --frn F355F1A0
REM 50% chance that this is the correct FRN value
lf em 4x70 auth --rnd 3FFE1FB6CC513F --frn F355F1B0
Each additional bit of the key that is changed
will double the number of Aᵥ values that need
to be tested to find the correct challenge.
Using K'' == K ^ 0x1FF (nine lowest bits changed),
requires testing only 16 possible Aᵥ'' values,
by permuting the least significant bits of Aᵥ.
Thus, exactly one of the following should result in a successful authentication:
REM modify the key's lowest nine bits
lf em 4x70 setkey --key A090A0A02080000000000100
REM 1/16 chance for each of these to work:
lf em 4x70 auth --rnd 3FFE1FB6CC513F --frn F355F100
lf em 4x70 auth --rnd 3FFE1FB6CC513F --frn F355F110
lf em 4x70 auth --rnd 3FFE1FB6CC513F --frn F355F120
lf em 4x70 auth --rnd 3FFE1FB6CC513F --frn F355F130
lf em 4x70 auth --rnd 3FFE1FB6CC513F --frn F355F140
lf em 4x70 auth --rnd 3FFE1FB6CC513F --frn F355F150
lf em 4x70 auth --rnd 3FFE1FB6CC513F --frn F355F160
lf em 4x70 auth --rnd 3FFE1FB6CC513F --frn F355F170
lf em 4x70 auth --rnd 3FFE1FB6CC513F --frn F355F180
lf em 4x70 auth --rnd 3FFE1FB6CC513F --frn F355F190
lf em 4x70 auth --rnd 3FFE1FB6CC513F --frn F355F1A0
lf em 4x70 auth --rnd 3FFE1FB6CC513F --frn F355F1B0
lf em 4x70 auth --rnd 3FFE1FB6CC513F --frn F355F1C0
lf em 4x70 auth --rnd 3FFE1FB6CC513F --frn F355F1D0
lf em 4x70 auth --rnd 3FFE1FB6CC513F --frn F355F1E0
lf em 4x70 auth --rnd 3FFE1FB6CC513F --frn F355F1F0
REM hint: response will be `65 09 A`
Depending on the most significant bit that changed in the key,
it can be trivially calculated how many variations of Aᵥ
need to be tested to find the correct challenge for that same
nonce.
| msb changed | key bits changed mask | Values to test | 2^N |
|---|---|---|---|
0 | 0x00'0000'0000 | 1 | 0 |
1 | 0x00'0000'0001 | 1 | 0 |
2 | 0x00'0000'0003 | 1 | 0 |
3 | 0x00'0000'0007 | 1 | 0 |
4 | 0x00'0000'000F | 1 | 0 |
5 | 0x00'0000'001F | 1 | 0 |
6 | 0x00'0000'003F | 2 | 1 |
7 | 0x00'0000'007F | 4 | 2 |
8 | 0x00'0000'00FF | 8 | 3 |
9 | 0x00'0000'01FF | 16 | 4 |
10 | 0x00'0000'03FF | 32 | 5 |
11 | 0x00'0000'07FF | 64 | 6 |
12 | 0x00'0000'0FFF | 128 | 7 |
13 | 0x00'0000'1FFF | 256 | 8 |
14 | 0x00'0000'3FFF | 512 | 9 |
15 | 0x00'0000'7FFF | 1,024 | 10 |
16 | 0x00'0000'FFFF | 2,048 | 11 |
17 | 0x00'0001'FFFF | 4,096 | 12 |
18 | 0x00'0003'FFFF | 8,192 | 13 |
19 | 0x00'0007'FFFF | 16,384 | 14 |
20 | 0x00'000F'FFFF | 32,768 | 15 |
21 | 0x00'001F'FFFF | 65,536 | 16 |
22 | 0x00'003F'FFFF | 131,072 | 17 |
23 | 0x00'007F'FFFF | 262,144 | 18 |
24 | 0x00'00FF'FFFF | 524,288 | 19 |
25 | 0x00'01FF'FFFF | 1,048,576 | 20 |
26 | 0x00'03FF'FFFF | 2,097,152 | 21 |
27 | 0x00'07FF'FFFF | 4,194,304 | 22 |
28 | 0x00'0FFF'FFFF | 8,388,608 | 23 |
29 | 0x00'1FFF'FFFF | 16,777,216 | 24 |
30 | 0x00'3FFF'FFFF | 33,554,432 | 25 |
31 | 0x00'7FFF'FFFF | 67,108,864 | 26 |
32 | 0x00'FFFF'FFFF | 134,217,728 | 27 |
33 | 0x01'FFFF'FFFF | 268,435,456 | 28 |
34 | 0x03'FFFF'FFFF | 536,870,912 | 29 |
35 | 0x07'FFFF'FFFF | 1,073,741,824 | 30 |
36 | 0x0F'FFFF'FFFF | 2,147,483,648 | 31 |
37 | 0x1F'FFFF'FFFF | 4,294,967,296 | 32 |
38 | 0x3F'FFFF'FFFF | 8,589,934,592 | 33 |
39 | 0x7F'FFFF'FFFF | 17,179,869,184 | 34 |
40 | 0xFF'FFFF'FFFF | 34,359,738,368 | 35 |
> 40 | ... more ... | changes s₀₀ ... | 56 |
Thus, it becomes almost trivial to generate millions of
valid authentication sequences for a given nonce, frn,
and K' ~= K. Each of these authentication sequences
has the potential to generate at least twenty distinct
internal cipher states from Aₜ.
While trivial, this takes time. Millions of traces were
generated over the course of multiple months using multiple
PM3 Easy devices 24/7, each one writing keys and
brute-forcing the frn values.
While the mechanics and computation of the output filter function is not known, the inputs are defined in Definition 3.9, and the output is a single bit.
Therefore, if the entire cipher except for the internal
computations of the output filter are known, given a
known valid authentication trace, all twenty of the
input bits passed to the output filter function can be
calculated for each of the 48 output bits (Aᵥ and Aₜ).
When using branched traces (from above), the first 36
internal cipher states (give or take) are shared, and
thus do not provide "new" information. This still
provides up to 12 bits of "new" information per trace,
or up to ~192 bits of "new" information per block of
32 consecutive keys that share the same frn value.
Treating the 20-bit parameter as an index to a bitmap, the full mapping requires only a 128k bitmap. Initially, when there remain unknown mappings, a second 128k bitmap is used to tracks if the output bit for that 20-bit parameter has already been found.
As the table become more filled, it becomes easier to
generate new authentication sequences using entirely
random values for N and K, especially where the
most significant bits of frn are known. Thus, the
brute force space for key branching never becomes
overwhelmingly large.
As an exercise for the reader, and as it is important to finish filling the last values in the table, an astute reader can realize optimizations that improve finding a "targeted" 20-bit input, especially where the cipher states from current branching had been archived.
In summary, these traces can thus be used to (slowly)
fill in a 128k bitmap indicating all possible output
values for any of the 2²⁰ inputs, without ever
needing to replicate or know the internal functioning
of the output filter function.
Given a static value for N, what bits in K
influence a given output bit?
| sₙ | Output Bit | Bits in K | Delta from s(N-1) | Hex Value |
|---|---|---|---|---|
s₁ | | K[39..95] | K₃₉ | 0x80_0000_0000 |
s₂ | | K[38..95] | K₃₈ | 0x40_0000_0000 |
s₃ | | K[37..95] | K₃₇ | 0x20_0000_0000 |
s₄ | | K[36..95] | K₃₆ | 0x10_0000_0000 |
s₅ | | K[35..95] | K₃₅ | 0x08_0000_0000 |
s₆ | | K[34..95] | K₃₄ | 0x04_0000_0000 |
s₇ | Aᵥ₂₇ | K[33..95] | K₃₃ | 0x02_0000_0000 |
s₈ | Aᵥ₂₆ | K[32..95] | K₃₂ | 0x01_0000_0000 |
s₉ | Aᵥ₂₅ | K[31..95] | K₃₁ | 0x00_8000_0000 |
s₁₀ | Aᵥ₂₄ | K[30..95] | K₃₀ | 0x00_4000_0000 |
s₁₁ | Aᵥ₂₃ | K[29..95] | K₂₉ | 0x00_2000_0000 |
s₁₂ | Aᵥ₂₂ | K[28..95] | K₂₈ | 0x00_1000_0000 |
s₁₃ | Aᵥ₂₁ | K[27..95] | K₂₇ | 0x00_0800_0000 |
s₁₄ | Aᵥ₂₀ | K[26..95] | K₂₆ | 0x00_0400_0000 |
s₁₅ | Aᵥ₁₉ | K[25..95] | K₂₅ | 0x00_0200_0000 |
s₁₆ | Aᵥ₁₈ | K[24..95] | K₂₄ | 0x00_0100_0000 |
s₁₇ | Aᵥ₁₇ | K[23..95] | K₂₃ | 0x00_0080_0000 |
s₁₈ | Aᵥ₁₆ | K[22..95] | K₂₂ | 0x00_0040_0000 |
s₁₉ | Aᵥ₁₅ | K[21..95] | K₂₁ | 0x00_0020_0000 |
s₂₀ | Aᵥ₁₄ | K[20..95] | K₂₀ | 0x00_0010_0000 |
s₂₁ | Aᵥ₁₃ | K[19..95] | K₁₉ | 0x00_0008_0000 |
s₂₂ | Aᵥ₁₂ | K[18..95] | K₁₈ | 0x00_0004_0000 |
s₂₃ | Aᵥ₁₁ | K[17..95] | K₁₇ | 0x00_0002_0000 |
s₂₄ | Aᵥ₁₀ | K[16..95] | K₁₆ | 0x00_0001_0000 |
s₂₅ | Aᵥ₀₉ | K[15..95] | K₁₅ | 0x00_0000_8000 |
s₂₆ | Aᵥ₀₈ | K[14..95] | K₁₄ | 0x00_0000_4000 |
s₂₇ | Aᵥ₀₇ | K[13..95] | K₁₃ | 0x00_0000_2000 |
s₂₈ | Aᵥ₀₆ | K[12..95] | K₁₂ | 0x00_0000_1000 |
s₂₉ | Aᵥ₀₅ | K[11..95] | K₁₁ | 0x00_0000_0800 |
s₃₀ | Aᵥ₀₄ | K[10..95] | K₁₀ | 0x00_0000_0400 |
s₃₁ | Aᵥ₀₃ | K[ 9..95] | K₀₉ | 0x00_0000_0200 |
s₃₂ | Aᵥ₀₂ | K[ 8..95] | K₀₈ | 0x00_0000_0100 |
s₃₃ | Aᵥ₀₁ | K[ 7..95] | K₀₇ | 0x00_0000_0080 |
s₃₄ | Aᵥ₀₀ | K[ 6..95] | K₀₆ | 0x00_0000_0040 |
s₃₅ | Aₜ₁₉ | K[ 5..95] | K₀₅ | 0x00_0000_0020 |
s₃₆ | Aₜ₁₈ | K[ 4..95] | K₀₄ | 0x00_0000_0010 |
s₃₇ | Aₜ₁₇ | K[ 3..95] | K₀₃ | 0x00_0000_0008 |
s₃₈ | Aₜ₁₆ | K[ 2..95] | K₀₂ | 0x00_0000_0004 |
s₃₉ | Aₜ₁₅ | K[ 1..95] | K₀₁ | 0x00_0000_0002 |
s₄₀ | Aₜ₁₄ | K[ 0..95] | K₀₀ | 0x00_0000_0001 |
s₄₁ | Aₜ₁₃ | K[ 0..95] | ... | |
s₄₂ | Aₜ₁₂ | K[ 0..95] | ... | |
s₄₃ | Aₜ₁₁ | K[ 0..95] | ... | |
s₄₄ | Aₜ₁₀ | K[ 0..95] | ... | |
s₄₅ | Aₜ₀₉ | K[ 0..95] | ... | |
s₄₆ | Aₜ₀₈ | K[ 0..95] | ... | |
s₄₇ | Aₜ₀₇ | K[ 0..95] | ... | |
s₄₈ | Aₜ₀₆ | K[ 0..95] | ... | |
s₄₉ | Aₜ₀₅ | K[ 0..95] | ... | |
s₅₀ | Aₜ₀₄ | K[ 0..95] | ... | |
s₅₁ | Aₜ₀₃ | K[ 0..95] | ... | |
s₅₂ | Aₜ₀₂ | K[ 0..95] | ... | |
s₅₃ | Aₜ₀₁ | K[ 0..95] | ... | |
s₅₄ | Aₜ₀₀ | K[ 0..95] | ... |
Although too large to fit, there are various two-level (boolean) logic reduction techniques that can migrate from a truth table (e.g., the bitmap) to a reduced set of logical operations that will obtain the same result. (ref: Espresso)
With the 128k bitmap converted to a truth table, a much more reduced set of tables was found to generate the same results. There is no assurance that this is the most optimal way to generate the results, but it is an acceptably small solution ... small enough to even be implemented in FPGA logic if desired.
There are sixteen (16x) blocks of memory, each storing a 16-bit value.
Blocks may be protected (P column) as read-only (RO) or write-only (WO).
Lock₀ === Disable writing ... (?) write-prevention when set to 1.
Lock₁ === Pin-code lock
Block | P | Purpose | Bits (LSB first) | Bits (MSB first) |
|---|---|---|---|---|
0 | | `user memory | bits 0..15` | bits 15.. 0 |
1 | | `user memory | bits 16..29, lock0, lock1` | lock₁, lock₀, bits 29..16 |
2 | RO | `id | bits 0..15` | bits 15.. 0 |
3 | RO | `id | bits 16..31` | bits 31..16 |
4 | wo | `crypto key | bits 0..15` | bits 15.. 0 |
5 | wo | `crypto key | bits 16..31` | bits 31..16 |
6 | wo | `crypto key | bits 32..47` | bits 47..32 |
7 | wo | `crypto key | bits 48..63` | bits 63..48 |
8 | wo | `crypto key | bits 64..79` | bits 79..64 |
9 | wo | `crypto key | bits 80..95` | bits 95..80 |
10 | wo | `pin code | bits 0..15` | bits 15.. 0 |
11 | wo | `pin code | bits 16..31` | bits 31..16 |
12 | | `user memory | bits 30..45` | bits 45..30 |
13 | | `user memory | bits 46..61` | bits 61..46 |
14 | | `user memory | bits 62..77` | bits 77..62 |
15 | | `user memory | bits 78..93` | bits 93..78 |
Given:
OF(X²⁰) -> r¹ function is a black box:
OF(X²⁰)
can be calculated for s₀..s₅₄, given only N and KOF_Known[2²⁰] (128kb) indicating if, for
a given 20-bit input, the result r¹ is known
OF_Result[2²⁰] (128kb) indicating, for a given
20-bit input, a known result r¹.
OF_Known is set to one (true)The, starting with a single known valid trace: K + [ N, Aᵥ, Aₜ]:
OF_Known/OF_ResultK'' having the same upper 91 bits,
31 additional traces [K'', N, Aᵥ] are trivially created.
Each K'' will share the first 28 output bits (Aᵥ is the same),
but have potentially 20 more unique internal states.
a. 31 instances x 20 bits per instance == 620 more potential entries
b. Subtotal: 668 entries known (0.06%)K' having the same upper 80 bits,
with least significant 5 bits set to zero:
a. Brute-forcing the required value of N' takes at most 512 attempts
because N(55..9) = N'(55..9).
b. On average, this takes 256 attempts.
b. As above, all other 31 values for K'' will use the same N',
allowing 668 additional output values to be potentially filledOF_Known will trend towards being mostly populatedCan leave multiple pm3 running 24/7, logging results.
Note that the initial state S₀ is also known
(for that nonce) for ALL OTHER 2^40 keys that
share the same bits in K[95..40]. (!!!)
Similar to Partial Key-Update Aₜtack, for creating mapping
of the output filter function OF( x²⁰ ) --> bool
Given:
Known private key K
Known working data: { Nonce[55..0] , AuthV[27..0], AuthT²⁰ }
ID48 Transponder with Rewritable Key
Output bit does not alter any other cryptographic state
s₀ depends ONLY on { N, K[40..95] }
sₙ depends ONLY on s(N-1) and K(40-N) --> { N, K[(40-N)..95] }
s₀ depends ONLY on --> { N, K[40..95] }
s₁ --> { N, K[39..95] }
s₂ --> { N, K[38..95] }
s₃ --> { N, K[37..95] }
s₄ --> { N, K[36..95] }
s₅ --> { N, K[35..95] }
s₆ --> { N, K[34..95] }
s₇ Aᵥ₂₇ --> { N, K[33..95] }
s₈ Aᵥ₂₆ --> { N, K[32..95] }
s₉ Aᵥ₂₅ --> { N, K[31..95] }
s₁₀ Aᵥ₂₄ --> { N, K[30..95] }
s₁₁ Aᵥ₂₃ --> { N, K[29..95] }
s₁₂ Aᵥ₂₂ --> { N, K[28..95] }
s₁₃ Aᵥ₂₁ --> { N, K[27..95] }
s₁₄ Aᵥ₂₀ --> { N, K[26..95] }
s₁₅ Aᵥ₁₉ --> { N, K[25..95] }
s₁₆ Aᵥ₁₈ --> { N, K[24..95] }
s₁₇ Aᵥ₁₇ --> { N, K[23..95] }
s₁₈ Aᵥ₁₆ --> { N, K[22..95] }
s₁₉ Aᵥ₁₅ --> { N, K[21..95] }
s₂₀ Aᵥ₁₄ --> { N, K[20..95] }
s₂₁ Aᵥ₁₃ --> { N, K[19..95] }
s₂₂ Aᵥ₁₂ --> { N, K[18..95] }
s₂₃ Aᵥ₁₁ --> { N, K[17..95] }
s₂₄ Aᵥ₁₀ --> { N, K[16..95] }
s₂₅ Aᵥ₉ --> { N, K[15..95] }
s₂₆ Aᵥ₈ --> { N, K[14..95] }
s₂₇ Aᵥ₇ --> { N, K[13..95] }
s₂₈ Aᵥ₆ --> { N, K[12..95] }
s₂₉ Aᵥ₅ --> { N, K[11..95] }
s₃₀ Aᵥ₄ --> { N, K[10..95] }
s₃₁ Aᵥ₃ --> { N, K[ 9..95] }
s₃₂ Aᵥ₂ --> { N, K[ 8..95] }
s₃₃ Aᵥ₁ --> { N, K[ 7..95] }
s₃₄ Aᵥ₀ --> { N, K[ 6..95] }
Therefore, if we write K' to a second transponder,
where K' == K ^ 0x20 (flip bit 6)
then Aᵥ' == Aᵥ[27..1] + one random bit
Therefore, by carefully selecting derived keys to be written to transponders, it becomes trivial to generate many successful authentication traces.
Example: Known valid trace: [ K, N, Aᵥ ] == [ F32AA98CF5BE4ADFA6D3480B, 45F54ADA252AAC, 4866BB70 ] --> 9B D1 80
[ K', N, Aᵥ' ] == [ F32AA98CF5BE4ADFA6D3482B, 45F54ADA252AAC, 4866BB60 ] --> Fail [ K', N, Aᵥ' ] == [ F32AA98CF5BE4ADFA6D3482B, 45F54ADA252AAC, 4866BB70 ] --> 4E BB D0
[ K', N, Aᵥ' ] == [ F32AA98CF5BE4ADFA6D3486B, 45F54ADA252AAC, 4866BB40 ] --> Fail [ K', N, Aᵥ' ] == [ F32AA98CF5BE4ADFA6D3486B, 45F54ADA252AAC, 4866BB50 ] --> Fail [ K', N, Aᵥ' ] == [ F32AA98CF5BE4ADFA6D3486B, 45F54ADA252AAC, 4866BB60 ] --> Fail [ K', N, Aᵥ' ] == [ F32AA98CF5BE4ADFA6D3486B, 45F54ADA252AAC, 4866BB70 ] --> 39 55 90
[ K', N, Aᵥ' ] == [ F32AA98CF5BE4ADFA6D3484B, 45F54ADA252AAC, 4866BB60 ] --> Fail [ K', N, Aᵥ' ] == [ F32AA98CF5BE4ADFA6D3484B, 45F54ADA252AAC, 4866BB70 ] --> E8 60 D0
[ K', N, Aᵥ' ] == [ F32AA98CF5BE4ADFA6D348DB, 45F54ADA252AAC, 4866BB70 ] --> Fail [ K', N, Aᵥ' ] == [ F32AA98CF5BE4ADFA6D348DB, 45F54ADA252AAC, 4866BB60 ] --> Fail [ K', N, Aᵥ' ] == [ F32AA98CF5BE4ADFA6D348DB, 45F54ADA252AAC, 4866BB50 ] --> Fail [ K', N, Aᵥ' ] == [ F32AA98CF5BE4ADFA6D348DB, 45F54ADA252AAC, 4866BB40 ] --> Fail [ K', N, Aᵥ' ] == [ F32AA98CF5BE4ADFA6D348DB, 45F54ADA252AAC, 4866BB30 ] --> Fail [ K', N, Aᵥ' ] == [ F32AA98CF5BE4ADFA6D348DB, 45F54ADA252AAC, 4866BB20 ] --> Fail [ K', N, Aᵥ' ] == [ F32AA98CF5BE4ADFA6D348DB, 45F54ADA252AAC, 4866BB10 ] --> ED 9C 20 [ K', N, Aᵥ' ] == [ F32AA98CF5BE4ADFA6D348DB, 45F54ADA252AAC, 4866BB00 ] --> Fail
This has been CONFIRMED WORKING using actual hardware.
See https://github.com/dorssel/usbipd-win/wiki/Automation#json
This can avoid having to swap to Windows to re-connect if the device disconnects/reconnects for any reason.
Function ExpandBy32() takes as input:
KNAᵥStep 1. Write the private key K
Step 2. Validate authentication works with N and Aᵥ
Step 3. Set lowest 5 bits of K to zero
Step 4. For i in (0..31):
4a. Set temporary key K' as K+i (set some of lowest 5 bits)
4b. Write private key K'
4c. Validate authentication works with N and Aᵥ
4d. Verify received 20-bit response, Aₜ
4e. For each success, print the set: { K', N, Aᵥ, Aₜ }
Function Branch() takes as input:
KNAᵥ (just A in below)VERIFY VALID INPUTS:
N and AᵥThen (using 2^16) potential authentications as maximum
Select a target key K', where K'[95..()]
This is when the private key IS already known, and you have a starting point.
My 2004 Volvo S60 key originally had a pin code of 'AAAAAAAA'.
Updating the pin code:
Get info:
In this example, block 1 data == ED08, (0b1110...)
lf em 4x70 info
Because Lockbit 0 was set, unlock with the PIN:
lf em 4x70 unlock --pin AAAAAAAA
Verify successful unlock by checking LockBit0:
In this example, block 1 data == AD08, (0b1010...)
so LockBit1 = 1, LockBit0 = 0 == success.
lf em 4x70 info
Write the new pin code as DEADBEEF
lf em 4x70 setpin --pin DEADBEEF
Set lockbit0 to 1 (based on existing data in block1):
e.g, AD08 | 4000 == ED08
lf em 4x70 write --block 1 --data ED08
[=] ------+----------+----------------------------- [=] 3 | xx xx | ID (redacted) [=] 2 | xx xx | ID (redacted) [=] ------+----------+----------------------------- [=] 1 | ED 08 | UM1 [=] 0 | 87 7D | UM1 [=] ------+----------+----------------------------- [=] [=] Tag ID: DB 4F B2 E8 [=] Lockbit 0: 1 [=] Lockbit 1: 1 [=] Tag is LOCKED.
To be written. Generally, save as WAV file, and then use more powerful tools than the data viewer that is built into PM3 client.
Symbols, subscripts, superscripts...
X₀₁₂₃₄₅₆₇₈₉₊₋₌₍₎ₐₑₒₓₔₕₖₗₘₙₚₛₜⱼᵢᵣᵤᵥᵦᵧᵨᵩᵪ.
X⁰¹²³⁴⁵⁶⁷⁸⁹⁺⁻⁼⁽⁾ⁿⁱ
⊕εx̄∧∨