用于侧信道攻击的C定时内存访问

时间:2014-05-20 22:50:04

标签: c pointers caching cryptography

我参加了加密课程,我必须做一个关于旁道攻击的演讲。因此,我试图自己实施一个。

我特意尝试关注this paper。但是,我在这种低级编程方面遇到了一些问题。

我写了一个简短的C程序来计算对变量的访问时间,以便找出它是否被访问过(尽管在这种情况下我是访问它的人,所以我知道前面的答案)。然后重点是将其概括为知道某个其他进程何时达到某个特定状态。

基本上,它运行10k次迭代,并且在每次迭代中以概率1/10,访问指针。在每次迭代中,注册处理器访问指针所花费的时间,然后将指针从缓存中刷新。这些值将打印到文件中。

这是我写的代码(汇编部分实际上来自我引用的论文):

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>

int probe(char *adrs) {
    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" (adrs)
            : "%esi", "%edx");
    return time;
}

void myfunc(void* buffer[]) {
    int nptrs;

    nptrs = backtrace(buffer, 10);
}

int main(int argc, char** argv) {
    srand(time(NULL));

    int r = rand(), i;
    struct timespec tim, tim2;
    tim.tv_sec = 0;
    tim.tv_nsec = 5000L;
    void* buffer[10];
    char letter = 'c';
    char* p = &letter;

    FILE *f = fopen("output.txt","w");
    if(f == NULL) printf("Error opening file!\n");

    myfunc(buffer);
    for(i=0; i < 10000; i++) {
        r = rand();
        nanosleep(&tim,&tim2);
        if(r%10 == 3) { // 3 is completely arbitrary; could be any value really
            myfunc(buffer);
            printf("%c ",letter);
        }
        fprintf(f,"%d,%d,%d\n", r%10 == 3, probe(buffer[0]),probe(p)); // print the timings to file, and whether the variable was accessed or not
    }

    return 0;
}

现在我的问题是:这应该写入文件&#34; 1,x,y&#34;如果r%10 == 3,则小x和y,以及&#34; 0,x,y&#34;否则,大x和y。我试过在运行Debian(32位和64位)的两个不同的VM中运行它,用gcc 4.7.2编译(只使用标志是-g),我得到的结果不同,没有一个是什么我想要。

在32位VM中,&#34;探针(缓冲区[0])&#34;似乎有点工作,虽然并非总是如此。但是&#34;探针(p)&#34;总是返回低值(这绝对没有信息)。以下是输出的相关部分(可用的完整输出here):

0,250,48
1,33,54
0,74,33
1,36,33
0,61,33
0,92,33
0,48,62
0,405,33

在64位VM中,两个值几乎总是高于4000,与被访问的指针无关。另一个相关细分(和完整输出here):

1,4341,4371
0,4320,4341
0,4495,4320

所以我的问题是:

  • 在32位VM中,为什么char *总是很快访问? (无效*与char *不同?还是其他原因)
  • 为什么VM有不同的结果?
  • 在64位VM中,为什么两个值都在4000左右?

1 个答案:

答案 0 :(得分:0)

这是一个非常有趣的问题。

char *和void *之间应该没有区别,唯一的区别在于指针算术。但是我认为从32位到64位的时间差异是由于架构的变化。 64位访问内存通常比32位慢,但由于有更多的寄存器,它们通常不必访问内存。 Here's a link to info on 64-bit architecture, and the difference from 32-bit.