rework cryptorf

This commit is contained in:
Philippe Teuwen 2020-08-19 21:38:21 +02:00
commit 9ade745f07
16 changed files with 693 additions and 985 deletions

View file

@ -1,31 +1,23 @@
CC = gcc
CXX = g++
LD = gcc
LXX = g++
CFLAGS = -W -Wall -O4
CXXFLAGS = -W -Wall -O4 -std=c++11
LDFLAGS =
LXXFLAGS = -lpthread
MYSRCPATHS = ../../common ../../common/cryptorf
MYSRCS = cryptolib.c util.c
MYINCLUDES = -I../../common/cryptorf
MYCFLAGS =
MYDEFS =
MYLDLIBS = -lpthread
OBJS = cryptolib.o util.o
HEADERS = cryptolib.h util.h
SRC = cryptolib.c util.c
EXES = cm sm sma sma_multi
#EXES = cm sm sma sma_multi crf
BINS = cm sm sma sma_multi
INSTALLTOOLS = $(BINS)
all: $(OBJS) $(EXES)
include ../../Makefile.host
%.o : %.c
$(CC) $(CFLAGS) -c -o $@ $<
# checking platform can be done only after Makefile.host
ifneq (,$(findstring MINGW,$(platform)))
# Mingw uses by default Microsoft printf, we want the GNU printf (e.g. for %z)
# and setting _ISOC99_SOURCE sets internally __USE_MINGW_ANSI_STDIO=1
CFLAGS += -D_ISOC99_SOURCE
endif
% : %.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
cm : $(OBJDIR)/cm.o $(MYOBJS)
sm : $(OBJDIR)/sm.o $(MYOBJS)
sma : $(OBJDIR)/sma.o $(MYOBJS)
sma_multi : $(OBJDIR)/sma_multi.o $(MYOBJS)

View file

@ -20,9 +20,16 @@
*
*/
#include "defines.h"
#include <inttypes.h>
#include <stddef.h>
#include <stdio.h>
#include "cryptolib.h"
#include "util.h"
#ifdef _MSC_VER
// avoid scanf warnings in Visual Studio
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_DEPRECATE
#endif
int main(int argc, const char* argv[])
{
@ -30,24 +37,24 @@ int main(int argc, const char* argv[])
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
uint8_t Q[8]; // Reader key-auth random
uint8_t Gc[8]; // Secret seed
uint8_t Ci[8]; // Card random (last state)
uint8_t Ch[8]; // Reader answer (challenge)
uint8_t Ci_1[8]; // Card answer
uint8_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?
uint8_t Qs[8]; // Reader session-auth random
uint8_t Chs[8]; // Reader session-answer (challenge)
uint8_t Ci_1s[8]; // Card answer for session
uint8_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
uint64_t nGc; // Card secret
uint64_t nCi; // Card random
uint64_t nQ; // Reader main-random
uint64_t nQs; // Reader session-random
// Show header and help syntax
printf("CryptoMemory simulator - (c) Radboud University Nijmegen\n");
@ -58,10 +65,10 @@ int main(int argc, const char* argv[])
}
// 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);
sscanf(argv[1],"%016" SCNx64,&nGc); num_to_bytes(nGc,8,Gc);
sscanf(argv[2],"%016" SCNx64,&nCi); num_to_bytes(nCi,8,Ci);
sscanf(argv[3],"%016" SCNx64,&nQ); num_to_bytes(nQ,8,Q);
sscanf(argv[4],"%016" SCNx64,&nQs); num_to_bytes(nQs,8,Qs);
// Calculate authentication
cm_auth(Gc,Ci,Q,Ch,Ci_1,Ci_2,&s);

View file

