]>
git.zerfleddert.de Git - proxmark3-svn/blob - client/loclass/ikeys.c
1 /*****************************************************************************
2 * This file is part of iClassCipher. It is a reconstructon of the cipher engine
3 * used in iClass, and RFID techology.
5 * The implementation is based on the work performed by
6 * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
7 * Milosch Meriac in the paper "Dismantling IClass".
9 * Copyright (C) 2014 Martin Holst Swende
11 * This is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as published
13 * by the Free Software Foundation.
15 * This file is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with IClassCipher. If not, see <http://www.gnu.org/licenses/>.
22 ****************************************************************************/
24 From "Dismantling iclass":
25 This section describes in detail the built-in key diversification algorithm of iClass.
26 Besides the obvious purpose of deriving a card key from a master key, this
27 algorithm intends to circumvent weaknesses in the cipher by preventing the
28 usage of certain ‘weak’ keys. In order to compute a diversified key, the iClass
29 reader first encrypts the card identity id with the master key K, using single
30 DES. The resulting ciphertext is then input to a function called hash0 which
31 outputs the diversified key k.
33 k = hash0(DES enc (id, K))
35 Here the DES encryption of id with master key K outputs a cryptogram c
36 of 64 bits. These 64 bits are divided as c = x, y, z [0] , . . . , z [7] ∈ F 82 × F 82 × (F 62 ) 8
37 which is used as input to the hash0 function. This function introduces some
38 obfuscation by performing a number of permutations, complement and modulo
39 operations, see Figure 2.5. Besides that, it checks for and removes patterns like
40 similar key bytes, which could produce a strong bias in the cipher. Finally, the
41 output of hash0 is the diversified card key k = k [0] , . . . , k [7] ∈ (F 82 ) 8 .
50 #include "cipherutils.h"
57 uint8_t pi
[35] = {0x0F,0x17,0x1B,0x1D,0x1E,0x27,0x2B,0x2D,0x2E,0x33,0x35,0x39,0x36,0x3A,0x3C,0x47,0x4B,0x4D,0x4E,0x53,0x55,0x56,0x59,0x5A,0x5C,0x63,0x65,0x66,0x69,0x6A,0x6C,0x71,0x72,0x74,0x78};
59 static des_context ctx_enc
= {DES_ENCRYPT
,{0}};
60 static des_context ctx_dec
= {DES_DECRYPT
,{0}};
62 static bool debug_print
= false;
65 * @brief The key diversification algorithm uses 6-bit bytes.
66 * This implementation uses 64 bit uint to pack seven of them into one
67 * variable. When they are there, they are placed as follows:
68 * XXXX XXXX N0 .... N7, occupying the lsat 48 bits.
70 * This function picks out one from such a collection
75 uint8_t getSixBitByte(uint64_t c
, int n
)
77 return (c
>> (42-6*n
)) & 0x3F;
78 //return (c >> n*6) & 0x3f;
82 * @brief Puts back a six-bit 'byte' into a uint64_t.
84 * @param z the value to place there
87 void pushbackSixBitByte(uint64_t *c
, uint8_t z
, int n
)
89 //0x XXXX YYYY ZZZZ ZZZZ ZZZZ
91 //z0: 1111 1100 0000 0000
93 uint64_t masked
= z
& 0x3F;
94 uint64_t eraser
= 0x3F;
107 uint64_t swapZvalues(uint64_t c
)
110 pushbackSixBitByte(&newz
, getSixBitByte(c
,0),7);
111 pushbackSixBitByte(&newz
, getSixBitByte(c
,1),6);
112 pushbackSixBitByte(&newz
, getSixBitByte(c
,2),5);
113 pushbackSixBitByte(&newz
, getSixBitByte(c
,3),4);
114 pushbackSixBitByte(&newz
, getSixBitByte(c
,4),3);
115 pushbackSixBitByte(&newz
, getSixBitByte(c
,5),2);
116 pushbackSixBitByte(&newz
, getSixBitByte(c
,6),1);
117 pushbackSixBitByte(&newz
, getSixBitByte(c
,7),0);
118 newz
|= (c
& 0xFFFF000000000000);
123 * @return 4 six-bit bytes chunked into a uint64_t,as 00..00a0a1a2a3
125 uint64_t ck(int i
, int j
, uint64_t z
)
128 // printf("ck( i=%d, j=%d), zi=[%d],zj=[%d] \n",i,j,getSixBitByte(z,i),getSixBitByte(z,j) );
130 if(i
== 1 && j
== -1)
132 // ck(1, −1, z [0] . . . z [3] ) = z [0] . . . z [3]
137 // ck(i, −1, z [0] . . . z [3] ) = ck(i − 1, i − 2, z [0] . . . z [3] )
138 return ck(i
-1,i
-2, z
);
141 if(getSixBitByte(z
,i
) == getSixBitByte(z
,j
))
143 // TODO, I dont know what they mean here in the paper
144 //ck(i, j − 1, z [0] . . . z [i] ← j . . . z [3] )
147 //printf("z[i]=z[i] (0x%02x), i=%d, j=%d\n",getSixBitByte(z,i),i,j );
148 for(c
= 0; c
< 4 ;c
++)
150 uint8_t val
= getSixBitByte(z
,c
);
154 pushbackSixBitByte(&newz
, j
, c
);
157 pushbackSixBitByte(&newz
, val
, c
);
160 return ck(i
,j
-1,newz
);
170 Let the function check : (F 62 ) 8 → (F 62 ) 8 be defined as
171 check(z [0] . . . z [7] ) = ck(3, 2, z [0] . . . z [3] ) · ck(3, 2, z [4] . . . z [7] )
173 where ck : N × N × (F 62 ) 4 → (F 62 ) 4 is defined as
175 ck(1, −1, z [0] . . . z [3] ) = z [0] . . . z [3]
176 ck(i, −1, z [0] . . . z [3] ) = ck(i − 1, i − 2, z [0] . . . z [3] )
177 ck(i, j, z [0] . . . z [3] ) =
178 ck(i, j − 1, z [0] . . . z [i] ← j . . . z [3] ), if z [i] = z [j] ;
179 ck(i, j − 1, z [0] . . . z [3] ), otherwise
184 uint64_t check(uint64_t z
)
186 //These 64 bits are divided as c = x, y, z [0] , . . . , z [7]
188 // ck(3, 2, z [0] . . . z [3] )
189 uint64_t ck1
= ck(3,2, z
);
191 // ck(3, 2, z [4] . . . z [7] )
192 uint64_t ck2
= ck(3,2, z
<< 24);
193 ck1
&= 0x00000000FFFFFF000000;
194 ck2
&= 0x00000000FFFFFF000000;
196 return ck1
| ck2
>> 24;
200 void permute(BitstreamIn
*p_in
, uint64_t z
,int l
,int r
, BitstreamOut
* out
)
202 if(bitsLeft(p_in
) == 0)
206 bool pn
= tailBit(p_in
);
209 uint8_t zl
= getSixBitByte(z
,l
);
210 //printf("permute pushing, zl=0x%02x, zl+1=0x%02x\n", zl, zl+1);
211 push6bits(out
, zl
+1);
212 permute(p_in
, z
, l
+1,r
, out
);
215 uint8_t zr
= getSixBitByte(z
,r
);
216 //printf("permute pushing, zr=0x%02x\n", zr);
218 permute(p_in
,z
,l
,r
+1,out
);
225 pushbackSixBitByte(&x
,0x00,0);
226 pushbackSixBitByte(&x
,0x01,1);
227 pushbackSixBitByte(&x
,0x02,2);
228 pushbackSixBitByte(&x
,0x03,3);
229 pushbackSixBitByte(&x
,0x04,4);
230 pushbackSixBitByte(&x
,0x05,5);
231 pushbackSixBitByte(&x
,0x06,6);
232 pushbackSixBitByte(&x
,0x07,7);
234 uint8_t mres
[8] = { getSixBitByte(x
, 0),
241 getSixBitByte(x
, 7)};
242 printarr("input_perm", mres
,8);
245 BitstreamIn p_in
= { &p
, 8,0 };
246 uint8_t outbuffer
[] = {0,0,0,0,0,0,0,0};
247 BitstreamOut out
= {outbuffer
,0,0};
249 permute(&p_in
, x
,0,4, &out
);
251 uint64_t permuted
= bytes_to_num(outbuffer
,8);
252 //printf("zTilde 0x%"PRIX64"\n", zTilde);
255 uint8_t res
[8] = { getSixBitByte(permuted
, 0),
256 getSixBitByte(permuted
, 1),
257 getSixBitByte(permuted
, 2),
258 getSixBitByte(permuted
, 3),
259 getSixBitByte(permuted
, 4),
260 getSixBitByte(permuted
, 5),
261 getSixBitByte(permuted
, 6),
262 getSixBitByte(permuted
, 7)};
263 printarr("permuted", res
, 8);
270 printf(" | x| y|z0|z1|z2|z3|z4|z5|z6|z7|\n");
273 void printState(char* desc
, int x
,int y
, uint64_t c
)
278 printf("%s : ", desc
);
279 //uint8_t x = (c & 0xFF00000000000000 ) >> 56;
280 //uint8_t y = (c & 0x00FF000000000000 ) >> 48;
281 printf(" %02x %02x", x
,y
);
283 for(i
=0 ; i
< 8 ; i
++)
285 printf(" %02x", getSixBitByte(c
,i
));
292 *Definition 11. Let the function hash0 : F 82 × F 82 × (F 62 ) 8 → (F 82 ) 8 be defined as
293 * hash0(x, y, z [0] . . . z [7] ) = k [0] . . . k [7] where
294 * z'[i] = (z[i] mod (63-i)) + i i = 0...3
295 * z'[i+4] = (z[i+4] mod (64-i)) + i i = 0...3
298 * @param k this is where the diversified key is put (should be 8 bytes)
301 void hash0(uint64_t c
, uint8_t *k
)
304 //These 64 bits are divided as c = x, y, z [0] , . . . , z [7]
307 // z0-z7 6 bits each : 48 bits
308 uint8_t x
= (c
& 0xFF00000000000000 ) >> 56;
309 uint8_t y
= (c
& 0x00FF000000000000 ) >> 48;
310 printState("origin",x
,y
,c
);
312 uint8_t zn
, zn4
, _zn
, _zn4
;
315 for(n
= 0; n
< 4 ; n
++)
317 zn
= getSixBitByte(c
,n
);
318 zn4
= getSixBitByte(c
,n
+4);
320 _zn
= (zn
% (63-n
)) + n
;
321 _zn4
= (zn4
% (64-n
)) + n
;
323 pushbackSixBitByte(&zP
, _zn
,n
);
324 pushbackSixBitByte(&zP
, _zn4
,n
+4);
327 printState("x|y|z'",x
,y
,zP
);
329 uint64_t zCaret
= check(zP
);
330 printState("x|y|z^",x
,y
,zP
);
333 uint8_t p
= pi
[x
% 35];
335 if(x
& 1) //Check if x7 is 1
339 printState("p|y|z^",p
,y
,zP
);
340 //if(debug_print) printf("p:%02x\n", p);
342 BitstreamIn p_in
= { &p
, 8,0 };
343 uint8_t outbuffer
[] = {0,0,0,0,0,0,0,0};
344 BitstreamOut out
= {outbuffer
,0,0};
345 permute(&p_in
,zCaret
,0,4,&out
);//returns 48 bits? or 6 8-bytes
347 //Out is now a buffer containing six-bit bytes, should be 48 bits
349 //printf("Permute output is %d num bits (48?)\n", out.numbits);
350 //Shift z-values down onto the lower segment
352 uint64_t zTilde
= bytes_to_num(outbuffer
,8);
354 //printf("zTilde 0x%"PRIX64"\n", zTilde);
356 //printf("z~ 0x%"PRIX64"\n", zTilde);
357 printState("p|y|z~", p
,y
,zTilde
);
361 for(i
=0 ; i
< 8 ; i
++)
364 // the key on index i is first a bit from y
365 // then six bits from z,
370 // First, place yi leftmost in k
371 //k[i] |= (y << i) & 0x80 ;
373 // First, place y(7-i) leftmost in k
374 k
[i
] |= (y
<< (7-i
)) & 0x80 ;
376 //printf("y%d = %d\n",i,(y << i) & 0x80);
378 uint8_t zTilde_i
= getSixBitByte(zTilde
, i
);
379 //printf("zTilde_%d 0x%02x (should be <= 0x3F)\n",i, zTilde_i);
380 // zTildeI is now on the form 00XXXXXX
381 // with one leftshift, it'll be
383 // So after leftshift, we can OR it into k
384 // However, when doing complement, we need to
385 // again MASK 0XXXXXX0 (0x7E)
388 //Finally, add bit from p or p-mod
389 //Shift bit i into rightmost location (mask only after complement)
390 uint8_t p_i
= p
>> i
& 0x1;
394 //printf("k[%d] +1\n", i);
395 k
[i
] |= ~zTilde_i
& 0x7E;
401 k
[i
] |= zTilde_i
& 0x7E;
409 //printf("zerocounter=%d (should be 4)\n",zerocounter);
410 //printf("permute fin, y:0x%02x, x: 0x%02x\n", y, x);
415 void reorder(uint8_t arr
[8])
417 uint8_t tmp
[4] = {arr
[3],arr
[2],arr
[1], arr
[0]};
422 arr
[4] = tmp
[0];//arr[3];
423 arr
[5] = tmp
[1];//arr[2];
424 arr
[6] = tmp
[2];//arr[3];
425 arr
[7] = tmp
[3];//arr[1]
428 //extern void printarr(char * name, uint8_t* arr, int len);
430 bool des_getParityBitFromKey(uint8_t key
)
431 {//The top 7 bits is used
432 bool parity
= ((key
& 0x80) >> 7)
433 ^ ((key
& 0x40) >> 6) ^ ((key
& 0x20) >> 5)
434 ^ ((key
& 0x10) >> 4) ^ ((key
& 0x08) >> 3)
435 ^ ((key
& 0x04) >> 2) ^ ((key
& 0x02) >> 1);
438 void des_checkParity(uint8_t* key
)
442 for(i
=0 ; i
< 8 ; i
++)
444 bool parity
= des_getParityBitFromKey(key
[i
]);
445 if(parity
!= (key
[i
] & 0x1))
448 printf("parity1 fail, byte %d [%02x] was %d, should be %d\n",i
,key
[i
],(key
[i
] & 0x1),parity
);
453 printf("parity fails: %d\n", fails
);
456 printf("Key syntax is with parity bits inside each byte\n");
460 void printarr2(char * name
, uint8_t* arr
, int len
)
463 printf("%s :", name
);
464 for(i
=0 ; i
< len
; i
++)
466 printf("%02x",*(arr
+i
));