کلیدهای سخت افزاری

مانند بسیاری از نرم افزارهای رمزگذاری دیسک و فایل، رمزگذاری ذخیره سازی اندروید به طور سنتی به کلیدهای رمزگذاری خام موجود در حافظه سیستم متکی است تا رمزگذاری انجام شود. حتی زمانی که رمزگذاری توسط سخت افزار اختصاصی به جای نرم افزار انجام می شود، نرم افزار به طور کلی هنوز نیاز به مدیریت کلیدهای رمزگذاری خام دارد.

این معمولاً به عنوان یک مشکل تلقی نمی شود زیرا کلیدها در طول حمله آفلاین وجود ندارند، که نوع اصلی حمله است که رمزگذاری ذخیره سازی برای محافظت در برابر آن طراحی شده است. با این حال، میل به افزایش محافظت در برابر انواع دیگر حملات، مانند حملات بوت سرد ، و حملات آنلاین که در آن مهاجم ممکن است بتواند حافظه سیستم را بدون به خطر انداختن کامل دستگاه نشت کند، وجود دارد.

برای حل این مشکل، اندروید 11 پشتیبانی از کلیدهای سخت افزاری را معرفی کرد، جایی که پشتیبانی سخت افزاری وجود دارد. کلیدهای سخت افزاری کلیدهای ذخیره سازی هستند که فقط به صورت خام برای سخت افزار اختصاصی شناخته می شوند. نرم افزار فقط این کلیدها را به صورت پیچیده (رمزگذاری شده) می بیند و با آنها کار می کند. این سخت‌افزار باید قادر به تولید و وارد کردن کلیدهای ذخیره‌سازی، بسته‌بندی کلیدهای ذخیره‌سازی به شکل‌های زودگذر و بلندمدت، استخراج کلیدهای فرعی، برنامه‌نویسی مستقیم یک کلید فرعی در یک موتور کریپتو درون خطی و بازگرداندن یک کلید فرعی جداگانه به نرم‌افزار باشد.

توجه : یک موتور کریپتو درون خطی (یا سخت‌افزار رمزگذاری درون خطی ) به سخت‌افزاری اطلاق می‌شود که داده‌ها را در حالی که در راه است به/از دستگاه ذخیره‌سازی رمزگذاری/رمزگشایی می‌کند. معمولاً این یک کنترل‌کننده میزبان UFS یا eMMC است که پسوندهای رمزنگاری تعریف شده توسط مشخصات JEDEC مربوطه را پیاده‌سازی می‌کند.

طرح

این بخش طراحی ویژگی کلیدهای پیچیده شده با سخت افزار را ارائه می دهد، از جمله اینکه چه پشتیبانی سخت افزاری برای آن لازم است. این بحث بر روی رمزگذاری مبتنی بر فایل (FBE) متمرکز است، اما راه حل برای رمزگذاری ابرداده نیز کاربرد دارد.

یکی از راه‌های اجتناب از نیاز به کلیدهای رمزنگاری خام در حافظه سیستم این است که آنها را فقط در شکاف‌های یک موتور رمزنگاری درون خطی نگه دارید. با این حال، این رویکرد با مشکلاتی روبرو می شود:

  • ممکن است تعداد کلیدهای رمزگذاری از تعداد شکاف های کلید بیشتر شود.
  • از موتورهای رمزنگاری درون خطی فقط می توان برای رمزگذاری/رمزگشایی بلوک های کامل داده روی دیسک استفاده کرد. با این حال، در مورد FBE، نرم افزار هنوز باید بتواند کارهای رمزنگاری دیگری مانند رمزگذاری نام فایل ها و استخراج شناسه های کلیدی را انجام دهد. نرم افزار همچنان برای انجام این کار دیگر نیاز به دسترسی به کلیدهای خام FBE دارد.