@ -1,294 +0,0 @@
/*
*
* 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;
}

View file

@ -1,359 +0,0 @@
/*
*
* 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);
}
}

View file

@ -1,56 +0,0 @@
/*
*
* 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_

View file

@ -1,36 +0,0 @@
/*
*
* 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_

View file

@ -1,2 +0,0 @@
#!/bin/sh
./crf 4f794a463ff81d81 2 0 80 546dae

View file

@ -20,10 +20,16 @@
*
*/
#include "defines.h"
#include <inttypes.h>
#include <stddef.h>
#include <stdio.h>
#include "cryptolib.h"
#include "util.h"
#include <stdio.h>
#ifdef _MSC_VER
// avoid scanf warnings in Visual Studio
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_DEPRECATE
#endif
int main(int argc, const char* argv[])
{
@ -31,16 +37,16 @@ int main(int argc, const char* argv[])
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
uint8_t Q[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; // Reader random
uint8_t Gc[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; // Secret seed
uint8_t Ci[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; // Card random (last state)
uint8_t Ch[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; // Reader answer
uint8_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
uint64_t nGc; // Card secret
uint64_t nCi; // Card random
uint64_t nQ; // Reader main-random
// Show header and help syntax
printf("SecureMemory simulator - (c) Radboud University Nijmegen\n");
@ -51,9 +57,9 @@ int main(int argc, const char* argv[])
}
// 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[1],"%016" SCNx64,&nGc); num_to_bytes(nGc,8,Gc);
sscanf(argv[2],"%016" SCNx64,&nCi); num_to_bytes(nCi,8,Ci);
sscanf(argv[3],"%016" SCNx64,&nQ); num_to_bytes(nQ,8,Q);
// Calculate authentication
sm_auth(Gc,Ci,Q,Ch,Ci_1,&s);

View file

@ -20,21 +20,24 @@
*
* Modified Iceman, 2020
*/
#include "defines.h"
#include "cryptolib.h"
#include "util.h"
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <inttypes.h>
#include <iostream>
#include <vector>
#include <map>
#include <algorithm> // sort, max_element, random_shuffle, remove_if, lower_bound
#include <functional> // greater, bind2nd
#include "cryptolib.h"
#include "util.h"
using namespace std;
#ifdef _MSC_VER
// avoid scanf warnings in Visual Studio
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_DEPRECATE
#define inline __inline
#endif
@ -125,13 +128,13 @@ typedef struct {
nibble b1r;
nibble b1s;
bool invalid;
byte_t Gc[8];
uint8_t Gc[8];
}cs_t;
typedef cs_t* pcs;
typedef struct {
byte_t addition;
byte_t out;
uint8_t addition;
uint8_t out;
} lookup_entry;
enum cipher_state_side {
@ -145,18 +148,18 @@ void print_cs(const char* text,pcs s)
printf("%s",text);
for(pos=6;pos>=0;pos--)
printf(" %02x",(byte_t)(s->l>>(pos*5))&0x1f);
printf(" %02x",(uint8_t)(s->l>>(pos*5))&0x1f);
printf(" |");
for(pos=6;pos>=0;pos--)
printf(" %02x",(byte_t)(s->m>>(pos*7))&0x7f);
printf(" %02x",(uint8_t)(s->m>>(pos*7))&0x7f);
printf(" |");
for(pos=4;pos>=0;pos--)
printf(" %02x",(byte_t)(s->r>>(pos*5))&0x1f);
printf(" %02x",(uint8_t)(s->r>>(pos*5))&0x1f);
printf("\n");
}
static inline byte_t mod(byte_t a, byte_t m)
static inline uint8_t mod(uint8_t a, uint8_t m)
{
// Just return the input when this is less or equal than the modular value
if (a<m) return a;
@ -168,27 +171,27 @@ static inline byte_t mod(byte_t a, byte_t m)
return (a == 0) ? m : a;
}
static inline byte_t bit_rotate_l(byte_t a, byte_t n_bits)
static inline uint8_t bit_rotate_l(uint8_t a, uint8_t n_bits)
{
// Rotate value a with the length of n_bits only 1 time
byte_t mask = (1 << n_bits) - 1;
uint8_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)
static inline uint8_t bit_rotate_r(uint8_t a, uint8_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 uint8_t lookup_left_substraction[0x400];
static uint8_t lookup_right_subtraction[0x400];
static lookup_entry lookup_left[0x100000];
static lookup_entry lookup_right[0x8000];
static byte_t left_addition[0x100000];
static uint8_t left_addition[0x100000];
static inline void init_lookup_left()
{
byte_t b3,b6,temp;
uint8_t b3,b6,temp;
int i,index;
for(i = 0; i <0x400; i++)
@ -207,7 +210,7 @@ static inline void init_lookup_left()
static inline void init_lookup_right()
{
byte_t b16,b18,temp;
uint8_t b16,b18,temp;
int i,index;
for(i = 0; i <0x400; i++)
@ -226,8 +229,8 @@ static void init_lookup_left_substraction()
{
for(int index = 0; index < 0x400 ; index++)
{
byte_t b3 = (index >> 5 & 0x1f);
byte_t bx = (index & 0x1f);
uint8_t b3 = (index >> 5 & 0x1f);
uint8_t bx = (index & 0x1f);
lookup_left_substraction[index] = bit_rotate_r(mod((bx+0x1f)-b3,0x1f),5);
}
}
@ -237,12 +240,12 @@ static void init_lookup_right_substraction()
for(int index = 0; index < 0x400 ; index++)
{
int b16 = (index >>5);
byte_t bx = (index & 0x1f);
uint8_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)
static inline void previous_left(uint8_t in, vector<cs_t> *candidate_states)
{
pcs state;
size_t size = candidate_states->size();
@ -250,7 +253,7 @@ static inline void previous_left(byte_t in, vector<cs_t> *candidate_states)
{
state = &((*candidate_states)[pos]);
byte_t bx = (byte_t)((state->l >> 30) & 0x1f);
uint8_t bx = (uint8_t)((state->l >> 30) & 0x1f);
unsigned b3 = (unsigned)(state->l >> 5) & 0x3e0;
state->l = (state->l << 5);
@ -267,7 +270,7 @@ static inline void previous_left(byte_t in, vector<cs_t> *candidate_states)
state->l ^= (((uint64_t)in & 0x1f) << 20);
}
} else {
byte_t b6 = lookup_left_substraction[b3|bx];
uint8_t b6 = lookup_left_substraction[b3|bx];
state->l = (state->l & 0x7ffffffe0ull) | b6;
state->l ^= (((uint64_t)in & 0x1f) << 20);
@ -282,7 +285,7 @@ static inline void previous_left(byte_t in, vector<cs_t> *candidate_states)
}
}
static inline void previous_right(byte_t in, vector<cs_t> *candidate_states)
static inline void previous_right(uint8_t in, vector<cs_t> *candidate_states)
{
pcs state;
size_t size = candidate_states->size();
@ -290,7 +293,7 @@ static inline void previous_right(byte_t in, vector<cs_t> *candidate_states)
{
state = &((*candidate_states)[pos]);
byte_t bx = (byte_t)((state->r >> 20) & 0x1f);
uint8_t bx = (uint8_t)((state->r >> 20) & 0x1f);
unsigned b16 = (unsigned)(state->r & 0x3e0);//(state->buffer_r >> 10) & 0x1f;
state->r = (state->r << 5);
@ -307,7 +310,7 @@ static inline void previous_right(byte_t in, vector<cs_t> *candidate_states)
state->r ^= (((uint64_t)in & 0xf8) << 12);
}
} else{
byte_t b18 = lookup_right_subtraction[b16|bx];
uint8_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);
@ -323,7 +326,7 @@ static inline void previous_right(byte_t in, vector<cs_t> *candidate_states)
}
}
static inline byte_t next_left_fast(byte_t in, uint64_t* left)
static inline uint8_t next_left_fast(uint8_t in, uint64_t* left)
{
if (in) *left ^= ((in & 0x1f) << 20);
lookup_entry* lookup = &(lookup_left[((*left) & 0xf801f)]);
@ -331,10 +334,10 @@ static inline byte_t next_left_fast(byte_t in, uint64_t* left)
return lookup->out;
}
static inline byte_t next_left_ksbyte(uint64_t* left)
static inline uint8_t next_left_ksbyte(uint64_t* left)
{
lookup_entry* lookup;
byte_t bt;
uint8_t bt;
*left = (((*left) >> 5)| ((uint64_t)left_addition[((*left) & 0xf801f)] << 30));
lookup = &(lookup_left[((*left) & 0xf801f)]);
@ -347,7 +350,7 @@ static inline byte_t next_left_ksbyte(uint64_t* left)
return bt;
}
static inline byte_t next_right_fast(byte_t in, uint64_t* right)
static inline uint8_t next_right_fast(uint8_t in, uint64_t* right)
{
if (in) *right ^= ((in&0xf8) << 12);
lookup_entry* lookup = &(lookup_right[((*right) & 0x7c1f)]);
@ -355,10 +358,10 @@ static inline byte_t next_right_fast(byte_t in, uint64_t* right)
return lookup->out;
}
static inline void sm_left_mask(const byte_t* ks, byte_t* mask, uint64_t rstate)
static inline void sm_left_mask(const uint8_t* ks, uint8_t* mask, uint64_t rstate)
{
size_t pos;
byte_t bt;
uint8_t bt;
for (pos=0; pos<16; pos++)
{
@ -375,14 +378,14 @@ static inline void sm_left_mask(const byte_t* ks, byte_t* mask, uint64_t rstate)
}
}
static inline uint32_t sm_right(const byte_t* ks, byte_t* mask, vector<uint64_t>* pcrstates)
static inline uint32_t sm_right(const uint8_t* ks, uint8_t* mask, vector<uint64_t>* pcrstates)
{
byte_t tmp_mask[16];
uint8_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;
uint8_t bt;
topbits = 0;
for (counter=0; counter<0x2000000; counter++)
@ -452,7 +455,7 @@ static inline uint32_t sm_right(const byte_t* ks, byte_t* mask, vector<uint64_t>
static inline void previous_all_input(vector<cs_t> *pcstates, uint32_t gc_byte_index, cipher_state_side css)
{
byte_t btGc,in;
uint8_t btGc,in;
vector<cs_t> ncstates;
vector<cs_t> prev_ncstates;
vector<cs_t>::iterator it,itnew;
@ -489,7 +492,7 @@ static inline void previous_all_input(vector<cs_t> *pcstates, uint32_t gc_byte_i
*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)
static inline void search_gc_candidates_right(const uint64_t rstate_before_gc, const uint64_t rstate_after_gc, const uint8_t* Q, vector<cs_t>* pcstates)
{
vector<cs_t>::iterator it;
vector<cs_t> csl_cand;
@ -556,14 +559,14 @@ static inline void search_gc_candidates_right(const uint64_t rstate_before_gc, c
}
}
static inline void sm_left(const byte_t* ks, byte_t* mask, vector<cs_t>* pcstates)
static inline void sm_left(const uint8_t* ks, uint8_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;
uint8_t correct_bits[16];
uint8_t bt;
cs_t state;
lookup_entry* lookup;
@ -645,7 +648,7 @@ static inline void sm_left(const byte_t* ks, byte_t* mask, vector<cs_t>* pcstate
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)
static inline void search_gc_candidates_left(const uint64_t lstate_before_gc, const uint8_t* Q, vector<cs_t>* pcstates)
{
vector<cs_t> csl_cand,csl_search;
vector<cs_t>::iterator itsearch,itcand;
@ -778,31 +781,31 @@ int main(int argc, const char* argv[])
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];
// uint8_t Gc[ 8] = {0x4f,0x79,0x4a,0x46,0x3f,0xf8,0x1d,0x81};
// uint8_t Gc[ 8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
// uint8_t Ci[ 8] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
// uint8_t Q[ 8] = {0x12,0x34,0x56,0x78,0x12,0x34,0x56,0x78};
uint8_t Gc[ 8];
uint8_t Ci[ 8];
uint8_t Q[ 8];
uint8_t Ch[ 8];
uint8_t Ci_1[ 8];
byte_t Gc_chk[ 8];
byte_t Ch_chk[ 8];
byte_t Ci_1_chk[ 8];
uint8_t Gc_chk[ 8];
uint8_t Ch_chk[ 8];
uint8_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};
// uint8_t ks[16] = {0xde,0x88,0xc2,0xc9,0xee,0xd4,0x1b,0x46,0x1c,0x6a,0x92,0x50,0x76,0x1a,0xe9,0x87};
// uint8_t mask[16] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
// uint8_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];
uint8_t ks[16];
uint8_t mask[16];
ui64 nCi; // Card random
ui64 nQ; // Reader random
ui64 nCh; // Reader challange
ui64 nCi_1; // Card anwser
uint64_t nCi; // Card random
uint64_t nQ; // Reader random
uint64_t nCh; // Reader challange
uint64_t nCi_1; // Card anwser
if ((argc != 2) && (argc != 5))
{
@ -818,7 +821,7 @@ int main(int argc, const char* argv[])
if (argc == 2)
{
// Generate random values for the key and randoms
srand((uint32_t)time(null));
srand((uint32_t)time(NULL));
for (pos = 0; pos<8; pos++)
{
Gc[pos] = rand();
@ -828,10 +831,10 @@ int main(int argc, const char* argv[])
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);
sscanf(argv[1],"%016" SCNx64,&nCi); num_to_bytes(nCi,8,Ci);
sscanf(argv[2],"%016" SCNx64,&nQ); num_to_bytes(nQ,8,Q);
sscanf(argv[3],"%016" SCNx64,&nCh); num_to_bytes(nCh,8,Ch);
sscanf(argv[4],"%016" SCNx64,&nCi_1); num_to_bytes(nCi_1,8,Ci_1);
printf(" Gc: unknown\n");
}
@ -883,7 +886,7 @@ int main(int argc, const char* argv[])
{
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);
printf("Using the state from the top-right bin: " _YELLOW_("0x%07" PRIx64)"\n",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());
@ -908,7 +911,7 @@ int main(int argc, const char* argv[])
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);
printf("\nFound valid key: " _GREEN_("%016" PRIx64)"\n\n",*itgc);
return 0;
}
}

View file

@ -20,12 +20,10 @@
*
* Modifed Iceman, 2020
*/
#include "defines.h"
#include "cryptolib.h"
#include "util.h"
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <inttypes.h>
#include <iostream>
#include <vector>
#include <map>
@ -34,9 +32,15 @@
#include <thread> // std::thread
#include <atomic>
#include <mutex>
#include "cryptolib.h"
#include "util.h"
using namespace std;
#ifdef _MSC_VER
// avoid scanf warnings in Visual Studio
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_DEPRECATE
#define inline __inline
#endif
@ -127,13 +131,13 @@ typedef struct {
nibble b1r;
nibble b1s;
bool invalid;
byte_t Gc[8];
uint8_t Gc[8];
}cs_t;
typedef cs_t* pcs;
typedef struct {
byte_t addition;
byte_t out;
uint8_t addition;
uint8_t out;
} lookup_entry;
enum cipher_state_side {
@ -147,21 +151,21 @@ void print_cs(const char* text,pcs s) {
printf("%s",text);
for(pos=6;pos>=0;pos--)
printf(" %02x",(byte_t)(s->l>>(pos*5))&0x1f);
printf(" %02x",(uint8_t)(s->l>>(pos*5))&0x1f);
printf(" |");
for(pos=6;pos>=0;pos--)
printf(" %02x",(byte_t)(s->m>>(pos*7))&0x7f);
printf(" %02x",(uint8_t)(s->m>>(pos*7))&0x7f);
printf(" |");
for(pos=4;pos>=0;pos--)
printf(" %02x",(byte_t)(s->r>>(pos*5))&0x1f);
printf(" %02x",(uint8_t)(s->r>>(pos*5))&0x1f);
printf("\n");
}
static inline byte_t mod(byte_t a, byte_t m) {
static inline uint8_t mod(uint8_t a, uint8_t m) {
// Just return the input when this is less or equal than the modular value
if (a<m) return a;
@ -173,13 +177,13 @@ static inline byte_t mod(byte_t a, byte_t m) {
}
/*
static inline byte_t bit_rotate_l(byte_t a, byte_t n_bits) {
static inline uint8_t bit_rotate_l(uint8_t a, uint8_t n_bits) {
// Rotate value a with the length of n_bits only 1 time
byte_t mask = (1 << n_bits) - 1;
uint8_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) {
static inline uint8_t bit_rotate_r(uint8_t a, uint8_t n_bits) {
return ((a >> 1) | ((a&1) << (n_bits - 1)));
}
*/
@ -189,14 +193,14 @@ static inline byte_t bit_rotate_r(byte_t a, byte_t n_bits) {
#define BIT_ROR(a) (((a) >> 1) | (((a) & 1) << 4))
static byte_t lookup_left_substraction[0x400];
static byte_t lookup_right_subtraction[0x400];
static uint8_t lookup_left_substraction[0x400];
static uint8_t lookup_right_subtraction[0x400];
static lookup_entry lookup_left[0x100000];
static lookup_entry lookup_right[0x8000];
static byte_t left_addition[0x100000];
static uint8_t left_addition[0x100000];
static inline void init_lookup_left() {
byte_t b3, b6, temp;
uint8_t b3, b6, temp;
int i, index;
for (i = 0; i <0x400; i++){
@ -215,7 +219,7 @@ static inline void init_lookup_left() {
}
static inline void init_lookup_right() {
byte_t b16, b18, temp;
uint8_t b16, b18, temp;
int i, index;
for(i = 0; i <0x400; i++) {
@ -231,8 +235,8 @@ static inline void init_lookup_right() {
static void init_lookup_left_substraction() {
for(int index = 0; index < 0x400 ; index++) {
byte_t b3 = (index >> 5 & 0x1f);
byte_t bx = (index & 0x1f);
uint8_t b3 = (index >> 5 & 0x1f);
uint8_t bx = (index & 0x1f);
//lookup_left_substraction[index] = bit_rotate_r(mod((bx+0x1f)-b3,0x1f),5);
lookup_left_substraction[index] = BIT_ROR( mod((bx + 0x1F) - b3, 0x1F));
@ -242,18 +246,18 @@ static void init_lookup_left_substraction() {
static void init_lookup_right_substraction() {
for(int index = 0; index < 0x400 ; index++) {
int b16 = (index >>5);
byte_t bx = (index & 0x1f);
uint8_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) {
static inline void previous_left(uint8_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);
uint8_t bx = (uint8_t)((state->l >> 30) & 0x1f);
unsigned b3 = (unsigned)(state->l >> 5) & 0x3e0;
state->l = (state->l << 5);
@ -268,7 +272,7 @@ static inline void previous_left(byte_t in, vector<cs_t> *candidate_states) {
state->l ^= (((uint64_t)in & 0x1f) << 20);
}
} else {
byte_t b6 = lookup_left_substraction[b3|bx];
uint8_t b6 = lookup_left_substraction[b3|bx];
state->l = (state->l & 0x7ffffffe0ull) | b6;
state->l ^= (((uint64_t)in & 0x1f) << 20);
@ -282,13 +286,13 @@ static inline void previous_left(byte_t in, vector<cs_t> *candidate_states) {
}
}
static inline void previous_right(byte_t in, vector<cs_t> *candidate_states) {
static inline void previous_right(uint8_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);
uint8_t bx = (uint8_t)((state->r >> 20) & 0x1f);
unsigned b16 = (unsigned)(state->r & 0x3e0);//(state->buffer_r >> 10) & 0x1f;
state->r = (state->r << 5);
@ -303,7 +307,7 @@ static inline void previous_right(byte_t in, vector<cs_t> *candidate_states) {
state->r ^= (((uint64_t)in & 0xf8) << 12);
}
} else {
byte_t b18 = lookup_right_subtraction[b16|bx];
uint8_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);
@ -318,7 +322,7 @@ static inline void previous_right(byte_t in, vector<cs_t> *candidate_states) {
}
}
static inline byte_t next_left_fast(byte_t in, uint64_t* left) {
static inline uint8_t next_left_fast(uint8_t in, uint64_t* left) {
if (in)
*left ^= ((in & 0x1f) << 20);
@ -327,9 +331,9 @@ static inline byte_t next_left_fast(byte_t in, uint64_t* left) {
return lookup->out;
}
static inline byte_t next_left_ksbyte(uint64_t* left) {
static inline uint8_t next_left_ksbyte(uint64_t* left) {
lookup_entry* lookup;
byte_t bt;
uint8_t bt;
*left = (((*left) >> 5)| ((uint64_t)left_addition[((*left) & 0xf801f)] << 30));
lookup = &(lookup_left[((*left) & 0xf801f)]);
@ -342,17 +346,17 @@ static inline byte_t next_left_ksbyte(uint64_t* left) {
return bt;
}
static inline byte_t next_right_fast(byte_t in, uint64_t* right) {
static inline uint8_t next_right_fast(uint8_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) {
static inline void sm_left_mask(const uint8_t* ks, uint8_t* mask, uint64_t rstate) {
for (uint8_t pos = 0; pos < 16; pos++) {
next_right_fast(0,&rstate);
byte_t bt = next_right_fast(0,&rstate) << 4;
uint8_t bt = next_right_fast(0,&rstate) << 4;
next_right_fast(0,&rstate);
bt |= next_right_fast(0,&rstate);
@ -375,13 +379,13 @@ uint32_t g_num_cpus = std::thread::hardware_concurrency();
static void ice_sm_right_thread(
uint8_t offset,
uint8_t skips,
const byte_t* ks,
const uint8_t* ks,
map<uint64_t,uint64_t>* bincstates,
byte_t* mask
uint8_t* mask
) {
byte_t tmp_mask[16];
byte_t bt;
uint8_t tmp_mask[16];
uint8_t bt;
for (uint64_t counter = offset; counter < 0x2000000; counter += skips) {
// Reset the current bitcount of correct bits
@ -444,7 +448,7 @@ static void ice_sm_right_thread(
}
}
}
static uint32_t ice_sm_right(const byte_t* ks, byte_t* mask, vector<uint64_t>* pcrstates) {
static uint32_t ice_sm_right(const uint8_t* ks, uint8_t* mask, vector<uint64_t>* pcrstates) {
uint32_t g_num_cpus = std::thread::hardware_concurrency();
map<uint64_t,uint64_t> bincstates;
@ -478,14 +482,14 @@ static uint32_t ice_sm_right(const byte_t* ks, byte_t* mask, vector<uint64_t>* p
static void ice_sm_left_thread(
uint8_t offset,
uint8_t skips,
const byte_t* ks,
const uint8_t* ks,
map<uint64_t, cs_t>* bincstates,
byte_t* mask
uint8_t* mask
) {
size_t pos, bits;
byte_t correct_bits[16];
byte_t bt;
uint8_t correct_bits[16];
uint8_t bt;
lookup_entry* lookup;
// Reset and initialize the cryptostate and vector
@ -561,7 +565,7 @@ static void ice_sm_left_thread(
}
}
static void ice_sm_left(const byte_t* ks, byte_t* mask, vector<cs_t>* pcstates) {
static void ice_sm_left(const uint8_t* ks, uint8_t* mask, vector<cs_t>* pcstates) {
uint32_t g_num_cpus = std::thread::hardware_concurrency();
@ -589,12 +593,12 @@ static void ice_sm_left(const byte_t* ks, byte_t* mask, vector<cs_t>* pcstates)
reverse(pcstates->begin(), pcstates->end());
}
static inline uint32_t sm_right(const byte_t* ks, byte_t* mask, vector<uint64_t>* pcrstates) {
byte_t tmp_mask[16];
static inline uint32_t sm_right(const uint8_t* ks, uint8_t* mask, vector<uint64_t>* pcrstates) {
uint8_t tmp_mask[16];
size_t pos, bits, bit, topbits;
map<uint64_t,uint64_t> bincstates;
map<uint64_t,uint64_t>::iterator it;
byte_t bt;
uint8_t bt;
topbits = 0;
@ -658,7 +662,7 @@ static inline uint32_t sm_right(const byte_t* ks, byte_t* mask, vector<uint64_t>
}
static inline void previous_all_input(vector<cs_t> *pcstates, uint32_t gc_byte_index, cipher_state_side css) {
byte_t btGc,in;
uint8_t btGc,in;
vector<cs_t> ncstates;
vector<cs_t> prev_ncstates;
vector<cs_t>::iterator it,itnew;
@ -691,7 +695,7 @@ static inline void previous_all_input(vector<cs_t> *pcstates, uint32_t gc_byte_i
*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) {
static inline void search_gc_candidates_right(const uint64_t rstate_before_gc, const uint64_t rstate_after_gc, const uint8_t* Q, vector<cs_t>* pcstates) {
vector<cs_t>::iterator it;
vector<cs_t> csl_cand;
map<uint64_t,uint64_t> matchbox;
@ -743,13 +747,13 @@ static inline void search_gc_candidates_right(const uint64_t rstate_before_gc, c
}
}
static inline void sm_left(const byte_t* ks, byte_t* mask, vector<cs_t>* pcstates) {
static inline void sm_left(const uint8_t* ks, uint8_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;
byte_t correct_bits[16];
byte_t bt;
uint8_t correct_bits[16];
uint8_t bt;
cs_t state;
lookup_entry* lookup;
@ -831,7 +835,7 @@ static inline void sm_left(const byte_t* ks, byte_t* mask, vector<cs_t>* pcstate
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) {
static inline void search_gc_candidates_left(const uint64_t lstate_before_gc, const uint8_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;
@ -937,14 +941,14 @@ static void ice_compare(
uint8_t skips,
vector<uint64_t>* candidates,
crypto_state_t* ostate,
byte_t *Ci,
byte_t *Q,
byte_t *Ch,
byte_t *Ci_1
uint8_t *Ci,
uint8_t *Q,
uint8_t *Ch,
uint8_t *Ci_1
) {
byte_t Gc_chk[8];
byte_t Ch_chk[ 8];
byte_t Ci_1_chk[ 8];
uint8_t Gc_chk[8];
uint8_t Ch_chk[ 8];
uint8_t Ci_1_chk[ 8];
for (std::size_t i = offset; i < candidates->size(); i += skips) {
if (key_found.load(std::memory_order_relaxed))
@ -976,27 +980,27 @@ int main(int argc, const char* argv[]) {
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];
// uint8_t Gc[ 8] = {0x4f,0x79,0x4a,0x46,0x3f,0xf8,0x1d,0x81};
// uint8_t Gc[ 8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
// uint8_t Ci[ 8] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
// uint8_t Q[ 8] = {0x12,0x34,0x56,0x78,0x12,0x34,0x56,0x78};
uint8_t Gc[ 8];
uint8_t Ci[ 8];
uint8_t Q[ 8];
uint8_t Ch[ 8];
uint8_t Ci_1[ 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};
// uint8_t ks[16] = {0xde,0x88,0xc2,0xc9,0xee,0xd4,0x1b,0x46,0x1c,0x6a,0x92,0x50,0x76,0x1a,0xe9,0x87};
// uint8_t mask[16] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
// uint8_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];
uint8_t ks[16];
uint8_t mask[16];
ui64 nCi; // Card random
ui64 nQ; // Reader random
ui64 nCh; // Reader challange
ui64 nCi_1; // Card anwser
uint64_t nCi; // Card random
uint64_t nQ; // Reader random
uint64_t nCh; // Reader challange
uint64_t nCi_1; // Card anwser
if ((argc != 2) && (argc != 5)) {
printf("SecureMemory recovery - (c) Radboud University Nijmegen\n\n");
@ -1010,7 +1014,7 @@ int main(int argc, const char* argv[]) {
// Check if this is a simulation
if (argc == 2) {
// Generate random values for the key and randoms
srand((uint32_t)time(null));
srand((uint32_t)time(NULL));
for (pos = 0; pos<8; pos++) {
Gc[pos] = rand();
Ci[pos] = rand();
@ -1019,10 +1023,10 @@ int main(int argc, const char* argv[]) {
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);
sscanf(argv[1],"%016" SCNx64,&nCi); num_to_bytes(nCi,8,Ci);
sscanf(argv[2],"%016" SCNx64,&nQ); num_to_bytes(nQ,8,Q);
sscanf(argv[3],"%016" SCNx64,&nCh); num_to_bytes(nCh,8,Ch);
sscanf(argv[4],"%016" SCNx64,&nCi_1); num_to_bytes(nCi_1,8,Ci_1);
printf(" Gc: unknown\n");
}
@ -1080,7 +1084,7 @@ int main(int argc, const char* argv[]) {
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);
printf("Using the state from the top-right bin: " _YELLOW_("0x%07" PRIx64)"\n", 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());

View file

@ -1,20 +1,20 @@
#include "util.h"
#include <stdio.h>
#include "util.h"
void num_to_bytes(uint64_t n, size_t len, byte_t* dst)
void num_to_bytes(uint64_t n, size_t len, uint8_t *dst)
{
while (len--)
{
dst[len] = (byte_t)n;
while (len--) {
dst[len] = (uint8_t)n;
n >>= 8;
}
}
void print_bytes(const byte_t* pbtData, const size_t szLen) {
void print_bytes(const uint8_t *pbtData, const size_t szLen)
{
size_t uiPos;
for (uiPos=0; uiPos < szLen; uiPos++) {
printf("%02x ",pbtData[uiPos]);
if (uiPos>20){
for (uiPos = 0; uiPos < szLen; uiPos++) {
printf("%02x ", pbtData[uiPos]);
if (uiPos > 20) {
printf("...");
break;
}

View file

@ -1,9 +1,9 @@
/*
*
*
* Various Utilities
*
* Copyright (C) 2010, Flavio D. Garcia, Peter van Rossum, Roel Verdult
* and Ronny Wichers Schreur. Radboud University Nijmegen
* 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
@ -17,15 +17,17 @@
*
* 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"
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#define AEND "\x1b[0m"
@ -37,7 +39,10 @@
#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);
void num_to_bytes(uint64_t n, size_t len, uint8_t *dst);
void print_bytes(const uint8_t *pbtData, const size_t szLen);
#ifdef __cplusplus
}
#endif
#endif // _UTIL_H_