Base32

קידוד טקסט או הקסדצימלי ל־Base32 או ל־base32hex, עם ריפוד או בלעדיו, באותיות גדולות או קטנות, ופענוח חזרה בדפדפן שלך, עם השורה והעמודה של תו שאינו במקומו.

קלט
פלט
26U5PHGXSXLZ2===

בייטים בשלושים ושניים תווים, והספרות שנשארו בחוץ

Base32 כותב בייטים כטקסט, בשלושים ושניים תווים שכל אחד מהם מייצג חמישה ביטים, כך שכל חמישה בייטים — ארבעים ביטים — הופכים לשמונה תווים. Hello הוא חמישה בייטים, והוא נכתב JBSWY3DP. בחרו «פענוח» והדביקו Base32, והעמוד מחזיר את הבייטים שה־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, אומר שיש להשמיט את הריפוד של סוד, ו־IPFS ורשומות NSEC3 אינם כותבים ריפוד כלל. המתג «אותיות קטנות» שלידו הופך את האותיות לקטנות; לספרות ולסימן = אין רישיות שאפשר לשנות. שני המתגים מוצגים רק בזמן קידוד, כי הקריאה מקבלת כל צירוף שלהם.

כלים אחרים קוראים פחות ממה שהעמוד הזה קורא. 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 מבקש, והכלי מקודד / מפענח URL קורא אותם.

גם כתובת onion בגרסה 3 של Tor היא Base32. 56 התווים שלה שלפני ‎.onion הם ה־Base32 של 35 בייטים: המפתח הציבורי בן 32 הבייטים של השירות, checksum של שני בייטים ובייט גרסה, 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 יוצרים במקרה תו אחד, סימן של כתב Thaana — ואחר כך שני 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, עם הגזירה המלאה.

  • מקודד / מפענח URL

    קידוד אחוזים לערך בודד או לכתובת שלמה, ובחזרה.

  • בריחת מחרוזות JSON

    בריחת טקסט למחרוזת JSON, או קריאה של טקסט בָּרוּח בחזרה.