Base32

يرمّز النص أو الأرقام الست عشرية إلى Base32 أو base32hex، بالحشو أو دونه، بأحرف كبيرة أو صغيرة، ويفك ترميزه مجددًا في متصفحك، مع السطر والعمود لأي حرف دخيل.

الإدخال
الإخراج
3GC5RMOYVXMKRWFH

البايتات باثنين وثلاثين محرفًا، والأرقام التي بقيت خارجها

يكتب Base32 البايتات نصًا، باثنين وثلاثين محرفًا يمثّل كل منها خمسة بتات، فكل خمسة بايتات — أي أربعون بتًا — تصير ثمانية محارف. والكلمة Hello خمسة بايتات، وتُكتب JBSWY3DP. اختر «فك الترميز» والصق Base32، فتعيد إليك الصفحة البايتات التي يمثّلها: نصًا، أو بالست عشري إذا اخترت «ست عشري» في «البايتات على هيئة».

والمعيار الذي يعرّفه، RFC 4648، يستخدم الأحرف الكبيرة الستة والعشرين والأرقام من 2 إلى 7. ويذكر الـ RFC سبب غياب 0 و1: فمن يتعامل مع النص قد يخلط بسهولة بين 0 وO، وبين 1 وl أو I، ولذلك تُبقي الأبجدية الأحرف وتترك هذين الرقمين خارجها. وتحتاج الأبجدية إلى جانب الأحرف إلى ستة أرقام، والستة التي تأخذها هي من 2 إلى 7، فليس فيها 8 ولا 9 أيضًا. وعند فك الترميز بهذه الأبجدية، ترفض الصفحة الرقم 0 أو 1 أو 8 أو 9 في موضعه، بدل أن تقرأ 0 على أنه O أو 1 على أنه I: فالـ RFC يسمح للمفكِّك بأن يقرأهما كذلك، ويقول إنه لا ينبغي له ذلك افتراضيًا.

حالة الأحرف ليست جزءًا من القيمة. فقد صمّم RFC 4648 ترميز Base32 لنص يجب أن يُقرأ دون اعتبار لحالة أحرفه، فالنص jbswy3dp هو Hello تمامًا مثل JBSWY3DP. ويكتب الـ RFC أبجديته بأحرف كبيرة، وكذلك تفعل هذه الصفحة ما لم تفعّل خيار «أحرف صغيرة». وتتخطى القراءة أيضًا محارف المسافات في أي موضع، بما فيها فواصل الأسطر، فيُقرأ Base32 المقسّم إلى مجموعات أو على عدة أسطر كأنه كُتب قطعة واحدة.

الحشو، والأطوال التي يأتي بها Base32

نادرًا ما تأتي البايتات خماسيات كاملة. فما يتبقى منها في النهاية، من بايت واحد إلى أربعة، يشغل محرفين أو أربعة أو خمسة أو سبعة، ويحشو RFC 4648 تلك المجموعة الأخيرة بالعلامة = حتى تبلغ ثمانية، فتكون العلامات ستًّا أو أربعًا أو ثلاثًا أو واحدة. وهكذا يكون f هو MY======‎، وfo هو MZXQ====‎، وfoo هو MZXW6===‎، وfoob هو MZXW6YQ=‎، أما fooba، وهو خمسة بايتات، فيملأ ثمانيته تمامًا، ويُكتب MZXW6YTB.

وإذا عُدّت المحارف التي تسبق أي = ثمانيةً ثمانيةً، بقي منها دائمًا 0 أو 2 أو 4 أو 5 أو 7، ولا يبقى أبدًا 1 أو 3 أو 6، لأنه ما من عدد من البايتات يترك ذلك؛ وترفض الصفحة نصًا كهذا عند محرفه الأخير، بدل أن تقرأه على أنه شيء أقصر. والحشو لا يقول شيئًا لا يقوله الطول، لذا تقرأ الصفحة Base32 الذي حُذف حشوه — فـ JBUQ هو Hi تمامًا مثل JBUQ====‎ — ولا ترفض الحشو إلا حيث يكون موجودًا وخاطئًا: علامة = في الوسط يليها مزيد من النص، أو عدد خاطئ من علامات = في النهاية، وعندها يقول الرفض كم علامة ينبغي أن تكون هناك.

