Convert C# function to Elixir

this is the function that I am trying to convert to Elixir:

private static byte[] HashBody(string content)
   {
       var contentBytes = Encoding.UTF8.GetBytes(content);

       using (var provider = new SHA256Managed())
       {
          var hash = provider.ComputeHash(contentBytes);
          return hash;
        }
    }

My attempt:

content = %{
  "id" => "123",
  "name" => "Jaqob"
} |> Poison.encode!

digest = :crypto.hash(:sha256, content)

I want to convert content variable to bytes which is where I am stuck, also is the hashing function correct?

1 Like

Your content variable is already a Binary (an Elixir string is a Binary) so it is already “bytes”.

Your code looks complete to me. Where are you having problems?

1 Like

How about using :erlang.term_to_binary/1? With this you can work with any data you want unlike Poison.

1 Like

I think @easco’s answer is pretty much correct, but I’m guessing what you’re after is maybe a list of bytes? Since your C# code returns an array of bytes? You can use :erlang.binary_to_list/1 on digest to convert the binary to a list.

3 Likes

Thanks for your prompt response @jordan0day , @Eiji , @easco
I needed to convert the map/json to string in order to match the hashed value.
I am now unable to match the Signature, in the elixir code I have include the expected Base64 string:

This is the signature code in C#:

