簡體   English   中英

使用 C# 計算 AMP 腳本哈希

[英]Calculating AMP Script Hash With C#

我正在嘗試為我們網站的 AMP 腳本計算 AMP 腳本哈希,因此我們不必在每次腳本中的某些內容發生更改時手動更新它們。 我們不使用 node.js 或者我只會使用 amp-script 文檔頁面 ( https://amp.dev/documentation/components/amp-script/ ) 上的給定解決方案。 我已嘗試按照文檔頁面上列出的算法的步驟進行操作,但我無法使哈希與元鏈接實際需要的哈希相匹配。 到目前為止,這是我的代碼...

        // Compute sha384 sum of script contents
        var sha384 = SHA384.Create();
        var hashBytes = sha384.ComputeHash(Encoding.UTF8.GetBytes(model.ScriptContents));
        // Express hash sum as hexadecimal
        var hashHex = BitConverter.ToString(hashBytes);
        // Base64url-encode the result
        var base64 = Convert.ToBase64String(Encoding.ASCII.GetBytes(hashHex)).TrimEnd('=').Replace('+', '-').Replace('/', '_');
        // Prefix with 'sha384-'
        var hash = "sha384-" + base64;

您實際上並不打算返回Base64-of-Base16-of-hash 只是Base64-of-hash 我認為關於“這個和應該用十六進制表示”的部分。 讓你失望:該頁面上的說明是為使用toolbox-script-csp NPM 模塊的 JS 開發人員編寫的,盡管我同意編寫它的人沒有考慮非 JS 開發人員。

計算腳本內容的 SHA384 哈希和。 該總和應以十六進制表示。

相反,請查看toolbox-script-csp中的參考實現:

https://github.com/ampproject/amp-toolbox/blob/main/packages/script-csp/lib/calculateHash.js

function calculateHash(src, {algorithm = DEFAULT_ALGORITHM} = {}) {
  const algo = algorithm.toLowerCase();
  if (!SUPPORTED_ALGORITHMS.has(algo)) {
    throw new Error(`Unsupported algorithm for CSP: ${algo}`);
  }

  if (typeof src === 'string') {
    src = Buffer.from(src, 'utf8');
  }

  const hash = crypto.createHash(algo);
  const data = hash.update(src);
  const base64 = base64URLFormat(data.digest('base64'));
  return `${algo}-${base64}`;
}

function base64URLFormat(base64) {
  return base64.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
}

這可以以一種直接的方式轉換為 C#/.NET,但是......

重要說明:不要使用String來表示您將進行散列服務的 JS 腳本文件:由於在解碼和重新編碼期間元信息丟失,String 的散列通常與原始文件不同,即使腳本的文本內容是相同的。 例如,非規范化的 Unicode 字節在解碼時被規范化,缺少前導字節順序標記( Encoding.UTF8默認呈現,順便說一句!)甚至從\\n\\r\\n的換行符轉換(或副-相反)取決於您的環境是如何設置的。

...因此,下面的代碼使用ReadOnlySpan<Byte>來表示 JS 腳本,而不是System.String


.NET 中的等價物是這樣的:

public static async Task<String> CalculateHashForGoogleAmpAsync( FileInfo jsFile )
{
    // DO NOT read the JS file into a String (and then re-encode it to Byte[] to get the hash)! Doing so will apply a potentially lossy Unicode transformation such that the resultant re-encoded bytes will be different to the source file bytes and so cause the hash to not match the source file.
    // Instead just read the file's raw bytes and hash that (it's much simpler too!)

    Byte[] bytes = await File.ReadAllBytesAsync( jsFile.FullName ).ConfigureAwait(false);
    return CalculateHashForGoogleAmp( js: bytes );
}

public static String CalculateHashForGoogleAmp( ReadOnlySpan<Byte> js )
{
    Byte[] hash          = SHA384.HashData( js );
    String hashBase64    = Convert.ToBase64String( hash );
    String hashBase64Url = hashBase64.TrimEnd('=').Replace('+', '-').Replace('/', '_'); // Or use `Microsoft.AspNetCore.WebUtilities.WebEncoders.Base64UrlEncode`
    return "sha384-" + hashBase64Url;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM