পাঠ ৫২ · ৫৭-এর মধ্যে · মডিউল ১২
Home / Courses / Microprocessors, Embedded Systems & IoT / সিকিউর বুট

এমবেডেড ডিভাইস সিকিউর করা — সিকিউর বুট ও এনক্রিপশন

Securing embedded devices — secure boot and encryption
১২ মিনিট পড়া মধ্যম · Intermediate Python সিমুলেশনসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • সিকিউর বুট/চেইন-অফ-ট্রাস্টের ধারণা, এবং এটি কেন ট্যাম্পার করা ফার্মওয়্যার চালানো থেকে ডিভাইসকে রক্ষা করে
  • real hashlib.sha256 দিয়ে একটি জেনুইন, কার্যকর হ্যাশ-চেইন সিকিউর-বুট সিমুলেশন লেখা
  • real hmac দিয়ে বার্তা ইন্টিগ্রিটি যাচাই করা — এবং এনক্রিপশন (গোপনীয়তা) ও ইন্টিগ্রিটি (পরিবর্তন ধরা) এর মধ্যে পার্থক্য
  • কেন এই কোর্স নিজে থেকে real AES/TLS বাস্তবায়ন করে না, এবং real এমবেডেড ডিভাইস আসলে কী ব্যবহার করে

১ · সিকিউর বুট — একটি চেইন-অফ-ট্রাস্ট

পাওয়ার-অন হওয়ার মুহূর্তে একটি এমবেডেড ডিভাইস কীভাবে নিশ্চিত হয় যে সে যে ফার্মওয়্যার চালাতে যাচ্ছে সেটি আসল, ট্যাম্পার করা নয়? উত্তর হলো সিকিউর বুটSecure Bootএকটি চেইন-অফ-ট্রাস্ট প্রক্রিয়া, যেখানে প্রতিটি বুট স্টেজ পরবর্তী স্টেজ চালানোর আগে তার হ্যাশ/স্বাক্ষর যাচাই করে। — একটি ধাপে-ধাপে যাচাই প্রক্রিয়া:

  • চিপে একটি অপরিবর্তনযোগ্য রুট অফ ট্রাস্ট থাকে (সাধারণত ROM-এ ফিক্সড কোড) — এটিই প্রথম চলে, নিজে কারও দ্বারা যাচাই হয় না, শুধু নিজেই পরবর্তী স্টেজকে যাচাই করে।
  • রুট অফ ট্রাস্টে পরবর্তী স্টেজের (বুটলোডার) প্রত্যাশিত হ্যাশ আগে থেকেই এমবেড করা থাকে (ফ্যাক্টরিতে সাইন করার সময়)।
  • বুট শুরু হলে রুট অফ ট্রাস্ট পরবর্তী স্টেজের প্রকৃত হ্যাশ গণনা করে, প্রত্যাশিত হ্যাশের সাথে মেলায় — মিললে তবেই সেই স্টেজ চালানো হয়।
  • প্রতিটি স্টেজ একইভাবে পরবর্তী স্টেজকে যাচাই করে — একটি চেইন তৈরি হয়। একটি স্টেজেও মিসম্যাচ হলে বুট সেখানেই থেমে যায়।
ROM রুট অফ ট্রাস্ট (অপরিবর্তনীয়, চিপে ফিক্সড) হ্যাশ যাচাই ✓ স্টেজ ১ বুটলোডার (পরবর্তী স্টেজের হ্যাশ ধারণ করে) হ্যাশ যাচাই ✓ স্টেজ ২ OS/অ্যাপ (শেষ পর্যন্ত ট্রাস্টেড)
সিকিউর বুট চেইন-অফ-ট্রাস্ট — প্রতিটি স্টেজ পরবর্তী স্টেজের হ্যাশ যাচাই করেই তবে চালায়; যেকোনো একটি ধাপে মিসম্যাচ হলে বুট সেখানেই থেমে যায়।

