【问题标题】:Azure IOT Hub - Device Security TokenAzure IOT 中心 - 设备安全令牌
【发布时间】:2017-01-01 22:45:08
【问题描述】:

所以我们使用 MQTT 连接设备/服务器。我使用 M2Mqtt 库的模拟客户端可以正常工作。我真正苦苦挣扎的是如何在代码中生成密码字段中使用的 签名

我关注了这个https://azure.microsoft.com/en-us/documentation/articles/iot-hub-sas-tokens/,但我正在与 HMAC 方面的事情作斗争。他们所说的“** signingKey**”是什么?那是设备共享访问密钥吗?现在,让模拟客户端在代码中创建自己的签名(而不是通过设备资源管理器)是必不可少的,然后我们甚至担心我们的现场产品是否可以计算这一点(发现这对于现场设备来说真的太复杂了)。除了node.js之外,我可以在其他地方关注C#示例吗?这条线是什么意思“hmac.update(toSign);”

有没有更简单的方法向服务器验证设备?也许只是使用它的共享访问密钥?

抱歉所有问题:/ 可能我只需要关于什么/何时进行 URI 编码/Base64 编码/解码、HMAC 256 等的分步指南,因为我认为文档还远远不够。

"{signature} HMAC-SHA256 签名字符串的形式:{URL-encoded-resourceURI} + "\n" + expiry。重要提示:密钥从 base64 解码并用作执行 HMAC-SHA256 的密钥计算。”

【问题讨论】:

  • 看来我可以只使用自定义协议网关来消除签名的复杂性?通过使用我自己的 IAuthenticationProvider 类???

标签: c# azure mqtt hmac azure-iot-hub


【解决方案1】:

https://azure.microsoft.com/en-us/documentation/articles/iot-hub-sas-tokens/ 页面包含一个 Node.js 函数,该函数从给定的输入生成一个 SAS 令牌。 根据您所说,您正在使用令牌使设备能够连接到您的 IoT 中心,因此 Node 函数的输入应该是:

  • 资源 URI:{IoT 中心名称}.azure-devices.net/devices/{设备 ID}。
  • 签名密钥:{device id} 身份的任何对称密钥。您可以从 IoT 中心设备身份注册表中获取此密钥,例如使用 DeviceExplorer 工具。
  • 没有策略名称。
  • 任何过期时间。

【讨论】:

  • 感谢您的回复。是的,我将花更多时间将 js 转换为可行的 C 函数,以便帮助在设备端生成令牌的固件工程师。可能有几个问题是关于生成这个的确切步骤。
  • 总结我需要更好地解释这一点://使用加密 var decodedPassword = new Buffer(signingKey,'base64').toString('binary'); const hmac = crypto.createHmac('sha256', decodedPassword); hmac.update(toSign); var base64signature = hmac.digest('base64'); var base64UriEncoded = encodeURIComponent(base64signature);
【解决方案2】:

终于明白了:)

    public static string getSaSToken()
    {
        TimeSpan fromEpochStart = DateTime.UtcNow - new DateTime(1970, 1, 1);
        string expiry = Convert.ToString((int)fromEpochStart.TotalSeconds + 3600);

        string baseAddress = "XYZABCBLAH.azure-devices.net/devices/12345".ToLower();
        string stringToSign = WebUtility.UrlEncode(baseAddress).ToLower() + "\n" + expiry;

        byte[] data = Convert.FromBase64String("y2moreblahblahblah=");
        HMACSHA256 hmac = new HMACSHA256(data);
        byte[] poo = hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign));
        string signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));

        string token = String.Format(CultureInfo.InvariantCulture, "SharedAccessSignature sr={0}&sig={1}&se={2}",
                        WebUtility.UrlEncode(baseAddress).ToLower(), WebUtility.UrlEncode(signature), expiry);

        return token;
    }

“12345”是我们设备的序列号。 y2z 的关键.. 将是我们的序列号与其他花哨的 base64 组合(只要它采用 base64 格式以使集线器开心;))

