C# 使用 SHA-1 和 Base64 编码 wsse 安全 password_digest 不匹配服务器 password_digest

标签 c# encoding base64 sha1 wsse

我正在使用一个 Web 服务,它在 soap 请求的 header 中需要 wsse 安全性,并且由创建的、随机数和密码摘要组成。 Web 服务器使用这些值来授权真正的请求。

密码摘要是使用网络服务 API 中所述的以下算法创建的:

Password Digest The OASIS Usertoken profile defines and describes the formula that computes the unique Password_Digest string submitted in the XML For Shipping API the password information used in this formula is the base 64 encoding of the SHA-1 hash of the plain text password.

The formula to use to construct the Password_Digest value is

Password_Digest = Base64(SHA-1(Nonce + Created + Base64(SHA-1(Password))))

请注意,上述算法中的 + 符号表示三个字符串的字符串连接:Nonce from xml request、Created from xml request 和密码的 SHA-1 摘要的 Base64 编码。

我正在处理一个已知已成功获得授权的示例 XML 请求。我遇到的问题是,当我尝试使用示例中提供的值重新创建密码摘要时,我得到了不同的密码摘要值。

示例值和预期的 password_digest:
随机数:4ETItj7Xc6+9sEDT5p2UjA==
创建:2014-08-04T10:22:48.994Z
密码:密码2014!
密码摘要:Ug3FRXgyAaWU8SjYHRabnAkn330=

这是我尝试重新创建 password_digest 时尝试的各种方法的输出

string nonce = "4ETItj7Xc6+9sEDT5p2UjA==";
string created = "2014-08-04T10:22:48.994Z";
string password = "Password2014!";

方法一

string passwordDigest = TestCall.encodeBase64SHA1(nonce + created + TestCall.encodeBase64SHA1(password));

private static string encodeBase64SHA1(string phrase)
{
    UTF8Encoding encoder = new UTF8Encoding();
    SHA1CryptoServiceProvider sha1Hasher = new SHA1CryptoServiceProvider();
    byte[] hashedDataBytes = sha1Hasher.ComputeHash(encoder.GetBytes(phrase));
    return Convert.ToBase64String(hashedDataBytes);
}
//passwordDigest = z5nyI25z7CBUL7l7UkTH8E8azlQ=

方法二

string passwordDigest = TestCall.encodeBase64SHA1Managed(nonce + created + TestCall.encodeBase64SHA1Managed(password));

private static string encodeBase64SHA1Managed(string phrase)
{
    using (SHA1Managed sha1 = new SHA1Managed())
    {
        byte[] hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(phrase));
        return Convert.ToBase64String(hash);
    }
}
//passwordDigest = z5nyI25z7CBUL7l7UkTH8E8azlQ=

方法三

string passwordDigest = TestCall.encodeAsciiToBase64SHA1(nonce + created + TestCall.encodeAsciiToBase64SHA1(password));

private static string encodeAsciiToBase64SHA1(string phrase)
{
    ASCIIEncoding encoder = new ASCIIEncoding();
    SHA1CryptoServiceProvider sha1Hasher = new SHA1CryptoServiceProvider();
    byte[] hashedDataBytes = sha1Hasher.ComputeHash(encoder.GetBytes(phrase));
    return Convert.ToBase64String(hashedDataBytes);
}
//passwordDigest = z5nyI25z7CBUL7l7UkTH8E8azlQ=

方法四

string passwordDigest = TestCall.encodeBase64SHA1HexString(nonce + created + TestCall.encodeBase64SHA1HexString(password));

private static string encodeBase64SHA1HexString(string phrase)
{
    UTF8Encoding encoder = new UTF8Encoding();
    SHA1CryptoServiceProvider sha1Hasher = new SHA1CryptoServiceProvider();
    byte[] hashedDataBytes = sha1Hasher.ComputeHash(encoder.GetBytes(phrase));

    StringBuilder output = new StringBuilder();
    for (int i = 0; i < hashedDataBytes.Length; i++)
    {
        output.Append(hashedDataBytes[i].ToString("X2"));
    }
    return Convert.ToBase64String(Encoding.UTF8.GetBytes(output.ToString()));
}
//passwordDigest =RjE4REQyRDg5MjFGMkZCNTM2MTMwOEM1MTkzRDc1RTZCNDgwMjhCNQ==