এই কোর্সের Pyodide স্যান্ডবক্সে সত্যিকারের ROM/ফ্ল্যাশ নেই — তাই নিচের সিমুলেশনে ফার্মওয়্যার "কনটেন্ট"কে সাধারণ Python স্ট্রিং দিয়ে রিপ্রেজেন্ট করা হয়েছে, কিন্তু হ্যাশ গণনাটি সত্যিকারের — Python-এর স্ট্যান্ডার্ড লাইব্রেরির hashlib.sha256 ব্যবহার করে, যা real ফার্মওয়্যার সিকিউর-বুট ইমপ্লিমেন্টেশনও ব্যবহার করে (সাধারণত একটি ডিজিটাল স্বাক্ষরের অংশ হিসেবে)।

Python
import hashlib

# --- সিকিউর বুট চেইন-অফ-ট্রাস্ট সিমুলেশন ---
# প্রতিটি বুট স্টেজ আসল বাইনারি ফার্মওয়্যার কনটেন্টের একটি স্ট্যান্ড-ইন হিসেবে একটি স্ট্রিং ব্যবহার করছে,
# কিন্তু হ্যাশ real hashlib.sha256() দিয়ে জেনুইনভাবে গণনা করা হচ্ছে -- কোনো হ্যাশ হার্ডকোড করা হয়নি।

def sha256_hex(content: str) -> str:
    return hashlib.sha256(content.encode("utf-8")).hexdigest()

stage1_firmware = "STAGE1_BOOTLOADER:v1.2:init_clocks();init_memory();load_stage2();"
stage2_firmware = "STAGE2_OS_IMAGE:v3.0:init_kernel();mount_fs();start_app();"

# রুট অফ ট্রাস্ট (স্টেজ ০, ROM-এ ফিক্সড)-এ স্টেজ ১-এর প্রত্যাশিত হ্যাশ আগে থেকেই এমবেড করা (ফ্যাক্টরি-সাইনড)
rom_expected_stage1_hash = sha256_hex(stage1_firmware)
# স্টেজ ১-এ স্টেজ ২-এর প্রত্যাশিত হ্যাশ এমবেড করা
stage1_expected_stage2_hash = sha256_hex(stage2_firmware)

def secure_boot(stage1_content, stage2_content, label):
    print(f"--- {label} ---")
    ok = True

    # ধাপ ১: রুট অফ ট্রাস্ট স্টেজ ১-এর প্রকৃত হ্যাশ গণনা করে প্রত্যাশিত হ্যাশের সাথে তুলনা করছে
    actual_stage1_hash = sha256_hex(stage1_content)
    print(f"স্টেজ ১ প্রত্যাশিত হ্যাশ: {rom_expected_stage1_hash}")
    print(f"স্টেজ ১ প্রকৃত হ্যাশ:   {actual_stage1_hash}")
    if actual_stage1_hash != rom_expected_stage1_hash:
        print("MISMATCH -- স্টেজ ১ যাচাই ব্যর্থ! বুট এখানেই বন্ধ করা হলো।\n")
        return False
    print("স্টেজ ১ যাচাই সফল -- চালানো হচ্ছে।")

    # ধাপ ২: স্টেজ ১ স্টেজ ২-এর প্রকৃত হ্যাশ গণনা করে নিজের এমবেডেড প্রত্যাশিত হ্যাশের সাথে তুলনা করছে
    actual_stage2_hash = sha256_hex(stage2_content)
    print(f"স্টেজ ২ প্রত্যাশিত হ্যাশ: {stage1_expected_stage2_hash}")
    print(f"স্টেজ ২ প্রকৃত হ্যাশ:   {actual_stage2_hash}")
    if actual_stage2_hash != stage1_expected_stage2_hash:
        print("MISMATCH -- স্টেজ ২ যাচাই ব্যর্থ! বুট এখানেই বন্ধ করা হলো।\n")
        return False
    print("স্টেজ ২ যাচাই সফল -- বুট সম্পূর্ণ, OS চালু হচ্ছে।\n")
    return True