عند الترميز، يقرّر خيار «الحشو» ما إذا كانت علامات = تُكتب. وهو مفعّل في البداية، لأن RFC 4648 يطلب الحشو ما لم تقل المواصفة التي تستخدمه غير ذلك، وثمة مواصفات تقول ذلك: فـ Key Uri Format، الذي يصف otpauth:// URI في رمز QR لـ 2FA، يقول إن حشو السرّ ينبغي أن يُحذف، وسجلات NSEC3 وIPFS لا تكتب حشوًا أصلًا. وخيار «أحرف صغيرة» الذي بجانبه يكتب الأحرف صغيرة؛ أما الأرقام والعلامة = فليست لها حالة تتغيّر. ولا يظهر الخياران إلا أثناء الترميز، لأن القراءة تقبل كل تركيب منهما.

والأدوات الأخرى تقرأ أقل مما تقرؤه هذه الصفحة. فـ GNU coreutils يكتب Base32 بالأمر base32، ويكتب base32hex، أي الأبجدية الثانية، بالأمر basenc --base32hex؛ وفي الوحدة النمطية base64 في Python دالة لكل منهما. وكلها تكتب ما تكتبه هذه الصفحة عند فتحها: بالحشو وبأحرف كبيرة. لكن base32 -d يرفض Base32 الذي ينقصه الحشو أو الذي أحرفه صغيرة، ويرفض b32decode في Python الحالتين كذلك، فلا يقرأ الأحرف الصغيرة إلا إذا أُعطي casefold=True:

# الكتابة: الأبجدية الافتراضية ثم الأبجدية الأخرى
printf 'Hi' | base32                          # JBUQ====
printf 'Hi' | basenc --base32hex              # 91KG====

# القراءة من جديد: بالحشو ثم دون حشو ثم بأحرف صغيرة
printf 'JBUQ====' | base32 -d                 # Hi
printf 'JBUQ' | base32 -d                     # base32: invalid input
printf 'jbuq====' | base32 -d                 # base32: invalid input

# الشيء نفسه في سكربت
import base64
base64.b32encode(b'Hi')                       # b'JBUQ===='
base64.b32hexencode(b'Hi')                    # b'91KG===='
base64.b32decode('JBUQ')                      # binascii.Error: Incorrect padding
base64.b32decode('jbuq====', casefold=True)   # b'Hi'

أبجديتان: base32 وbase32hex

يعرّف RFC 4648 أبجدية ثانية، base32hex: الأرقام من 0 إلى 9، ثم الأحرف من A إلى V، فتتوالى محارفها بترتيب القيم التي تمثّلها، من 0 للصفر إلى V للواحد والثلاثين. وهذا يمنحها خاصية تفتقر إليها الأولى، يشير إليها الـ RFC: إذا قورن نصها محرفًا بمحرف، رُتّب بترتيب البايتات التي يمثّلها. فالبايت 00 هو AA======‎ في base32 و‎00======‎ في base32hex، والبايت FF هو ‎74======‎ وVS======‎؛ وعند الترتيب نصًا، يضع base32 البايت FF أولًا، لأن الأرقام تأتي قبل الأحرف في الترتيب، بينما يُبقي base32hex البايتات على ترتيبها.

وتستخدمها سجلات NSEC3 في DNSSEC. فاسم السجل يبدأ ببصمة اسم نطاق، مكتوبة بأبجدية base32hex دون حشو، ويشير RFC 5155 إلى أن الأسماء المبنية على البصمات، إذا كُتبت كذلك، تُرتَّب بالترتيب نفسه الذي تُرتَّب به البصمات بحسب قيمتها. وفي منطقة المثال التي يقدّمها ذلك الـ RFC، تكون بصمة الاسم example هي 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom. وإذا كانت الأبجدية المختارة base32hex، قرأت الصفحة هذه المحارف الـ 32 على أنها بايتات البصمة، وعددها 20؛ وإذا كانت base32، رفضت المحرف 0 — ويقول تنبيه إن النص يُقرأ كاملًا بأبجدية base32hex، بجانب زر يبدّل إليها.

ولأن البايتات نفسها نص مختلف في كل منهما — فـ Hi هو JBUQ====‎ في base32 و91KG====‎ في base32hex — تسري الأبجدية التي تختارها في الاتجاهين كليهما، ولا تغيّرها الصفحة نيابةً عنك أبدًا. وحين يحتوي نص تفك ترميزه على محرف ليس في الأبجدية المختارة، أو ينتهي ببتات زائدة ليست أصفارًا، وهي ما تشرحه الأسئلة أدناه، بينما تقرؤه الأبجدية الأخرى كاملًا كما يكتبه المرمِّز، يقول ذلك تنبيه بجانب زر يبدّل إليها؛ ولا تتغيّر الأبجدية إلا حين تضغط ذلك الزر أو تختارها بنفسك. أما النص الذي تقرؤه الأبجديتان كلتاهما بلا خلل، مثل ABCDEFGH، فيُقرأ بالأبجدية المختارة، إذ لا شيء فيه يدل على أيهما كانت المقصودة.