所有方法均未创建与样本匹配的 password_digest。方法 1 - 3 至少创建了与示例具有相同字符数的 password_digest,所以我假设编码在字符串的末尾字节数匹配的意义上是部分正确的,这是否正确?

我的问题是任何人都可以使用提供的示例值帮助重新创建 password_digest 吗?

我只想提一下,这是我第一次使用 ws-security 并且几乎没有接触过 SHA-1 和字符串编码/解码,因此非常感谢任何帮助。

注意:

示例中的 nonce 字符串以“==”结尾,表明它已被编码,Nonce 元素的 xml 模式如下:

<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">4ETItj7Xc6+9sEDT5p2UjA==</wsse:Nonce>

这表明 nonce 已编码为 base64,因此我尝试再次重新运行这些方法,但使用以下行将 nonce 转换为纯文本

nonce = Encoding.UTF8.GetString(Convert.FromBase64String(nonce));
//nonce = �Dȶ>�s���@�杔�

从结果来看,我认为 API 公司不会创建这样的随机数,或者我对随机数被加密的假设是错误的,或者我没有正确解码它。

我仍然尝试使用 nonce 的新值并得到以下结果

方法一、二

//passwordDigest = WcuTBY2W06vv2/JemRuorgxMCns=

方法三

//passwordDigest = KPHT7/ojTkvI6kJCaojbp0wKFZ4=

方法四

//passwordDigest = NzRBOTM2NUQ2RjAyMjEzN0E1NEVCN0Q0NEExODU2M0U4Q0FEMDkyQg==

因此再次没有成功,方法 3 的结果与方法 1 和 2 不同,这是出乎意料的,因为之前的 nonce 方法 1、2 和 3 给出了相同的结果。

最佳答案

我玩了例子和公式,然后我发现需要先将 nounce 解码为字节,然后再应用公式

这是具有正确结果的完整示例:

class Program
{
    static void Main(string[] args)
    {
        // Base64(SHA-1(Nonce + Created + Base64(SHA-1(Password))))

        string nonce = "4ETItj7Xc6+9sEDT5p2UjA==";            
        string createdString = "2014-08-04T10:22:48.994Z";
        string password = "Password2014!";

        string basedPassword = System.Convert.ToBase64String(SHAOneHash(Encoding.UTF8.GetBytes(password)));
        byte[] combined = buildBytes(nonce, createdString, basedPassword);
        string output = System.Convert.ToBase64String(SHAOneHash(combined));

        Console.WriteLine("result is: " + output); // Ug3FRXgyAaWU8SjYHRabnAkn330=
        Console.ReadKey();
    }

    private static byte[] buildBytes(string nonce, string createdString, string basedPassword)
    {
        byte[] nonceBytes = System.Convert.FromBase64String(nonce);    
        byte[] time = Encoding.UTF8.GetBytes(createdString);
        byte[] pwd = Encoding.UTF8.GetBytes(basedPassword);

        byte[] operand = new byte[nonceBytes.Length + time.Length + pwd.Length];
        Array.Copy(nonceBytes, operand, nonceBytes.Length);
        Array.Copy(time, 0, operand, nonceBytes.Length, time.Length);
        Array.Copy(pwd, 0, operand, nonceBytes.Length + time.Length, pwd.Length);

        return operand;
    }

    public static byte[] SHAOneHash(byte[] data)
    {
        using (SHA1Managed sha1 = new SHA1Managed())
        {
            var hash = sha1.ComputeHash(data);
            return hash;
        }
    }
}

关于C# 使用 SHA-1 和 Base64 编码 wsse 安全 password_digest 不匹配服务器 password_digest,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25262909/

相关文章:

java - DES-加密字节数组,java

java - 将 base64 字符串图像显示为超链接

javascript - DevExtreme:添加带有 base64 图标的标记

c# - DataSet 在什么依赖中?

c# - 为什么 ThreadPool 线程不打印任何内容到控制台,除非主线程先打印

python - 在 Python 2.7 中打印重音字符

python - 无法解析 Google Play 应用评分数据

python - base64 类型错误,TypeError : expected bytes, 不是 str

c# - 反序列化不同类型的JSON数组

c# - 使用 C# 格式化和打印 HTML 页面