10.4. Signing a message with C#

The following code shows how a challenge may be signed using C#.

Firstly, the user needs to obtain a challenge string:

  • C#

    ...
    
    static HttpClient client = new HttpClient();
    
    //specify to use TLS 1.2 as default connection
    System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
    
    client.BaseAddress = new Uri("https://app.smartbl.io/");
    // Add an Accept header for JSON format.
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    
    ...
    
    public static string GetChallenge() {
        HttpResponseMessage response = await client.GetAsync("https://app.smartbl.io/api/v1/challenge/");
        response.EnsureSuccessStatusCode();
    
        challengeresponse = await response.Content.ReadAsAsync<ChallengeResponse>();
    
        return challengeresponse.challenge_string;
    }
    

This challenge is then signed using the SHA-3 and user’s private key. The following method will sign a challenge using C#.

Important

This use case expect the system to have full access to the private key. This means that the user will need to submit the key to the application. This has two security implications:

  • the key might be compromised if the application or trasfer path is not secure

  • it's not possible to use hardware keys as they by default do not allow the private key to be exported in any way

This approach is the most appropriate if you decide to store the private keys on behalf of your users in your database. Either way make sure that private keys are never stored anywhere in plain text -- always encrypt the data before storage.

  • C#

    public static string SignChallenge(string challenge, string privateKey) {
        var hasher = new Sha3Keccack();
        var hash = hasher.CalculateHash(challenge);
        return SignHash(hash, privateKey);
    }
    
    public static string SignHash(string hash, string privateKey) {
        var signer = new MessageSigner();
        var hasher = new Sha3Keccack();
        var byteList = new List<byte>();
    
        var bytePrefix = "0x19".HexToByteArray();
        var textBytePrefix = Encoding.UTF8.GetBytes("Ethereum Signed Message:\n" + hash.HexToByteArray().Length);
        var bytesMessage = hash.HexToByteArray();
    
        byteList.AddRange(bytePrefix);
        byteList.AddRange(textBytePrefix);
        byteList.AddRange(bytesMessage);
        var hashPrefix2 = hasher.CalculateHash(byteList.ToArray()).ToHex();
        return signer.Sign(hashPrefix2.HexToByteArray(), privateKey);
    }