أين يظهر Base32: أسرار 2FA وعناوين onion وIPFS

بـ Base32 يُكتب السرّ الذي تقوم عليه رموز تطبيق المصادقة في Key Uri Format، الذي يصف otpauth:// URI الذي قد يحمله رمز QR للإعداد: فمعامل secret فيه Base32، وينبغي حذف الحشو منه. الصق سرًّا كهذا بأحرف كبيرة أو صغيرة، في مجموعات تفصل بينها مسافات أو موزّعًا على عدة أسطر، بعلامات = أو بدونها — أما الشرطة بين المجموعات فتُرفض في موضعها — أو الصق الـ URI كاملًا، فتقرأ الصفحة السرّ منه وتقول ذلك. أما ما تعنيه معاملات الـ URI الأخرى، وكيف يصير السرّ الرموز التي يعرضها التطبيق، فمن شأن مولّد رموز TOTP / 2FA: فدليله يشرح الـ URI ومعاملاته، وصفحته تحسب الرموز. والتسمية والمُصدِر في الـ URI مرمَّزان ترميزًا نسبيًا، كما يطلب Key Uri Format، ويقرؤهما مُرمِّز / فاكّ ترميز العناوين.

وعنوان onion في الإصدار 3 من Tor هو Base32 أيضًا. فمحارفه الـ 56 التي تسبق ‎.onion هي Base32 لـ 35 بايتًا: المفتاح العام للخدمة، وطوله 32 بايتًا، ومجموع تحقق من بايتين، وبايت للإصدار، 03. ومواصفة Tor تكتب عناوين الأمثلة فيها بأحرف صغيرة، والبايتات الـ 35 تملأ مجموعات كاملة، فلا حشو فيه لتحذفه. الصق المحارف الـ 56 دون ‎.onion، واختر «ست عشري» في «البايتات على هيئة»، فيُقرأ البايت الأخير 03.

ويكتب IPFS معرّفات المحتوى الخاصة به، أي CID، بـ Base32 افتراضيًا منذ الإصدار 1: بأحرف صغيرة ودون حشو، بعد حرف واحد، b، ليس جزءًا من الـ Base32 بل يسمّيه — وهو بادئة multibase، التي تُنزع قبل فك ترميز البقية. ولذلك فإن bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi، المثال الوارد في وثائق IPFS نفسها، يُرفض هنا كاملًا، على أنه طول لا تنتجه أي بايتات؛ ودون حرفه b يُقرأ على أنه 36 بايتًا، أي الـ CID الثنائي، الذي يبدأ بالبايت 01 دلالةً على إصداره.

سرّ 2FA بايتات، لا نص

السرّ الذي يضربه Key Uri Format مثالًا هو JBSWY3DPEHPK3PXP، وتذكر تلك الوثيقة قيمته صراحةً على أنها عشرة بايتات: محارف Hello!‎، ثم DE AD BE EF. ومحارفه الثمانية الأولى، JBSWY3DP، هي وحدها Hello. وإذا فُك ترميزه هنا و«نص» مختار في «البايتات على هيئة»، وهو اختيار الصفحة الافتراضي، خرج Hello!‎، ثم U+07AD — إذ يكوّن DE AD معًا، مصادفةً، محرفًا واحدًا، هو علامة من كتابة التانة — ثم U+FFFD مرتين، يمثّل كل منهما تسلسلًا ليس نصًا. ويعدّ تنبيه تحت النتيجة التسلسلات المستبدلة، ويقول إن أولها يبدأ عند البايت 9، الذي تبدأ بتاته في المحرف الواقع في السطر 1، العمود 13، أي المحرف 3، ويقول إن البايتات قد لا تكون نصًا أصلًا.