برای جلوگیری از این مشکلات، کلیدهای ذخیره سازی در عوض به کلیدهای سخت افزاری تبدیل می شوند که فقط می توانند توسط سخت افزار اختصاصی باز شوند و استفاده شوند. این اجازه می دهد تا تعداد نامحدودی از کلیدها پشتیبانی شوند. علاوه بر این، سلسله‌مراتب کلید اصلاح شده و تا حدی به این سخت‌افزار منتقل می‌شود، که اجازه می‌دهد یک کلید فرعی به نرم‌افزار برای کارهایی که نمی‌توانند از یک موتور رمزنگاری درون خطی استفاده کنند، بازگردانده شود.

سلسله مراتب کلیدی

کلیدها را می توان از کلیدهای دیگر با استفاده از KDF (تابع مشتق کلید) مانند HKDF مشتق کرد که منجر به سلسله مراتب کلید می شود.

نمودار زیر یک سلسله مراتب کلید معمولی برای FBE را در زمانی که از کلیدهای پیچیده شده با سخت افزار استفاده نمی شود نشان می دهد:

سلسله مراتب کلید FBE (استاندارد)
شکل 1. سلسله مراتب کلید FBE (استاندارد)

کلید کلاس FBE کلید رمزگذاری خامی است که اندروید به هسته لینوکس ارسال می کند تا مجموعه خاصی از دایرکتوری های رمزگذاری شده را باز کند، مانند فضای ذخیره سازی رمزگذاری شده با اعتبار برای یک کاربر خاص اندروید. (در هسته، این کلید یک کلید اصلی fscrypt نامیده می شود.) از این کلید، هسته زیر کلیدهای زیر را استخراج می کند:

  • شناسه کلید این برای رمزگذاری استفاده نمی شود، بلکه مقداری است که برای شناسایی کلیدی که یک فایل یا دایرکتوری خاص با آن محافظت می شود، استفاده می شود.
  • کلید رمزگذاری محتویات فایل
  • کلید رمزگذاری نام فایل ها

در مقابل، نمودار زیر سلسله مراتب کلید را برای FBE در هنگام استفاده از کلیدهای پیچیده شده با سخت افزار نشان می دهد:

سلسله مراتب کلید FBE (با کلید سخت افزاری)
شکل 2. سلسله مراتب کلید FBE (با کلید سخت افزاری)

در مقایسه با مورد قبلی، یک سطح اضافی به سلسله مراتب کلید اضافه شده است و کلید رمزگذاری محتویات فایل جابجا شده است. گره ریشه همچنان نشان دهنده کلیدی است که اندروید برای باز کردن مجموعه ای از دایرکتوری های رمزگذاری شده به لینوکس می دهد. با این حال، اکنون آن کلید به شکل موقتی پیچیده شده است و برای استفاده باید از آن به سخت افزار اختصاصی منتقل شود. این سخت افزار باید دو اینترفیس را پیاده سازی کند که یک کلید موقتی پیچیده شده باشد:

  • یک رابط برای استخراج inline_encryption_key و برنامه‌ریزی مستقیم آن در شکاف کلید موتور کریپتو داخلی. این اجازه می دهد تا محتویات فایل بدون دسترسی نرم افزار به کلید خام، رمزگذاری/رمزگشایی شوند. در کرنل های رایج اندروید، این رابط مربوط به عملیات blk_ksm_ll_ops::keyslot_program است که باید توسط درایور ذخیره سازی پیاده سازی شود.
  • یک رابط برای استخراج و بازگرداندن sw_secret ("محرمانه نرم افزار" -- همچنین در برخی مکان ها "راز خام" نیز نامیده می شود)، که کلیدی است که لینوکس برای استخراج کلیدهای فرعی برای هر چیزی غیر از رمزگذاری محتوای فایل استفاده می کند. در هسته های رایج اندروید، این رابط مربوط به عملیات blk_ksm_ll_ops::derive_raw_secret است که باید توسط درایور ذخیره سازی پیاده سازی شود.

