2014-05-20 1 views
1

나는 암호 과정을 사용하고 있으며 사이드 채널 공격에 대한 프레젠테이션을해야합니다. 따라서, 나는 나 자신을 구현하려고 노력하고있다.사이드 채널 공격을위한 C 타이밍 메모리 액세스

나는 특별히 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; 
} 

그리고 지금 내 문제 : 다음

내가 쓴 코드 (어셈블리 부분은 내가 인용 한 논문에서 실제로) 인이이 파일에 기록하도록되어 "1, X, Y" r % 10 == 3이면 작은 x와 y, 그렇지 않으면 큰 x와 y를 갖는 "0, x, y"가됩니다. 나는 데비안 (32 비트 및 64 비트)을 실행하는 두 개의 다른 VM에서 gcc 4.7.2 (사용 된 플래그 만 -g)를 컴파일하여 실행하려고 시도했으며, 다른 결과를 얻었습니다. 원하는 결과가 없습니다. .

"프로브 (버퍼 [0])"는 항상 그런 것은 아니지만 일종의 작업으로 보입니다. 그러나 "probe (p)"는 항상 낮은 값을 반환합니다 (절대적으로 아무 정보도 제공하지 않습니다). 여기에서 중요한 출력 (최대 출력 가능한 here)의 세그먼트 : 64 비트 VM에서

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

이 두 값들은 독립적으로 액세스 포인터의 여부되고, 거의 항상 상기 4000이다. 또 다른 관련 세그먼트 (전체 출력 here) :

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

그래서 내 질문은 : 32 비트

  • 는 VM 왜 문자 * 항상 매우 빠르게 액세스 할 수 있습니까? (void * char *와 다른가요? 아니면 다른 이유가 있습니까?)
  • VM의 결과가 다른 이유는 무엇입니까?
  • 의 64 비트 VM에서 4000이라는 값은 왜 둘 다입니까?
+0

누군가는 펜싱을 정말 좋아합니다! –

+0

당신이 의미하는 것을 이해하는 데 시간을 좀 할애했는데, 나는 당신이 스포츠를 의미한다고 생각했습니다. :) 예, 저자의 말에 따르면 명령의 순서대로 실행되도록하는 것이 목적입니다. 나는 정말로 asm을 배웠다. 그러나 설명은 이해가가는 것처럼 보인다. :) – user2270119

+0

음 ...메모리 주문은 * 매우 * 미묘한 주제이며 아키텍처 설명서를 훑어 보면서 각 명령어가 무엇인지에 대한 아이디어를 얻을 것을 강력하게 권장합니다. 나는 울타리의 절반이 정확히 제로 효과가 있다고 생각하지만, 그것을 보장 할 수는 없다. –

답변

0

이것은 매우 흥미로운 질문입니다.

char *와 void * 사이에 차이가 없어야합니다. 유일한 차이점은 포인터 산술입니다. 그러나 32 비트에서 64 비트로의 시간 차이는 아키텍처 변경으로 인한 것입니다. 일반적으로 64 비트는 32 비트보다 메모리에 액세스 할 때 속도가 느리지 만 더 많은 레지스터가 있기 때문에 일반적으로 메모리에 액세스 할 필요가 없습니다. Here's a link to info on 64-bit architecture, and the difference from 32-bit.