# দৃশ্য ১: আসল, অপরিবর্তিত ফার্মওয়্যার
result_genuine = secure_boot(stage1_firmware, stage2_firmware, "দৃশ্য ১: জেনুইন ফার্মওয়্যার")
print(f"বুট সফল হয়েছে: {result_genuine}\n")

# দৃশ্য ২: স্টেজ ২-তে একটি লাইন বদলে ট্যাম্পারিং সিমুলেট করা হলো (নতুন কন্টেন্ট = নতুন real হ্যাশ)
tampered_stage2 = stage2_firmware.replace("start_app();", "start_malware();")
result_tampered = secure_boot(stage1_firmware, tampered_stage2, "দৃশ্য ২: ট্যাম্পারড স্টেজ ২ ফার্মওয়্যার")
print(f"বুট সফল হয়েছে: {result_tampered}")

    
লক্ষ্য করুন — দৃশ্য ২-তে tampered_stage2 কনটেন্টের একটি মাত্র শব্দ বদলানো হয়েছে (start_app() থেকে start_malware()), কিন্তু SHA-256 হ্যাশের অ্যাভালাঞ্চ ইফেক্ট-এর কারণে সম্পূর্ণ হ্যাশ ভিন্ন হয়ে যায় — এটি কোনো হার্ডকোড করা "ব্যর্থ" বার্তা নয়, বরং actual_stage2_hash সত্যিই stage1_expected_stage2_hash-এর সাথে না মেলার কারণে জেনুইনভাবে ব্যর্থ হচ্ছে। বাস্তব সিকিউর বুট এভাবেই ম্যালওয়্যার-ইনজেক্টেড ফার্মওয়্যারকে বুট হতে বাধা দেয়।

২ · HMAC — বার্তা/ফার্মওয়্যার ইন্টিগ্রিটি যাচাই

হ্যাশ-চেইন সিকিউর বুটের মতো, নেটওয়ার্কে পাঠানো একটি বার্তাও পথে বদলে যেতে পারে (দুর্ঘটনাক্রমে বা আক্রমণাত্মকভাবে)। শুধু একটি হ্যাশ পাঠালে সমস্যা আছে — আক্রমণকারী বার্তা বদলে নতুন হ্যাশও গণনা করে পাঠিয়ে দিতে পারে। এই সমস্যার সমাধান HMACHash-based Message Authentication Codeএকটি গোপন কী ও একটি হ্যাশ ফাংশন একসাথে ব্যবহার করে তৈরি একটি ট্যাগ, যা শুধুমাত্র কী-জানা পক্ষই সঠিকভাবে গণনা/যাচাই করতে পারে। — এখানে একটি গোপন কীও হ্যাশের সাথে মেশানো হয়, যা শুধু ডিভাইস ও সার্ভার জানে — আক্রমণকারী কী না জানলে বৈধ HMAC ট্যাগ তৈরি করতে পারে না।

নিচের কোড সেলে Python-এর real hmac ও hashlib মডিউল দিয়ে একটি সেন্সর বার্তার HMAC ট্যাগ গণনা এবং যাচাই করা হয়েছে — একবার অপরিবর্তিত বার্তার জন্য, একবার ট্যাম্পার করা বার্তার জন্য।

Python
import hmac
import hashlib

# ফ্যাক্টরি-প্রোভিশনড শেয়ারড সিক্রেট কী -- বাস্তবে ডিভাইসের একটি সিকিউর এলিমেন্ট/সিকিউর স্টোরেজে থাকে
device_secret_key = b"factory-provisioned-shared-secret-32B"

def make_hmac(message: bytes, key: bytes) -> str:
    return hmac.new(key, message, hashlib.sha256).hexdigest()

def verify_hmac(message: bytes, key: bytes, received_tag: str) -> bool:
    expected_tag = make_hmac(message, key)
    # hmac.compare_digest -- টাইমিং-অ্যাটাক প্রতিরোধী তুলনা, real hmac মডিউলেরই একটি ফাংশন
    return hmac.compare_digest(expected_tag, received_tag)

