Skip to content

Instantly share code, notes, and snippets.

@marcinotorowski
Last active April 8, 2026 18:57
Show Gist options
  • Select an option

  • Save marcinotorowski/6a51023600160fcceef9ceea341bbc4a to your computer and use it in GitHub Desktop.

Select an option

Save marcinotorowski/6a51023600160fcceef9ceea341bbc4a to your computer and use it in GitHub Desktop.
using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
namespace Otor
{
public class MsixUtils
{
public static string GetPublisherHash(string publisherId)
{
using var sha = HashAlgorithm.Create("SHA256");
var encoded = sha.ComputeHash(Encoding.Unicode.GetBytes(publisherId));
var binaryString = string.Concat(encoded.Take(8).Select(c => Convert.ToString(c, 2).PadLeft(8, '0'))) + '0'; // representing 65-bits = 13 * 5
var encodedPublisherId = string.Concat(Enumerable.Range(0, binaryString.Length / 5).Select(i => "0123456789abcdefghjkmnpqrstvwxyz".Substring(Convert.ToInt32(binaryString.Substring(i * 5, 5), 2), 1)));
return encodedPublisherId;
}
}
}
@marcinotorowski
Copy link
Copy Markdown
Author

This is a compact algorithm that given a publisher ID calculates its hash for APPX-management purposes.

The algorithm:

  1. Takes an UTF-16 encoded string and calculates its SHA-256 hash
  2. It takes the first 8-bytes of the checksum
  3. For each byte, it converts it to a binary representation (8 characters)
  4. Since this gives 8 x 8 = 64 characters, an extra zero ('0') is added to have a string of a length divisible by 5
  5. Then an algorithm processes the bytes in chunk of 5 characters.
    • For each chunk, the 5-character string is converted to an integer (since 2^5 = 32, it produces a number from 0 to 31).
    • It then takes the n-th character of a string 0123456789abcdefghjkmnpqrstvwxyz (32 letters), where n is the result of the previous operation.
  6. Finally, it joins all produced letters, which gives a string of 13 characters

Steps 5 and 6 actually represent the Douglas Crockford Base32 algorithm

Sample input:

E=marcin@otorowski.com, CN=Marcin Otorowski, O=Marcin Otorowski, S=zachodniopomorskie, C=PL

Output:

zxq1da1qqbeze

Verification:

image

@asilichenko
Copy link
Copy Markdown

Thank you, it works for me!
Migrated to Python:

import hashlib

def calculate_publisher_hash(publisher_id):
    encoded = hashlib.sha256(publisher_id.encode("utf-16-le")).digest()

    binary_string = "".join(f"{b:08b}" for b in encoded[:8]) + "0"  # 65 bits = 13 * 5

    alphabet = "0123456789abcdefghjkmnpqrstvwxyz"
    return "".join(
        alphabet[int(binary_string[i * 5:(i + 1) * 5], 2)]
        for i in range(len(binary_string) // 5)
    )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment