รหัสสำหรับถอดรหัส / เข้ารหัส URL base64 ที่แก้ไข


113

ฉันต้องการเข้ารหัสข้อมูล base64 เพื่อใส่ไว้ใน URL แล้วถอดรหัสภายใน HttpHandler ของฉัน

ฉันพบว่าการเข้ารหัส Base64อนุญาตให้มีอักขระ '/' ซึ่งจะทำให้การจับคู่ UriTemplate ของฉันยุ่งเหยิง จากนั้นฉันพบว่ามีแนวคิด "แก้ไข Base64 สำหรับ URL" จาก wikipedia:

มีการแก้ไข Base64 สำหรับตัวแปร URL โดยที่จะไม่มีการใช้ padding '=' และอักขระ '+' และ '/' ของ Base64 มาตรฐานจะถูกแทนที่ด้วย '-' และ '_' ตามลำดับดังนั้นการใช้ตัวเข้ารหัส / ตัวถอดรหัส URL ไม่จำเป็นอีกต่อไปและไม่มีผลกระทบต่อความยาวของค่าที่เข้ารหัสโดยปล่อยให้รูปแบบที่เข้ารหัสเดิมไม่เสียหายสำหรับใช้ในฐานข้อมูลเชิงสัมพันธ์เว็บฟอร์มและตัวระบุอ็อบเจ็กต์โดยทั่วไป

การใช้. NET ฉันต้องการแก้ไขโค้ดปัจจุบันของฉันจากการเข้ารหัสและถอดรหัส base64 พื้นฐานไปสู่การใช้เมธอด "modified base64 for URL" มีใครทำแบบนี้บ้าง?

ในการถอดรหัสฉันรู้ว่ามันเริ่มต้นด้วยสิ่งต่างๆเช่น:

string base64EncodedText = base64UrlEncodedText.Replace('-', '+').Replace('_', '/');

// Append '=' char(s) if necessary - how best to do this?

// My normal base64 decoding now uses encodedText

แต่ฉันอาจต้องเพิ่มตัวอักษร '=' หนึ่งหรือสองตัวต่อท้ายซึ่งดูซับซ้อนกว่าเล็กน้อย

ตรรกะการเข้ารหัสของฉันควรจะง่ายกว่านี้เล็กน้อย:

// Perform normal base64 encoding
byte[] encodedBytes = Encoding.UTF8.GetBytes(unencodedText);
string base64EncodedText = Convert.ToBase64String(encodedBytes);

// Apply URL variant
string base64UrlEncodedText = base64EncodedText.Replace("=", String.Empty).Replace('+', '-').Replace('/', '_');

ฉันเคยเห็นรายการGuid to Base64 สำหรับ URL StackOverflow แต่มีความยาวที่ทราบแล้วดังนั้นพวกเขาจึงสามารถฮาร์ดโค้ดจำนวนเครื่องหมายเท่ากันที่ต้องการในตอนท้ายได้


@ เคิร์ก: ปรับคำตอบของฉันด้วยคณิตศาสตร์ที่ผ่านการทดสอบ
AnthonyWJones

คำตอบ:


69

สิ่งนี้ควรจะทำให้ถูกต้อง: -

 base64 = base64.PadRight(base64.Length + (4 - base64.Length % 4) % 4, '=');

11
คุณเอาชนะฉัน ฉันจะลบโพสต์ของฉันเพราะดูเหมือนว่าฉันคัดลอกคุณ :)
AaronLS

3
สิ่งนี้จะไม่เพิ่มอักขระ '=' สามตัวหรือไม่? ปรากฏว่าจะมีเพียง 0, 1 หรือ 2 เท่านั้น
Kirk Liemohn

1
@Kirk: ถ้ามันเพิ่ม 3 ตัวอักษรสตริง base64 ก็เสียหายแล้ว ฉันเดาว่ามันเป็นความคิดที่ดีที่จะตรวจสอบความถูกต้องของสตริงควรมีเฉพาะอักขระที่คาดไว้และความยาว% 4! = 3
AnthonyWJones

อืมม ในการลองใช้วิธีนี้มันไม่ได้เป็นการหลอกลวง ยังคงมองหาคำตอบ จำนวนเครื่องหมายเท่ากันไม่ได้ปรากฎอย่างถูกต้อง
Kirk Liemohn

2
@AnthonyWJones 'ควรมีเฉพาะอักขระที่คาดไว้และ Length% 4! = 1 ' ใช่ไหม
สีน้ำเงิน

173

ตรวจสอบคลาสHttpServerUtilityด้วยเมธอด UrlTokenEncode และ UrlTokenDecode ที่จัดการการเข้ารหัสและถอดรหัส Base64 URL ที่ปลอดภัย

หมายเหตุ 1: ผลลัพธ์ไม่ใช่สตริง Base64 ที่ถูกต้อง อักขระที่ไม่ปลอดภัยบางตัวสำหรับ URL จะถูกแทนที่

หมายเหตุ 2: ผลลัพธ์แตกต่างจากอัลกอริทึม base64url ใน RFC4648

