+ char cmdp = param_getchar(Cmd, 0);
+ uint8_t blockno = -1;
+ uint8_t data[4] = {0x00};
+ bool isSrix4k = true;
+ char str[20];
+
+ if (strlen(Cmd) < 1 || cmdp == 'h' || cmdp == 'H') {
+ PrintAndLog("Usage: hf 14b write <1|2> <BLOCK> <DATA>");
+ PrintAndLog(" [1 = SRIX4K]");
+ PrintAndLog(" [2 = SRI512]");
+ PrintAndLog(" [BLOCK number depends on tag, special block == FF]");
+ PrintAndLog(" sample: hf 14b write 1 7F 11223344");
+ PrintAndLog(" : hf 14b write 1 FF 11223344");
+ PrintAndLog(" : hf 14b write 2 15 11223344");
+ PrintAndLog(" : hf 14b write 2 FF 11223344");
+ return 0;
+ }
+
+ if ( cmdp == '2' )
+ isSrix4k = false;
+
+ //blockno = param_get8(Cmd, 1);
+
+ if ( param_gethex(Cmd,1, &blockno, 2) ) {
+ PrintAndLog("Block number must include 2 HEX symbols");
+ return 0;
+ }
+
+ if ( isSrix4k ){
+ if ( blockno > 0x7f && blockno != 0xff ){
+ PrintAndLog("Block number out of range");
+ return 0;
+ }
+ } else {
+ if ( blockno > 0x0f && blockno != 0xff ){
+ PrintAndLog("Block number out of range");
+ return 0;
+ }
+ }
+
+ if (param_gethex(Cmd, 2, data, 8)) {
+ PrintAndLog("Data must include 8 HEX symbols");
+ return 0;
+ }
+
+ if ( blockno == 0xff)
+ PrintAndLog("[%s] Write special block %02X [ %s ]", (isSrix4k)?"SRIX4K":"SRI512" , blockno, sprint_hex(data,4) );
+ else
+ PrintAndLog("[%s] Write block %02X [ %s ]", (isSrix4k)?"SRIX4K":"SRI512", blockno, sprint_hex(data,4) );
+
+ sprintf(str, "-c 09 %02x %02x%02x%02x%02x", blockno, data[0], data[1], data[2], data[3]);
+
+ CmdHF14BCmdRaw(str);
+ return 0;
+}
+
+uint32_t srix4kEncode(uint32_t value) {
+/*
+// vv = value
+// pp = position
+// vv vv vv pp
+4 bytes : 00 1A 20 01
+*/
+
+#define NibbleHigh(b) ( (b & 0xF0) >> 4 )
+#define NibbleLow(b) ( b & 0x0F )
+#define Crumb(b,p) (((b & (0x3 << p) ) >> p ) & 0xF)
+
+ // only the lower crumbs.
+ uint8_t block = (value & 0xFF);
+ uint8_t i = 0;
+ uint8_t valuebytes[] = {0,0,0};
+
+ num_to_bytes(value, 3, valuebytes);
+
+ // Scrambled part
+ // Crumb swapping of value.
+ uint8_t temp[] = {0,0};
+ temp[0] = (Crumb(value, 22) << 4 | Crumb(value, 14 ) << 2 | Crumb(value, 6)) << 4;
+ temp[0] |= Crumb(value, 20) << 4 | Crumb(value, 12 ) << 2 | Crumb(value, 4);
+ temp[1] = (Crumb(value, 18) << 4 | Crumb(value, 10 ) << 2 | Crumb(value, 2)) << 4;
+ temp[1] |= Crumb(value, 16) << 4 | Crumb(value, 8 ) << 2 | Crumb(value, 0);
+
+ // chksum part
+ uint32_t chksum = 0xFF - block;
+
+ // chksum is reduced by each nibbles of value.
+ for (i = 0; i < 3; ++i){
+ chksum -= NibbleHigh(valuebytes[i]);
+ chksum -= NibbleLow(valuebytes[i]);
+ }
+
+ // base4 conversion and left shift twice
+ i = 3;
+ uint8_t base4[] = {0,0,0,0};
+ while( chksum !=0 ){
+ base4[i--] = (chksum % 4 << 2);
+ chksum /= 4;
+ }
+
+ // merge scambled and chksum parts
+ uint32_t encvalue =
+ ( NibbleLow ( base4[0]) << 28 ) |
+ ( NibbleHigh( temp[0]) << 24 ) |
+
+ ( NibbleLow ( base4[1]) << 20 ) |
+ ( NibbleLow ( temp[0]) << 16 ) |
+
+ ( NibbleLow ( base4[2]) << 12 ) |
+ ( NibbleHigh( temp[1]) << 8 ) |
+
+ ( NibbleLow ( base4[3]) << 4 ) |
+ NibbleLow ( temp[1] );
+
+ PrintAndLog("ICE encoded | %08X -> %08X", value, encvalue);
+ return encvalue;
+}
+uint32_t srix4kDecode(uint32_t value) {
+ switch(value) {
+ case 0xC04F42C5: return 0x003139;
+ case 0xC1484807: return 0x002943;
+ case 0xC0C60848: return 0x001A20;
+ }
+ return 0;
+}
+uint32_t srix4kDecodeCounter(uint32_t num) {
+ uint32_t value = ~num;
+ ++value;
+ return value;
+}
+
+uint32_t srix4kGetMagicbytes( uint64_t uid, uint32_t block6, uint32_t block18, uint32_t block19 ){
+#define MASK 0xFFFFFFFF;
+ uint32_t uid32 = uid & MASK;
+ uint32_t counter = srix4kDecodeCounter(block6);
+ uint32_t decodedBlock18 = srix4kDecode(block18);
+ uint32_t decodedBlock19 = srix4kDecode(block19);
+ uint32_t doubleBlock = (decodedBlock18 << 16 | decodedBlock19) + 1;
+
+ uint32_t result = (uid32 * doubleBlock * counter) & MASK;
+ PrintAndLog("Magic bytes | %08X", result);
+ return result;
+}
+int srix4kValid(const char *Cmd){
+
+ uint64_t uid = 0xD00202501A4532F9;
+ uint32_t block6 = 0xFFFFFFFF;
+ uint32_t block18 = 0xC04F42C5;
+ uint32_t block19 = 0xC1484807;
+ uint32_t block21 = 0xD1BCABA4;
+
+ uint32_t test_b18 = 0x00313918;
+ uint32_t test_b18_enc = srix4kEncode(test_b18);
+ //uint32_t test_b18_dec = srix4kDecode(test_b18_enc);
+ PrintAndLog("ENCODE & CHECKSUM | %08X -> %08X (%s)", test_b18, test_b18_enc , "");
+
+ uint32_t magic = srix4kGetMagicbytes(uid, block6, block18, block19);
+ PrintAndLog("BLOCK 21 | %08X -> %08X (no XOR)", block21, magic ^ block21);
+ return 0;
+}
+
+int CmdteaSelfTest(const char *Cmd){
+
+ uint8_t v[8], v_le[8];
+ memset(v, 0x00, sizeof(v));
+ memset(v_le, 0x00, sizeof(v_le));
+ uint8_t* v_ptr = v_le;
+
+ uint8_t cmdlen = strlen(Cmd);
+ cmdlen = ( sizeof(v)<<2 < cmdlen ) ? sizeof(v)<<2 : cmdlen;
+
+ if ( param_gethex(Cmd, 0, v, cmdlen) > 0 ){
+ PrintAndLog("can't read hex chars, uneven? :: %u", cmdlen);
+ return 1;
+ }
+
+ SwapEndian64ex(v , 8, 4, v_ptr);
+
+
+
+ PrintAndLog("Modified Burtle");
+ prng_ctx ctx; // = { 0, 0, 0, 0 };
+ uint32_t num = bytes_to_num(v+1, 4);
+ burtle_init_mod( &ctx, num);
+ PrintAndLog("V : %X", num);
+ PrintAndLog("BURT: %X", burtle_get_mod( &ctx));
+ PrintAndLog("SIMP: %X", GetSimplePrng(num));
+
+ uint8_t calc[16];
+
+ for ( uint8_t i=0; i<8; ++i){
+ if ( i%2 == 0) {
+ calc[0] += v[i];
+ calc[1] += NibbleHigh( v[i]);
+ calc[2] += NibbleLow( v[i]);
+ calc[3] ^= v[i];
+ calc[4] ^= NibbleHigh(v[i]);
+ calc[5] ^= NibbleLow( v[i]);
+ }
+ else {
+ calc[6] += v[i];
+ calc[7] += NibbleHigh( v[i]);
+ calc[8] += NibbleLow( v[i]);
+ calc[9] ^= v[i];
+ calc[10] ^= NibbleHigh(v[i]);
+ calc[11] ^= NibbleLow( v[i]);
+ }
+ }
+ for ( uint8_t i=0; i<4; ++i) calc[12] += v[i];
+ for ( uint8_t i=1; i<5; ++i) calc[13] += v[i];
+ for ( uint8_t i=2; i<6; ++i) calc[14] += v[i];
+ for ( uint8_t i=3; i<7; ++i) calc[15] += v[i];
+
+ PrintAndLog("%s ", sprint_hex(calc, 16) );
+ return 0;