C#でBase64 URLセーフエンコーディングを実現するにはどうすればよいですか?


104

C#でBase64 URLセーフエンコーディングを実現したい。JavaにはCodec、URLを安全にエンコードした文字列を提供する共通ライブラリがあります。C#を使用して同じようにするにはどうすればよいですか?

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

上記のコードはそれをBase64に変換しますが、パディングします==。URLセーフエンコーディングを実現する方法はありますか?


Url.Encode文字列で使用することはできませんBASE64か?

どの名前空間のUrlクラスがC#に存在しますか?
Vishvesh Phadnis 2014年

見てくださいmsdn.microsoft.com/en-us/library/…System.Webアセンブリを参照する必要があります。

=を%3Dに変換しています。私はそれを望まない。
Vishvesh Phadnis 2014年

3
それであなたはどういう意味url safeですか?%3DURLセーフです。

回答:


181

%エンコーディングが不要になるように、URLで使用するために単にアルファベット交換するのが一般的です。わずか3 65の文字は問題がある- +/=。最も一般的な代替品がある-の代わりに、+_の代わりに/。パディングについては、それを削除するだけ=です(); 必要なパディングの量を推測できます。反対側:プロセスを逆にしてください:

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);

ただし、興味深い質問は次のとおりです。これは、「共通コーデックライブラリ」が使用するアプローチと同じですか?それは確かにテストするための合理的な最初のことでしょう-これはかなり一般的なアプローチです。


1
一般的なコーデックでは、URLセーフモードに[0-9a-zA-Z_-]文字を使用しています。
Vishvesh Phadnis 2014年

これは、URLアプリケーションの下のBase64のwikiページにも記載されています。en.wikipedia.org/wiki/Base64
ワンスター2015

2
また、この関数 ' stackoverflow.com/questions/1886686/… 'を使用して、すべてのハードワークを実行します。
toy4fun 2017年

1
なぜ必要ないのか:ケース1:着信+ = "==="; ブレーク; ?
アレックスダフランカ

5
@alexdafrancaは、mod 4の長さが1になることは決してないためです。3x8ビットは4x6ビットになり(各6ビットは選択したアルファベットの64文字の1つです)、0x8ビットはパディングなしで0x6ビットとしてエンコードされ、1x8ビットは次のようにエンコードされます==パディング付き2x6ビット、2x8は=パディング付き3x6としてエンコードされ、3x8はパディングなしの4x6としてエンコードされ、それが繰り返されるように配置されます。1x6ビットにエンコードされるものはないため、===パディングは必要ありません。
George Helyar

83

Base64UrlEncoder名前空間のクラスを使用できますMicrosoft.IdentityModel.Tokens

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!");

1
これは受け入れられた答えよりもはるかにきれいです。欠点はありますか?
taktak004 2017

18
注:Microsoft.IdentityModel.Tokensは、ダウンロードする必要があるNuGetパッケージです。
Uber Schnoz 2017年

これはクロスプラットフォームではないという名前で仮定しています。それは事実ですか?
Brandon S.


8

ここでの回答に基づいてパフォーマンスを改善し、GitHub(MITライセンス)で入手可能なソースコードを使用して、非常に使いやすいURLセーフのbase64実装をNuGet に公開しました

使い方は簡単

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

本当にありがとうございます。関心の外になぜあなたはを選択している"string".Replaceためencodeの方法が、のためのマニュアル置き換えでループdecode
ᴍᴀᴛᴛʙᴀᴋᴇʀ

@ᴍᴀᴛᴛʙᴀᴋᴇʀ再確認していくつかのベンチマークを実行する必要がありますが、これは、後者に追加して、不変文字列ではなく拡張可能な文字のリストで表すためです。
Mahmoud Al-Qudsi

代わりに、戻り値の型=文字列を別のクラス:github.com/vndevpro/architecture-common/blob/master/...
hazjack

8

RFC4648に従って「base64url」ではなく、URLセーフなbase64のようなエンコーディングを取得するにはSystem.Web.HttpServerUtility.UrlTokenEncode(bytes)、エンコードとSystem.Web.HttpServerUtility.UrlTokenDecode(bytes)デコードに使用し ます。


6
これは、RFC4648に準拠した標準に準拠したURLセーフのBase64エンコーディングを提供しません。こちらのQ&Aもご覧ください。注意して使用してください。
Artjom B.

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
  }

クレジットは次のとおりです:Tholle


0

Marcと同じ方法でエンコードされた、URLセーフなbase64をデコードする別の方法を次に示します。なぜ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
                "=="            "="

したがって、逆にそれを行うことができます。結果のビット長が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);

0

UWPでのMicrosoft暗号化エンジンの使用。

uint length = 32;

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

return base64Str;

0

Karanvir Kangの回答は良いものであり、私はそれに投票しました。ただし、文字列の末尾に奇数文字が残ります(削除された埋め込み文字の数を示します)。これが私の解決策です。

var bytesToEncode = System.Text.Encoding.UTF8.GetBytes("StringToEncode"); 
var bytesEncodedPadded = HttpServerUtility.UrlTokenEncode(bytesToEncode);
var objectIdBase64 = bytesEncodedPadded.Substring(0, bytesEncodedPadded.Length - 1);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.