【讨论】:

    【解决方案3】:

    这有一天会对某人有所帮助:

    为 Azure IoT Hub 构建授权标头

    https://github.com/snobu/Azure-IoT-Hub/blob/master/make-token.sh

    #!/usr/bin/env bash
    #
    # GitHub repo:
    #    https://github.com/snobu/Azure-IoT-Hub
    #
    # Construct authorization header for Azure IoT Hub
    #    https://azure.microsoft.com/en-us/documentation/articles/iot-hub-devguide/#security
    #
    # The security token has the following format:
    #    SharedAccessSignature sig={signature-string}&se={expiry}&skn={policyName}&sr={URL-encoded-resourceURI}
    #
    # Author:
    #    Adrian Calinescu (a-adcali@microsoft.com), Twitter: @evilSnobu, github.com/snobu
    #
    # Many things borrowed from:
    #    http://stackoverflow.com/questions/20103258/accessing-azure-blob-storage-using-bash-curl
    #
    # Prereq:
    #    OpenSSL
    #    npm install underscore -g (for the tidy JSON colorized output) - OPTIONAL
    #    Python 2.6 (Might work with 2.5 too)
    #    curl (a build from this century should do)
    
    urlencodesafe() {
        # Use urllib to safely urlencode stuff
        python -c "import urllib, sys; print urllib.quote_plus(sys.argv[1])" $1
    }
    
    iothub_name="heresthething"
    apiversion="2015-08-15-preview"
    req_url="${iothub_name}.azure-devices.net/devices?top=100&api-version=${apiversion}"
    
    sas_key="eU2XXXXXXXXXXXXXXXXXXXXXXXXXXXXX="
    sas_name="iothubowner"
    
    authorization="SharedAccessSignature"
    
    # 259200 seconds = 72h (Signature is good for the next 72h)
    expiry=$(echo $(date +%s)+259200 | bc)
    req_url_encoded=$(urlencodesafe $req_url)
    string_to_sign="$req_url_encoded\\n$expiry"
    
    # Create the HMAC signature for the Authorization header
    #
    # In pseudocode:
    #      BASE64_ENCODE(HMAC_SHA256($string_to_sign))
    #
    # With OpenSSL it's a little more work (StackOverflow thread at the top for details)
    decoded_hex_key=$(printf %b "$sas_key" | base64 -d -w0 | xxd -p -c256)
    signature=$(printf %b "$string_to_sign" | openssl dgst -sha256 -mac HMAC -macopt "hexkey:$decoded_hex_key" -binary | base64 -w0)
    
    # URLencode computed HMAC signature
    sig_urlencoded=$(urlencodesafe $signature)
    
    # Print Authorization header
    authorization_header="Authorization: $authorization sr=$req_url_encoded&sig=$sig_urlencoded&se=$expiry&skn=$sas_name"
    
    echo -e "\n$authorization_header\n"
    
    # We're ready to make the GET request against azure-devices.net REST API
    curl -s -H "$authorization_header" "https://$req_url" | underscore print --color
    
    echo -e "\n"
    

    还有一个用于 Azure IoT Hub 的示例 MQTT 用户/通行证组合(是的,密码很粗略,包括一个空格):

    https://github.com/Azure/azure-content/blob/master/articles/iot-hub/iot-hub-devguide.md#example

    用户名(DeviceId 区分大小写): iothubname.azure-devices.net/DeviceId

    密码(使用设备资源管理器生成 SAS): SharedAccessSignature sr=iothubname.azure-devices.net%2fdevices%2fDeviceId&sig=kPszxZZZZZZZZZZZZZZZZZAhLT%2bV7o%3d&se=1487709501

    【讨论】:

      【解决方案4】:

      下面是如何在 Java 中生成 SAS 令牌:

      import java.io.UnsupportedEncodingException;
      import java.net.MalformedURLException;
      import java.net.URLEncoder;
      import java.nio.charset.StandardCharsets;
      import java.security.InvalidKeyException;
      import java.security.NoSuchAlgorithmException;
      import java.util.Base64;
      import java.util.Date;
      import javax.crypto.Mac;
      import javax.crypto.spec.SecretKeySpec;
      
      public class AzureSasTokenCreator
      {
      
          public static void main(String[] args) throws InvalidKeyException, UnsupportedEncodingException,
                          MalformedURLException, NoSuchAlgorithmException
          {
              String token = generateSasTokenForIotDevice("myiothub.azure-devices.net/devices/mydevice",
                              "ZNILSsz4ke0r5DQ8rfB/PBWf6QqWGV7aaT/iICi9WTc=", 3600);
      
              System.out.println(token);
          }
      
          private static String generateSasTokenForIotDevice(String uri, String devicePrimaryKey, int validtySeconds)
                          throws UnsupportedEncodingException, MalformedURLException, NoSuchAlgorithmException,
                          InvalidKeyException
          {
              Date now = new Date();
              Date previousDate = new Date(1970);
              long tokenExpirationTime = ((now.getTime() - previousDate.getTime()) / 1000) + validtySeconds;
      
              String signature = getSignature(uri, tokenExpirationTime, devicePrimaryKey);
      
              String token = String.format("SharedAccessSignature sr=%s&sig=%s&se=%s", uri, signature,
                              String.valueOf(tokenExpirationTime));
      
              return token;
          }
      
          private static String getSignature(String resourceUri, long expiryTime, String devicePrimaryKey)
                          throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException
          {
              byte[] textToSign = new String(resourceUri + "\n" + expiryTime).getBytes();
              byte[] decodedDeviceKey = Base64.getDecoder().decode(devicePrimaryKey);
              byte[] signature = encryptHmacSha256(textToSign, decodedDeviceKey);
              byte[] encryptedSignature = Base64.getEncoder().encode(signature);
              String encryptedSignatureUtf8 = new String(encryptedSignature, StandardCharsets.UTF_8);
      
              return URLEncoder.encode(encryptedSignatureUtf8, "utf-8");
          }
      
          private static byte[] encryptHmacSha256(byte[] textToSign, byte[] key)
                          throws NoSuchAlgorithmException, InvalidKeyException
      
          {
              SecretKeySpec secretKey = new SecretKeySpec(key, "HmacSHA256");
              Mac hMacSha256 = Mac.getInstance("HmacSHA256");
              hMacSha256.init(secretKey);
              return hMacSha256.doFinal(textToSign);
          }
      }
      

      另请参阅:https://github.com/Breitmann/AzureSasTokenCreator

      【讨论】:

        猜你喜欢
        • 2022-11-02
        • 2019-06-05
        • 2018-11-11
        • 1970-01-01
        • 2017-07-09
        • 2019-04-27
        • 2023-03-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多