You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript与C#编码QNAP NAS密码时特殊字符输出差异排查

Why does special character encoding differ between C# and QNAP's JavaScript API?

The core issue here is a mismatch in how you're converting the intermediate string back to bytes in your C# code. Let's break this down step by step:

Root Cause

Your Utf16to8 function correctly converts the input UTF-16 string to UTF-8 bytes, then wraps each byte into a char (resulting in a string of U+00xx characters where xx is the original UTF-8 byte value).

However, when you use Encoding.UTF8.GetBytes(utf8Input) on this string, you're re-encoding those U+00xx characters as UTF-8. For characters in the U+0080 to U+00FF range (like à = U+00C3 or ¤ = U+00A4), UTF-8 uses two bytes instead of one. This doubles the number of bytes for non-ASCII characters, leading to a longer Base64 output than the JavaScript version.

In contrast, QNAP's JavaScript script uses btoa, which takes each character's low 8 bits directly as a byte (treating the string as Latin-1/ISO-8859-1 encoded). This preserves the original UTF-8 byte sequence, so the Base64 output matches the expected result.

Solution

You have two straightforward fixes to align your C# code with the JavaScript behavior:

Option 1: Skip the intermediate string step (simplest)

Directly convert the input string to UTF-8 bytes and encode to Base64, cutting out the unnecessary Utf16to8 function entirely:

public static class EncodeHelper {
    public static string Encode(string input) {
        byte[] utf8Bytes = Encoding.UTF8.GetBytes(input);
        return Convert.ToBase64String(utf8Bytes);
    }
}

This works because QNAP's API expects the password to be UTF-8 encoded then Base64'd, which is exactly what this code does.

Option 2: Use Latin-1 encoding for the intermediate string

If you need to keep the Utf16to8 logic (for consistency with your existing code structure), replace Encoding.UTF8.GetBytes with Encoding.GetEncoding("ISO-8859-1").GetBytes. Latin-1 maps each U+00xx character directly to a single byte, preserving the original UTF-8 sequence:

public static class EncodeHelper {
    private const string EzEncodechars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    public static string Utf16to8(string input) {
        byte[] utf16Bytes = Encoding.Unicode.GetBytes(input);
        byte[] utf8Bytes = Encoding.Convert(Encoding.Unicode, Encoding.UTF8, utf16Bytes);
        char[] chars = (char[])Array.CreateInstance(typeof(char), utf8Bytes.Length);
        for (int i = 0; i < utf8Bytes.Length; i++) {
            chars[i] = BitConverter.ToChar(new byte[2] { utf8Bytes[i], 0 }, 0);
        }
        return new string(chars);
    }
    public static string Encode(string input) {
        var utf8Input = Utf16to8(input);
        var plainTextBytes = Encoding.GetEncoding("ISO-8859-1").GetBytes(utf8Input);
        return Convert.ToBase64String(plainTextBytes);
    }
}

Verification

For the input äçéè:

  • Both fixes will produce the Base64 string w6TDp8Opw6g=, which matches the JavaScript output from QNAP's get_sid.js.
  • Your original C# code produced a longer string because it was re-encoding the intermediate string with UTF-8, expanding each non-ASCII character to two bytes.

内容的提问来源于stack exchange,提问作者Cornelis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 22:44:08