original_message = b'{"sensor":"temp01","value":24.6,"ts":1730000000}'
sent_tag = make_hmac(original_message, device_secret_key)
print("ডিভাইস পাঠানো বার্তা:", original_message)
print("গণনাকৃত HMAC ট্যাগ:  ", sent_tag)

print("\n--- দৃশ্য ১: অপরিবর্তিত বার্তা রিসিভারে পৌঁছালো ---")
print("যাচাই ফলাফল:", verify_hmac(original_message, device_secret_key, sent_tag))

print("\n--- দৃশ্য ২: বার্তাটি পথে ট্যাম্পার হলো (একই পুরনো ট্যাগসহ) ---")
tampered_message = b'{"sensor":"temp01","value":99.9,"ts":1730000000}'
print("ট্যাম্পারড বার্তা:  ", tampered_message)
print("পুরনো HMAC ট্যাগ:   ", sent_tag)
print("যাচাই ফলাফল:", verify_hmac(tampered_message, device_secret_key, sent_tag))

    
দৃশ্য ২-তে verify_hmac ফাংশন tampered_message থেকে একটি নতুন expected_tag real গণনা করে, আর সেটি পুরনো sent_tag-এর (যা original message থেকে গণনা হয়েছিল) সাথে মেলে না — তাই hmac.compare_digest জেনুইনভাবে False ফেরত দেয়। আক্রমণকারী device_secret_key না জানলে ট্যাম্পার করা বার্তার জন্য একটি বৈধ নতুন ট্যাগও তৈরি করতে পারবে না — এটাই HMAC-এর মূল শক্তি।

৩ · এনক্রিপশন — গোপনীয়তা বনাম ইন্টিগ্রিটি

HMAC ইন্টিগ্রিটি নিশ্চিত করে (বার্তা বদলায়নি তা ধরা), কিন্তু বার্তার কনটেন্ট গোপন রাখে না — যে কেউ বার্তাটি দেখলে এর মান পড়তে পারবে। কনটেন্ট গোপন রাখতে দরকার এনক্রিপশন। real এমবেডেড ডিভাইস এর জন্য AES (প্রায়ই চিপের একটি ডেডিকেটেড হার্ডওয়্যার ক্রিপ্টো ইঞ্জিনে, দ্রুত ও কম পাওয়ারে চালানোর জন্য) এবং নেটওয়ার্ক লেয়ারে TLS (mbedTLS বা wolfSSL-এর মতো real, ব্যাপকভাবে ব্যবহৃত এমবেডেড TLS লাইব্রেরি দিয়ে) ব্যবহার করে। এই কোর্স নিজে থেকে AES বা TLS বাস্তবায়ন করে না — সেগুলো জটিল, সাবধানে অডিট করা ক্রিপ্টোগ্রাফিক প্রিমিটিভ, এবং ভুল বাস্তবায়ন বিপজ্জনক।

নিচে শুধু ধারণা বোঝানোর জন্য একটি শিক্ষামূলক TOY XOR সাইফার দেখানো হচ্ছে — এটি real এনক্রিপশন নয় এবং কখনোই বাস্তব ডিভাইসে ব্যবহার করা উচিত নয় (একই কী পুনরায় ব্যবহার করলে সহজেই ভাঙা যায়) — শুধু "ডেটাকে কী দিয়ে রূপান্তর করে অপাঠযোগ্য করা, একই কী দিয়ে আবার ফিরিয়ে আনা" এই মৌলিক ধারণাটি জেনুইনভাবে দেখানোর জন্য।

Python
# --- শিক্ষামূলক TOY XOR সাইফার -- এটি real এনক্রিপশন নয়, শুধু ধারণা বোঝানোর জন্য! ---
# real ডিভাইস AES (প্রায়ই হার্ডওয়্যার ক্রিপ্টো ইঞ্জিনে) বা TLS (mbedTLS/wolfSSL) ব্যবহার করে, এই সরল XOR নয়।

def xor_toy_cipher(data: bytes, key: bytes) -> bytes:
    return bytes(byte ^ key[i % len(key)] for i, byte in enumerate(data))

