Sync crapto1 files with official crapto1 3.2

This commit is contained in:
romuald@libnfc.org 2012-09-26 19:14:01 +00:00
parent 7fe60310b0
commit bb64564cad
2 changed files with 487 additions and 491 deletions

View File

@ -1,487 +1,480 @@
/* crapto1.c /* crapto1.c
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2 as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version. of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, US$ Boston, MA 02110-1301, US$
Copyright (C) 2008-2008 bla <blapost@gmail.com> Copyright (C) 2008-2008 bla <blapost@gmail.com>
*/ */
#include "crapto1.h" #include "crapto1.h"
#include <stdlib.h> #include <stdlib.h>
#if !defined LOWMEM && defined __GNUC__ #if !defined LOWMEM && defined __GNUC__
static uint8_t filterlut[1 << 20]; static uint8_t filterlut[1 << 20];
static void __attribute__((constructor)) fill_lut() static void __attribute__((constructor)) fill_lut()
{ {
uint32_t i; uint32_t i;
for(i = 0; i < 1 << 20; ++i) for(i = 0; i < 1 << 20; ++i)
filterlut[i] = filter(i); filterlut[i] = filter(i);
} }
#define filter(x) (filterlut[(x) & 0xfffff]) #define filter(x) (filterlut[(x) & 0xfffff])
#endif #endif
static void quicksort(uint32_t* const start, uint32_t* const stop) static void quicksort(uint32_t* const start, uint32_t* const stop)
{ {
uint32_t *it = start + 1, *rit = stop; uint32_t *it = start + 1, *rit = stop;
if(it > rit) if(it > rit)
return; return;
while(it < rit) while(it < rit)
if(*it <= *start) if(*it <= *start)
++it; ++it;
else if(*rit > *start) else if(*rit > *start)
--rit; --rit;
else else
*it ^= (*it ^= *rit, *rit ^= *it); *it ^= (*it ^= *rit, *rit ^= *it);
if(*rit >= *start) if(*rit >= *start)
--rit; --rit;
if(rit != start) if(rit != start)
*rit ^= (*rit ^= *start, *start ^= *rit); *rit ^= (*rit ^= *start, *start ^= *rit);
quicksort(start, rit - 1); quicksort(start, rit - 1);
quicksort(rit + 1, stop); quicksort(rit + 1, stop);
} }
/** binsearch /** binsearch
* Binary search for the first occurence of *stop's MSB in sorted [start,stop] * Binary search for the first occurence of *stop's MSB in sorted [start,stop]
*/ */
static inline uint32_t* static inline uint32_t* binsearch(uint32_t *start, uint32_t *stop)
binsearch(uint32_t *start, uint32_t *stop) {
{ uint32_t mid, val = *stop & 0xff000000;
uint32_t mid, val = *stop & 0xff000000; while(start != stop)
while(start != stop) if(start[mid = (stop - start) >> 1] > val)
if(start[mid = (stop - start) >> 1] > val) stop = &start[mid];
stop = &start[mid]; else
else start += mid + 1;
start += mid + 1;
return start;
return start; }
}
/** update_contribution
/** update_contribution * helper, calculates the partial linear feedback contributions and puts in MSB
* helper, calculates the partial linear feedback contributions and puts in MSB */
*/ static inline void
static inline void update_contribution(uint32_t *item, const uint32_t mask1, const uint32_t mask2)
update_contribution(uint32_t *item, const uint32_t mask1, const uint32_t mask2) {
{ uint32_t p = *item >> 25;
uint32_t p = *item >> 25;
p = p << 1 | parity(*item & mask1);
p = p << 1 | parity(*item & mask1); p = p << 1 | parity(*item & mask2);
p = p << 1 | parity(*item & mask2); *item = p << 24 | (*item & 0xffffff);
*item = p << 24 | (*item & 0xffffff); }
}
/** extend_table
/** extend_table * using a bit of the keystream extend the table of possible lfsr states
* using a bit of the keystream extend the table of possible lfsr states */
*/ static inline void
static inline void extend_table(uint32_t *tbl, uint32_t **end, int bit, int m1, int m2, uint32_t in)
extend_table(uint32_t *tbl, uint32_t **end, int bit, int m1, int m2, uint32_t in) {
{ in <<= 24;
in <<= 24; for(*tbl <<= 1; tbl <= *end; *++tbl <<= 1)
for(*tbl <<= 1; tbl <= *end; *++tbl <<= 1) if(filter(*tbl) ^ filter(*tbl | 1)) {
*tbl |= filter(*tbl) ^ bit;
update_contribution(tbl, m1, m2);
*tbl ^= in;
} else if(filter(*tbl) == bit) {
*++*end = tbl[1];
tbl[1] = tbl[0] | 1;
update_contribution(tbl, m1, m2);
*tbl++ ^= in;
update_contribution(tbl, m1, m2);
*tbl ^= in;
} else
*tbl-- = *(*end)--;
}
/** extend_table_simple
* using a bit of the keystream extend the table of possible lfsr states
*/
static inline void extend_table_simple(uint32_t *tbl, uint32_t **end, int bit)
{
for(*tbl <<= 1; tbl <= *end; *++tbl <<= 1)
if(filter(*tbl) ^ filter(*tbl | 1)) { if(filter(*tbl) ^ filter(*tbl | 1)) {
*tbl |= filter(*tbl) ^ bit; *tbl |= filter(*tbl) ^ bit;
update_contribution(tbl, m1, m2);
*tbl ^= in;
} else if(filter(*tbl) == bit) { } else if(filter(*tbl) == bit) {
*++*end = tbl[1]; *++*end = *++tbl;
tbl[1] = tbl[0] | 1; *tbl = tbl[-1] | 1;
update_contribution(tbl, m1, m2); } else
*tbl++ ^= in; *tbl-- = *(*end)--;
update_contribution(tbl, m1, m2); }
*tbl ^= in; /** recover
} else * recursively narrow down the search space, 4 bits of keystream at a time
*tbl-- = *(*end)--; */
} static struct Crypto1State*
/** extend_table_simple recover(uint32_t *o_head, uint32_t *o_tail, uint32_t oks,
* using a bit of the keystream extend the table of possible lfsr states uint32_t *e_head, uint32_t *e_tail, uint32_t eks, int rem,
*/ struct Crypto1State *sl, uint32_t in)
static inline void {
extend_table_simple(uint32_t *tbl, uint32_t **end, int bit) uint32_t *o, *e, i;
{
for(*tbl <<= 1; tbl <= *end; *++tbl <<= 1) if(rem == -1) {
if(filter(*tbl) ^ filter(*tbl | 1)) { for(e = e_head; e <= e_tail; ++e) {
*tbl |= filter(*tbl) ^ bit; *e = *e << 1 ^ parity(*e & LF_POLY_EVEN) ^ !!(in & 4);
} else if(filter(*tbl) == bit) { for(o = o_head; o <= o_tail; ++o, ++sl) {
*++*end = *++tbl; sl->even = *o;
*tbl = tbl[-1] | 1; sl->odd = *e ^ parity(*o & LF_POLY_ODD);
} else sl[1].odd = sl[1].even = 0;
*tbl-- = *(*end)--; }
} }
/** recover return sl;
* recursively narrow down the search space, 4 bits of keystream at a time }
*/
static struct Crypto1State* for(i = 0; i < 4 && rem--; i++) {
recover(uint32_t *o_head, uint32_t *o_tail, uint32_t oks, oks >>= 1;
uint32_t *e_head, uint32_t *e_tail, uint32_t eks, int rem, eks >>= 1;
struct Crypto1State *sl, uint32_t in) in >>= 2;
{ extend_table(o_head, &o_tail, oks & 1, LF_POLY_EVEN << 1 | 1,
uint32_t *o, *e, i; LF_POLY_ODD << 1, 0);
if(o_head > o_tail)
if(rem == -1) { return sl;
for(e = e_head; e <= e_tail; ++e) {
*e = *e << 1 ^ parity(*e & LF_POLY_EVEN) ^ !!(in & 4); extend_table(e_head, &e_tail, eks & 1, LF_POLY_ODD,
for(o = o_head; o <= o_tail; ++o, ++sl) { LF_POLY_EVEN << 1 | 1, in & 3);
sl->even = *o; if(e_head > e_tail)
sl->odd = *e ^ parity(*o & LF_POLY_ODD); return sl;
sl[1].odd = sl[1].even = 0; }
}
} quicksort(o_head, o_tail);
return sl; quicksort(e_head, e_tail);
}
while(o_tail >= o_head && e_tail >= e_head)
for(i = 0; i < 4 && rem--; i++) { if(((*o_tail ^ *e_tail) >> 24) == 0) {
extend_table(o_head, &o_tail, (oks >>= 1) & 1, o_tail = binsearch(o_head, o = o_tail);
LF_POLY_EVEN << 1 | 1, LF_POLY_ODD << 1, 0); e_tail = binsearch(e_head, e = e_tail);
if(o_head > o_tail) sl = recover(o_tail--, o, oks,
return sl; e_tail--, e, eks, rem, sl, in);
}
extend_table(e_head, &e_tail, (eks >>= 1) & 1, else if(*o_tail > *e_tail)
LF_POLY_ODD, LF_POLY_EVEN << 1 | 1, (in >>= 2) & 3); o_tail = binsearch(o_head, o_tail) - 1;
if(e_head > e_tail) else
return sl; e_tail = binsearch(e_head, e_tail) - 1;
}
return sl;
quicksort(o_head, o_tail); }
quicksort(e_head, e_tail); /** lfsr_recovery
* recover the state of the lfsr given 32 bits of the keystream
while(o_tail >= o_head && e_tail >= e_head) * additionally you can use the in parameter to specify the value
if(((*o_tail ^ *e_tail) >> 24) == 0) { * that was fed into the lfsr at the time the keystream was generated
o_tail = binsearch(o_head, o = o_tail); */
e_tail = binsearch(e_head, e = e_tail); struct Crypto1State* lfsr_recovery32(uint32_t ks2, uint32_t in)
sl = recover(o_tail--, o, oks, {
e_tail--, e, eks, rem, sl, in); struct Crypto1State *statelist;
} uint32_t *odd_head = 0, *odd_tail = 0, oks = 0;
else if(*o_tail > *e_tail) uint32_t *even_head = 0, *even_tail = 0, eks = 0;
o_tail = binsearch(o_head, o_tail) - 1; int i;
else
e_tail = binsearch(e_head, e_tail) - 1; for(i = 31; i >= 0; i -= 2)
oks = oks << 1 | BEBIT(ks2, i);
return sl; for(i = 30; i >= 0; i -= 2)
} eks = eks << 1 | BEBIT(ks2, i);
/** lfsr_recovery
* recover the state of the lfsr given 32 bits of the keystream odd_head = odd_tail = malloc(sizeof(uint32_t) << 21);
* additionally you can use the in parameter to specify the value even_head = even_tail = malloc(sizeof(uint32_t) << 21);
* that was fed into the lfsr at the time the keystream was generated statelist = malloc(sizeof(struct Crypto1State) << 18);
*/ if(!odd_tail-- || !even_tail-- || !statelist) {
struct Crypto1State* lfsr_recovery32(uint32_t ks2, uint32_t in) free(statelist);
{ statelist = 0;
struct Crypto1State *statelist; goto out;
uint32_t *odd_head = 0, *odd_tail = 0, oks = 0; }
uint32_t *even_head = 0, *even_tail = 0, eks = 0;
int i; statelist->odd = statelist->even = 0;
for(i = 31; i >= 0; i -= 2) for(i = 1 << 20; i >= 0; --i) {
oks = oks << 1 | BEBIT(ks2, i); if(filter(i) == (oks & 1))
for(i = 30; i >= 0; i -= 2) *++odd_tail = i;
eks = eks << 1 | BEBIT(ks2, i); if(filter(i) == (eks & 1))
*++even_tail = i;
odd_head = odd_tail = malloc(sizeof(uint32_t) << 21); }
even_head = even_tail = malloc(sizeof(uint32_t) << 21);
statelist = malloc(sizeof(struct Crypto1State) << 18); for(i = 0; i < 4; i++) {
if(!odd_tail-- || !even_tail-- || !statelist) extend_table_simple(odd_head, &odd_tail, (oks >>= 1) & 1);
goto out; extend_table_simple(even_head, &even_tail, (eks >>= 1) & 1);
}
statelist->odd = statelist->even = 0;
in = (in >> 16 & 0xff) | (in << 16) | (in & 0xff00);
for(i = 1 << 20; i >= 0; --i) { recover(odd_head, odd_tail, oks,
if(filter(i) == (oks & 1)) even_head, even_tail, eks, 11, statelist, in << 1);
*++odd_tail = i;
if(filter(i) == (eks & 1)) out:
*++even_tail = i; free(odd_head);
} free(even_head);
return statelist;
for(i = 0; i < 4; i++) { }
extend_table_simple(odd_head, &odd_tail, (oks >>= 1) & 1);
extend_table_simple(even_head, &even_tail, (eks >>= 1) & 1); static const uint32_t S1[] = { 0x62141, 0x310A0, 0x18850, 0x0C428, 0x06214,
} 0x0310A, 0x85E30, 0xC69AD, 0x634D6, 0xB5CDE, 0xDE8DA, 0x6F46D, 0xB3C83,
0x59E41, 0xA8995, 0xD027F, 0x6813F, 0x3409F, 0x9E6FA};
in = (in >> 16 & 0xff) | (in << 16) | (in & 0xff00); static const uint32_t S2[] = { 0x3A557B00, 0x5D2ABD80, 0x2E955EC0, 0x174AAF60,
recover(odd_head, odd_tail, oks, 0x0BA557B0, 0x05D2ABD8, 0x0449DE68, 0x048464B0, 0x42423258, 0x278192A8,
even_head, even_tail, eks, 11, statelist, in << 1); 0x156042D0, 0x0AB02168, 0x43F89B30, 0x61FC4D98, 0x765EAD48, 0x7D8FDD20,
0x7EC7EE90, 0x7F63F748, 0x79117020};
out: static const uint32_t T1[] = {
free(odd_head); 0x4F37D, 0x279BE, 0x97A6A, 0x4BD35, 0x25E9A, 0x12F4D, 0x097A6, 0x80D66,
free(even_head); 0xC4006, 0x62003, 0xB56B4, 0x5AB5A, 0xA9318, 0xD0F39, 0x6879C, 0xB057B,
return statelist; 0x582BD, 0x2C15E, 0x160AF, 0x8F6E2, 0xC3DC4, 0xE5857, 0x72C2B, 0x39615,
} 0x98DBF, 0xC806A, 0xE0680, 0x70340, 0x381A0, 0x98665, 0x4C332, 0xA272C};
static const uint32_t T2[] = { 0x3C88B810, 0x5E445C08, 0x2982A580, 0x14C152C0,
static const uint32_t S1[] = { 0x62141, 0x310A0, 0x18850, 0x0C428, 0x06214, 0x4A60A960, 0x253054B0, 0x52982A58, 0x2FEC9EA8, 0x1156C4D0, 0x08AB6268,
0x0310A, 0x85E30, 0xC69AD, 0x634D6, 0xB5CDE, 0xDE8DA, 0x6F46D, 0xB3C83, 0x42F53AB0, 0x217A9D58, 0x161DC528, 0x0DAE6910, 0x46D73488, 0x25CB11C0,
0x59E41, 0xA8995, 0xD027F, 0x6813F, 0x3409F, 0x9E6FA}; 0x52E588E0, 0x6972C470, 0x34B96238, 0x5CFC3A98, 0x28DE96C8, 0x12CFC0E0,
static const uint32_t S2[] = { 0x3A557B00, 0x5D2ABD80, 0x2E955EC0, 0x174AAF60, 0x4967E070, 0x64B3F038, 0x74F97398, 0x7CDC3248, 0x38CE92A0, 0x1C674950,
0x0BA557B0, 0x05D2ABD8, 0x0449DE68, 0x048464B0, 0x42423258, 0x278192A8, 0x0E33A4A8, 0x01B959D0, 0x40DCACE8, 0x26CEDDF0};
0x156042D0, 0x0AB02168, 0x43F89B30, 0x61FC4D98, 0x765EAD48, 0x7D8FDD20, static const uint32_t C1[] = { 0x846B5, 0x4235A, 0x211AD};
0x7EC7EE90, 0x7F63F748, 0x79117020}; static const uint32_t C2[] = { 0x1A822E0, 0x21A822E0, 0x21A822E0};
static const uint32_t T1[] = { /** Reverse 64 bits of keystream into possible cipher states
0x4F37D, 0x279BE, 0x97A6A, 0x4BD35, 0x25E9A, 0x12F4D, 0x097A6, 0x80D66, * Variation mentioned in the paper. Somewhat optimized version
0xC4006, 0x62003, 0xB56B4, 0x5AB5A, 0xA9318, 0xD0F39, 0x6879C, 0xB057B, */
0x582BD, 0x2C15E, 0x160AF, 0x8F6E2, 0xC3DC4, 0xE5857, 0x72C2B, 0x39615, struct Crypto1State* lfsr_recovery64(uint32_t ks2, uint32_t ks3)
0x98DBF, 0xC806A, 0xE0680, 0x70340, 0x381A0, 0x98665, 0x4C332, 0xA272C}; {
static const uint32_t T2[] = { 0x3C88B810, 0x5E445C08, 0x2982A580, 0x14C152C0, struct Crypto1State *statelist, *sl;
0x4A60A960, 0x253054B0, 0x52982A58, 0x2FEC9EA8, 0x1156C4D0, 0x08AB6268, uint8_t oks[32], eks[32], hi[32];
0x42F53AB0, 0x217A9D58, 0x161DC528, 0x0DAE6910, 0x46D73488, 0x25CB11C0, uint32_t low = 0, win = 0;
0x52E588E0, 0x6972C470, 0x34B96238, 0x5CFC3A98, 0x28DE96C8, 0x12CFC0E0, uint32_t *tail, table[1 << 16];
0x4967E070, 0x64B3F038, 0x74F97398, 0x7CDC3248, 0x38CE92A0, 0x1C674950, int i, j;
0x0E33A4A8, 0x01B959D0, 0x40DCACE8, 0x26CEDDF0};
static const uint32_t C1[] = { 0x846B5, 0x4235A, 0x211AD}; sl = statelist = malloc(sizeof(struct Crypto1State) << 4);
static const uint32_t C2[] = { 0x1A822E0, 0x21A822E0, 0x21A822E0}; if(!sl)
/** Reverse 64 bits of keystream into possible cipher states return 0;
* Variation mentioned in the paper. Somewhat optimized version sl->odd = sl->even = 0;
*/
struct Crypto1State* lfsr_recovery64(uint32_t ks2, uint32_t ks3) for(i = 30; i >= 0; i -= 2) {
{ oks[i >> 1] = BEBIT(ks2, i);
struct Crypto1State *statelist, *sl; oks[16 + (i >> 1)] = BEBIT(ks3, i);
uint8_t oks[32], eks[32], hi[32]; }
uint32_t low = 0, win = 0; for(i = 31; i >= 0; i -= 2) {
uint32_t *tail, table[1 << 16]; eks[i >> 1] = BEBIT(ks2, i);
int i, j; eks[16 + (i >> 1)] = BEBIT(ks3, i);
}
sl = statelist = malloc(sizeof(struct Crypto1State) << 4);
if(!sl) for(i = 0xfffff; i >= 0; --i) {
return 0; if (filter(i) != oks[0])
sl->odd = sl->even = 0; continue;
for(i = 30; i >= 0; i -= 2) { *(tail = table) = i;
oks[i >> 1] = BIT(ks2, i ^ 24); for(j = 1; tail >= table && j < 29; ++j)
oks[16 + (i >> 1)] = BIT(ks3, i ^ 24); extend_table_simple(table, &tail, oks[j]);
}
for(i = 31; i >= 0; i -= 2) { if(tail < table)
eks[i >> 1] = BIT(ks2, i ^ 24); continue;
eks[16 + (i >> 1)] = BIT(ks3, i ^ 24);
} for(j = 0; j < 19; ++j)
low = low << 1 | parity(i & S1[j]);
for(i = 0xfffff; i >= 0; --i) { for(j = 0; j < 32; ++j)
if (filter(i) != oks[0]) hi[j] = parity(i & T1[j]);
continue;
for(; tail >= table; --tail) {
*(tail = table) = i; for(j = 0; j < 3; ++j) {
for(j = 1; tail >= table && j < 29; ++j) *tail = *tail << 1;
extend_table_simple(table, &tail, oks[j]); *tail |= parity((i & C1[j]) ^ (*tail & C2[j]));
if(filter(*tail) != oks[29 + j])
if(tail < table) goto continue2;
continue; }
for(j = 0; j < 19; ++j) for(j = 0; j < 19; ++j)
low = low << 1 | parity(i & S1[j]); win = win << 1 | parity(*tail & S2[j]);
for(j = 0; j < 32; ++j)
hi[j] = parity(i & T1[j]); win ^= low;
for(j = 0; j < 32; ++j) {
for(; tail >= table; --tail) { win = win << 1 ^ hi[j] ^ parity(*tail & T2[j]);
for(j = 0; j < 3; ++j) { if(filter(win) != eks[j])
*tail = *tail << 1; goto continue2;
*tail |= parity((i & C1[j]) ^ (*tail & C2[j])); }
if(filter(*tail) != oks[29 + j])
goto continue2; *tail = *tail << 1 | parity(LF_POLY_EVEN & *tail);
} sl->odd = *tail ^ parity(LF_POLY_ODD & win);
sl->even = win;
for(j = 0; j < 19; ++j) ++sl;
win = win << 1 | parity(*tail & S2[j]); sl->odd = sl->even = 0;
continue2:;
win ^= low; }
for(j = 0; j < 32; ++j) { }
win = win << 1 ^ hi[j] ^ parity(*tail & T2[j]); return statelist;
if(filter(win) != eks[j]) }
goto continue2;
} /** lfsr_rollback_bit
* Rollback the shift register in order to get previous states
*tail = *tail << 1 | parity(LF_POLY_EVEN & *tail); */
sl->odd = *tail ^ parity(LF_POLY_ODD & win); uint8_t lfsr_rollback_bit(struct Crypto1State *s, uint32_t in, int fb)
sl->even = win; {
++sl; int out;
sl->odd = sl->even = 0; uint8_t ret;
continue2:;
} s->odd &= 0xffffff;
} s->odd ^= (s->odd ^= s->even, s->even ^= s->odd);
return statelist;
} out = s->even & 1;
out ^= LF_POLY_EVEN & (s->even >>= 1);
/** lfsr_rollback_bit out ^= LF_POLY_ODD & s->odd;
* Rollback the shift register in order to get previous states out ^= !!in;
*/ out ^= (ret = filter(s->odd)) & !!fb;
uint8_t lfsr_rollback_bit(struct Crypto1State *s, uint32_t in, int fb)
{ s->even |= parity(out) << 23;
int out; return ret;
uint8_t ret; }
/** lfsr_rollback_byte
s->odd &= 0xffffff; * Rollback the shift register in order to get previous states
s->odd ^= (s->odd ^= s->even, s->even ^= s->odd); */
uint8_t lfsr_rollback_byte(struct Crypto1State *s, uint32_t in, int fb)
out = s->even & 1; {
out ^= LF_POLY_EVEN & (s->even >>= 1); int i, ret = 0;
out ^= LF_POLY_ODD & s->odd; for (i = 7; i >= 0; --i)
out ^= !!in; ret |= lfsr_rollback_bit(s, BIT(in, i), fb) << i;
out ^= (ret = filter(s->odd)) & !!fb; return ret;
}
s->even |= parity(out) << 23; /** lfsr_rollback_word
return ret; * Rollback the shift register in order to get previous states
} */
/** lfsr_rollback_byte uint32_t lfsr_rollback_word(struct Crypto1State *s, uint32_t in, int fb)
* Rollback the shift register in order to get previous states {
*/ int i;
uint8_t lfsr_rollback_byte(struct Crypto1State *s, uint32_t in, int fb) uint32_t ret = 0;
{ for (i = 31; i >= 0; --i)
int i; ret |= lfsr_rollback_bit(s, BEBIT(in, i), fb) << (i ^ 24);
uint8_t ret = 0; return ret;
for (i = 7; i >= 0; --i) }
ret |= lfsr_rollback_bit(s, BIT(in, i), fb) << i;
return ret; /** nonce_distance
} * x,y valid tag nonces, then prng_successor(x, nonce_distance(x, y)) = y
/** lfsr_rollback_word */
* Rollback the shift register in order to get previous states static uint16_t *dist = 0;
*/ int nonce_distance(uint32_t from, uint32_t to)
uint32_t lfsr_rollback_word(struct Crypto1State *s, uint32_t in, int fb) {
{ uint16_t x, i;
int i; if(!dist) {
uint32_t ret = 0; dist = malloc(2 << 16);
for (i = 31; i >= 0; --i) if(!dist)
ret |= lfsr_rollback_bit(s, BEBIT(in, i), fb) << (i ^ 24); return -1;
return ret; for (x = i = 1; i; ++i) {
} dist[(x & 0xff) << 8 | x >> 8] = i;
x = x >> 1 | (x ^ x >> 2 ^ x >> 3 ^ x >> 5) << 15;
/** nonce_distance }
* x,y valid tag nonces, then prng_successor(x, nonce_distance(x, y)) = y }
*/ return (65535 + dist[to >> 16] - dist[from >> 16]) % 65535;
static uint16_t *dist = 0; }
int nonce_distance(uint32_t from, uint32_t to)
{
uint16_t x, i; static uint32_t fastfwd[2][8] = {
if(!dist) { { 0, 0x4BC53, 0xECB1, 0x450E2, 0x25E29, 0x6E27A, 0x2B298, 0x60ECB},
dist = malloc(2 << 16); { 0, 0x1D962, 0x4BC53, 0x56531, 0xECB1, 0x135D3, 0x450E2, 0x58980}};
if(!dist)
return -1;
for (x = i = 1; i; ++i) {
dist[(x & 0xff) << 8 | x >> 8] = i;
x = x >> 1 | (x ^ x >> 2 ^ x >> 3 ^ x >> 5) << 15;
}
}
return (65535 + dist[to >> 16] - dist[from >> 16]) % 65535;
}
static uint32_t fastfwd[2][8] = { /** lfsr_prefix_ks
{ 0, 0x4BC53, 0xECB1, 0x450E2, 0x25E29, 0x6E27A, 0x2B298, 0x60ECB}, *
{ 0, 0x1D962, 0x4BC53, 0x56531, 0xECB1, 0x135D3, 0x450E2, 0x58980}}; * Is an exported helper function from the common prefix attack
* Described in the "dark side" paper. It returns an -1 terminated array
* of possible partial(21 bit) secret state.
/** lfsr_prefix_ks * The required keystream(ks) needs to contain the keystream that was used to
* * encrypt the NACK which is observed when varying only the 3 last bits of Nr
* Is an exported helper function from the common prefix attack * only correct iff [NR_3] ^ NR_3 does not depend on Nr_3
* Described in the "dark side" paper. It returns an -1 terminated array */
* of possible partial(21 bit) secret state. uint32_t *lfsr_prefix_ks(uint8_t ks[8], int isodd)
* The required keystream(ks) needs to contain the keystream that was used to {
* encrypt the NACK which is observed when varying only the 4 last bits of Nr uint32_t c, entry, *candidates = malloc(4 << 10);
* only correct iff [NR_3] ^ NR_3 does not depend on Nr_3 int i, size = 0, good;
*/
uint32_t *lfsr_prefix_ks(uint8_t ks[8], int isodd) if(!candidates)
{ return 0;
uint32_t c, entry, *candidates = malloc(4 << 21);
int i, size = (1 << 21) - 1; for(i = 0; i < 1 << 21; ++i) {
for(c = 0, good = 1; good && c < 8; ++c) {
if(!candidates) entry = i ^ fastfwd[isodd][c];
return 0; good &= (BIT(ks[c], isodd) == filter(entry >> 1));
good &= (BIT(ks[c], isodd + 2) == filter(entry));
for(i = 0; i <= size; ++i) }
candidates[i] = i; if(good)
candidates[size++] = i;
for(c = 0; c < 8; ++c) }
for(i = 0;i <= size; ++i) {
entry = candidates[i] ^ fastfwd[isodd][c]; candidates[size] = -1;
if(filter(entry >> 1) != BIT(ks[c], isodd) || return candidates;
filter(entry) != BIT(ks[c], isodd + 2)) }
candidates[i--] = candidates[size--];
} /** check_pfx_parity
* helper function which eliminates possible secret states using parity bits
candidates[size + 1] = -1; */
static struct Crypto1State*
return candidates; check_pfx_parity(uint32_t prefix, uint32_t rresp, uint8_t parities[8][8],
} uint32_t odd, uint32_t even, struct Crypto1State* sl)
{
/** check_pfx_parity uint32_t ks1, nr, ks2, rr, ks3, c, good = 1;
* helper function which eliminates possible secret states using parity bits
*/ for(c = 0; good && c < 8; ++c) {
static struct Crypto1State* sl->odd = odd ^ fastfwd[1][c];
check_pfx_parity(uint32_t prefix, uint32_t rresp, uint8_t parities[8][8], sl->even = even ^ fastfwd[0][c];
uint32_t odd, uint32_t even, struct Crypto1State* sl)
{ lfsr_rollback_bit(sl, 0, 0);
uint32_t ks1, nr, ks2, rr, ks3, c, good = 1; lfsr_rollback_bit(sl, 0, 0);
for(c = 0; good && c < 8; ++c) { ks3 = lfsr_rollback_bit(sl, 0, 0);
sl->odd = odd ^ fastfwd[1][c]; ks2 = lfsr_rollback_word(sl, 0, 0);
sl->even = even ^ fastfwd[0][c]; ks1 = lfsr_rollback_word(sl, prefix | c << 5, 1);
lfsr_rollback_bit(sl, 0, 0); nr = ks1 ^ (prefix | c << 5);
lfsr_rollback_bit(sl, 0, 0); rr = ks2 ^ rresp;
ks3 = lfsr_rollback_bit(sl, 0, 0); good &= parity(nr & 0x000000ff) ^ parities[c][3] ^ BIT(ks2, 24);
ks2 = lfsr_rollback_word(sl, 0, 0); good &= parity(rr & 0xff000000) ^ parities[c][4] ^ BIT(ks2, 16);
ks1 = lfsr_rollback_word(sl, prefix | c << 5, 1); good &= parity(rr & 0x00ff0000) ^ parities[c][5] ^ BIT(ks2, 8);
good &= parity(rr & 0x0000ff00) ^ parities[c][6] ^ BIT(ks2, 0);
nr = ks1 ^ (prefix | c << 5); good &= parity(rr & 0x000000ff) ^ parities[c][7] ^ ks3;
rr = ks2 ^ rresp; }
good &= parity(nr & 0x000000ff) ^ parities[c][3] ^ BIT(ks2, 24); return sl + good;
good &= parity(rr & 0xff000000) ^ parities[c][4] ^ BIT(ks2, 16); }
good &= parity(rr & 0x00ff0000) ^ parities[c][5] ^ BIT(ks2, 8);
good &= parity(rr & 0x0000ff00) ^ parities[c][6] ^ BIT(ks2, 0);
good &= parity(rr & 0x000000ff) ^ parities[c][7] ^ ks3; /** lfsr_common_prefix
} * Implentation of the common prefix attack.
*/
return sl + good; struct Crypto1State*
} lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8])
{
struct Crypto1State *statelist, *s;
/** lfsr_common_prefix uint32_t *odd, *even, *o, *e, top;
* Implentation of the common prefix attack.
* Requires the 29 bit constant prefix used as reader nonce (pfx) odd = lfsr_prefix_ks(ks, 1);
* The reader response used (rr) even = lfsr_prefix_ks(ks, 0);
* The keystream used to encrypt the observed NACK's (ks)
* The parity bits (par) s = statelist = malloc((sizeof *statelist) << 20);
* It returns a zero terminated list of possible cipher states after the if(!s || !odd || !even) {
* tag nonce was fed in free(statelist);
*/ statelist = 0;
struct Crypto1State* goto out;
lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8]) }
{
struct Crypto1State *statelist, *s; for(o = odd; *o + 1; ++o)
uint32_t *odd, *even, *o, *e, top; for(e = even; *e + 1; ++e)
for(top = 0; top < 64; ++top) {
odd = lfsr_prefix_ks(ks, 1); *o += 1 << 21;
even = lfsr_prefix_ks(ks, 0); *e += (!(top & 7) + 1) << 21;
s = check_pfx_parity(pfx, rr, par, *o, *e, s);
s = statelist = malloc((sizeof *statelist) << 20); }
if(!s || !odd || !even) {
free(odd); s->odd = s->even = 0;
free(even); out:
free(statelist); free(odd);
return 0; free(even);
} return statelist;
}
for(o = odd; *o + 1; ++o)
for(e = even; *e + 1; ++e)
for(top = 0; top < 64; ++top) {
*o += 1 << 21;
*e += (!(top & 7) + 1) << 21;
s = check_pfx_parity(pfx, rr, par, *o, *e, s);
}
s->odd = s->even = 0;
free(odd);
free(even);
return statelist;
}

