APK Signature Scheme v2

APK Signature Scheme v2 یک طرح امضای کل فایل است که با شناسایی هرگونه تغییر در قسمت های محافظت شده APK، سرعت تأیید را افزایش می دهد و تضمین های یکپارچگی را تقویت می کند .

امضا با استفاده از APK Signature Scheme v2 یک بلوک امضای APK را بلافاصله قبل از بخش ZIP Central Directory در فایل APK وارد می‌کند. در داخل بلوک امضای APK، امضاهای v2 و اطلاعات هویت امضاکننده در یک APK Signature Scheme v2 Block ذخیره می‌شوند.

APK قبل و بعد از امضا

شکل 1. APK قبل و بعد از امضا

APK Signature Scheme v2 در اندروید 7.0 (نوقا) معرفی شد. برای نصب APK روی Android نسخه 6.0 (Marshmallow) و دستگاه‌های قدیمی‌تر، APK باید با استفاده از امضای JAR قبل از امضا شدن با طرح v2 امضا شود.

بلوک امضای APK

برای حفظ سازگاری با فرمت v1 APK، v2 و امضاهای جدیدتر APK در یک بلوک امضای APK ذخیره می‌شوند، یک ظرف جدید برای پشتیبانی از APK Signature Scheme v2. در یک فایل APK، بلوک امضای APK بلافاصله قبل از فهرست مرکزی ZIP، که در انتهای فایل قرار دارد، قرار دارد.

بلوک شامل جفت‌های ID-value است که به‌گونه‌ای پیچیده شده‌اند که مکان‌یابی بلوک را در APK آسان‌تر می‌کند. امضای v2 APK به عنوان یک جفت ID-value با شناسه 0x7109871a ذخیره می‌شود.

قالب

فرمت بلوک امضای APK به شرح زیر است (همه فیلدهای عددی اندکی اند):

  • size of block بر حسب بایت (به استثنای این فیلد) (uint64)
  • دنباله ای از جفت های مقدار شناسه با پیشوند uint64:
    • ID (uint32)
    • value (طول متغیر: طول جفت - 4 بایت)
  • size of block بر حسب بایت - همانند فیلد اول (uint64)
  • magic "APK Sig Block 42" (16 بایت)

APK ابتدا با یافتن شروع فهرست راهنمای مرکزی ZIP (با یافتن رکورد پایان ZIP دایرکتوری مرکزی در انتهای فایل، سپس خواندن آفست شروع دایرکتوری مرکزی از روی رکورد) تجزیه می شود. مقدار magic راهی سریع برای تعیین اینکه آنچه قبل از Central Directory قرار دارد، بلوک امضای APK است. سپس size of block به طور موثر به شروع بلوک در فایل اشاره می کند.

جفت های ID-مقدار با شناسه های ناشناخته باید هنگام تفسیر بلوک نادیده گرفته شوند.

APK Signature Scheme v2 Block

APK توسط یک یا چند امضاکننده/هویت امضا می‌شود که هر کدام با یک کلید امضا نشان داده می‌شوند. این اطلاعات به عنوان یک بلوک APK Signature Scheme v2 ذخیره می شود. برای هر امضا کننده، اطلاعات زیر ذخیره می شود:

  • (الگوریتم امضا، هضم، امضا) تاپل. خلاصه برای جدا کردن تأیید امضا از بررسی یکپارچگی محتوای APK ذخیره می‌شود.
  • زنجیره گواهی X.509 نشان دهنده هویت امضاکننده است.
  • ویژگی های اضافی به عنوان جفت کلید-مقدار.

برای هر امضاکننده، APK با استفاده از یک امضای پشتیبانی شده از لیست ارائه شده تأیید می‌شود. امضاهایی با الگوریتم امضا ناشناخته نادیده گرفته می شوند. این به هر پیاده سازی بستگی دارد که انتخاب کند در صورت مواجه شدن با چندین امضای پشتیبانی شده از کدام امضا استفاده کند. این امکان معرفی روش های امضای قوی تری را در آینده به روشی سازگار با عقب را فراهم می کند. روش پیشنهادی تأیید قوی ترین امضا است.

قالب

APK Signature Scheme v2 Block در داخل بلوک امضای APK تحت شناسه 0x7109871a ذخیره می‌شود.

قالب APK Signature Scheme v2 Block به شرح زیر است (همه مقادیر عددی کمی اندین هستند، همه فیلدهای با پیشوند طول از uint32 برای طول استفاده می کنند):

  • دنباله طول پیشوند signer با پیشوند طول:
    • signed data با پیشوند طول:
      • دنباله پیشوند طولی از digests پیشوند طول:
      • دنباله پیشوند طول certificates X.509 :
        • certificate X.509 با پیشوند طول (فرم ASN.1 DER)
      • دنباله طول-پیشوند از additional attributes طول-پیشوند:
        • ID (uint32)
        • value (طول متغیر: طول ویژگی اضافی - 4 بایت)
    • دنباله طول-پیشوند signatures طول-پیشوند:
      • signature algorithm ID (uint32)
      • signature با پیشوند طول روی signed data
    • public key با پیشوند طول (SubjectPublicKeyInfo، فرم ASN.1 DER)

شناسه های الگوریتم امضا

  • 0x0101—RSASSA-PSS با خلاصه SHA2-256، SHA2-256 MGF1، 32 بایت نمک، تریلر: 0xbc
  • 0x0102—RSASSA-PSS با خلاصه SHA2-512، SHA2-512 MGF1، 64 بایت نمک، تریلر: 0xbc
  • 0x0103—RSASSA-PKCS1-v1_5 با خلاصه SHA2-256. این برای ساخت سیستم هایی است که به امضاهای قطعی نیاز دارند.
  • 0x0104—RSASSA-PKCS1-v1_5 با خلاصه SHA2-512. این برای ساخت سیستم هایی است که به امضاهای قطعی نیاز دارند.
  • 0x0201-ECDSA با هضم SHA2-256
  • 0x0202-ECDSA با هضم SHA2-512
  • 0x0301-DSA با هضم SHA2-256

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

اندازه کلیدهای پشتیبانی شده و منحنی های EC:

  • RSA: 1024، 2048، 4096، 8192، 16384
  • EC: NIST P-256, P-384, P-521
  • DSA: 1024، 2048، 3072

محتوای محافظت شده از یکپارچگی

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

  1. محتویات ورودی های ZIP (از افست 0 تا شروع بلوک امضای APK)
  2. بلوک امضای APK
  3. دایرکتوری مرکزی ZIP
  4. پایان ZIP دایرکتوری مرکزی

بخش های APK پس از امضا

شکل 2. بخش های APK پس از امضا

APK Signature Scheme v2 از یکپارچگی بخش‌های 1، 3، 4 و بلوک‌های signed data APK Signature Scheme v2 Block موجود در بخش 2 محافظت می‌کند.

یکپارچگی بخش های 1، 3 و 4 توسط یک یا چند خلاصه از محتویات ذخیره شده در بلوک های signed data محافظت می شود که به نوبه خود توسط یک یا چند امضا محافظت می شوند.

هضم بخش های 1، 3 و 4 به صورت زیر محاسبه می شود، شبیه به درخت مرکل دو سطحی. هر بخش به تکه های 1 مگابایتی (2 20 بایتی) متوالی تقسیم می شود. آخرین تکه در هر بخش ممکن است کوتاهتر باشد. خلاصه هر تکه بر روی الحاق بایت 0xa5 ، طول تکه بر حسب بایت (uint32 کمی اندین) و محتویات تکه محاسبه می شود. خلاصه سطح بالا بر روی الحاق بایت 0x5a ، تعداد تکه ها (uint32 اندکی اندین)، و الحاق خلاصه های تکه ها به ترتیب ظاهر شدن تکه ها در APK محاسبه می شود. هضم به صورت تکه‌ای محاسبه می‌شود تا با موازی کردن آن، محاسبات را سرعت بخشد.

خلاصه APK

شکل 3. خلاصه APK

حفاظت از بخش 4 (ZIP End of Central Directory) به دلیل بخشی که شامل افست ZIP Central Directory است پیچیده است. هنگامی که اندازه بلوک امضای APK تغییر می کند، به عنوان مثال، هنگامی که یک امضای جدید اضافه می شود، افست تغییر می کند. بنابراین، هنگام محاسبه خلاصه بر روی پایان ZIP دایرکتوری مرکزی، فیلد حاوی افست دایرکتوری مرکزی ZIP باید به عنوان حاوی افست بلوک امضای APK در نظر گرفته شود.

حفاظت های برگشتی

