Base64自定義編碼表及破解

大頭呆發表於2018-12-13

什麼是Base64

Base64是網路上最常見的用於傳輸8Bit位元組程式碼的編碼方式之一,Base64並不是安全領域的加密演算法,其實Base64只能算是一個編碼演算法,對資料內容進行編碼來適合傳輸。標準Base64編碼解碼無需額外資訊即完全可逆,即使你自己自定義字符集設計一種類Base64的編碼方式用於資料加密,在多數場景下也較容易破解。Base64編碼本質上是一種將二進位制資料轉成文字資料的方案。對於非二進位制資料,是先將其轉換成二進位制形式,然後每連續6位元(2的6次方=64)計算其十進位制值,根據該值在A--Z,a--z,0--9,+,/ 這64個字元中找到對應的字元,最終得到一個文字字串。

Base64 編碼要求把 3 個 8 位位元組(3x8=24)轉化為 4 個 6 位的位元組(4x6=24),之後在 6 位的前面補兩個 0 ,形成 8 位一個位元組的形式。 如果剩下的字元不足 3 個位元組,則用 0 填充,輸出字元使用 ‘=’,因此編碼後輸出的文字末尾可能會出現 1 或 2 個 ‘=’。

Base64自定義編碼表及破解

java實現

public abstract class Base64 {
	private static final char[] legalChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
			.toCharArray();

	public static String encode(byte[] data) {
		int start = 0;
		int len = data.length;
		StringBuilder buf = new StringBuilder(data.length * 3 / 2);

		int end = len - 3;
		int i = start;
		int n = 0;

		while (i <= end) {
			int d = ((((int) data[i]) & 0x0ff) << 16)
					| ((((int) data[i + 1]) & 0x0ff) << 8)
					| (((int) data[i + 2]) & 0x0ff);

			buf.append(legalChars[(d >> 18) & 63]);
			buf.append(legalChars[(d >> 12) & 63]);
			buf.append(legalChars[(d >> 6) & 63]);
			buf.append(legalChars[d & 63]);

			i += 3;

			if (n++ >= 14) {
				n = 0;
				buf.append(" ");
			}
		}

		if (i == start + len - 2) {
			int d = ((((int) data[i]) & 0x0ff) << 16)
					| ((((int) data[i + 1]) & 255) << 8);

			buf.append(legalChars[(d >> 18) & 63]);
			buf.append(legalChars[(d >> 12) & 63]);
			buf.append(legalChars[(d >> 6) & 63]);
			buf.append("=");
		} else if (i == start + len - 1) {
			int d = (((int) data[i]) & 0x0ff) << 16;

			buf.append(legalChars[(d >> 18) & 63]);
			buf.append(legalChars[(d >> 12) & 63]);
			buf.append("==");
		}

		return buf.toString();
	}

}

複製程式碼

自定義 Base64 編碼表及破解

標準的base64編碼表是A--Z,a--z,0--9,+,/,但是我們完全可以替換這64個字元或者打亂順序,這樣只有我們知道編碼表才能解碼。通過拼接0~63的6位2進位制字串,然後分割轉換成長度為48的byte陣列,便可以得到編碼表。詳細步驟如下:

  • 計算出0-63這64個數字的6位2進位制數,轉換成字串拼接成一個完整的字串,長度就是64x6
  • 將字串每8個(1byte就是8位)一組,分割成48份,48x8
  • 通過Integer.parseInt(binaryString, 2)解析成數字,再強轉成byte
  • 對這個長度為48的byte陣列進行編碼
  • 編碼的結果就是編碼表了
public class test {

    public static void main(String[] args) {

        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < 64; i++) {
            stringBuilder.append(binary2decimal(i, 6));
        }

        byte[] byteDecode = new byte[48];
        System.out.println(stringBuilder.toString());
        for (int i = 0; i < 48; i++) {
            String binaryString = stringBuilder.substring(i * 8, (i + 1) * 8);
            byteDecode[i] = (byte) Integer.parseInt(binaryString, 2);
        }
        System.out.println(Base64.encode(byteDecode));

    }

    //十進位制轉換為指定位數的二進位制
    private static String binary2decimal(int decNum, int digit) {
        StringBuilder binStr = new StringBuilder();
        for (int i = digit - 1; i >= 0; i--) {
            binStr.append((decNum >> i) & 1);
        }
        return binStr.toString();
    }

}
複製程式碼

列印如下:

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567 89+/
複製程式碼

相關文章