![](/img/trans.png)
[英]SHA1 keyed Hash with HMAC in Xamarin Forms PCL [C# equivalent to hash_hmac in PHP]
[英]Raw HMAC-SHA1 in C# — hmac_hash() PHP equivalent
我正在嘗試將Desk.com的Multipass SSO集成到我的網站中,並且無法生成正確的HMAC-SHA1簽名(例如錯誤日志)。 以下是Desk.com網站上的說明:
根據日志,我的多通道令牌似乎是正確的。 首先,PHP中的代碼完美地運行:
// Build an HMAC-SHA1 signature using the multipass string and your API key
$signature = hash_hmac("sha1", $multipass, $api_key, true);
// Base64 encode the signature
$signature = base64_encode($signature);
^請注意hash_hmac的'true'值是以原始二進制文件輸出信息 - 我不確定我的C#代碼是否就是這種情況
接下來,我的C#代碼無法正常工作:
protected string getSignature(string multipass)
{
string api_key = "my_key_goes_here";
HMACSHA1 hmac = new HMACSHA1(Encoding.ASCII.GetBytes(api_key));
hmac.Initialize();
byte[] buffer = Encoding.ASCII.GetBytes(multipass);
string signature = BitConverter.ToString(hmac.ComputeHash(buffer)).Replace("-", "").ToLower();
return Convert.ToBase64String(Encoding.ASCII.GetBytes(signature));
}
這是(字面上)數小時搜索和嘗試多種不同方式的結果。 如果我能理解這一點,我將非常感激。
如果您需要參考,請通過Desk.com查看此頁面: http ://dev.desk.com/docs/portal/multipass。 它有代碼示例,並概述了完成代碼的說明。
編輯:這是我的多通道代碼。
protected string getMultipass(UserData user_data)
{
// Encode the data into a JSON object
JavaScriptSerializer s = new JavaScriptSerializer();
string json_data = s.Serialize(user_data);
// Acquire the Web.config appSettings
string site_key = "my_site_here";
string api_key = "my_key_here";
string iv = "OpenSSL for Ruby";
// Using byte arrays now instead of strings
byte[] encrypted = null;
byte[] bIV = Encoding.ASCII.GetBytes(iv);
byte[] data = Encoding.ASCII.GetBytes(json_data);
// XOR the first block (16 bytes)
// once before the full XOR
// so it gets double XORed
for (var i = 0; i < 16; i++)
data[i] = (byte)(data[i] ^ bIV[i]);
// Pad using block size of 16 bytes
int pad = 16 - (data.Length % 16);
Array.Resize(ref data, data.Length + pad);
for (var i = 0; i < pad; i++)
data[data.Length - pad + i] = (byte)pad;
// Use the AesManaged object to do the encryption
using (AesManaged aesAlg = new AesManaged())
{
aesAlg.IV = bIV;
aesAlg.KeySize = 128;
// Create the 16-byte salted hash
SHA1 sha1 = SHA1.Create();
byte[] saltedHash = sha1.ComputeHash(Encoding.UTF8.GetBytes(api_key + site_key), 0, (api_key + site_key).Length);
Array.Resize(ref saltedHash, 16);
aesAlg.Key = saltedHash;
// Encrypt using the AES managed object
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
csEncrypt.Write(data, 0, data.Length);
csEncrypt.FlushFinalBlock();
}
encrypted = msEncrypt.ToArray();
}
}
// Return the Base64-encoded encrypted data
return Convert.ToBase64String(encrypted, Base64FormattingOptions.None)
.TrimEnd("=".ToCharArray()) // Remove trailing "=" characters
.Replace("+", "-") // Change "+" to "-"
.Replace("/", "_"); // Change "/" to "_"
}
您可以看到以下代碼有效:
static string create(string userDetails) {
string accountKey = "YOUR_ACCOUNT_KEY";
string apiKey = "YOUR_API_KEY";
string initVector = "OpenSSL for Ruby"; // DO NOT CHANGE
byte[] initVectorBytes = Encoding.UTF8.GetBytes(initVector);
byte[] keyBytesLong;
using( SHA1CryptoServiceProvider sha = new SHA1CryptoServiceProvider() ) {
keyBytesLong = sha.ComputeHash( Encoding.UTF8.GetBytes( apiKey + accountKey ) );
}
byte[] keyBytes = new byte[16];
Array.Copy(keyBytesLong, keyBytes, 16);
byte[] textBytes = Encoding.UTF8.GetBytes(userDetails);
for (int i = 0; i < 16; i++) {
textBytes[i] ^= initVectorBytes[i];
}
// Encrypt the string to an array of bytes
byte[] encrypted = encryptStringToBytes_AES(textBytes, keyBytes, initVectorBytes);
string encoded = Convert.ToBase64String(encrypted);
return HttpUtility.UrlEncode(encoded);
}
static byte[] encryptStringToBytes_AES(byte[] textBytes, byte[] Key, byte[] IV) {
// Declare the stream used to encrypt to an in memory
// array of bytes and the RijndaelManaged object
// used to encrypt the data.
using( MemoryStream msEncrypt = new MemoryStream() )
using( RijndaelManaged aesAlg = new RijndaelManaged() )
{
// Provide the RijndaelManaged object with the specified key and IV.
aesAlg.Mode = CipherMode.CBC;
aesAlg.Padding = PaddingMode.PKCS7;
aesAlg.KeySize = 128;
aesAlg.BlockSize = 128;
aesAlg.Key = Key;
aesAlg.IV = IV;
// Create an encrytor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor();
// Create the streams used for encryption.
using( CryptoStream csEncrypt = new CryptoStream( msEncrypt, encryptor, CryptoStreamMode.Write ) ) {
csEncrypt.Write( textBytes, 0, textBytes.Length );
csEncrypt.FlushFinalBlock();
}
byte[] encrypted = msEncrypt.ToArray();
// Return the encrypted bytes from the memory stream.
return encrypted;
}
}
我希望這個對你有用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.