مهاجم می‌تواند سعی کند یک APK با امضای v2 را به عنوان یک APK با امضای v1 در پلتفرم‌های Android که از تأیید APK با امضای v2 پشتیبانی می‌کنند، تأیید کند. برای کاهش این حمله، فایل‌های APK با امضای v2 که دارای امضای v1 نیز هستند، باید دارای ویژگی X-Android-APK-Signed در بخش اصلی فایل‌های META-INF/*.SF خود باشند. مقدار مشخصه مجموعه ای از شناسه های طرح امضای APK جدا شده با کاما است (شناسه این طرح 2 است). هنگام تأیید امضای v1، تأییدکننده APK لازم است فایل‌های APK را که برای طرح امضای APK که تأییدکننده از این مجموعه ترجیح می‌دهد، رد کند (به عنوان مثال، طرح v2). این حفاظت متکی به این واقعیت است که محتویات فایل های META-INF/*.SF توسط امضاهای v1 محافظت می شوند. به بخش تأیید APK امضا شده با JAR مراجعه کنید.

مهاجم می‌تواند سعی کند امضاهای قوی‌تری را از بلوک APK Signature Scheme v2 حذف کند. برای کاهش این حمله، فهرست شناسه‌های الگوریتم امضایی که APK با آن امضا شده است در بلوک signed data ذخیره می‌شود که توسط هر امضا محافظت می‌شود.

تایید

در Android نسخه 7.0 و جدیدتر، فایل‌های APK را می‌توان براساس APK Signature Scheme v2+ یا امضای JAR (طرح v1) تأیید کرد. پلتفرم های قدیمی امضاهای v2 را نادیده می گیرند و فقط امضاهای v1 را تأیید می کنند.

فرآیند تأیید امضای APK

شکل 4. فرآیند تأیید امضای APK (مراحل جدید به رنگ قرمز)

تأیید طرح امضای APK نسخه 2

  1. بلوک امضای APK را پیدا کنید و تأیید کنید که:
    1. دو فیلد اندازه بلوک امضای APK حاوی یک مقدار است.
    2. ZIP Central Directory بلافاصله پس از ZIP End of Central Directory ثبت می شود.
    3. پایان ZIP از دایرکتوری مرکزی با داده های بیشتری دنبال نمی شود.
  2. اولین بلوک APK Signature Scheme v2 را در داخل بلوک امضای APK قرار دهید. اگر v2 Block وجود دارد، به مرحله 3 بروید. در غیر این صورت، به تأیید APK با استفاده از طرح v1 برگردید.
  3. برای هر signer در بلوک APK Signature Scheme v2:
    1. قوی ترین signature algorithm ID پشتیبانی شده را از signatures انتخاب کنید. ترتیب قدرت به هر نسخه پیاده سازی/پلتفرم بستگی دارد.
    2. signature مربوطه را از signatures در برابر signed data با استفاده از public key تأیید کنید. (اکنون تجزیه signed data امن است.)
    3. بررسی کنید که لیست مرتب شده شناسه های الگوریتم امضا در digests و signatures یکسان است. (این کار برای جلوگیری از حذف/افزودن امضا است.)
    4. خلاصه محتویات APK را با استفاده از الگوریتم خلاصه مشابه الگوریتم خلاصه مورد استفاده توسط الگوریتم امضا محاسبه کنید .
    5. بررسی کنید که خلاصه محاسبه شده با digest مربوطه از digests یکسان است.
    6. بررسی کنید که certificates certificate public key یکسان است.
  4. اگر حداقل یک signer پیدا شود و مرحله 3 برای هر signer پیدا شده باشد، تأیید موفقیت آمیز است.

توجه : اگر در مرحله 3 یا 4 مشکلی رخ داد، APK نباید با استفاده از طرح v1 تأیید شود.

تأیید APK با امضای JAR (طرح v1)

APK با امضای JAR یک JAR با امضای استاندارد است که باید دقیقاً حاوی ورودی‌های فهرست‌شده در META-INF/MANIFEST.MF باشد و همه ورودی‌ها باید توسط مجموعه‌ای از امضاکنندگان امضا شوند. یکپارچگی آن به شرح زیر تأیید می شود:

  1. هر امضاکننده با یک ورودی META-INF/<signer>.SF و META-INF/<signer>.(RSA|DSA|EC) JAR نشان داده می شود.
  2. <signer>.(RSA|DSA|EC) یک PKCS #7 CMS ContentInfo با ساختار SignedData است که امضای آن در فایل <signer>.SF تأیید می‌شود.
  3. فایل <signer>.SF حاوی خلاصه فایل کامل META-INF/MANIFEST.MF و خلاصه هر بخش از META-INF/MANIFEST.MF است. خلاصه کل فایل MANIFEST.MF تأیید شده است. اگر این کار انجام نشد، خلاصه هر بخش MANIFEST.MF به جای آن تأیید می شود.
  4. META-INF/MANIFEST.MF شامل، برای هر ورودی JAR محافظت شده با یکپارچگی، یک بخش با نام مربوطه شامل خلاصه محتویات فشرده نشده ورودی است. همه این هضم ها تأیید شده است.
  5. اگر APK حاوی ورودی‌های JAR باشد که در MANIFEST.MF فهرست نشده‌اند و بخشی از امضای JAR نیستند، تأیید APK انجام نمی‌شود.

بنابراین زنجیره حفاظتی <signer>.(RSA|DSA|EC) -> <signer>.SF -> MANIFEST.MF -> محتویات هر ورودی JAR محافظت شده با یکپارچگی است.