والسرّ الحقيقي بايتات عشوائية، ونادرًا ما تكوّن نصًا، فإذا فُك ترميزه نصًا كان خليطًا مبعثرًا من محارف شاردة ومن U+FFFD، لا يخبرك بشيء عن صحة السرّ. ولهذا وُجد الخيار «ست عشري» في «البايتات على هيئة». اختره، أو اضغط الزر الذي بجانب التنبيه، فيظهر السرّ نفسه كاملًا على هيئة ‎48 65 6C 6C 6F 21 DE AD BE EF: البايتات نفسها، وهي ما يحفظه الخادم وما يُحسب منه كل رمز. ولا تنتقل الصفحة إلى الست عشري من تلقاء نفسها أبدًا، فما يظهر على الشاشة هو دائمًا ما اخترته.

والاتجاه المعاكس هو الاختيار نفسه، يُتّخذ أثناء الترميز. فالمفتاح الذي يحفظه الخادم بالست عشري هو بايتات: اختر «ترميز»، و«ست عشري» في «البايتات على هيئة»، والصقه — مفصولًا بمسافات أو متصلًا، أو مع 0x قبل البايتات، أو مصفوفةً من الأعداد، أو تفريغًا ست عشريًا بتخطيط hexdump -C أو xxd — فتكتب الصفحة الـ Base32 الذي يقبله تطبيق المصادقة. فالست عشري 48656C6C6F21DEADBEEF يصير JBSWY3DPEHPK3PXP، أي السرّ الذي سبق؛ والبايتات العشرة تملأ مجموعات كاملة، أما المفتاح الذي لا يملؤها، كمفتاح من ستة عشر بايتًا، فيخرج وبعده علامات = ما لم تُلغِ خيار «الحشو»، كما يطلب Key Uri Format. أما الست عشري الملصوق خطأً أثناء فك الترميز — عدد زوجي من الأرقام الست عشرية ولا شيء غيرها عدا محارف المسافات، في صورة يستطيع الترميز أن يقرأها على أنها بايتات — فيأتيه تنبيه بأنه يشبه الست عشري، بجانب زر ينتقل إلى ترميزه. وأثناء فك الترميز، يحفظ الزر «تنزيل» البايتات نفسها في ملف اسمه bytes.bin.

Base32 أم Base64، ولماذا لا أبجدية Crockford

يؤدي Base64 العمل نفسه بأربعة وستين محرفًا، أربعة لكل ثلاثة بايتات، فيكون نصه أطول من البايتات بالثلث، بينما يكون نص Base32 أطول منها بثلاثة أخماس. وما يتخلى عنه Base64 مقابل ذلك هو حالة الأحرف: فأبجديته تعدّ الأحرف الكبيرة والصغيرة قيمًا مختلفة، ومعها + و/، فـ SGk=‎ هو Hi، أما sgk=‎ فبايتان آخران. ويناسب Base32 النص الذي يمرّ عبر شيء يتجاهل حالة الأحرف، أو الذي يقرؤه شخص من شاشة ويكتبه في أخرى. وإذا احتوى Base64 ملصوق هنا على + أو /، وهما محرفان لا يكتبهما أي Base32، وكان على هيئة Base64 من أوله إلى آخره، رُفض مع تنبيه بأنه يشبه Base64 ورابط إلى أداة Base64، التي تقرأ Base64 نصًا.

وتوجد أبجديات أخرى من اثنين وثلاثين محرفًا، وهذه الصفحة تقدّم أبجديتَي RFC 4648 ولا تقدّم غيرهما. إحداها أبجدية Douglas Crockford، التي تُبقي الأرقام العشرة كلها وتترك I وL وO وU خارجها، والتي يستخدمها تنسيق ULID. وقد عرّفها Crockford لكتابة الأعداد، وإذا كُتبت بها البايتات كان لها جوابان: فالبايتات الستة عشر من 00 إلى 0F، إذا حُزمت خمسة بتات في كل مرة كما يحزم RFC 4648 البايتات، هي 000G40R40M30E209185GR38E1W، وإذا قُرئت عددًا واحدًا من 128 بتًا، كما تُقرأ محارف ULID الستة والعشرون، هي 00041061050R3GG28A1C60T3GF. والصفحة التي تكتب بها البايتات كانت ستختار نيابةً عنك أحد الجوابين، دون أن يظهر لك ذلك.

الأسئلة الشائعة