public static string GenerateDigitalSignature(string body, string privateKeyText)
{
var hash = HashBody(body);

byte[] signedHash;
using (var privateKey = ImportPrivateKey(privateKeyText))
{
signedHash = privateKey.SignHash(hash, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
Console.WriteLine("signedHash");
}

var encodedHash = Convert.ToBase64String(signedHash);
Console.WriteLine(encodedHash);

return encodedHash;
}

and this is my code in elixir

def test(conn, _params) do
{:ok, rawSkey} = File.read("/home/danish/www/apis/signtest/keys/private_key.pem")

[encSKey] = :public_key.pem_decode(rawSkey)
sKey = :public_key.pem_entry_decode(encSKey)

string = "{\"MachineName\":\"DESKTOP-04VG548\",\"Userame\":\"inder\",\"Timestamp\":\"2018-10-26T20:58:48.7840832Z\"}"

msg = :crypto.hash(:sha256, string)

signature = :public_key.sign(msg, :sha256, sKey,  [{:rsa_padding, :rsa_pkcs1_padding}])
           |> Base.encode64

#
IO.inspect("signature")
IO.inspect(signature)
IO.inspect("EXPECTED SIGNATURE")
IO.inspect("1FdzHD5FhYFEbV9NpbXpE/CfrvHcv8p/LDQxMd900iZQxrSNbNqwQ/3coWO2Pof3nCmRIPicURyvp3+UrRALp/4eEFprdzmITFh9ojVrOvFI0FYqDsvEDQYvw6G2oX6vVw0b640dg3a+J3A8KEUs3RwSuiilSiqi/CeUzRNFhI3+7aPYF5p0QrAnoNmgmK6GbIY6eu0WnMxyJcGsrkE2KYWCqxrfMq5AiKIPdZVdXfLM6+0AoVw2Q7EgUILNRA91v2QGkdpBwvpHX5Feau2NspS8sq8zdTz8wEVHXC0GjLMqK5M1VvWAW+evYi15qqPOtYHXrvN2KJXjEwSbFdRc7A==")
json conn, "ok"

end

private_key:

-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDo4LOhXxF5f3yU
BhOsyv4wiIn2aMpCiFYOd4X/TufdgBZc4DcTkXOqQ0piIcgnWN0pp9ZTXc5Fmj51
UO2/bs7uZedi/Q7zcHpuI8DB9tCa82cuGkx1uHzTRzQF3cEbkZD/7pC6mopCGOgJ
y8rGZWuKPzcyhNgmo9J0ou04Nkqvzsd3O8STaGd1eF3Q+eb2rWgSLOfYsuO4Fu13
JZJK+IJYA5oj5ci132KEi6LPK9HDHbb4u1ie5J1GvMgVUSD+MK4IP4lcJBbpQP5f
1dAJ4Y2/OTqv66YNeSSOdrVq36l2iSKErImk7B9GjKCuDAMLBgllI/nGgSRK5EdQ
Ke5i9VSlAgMBAAECggEBAImY8yo/JPEYDcDcklV/n4+HrZTFt/R13/suTiNbOQ8c
dpor9P7/60rH9bRj54KwNAU/4RhjDdT8XTkuNzvsOiKMXZqUkXfvlrdrMqKotftI
JEgOS+0ms8KWiLuKmmYyrW07RZKsa1LAqqHXIxn0pQULcw7LhXfXRiuadPXIxnp3
X8KvCy4BGk6J3OtWbhPT7Pz/ImPKc0TxKdiQMkY848ghDpo3+BVT2e69kfFkQd/6
j+ghjjs7RN9jniIxJGJYLDSwVngOaFt8SVe95r4tBw4Kr28T66E7WP8xyLwih6ZA
/+QVQr2f4WZtKSyHxDgfkCh3lvzAEXPBCs782peIYGECgYEA9dlgqaKxyqZwFsvK
dMTTSK9MgqOLKKv16AUMh+Zmvt/kBvqAO6FHqqOw44jYV6XtleUnO54c87/wxtOd
KNHR0tp69fWChwPVAeN42Dby8nG5SMpauE7oi9TkULmBXXVuKFDHw1s9TZ3vw69c
tBiKglI+ulXhWvZNng6vso4YMZkCgYEA8n43dm4ux5kNSszqk3CmhJUMC6yw1/Yo
V1NRAsmJ+3HnRS61TFzij3KjYbO5e975nXxC+S+Mw3vb5PnOUTpIew/ABQyLBAHE
CkNXVr65O+r9ePgFmJEHK8cWF7o5tMO7CxfqJohJFn2u9dq/WuaVhTxZN0r5TIBo
8tYupvsg+u0CgYEA3B5zM68drKn0thRlAsOvwOZjhJxVXmcI12Kd45fg6omfqrfi
1IEEn73MBQ1jVqaT4J+5zuE0XvG97OdPUVr7mORRL6NP6P7/Wp+GdWBNidFU6d1z
+I1+HKTSf4x4TWt049ff5APvEW2VXQnH4OAQM7rbuw5lpYHd4OSZXy9mbhECgYAi
Yo1gyLzvZp+A5M+6enXSRQRBP4qQBQKxZ0oMeCGNuxgNMlNY8a7aomnSd9asXvDM
SQuCJCD0s0J6FIYR9I7EjHYxARdRSSLQRb5DuaWwfmDU326DtMTsiz1xveFi5YJH
T2vPbPHYM5g0moEZ1aqMCwOnmIUDOQ4oqQBSgzeo/QKBgQCJMGKVdG9zVr/za4fS
mQaRm+U8gHoohozgczsD9dB9dHgm7KEXhi+S6LhQfks0GnQvg9MuNfW5zrYXf+rq
DVCOF6jtp3hHDEd+KdDUgikF3FnwGzcq8e1hRLGvcIvqWEb+psimekk1aaAgUyCj
2JOy9eD5+cReQ1vL3Eh6Vtg5vw==-----END PRIVATE KEY-----

what do you reckon I am doing wrong?

This line (above) is unnecessary: your call to :public_key.sign already calculates a SHA256 over the input, so right now the input string is hashed twice. Just pass string instead of msg to the sign function.

3 Likes

BTW, just FYI and FWIW, a bit more idiomatic Elixir would be:

def test(conn, _params) do
  raw_skey = File.read!("/home/danish/www/apis/signtest/keys/private_key.pem")

  [enc_skey] = :public_key.pem_decode(raw_skey)
  skey = :public_key.pem_entry_decode(enc_skey)

  string = ~s("MachineName":"DESKTOP-04VG548","Userame":"inder","Timestamp":"2018-10-26T20:58:48.7840832Z"})

  signature =
    string
    |> :public_key.sign(:sha256, skey,  rsa_padding: :rsa_pkcs1_padding)
    |> Base.encode64

  IO.puts("signature")
  IO.inspect(signature)
  json conn, "ok"
end
5 Likes

thank you @voltone, this resolves my issue.

1 Like