[C#] Base32 编码/解码方法 不分大小写的编码方式

前阵子在教学一篇 Base64 及 Base64Url 编码 的方法,有提到可以将网址上传送的资料采用 Base64 编码。

但今天遇到一个特别的问题,因为网站上某些网址已经被搜寻引擎收录,偶尔会有一些爬虫程序到我的页面上,而爬虫程序使用的网址竟然全改为小写,而我原本使用大小写有别的 Base64 参数,造成解码错误。

例如我原网址为: /Index/StraInfo/MTk0
参数 MTk0 可被 Base64 解码

可是爬虫程序呼叫网址为: /index/straInfo/mtk0
程序收到的参数为 mtk0 经过 Base64 解码就无法正确还原了。

为了让爬虫程序使用全小写网址可以正常浏览我的网站,我将原本 Base64 编码的方式改为 Base32 编码。
Base32 编码为不分大小写的编码方式,编码後可用的字母为
abcdefghijklmnopqrstuvwxyz234567

使用 Base32 编码结果放在网址上当参数,也不会因为对方更改大小写而造成解码错误

Base32 编码与解码的方法

以下是我使用 Base32 编码与解码的方法

/// <summary>
/// Base 32 编码
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public string EncodeBase32(string value)
{
	if (string.IsNullOrEmpty(value)) return null;

	string Alphabet = "abcdefghijklmnopqrstuvwxyz234567";
	var valueBytes = Encoding.UTF8.GetBytes(value);
	var encodedBuilder = new StringBuilder();
	var position = 0;
	var left = 0;
	for (var i = 0; i < valueBytes.Length * 8 / 5 + (valueBytes.Length * 8 % 5 == 0 ? 0 : 1); i++)
	{
		var encodedByte = default(byte);
		if (left > 0)
		{
			encodedByte |= (byte)(valueBytes[position] << (8 - left));
			if (left <= 5 && position < valueBytes.Length - 1)
			{
				position++;
				if (left < 5) encodedByte |= (byte)(valueBytes[position] >> left);
			}
		}
		else
		{
			encodedByte |= valueBytes[position];
		}
		encodedBuilder.Append(Alphabet[(byte)(encodedByte >> 3)]);
		left = 8 * (position + 1) - 5 * (i + 1);
	}
	return encodedBuilder.ToString();
}

/// <summary>
/// Base 32 解码
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public string DecodeBase32(string value)
{
	if (string.IsNullOrEmpty(value)) return null;
	string Alphabet = "abcdefghijklmnopqrstuvwxyz234567";
	value = value.ToLower().TrimEnd('=');

	var decodedBytes = new byte[value.Length * 5 / 8];
	var position = 0;
	var available = 0;

	for (var i = 0; i < value.Length; i++)
	{
		var symbol = (byte)(Alphabet.IndexOf(value[i]) << 3);
		if (available > 0)
		{
			decodedBytes[position] |= (byte)(symbol >> (8 - available));
			if (available <= 5 && position < decodedBytes.Length - 1)
			{
				decodedBytes[++position] |= (byte)(symbol << available);
			}
		}
		else
		{
			decodedBytes[position] |= symbol;
		}
		available = 8 * (position + 1) - 5 * (i + 1);
	}
	return Encoding.UTF8.GetString(decodedBytes);
}

程序码中的语法
string Alphabet = "abcdefghijklmnopqrstuvwxyz234567";
可以修改为
string Alphabet = " ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
这样编码结果字母就可以为全大写。

Base32 优缺点比较

使用 Base32 当网址参数有几个好处

  1. 适用不分大小写的环境
  2. 数字少了 0, 1 ,避免与 O, I 混淆
  3. 当网址参数不需要用 HttpUtility.UrlEncode() 再编码

而缺点的话包含

  1. 编码後长度膨胀约 60%,比 Base64 膨胀 33% 还多。
  2. 在 .Net 没有内建支援的方法,需要自己写。
  3. 并非为常见编码方式

有关 Base32 的编码说明可以参考维基百科

相关学习文章

[C#] Convert.ToBase64String 基本转码及适用网址参数转码延伸应用


<<:  eztool ERP使用心得文

>>:  TP-LINK ARCHER C60及TL-WR841N有线接WAN的AP模式和有线桥接差在那?

[DAY 28] 用google sheet 做简易UI介面(3/3)

题库一个人不容易维护 如果想要多人共用试算表 就会怕有些人动到你设定好的格式 此时可以选择保护工作表...

KSP 的实作方向

这系列的文章不会讲完全部 KSP 的实作,毕竟我也还正在实作中,不过实作的方向应该是跟前几篇讲的差不...

练习严谨

我自己秉持着最少力气解决问题,但换句话说就是,有点得过且过,尤其如果快要放假的时候,这时候“选对环境...

Day#06 新增

前言 昨天已经在storyboard上将tableView连结上程序中的table,不过并没有解释到...

AI ninja project [day 25] QLattice -- 基础分类

你听过的有AI框架有scikit-learn(机器学习)、tensorflow(深度学习)、pyto...