View File

@ -15,7 +15,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, US$ MA 02110-1301, US$
Copyright (C) 2008-2009 bla <blapost@gmail.com> Copyright (C) 2008-2008 bla <blapost@gmail.com>
*/ */
#ifndef CRAPTO1_INCLUDED #ifndef CRAPTO1_INCLUDED
#define CRAPTO1_INCLUDED #define CRAPTO1_INCLUDED
@ -35,8 +35,13 @@ uint32_t prng_successor(uint32_t x, uint32_t n);
struct Crypto1State* lfsr_recovery32(uint32_t ks2, uint32_t in); struct Crypto1State* lfsr_recovery32(uint32_t ks2, uint32_t in);
struct Crypto1State* lfsr_recovery64(uint32_t ks2, uint32_t ks3); struct Crypto1State* lfsr_recovery64(uint32_t ks2, uint32_t ks3);
uint32_t *lfsr_prefix_ks(uint8_t ks[8], int isodd);
struct Crypto1State*
lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8]);
void lfsr_rollback(struct Crypto1State* s, uint32_t in, int fb); uint8_t lfsr_rollback_bit(struct Crypto1State* s, uint32_t in, int fb);
uint8_t lfsr_rollback_byte(struct Crypto1State* s, uint32_t in, int fb);
uint32_t lfsr_rollback_word(struct Crypto1State* s, uint32_t in, int fb);
int nonce_distance(uint32_t from, uint32_t to); int nonce_distance(uint32_t from, uint32_t to);
#define FOREACH_VALID_NONCE(N, FILTER, FSIZE)\ #define FOREACH_VALID_NONCE(N, FILTER, FSIZE)\
uint32_t __n = 0,__M = 0, N = 0;\ uint32_t __n = 0,__M = 0, N = 0;\
@ -61,15 +66,13 @@ static inline int parity(uint32_t x)
x ^= x >> 4; x ^= x >> 4;
return BIT(0x6996, x & 0xf); return BIT(0x6996, x & 0xf);
#else #else
__asm__( asm( "movl %1, %%eax\n"
"movl %1, %%eax\n"
"mov %%ax, %%cx\n" "mov %%ax, %%cx\n"
"shrl $0x10, %%eax\n" "shrl $0x10, %%eax\n"
"xor %%ax, %%cx\n" "xor %%ax, %%cx\n"
"xor %%ch, %%cl\n" "xor %%ch, %%cl\n"
"setpo %%al\n" "setpo %%al\n"
"movzx %%al, %0\n": "=r"(x) : "r"(x): "eax","ecx" "movzx %%al, %0\n": "=r"(x) : "r"(x): "eax","ecx");
);
return x; return x;
#endif #endif
} }