///<summary>
/// Base 64 Encoding with URL and Filename Safe Alphabet using UTF-8 character set.
///</summary>
///<param name="str">The origianl string</param>
///<returns>The Base64 encoded string</returns>
public static string Base64ForUrlEncode(string str)
{
    byte[] encbuff = Encoding.UTF8.GetBytes(str);
    return HttpServerUtility.UrlTokenEncode(encbuff);
}
///<summary>
/// Decode Base64 encoded string with URL and Filename Safe Alphabet using UTF-8.
///</summary>
///<param name="str">Base64 code</param>
///<returns>The decoded string.</returns>
public static string Base64ForUrlDecode(string str)
{
    byte[] decbuff = HttpServerUtility.UrlTokenDecode(str);
    return Encoding.UTF8.GetString(decbuff);
}

ขอบคุณสำหรับทิป. คราวหน้าจะลองดู!
Kirk Liemohn

12
เคล็ดลับของคุณคือจุดจบอันรุ่งโรจน์ของเวลาหลายชั่วโมงและการค้นหาคำตอบ ขอบคุณ
Praesagus

สิ่งนี้จะไม่ใช้การเข้ารหัส% สำหรับทุกๆ / + และ = หรือไม่ สิ่งนี้ไม่ได้ผลเท่ากับคำตอบอื่น ๆ
JoelFan

ไม่มันจะแทนที่เครื่องหมายเท่ากับที่ใช้ในการเว้นวรรคท้ายด้วยตัวเลขและแทนที่บวกและทับด้วยเครื่องหมายลบและขีดล่าง
Fredrik Haglund

15
โปรดทราบว่าUrlTokenEncodeไม่ใช่base64urlอย่างเคร่งครัดเนื่องจากแทนที่ '=' padding ด้วย '0', '1' หรือ '2' ขึ้นอยู่กับจำนวนเครื่องหมายที่เท่ากันแทนที่
ภาระ

28

มีจุดไม่เพียงพอที่จะแสดงความคิดเห็น แต่ในกรณีนี้จะช่วยได้ข้อมูลโค้ดที่ Sushil พบในลิงก์ที่มีให้ (JSON Web Signature ietf draft) จะทำงานเมื่อเข้ารหัส Base 64 เป็นพารามิเตอร์ใน URL

ตัวอย่างข้อมูลที่คัดลอกด้านล่างสำหรับผู้ที่ขี้เกียจ:

    static string Base64UrlEncode(byte[] arg)
    {
        string s = Convert.ToBase64String(arg); // Regular base64 encoder
        s = s.Split('=')[0]; // Remove any trailing '='s
        s = s.Replace('+', '-'); // 62nd char of encoding
        s = s.Replace('/', '_'); // 63rd char of encoding
        return s;
    }

    static byte[] Base64UrlDecode(string arg)
    {
        string s = arg;
        s = s.Replace('-', '+'); // 62nd char of encoding
        s = s.Replace('_', '/'); // 63rd char of encoding
        switch (s.Length % 4) // Pad with trailing '='s
        {
            case 0: break; // No pad chars in this case
            case 2: s += "=="; break; // Two pad chars
            case 3: s += "="; break; // One pad char
            default: throw new System.Exception(
              "Illegal base64url string!");
        }
        return Convert.FromBase64String(s); // Standard base64 decoder
    }

เข้ากันได้กับ Xamarin ที่ไม่ได้ใช้ System.Web
Reza Mortazavi

สิ่งที่ฉันกำลังมองหา! ตัวเลือกที่ดีจริงๆสำหรับ Xamarin โดยไม่ต้องดึงห้องสมุด
Sleeping_Giant

19

ฉันกดที่นี่ในขณะที่กำลังมองหารหัสเพื่อทำการเข้ารหัส / ถอดรหัสสำหรับการเข้ารหัส base64url ซึ่งแตกต่างจาก base64 เล็กน้อยตามที่อธิบายไว้ในคำถาม

พบข้อมูลโค้ด c # ในเอกสารนี้ JSON Web Signature ietf แบบร่าง


2
นี่เป็นทางออกเดียวที่ใช้ได้ผลสำหรับฉันเมื่อแยกวิเคราะห์ข้อความใน GMail API v1 (Message.Raw)
HeyZiko

5

เมื่อเปรียบเทียบกับคำตอบที่ได้รับการยอมรับนี่คือวิธีพื้นฐานที่คุณจะถอดรหัส URL ที่เข้ารหัส base64 โดยใช้ C #:

Decode:

string codedValue = "base64encodedUrlHere";

string decoded;
byte[] buffer =  Convert.FromBase64String(codedValue);
decoded = Encoding.UTF8.GetString(buffer);

บางทีถ้าคุณให้รายละเอียดเพิ่มเติมและเปรียบเทียบกับคำตอบที่ยอมรับคุณอาจได้รับการโหวตเพิ่ม - ขอบคุณ
Mauricio Gracia Gutierrez
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.