Skip to content
Chrono edited this page Sep 16, 2021 · 4 revisions

This section will be describing how developers can call account recovery related functions in this server API.

Warning: This is a conditional account recovery.. If the keys were lost, it's impossible to perform account recovery.
Warning: However, normal users don't need to worry about account recovery.. If there exists a corporate version, account recovery will play a role

API Root URL: https://mrchewitsoftware.com.my:5001/api/AccountRecovery

Prerequisites:

  1. You must know how to convert data into/from Base64 encoding
  2. You must know how to convert data into URL encoded format
  3. You must know how to read cryptography data that stores on your side through files in binary format/any other applicable format
  4. You must know how to use query string in HttpGet
  5. You must know how to convert data into/from JSON string
https://mrchewitsoftware.com.my:5001/api/AccountRecovery/byUserID?
https://mrchewitsoftware.com.my:5001/api/AccountRecovery/DeletebyUserID?
https://mrchewitsoftware.com.my:5001/api/AccountRecovery/UpdatebyUserID?

These 3 endpoints act differently and have different purposes

1st Endpoint: Request Recovery Data

https://mrchewitsoftware.com.my:5001/api/AccountRecovery/byUserID?

This endpoint was responsible to request account recovery data from server.

Here's an example on how to do it.

public String GetRecoveryData(String UserID)
{
    Byte[] UserIDByte = new Byte[] { };
    Byte[] ETLSSignedUserIDByte = new Byte[] { };
    Boolean ServerOnlineChecker = true;
    String ETLSSessionID = "";
    Byte[] ClientECDSASK = new Byte[] { };
    ETLSSessionID = File.ReadAllText(Application.StartupPath + "\\Temp_Session\\" + "SessionID.txt");
    if (ETLSSessionID != null && ETLSSessionID.CompareTo("") != 0)
    {
        ClientECDSASK = File.ReadAllBytes(Application.StartupPath + "\\Temp_Session\\" + ETLSSessionID + "\\" + "ECDSASK.txt");
        if (UserID != null && UserID.CompareTo("") != 0)
        {
            UserIDByte = Encoding.UTF8.GetBytes(UserID);
            ETLSSignedUserIDByte = SodiumPublicKeyAuth.Sign(UserIDByte, ClientECDSASK,true);
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri("https://mrchewitsoftware.com.my:5001/api/");
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(
                    new MediaTypeWithQualityHeaderValue("application/json"));
                var response = client.GetAsync("AccountRecovery/byUserID?ClientPathID=" + ETLSSessionID + "&SignedUserID=" + HttpUtility.UrlEncode(Convert.ToBase64String(ETLSSignedUserIDByte)));
                try
                {
                    response.Wait();
                }
                catch
                {
                    ServerOnlineChecker = false;
                }
                if (ServerOnlineChecker == true)
                {
                    var result = response.Result;
                    if (result.IsSuccessStatusCode)
                    {
                        var readTask = result.Content.ReadAsStringAsync();
                        readTask.Wait();

                        return readTask.Result;
                    }
                    else
                    {
                        return "Error: Failed to fetch value from server";
                    }
                }
                else
                {
                    return "Error: Server is not online";
                }
            }
        }
        else
        {
            SodiumSecureMemory.SecureClearBytes(ClientECDSASK);
            return "";
        }
    }
    else
    {
        return "";
    }
}

2nd Endpoint: Delete Account Data

https://mrchewitsoftware.com.my:5001/api/AccountRecovery/DeletebyUserID?

This endpoint was responsible to delete account data from server.

Here's an example on how to do it.

