ADD: added @azcid 's bitsliced BF solver for @piwi 's hardnested command. Awsume work! The original patch demanded some tweaking to work in mingw.
This is not tested for other systems so far.
This commit is contained in:
120
client/nonce2key/crypto1_bs.c
Normal file
120
client/nonce2key/crypto1_bs.c
Normal file
@@ -0,0 +1,120 @@
|
||||
// Bit-sliced Crypto-1 implementation
|
||||
// The cipher states are stored with the least significant bit first, hence all bit indexes are reversed here
|
||||
/*
|
||||
Copyright (c) 2015-2016 Aram Verstegen
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "crypto1_bs.h"
|
||||
#include <inttypes.h>
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#define llx PRIx64
|
||||
#define lli PRIi64
|
||||
#define lu PRIu32
|
||||
|
||||
// The following functions use this global or thread-local state
|
||||
// It is sized to fit exactly KEYSTREAM_SIZE more states next to the initial state
|
||||
__thread bitslice_t states[KEYSTREAM_SIZE+STATE_SIZE];
|
||||
__thread bitslice_t * restrict state_p;
|
||||
|
||||
void crypto1_bs_init(){
|
||||
// initialize constant one and zero bit vectors
|
||||
memset(bs_ones.bytes, 0xff, VECTOR_SIZE);
|
||||
memset(bs_zeroes.bytes, 0x00, VECTOR_SIZE);
|
||||
}
|
||||
|
||||
// The following functions have side effects on 48 bitslices at the state_p pointer
|
||||
// use the crypto1_bs_rewind_* macros to (re-)initialize them as needed
|
||||
|
||||
inline const bitslice_value_t crypto1_bs_bit(const bitslice_value_t input, const bool is_encrypted){
|
||||
bitslice_value_t feedback = (state_p[47- 0].value ^ state_p[47- 5].value ^ state_p[47- 9].value ^
|
||||
state_p[47-10].value ^ state_p[47-12].value ^ state_p[47-14].value ^
|
||||
state_p[47-15].value ^ state_p[47-17].value ^ state_p[47-19].value ^
|
||||
state_p[47-24].value ^ state_p[47-25].value ^ state_p[47-27].value ^
|
||||
state_p[47-29].value ^ state_p[47-35].value ^ state_p[47-39].value ^
|
||||
state_p[47-41].value ^ state_p[47-42].value ^ state_p[47-43].value);
|
||||
const bitslice_value_t ks_bits = crypto1_bs_f20(state_p);
|
||||
if(is_encrypted){
|
||||
feedback ^= ks_bits;
|
||||
}
|
||||
state_p--;
|
||||
state_p[0].value = feedback ^ input;
|
||||
return ks_bits;
|
||||
}
|
||||
|
||||
inline const bitslice_value_t crypto1_bs_lfsr_rollback(const bitslice_value_t input, const bool is_encrypted){
|
||||
bitslice_value_t feedout = state_p[0].value;
|
||||
state_p++;
|
||||
const bitslice_value_t ks_bits = crypto1_bs_f20(state_p);
|
||||
if(is_encrypted){
|
||||
feedout ^= ks_bits;
|
||||
}
|
||||
const bitslice_value_t feedback = (feedout ^ state_p[47- 5].value ^ state_p[47- 9].value ^
|
||||
state_p[47-10].value ^ state_p[47-12].value ^ state_p[47-14].value ^
|
||||
state_p[47-15].value ^ state_p[47-17].value ^ state_p[47-19].value ^
|
||||
state_p[47-24].value ^ state_p[47-25].value ^ state_p[47-27].value ^
|
||||
state_p[47-29].value ^ state_p[47-35].value ^ state_p[47-39].value ^
|
||||
state_p[47-41].value ^ state_p[47-42].value ^ state_p[47-43].value);
|
||||
state_p[47].value = feedback ^ input;
|
||||
return ks_bits;
|
||||
}
|
||||
|
||||
// side-effect free from here on
|
||||
// note that bytes are sliced and unsliced with reversed endianness
|
||||
inline void crypto1_bs_convert_states(bitslice_t bitsliced_states[], state_t regular_states[]){
|
||||
size_t bit_idx = 0, slice_idx = 0;
|
||||
state_t values[MAX_BITSLICES];
|
||||
for(slice_idx = 0; slice_idx < MAX_BITSLICES; slice_idx++){
|
||||
for(bit_idx = 0; bit_idx < STATE_SIZE; bit_idx++){
|
||||
bool bit = get_vector_bit(slice_idx, bitsliced_states[bit_idx]);
|
||||
values[slice_idx].value <<= 1;
|
||||
values[slice_idx].value |= bit;
|
||||
}
|
||||
// swap endianness
|
||||
values[slice_idx].value = rev_state_t(values[slice_idx].value);
|
||||
// roll off unused bits
|
||||
values[slice_idx].value >>= ((sizeof(state_t)*8)-STATE_SIZE);
|
||||
}
|
||||
memcpy(regular_states, values, sizeof(values));
|
||||
}
|
||||
|
||||
// bitslice a value
|
||||
void crypto1_bs_bitslice_value32(uint32_t value, bitslice_t bitsliced_value[], size_t bit_len){
|
||||
// load nonce bytes with unswapped endianness
|
||||
size_t bit_idx;
|
||||
for(bit_idx = 0; bit_idx < bit_len; bit_idx++){
|
||||
bool bit = get_bit(bit_len-1-bit_idx, rev32(value));
|
||||
if(bit){
|
||||
bitsliced_value[bit_idx].value = bs_ones.value;
|
||||
} else {
|
||||
bitsliced_value[bit_idx].value = bs_zeroes.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void crypto1_bs_print_states(bitslice_t bitsliced_states[]){
|
||||
size_t slice_idx = 0;
|
||||
state_t values[MAX_BITSLICES];
|
||||
crypto1_bs_convert_states(bitsliced_states, values);
|
||||
for(slice_idx = 0; slice_idx < MAX_BITSLICES; slice_idx++){
|
||||
printf("State %03zu: %012"llx"\n", slice_idx, values[slice_idx].value);
|
||||
}
|
||||
}
|
||||
|
||||
99
client/nonce2key/crypto1_bs.h
Normal file
99
client/nonce2key/crypto1_bs.h
Normal file
@@ -0,0 +1,99 @@
|
||||
#ifndef _CRYPTO1_BS_H
|
||||
#define _CRYPTO1_BS_H
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// bitslice type
|
||||
// while AVX supports 256 bit vector floating point operations, we need integer operations for boolean logic
|
||||
// same for AVX2 and 512 bit vectors
|
||||
// using larger vectors works but seems to generate more register pressure
|
||||
#if defined(__AVX2__)
|
||||
#define MAX_BITSLICES 256
|
||||
#elif defined(__AVX__)
|
||||
#define MAX_BITSLICES 128
|
||||
#elif defined(__SSE2__)
|
||||
#define MAX_BITSLICES 128
|
||||
#else
|
||||
#define MAX_BITSLICES 64
|
||||
#endif
|
||||
|
||||
#define VECTOR_SIZE (MAX_BITSLICES/8)
|
||||
typedef unsigned int __attribute__((aligned(VECTOR_SIZE))) __attribute__((vector_size(VECTOR_SIZE))) bitslice_value_t;
|
||||
typedef union {
|
||||
bitslice_value_t value;
|
||||
uint64_t bytes64[MAX_BITSLICES/64];
|
||||
uint8_t bytes[MAX_BITSLICES/8];
|
||||
} bitslice_t;
|
||||
|
||||
// filter function (f20)
|
||||
// sourced from ``Wirelessly Pickpocketing a Mifare Classic Card'' by Flavio Garcia, Peter van Rossum, Roel Verdult and Ronny Wichers Schreur
|
||||
#define f20a(a,b,c,d) (((a|b)^(a&d))^(c&((a^b)|d)))
|
||||
#define f20b(a,b,c,d) (((a&b)|c)^((a^b)&(c|d)))
|
||||
#define f20c(a,b,c,d,e) ((a|((b|e)&(d^e)))^((a^(b&d))&((c^d)|(b&e))))
|
||||
|
||||
#define crypto1_bs_f20(s) \
|
||||
f20c(f20a((s[47- 9].value), (s[47-11].value), (s[47-13].value), (s[47-15].value)), \
|
||||
f20b((s[47-17].value), (s[47-19].value), (s[47-21].value), (s[47-23].value)), \
|
||||
f20b((s[47-25].value), (s[47-27].value), (s[47-29].value), (s[47-31].value)), \
|
||||
f20a((s[47-33].value), (s[47-35].value), (s[47-37].value), (s[47-39].value)), \
|
||||
f20b((s[47-41].value), (s[47-43].value), (s[47-45].value), (s[47-47].value)))
|
||||
|
||||
// bit indexing
|
||||
#define get_bit(n, word) ((word >> (n)) & 1)
|
||||
#define get_vector_bit(slice, value) get_bit(slice&0x3f, value.bytes64[slice>>6])
|
||||
|
||||
// constant ones/zeroes
|
||||
bitslice_t bs_ones;
|
||||
bitslice_t bs_zeroes;
|
||||
|
||||
// size of crypto-1 state
|
||||
#define STATE_SIZE 48
|
||||
// size of nonce to be decrypted
|
||||
#define KEYSTREAM_SIZE 32
|
||||
// size of first uid^nonce byte to be rolled back to the initial key
|
||||
#define ROLLBACK_SIZE 8
|
||||
// number of nonces required to test to cover entire 48-bit state
|
||||
// I would have said it's 12... but bla goes with 100, so I do too
|
||||
#define NONCE_TESTS 100
|
||||
|
||||
// state pointer management
|
||||
extern __thread bitslice_t states[KEYSTREAM_SIZE+STATE_SIZE];
|
||||
extern __thread bitslice_t * restrict state_p;
|
||||
|
||||
// rewind to the point a0, at which KEYSTREAM_SIZE more bits can be generated
|
||||
#define crypto1_bs_rewind_a0() (state_p = &states[KEYSTREAM_SIZE])
|
||||
|
||||
// bitsliced bytewise parity
|
||||
#define bitsliced_byte_parity(n) (n[0].value ^ n[1].value ^ n[2].value ^ n[3].value ^ n[4].value ^ n[5].value ^ n[6].value ^ n[7].value)
|
||||
|
||||
// 48-bit crypto-1 states are normally represented using 64-bit values
|
||||
typedef union {
|
||||
uint64_t value;
|
||||
uint8_t bytes[8];
|
||||
} state_t;
|
||||
|
||||
// endianness conversion
|
||||
#define rev32(word) (((word & 0xff) << 24) | (((word >> 8) & 0xff) << 16) | (((word >> 16) & 0xff) << 8) | (((word >> 24) & 0xff)))
|
||||
#define rev64(x) (rev32(x)<<32|(rev32((x>>32))))
|
||||
#define rev_state_t rev64
|
||||
|
||||
// crypto-1 functions
|
||||
const bitslice_value_t crypto1_bs_bit(const bitslice_value_t input, const bool is_encrypted);
|
||||
const bitslice_value_t crypto1_bs_lfsr_rollback(const bitslice_value_t input, const bool is_encrypted);
|
||||
|
||||
// initialization functions
|
||||
void crypto1_bs_init();
|
||||
|
||||
// conversion functions
|
||||
void crypto1_bs_bitslice_value32(uint32_t value, bitslice_t bitsliced_value[], size_t bit_len);
|
||||
void crypto1_bs_convert_states(bitslice_t bitsliced_states[], state_t regular_states[]);
|
||||
|
||||
// debug print
|
||||
void crypto1_bs_print_states(bitslice_t *bitsliced_states);
|
||||
|
||||
#endif // _CRYPTO1_BS_H
|
||||
|
||||
Reference in New Issue
Block a user