لماذا يظهر U+FFFD في السرّ الذي فككت ترميزه؟
لأن سرّ 2FA بايتات عشوائية، والبايتات العشوائية نادرًا ما تكون نصًا بترميز UTF-8. ومع «نص» في «البايتات على هيئة»، تكتب الصفحة كل تسلسل ليس نصًا على هيئة U+FFFD، أي حرف الاستبدال، ويقول تنبيه كم كان عددها وأين يبدأ أولها: عند أي بايت، وفي أي سطر وعمود يقع المحرف الذي تبدأ فيه بتات ذلك البايت. أما البايتات نفسها فلا يمسّها شيء: فالزر الذي بجانب التنبيه يعرضها بالست عشري، والزر «تنزيل» يحفظها. وU+FFFD الموجود فعلًا في نص، أي البايتات EF BF BD، يُقرأ نصًا ولا يُعدّ.
ما معنى «طول لا تنتجه أي بايتات»؟
إذا عُدّت محارف Base32 ثمانيةً ثمانيةً، دون حساب أي =، بقي منها 0 أو 2 أو 4 أو 5 أو 7، أيًّا كانت البايتات، فالنص الذي يبقى منه 1 أو 3 أو 6 لا يمكن أن يمثّل أي بايتات، وترفضه الصفحة عند محرفه الأخير. ومثل هذا النص لم يكتبه مرمِّز على هذا النحو: فقد ضاع منه شيء أو أُضيف إليه في طريقه إليك. فـ JBSWY3DPEHPK3P، أي سرّ Key Uri Format ناقصًا محرفين، يُرفض هناك. وقد يقع القطع أيضًا على طول تنتجه البايتات فعلًا، فيُقرأ النص حينها على أنه بايتات أقل — JBSWY3DPEHPK3PX على أنه تسعة — ولا تستطيع الصفحة أن تلاحظ ذلك إلا حيث لا تكون البتات الزائدة في المحرف الأخير أصفارًا، كما هي حال بتات ذلك الـ X. أما القطع عند حد مجموعة كاملة من ثمانية فلا يترك شيئًا يُلاحظ.
ما البتات الزائدة، ولماذا تقول الصفحة إن بتاتي ليست أصفارًا؟
خمسة بتات لكل محرف وثمانية لكل بايت نادرًا ما تتوافق تمامًا، فما لم تأتِ البايتات خماسيات، يحمل المحرف الأخير من بت واحد إلى أربعة بتات لا يحملها أي بايت، ويكتبها المرمِّز أصفارًا. فـ MZXW6YQ=‎ وMZXW6YR=‎ كلاهما foob: البتات الثلاثة الأخيرة في Q هي 000 وفي R هي 001، والأول وحده هو ما يكتبه المرمِّز. والصفحة تقرأ الاثنين، وفي الثاني يسمّي تنبيهها المحرف R وموضعه، والمحرف Q الذي يكتبه المرمِّز هناك. والبتات الزائدة التي ليست أصفارًا تعني أن النص ليس ما كتبه مرمِّز: فربما قُطع، أو عُدّل يدويًا، أو كُتب بالأبجدية الأخرى، وهذا الاحتمال الأخير تتحقق منه الصفحة نيابةً عنك.
هل Base32 تشفير؟
لا. يغيّر Base32 طريقة كتابة البايتات ولا شيء غير ذلك: يستطيع أي شخص فك ترميزه، وكل مفكِّك يتبع RFC 4648 يستعيد البايتات نفسها بالأبجدية نفسها. وسرّ 2FA المكتوب بـ Base32 هو السرّ نفسه، فكل من يرى مفتاح الإعداد يملك عاملك الثاني.
هل يُرسَل شيء مما ألصقه إلى خادم؟
لا. يعمل الاتجاهان كلاهما في هذه الصفحة على جهازك أنت: لا يُرفع شيء مما تلصقه — سرًّا كان أو نصًا أو أرقامًا ست عشرية — والملف الذي يحفظه الزر «تنزيل» يُنشأ في متصفحك من البايتات الموجودة فيه أصلًا.

أدوات ذات صلة

  • Base64

    يكتب Base64 أربعة محارف لكل ثلاثة بايتات، حيث يكتب Base32 ثمانية لكل خمسة، والحرف الكبير والحرف الصغير في Base64 قيمتان مختلفتان: فالنص abc هناك YWJj، والنص YWJJ يُقرأ هناك abI.

  • مولّد رموز TOTP / 2FA

    أنشئ رموز 2FA ونقّحها، مع الاشتقاق الكامل.

  • مُرمِّز / فاكّ ترميز العناوين

    ترميز نسبي لقيمة مفردة أو لعنوان كامل، والعكس.

  • هروب نصوص JSON

    هروب النص ليصلح داخل سلسلة JSON، أو إعادة نص هارب إلى ما يقوله.