public Boolean DeleteAccount(String UserID, Byte[] ED25519PK,Byte[] UserSymmetricKey)
{
    Byte[] UserIDByte = new Byte[] { };
    Byte[] ETLSSignedUserIDByte = new Byte[] { };
    Byte[] ETLSSignedED25519PK = new Byte[] { };
    Byte[] ServerECDHPK = new Byte[] { };
    Byte[] SealedUserSymmetricKey = new Byte[] { };
    Boolean ServerOnlineChecker = true;
    String ETLSSessionID = "";
    String Status = "";
    Byte[] ClientECDSASK = new Byte[] { };
    ETLSSessionID = File.ReadAllText(Application.StartupPath + "\\Temp_Session\\" + "SessionID.txt");
    if (ETLSSessionID != null && ETLSSessionID.CompareTo("") != 0)
    {
        if (UserID != null && UserID.CompareTo("") != 0)
        {
            ClientECDSASK = File.ReadAllBytes(Application.StartupPath + "\\Temp_Session\\" + ETLSSessionID + "\\" + "ECDSASK.txt");
			//This is the server ECDHPK or X25519 PK that developer require to store on client device if client
			//would like to have account recovery.
            ServerECDHPK = File.ReadAllBytes(Application.StartupPath + "\\Temp_Session\\" + ETLSSessionID + "\\ServerECDHPK.txt");
            SealedUserSymmetricKey = SodiumSealedPublicKeyBox.Create(UserSymmetricKey,ServerECDHPK);
            UserIDByte = Encoding.UTF8.GetBytes(UserID);
            ETLSSignedUserIDByte = SodiumPublicKeyAuth.Sign(UserIDByte, ClientECDSASK);
            ETLSSignedED25519PK = SodiumPublicKeyAuth.Sign(ED25519PK, ClientECDSASK,true);
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri("https://mrchewitsoftware.com.my:5001/api/");
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(
                    new MediaTypeWithQualityHeaderValue("application/json"));
                var response = client.GetAsync("AccountRecovery/DeletebyUserID?ClientPathID=" + ETLSSessionID + "&SignedUserID=" + HttpUtility.UrlEncode(Convert.ToBase64String(ETLSSignedUserIDByte)) + "&SignedECDSAPK=" + HttpUtility.UrlEncode(Convert.ToBase64String(ETLSSignedED25519PK))+"&SealedUserSymmetricKey="+HttpUtility.UrlEncode(Convert.ToBase64String(SealedUserSymmetricKey)));
                try
                {
                    response.Wait();
                }
                catch
                {
                    ServerOnlineChecker = false;
                }
                if (ServerOnlineChecker == true)
                {
                    var result = response.Result;
                    if (result.IsSuccessStatusCode)
                    {
                        var readTask = result.Content.ReadAsStringAsync();
                        readTask.Wait();

                        Status = readTask.Result;

                        if (Status.Contains("Error"))
                        {
                            return false;
                        }
                        else
                        {
                            return true;
                        }
                    }
                    else
                    {
                        return false;
                    }
                }
                else
                {
                    return false;
                }
            }
        }
        else
        {
            return false;
        }
    }
    else
    {
        return false;
    }
}

3rd Endpoint: Reset Account Data

https://mrchewitsoftware.com.my:5001/api/AccountRecovery/UpdatebyUserID?

This endpoint was responsible to delete account data from server.

Here's an example on how to do it.

