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

Java转C#:MD5签名代码迁移、签名无效问题排查及排序优化

Fixing MD5 Signature Mismatch When Porting Java Code to C# (With Built-In Key Sorting)

Looks like you're already halfway there—you figured out that sorting parameters by key was the missing piece, but you want to clean up the code by moving that sorting logic directly into your GenerateSign method instead of handling it manually every time. Let's break down how to align your C# code perfectly with the original Java implementation, and fix any subtle mismatches that might have caused the signature failure.

First, Match the Java Logic Step-by-Step

The original Java code does three critical things your initial C# code missed or handled differently:

  1. Sorts parameters by key (ordinal string order) before concatenation
  2. Does NOT URL-encode parameter values (your initial C# code was doing this, which would definitely break the signature)
  3. Concatenates all entries without extra null/empty filtering (unless your business requires it, the Java code doesn't include this)

Revised C# Code With Built-In Sorting

Here's the updated code that integrates key sorting directly into GenerateSign, and aligns 1:1 with the Java implementation:

using System.Text;
using System.Security.Cryptography;
using System.Collections.Generic;
using System.Linq;

// ...

private static string GenerateSign(Dictionary<string, object> query, string apiSecret) 
{ 
    var sb = new StringBuilder(); 
    // 1. Sort dictionary entries by key using ordinal order (matches Java's comparingByKey())
    var sortedParams = query.OrderBy(kvp => kvp.Key, StringComparer.Ordinal);

    // 2. Concatenate key=value pairs separated by & (no URL encoding!)
    foreach (var kvp in sortedParams)
    {
        // Optional: Uncomment if you need to skip null/empty values (match your initial logic)
        // if (string.IsNullOrWhiteSpace(kvp.Value?.ToString()))
        //     continue;

        if (sb.Length > 0)
            sb.Append('&');
        
        sb.Append(kvp.Key)
          .Append('=')
          .Append(kvp.Value?.ToString() ?? string.Empty);
    }

    // 3. Append the required api_secret parameter
    if (sb.Length > 0)
        sb.Append('&');
    
    sb.Append("api_secret=").Append(apiSecret); 
    return sb.ToString(); 
} 

private static string Sign(string source) 
{ 
    using var md5 = MD5.Create(); 
    var sourceBytes = Encoding.UTF8.GetBytes(source); 
    var hash = md5.ComputeHash(sourceBytes); 

    // Convert bytes to lowercase hex string, mirroring Java's exact logic
    var output = new StringBuilder(hash.Length * 2);
    foreach (byte b in hash)
    {
        int current = b & 0xff;
        if (current < 16)
            output.Append('0');
        output.Append(current.ToString("x")); // "x" ensures lowercase hex
    }
    return output.ToString();
}

Key Fixes & Explanations

  • Built-in sorting: The OrderBy(kvp => kvp.Key, StringComparer.Ordinal) uses the same ordinal, culture-insensitive sorting as Java's Map.Entry.comparingByKey(), so you no longer need to sort the dictionary manually before calling the method.
  • Removed URL encoding: The original Java code doesn't encode parameter values, so removing HttpUtility.UrlEncode ensures the input string to MD5 matches exactly what the Java code uses.
  • Exact hex conversion: While your original Sign method worked, the revised byte-to-hex logic mirrors Java's implementation perfectly, eliminating any potential edge cases (though both approaches produce the same result here).
  • Optional null handling: If you need to skip empty/null values like your initial code did, uncomment the filtering check. Just make sure this matches the Java code's behavior—if Java includes empty values, remove the check entirely.

How to Use It

Now you can call the methods directly without pre-sorting the dictionary:

var @params = new Dictionary<string, object> { 
    { "api_key", _apiKey }, 
    { "req_time", now }, 
    { "op", "sub.personal" } 
}; 
var signature = Sign(GenerateSign(@params, _apiSecret));

This should produce an identical signature to the Java code every time.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 23:08:14