ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • SecOC (Secure On-board Communication)
    application 2025. 2. 9. 12:18

    시작하기 전에 

    SecOC에 관한 글을 작성한다. 아래 내용들을 포함한다.

    • SecOC가 무엇인가?
    • 왜 CRC는 사용하지 않는가?
    • SecOC 구현

     

     

    SecOC는 무엇인가?

    • SecOC는 Secure On-board Communication을 줄임말이다.
      • On-board는 "차량 내"라는 의미이다. "차량 내 통신 보안" 정도로 해석할 수 있다.
      • AUTOSAR에서 발표한 통신 보안을 위한 사양이다.
    • 다양한 통신 프로토콜에 적용 가능하다고 한다. 나는 CAN(CAN-FD를 포함하여)으로 설명한다.
    •  아래는 SecOC의 작동 방식을 설명하는 그림이다.

    AUTOSAR SecOC 작동 방식

    • 통신이니까 센더와 리시버가 있다.
    • 센더와 리시버는 "동일"한 "비밀키"를 나눠갖고 있다
      • 센더와 리시버가 키를 어떻게 "비밀"로 나눠갖는 지는 별도의 (복잡한) 문제이다. 여기서 다루지 않겠다. 
    • 센더는 보낼 데이터가 있다. 그림에서 Authentic I-PDU이다. 무슨(?) Data Unit의 줄임말이다. 전송 단위라는 의미이다. (PDU)

     

    FV (Freshness Value)

    • 위 그림에 Freshness Value라는 것이 있다. 흔히 FV라고 줄여서 부른다. 전송할 때마다 바뀌는 값이다. 대략 두가지 용도가 있다.
      • 데이터를 전송하다 보면 동일한 데이터를 반복해서 전송하는 경우가 있다. FV를 PDU에 포함하여 매번 동일한 데이터를 전송하는 것을 방지한다. 
      • 일반적으로 FV를 순차적으로 증가하도록 한다. 1, 2, 3 ... 이렇게. 만일 1 다음에 2가 아닌 다른 값을 수신하였다면 수신 제어기는 전송에 혹은 송신 제어기에 문제가 있음을 감지할 수 있다. 이런 문제가 반복되면 통신 이상을 판정한다.
      • FV 값은 차의 전원을 켜면 끌 때까지 같은 값을 다시 사용하지 않다도 될 정도로 큰 자리 수의 값을 사용하면 좋다고 한다. 10msec 마다 전송하는 메시지라면, 100 시간 동안 연속해서 전원을 켜 둔다면 36,000,000 (= 1 FV/10  ms * 1000 ms / s * 100 FV/s * 60 s/m * 60 m/h * 100 h)개의 서로 다른 FV가 필요하다.  Hex로 0x02 25 51 00이다. 4 바이트로 표시할 수 있다. 4 바이트로 표시할 수 있는 가장 큰 십진수는 4,294,967,295이다.  주기가 10msec인 메시지는 11,930시간 동안 서로 다른 FV를 사용할 수 있다. 497 시간이다. 498일간 연속으로 전원을 켜두는 일은 드물 것이다. FV는 4 바이트(uint32: unsigned integrer 32-bit)면 충분히 길다고 생각한다. 아래에서 추가로 논한다.

     

    MAC 

    • 위 그림에 MAC 이라는 부분을 설명한다. (그림에 MAC보다 Hash라고 했으면 더 설명이 쉬웠을 텐데 ...)
    • MAC은 Message Authentication Code를 줄인말이다.
    • 비밀키, 데이터, FV를 이용해서 MAC이라는 것을 계산한다. 
      • Hash 함수라는 것이 있다. (cluade.ai에게 Hash를 처음 접하는 사람에게 설명해달라고 했다.)
    더보기
    • "해시 값은 마치 지문과 같습니다. 사람마다 고유한 지문이 있는 것처럼, 어떤 데이터든 그 데이터만의 고유한 '디지털 지문'을 만들 수 있습니다. 

      예를 들어:
      - 여러분이 '안녕하세요'라는 메시지를 보낸다면, 이 메시지는 특정한 해시 값(예: 'X7Y2Z9')을 가집니다.
      - 만약 누군가가 메시지를 '안녕하세요!'로 살짝만 바꿔도, 해시 값은 완전히 다른 값(예: 'A1B4C7')으로 변합니다.

      즉, 해시는 어떤 데이터를 '고유한 식별 코드'로 바꾸는 것이라고 생각하면 됩니다. 이 식별 코드는:
      1. 원본 데이터가 조금이라도 변경되면 완전히 달라집니다
      2. 원본 데이터의 크기와 상관없이 항상 일정한 길이를 가집니다
      3. 같은 데이터는 항상 같은 해시 값을 만듭니다"
    • 센더는 비밀키, 데이터, FV를 이용해서 Hash 값을 계산한다.
    • 센더는 데이터와 Hash를 전송한다. (정확히는 Hash의 일부를 전송한다. 나중에 설명한다.) 
    • 리시버는메시지에 포함된 Hash와 스스로 계산한 Hash가 다르면, Hash의 세가지 특징 덕택에, 아래 중에 한 가지 상황이라는 것을 감지할 수 있다.
      • 키가 맞지 않다. 즉, 권한이 없는 제어기로 부터 전송된 메시지다. 
      • 전송 과정 중에 오류가 있었다.
      • 송신 제어기에 오류가 있다.
    • 자주 사용되는 Hash 함수들 중에 CMAC이라는 함수가 있다. CMAC은 128 비트 (16 바이트)의 해쉬값을 출력한다. CAN 메시지에 FV 4 바이트와 CMAC 16 바이트 CMAC을 넣는다고 생각해보자. 둘이 20 바이트를 차지한다. CAN 메시지의 길이는 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64 바이트가 가능하다. 메시지 길이가 24 바이트 이상이어야 데이터를 전송할 수 있다. (8 바이트가 최대 메시지 길이인 CAN은 SecOC를 할 수 없다?)  CMAC의 보안성이 충분하지 않다고 하여 256 비트 (32 바이트)의 HMAC 해쉬값을 사용하는 경우도 있다. 이 경우 메시지 길이가 48 바이트 이상이어야 데이터를 전송할 수 있다. 한 메시지에 데이터 바이트 보다 SecOC 바이트가 더 많다. 비효율적이다. 그래서 Truncation을 한다.
    • 예를 들어 FV의 가장 낮은 자리(아래)에서 1 바이트와 CMAC(일반적으로 가장 위)에서 1바이트만 전송한다면 어떨까? (잘라 낸 FV와 CMAC을 각각 FV_trunc, CMAC_truc라고 하겠다.) 리시버는 FV_trunc를 보고 FV 계산이 맞는 지를 "어느 정도" 확신을 갖고 알 수 있다. CMAC도 그렇다. 즉, FV_trunc는 여전히 FV의 구실을 CMAC_trunc는 CMAC 구실을 할 수 있다.
    •  FV_trunc의 길이는 몇 비트가 적당한가? CMAC_trunc의 길이는 어떤가? 먼저 CMAC 부터 생각해본다.

     

    Truncation

    • 위 그림의 Truncation 부분에 관한 설명이다.
    • claude.ai에게 CMAC의 길이에 관해 문의하니 아래와 같이 답을 한다.
    더보기

    NIST SP 800-38B에서는 다음과 같은 길이를 권장합니다:

    • 최소 64비트 이상 사용할 것을 권장
    • 보안 요구사항에 따라 32비트, 64비트, 96비트, 128비트 등으로 잘라서 사용 가능

    가장 일반적으로는 128비트 전체를 사용하거나 96비트로 잘라서 사용합니다.

    • 내 직감으로 64 비트도 과하고 16 비트면 될 것 같다. 이유는 아래와 같다.
      • CMAC이 1 비트인 경우를 가정한다. 가능한 CMAC 값들은 0 혹은 1뿐이다. 우연히 맞출 가능성은 1/2이다. 2 비트라면 1/4. n 비트라면 1/2^n이다. NIST(National Institute of Standards and Technology )는 우연히 맞출 확률을 충분히 낮게 하려고 최소 64 비트(8 바이트) 이상을 권장하는 것이라 생각한다. 1/2^64 = 5.4e-20 이다.   
      • 전송 주기가 10msec인 메시지가 있다고 가정하자. 이 메시지는 제동 제어기가 엔진 제어기에 토크 요청을 하는데 사용된다고 하자. 엔진 제어기는 CMAC_trunc가 맞지 않으면 요청을 무시한다. 누군가 1 바이트 CMAC_trunc를 그냥 찍었을 때 맞출 확률은 1/256이다. 우연히 맞았다고 가정하자. 하지만 엔진 토크는 10msec 동안 운전자가 감지할 만큼  증가/감소하지 못한다. 관성 때문이 있다. 엔진 토크는 관성이 큰 부류에 속한다. 실제 사람이 감지할 만큼의 엔진 토크 변화가 만들어지려면 얼마의 시간이 필요할까? 100msec라고 가정하자. (내 차는 확실히 이것보다 더 길다.) 메시지 10회 전송 시간이다. 10번 연속 CMAC_trunc를 찍어서 맞춰야 한다면 그 확률은 1/256^10 = 8.3e-25이다.
      • 전송 주기가 100msec인 메시지가 있다고 가정하자. 이 메시지는 제동 제어기가 클러스터에 경고등 on/off를 요청하는데 사용된다고 하자. 클러스터는 CMAC_trunc가 맞지 않으면 요청을 무시한다. 램프는 100msec만 켜졌다가 꺼져도 사람 눈에 보일 수 있다. (램프는 관성이 매우 작은 부류에 속한다.) 그렇다면 램프는 CMAC_trunc를 1 바이트 보다 더 크게 해야한다. 4 바이트로 한다면 확률은 1/2^32 = 2.3e-10이다. 나는 충분히 낮은 가능성이라고 생각한다. 만일 클러스터가 2회째 요청부터 경고등을 켠다고 하면 (100msec의 추가 지연 시간이 있다.) 확률은 5.4e-20이 된다. (NIST의 64 비트 권장을 만족한다.) (경고등 지연 시간이 문제가 된다면 전송 주기를 50msec인 반으로 줄이면 어떤가? 이미 CAN 버스에 메시지들이 많다면 버스 로드 문제가 생길 수도 있다. 이래서 네트워크 설계는 복잡하다.)
    • FV_trunc는 어떤가? FV 본연의 역할을 생각하면 1 비트도 충분하다. 0 -> 1 -> 0으로 송신 때마다 바뀐다. 하지만 CMAC 계산에 FV가 들어간다는 것을 고려하면 FV는 길고(위에 설명했던 것보다 1~2 바이트 더 길면 더 좋을 것이다. 연산량의 증가가 조금 있겠지만 보안 측면에서 득이 연산량 증가의 실보다 클 것 같다.) FV_trunc는 짧은 것이 보안성에 유리할 것이다. FV의 더 많은 부분이 숨겨질 수 있으니까. CMAC에 FV가 포함되어 메시지에 FV_trunc가 없어도 괜찮지만 나는 다음의 이유로 FV_trunc가 메시지에 포함된다고 이해한다.
    • 아래 그림의 왼쪽은 메시지에 FV_trunc와 CMAC_trunc가 모두 있는 경우이고, 오른쪽은 CMAC_trunc만 있는 경우이다. CMAC 계산에는 연산 리소스가 많이 필요하다. 어느 경우이건 FV 계산은 필요하다. (FV를 적용한다면 말이다. FV를 적용하지 않을 수도 있다. 높은 기능 안전을 갖고 있는 시스템의 경우 FV가 필요하다.) FV_trunc에서 이상을 발견하는 경우 CMAC 계산을 피할 수 있다.  

    메시지에 FV_trunc가 있는 경우, 수신한 FV_trunc와 계산한 FV_trunc가 다르면 CMAC 계산을 하지 않아도 된다.

    • 내 직감으로 FV_trunc로 1 바이트가 적당하다고 생각한다. 필요하면 4 비트로 줄여도 괜찮다고 생각한다. 
    • 센더는 데이터, FV_trunc, CMAC_trunc를 메시지에 담아 전송한다.
    • 리시버는 메지지에서 FV_trunc를 추출한다. 리시버는 스스로 FV를 추적하고 있어야 한다. 수신한 FV_trunc와 스스로 계산한 FV_trunc가 다르면 리시버는 메시지를 버린다.
    • 수신한 FV_trunc와 계산한 FV가 같다면 리시버는 비밀키, 데이터, FV(FV_trunc가 아니다.)를 이용하여 CMAC을 계산한다. 수신한 CMAC_trunc와 계산한 CMAC_trunc가 다르면 리시버는 메시지를 버린다. 같다면 메시지를 사용한다.

     

    왜 CRC를 사용하지 않는가?

    • CRC는 데이터에 손상이 없다는 것을 확인하기 위한 용도로 좋다. 즉, 기능 안전의 목적에 합당하다. 하지만 어렵지 않게 리버스 엔지니어링 할 수 있다. 보안 목적에 합당하지 않다. CRC 리버스 엔지니어링하기 :: hsl's tsmaster 사용기 
    • CRC로는 센더가 자격을 갖췄는지 확인할 수 없다. 
    • 위 두가지 이유로 보안이 필요한 통신에는 CRC 대신 "비밀키를 포함"한 MAC이 적용된 SecOC를 한다.

     

     

    SecOC 구현

    • SecOC 구현 :: hsl's tsmaster 사용기
      • AUTOSAR SecOC 스펙을 온전히 구현하지 않았다. MAC의 작용을 설명하는 목적이다.
    • 아래 비디오 프로그램 작동 화면이다. 다음의 사건들이 일어난다.
    • 센더는 1s 주기로 ECU_1 (0x101) 메시지를 전송한다.
    • 리시버는 스스로 계산한 FV_trunc_calc와 메시지의 FV_trunc를 비교한다. 문제가 없으면 CMAC_trunc를 비교한다. 둘 다 문제가 없으면 리시버는 화면에 ok를 출력한다.
    • 센더에서 ctrl+5를 입력하여 FV를 재설정한다. 센더는 화면에 reset fv를 리시버는 fv updated를 출력한다.

    • 센더의 CAN / CAN FD Transmit 창에서 play 버튼을 클릭하여 미리 준비한 메시지를 전송한다. 미리 준비한 메시지의 FV_trunc는 0x0A이다. 10이다. 
    • 리시버가 추적 중인 FV에서 추출한  FV_trunc_calc와 메시지의 FV_trunc가 다르면 리시버는 화면에 fv error 표시한다. fv error가 발생하면 CMAC 계산을 하지 않는다.

    리시버가 계산한 FV_trunc_calc는 9인데 센더가 보낸 FV_trunc는 10이다. fv error가 발생한다. cmac 검사를 하지 않는다.

    • FV_trunc_calc와 FV_trunc가 동일한 경우 CMAC 계산을 한다. CMAC_trunc_calc와 CMAC_trunc가 다르면 리시버는 화면에 cmac error를 표시한다. cmac error가 발생하면 메시지를 처리하지 않는다.

    리시버가 계산한 FV_trunc_calc와 FV_trunc가 모두 10으로 동일하다. cmac 검사를 한다. CMAC_trunc_calc와 CMAC_trunc가 다르다. cmac error가 발생한다. 메시지를 버린다.

    20250211 SecOC

     

     

     

    결론

    • SecOC를 전반적으로 설명하였다. 
    • CRC는 기능 안전 측면에서 데이터 전송의 결함 유무를 확인하는데 적합하나 리버스 엔지니어링에 취약하다. 사이버 보안 측면에서 충분하지 않다. 센더를 확인할 수 없기 때문이다.
    • SecOC는 MAC (Message Authentication Code)을 이용한다. MAC 계산에는 센더와 리시버가 공유한 비밀(키)을 이용한다. 이 비밀을 이용하여 리시버는 센더를 신뢰할지 말지를 결정할 수 있다.   
    • MAC은 FV (Freshness Value)와 Hash 값으로 구성된다.
      • 예제에서는 Hash를 구하는 함수로 CMAC을 사용했다.
      • FV로 큰 값을 사용하는 경우, 제한된 CAN 메시지의 데이터 공간이 부족하다. FV의 일부인 FV_trunc를 MAC에 포함한다. FV_trunc의 MAC 포함은 선택이다. 
      • CMAC으로 큰 값을 사용할 경우, 제한된 CAN 메시지의 데이터 공간이 부족하다. CMAC의 일부인 CMAC_trunc를 MAC에 포함한다. CMAC_trunc의 MAC 포함은 필수이다.
    • MAC을 이용하면 비밀을 공유하지 않은 센더로 부터 전송된 메시지를 차단할 수 있다.

     

     

    목차 :: hsl's tsmaster 사용기