C# Кодировка wsse security password_digest с SHA-1 и Base64 не совпадает с сервером password_digest
Я использую веб-сервис, который требует безопасности wsse в заголовке запросов мыла и состоит из созданного, одноразового номера и пароля. Веб-сервер использует эти значения для авторизации подлинного запроса.
Дайджест пароля создается с использованием следующего алгоритма, как указано в API веб-службы:
Дайджест пароля Профиль OASIS Usertoken определяет и описывает формулу, которая вычисляет уникальную строку Password_Digest, представленную в API XML для доставки. Информация о пароле, используемая в этой формуле, является кодировкой base 64 хэша SHA-1 обычного текстового пароля.
Формула, используемая для построения значения Password_Digest:
Password_Digest = Base64(SHA-1(Nonce + Created + Base64(SHA-1(Password))))
Обратите внимание, что символ + в вышеприведенном алгоритме представляет собой конкатенацию трех строк: Nonce из xml-запроса, Created from xml request и кодирование Base64 дайджеста SHA-1 пароля.
Я работаю с примером запроса XML, который, как известно, был успешно авторизован. Проблема, с которой я сталкиваюсь, заключается в том, что я получаю другое значение для дайджеста пароля, когда пытаюсь воссоздать его со значениями, приведенными в примере.
Примеры значений и ожидаемый password_digest:
Одноразовый номер: 4ETItj7Xc6+9sEDT5p2UjA==
Создано: 2014-08-04T10:22:48.994Z
Пароль: Пароль2014!
Password_Digest: Ug3FRXgyAaWU8SjYHRabnAkn330 =
Вот вывод различных методов, которые я пробовал при попытке воссоздать password_digest
string nonce = "4ETItj7Xc6+9sEDT5p2UjA==";
string created = "2014-08-04T10:22:48.994Z";
string password = "Password2014!";
Способ 1
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=
Способ 2
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=
Способ 3
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=
Способ 4
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 в образце оканчивается на "==", предполагая, что она была закодирована как и как XML-схема для элемента Nonce выглядит следующим образом:
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">4ETItj7Xc6+9sEDT5p2UjA==</wsse:Nonce>
Что говорит о том, что одноразовый номер закодирован в base64, поэтому я попытался перезапустить методы снова, но одноразовый номер был преобразован в обычный текст со следующей строкой
nonce = Encoding.UTF8.GetString(Convert.FromBase64String(nonce));
//nonce = �Dȶ>�s���@�杔�
Исходя из этого, я не думаю, что компания API создаст одноразовый номер, как этот, или мои предположения неверны в отношении шифрования одноразового номера, или я неправильно его декодирую.
Я все еще пытался с новым значением для nonce и получил следующие результаты
Метод 1, 2
//passwordDigest = WcuTBY2W06vv2/JemRuorgxMCns=
Способ 3
//passwordDigest = KPHT7/ojTkvI6kJCaojbp0wKFZ4=
Способ 4
//passwordDigest = NzRBOTM2NUQ2RjAyMjEzN0E1NEVCN0Q0NEExODU2M0U4Q0FEMDkyQg==
Итак, опять нет успеха, и результат метода 3 отличается от метода 1 и 2, который был неожиданным, так как предыдущие методы одноразового использования 1, 2 и 3 дали те же результаты.
1 ответ
Я играю с примером и формулой, а затем я обнаружил, что существительное нужно сначала расшифровать в байты, а затем применить формулу
это полный пример с правильным результатом:
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;
}
}
}