에 대한 실용적인 IoT 암호화 Espressif ESP8266 칩셋은 3 달러의 ‘인터넷의 인터넷’개발 보드가 경제적 현실을 만듭니다. 인기있는 자동 펌웨어 구축 사이트 NodeMCU 빌드에 따르면 지난 60 일 동안 해당 플랫폼에 대해서는 13,341 개의 사용자 정의 펌웨어가 빌드되었습니다. 이 중 19 % 만 SSL 지원이 있으며 10 %는 암호화 모듈을 포함합니다.
우리는 IoT 부문의 보안이 부족하고 자주 봇넷 및 기타 공격을 다루는 데 자주 중요하지만 우리가 요구하는 동일한 기준에 프로젝트를 개최 할 것입니다. 우리는 문제를 식별 할 때 멈추거나 해결책의 일부가 될 수 있습니까?
이 문서에서는 NodeMCU 펌웨어를 실행하는 인기 ESP8266 칩을 사용하여 AES 암호화 및 해시 권한 부여 기능을 MQTT 프로토콜에 적용하는 데 중점을 둡니다. 우리의 목적은 사본 / 붙여 넣기 PANACEA를 제공하는 것이 아니라 단계별로 프로세스를 거쳐서 도전과 해결책을 식별합니다. 그 결과 SSL에 의존하지 않고도 eled-to-end 암호화 및 인증, 도청 방지 및 유효한 데이터의 스푸핑을 방지하는 시스템입니다.
우리는 또한 SSL을 쉽게 지원할 수있는 강력한 플랫폼 (예 : 라스베리 PI, Orange PI, Friend)을 쉽게 지원할 수있는 더 강력한 플랫폼이 있지만 가장 저렴한 하드웨어가 주위에 누워 있고 많은 프로젝트에 적합한 프로토콜을 시작합니다. …에 AES는 필요한 경우 AVR에서 구현할 수있는 것입니다.
이론
MQTT는 TCP / IP 상단에서 실행되는 경량 메시징 프로토콜이며 자주 IoT 프로젝트에 사용됩니다. 클라이언트 장치는 주제 (예 : 센서 / 온도 / 주방)에 가입하거나 게시 하고이 메시지는 MQTT 브로커가 중계합니다. MQTT에 대한 자세한 내용은 웹 페이지 또는 자체 시작 시리즈에서 사용할 수 있습니다.
MQTT 프로토콜에는 사용자 이름 / 암호 인증을 초과하여 기본 제공 보안 기능이 없으므로 SSL이있는 네트워크를 암호화하고 인증하는 것이 일반적입니다. 그러나 SSL은 ESP8266에 대해 요구할 수 있으며 사용하도록 설정하면 응용 프로그램에 대한 메모리가 훨씬 적습니다. 가벼운 대안으로, 전송되는 데이터 페이로드 만 암호화하고 인증을 위해 세션 ID 및 해시 함수를 사용하십시오.
이를 수행하는 직접적인 방법은 LUA 및 NodEmcu Crypto 모듈을 사용하는 것입니다. 이는 CBC 모드의 AES 알고리즘 및 HMAC 해시 기능의 지원을 포함합니다. AES 암호화를 사용하여 암호문을 생성하는 세 가지가 필요합니다. 메시지, 키 및 초기화 벡터 (IV). 메시지와 키는 간단한 개념이지만 초기화 벡터는 약간의 토론 가치가 있습니다.
정적 키가있는 AES에서 메시지를 인코딩 할 때 항상 동일한 출력을 생성합니다. 예를 들어 “1234567890abcdef”키로 “usernamepassword”라는 메시지는 “e40d86c04d723aff”와 같은 결과를 생성 할 수 있습니다. 동일한 키와 메시지로 암호화를 다시 실행하면 동일한 결과가 발생합니다. 이렇게하면 여러 가지 공통 유형의 공격, 특히 패턴 분석 및 재생 공격을 엽니 다.
패턴 분석 공격에서 주어진 데이터 부분이 비밀 키를 실제로 알지 못하고 다른 메시지의 목적이나 내용이 무엇인지 추측하기 위해 항상 동일한 암호문을 생성하는 지식을 사용합니다. 예를 들어, “E40D86C04D723AFF”가 다른 모든 통신 이전에 메시지가 전송되면 신속하게 로그인이라고 생각할 수 있습니다. 즉, 로그인 시스템이 단순하면 패킷 (재생 공격)을 보내는 사용자로서 자신을 식별하기에 충분할 수 있으며 카오스가 계속됩니다.
IVS는 패턴 분석을보다 어렵게 만듭니다. IV는 엔드 암호문 결과를 수정하는 키와 함께 전송 된 데이터 조각입니다. 이름이 제안되었으므로 데이터가 입력되기 전에 암호화 알고리즘의 상태를 초기화합니다. 반복 된 데이터가 다른 암호문으로 암호화되도록 전송 된 각 메시지마다 다르게 필요하며, 일부 암호 (예 : AES-CBC)는 예측할 수 없도록 요구합니다. 실용적인 방법은 매번 무작위로 수행하는 것입니다. IVS는 비밀을 유지할 필요가 없지만 어떤 방식 으로든 그들을 난독 화하는 것이 전형적입니다.
이는 패턴 분석을 보호하는 동안 재생 공격에 도움이되지 않습니다. 예를 들어, 주어진 암호화 된 데이터 집합을 재전송하면 결과를 복제합니다. 이를 방지하기 위해 보낸 사람을 인증해야합니다. 우리는 각 메시지에 대해 공개, 의사 andoomly 생성 세션 ID를 사용합니다. 이 세션 ID는 MQTT 주제에 게시하여 수신 장치에 의해 생성 될 수 있습니다.
이러한 유형의 공격을 방지하는 것은 몇 가지 일반적인 유스 케이스에서 중요합니다. 인터넷 통제 스토브가 존재하고 의심스러운 유틸리티가 불안정한 명령을 사용하지 않으면 좋을 것입니다. 둘째, 백 센서에서 데이트로깅하는 경우, 저는 나의 데이터베이스를 쓰레기로 채우는 것을 원하지 않습니다.
실제 암호화
NodeMCU에서 위의 사항을 구현하려면 몇 가지 노력이 필요합니다. ‘Crypto’모듈을 포함하도록 컴파일 된 펌웨어가 필요합니다.귀하의 신청을위한 IRE. SSL 지원이 필요하지 않습니다.
첫째, 다음과 같이 MQTT 브로커에 연결되어있는 것으로 가정 해 봅시다. 이 작업을 암호화에서 별도의 함수로 구현하여 깨끗하게 유지할 수 있습니다. 클라이언트는 SessionID 채널을 구독하여 적절하게 길고 긴 세션 ID를 게시합니다. 당신은 그들을 암호화 할 수 있었지만 필요하지 않습니다.
1
2
삼
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
M = MQTT.CLIENT ( “CLIENTID”, 120)
M : 연결 ( “myserver.com”, 1883, 0,
기능 (클라이언트)
인쇄 ( “연결됨”)
클라이언트 : 가입 ( “myToPic / SessionID”, 0,
기능 (클라이언트) 인쇄 ( “가입 성공”) 끝
)
끝,
기능 (클라이언트, 이유)
인쇄 (& quot; 실패한 이유 : “이유)
끝
)
M : ON ( “메시지”, 기능 (클라이언트, 주제, SESSIONID) 엔드)
계속 이동하면 노드 ID는 데이터 소스를 식별하는 데 편리한 방법입니다. nodeid = node.chipid ()를 사용하는 문자열을 사용할 수 있습니다.
그런 다음 정적 초기화 벡터와 키를 설정합니다. 이것은 모든 데이터에 사용되지 않고 각 메시지와 함께 전송 된 무작위 초기화 벡터를 난독 화하는 데에만 사용됩니다. 우리는 또한 데이터의 별도의 키를 선택합니다. 이 키는 16 비트 헥스이며 그냥 대체하십시오.
마지막으로 나중에 사용할 해시 함수에 대한 암호 문구가 필요합니다. 합리적인 길이의 끈은 괜찮습니다.
1
2
삼
4.
staticiv = “ABCDEF2345678901”
ivkey = “2345678901ABCDEF”
DATAKEY = “0123456789ABCDEF”
암호문 = “MyPassphrase”
또한 몇 가지 데이터 소스가 있다고 가정합니다. 이 예제에서는 ADC에서 읽은 값이 될 것입니다. 데이터 = ADC.READ (0)
자, 우리는 의사 andom 초기화 벡터를 생성합니다. 16 자리 16 진수는 의사 숫자 기능이 너무 큽니다. 그래서 우리는 2 개의 반쪽 (16 ^ 8 마이너스 1)으로 그것을 생성하고이를 연결합니다.
1
2
삼
4.
5.
반 1 = Node.Random (4294967295)
반 2 = node.random (4294967295)
i = string.Format ( “% 8x”, 반 1)
v = string.Format ( “% 8x”, 반값)
iv = i .. V.
이제 실제 암호화를 실행할 수 있습니다. 여기서 우리는 현재 초기화 벡터, 노드 ID 및 센서 데이터 한 장을 암호화하고 있습니다.
1
2
삼
암호화 된 _iv = crypto.encrypt ( “AES-CBC”, iukey, IV, 정전기)
encrypted_nodeid = crypto.encrypt ( “AES-CBC”, datakey, nodeid, iv)
encrypted_data = crypto.encrypt ( “AES-CBC”, Datakey, Data, IV)
이제 우리는 인증을 위해 해시 함수를 적용합니다. 먼저 우리는 NodeID, IV, 데이터 및 세션 ID를 단일 메시지로 결합 한 다음 우리가 이전에 정의한 암호문을 사용하여 HMAC SHA1 해시를 계산합니다. 우리는 그것을 16 진수로 변환하여 디버깅에 대해 더 많은 사람이 읽을 수있게 만듭니다.
1
2
fullmessage = nodeid .. iv .. 데이터 .. SessionID.
hmac = crypto.tohex (crypto.hmac ( “sha1”, fullMessage, passphrase))
이제 암호화 및 인증 검사가 모두 제자리에 있기 때문에이 모든 정보를 일부 구조에두고 보내고 전송할 수 있습니다. 여기에서는 쉼표로 구분 된 값을 편리하게 사용할 것입니다.
1
2
payload = table.concat ({encrypted_iv, eid, data1, hmac}, “”)
M : 게시 ( “YourMQTTtopic”, 페이로드, 2, 1, 함수 (클라이언트) P = “전송 된”인쇄 (P) end)
실제 NodeMCU에서 위의 코드를 실행하면 다음과 같이 출력됩니다.
1D54D1AF0F75A91A00D4DCD8F4AD28D,
D1A0B14D187C5ADFC948DFD77C2B2EE5,
564633A4A053153BCBD6ED25370346D5,
C66697DF7E7D467112757C841BF6BCE051D6289.
모두 함께, 암호화 프로그램은 다음과 같습니다 (명확성을 위해 제외 된 MQTT 섹션).
1
2
삼
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
nodeid = node.chipid ()
staticiv = “ABCDEF2345678901”
ivkey = “2345678901ABCDEF”
DATAKEY = “0123456789ABCDEF”
암호문 = “MyPassphrase”
데이터 = ADC.READ (0)
반 1 = Node.Random (4294967295)
반 2 = node.random (4294967295)
i = string.Format ( “% 8x”, 반 1)
v = string.Format ( “% 8x”, 반값)
iv = i .. V.
암호화 된 _iv = crypto.encrypt ( “AES-CBC”, iukey, IV, 정전기)
encrypted_nodeid = crypto.encrypt ( “AES-CBC”, datakey, nodeid, iv)
encrypted_data = crypto.encrypt ( “AES-CBC”, Datakey, Data, IV)
fullmessage = nodeid .. iv .. 데이터 .. SessionID.
HMAC = crypto.tohex (crypto.hmac ( “SHA1”, FullMessage, Passphrase))
payload = table.concat ({encrypted_iv, encrypted_nodeid, encrypted_data, hMac}, “,”)
암호 해독
이제 MQTT 브로커가 데이터가 암호화되어 있음을 알지 못하거나 관리하지 않으므로 전달합니다. 따라서 다른 MQTT 클라이언트는 주제에 가입하여 데이터를 해독하는 방법을 알아야합니다. NodeMCU에서 이것은 다소 쉽습니다. 수신 된 데이터를 쉼표를 통해 문자열로 분리하고 아래와 같은 것을 수행하십시오. 참고이 end는 세션 ID를 생성하여 이미 알고 있습니다.
1
2
삼
4.
5.
6.
7.
8.
9.
10.
staticiv = “ABCDEF2345678901”
ivkey = “2345678901ABCDEF”
DATAKEY = “0123456789ABCDEF”
암호문 = “MyPassphrase”
iv = crypto.decrypt ( “AES-CBC”, iukey, encrypted_iv, staticiv)
nodeid = crypto.decrypt ( “AES-CBC & quot;, datakey, encrypted_nodeid, iv)
data = crypto.deCrypt ( “AES-CBC”, datakey, encrypted_data, iv)
fullmessage = nodeid .. iv .. 데이터 .. SessionID.
HMAC = crypto.tohex (crypto.hmac ( “SHA1”, FullMessage, Passphrase))
그런 다음 수신 및 계산 된 HMAC를 비교하고 결과에 관계없이 해당 세션 ID가 새 것을 생성하여 해당 세션 ID를 무효화합니다.
파이썬에서 한 번 더
약간의 다양성을 위해 데이터를 분석하거나 데이터베이스에 저장하는 브로커와 동일한 가상 컴퓨터에 MQTT 클라이언트가있는 경우 Python에서 암호 해독을 처리하는 방법을 고려하십시오. Python을 위해 우수한 Paho MQTT 클라이언트와 같은 무언가에서 “페이로드”문자열로 데이터를 받았다고 가정 할 수 있습니다.
이 경우 송신하기 전에 NodeMCU에서 암호화 된 데이터를 인코딩하는 것이 편리합니다. NodeMCU에서 우리는 모든 암호화 된 데이터를 16 진수로 변환합니다 (예 : encrypted_iv = crypto.tohex) (crypto.encrypt ( “AES-CBC”, IVKEY, IV, IV, STATIVIV))
무작위로 된 SessionID를 게시하지는 않지만 OS.urandom () 및 Paho MQTT 클라이언트를 사용하여 쉽습니다. 암호 해독은 다음과 같이 처리됩니다.
1
2
삼
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
crypto.cipher 가져 오는 AES.에서
BinAscii 가져 오기
Crypto.hash Import Sha, HMAC.에서
# 모든 키를 정의하십시오
ivkey = ‘2345678901Abcdef’
datakey = ‘0123456789abcdef’
staticiv = ‘abcdef2345678901’
passphrase = ‘mypassphrase’
# 수신 된 문자열을 목록으로 변환합니다
데이터 = payload.split ( “,” “)
# 목록 항목을 추출합니다
encrypted_iv = binascii.unhexlify (데이터 [0])
encrypted_nodeid = binascii.unhexlify (데이터 [1])
encrypted_data = binascii.unhexlify (데이터 [2])
repenced_hash = binascii.unhexlify (데이터 [3])
# 초기화 벡터를 해독합니다
iv_decryption_suite = aes.new (ivkey, aes.mode_cbc, staticiv)
IV = IV_DECRYPTION_SUITE.DECRYPT (ENCRYPTED_IV)
# 초기화 벡터를 사용하여 데이터를 해독하십시오
id_decryption_suite = aes.new (datakey, aes.mode_cbc, iv)
nodeid = id_decryption_suite.decrypt (encrypted_nodeid)
data_decryption_suite = aes.new (datakey, aes.mode_cbc, iv)
sensordata = data_decryption_suite.decrypt (encrypted_data)
# received_hash와 비교할 해시 함수를 계산합니다
FullMessage = S.Join ([NodeID, IV, Sensordata, SessionID])
hmac = hmac.new (암호, FullMessage, Sha)
computed_hash = hmac.hexdigest ()
# 해시를 안전하게 비교하는 방법은 docs.python.org/2/library/hmac.html을 참조하십시오
끝, 처음
이제 우리는 MQTT 서버를 통해 암호화 된 인증 된 메시지를 다른 ESP8266 클라이언트 또는 Python을 실행하는 더 큰 시스템으로 전송하는 시스템이 있습니다. 이걸 스스로 구현하면 묶을 수있는 중요한 느슨한 끝이 있습니다. 키는 모두 ESP8266S의 플래시 메모리에 저장되므로 리버스 엔지니어링을 방지하기 위해 이러한 장치에 대한 액세스를 제어 할 수 있습니다. 키는 데이터를 수신하는 컴퓨터의 코드에 Python을 실행합니다. 또한 각 클라이언트가 다른 키와 암호를 갖기를 원할 것입니다. 그것은 필요한 경우 안전하고 잠재적으로 업데이트 할 수있는 많은 비밀 자료입니다. 주요 배포 문제 해결 동기 부여 된 독자의 운동으로 남아 있습니다.
그리고 닫는 메모에서는 암호화가 포함 된 기사를 쓰는 것에 관한 무서운 것들 중 하나가 인터넷에서 잘못 될 가능성이 있습니다. 이것은 HMAC와 함께 테스트 및 진정한 AES-CBC 모드의 상당히 간단한 응용 프로그램이므로 매우 견고해야합니다. 그럼에도 불구하고, 위의 흥미로운 단점을 발견하면 의견을 알려주십시오.
0 Comments