如何在 C # 中实现 Base64 URL 的安全编码?

我想在 C # 中实现 Base64 URL 的安全编码。在 Java 中,我们有通用的 Codec库,它为我提供了一个 URL 安全的编码字符串。如何使用 C # 实现同样的目标?

byte[] toEncodeAsBytes = System.Text.ASCIIEncoding.ASCII.GetBytes("StringToEncode");
string returnValue = System.Convert.ToBase64String(toEncodeAsBytes);

上面的代码将其转换为 Base64,但是它填充了 ==。有没有实现 URL 安全编码的方法?

137635 次浏览

在 URL 中使用 简单地交换字母表是很常见的,因此不需要% 编码; 65个字符中只有3个有问题—— +/=。最常见的替代品是取代 +-和取代 /_。至于填充: 把它取出来(=) ; 您可以 /0所需的填充量。另一方面,只要逆转这个过程:

string returnValue = System.Convert.ToBase64String(toEncodeAsBytes)
.TrimEnd(padding).Replace('+', '-').Replace('/', '_');

与:

static readonly char[] padding = { '=' };

反过来说:

string incoming = returnValue
.Replace('_', '/').Replace('-', '+');
switch(returnValue.Length % 4) {
case 2: incoming += "=="; break;
case 3: incoming += "="; break;
}
byte[] bytes = Convert.FromBase64String(incoming);
string originalText = Encoding.ASCII.GetString(bytes);

然而,有趣的问题是: 这是否与“公共编解码器库”使用的方法相同?这当然是一个合理的首要测试——这是一个相当常见的方法。

下面是另一种解码 url 安全 base64的方法,它与 Marc 的编码方式相同。我只是不明白为什么 4-length%4会起作用(它确实起作用)。

如下所示,只有原点的位长度是6和8的公共倍数,base64不附加“ =”到结果。

1 2 3 4 5 6 7 8|1 2 3 4 5 6 7 8|1 2 3 4 5 6 7 8
1 2 3 4 5 6|1 2 3 4 5 6|1 2 3 4 5 6|1 2 3 4 5 6
"=="            "="

所以我们可以反过来做,如果 result 的比特长度不能被8整除,它被附加:

base64String = base64String.Replace("-", "+").Replace("_", "/");
var base64 = Encoding.ASCII.GetBytes(base64String);
var padding = base64.Length * 3 % 4;//(base64.Length*6 % 8)/2
if (padding != 0)
{
base64String = base64String.PadRight(base64String.Length + padding, '=');
}
return Convert.FromBase64String(base64String);

要获得一个 URL 安全的类似 base64的编码,但是不能使用 RFC4648中的“ base64url”,请使用 System.Web.HttpServerUtility.UrlTokenEncode(bytes)进行编码,并且 解码 System.Web.HttpServerUtility.UrlTokenDecode(bytes)

可以使用命名空间 Microsoft.IdentityModel.Tokens中的类 Base64UrlEncoder

const string StringToEncode = "He=llo+Wo/rld";


var encodedStr = Base64UrlEncoder.Encode(StringToEncode);
var decodedStr = Base64UrlEncoder.Decode(encodedStr);


if (decodedStr == StringToEncode)
Console.WriteLine("It works!");
else
Console.WriteLine("Dangit!");

Microsoft.IdentityModel.Tokens是一个必须下载的 NuGet 软件包。

基于这里的答案和一些性能改进,我们发布了一个非常容易使用的 向 NuGet 实现 url-safe base64和源代码 可以在 GitHub 上找到(MIT 授权)。

使用就像

var bytes = Encoding.UTF8.GetBytes("Foo");
var encoded = UrlBase64.Encode(bytes);
var decoded = UrlBase64.Decode(encoded);

如果使用 ASP.NET Core,另一种选择是使用 Microsoft.AspNetCore.WebUtilities.WebEncoders.Base64UrlEncode

如果您不使用 ASP.NET 内核,WebEncoders可以在 Apache 2.0许可证下使用。

在 UWP 中使用 Microsoft 加密引擎。

uint length = 32;


IBuffer buffer = CryptographicBuffer.GenerateRandom(length);
string base64Str = CryptographicBuffer.EncodeToBase64String(buffer)
// ensure url safe
.TrimEnd('=').Replace('+', '-').Replace('/', '_');


return base64Str;

Karanvir Kang 的回答很好,我投了赞成票。但是,它在字符串的末尾留下一个奇数字符(表示删除的填充字符数)。这是我的解决办法。

var bytesToEncode = System.Text.Encoding.UTF8.GetBytes("StringToEncode");
var bytesEncodedPadded = HttpServerUtility.UrlTokenEncode(bytesToEncode);
var objectIdBase64 = bytesEncodedPadded.Substring(0, bytesEncodedPadded.Length - 1);

最简单的解决办法: (没有填充物)

private static string Base64UrlEncode(string input) {
var inputBytes = System.Text.Encoding.UTF8.GetBytes(input);
// Special "url-safe" base64 encode.
return Convert.ToBase64String(inputBytes)
.Replace('+', '-') // replace URL unsafe characters with safe ones
.Replace('/', '_') // replace URL unsafe characters with safe ones
.Replace("=", ""); // no padding
}

提供者: 索尔

    public string Decode(string str)
{
byte[] decbuff = Convert.FromBase64String(str.Replace(",", "=").Replace("-", "+").Replace("/", "_"));
return System.Text.Encoding.UTF8.GetString(decbuff);
}
    

public string Encode(string input)
{
byte[] encbuff = Encoding.UTF8.GetBytes(input ?? "");
return Convert.ToBase64String(encbuff).Replace("=", ",").Replace("+", "-").Replace("_", "/");
}

这就是与 JavaScript 对齐的方法!