plaintext = b"PUMP_ON"
toy_key = b"K3Y"

ciphertext = xor_toy_cipher(plaintext, toy_key)
decrypted = xor_toy_cipher(ciphertext, toy_key)  # একই XOR অপারেশন আবার প্রয়োগ করলে মূল ডেটা ফিরে আসে

print("প্লেইনটেক্সট:      ", plaintext)
print("সাইফারটেক্সট bytes:", ciphertext)
print("ডিক্রিপ্ট করা:      ", decrypted)
print("মূল ডেটা ফিরে পাওয়া গেছে:", decrypted == plaintext)

    
মূল কথা · Key takeaway

সিকিউর বুট (হ্যাশ-চেইন দিয়ে ট্যাম্পার করা ফার্মওয়্যার ধরা), HMAC (ট্যাম্পার করা বার্তা ধরা), এবং এনক্রিপশন (কনটেন্ট গোপন রাখা) — তিনটি ভিন্ন কিন্তু পরিপূরক সুরক্ষা। এই পাঠের হ্যাশ-চেইন ও HMAC সিমুলেশন উভয়ই real hashlib/hmac দিয়ে জেনুইনভাবে গণনা করা এবং জেনুইনভাবে ট্যাম্পারিং ধরে ফেলে — শুধু বর্ণনা নয়, প্রকৃত চলমান কোড। এই ধরনের প্রযুক্তিগত সুরক্ষা L51-এ আলোচিত চ্যালেঞ্জগুলোর (দুর্বল ক্রেডেনশিয়াল, অনিয়মিত প্যাচিং, ফিজিক্যাল অ্যাক্সেস) একটি বড় অংশ প্রশমিত করে।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ যদি আক্রমণকারী rom_expected_stage1_hash নিজে থেকে বদলে দিতে পারে, তাহলে পুরো সিকিউর বুট চেইন কেন ভেঙে পড়বে?

কারণ পুরো চেইনের নিরাপত্তা রুট অফ ট্রাস্টের অপরিবর্তনযোগ্যতার উপর নির্ভর করে। যদি রুট অফ ট্রাস্টের এমবেডেড প্রত্যাশিত হ্যাশও আক্রমণকারী বদলাতে পারে, তাহলে সে সহজেই ট্যাম্পার করা ফার্মওয়্যারের real হ্যাশ গণনা করে সেটিকেই "প্রত্যাশিত" হিসেবে বসিয়ে দিতে পারবে — তখন যাচাই সবসময় সফল দেখাবে। এই কারণেই বাস্তব চিপে রুট অফ ট্রাস্ট সাধারণত ROM-এ বার্ন করা থাকে (এক-বার-লেখা যায়, পরে পরিবর্তনযোগ্য নয়) — সফটওয়্যার দিয়ে বদলানো যায় না।

প্র ০২ শুধু একটি সাধারণ হ্যাশ (SHA-256, কোনো সিক্রেট কী ছাড়া) পাঠালেই কি বার্তার ইন্টিগ্রিটি নিশ্চিত করা যেত? HMAC কেন আলাদাভাবে দরকার হলো?

না। একটি সাধারণ হ্যাশ পাবলিকলি যে কেউ গণনা করতে পারে — আক্রমণকারী বার্তা বদলে নতুন হ্যাশও নিজে গণনা করে দুটোই একসাথে পাঠিয়ে দিতে পারবে, আর রিসিভার কিছু ধরতেই পারবে না। HMAC-এ একটি গোপন কী মেশানো থাকে বলে আক্রমণকারী কী না জানলে বৈধ ট্যাগ তৈরি করতেই পারবে না — এটাই সাধারণ হ্যাশ ও HMAC-এর মূল পার্থক্য।

প্র ০৩ উপরের TOY XOR সাইফার কোড সেলে xor_toy_cipher ফাংশনটিকে এনক্রিপশন ও ডিক্রিপশন দুটোর জন্যই একইভাবে কল করা হয়েছে কেন?