برای استخراج inline_encryption_key و sw_secret از کلید ذخیره سازی خام، سخت افزار باید از یک KDF رمزنگاری قوی استفاده کند. این KDF باید بهترین شیوه های رمزنگاری را دنبال کند. باید قدرت امنیتی حداقل 256 بیت داشته باشد، یعنی برای هر الگوریتمی که بعداً استفاده می شود کافی است. همچنین هنگام استخراج هر نوع کلید فرعی باید از یک برچسب متمایز، زمینه، و/یا رشته اطلاعات ویژه برنامه استفاده کند تا تضمین کند که زیرکلیدهای حاصل از نظر رمزنگاری ایزوله هستند، یعنی دانش یکی از آنها هیچ دیگری را آشکار نمی کند. کشش کلید لازم نیست، زیرا کلید ذخیره سازی خام در حال حاضر یک کلید تصادفی یکنواخت است.

از نظر فنی، هر KDF که الزامات امنیتی را برآورده می کند، می تواند مورد استفاده قرار گیرد. با این حال، برای اهداف آزمایش، لازم است دوباره همان KDF را در کد تست پیاده سازی کنید. در حال حاضر، یک KDF بررسی و اجرا شده است. می توان آن را در کد منبع vts_kernel_encryption_test . توصیه می شود که سخت افزار از این KDF استفاده کند که از NIST SP 800-108 "KDF در حالت شمارنده" با AES-256-CMAC به عنوان PRF استفاده می کند. توجه داشته باشید که برای سازگاری، همه بخش‌های الگوریتم باید یکسان باشند، از جمله انتخاب زمینه‌ها و برچسب‌های KDF برای هر کلید فرعی.

بسته بندی کلید

برای دستیابی به اهداف امنیتی کلیدهای سخت افزاری، دو نوع بسته بندی کلید تعریف شده است:

  • بسته بندی زودگذر : سخت افزار کلید خام را با استفاده از کلیدی رمزگذاری می کند که به طور تصادفی در هر بوت ایجاد می شود و مستقیماً در خارج از سخت افزار قرار نمی گیرد.
  • بسته‌بندی طولانی‌مدت : سخت‌افزار کلید خام را با استفاده از یک کلید منحصربه‌فرد و پایدار که در سخت‌افزار تعبیه شده است، رمزگذاری می‌کند که مستقیماً در خارج از سخت‌افزار قرار نمی‌گیرد.

تمام کلیدهایی که برای باز کردن قفل فضای ذخیره‌سازی به هسته لینوکس ارسال می‌شوند، به‌صورت موقتی پیچیده شده‌اند. این تضمین می‌کند که اگر مهاجم بتواند یک کلید در حال استفاده را از حافظه سیستم استخراج کند، آن کلید نه تنها در خارج از دستگاه، بلکه پس از راه‌اندازی مجدد روی دستگاه نیز غیرقابل استفاده خواهد بود.

در عین حال، اندروید همچنان باید بتواند نسخه رمزگذاری شده ای از کلیدها را روی دیسک ذخیره کند تا بتوان در وهله اول قفل آنها را باز کرد. کلیدهای خام برای این منظور کار می کنند. با این حال، مطلوب است که کلیدهای خام به هیچ وجه در حافظه سیستم وجود نداشته باشند تا هرگز نتوان آنها را برای استفاده خارج از دستگاه استخراج کرد، حتی اگر در زمان بوت استخراج شوند. به همین دلیل مفهوم بسته بندی طولانی مدت تعریف شده است.

