The Espressif ESP8266 chipset makes three-dollar ‘Internet of Things’ development boards an economic reality. According to the popular automatic firmware-building site nodeMCU-builds, in the last 60 days there have been 13,341 custom firmware builds for that platform. Of those, only 19% have SSL support, and 10% include the cryptography module.
We’re often critical of the lack of security in the IoT sector, and frequently cover botnets and other attacks, but will we hold our projects to the same standards we demand? will we stop at identifying the problem, or can we be part of the solution?
This article will focus on applying AES encryption and hash authorization functions to the MQTT protocol using the popular ESP8266 chip running NodeMCU firmware. Our purpose is not to provide a copy/paste panacea, but to go through the process step by step, identifying challenges and solutions along the way. The result is a system that’s end-to-end encrypted and authenticated, preventing eavesdropping along the way, and spoofing of valid data, without relying on SSL.
We’re aware that there are also more powerful platforms that can easily support SSL (e.g. Raspberry Pi, Orange Pi, FriendlyARM), but let’s start with the cheapest hardware most of us have lying around, and a protocol suitable for many of our projects. AES is something you could implement on an AVR if you needed to.
सिद्धान्त
MQTT is a lightweight messaging protocol that runs on top of TCP/IP and is frequently used for IoT projects. client devices subscribe or publish to topics (e.g. sensors/temperature/kitchen), and these messages are relayed by an MQTT broker. more information on MQTT is available on their webpage or in our own getting-started series.
The MQTT protocol doesn’t have any built-in security features beyond username/password authentication, so it’s common to encrypt and authenticate across a network with SSL. However, SSL can be rather demanding for the ESP8266 and when enabled, you’re left with much less memory for your application. As a lightweight alternative, you can encrypt only the data payload being sent, and use a session ID and hash function for authentication.
A straightforward way to do this is using Lua and the NodeMCU Crypto module, which includes support for the AES algorithm in CBC mode as well as the HMAC hash function. using AES encryption correctly requires three things to produce ciphertext: a message, a key, and an initialization vector (IV). Messages and keys are straightforward concepts, but the initialization vector is worth some discussion.
When you encode a message in AES with a static key, it will always produce the same output. For example, the message “usernamepassword” encrypted with key “1234567890ABCDEF” might produce a result like “E40D86C04D723AFF”. If you run the encryption again with the same key and message, you will get the same result. This opens you to several common types of attack, especially pattern analysis and replay attacks.
In a pattern analysis attack, you use the knowledge that a given piece of data will always produce the same ciphertext to guess what the purpose or content of different messages are without actually knowing the secret key. For example, if the message “E40D86C04D723AFF” is sent prior to all other communications, one might quickly guess it is a login. In short, if the login system is simplistic, sending that packet (a replay attack) might be enough to identify yourself as an authorized user, and chaos ensues.
IVs make pattern analysis more difficult. An IV is a piece of data sent along with the key that modifies the end ciphertext result. As the name suggests, it initializes the state of the encryption algorithm before the data enters. The IV needs to be different for each message sent so that repeated data encrypts into different ciphertext, and some ciphers (like AES-CBC) require it to be unpredictable – a practical way to accomplish this is just to randomize it each time. IVs do not have to be kept secret, but it’s typical to obfuscate them in some way.
While this protects against pattern analysis, it doesn’t help with replay attacks. For example, retransmitting a given set of encrypted data will still duplicate the result. To prevent that, we need to authenticate the sender. We will use a public, pseudorandomly generated session ID for each message. This session ID can be generated by the receiving device by posting to an MQTT topic.
Preventing these types of attacks is important in a couple of common use cases. Internet controlled stoves exist, and questionable utility aside, it would be nice if they didn’t use insecure commands. Secondly, if I’m datalogging from a hundred sensors, I don’t want anyone filling my database with garbage.
Practical Encryption
Implementing the above on the NodeMCU requires some effort. You will need firmware compiled to include the ‘crypto’ module in addition to any others you require तपाईंको अनुप्रयोगको लागि। SSL समर्थन आवश्यक छैन।
पहिले, मानौं कि तपाईं निम्न जस्तो केहि चीजको साथ जडित हुनुहुन्छ। तपाइँले यसलाई चीजहरू सफा राख्न क्रिप्टिष्टिको भावबाट अलग कार्य गर्न सक्नुहुनेछ। ग्राहकले सत्तर च्यानलसँग सदस्यता लिन्छन्, जसले उपयुक्त लामो समयदेखि उपयुक्त लामो समयदेखि प्रकाशित गर्दछ, फ्यूडोरा सत्र। तपाईं तिनीहरूलाई गुप्तिकरण गर्न सक्नुहुन्छ, तर यो आवश्यक छैन।
1
2.
We
?
W
The
?
8
दोष
रों 10
11
12
1 ‘्ग
1 ‘
1
M = MQTTT.LICITITE (& & quot; ग्राहकको; 120)
m: जडान (& & quot; Myserver.com & quot; 1 188383, 0,
कार्य (ग्राहक)
प्रिन्ट (& & quot; जोडिएको र उद्धृत;)
ग्राहक: सदस्यता लिनुहोस् (& & quot; mytopic / सत्र & quid ;, 0,
प्रकार्य (ग्राहक) प्रिन्ट (& & & quote; सदस्यता लिनुहोस्)।) अन्त्य
)
अन्त,
कार्य (ग्राहक, कारण)
प्रिन्ट (& & & quot; असफल कारण: & & उद्धरण; .. कारण)
समाप्ति
)
M: & & & quot; सन्देश र उद्धरण; प्रकार्य (ग्राहक, शीर्षक, सत्र) अन्त्य)
अगाडि बढ्दै, नोड आईडी डाटा स्रोतहरू पहिचान गर्न मद्दतको लागि उपयुक्त तरीका हो। तपाईं कुनै पनि स्ट्रिप प्रयोग गर्न सक्नुहुनेछ जुन तपाईं चाहनुहुन्छ: nodeid = नोड .चिशिड ()।
त्यसो भए, हामी एक स्थिर आरम्भ भेक्टर र एक कुञ्जी सेट अप गर्यौं। यो केवल प्रत्येक सन्देशको साथ पठाइएको अनियमित आरम्भ भेक्टर पठाइएको छ, कुनै पनि डाटाको लागि प्रयोग गरिएको छैन। हामी डाटाको लागि पनि छुट्टै कुञ्जी छनौट गर्दछौं। यी कुञ्जीहरू 1 16-बिट हेक्स हुन्, तिनीहरूलाई तपाईंको साथ बदल्नुहोस्।
अन्तमा हामीसँग एक ह्यास प्रकार्यका लागि पासफ्रेज चाहिन्छ हामी पछि प्रयोग गरिरहेका छौं। व्यावहारिक लम्बाईको स्ट्रिंग ठीक छ।
1
2.
We
?
स्ट्याटिव
iveke = & & quot; 2454567868901BCECDEF & quot
datapty = & quot; 01234555678686789BECDEF & quot;
पासफ्रेज = & out; म्यूफेजरेज र उद्धरण;
हामी यो पनि लिनेछौं तपाईंको डाटाको केहि स्रोत छ। यस उदाहरणका लागि यो एडीसीबाट पढिएको मान हुनेछ। डाटा = ADC.ED (0)
अब, हामी एक pseaduhorada परिचय भेटो एकता को परिचय। प्रदूषण सुसज्जित कार्यका लागि 1 16-अंक हेक्स नम्बर धेरै ठूलो छ, त्यसैले हामी यसलाई दुई भागमा उत्पन्न गर्दछौं (1 ^ ^ 8 minus 1) र तिनीहरूलाई अभिनय गर्दछ।
1
2.
We
?
W
साढे = नोड.र्याज (42 42 49 67 6767295295))
आधा2 = नोड वीणा (42 42 49 67 6767295295))
I = स्ट्रिंग.अप: & & उद्धृत;% xx & & quote; आधा 12)
V = स्ट्रिंग.रफुट (& & quot;% 8x & & उद्धरण; आधा 2)
iv = i .. v
हामी अब वास्तविक ईन्क्रिप्शन चलाउन सक्छौं। यहाँ हामी हालको सुरुवात भेक्टर, नोड आईडी, र सेन्सर डाटाको एक टुक्रा ईन्क्रिप्ट गर्दैछौं।
1
2.
We
ईन्क्रिप्टेड_इभ = क्रिप्टो। समन्वय (& quot; As-cbc & & quot; ivey, iv, तथ्या .्कन)
ईन्क्रिप्टेड_NODDID = क्रिप्टो.encriest (& quot; As-CBC & & choodey, नोमेड, IV)
ईन्क्रिप्टेड_date = क्रिप्टो.encriest (& quot; As-CBC & & cot
अब हामी प्रमाणीकरणको लागि ह्यास प्रकार्य लागू गर्दछौं। पहिले हामी नोभेड, IV, डाटा, र सत्र आईडी एकल सन्देशमा संकुचित गर्छौं, तब हामीले परिभाषित पासफ्रेज प्रयोग गरेर हमक्ष शो 1 हेशलाई कम्पाइल गर्नुहोस्। हामी यसलाई हेक्समा रूपान्तरण गर्दछौं जुन कुनै पनि डिबगिंगको लागि अलि बढी मानव-पठनीय बनाउन।
1
2.
पूर्णमेज = नोहेड। IV .. डाटा .. सत्र
HMAC = क्रिप्टो. नहेीशक्स (क्रिप्टो.HMAC (& & & & उद्धरण;, पूर्ण, पासफ्रेज))
अब त्यो दुबै ईन्क्रिप्शन र प्रमाणीकरण चेक स्थानमा छन्, हामी यी सबै जानकारी केहि संरचनामा राख्न र यसलाई पठाउन सक्छौं। यहाँ, हामी अल्पविराम विभाजित मानहरू प्रयोग गर्दछौं जुन यो सुविधाजनक छ:
1
2.
पेडलोड = तालिका
m: प्रकाशित गर्नुहोस् (& & quotttttopic & quotlodtic & quotlod,, पेलोड, 2, 1, प्रकार्य (PR); प्रिन्ट गर्नुहोस् (p)
जब हामी वास्तविक नोडेकुकुमा माथिको कोड चलाउँछौं, हामी यस जस्तो केही आउटपुट हुनेछौं:
1D54dd10F75a91a00d40DCDCD8F2D28D,
d1a0b14d187C57C5DFC948DFD477777777777777777777777777777777777777777777777777777777777777777777
56463633633a 43a053153bcd6D253756868686868686867676786868686768686465।
C66797DF4D4D477112757571BEB441BFB641D628999
सबै सँगै, ईन्क्रिप्शन कार्यक्रम निम्नानुसार छ (lqtt सेक्सन स्पष्टताको लागि हटाइएको):
1
2.
We
?
W
The
?
8
दोष
रों 10
11
12
1 ‘्ग
1 ‘
1
1 16
1
18
1 19
नोहेइड = नोड .चिपिड ()
स्ट्याटिव
iveke = & & quot; 2454567868901BCECDEF & quot
datapty = & quot; 01234555678686789BECDEF & quot;
पासफ्रेज = & out; म्यूफेजरेज र उद्धरण;
डाटा = ADC.ED (0)
साढे = नोड.र्याज (42 42 49 67 6767295295))
आधा2 = नोड वीणा (42 42 49 67 6767295295))
I = स्ट्रिंग.अप: & & उद्धृत;% xx & & quote; आधा 12)
V = स्ट्रिंग.रफुट (& & quot;% 8x & & उद्धरण; आधा 2)
iv = i .. v
ईन्क्रिप्टेड_इभ = क्रिप्टो। समन्वय (& quot; As-cbc & & quot; ivey, iv, तथ्या .्कन)
ईन्क्रिप्टेड_NODDID = क्रिप्टो.encriest (& quot; As-CBC & & choodey, नोमेड, IV)
ईन्क्रिप्टेड_date = क्रिप्टो.encriest (& quot; As-CBC & & cot
पूर्णमेज = नोहेड। IV .. डाटा .. सत्र
HMAC = क्रिप्टो. नहेनेक्स (क्रिप्टो.HMAC (& & & & quot; शालिस र पासफ्रेज, पासफ्रेज))
पेडलोड = तालिका
विस्फोट
अब, तपाईंको MQTT ब्रोकरलाई थाहा छैन वा ख्याल राख्नुहुन्न कि डाटा ईन्क्रिप्टेड छ, यो केवल यसलाई भित्र पस्दछ। त्यसो भए, शीर्षकमा सदस्यता लिई तपाईंको अन्य MQTTTIT ग्राहकहरूले कसरी डाटा डिक्रिप्ट गर्ने जान्नु आवश्यक पर्दछ। नोडमाईमा यो सजिलो छ। भर्खर अल्पविराम मार्फत स्ट्रिंगमा प्राप्त डाटा विभाजन गर्नुहोस्, र तल जस्तो केहि गर्नुहोस्। नोट गर्नुहोस् यो अन्तले सत्र आईडी उत्पन्न गरेको छ त्यसैले पहिले नै यो थाहा छ।
1
2.
We
?
W
The
?
8
दोष
रों 10
स्ट्याटिव
iveke = & & quot; 2454567868901BCECDEF & quot
datapty = & quot; 01234555678686789BECDEF & quot;
पासफ्रेज = & out; म्यूफेजरेज र उद्धरण;
IV = क्रिप्टो.DECRITAPT (& quot; As-CBC & quote, irscry_iv_iv, encricive)
नोहेइड = क्रिप्टो.डैक्रिप्ट (& & उद्धृत; ASES-CBC & Culओट,, डाटेडी, ईन्क्रिप्टेड_NODED, IV)
डाटा = क्रिप्टो.डैक्रिप्ट (& & quot; ASES-CBC & quoty, datty, ईन्क्रिप्टेड_डाटा, IV)
पूर्णमेज = नोहेड। IV .. डाटा .. सत्र
HMAC = क्रिप्टो. नहेनेक्स (क्रिप्टो.HMAC (& & & & quot; शालिस र पासफ्रेज, पासफ्रेज))
त्यसोभए प्राप्त र गणना गरिएको HMAC तुलना गर्नुहोस्, र नतिजाको परवाह नगरी, एक नयाँ उत्पादन गरेर सत्र आईडी अमान्य छ।
एक पटक फेरि, पाइथनमा
एक सानो विविधताको लागि, हामी पाथीको डि ret ्क्रमण कसरी ह्यान्डल गर्ने विचार गर्दछौं, यदि हामीसँग समान भर्चुअल मेसिनको रूपमा एक दटाईको विश्लेषण गरिएको थियो वा डाटाबेसमा भण्डारण गरिएको छ भने। मानौं कि तपाईंले स्ट्रिंग “पेललोड” को रूपमा डेटा प्राप्त गर्नुभएको छ, केहिबाट केहि देखि कुनै चीजबाट पाइथनको लागि उत्कृष्ट PQTT ग्राहक जस्तो देखि।
यस अवस्थामा यो हेक्स गर्न सुविधाजनक छ। यसरी नोडम्याकमा हामी सबै ईन्क्रिप्टेड डेटा हेक्सलाई रूपान्तरण गर्दछौं, उदाहरणका लागि: ईन्क्रिप्टेड_ईभ = क्रिप्टो.ईक्स्टेक्स (“AES-CBC”, ive, %%%%%))
एक अनियमित सत्र प्रकाशित गर्दै तल उल्लेखित छैन, तर ओएस.अराले विद्यार्थीलाई () र PAQTT ग्राहक प्रयोग गरेर पर्याप्त सजिलो छ। डिस्क्रिप्शन पनि तलका रूपमा ह्यान्डल गरिएको छ:
1
2.
We
?
W
The
?
8
दोष
रों 10
11
12
1 ‘्ग
1 ‘
1
1 16
1
18
1 19
राष्ट
21
चिहान 22
2 23
2 the
2.
2 6
2 27
2 2
2.
0वटा
?1
A2
अवस्थामा 3 33
? 34
35
क्रिप्टो.cifer आयात एण्डबाट
आयात आविस्सीआईआईई
क्रिप्टो.HASH आयात शो, हमक
# सबै कुञ्जीहरू परिभाषित गर्नुहोस्
iveke = ‘2454567868901BCCEDF’
datapty = ‘012345567868686789BCDEF’
स्ट्याटिवविक = ‘ABCDEF23455568686868686868686868686868.901’
पासफ्रेज = ‘म्फोफ्रेज’
# प्राप्त गर्नको लागि प्राप्त स्ट्रिंगलाई रूपान्तरण गर्नुहोस्
डाटा = पेलोलोड.SPLIT (& & quot;, & & उद्धरण;)
# एक्स्ट्र्याक्ट सूची आईटमहरू
ईन्क्रिप्टेड_इभ = BINASCII.UTHEXILE (डाटा [0])
ईन्क्रिप्टेड_NODDID = BINASCII.UTHENEXILE (डाटा [1])
ईन्क्रिप्टेड_data = BINASCII.UTHENEXILE (डाटा [2])
प्राप्त_hash = BEASACII.UTHENXILE (डाटा []])
# आरम्भ भेक्टर डिक्रिप्ट गर्नुहोस्
IV_DECRICICT_SCHET_SUite = AES.EN (iveke, Asode_cbc, तथ्या ut ्कभ)
IV = IV_DECRICRICTECT_SUIT.DECRICT (ईन्क्रिप्टेड_iv)
# आरम्भ भेक्टर प्रयोग गरेर डाटा डिक्रिप्ट गर्नुहोस्
ID_DECRICTICT_SUITE = AES. UNS.EN (DATEDY, AESE_CBC, IV)
नोहेइड = id_decryryright_Suite.decrypt (ईन्क्रिप्टेड_nagedid)
डाटा_DECRICTECT_SUite = AES. UNS.NE (DATEDY, AESE_CBC, IV)
सेन्सफोर्टा = डाटा_देवर्चेन्ट_सुइट_सुइट_डबेट (ईन्क्रिप्टेड_डाटा)
# प्राप्त_हाशसँग तुलना गर्न गणना ह्यास प्रकार्य
पूर्णमेज = s.join ([नोवाइड, IV, सेन्सर्डाटा, सत्र, सत्र])
HMAL = HMAC. नयाँ (पासफ्रेज, पूर्ण मिश्मेद, शेल)
गणना_हाश = HMAC.HEXDISTIST ()
# Docs.python.org/2/liblary/hmacac.htmac.htmac.htmlls कसरी ह्यासहरू सुरक्षित रूपमा तुलना गर्न को लागी
अन्त्य, सुरुवात
अब हामीसँग एउटा प्रणाली छ जसले एक एन्क्रिप्टेड, एक MQTT सर्भर मार्फत या त अर्को ESQ8266 ग्राहक वा एक ठूलो प्रणालीलाई पाइथन चलाइयो। यदि तपाईंले आफैंलाई कार्यान्वयन गर्नुभयो भने अझै महत्त्वपूर्ण ढीलाहरू छन्। कुञ्जीहरू ESP826676s को फ्ल्यास मेमोरीमा सबै भण्डारण भएका छन्, त्यसैले तपाईं यी उपकरणहरूमा पहुँच नियन्त्रण गर्न चाहानुहुन्छ रिभर्स रोप्न रोक्नुहोस्। कुञ्जी पनि डाटा प्राप्त डाटा प्राप्त को कोड मा भण्डारण छ, यहाँ python चलिरहेको। थप, तपाईं सायद प्रत्येक ग्राहकलाई फरक कुञ्जी र पासफ्रेज हुनुहुनेछ। यो आवश्यक हुँदा सुरक्षित र सम्भावित अपडेट राख्नको लागि धेरै गोप्य सामग्री हो। कुञ्जी वितरण समस्या समाधान गर्दै प्रेरित पाठकको लागि व्यायामको रूपमा छोडियो।
र क्रिप्टिटोग्राफी समावेश लेख लेख्ने बारेमा डरलाग्दो कुराहरु इन्टरनेटमा गलत हुनु पर्ने सम्भावना हो। यो एचएमसीको साथ परीक्षणको साथ परीक्षण गरिएको-र-सही ASBC मोडको पर्याप्त सीधा स्टेशन अनुप्रयोग हो, त्यसैले यो एकदम ठोस हुनुपर्दछ। जे होस्, माथिको कुनै पनि चाखलाग्दो कमजोरीहरू फेला पार्नुहोस् भने कृपया हामीलाई टिप्पणीहरूमा बताउनुहोस्।