কারণ XOR একটি "নিজের-বিপরীত" (self-inverse) অপারেশন — একই মান দিয়ে দুইবার XOR করলে মূল মান ফিরে আসে ($a \oplus k \oplus k = a$)। তাই একই ফাংশন-কল দিয়েই এনক্রিপ্ট ও ডিক্রিপ্ট দুটোই করা যায়। কিন্তু এটাই এর দুর্বলতাও — এই সরলতার কারণে এটি real ক্রিপ্টোগ্রাফিক শক্তি দেয় না, তাই এটি স্পষ্টভাবে শুধু শিক্ষামূলক টয় হিসেবে দেখানো হয়েছে, real AES-এর বিকল্প হিসেবে নয়।

অনুশীলন

  1. চিন্তা করুন: সিকিউর বুট কোড সেলে যদি stage1_firmware-এ (স্টেজ ২ নয়, স্টেজ ১-এ) একটি অক্ষর বদলে ট্যাম্পার করা হয়, তাহলে কি "দৃশ্য" স্টেজ ১-এই থেমে যাবে, নাকি স্টেজ ২ পর্যন্ত পৌঁছাবে?

    এটি স্টেজ ১-এই থেমে যাবে, কারণ secure_boot ফাংশন প্রথমে actual_stage1_hash-কে rom_expected_stage1_hash-এর সাথে তুলনা করে — এটি না মিললে ফাংশন সাথে সাথে False রিটার্ন করে, স্টেজ ২ যাচাই করার পর্যায় পর্যন্ত পৌঁছায়ই না। এটাই চেইন-অফ-ট্রাস্টের মূল ধারণা — একটি স্টেজে ব্যর্থ হলেই বাকি চেইন থেমে যায়।

  2. পরীক্ষা করুন: HMAC কোড সেলে device_secret_key-এর মান সামান্য বদলে (যেমন শেষে একটি অক্ষর যোগ করে) দৃশ্য ১-এর verify_hmac(original_message, device_secret_key, sent_tag) আবার কল করুন (তবে sent_tag আগের কী দিয়ে গণনা করা থাকবে)। ফলাফল কী হবে বলে আপনার ধারণা?

    ফলাফল False হবে — এমনকি বার্তা নিজে অপরিবর্তিত থাকলেও। কারণ make_hmac এখন একটি ভিন্ন কী দিয়ে expected_tag গণনা করবে, যা পুরনো কী দিয়ে গণনা করা sent_tag-এর সাথে মিলবে না। এটি দেখায় কেন দুই পক্ষের একই সিক্রেট কী ব্যবহার করা অপরিহার্য — কী না মিললে বৈধ বার্তাও "যাচাই ব্যর্থ" দেখাবে।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

  • কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৭টি পাঠ মাইক্রোপ্রসেসর আর্কিটেকচার, এমবেডেড C, GPIO, টাইমার/PWM/ADC, সিরিয়াল প্রোটোকল, RTOS, সেন্সর/অ্যাকচুয়েটর, IoT আর্কিটেকচার, ওয়্যারলেস প্রোটোকল, MQTT/CoAP ও IoT সিকিউরিটি — বাকি পাঠগুলো শীঘ্রই যুক্ত হবে।
  • Cybersecurity & Ethical Hacking কোর্স সহোদর কোর্স ক্রিপ্টোগ্রাফির সাধারণ ভিত্তি (সিমেট্রিক/অ্যাসিমেট্রিক এনক্রিপশন, TLS হ্যান্ডশেক) সেই কোর্সেই তৈরি হয়েছে — এই পাঠ শুধু এমবেডেড-স্পেসিফিক প্রয়োগে ফোকাস করে।
  • সব Courses দেখুন ABCL TECH C, C++, Python, Java, JavaScript, DSA, DBMS, Discrete Mathematics, System Design, Cybersecurity, Cloud Computing & DevOps, Computer Networks, Operating Systems, Computer Architecture, Design and Analysis of Algorithms ও আরও অনেক কোর্স — সব এক জায়গায়।
আগের পাঠ
IoT সিকিউরিটি চ্যালেঞ্জ ও থ্রেট