C#--HMAC#u hash()PHP等效格式中的原始HMAC-SHA1

C#--HMAC#u hash()PHP等效格式中的原始HMAC-SHA1,c#,php,C#,Php,我试图将Desk.com的多路径SSO集成到我的网站中,但在生成正确的HMAC-SHA1签名时遇到了问题(比如说错误日志)。以下是Desk.com网站上的说明: 使用多路径API密钥和完成的多路径令牌构建SHA1 HMAC Base64对生成的HMAC进行编码 根据日志,我的多路径令牌似乎是正确的。首先,PHP中完美运行的代码: // Build an HMAC-SHA1 signature using the multipass string and your API key $signatu

我试图将Desk.com的多路径SSO集成到我的网站中,但在生成正确的HMAC-SHA1签名时遇到了问题(比如说错误日志)。以下是Desk.com网站上的说明:

  • 使用多路径API密钥和完成的多路径令牌构建SHA1 HMAC
  • Base64对生成的HMAC进行编码
  • 根据日志,我的多路径令牌似乎是正确的。首先,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查看此页面:。它有代码示例,并概述了完成代码的说明

    编辑:这是我的多路径生成代码

    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 "_"
            }
    
    受保护的字符串getMultipass(UserData user\u data)
    {
    //将数据编码为JSON对象
    JavaScriptSerializer s=新的JavaScriptSerializer();
    字符串json_data=s.Serialize(用户_数据);
    //获取Web.config应用程序设置
    字符串site\u key=“my\u site\u here”;
    字符串api_key=“my_key\u here”;
    string iv=“OpenSSL for Ruby”;
    //现在使用字节数组而不是字符串
    字节[]加密=空;
    byte[]bIV=Encoding.ASCII.GetBytes(iv);
    byte[]data=Encoding.ASCII.GetBytes(json_数据);
    //XOR第一个块(16字节)
    //在完全异或之前一次
    //所以它得到了双重XORed
    对于(变量i=0;i<16;i++)
    数据[i]=(字节)(数据[i]^bIV[i]);
    //使用块大小为16字节的Pad
    int pad=16-(data.Length%16);
    数组.调整大小(参考数据,数据.长度+焊盘);
    对于(变量i=0;i
    您可以看到以下代码:

    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;
          }
        }
    
    静态字符串创建(字符串用户详细信息){
    string accountKey=“您的账户密钥”;
    string apiKey=“您的API密钥”;
    string initVector=“OpenSSL for Ruby”;//不要更改
    byte[]initVectorBytes=Encoding.UTF8.GetBytes(initVector);
    字节[]keyBytesLong;
    使用(SHA1CryptoServiceProvider sha=new SHA1CryptoServiceProvider()){
    keyBytesLong=sha.ComputeHash(Encoding.UTF8.GetBytes(apiKey+accountKey));
    }
    字节[]键字节=新字节[16];
    复制(keyBytesLong,keyBytes,16);
    byte[]textBytes=Encoding.UTF8.GetBytes(userDetails);
    对于(int i=0;i<16;i++){
    textBytes[i]^=initVectorBytes[i];
    }
    //将字符串加密为字节数组
    byte[]encrypted=encryptStringToBytes_AES(textBytes、keyBytes、initVectorBytes);
    字符串编码=Convert.ToBase64String(加密);
    返回HttpUtility.UrlEncode(已编码);
    }
    静态字节[]encryptStringToBytes_AES(字节[]textBytes,字节[]Key,字节[]IV){
    //声明用于加密到内存中的
    //字节数组和RijndaelManaged对象
    //用于加密数据。
    使用(MemoryStream msEncrypt=new MemoryStream())
    使用(RijndaelManaged aesAlg=new RijndaelManaged())
    {
    //为RijndaelManaged对象提供指定的密钥和IV。
    aesAlg.Mode=CipherMode.CBC;
    aesAlg.Padding=PaddingMode.PKCS7;
    aesAlg.KeySize=128;
    aesAlg.BlockSize=128;
    aesAlg.Key=Key;
    aesAlg.IV=IV;
    //创建encrytor以执行流变换。
    ICryptoTransform encryptor=aesAlg.CreateEncryptor();
    //创建用于加密的流。
    使用(CryptoStream csEncrypt=new CryptoStream(msEncrypt,encryptor,CryptoStreamMode.Write)){
    csEncrypt.Write(textBytes,0,textBytes.Length);
    csEncrypt.FlushFinalBlock();
    }
    byte[]encrypted=msEncrypt.ToArray();
    //从内存流返回加密的字节。
    返回加密;
    }
    }
    
    我希望它对你有用