1. نظرة عامة
1.ما هو Base64:
يعد Base64 أحد أكثر طرق التشفير شيوعًا لنقل رموز البايت 8 بت على الإنترنت. يمكنك التحقق من RFC2045~RFC2049، الذي يحتوي على مواصفات تفصيلية لـ MIME. يمكن استخدام ترميز Base64 لتمرير معلومات تعريف أطول في بيئة HTTP. على سبيل المثال، في نظام السبات Java Persistence، يتم استخدام Base64 لتشفير معرف فريد طويل (عادةً UUID 128 بت) في سلسلة، والتي يتم استخدامها كمعلمات في نماذج HTTP وعناوين HTTP GET. في التطبيقات الأخرى، غالبًا ما يكون من الضروري تشفير البيانات الثنائية في نموذج مناسب لوضعها في عنوان URL (بما في ذلك حقول النماذج المخفية). في هذا الوقت، استخدام ترميز Base64 ليس فقط أقصر، ولكنه أيضًا غير قابل للقراءة، أي أن البيانات المشفرة لن تكون مرئية مباشرة بالعين المجردة.
2. المقدمة:
Standard Base64 غير مناسب للإرسال مباشرة في عنوان URL، لأن برنامج تشفير URL سيغير الأحرف "/" و"+" في Base64 القياسي إلى شكل "%XX"، وهذه الأحرف "%" موجودة عند الدخول إلى قاعدة البيانات ، يلزم إجراء مزيد من التحويل نظرًا لاستخدام علامة "%" كحرف بدل في ANSI SQL.
لحل هذه المشكلة، يمكن استخدام ترميز Base64 المحسّن لعناوين URL، والذي لا يحشو علامة '=' في النهاية ويغير "+" و"/" في Base64 القياسي إلى "*" و"-" على التوالي. ، وهذا يلغي الحاجة إلى التحويل أثناء تشفير عنوان URL وفك تشفيره وتخزين قاعدة البيانات، ويتجنب الزيادة في طول المعلومات المشفرة في العملية، ويوحد تنسيق معرفات الكائنات في قواعد البيانات والنماذج وما إلى ذلك.
يوجد أيضًا متغير Base64 محسّن للتعبيرات العادية، والذي يغير "+" و"/" إلى "!" و"-" لأن "+" و"*" و"كلاهما [" و"]" قد يكون لهما معاني خاصة في التعبيرات العادية.
هناك أيضًا متغيرات تغير "+/" إلى "_-" أو "._" (تستخدم كأسماء معرفات في لغات البرمجة) أو ".-" (تستخدم لـ Nmtokens في XML) أو حتى "_ :" (للاسم) في XML).
يتطلب Base64 تحويل كل ثلاث بايتات 8 بت إلى أربع بايتات 6 بت (3*8 = 4*6 = 24)، ثم إضافة 0 بتات عالية إلى 6 بت لتكوين أربع بايتات 8 بت، أي أن السلسلة المحولة ستكون نظريًا 1/3 أطول من الأصلي.
3. القواعد:
قواعد حول هذا التشفير:
①.تحويل 3 أحرف إلى 4 أحرف..
②.أضف حرف سطر جديد كل 76 حرفًا..
③.يجب أيضًا معالجة الإنهاء النهائي..
أليس هذا مجردا جدا؟ لا تقلق، دعونا نلقي نظرة على مثال:
قبل التحويل: aaaaaabb ccccdddd eeffffff
بعد التحويل: 00aaaaaa 00bbcccc 00ddddee 00ffffff
ينبغي أن يكون واضحا، أليس كذلك؟ البايتات الثلاث العليا هي النص الأصلي، والبايتات الأربع السفلية هي ترميز Base64 المحول، حيث تكون أول بتتين 0.
بعد التحويل، نستخدم جدول التعليمات البرمجية للحصول على السلسلة التي نريدها (أي ترميز Base64 النهائي).
2. مثال على كود تنفيذ Java:
public Final class Base64 { static Private Final int BASELENGTH = 255; static Private Final int SIXTEENBIT = 16; = 6؛ نهائي خاص ثابت FOURBYTE = 4؛ نهائي خاص ثابت int SIGN = -128; static Private Final boolean fDebug = false; static Final Private byte[] base64Alphabet = new byte[BASELENGTH]; lookUpBase64Alphabet = new char[LOOKUPLENGTH ]; ثابت { for (int i = 0; i < BASELENGTH; i++) { base64Alphabet[i] = -1 } for (int i = 'Z'; i >= 'A'; i--) { base64Alphabet[i] = (بايت) (i - 'A' } for (int i = 'z'; i >= 'a';-) { base64Alphabet[i] = (بايت) (i - 'a' + 26); >= '0';--) { base64Alphabet[i] = (بايت) (i - '0' + 52); } base64Alphabet['+'] = 62; int i = 0; i <= 25; 26, j = 0; i <= 51; i++, j++) lookUpBase64Alphabet[i] = (char) ('a' + j); ) lookUpBase64Alphabet[i] = (char) ('0' + j); lookUpBase64Alphabet[62] = (char) '+'; lookUpBase64Alphabet[63] = (char) '/' } protected static boolean isWhiteSpace(char octect) { return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9)); منطقية ثابتة isPad(char octect) { return (octect == PAD); } protected boolean isBase64(char octect) { return (base64Alphabet[octect] != -1); } /** * تشفير الأشكال الثمانية السداسية في Base64 * * @param BinaryData * مصفوفة تحتوي على BinaryData * @return Encoded Base64 array */ public static String encode(byte[] BinaryData) { if (binaryData == null) return null; } int lessThan24bits = lengthDataBits % TWENTYFOURBITGROUP; TWENTYFOURBITGROUP; int numberQuartet = lessThan24bits != 0 ? numberTriplets + 1 : numberTriplets; int numberLines = (numberQuartet - 1) / 19 + 1; = 0، ل = 0، ب1 = 0، b2 = 0, b3 = 0; int encodedIndex = 0; int i = 0; 0; line < numberLines - 1 line++) { for (int quartet = 0; quartet < 19; quartet++) { b1 = ثنائي البيانات[dataIndex++]; b2 = ثنائي البيانات[dataIndex++]; b3 = ثنائي البيانات[dataIndex++]; + b3); } l = (بايت) (b2 & 0x0f k = (بايت) (b1 & 0x03); ((b1 & SIGN) == 0) ? (بايت) (b1 >> 2) : (بايت) ((b1) >> 2 ^ 0xc0); بايت) (b2 >> 4) : (بايت) ((b2) >> 4 ^ 0xf0)؛ بايت val3 = ((b3 & SIGN) == 0) ? (بايت) (b3 >> 6) : (بايت) ((b3) >> 6 ^ 0xfc); println("k4 = " + (k << 4)); System.out.println("vak = " + (val2 | (k << 4))); encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 |.encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << val3] | lookUpBase64Alphabet[b3 & 0x3f]; } encodedData[encodedIndex++] = 0xa; } for (; i < numberTriplets; i++) { b1 = BinaryData[dataIndex++]; (fDebug) { System.out.println("b1= " + b1 + ", b2= " + b2 + ", b3= " + b3 } l = (بايت) (b2 & 0x0f); = 0) ? (بايت) (b1 >> 2) : (بايت) ((b1) >> 2 ^ 0xc0); ((b2 & SIGN) == 0) ? (بايت) (b2 >> 4) : (بايت) ((b2) >> 4 ^ 0xf0); بايت) (b3 >> 6) : (بايت) ((b3) >> 6 ^ 0xfc); System.out.println("val2 = " + val2); System.out.println("k4 = " + (k << 4)); System.out.println("vak = " + (val2 | (k < < 4))); } encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; lookUpBase64Alphabet[val2 |.encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << val3] | مجموعات البت إذا (أقل من 24 بت == EIGHTBIT) { b1 = ثنائي البيانات[dataIndex] k = (بايت) (b1 & 0x03); if (fDebug) { System.out.println("b1=" + b1); " + (b1 >> 2)); } بايت val1 = ((b1 & SIGN) == 0) ? (بايت) (b1 >> 2) : (بايت) ((b1) >> 2 ^ 0xc0); encodedData[encodedIndex++] = lookUpBase64Alphabet[val1]; encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4] = PAD; إذا (أقل من 24 بت == SIXTEENBIT) { b1 = ثنائي البيانات[dataIndex]; b2 = ثنائي البيانات[dataIndex + 1]; == 0) ؟ (بايت) (b1 >> 2) : (بايت) ((b1) >> 2 ^ 0xc0); بايت val2 = ((b2 & SIGN) == 0) ? (بايت) (b2 >> 4) : (بايت) ((b2) >> 4 ^ 0xf0); ; encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | 4)]; encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2]; encodedData[encodedIndex++] = PAD; } encodedData[encodedIndex] = 0xa; return new String(encodedData); * @param ثنائي البيانات * مجموعة بايت تحتوي على بيانات Base64 * @return Array يحتوي على ind البيانات التي تم فك تشفيرها */ public static byte[] decode(String encoded) { if (encoded == null) return null; if (len % FOURBYTE != 0) { return null;// يجب أن يكون قابلاً للقسمة على أربعة } int numberQuadruple = (len / FOURBYTE); if (numberQuadruple == 0) return byte new[0]; byte decodedData[] = null; d1 = 0, d2 = 0, d3 = 0, d4 = 0; int i = 0; = 0; int dataIndex = 0; decodedData = new byte[(numberQuadruple) * 3]; for (; i < numberQuadruple - 1; i++) { if (!isData((d1 = base64Data[dataIndex++])) || !isData ((d2 = base64Data[dataIndex++])) ||. !isData((d3 = base64Data[dataIndex++])) ||!isData((d4 = base64Data[dataIndex++]))) return null;// إذا لم يتم العثور على "لا توجد بيانات"، فما عليك سوى إرجاع null b1 = base64Alphabet[d1] b2 = base64Alphabet[d2]; = base64Alphabet[d3] b4 = base64Alphabet[d4]; = (بايت) (b1 << 2 | b2 >> 4); ((b3 >> 2) & 0xf)); encodedIndex++] = (بايت) (b3 << 6 | b4 } if (!isData((d1 = base64Data[dataIndex++])) ||!isData((d2 = base64Data[dataIndex++]))) { return null;// إذا لم يتم العثور على "لا توجد بيانات"، فما عليك سوى إرجاع null } b1 = base64Alphabet[d1]; ; d3 = base64Data[dataIndex++]; (!isData((d3)) || !isData((d4))) {// تحقق مما إذا كانت أحرف PAD if (isPad(d3) && isPad(d4)) { // اثنان PAD على سبيل المثال 3c[Pad][ Pad] if ((b2 & 0xf) != 0)// آخر 4 بتات يجب أن تكون صفر return byte[] tmp = new byte[i * 3 + 1]؛ System.arraycopy(decodedData, 0, tmp, 0, i * 3); tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4); d3) && isPad(d4)) {// لوحة واحدة على سبيل المثال 3cQ[Pad] b3 = base64Alphabet[d3]; if ((b3 & 0x3) != 0)// يجب أن تكون البتتان الأخيرتان صفرًا return byte[] tmp = new byte[i * 3 + 2]; tmp, 0, i * 3); tmp[encodedIndex++] = (بايت) (b1 << 2 | b2 >> 4); tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf)); return tmp } else { return null;// خطأ مثل " 3c[Pad]r"، "3cdX"، "3cXd"، "3cXX" // حيث X ليس بيانات } } else { // No PAD على سبيل المثال 3cQl b3 = base64Alphabet[d3]; b4 = base64Alphabet[d4]; decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4); << 4) |. ((b3 >> 2) & 0xf)); decodedData[encodedIndex++] = (byte) (b3 << 6 | b4); ) * @return the new length */ protected static int RemoveWhiteSpace(char[] data) { if (data == null) return 0; مسافة بيضاء int newSize = 0; int len = data. length; for (int i = 0; i < len; i++) { if (!isWhiteSpace(data[i])) data[newSize++] = data[i]; } return newSize } public static void main(String[] args) { System.out.println(encode("جمهورية الصين الشعبية".getBytes()));