【问题标题】:C timing memory access for side-channel attacks用于侧信道攻击的 C 定时内存访问
【发布时间】:2014-05-20 22:50:03
【问题描述】:

我正在学习密码学课程,我必须做一个关于侧信道攻击的演讲。因此,我正在尝试自己实现一个。

我特别想关注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;
}

现在我的问题:如果 r % 10 == 3,这应该写入文件“1,x,y”,x 和 y 小,否则,“0,x,y”,x 和 y 大.我尝试在运行 Debian(32 位和 64 位)的两个不同 VM 中运行它,两者均使用 gcc 4.7.2(仅使用的标志是 -g)编译,但我得到了不同的结果,这些都不是我想要的.

在 32 位 VM 中,“probe(buffer[0])”似乎有点工作,但并非总是如此。但是“probe(p)”总是返回低值(这绝对没有给我任何信息)。这是输出的相关部分(完整输出可用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* 访问总是非常快? (void* 和 char* 有区别吗?还是其他原因)
  • 为什么虚拟机有不同的结果?
  • 在 64 位 VM 中,为什么两个值都在 4000 左右?

【问题讨论】:

  • 有人真的很喜欢击剑!
  • 我花了一些时间才明白你的意思,我以为你的意思是这项运动:)。是的,根据作者的说法,他们的目的是确保指令按顺序执行。我从来没有真正学过asm,但解释似乎很有意义。 :)
  • 嗯...内存排序是一个非常微妙的话题,我强烈建议您至少浏览一下架构手册并了解每条指令的用途。我认为一半的栅栏的效果完全为零,但我不能保证。

标签: c pointers caching cryptography


【解决方案1】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-03-08
    • 2018-09-25
    • 1970-01-01
    • 2021-12-04
    • 1970-01-01
    • 2018-01-11
    • 2017-07-01
    • 1970-01-01
    相关资源
    最近更新 更多