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

How to achieve Base64 URL safe encoding in C#?

我想在C中实现base64 URL安全编码。在Java中,我们有一个通用的EDCOX1×0库,它提供了一个URL安全编码的字符串。如何使用c_实现相同的效果?

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

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


简单地交换字母以在URL中使用是很常见的,因此不需要%编码;65个字符中只有3个有问题-+/=。最常见的替代品是用-代替+,用_代替/。至于填充物:只需去掉它(=);您可以推断所需的填充物数量。在另一端:只是颠倒过程:

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

用:

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

并扭转:

1
2
3
4
5
6
7
8
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);

然而,有趣的问题是:这是"公共编解码器库"使用的相同方法吗?这当然是一个合理的第一件事来测试-这是一个相当常见的方法。


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

1
2
3
4
5
6
7
8
9
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!");


基于这里的答案和一些性能改进,我们发布了一个非常容易使用的URL安全base64实现来nuget,其源代码在GitHub(MIT许可)上可用。

使用起来就像

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


使用system.web.httpserverputility.urltokenencode(bytes)进行编码,以及要解码的system.web.httpserverputility.urltokendecode(字节)。


另一种选择是,如果您使用的是ASP.NET内核,则使用Microsoft.AspNetCore.WebUtilities.WebEncoders.Base64UrlEncode

如果您不使用ASP.NET核心,则可以在Apache2.0许可证下使用WebEncoders源代码。


在UWP中使用Microsoft加密引擎。

1
2
3
4
5
6
7
8
uint length = 32;

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

return base64Str;


这是另一种解码URL安全base64的方法,与marc的编码方法相同。我就是不明白为什么4-length%4起作用了。

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

1
2
3
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
               "=="           "="

所以我们可以反过来做,如果结果的位长度不能被8整除,那么它已经被附加:

1
2
3
4
5
6
7
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);