برای پشتیبانی از مدیریت کلیدهای پیچیده شده به این دو روش مختلف، سخت افزار باید رابط های زیر را پیاده سازی کند:

  • رابط‌هایی برای تولید و وارد کردن کلیدهای ذخیره‌سازی، بازگرداندن آن‌ها به شکل بسته‌بندی شده طولانی‌مدت. این واسط ها به طور غیر مستقیم از طریق KeyMint قابل دسترسی هستند و با برچسب TAG_STORAGE_KEY TAG_STORAGE_KEY مطابقت دارند. توانایی "تولید" توسط vts_kernel_encryption_test vold وارد کردن کلیدهای آزمایشی استفاده می شود.
  • رابطی برای تبدیل یک کلید ذخیره سازی پیچیده شده طولانی مدت به یک کلید ذخیره سازی موقتی. این مربوط به روش convertStorageKeyToEphemeral KeyMint است. این روش هم توسط vold و هم توسط vts_kernel_encryption_test برای باز کردن قفل حافظه استفاده می شود.

الگوریتم بسته بندی کلید یک جزئیات پیاده سازی است، اما باید از یک AEAD قوی مانند AES-256-GCM با IV های تصادفی استفاده کند.

تغییرات نرم افزاری مورد نیاز است

AOSP در حال حاضر یک چارچوب اساسی برای پشتیبانی از کلیدهای سخت افزاری دارد. این شامل پشتیبانی در مولفه‌های فضای کاربری مانند ولد و همچنین پشتیبانی از هسته لینوکس در blk -crypto ، vold و dm-default-key است.

با این حال، برخی تغییرات خاص پیاده سازی مورد نیاز است.

KeyMint تغییر می کند

پیاده سازی KeyMint دستگاه باید برای پشتیبانی از TAG_STORAGE_KEY و پیاده سازی روش convertStorageKeyToEphemeral شود.

در Keymaster، exportKey به جای convertStorageKeyToEphemeral استفاده شد.

تغییرات هسته لینوکس

درایور هسته لینوکس برای موتور کریپتو درون خطی دستگاه باید برای تنظیم BLK_CRYPTO_FEATURE_WRAPPED_KEYS تغییر داده شود، عملیات keyslot_program() و keyslot_evict() از برنامه‌نویسی/اخراج کلیدهای پیچیده‌شده با سخت‌افزار پشتیبانی کند و عملیات derive_raw_secret() را اجرا کند.

آزمایش کردن

اگرچه تست رمزگذاری با کلیدهای سخت‌افزاری سخت‌تر از رمزگذاری با کلیدهای استاندارد است، اما هنوز هم می‌توان با وارد کردن یک کلید تست و اجرای مجدد مشتق کلیدی که سخت‌افزار انجام می‌دهد، آزمایش کرد. این در vts_kernel_encryption_test پیاده سازی شده است. برای اجرای این تست، اجرا کنید:

atest -v vts_kernel_encryption_test

گزارش تست را بخوانید و بررسی کنید که موارد تست کلید پیچیده‌شده با سخت‌افزار (مانند FBEPolicyTest.TestAesInlineCryptOptimizedHwWrappedKeyPolicy و DmDefaultKeyTest.TestHwWrappedKey ) نادیده گرفته نشده‌اند، زیرا از کلیدهای پیچیده‌شده با سخت‌افزار پشتیبانی نمی‌شود، زیرا نتایج تست هنوز شناسایی نمی‌شوند. آن پرونده.

را قادر می سازد

هنگامی که پشتیبانی کلید سخت افزاری دستگاه به درستی کار می کند، می توانید تغییرات زیر را در fstab دستگاه اعمال کنید تا اندروید از آن برای رمزگذاری FBE و ابرداده استفاده کند:

  • FBE: پرچم wrappedkey_v0 را به پارامتر fileencryption اضافه کنید. برای مثال، از fileencryption=::inlinecrypt_optimized+wrappedkey_v0 استفاده کنید. برای جزئیات بیشتر، به مستندات FBE مراجعه کنید.
  • رمزگذاری فراداده: پرچم wrappedkey_v0 را به پارامتر metadata_encryption اضافه کنید. برای مثال، از metadata_encryption=:wrappedkey_v0 استفاده کنید. برای جزئیات بیشتر، به مستندات رمزگذاری ابرداده مراجعه کنید.