public Boolean ResetAccount(String UserID, Byte[] ED25519PK,Byte[] UserSymmetricKey)
{
    Boolean ResetStatus = false;
    String ETLSSessionID = "";
    RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider();
    Byte[] UserIDByte = new Byte[] { };
    Byte[] MyETLSSignedSecureUserIDByte = new Byte[] { };
    Byte[] ServerECDHPK = new Byte[] { };
    Byte[] SealedUserSymmetricKey = new Byte[] { };
    Byte[] UserLoginED25519PK = new Byte[] { };
    Byte[] UserLoginSignedED25519PK = new Byte[] { };
    Byte[] ETLSSignedUserLoginED25519PK = new Byte[] { };
    Byte[] ETLSSignedUserLoginSignedED25519PK = new Byte[] { };
    Byte[] RandomData = new Byte[128];
    Byte[] CipheredRandomData = new Byte[] { };
    Byte[] NonceByte = new Byte[] { };
    Byte[] CombinedCipheredRandomData = new Byte[] { };
    Byte[] SignedCombinedCipheredRandomData = new Byte[] { };
    Byte[] ETLSSignedSignedCombinedCipheredRandomData = new Byte[] { };
    Byte[] StreamCipherKeyByte = new Byte[] { };
    Byte[] ClientECDSASK = new Byte[] { };
    Byte[] ETLSSignedED25519PK = new Byte[] { };
    Boolean CheckServerBoolean = true;
    RevampedKeyPair MyLoginKeyPair = SodiumPublicKeyAuth.GenerateRevampedKeyPair();
    RevampedKeyPair MyRecoveryKeyPair = SodiumPublicKeyAuth.GenerateRevampedKeyPair();
    String UserIDStoragePath = Application.StartupPath + "\\Application_Data\\User\\";
    ETLSSessionID = File.ReadAllText(Application.StartupPath + "\\Temp_Session\\" + "SessionID.txt");
    if (ETLSSessionID != null && ETLSSessionID.CompareTo("") != 0)
    {
        if (UserID == null || UserID.CompareTo("") == 0)
        {
            //Display Error
        }
        else
        {
            ClientECDSASK = File.ReadAllBytes(Application.StartupPath + "\\Temp_Session\\" + ETLSSessionID + "\\" + "ECDSASK.txt");
            ServerECDHPK = File.ReadAllBytes(Application.StartupPath + "\\Temp_Session\\" + ETLSSessionID + "\\ServerECDHPK.txt");
            SealedUserSymmetricKey = SodiumSealedPublicKeyBox.Create(UserSymmetricKey, ServerECDHPK);
            UserIDByte = Encoding.UTF8.GetBytes(UserID);
            UserLoginED25519PK = MyLoginKeyPair.PublicKey;
            rngCsp.GetBytes(RandomData);
            NonceByte = SodiumSecretBox.GenerateNonce();
            StreamCipherKeyByte = SodiumSecretBox.GenerateKey();
            CipheredRandomData = SodiumSecretBox.Create(RandomData, NonceByte, StreamCipherKeyByte);
            CombinedCipheredRandomData = NonceByte.Concat(CipheredRandomData).ToArray();
            SignedCombinedCipheredRandomData = SodiumPublicKeyAuth.Sign(CombinedCipheredRandomData, MyRecoveryKeyPair.PrivateKey);
            MyETLSSignedSecureUserIDByte = SodiumPublicKeyAuth.Sign(UserIDByte, ClientECDSASK);
            UserLoginSignedED25519PK = SodiumPublicKeyAuth.Sign(UserLoginED25519PK, MyLoginKeyPair.PrivateKey);
            ETLSSignedUserLoginSignedED25519PK = SodiumPublicKeyAuth.Sign(UserLoginSignedED25519PK, ClientECDSASK);
            ETLSSignedUserLoginED25519PK = SodiumPublicKeyAuth.Sign(UserLoginED25519PK, ClientECDSASK);
            ETLSSignedSignedCombinedCipheredRandomData = SodiumPublicKeyAuth.Sign(SignedCombinedCipheredRandomData, ClientECDSASK);
            ETLSSignedED25519PK = SodiumPublicKeyAuth.Sign(ED25519PK, ClientECDSASK,true);
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri("https://mrchewitsoftware.com.my:5001/api/");
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(
                    new MediaTypeWithQualityHeaderValue("application/json"));
                var response = client.GetAsync("AccountRecovery/UpdatebyUserID?ClientPathID=" + ETLSSessionID + "&SignedUserID=" + HttpUtility.UrlEncode(Convert.ToBase64String(MyETLSSignedSecureUserIDByte)) + "&SignedECDSAPK=" + HttpUtility.UrlEncode(Convert.ToBase64String(ETLSSignedED25519PK)) + "&SignedLoginSignedPK=" + HttpUtility.UrlEncode(Convert.ToBase64String(ETLSSignedUserLoginSignedED25519PK)) + "&SignedLoginPK=" + HttpUtility.UrlEncode(Convert.ToBase64String(ETLSSignedUserLoginED25519PK)) + "&SignedCiphered_Recovery_Data=" + HttpUtility.UrlEncode(Convert.ToBase64String(ETLSSignedSignedCombinedCipheredRandomData)) + "&SealedUserSymmetricKey=" + HttpUtility.UrlEncode(Convert.ToBase64String(SealedUserSymmetricKey)));
                try
                {
                    response.Wait();
                }
                catch
                {
                    CheckServerBoolean = false;
                }
                if (CheckServerBoolean == true)
                {
                    var result = response.Result;
                    if (result.IsSuccessStatusCode)
                    {
                        var readTask = result.Content.ReadAsStringAsync();
                        readTask.Wait();

                        var Result = readTask.Result;
                        if (Result.Contains("Error"))
                        {
                            //Display Error
                        }
                        else
                        {
		            //Store Recovery ED25519 PK and SK
			    //Store Recovery Stream Cipher Key
			    //Store Signed Combined Ciphered Random Data(Optional)
                            SodiumSecureMemory.SecureClearBytes(StreamCipherKeyByte);
                            MyRecoveryKeyPair.Clear();
                            MyLoginKeyPair.Clear();
                            ResetStatus = true;
                        }
                    }
                    else
                    {
		        //Display Error
                    }
                }
                else
                {
                    //Server is offline
                }
            }
        }
    }
    else
    {
	//ETLS session must be established
        MyRecoveryKeyPair.Clear();
        MyLoginKeyPair.Clear();
    }
    return ResetStatus;
}
Clone this wiki locally