/// <summary>
    /// 解密Comment
    /// </summary>
    /// <param name="ori"></param>
    private void DecryptText(string ori)
    {
        var result = AesUtils.Decrypt(ori, UIPanel163Key.AesKey);

        Debug.Log("" + result);
        mIpResult.text = result;
    }
        public void Can_Send_Encrypted_Message()
        {
            var client = CreateClient();

            var request = new HelloSecure {
                Name = "World"
            };

            var aes = new AesManaged {
                KeySize = AesUtils.KeySize
            };

            var aesKeyBytes       = aes.Key.Combine(aes.IV);
            var rsaEncAesKeyBytes = RsaUtils.Encrypt(aesKeyBytes, SecureConfig.PublicKeyXml);

            var timestamp = DateTime.UtcNow.ToUnixTime();

            var requestBody = timestamp + " POST " + typeof(HelloSecure).Name + " " + request.ToJson();

            var encryptedMessage = new EncryptedMessage
            {
                EncryptedSymmetricKey = Convert.ToBase64String(rsaEncAesKeyBytes),
                EncryptedBody         = AesUtils.Encrypt(requestBody, aes.Key, aes.IV)
            };
            var encResponse = client.Post(encryptedMessage);

            var responseJson = AesUtils.Decrypt(encResponse.EncryptedBody, aes.Key, aes.IV);
            var response     = responseJson.FromJson <HelloSecureResponse>();

            Assert.That(response.Result, Is.EqualTo("Hello, World!"));
        }
Beispiel #3
0
        public (string token, Key privateKey) Login(string email, string password, string pin)
        {
            string token = api.Auth.PostAuthResponse(new AuthenticateModel()
            {
                Email    = email,
                Password = password
            }).Validate.StatusCode(HttpStatusCode.OK).Validate.NoApiError()
                           .GetResponseObject().Result.Token;

            api.PinSecurity.GetPinSecurity(pin, token).Validate.StatusCode(HttpStatusCode.OK).Validate.NoApiError();

            api.Client.GetClientCodes(token).Validate.StatusCode(HttpStatusCode.OK).Validate.NoApiError();

            string accessToken = api.Client.PostClientCodes(new SubmitCodeModel("0000"), token).Validate.StatusCode(HttpStatusCode.OK)
                                 .Validate.NoApiError().GetResponseObject().Result.AccessToken;

            string encodedPrivateKey = api.Client
                                       .PostClientEncodedMainKey(new AccessTokenModel(accessToken), token)
                                       .Validate.StatusCode(HttpStatusCode.OK).Validate.NoApiError()
                                       .GetResponseObject().Result.EncodedPrivateKey;

            string privateKeyStr = AesUtils.Decrypt(encodedPrivateKey, password);
            Key    privateKey    = Key.Parse(privateKeyStr);

            return(token, privateKey);
        }
    public void Can_Encrypt_and_Decrypt_with_AES_bytes()
    {
        var msg = new HelloSecure {
            Name = "World"
        };

        AesUtils.CreateKeyAndIv(out var cryptKey, out var iv);

        var encryptedBytes = AesUtils.Encrypt(msg.ToJson().ToUtf8Bytes(), cryptKey, iv);

        var msgBytes = AesUtils.Decrypt(encryptedBytes, cryptKey, iv);

        var decryptedMsg = msgBytes.FromUtf8Bytes().FromJson <HelloSecure>();

        Assert.That(decryptedMsg.Name, Is.EqualTo(msg.Name));
    }
    public void Can_Encrypt_and_Decrypt_with_AES()
    {
        var msg = new HelloSecure {
            Name = "World"
        };

        AesUtils.CreateKeyAndIv(out var cryptKey, out var iv);

        var encryptedText = AesUtils.Encrypt(msg.ToJson(), cryptKey, iv);

        var decryptedJson = AesUtils.Decrypt(encryptedText, cryptKey, iv);

        var decryptedMsg = decryptedJson.FromJson <HelloSecure>();

        Assert.That(decryptedMsg.Name, Is.EqualTo(msg.Name));
    }
        public void Does_Hybrid_RSA_Crypt_and_Auth_AES_with_HMAC_SHA256()
        {
            var request = new HelloSecure {
                Name = "World"
            };
            var timestamp = DateTime.UtcNow.ToUnixTime();
            var msg       = timestamp + " POST " + request.GetType().Name + " " + request.ToJson();
            var msgBytes  = msg.ToUtf8Bytes();

            byte[] cryptKey, authKey, iv;
            AesUtils.CreateCryptAuthKeysAndIv(out cryptKey, out authKey, out iv);

            var encryptedBytes = AesUtils.Encrypt(msgBytes, cryptKey, iv);

            var decryptedBytes = AesUtils.Decrypt(encryptedBytes, cryptKey, iv);

            Assert.That(decryptedBytes, Is.EquivalentTo(msgBytes));

            var authEncryptedBytes = HmacUtils.Authenticate(encryptedBytes, authKey, iv);

            var cryptAuthKeys = cryptKey.Combine(authKey);

            var rsaEncCryptAuthKeys     = RsaUtils.Encrypt(cryptAuthKeys, SecureConfig.PublicKeyXml);
            var authRsaEncCryptAuthKeys = HmacUtils.Authenticate(rsaEncCryptAuthKeys, authKey, iv);

            var decryptedMsg = ValidateAndDecrypt(authRsaEncCryptAuthKeys, authEncryptedBytes);

            var parts = decryptedMsg.SplitOnFirst(' ');

            Assert.That(long.Parse(parts[0]), Is.EqualTo(timestamp));

            parts = parts[1].SplitOnFirst(' ');
            Assert.That(parts[0], Is.EqualTo("POST"));

            parts = parts[1].SplitOnFirst(' ');
            Assert.That(parts[0], Is.EqualTo(request.GetType().Name));

            var decryptedJson    = parts[1];
            var decryptedRequest = decryptedJson.FromJson <HelloSecure>();

            Assert.That(decryptedRequest.Name, Is.EqualTo(request.Name));
        }
        public void Does_throw_on_replayed_messages()
        {
            var client = CreateClient();

            var request = new HelloSecure {
                Name = "World"
            };

            var aes = new AesManaged {
                KeySize = AesUtils.KeySize
            };

            var aesKeyBytes       = aes.Key.Combine(aes.IV);
            var rsaEncAesKeyBytes = RsaUtils.Encrypt(aesKeyBytes, SecureConfig.PublicKeyXml);

            var timestamp   = DateTime.UtcNow.ToUnixTime();
            var requestBody = timestamp + " POST " + typeof(HelloSecure).Name + " " + request.ToJson();

            var encryptedMessage = new EncryptedMessage
            {
                EncryptedSymmetricKey = Convert.ToBase64String(rsaEncAesKeyBytes),
                EncryptedBody         = AesUtils.Encrypt(requestBody, aes.Key, aes.IV)
            };
            var encResponse = client.Post(encryptedMessage);

            try
            {
                client.Post(encryptedMessage);

                Assert.Fail("Should throw");
            }
            catch (WebServiceException ex)
            {
                ex.StatusDescription.Print();

                var errorResponse = (EncryptedMessageResponse)ex.ResponseDto;
                var responseJson  = AesUtils.Decrypt(errorResponse.EncryptedBody, aes.Key, aes.IV);
                var response      = responseJson.FromJson <ErrorResponse>();
                Assert.That(response.ResponseStatus.Message, Is.EqualTo("Nonce already seen"));
            }
        }
            public string GetApi1SignVerToken()
            {
                var signTokenResponse = WalletApi.SignatureVerificationToken.GetKeyConfirmation(wallet.WalletAddress, BearerToken);

                Assert.That(signTokenResponse.StatusCode, Is.EqualTo(HttpStatusCode.OK));

                var signToken    = signTokenResponse.ResponseObject.Result.Message.ToString();
                var signVerToken = signToken;

                //
                WalletApi.PinSecurity.GetPinSecurity(pin, BearerToken).Validate.StatusCode(HttpStatusCode.OK).Validate.NoApiError("Please Reset Pin for user in Back Office");

                WalletApi.Client.GetClientCodes(BearerToken).Validate.StatusCode(HttpStatusCode.OK).Validate.NoApiError();

                string accessToken = WalletApi.Client.PostClientCodes(new SubmitCodeModel("0000"), BearerToken).Validate.StatusCode(HttpStatusCode.OK)
                                     .Validate.NoApiError().GetResponseObject().Result.AccessToken;

                string encodedPrivateKey = WalletApi.Client
                                           .PostClientEncodedMainKey(new AccessTokenModel(accessToken), BearerToken)
                                           .Validate.StatusCode(HttpStatusCode.OK).Validate.NoApiError()
                                           .GetResponseObject().Result.EncodedPrivateKey;

                string privateKeyStr = AesUtils.Decrypt(encodedPrivateKey, wallet.WalletKey);
                Key    privateKey    = Key.Parse(privateKeyStr);

                //

                signToken = privateKey.SignMessage(signToken);

                var postSignResponse = WalletApi.SignatureVerificationToken.PostKeyConfirmation(new RecoveryTokenChallangeResponse {
                    Email = wallet.WalletAddress, SignedMessage = signToken
                }, BearerToken);

                Assert.That(postSignResponse.StatusCode, Is.EqualTo(HttpStatusCode.OK));
                return(postSignResponse.ResponseObject.Result.AccessToken);
            }
            public void E2EOrdinaryFlowApi1ExtensionsTest()
            {
                string initialEtherBalance = "";
                string finalEtherBalance   = "";
                string DESTNATION_ADDRESS  = "rLUEUviNDaEU395WAdD7osWbzy6v9FqaMY";
                var    RippleBalanceAPIURL = $"https://s.altnet.rippletest.net:51234";
                var    walletBalance       = 0d;
                var    finalBalance        = 0d;
                var    assetId             = "c9cf27b2-9c68-4159-a30f-23a99950d929";
                var    signToken           = "";
                var    signVerToken        = "";
                var    pin = "1111";
                var    signedVerificationToken = "";
                var    WalletId          = "da268259-c2f1-414a-96b1-e0fd5b9b724f";
                var    zeroTransactionId = "";
                var    extension         = "";
                var    pkSecret          = "sapoZtw4oZiwhoHvF6Z7thTGmpaJ6";
                var    volume            = 1m;

                //Step($"Get latest transaction id for wallet {WalletId}", () =>
                //{
                //    zeroTransactionId = GetLatestFinishedTransactionId(WalletId);
                //});

                Step("Get initial balance of Ripple waller: bcn initial balance = GET http://ripplerpc:[email protected]:5005/", () =>
                {
                    var json = "{\"method\": \"account_info\",\"params\": [{\"account\": \"rLUEUviNDaEU395WAdD7osWbzy6v9FqaMY\" }]}";

                    var balancePage = apiV2.CustomRequests.PostResponse(RippleBalanceAPIURL, json);
                    Assert.That(balancePage.StatusCode, Is.EqualTo(HttpStatusCode.OK), "Could not get initial Ripple balance");

                    initialEtherBalance = JsonConvert.DeserializeObject <ExtensionBalanceResponse>(balancePage.Content).result.account_data.Balance;
                });

                Step("Get initial balance of lykke client wallet. initial balance = GET https://api-test.lykkex.net/api/Wallets assets.id = e58aa37d - dd46 - 4bdb - bac1 - a6d0d44e6dc9 assets.Balance-> % initialBalance % ", () =>
                {
                    var wallet         = WalletApi.Wallets.GetWallets(BearerToken);
                    var balances       = apiV2.wallets.GetWalletsBalances(BearerToken).ResponseObject;
                    var walletBalances = balances.First().Balances.ToList();
                    var assetBalance   = walletBalances.Find(b => b.AssetId == assetId);

                    walletBalance = assetBalance.Balance;
                });

                Step("GET https://api-test.lykkex.net/api/signatureVerificationToken/KeyConfirmation?email=%email%", () =>
                {
                    var signTokenResponse = WalletApi.SignatureVerificationToken.GetKeyConfirmation(wallet.WalletAddress, BearerToken);
                    Assert.That(signTokenResponse.StatusCode, Is.EqualTo(HttpStatusCode.OK));

                    signToken    = signTokenResponse.ResponseObject.Result.Message.ToString();
                    signVerToken = signToken;

                    //
                    WalletApi.PinSecurity.GetPinSecurity(pin, BearerToken).Validate.StatusCode(HttpStatusCode.OK).Validate.NoApiError("Please Reset Pin for user in Back Office");

                    WalletApi.Client.GetClientCodes(BearerToken).Validate.StatusCode(HttpStatusCode.OK).Validate.NoApiError();

                    string accessToken = WalletApi.Client.PostClientCodes(new SubmitCodeModel("0000"), BearerToken).Validate.StatusCode(HttpStatusCode.OK)
                                         .Validate.NoApiError().GetResponseObject().Result.AccessToken;

                    string encodedPrivateKey = WalletApi.Client
                                               .PostClientEncodedMainKey(new AccessTokenModel(accessToken), BearerToken)
                                               .Validate.StatusCode(HttpStatusCode.OK).Validate.NoApiError()
                                               .GetResponseObject().Result.EncodedPrivateKey;

                    string privateKeyStr = AesUtils.Decrypt(encodedPrivateKey, wallet.WalletKey);
                    Key privateKey       = Key.Parse(privateKeyStr);
                    //

                    signToken = privateKey.SignMessage(signToken);
                });

                Step("POST https://api-test.lykkex.net/api/signatureVerificationToken/KeyConfirmation", () =>
                {
                    var postSignResponse = WalletApi.SignatureVerificationToken.PostKeyConfirmation(new RecoveryTokenChallangeResponse {
                        Email = wallet.WalletAddress, SignedMessage = signToken
                    }, BearerToken);
                    Assert.That(postSignResponse.StatusCode, Is.EqualTo(HttpStatusCode.OK));
                    signedVerificationToken = postSignResponse.ResponseObject.Result.AccessToken;
                });

                Step("POST https://api-test.lykkex.net/api/HotWallet/cashout", () =>
                {
                    var postCashOut = WalletApi.HotWallet.PostCashOut(new HotWalletCashoutOperation
                    {
                        AssetId                     = assetId,
                        DestinationAddress          = DESTNATION_ADDRESS,
                        DestinationAddressExtension = "",
                        Volume = (double)volume
                    }, signedVerificationToken, BearerToken);

                    Assert.That(postCashOut.StatusCode, Does.Not.EqualTo(HttpStatusCode.NotFound).And.Not.EqualTo(HttpStatusCode.InternalServerError).And.Not.EqualTo(HttpStatusCode.BadGateway), "Wrong Cashout Status code");
                });

                Step("Delay ~ 20min cashout confirmation and waiting fo Finished status", () =>
                {
                    if (!WaitForLatestHistoryResponseGotFinishedState(WalletId, TimeSpan.FromMinutes(20)))
                    {
                        Assert.Fail("Cashout comfirmation does not exist afer 20 minutes");
                    }
                    Assert.That(GetLatestFinishedTransactionId(WalletId), Does.Not.EqualTo(zeroTransactionId), "Latest transaction ID is the same as before test. History service does not know about our transaction. POST cashout failed?");
                });

                Step("Get Final Balance; final balance = GET https://api-test.lykkex.net/api/Wallets assets.id = e58aa37d - dd46 - 4bdb  - bac1 - a6d0d44e6dc9 assets.Balance-> % finalBalance %      initialBalance + finalBalance = %Volume - %feeSize", () =>
                {
                    var wallet         = WalletApi.Wallets.GetWallets(BearerToken);
                    var balances       = apiV2.wallets.GetWalletsBalances(BearerToken).ResponseObject;
                    var walletBalances = balances.First().Balances.ToList();
                    var assetBalance   = walletBalances.Find(b => b.AssetId == assetId);

                    finalBalance = assetBalance.Balance;
                });

                Step("bcn final balance = GET https://ropsten.etherscan.io/address/0x856924997fa22efad8dc75e83acfa916490989a4 . Validate that final balance on ether wallet is initial balance + volume cashout ", () =>
                {
                    var json = "{\"method\": \"account_info\",\"params\": [{\"account\": \"rLUEUviNDaEU395WAdD7osWbzy6v9FqaMY\" }]}";

                    var balancePage = apiV2.CustomRequests.PostResponse(RippleBalanceAPIURL, json);
                    Assert.That(balancePage.StatusCode, Is.EqualTo(HttpStatusCode.OK), "Could not get initial Ripple balance");

                    Assert.That(() => decimal.Parse(
                                    JsonConvert.DeserializeObject <ExtensionBalanceResponse>(apiV2.CustomRequests.PostResponse(RippleBalanceAPIURL, json).Content).result.account_data.Balance

                                    ), Is.EqualTo(decimal.Parse(initialEtherBalance) + volume * (decimal)Math.Pow(10, 6)).After(3).Minutes.PollEvery(2).Seconds);
                });
            }
            public void E2EOrdinaryCashOutNumerousTest()
            {
                string initialEtherBalance = "";
                string finalEtherBalance   = "";
                string DESTNATION_ADDRESS  = "0x856924997fa22efad8dc75e83acfa916490989a4";
                var    EtherBalanceAPIURL  = $"https://api-ropsten.etherscan.io/api?module=account&action=balance&address={DESTNATION_ADDRESS}&tag=latest";
                var    walletBalance       = 0d;
                var    finalBalance        = 0d;
                var    assetId             = "e58aa37d-dd46-4bdb-bac1-a6d0d44e6dc9";
                var    signToken           = "";
                var    signVerToken        = "";
                var    pin = "1111";
                var    signedVerificationToken = "";
                var    WalletId          = "da268259-c2f1-414a-96b1-e0fd5b9b724f";
                var    zeroTransactionId = "";

                Step($"Get latest transaction id for wallet {WalletId}", () =>
                {
                    zeroTransactionId = GetLatestFinishedTransactionId(WalletId);
                });

                Step("Get initial balance of Ether waller: bcn initial balance = GET https://ropsten.etherscan.io/address/0x856924997fa22efad8dc75e83acfa916490989a4   Balance: % somebalance % Ether-> % inicialBcnBalance % ", () =>
                {
                    var balancePage = apiV2.CustomRequests.GetResponse(EtherBalanceAPIURL);
                    Assert.That(balancePage.StatusCode, Is.EqualTo(HttpStatusCode.OK), "Could not get initial ETHER balance");

                    initialEtherBalance = JsonConvert.DeserializeObject <EtherBalanceObjectModel>(balancePage.Content).result;
                });

                Step("Get initial balance of lykke client wallet. initial balance = GET https://api-test.lykkex.net/api/Wallets assets.id = e58aa37d - dd46 - 4bdb - bac1 - a6d0d44e6dc9 assets.Balance-> % initialBalance % ", () =>
                {
                    var wallet         = WalletApi.Wallets.GetWallets(BearerToken);
                    var balances       = apiV2.wallets.GetWalletsBalances(BearerToken).ResponseObject;
                    var walletBalances = balances.First().Balances.ToList();
                    var assetBalance   = walletBalances.Find(b => b.AssetId == assetId);

                    walletBalance = assetBalance.Balance;
                });

                Step("GET https://api-test.lykkex.net/api/signatureVerificationToken/KeyConfirmation?email=%email%", () =>
                {
                    var signTokenResponse = WalletApi.SignatureVerificationToken.GetKeyConfirmation(wallet.WalletAddress, BearerToken);
                    Assert.That(signTokenResponse.StatusCode, Is.EqualTo(HttpStatusCode.OK));

                    signToken    = signTokenResponse.ResponseObject.Result.Message.ToString();
                    signVerToken = signToken;

                    //
                    WalletApi.PinSecurity.GetPinSecurity(pin, BearerToken).Validate.StatusCode(HttpStatusCode.OK).Validate.NoApiError("Please Reset Pin for user in Back Office");

                    WalletApi.Client.GetClientCodes(BearerToken).Validate.StatusCode(HttpStatusCode.OK).Validate.NoApiError();

                    string accessToken = WalletApi.Client.PostClientCodes(new SubmitCodeModel("0000"), BearerToken).Validate.StatusCode(HttpStatusCode.OK)
                                         .Validate.NoApiError().GetResponseObject().Result.AccessToken;

                    string encodedPrivateKey = WalletApi.Client
                                               .PostClientEncodedMainKey(new AccessTokenModel(accessToken), BearerToken)
                                               .Validate.StatusCode(HttpStatusCode.OK).Validate.NoApiError()
                                               .GetResponseObject().Result.EncodedPrivateKey;

                    string privateKeyStr = AesUtils.Decrypt(encodedPrivateKey, wallet.WalletKey);
                    Key privateKey       = Key.Parse(privateKeyStr);
                    //

                    signToken = privateKey.SignMessage(signToken);
                });

                Step("POST https://api-test.lykkex.net/api/signatureVerificationToken/KeyConfirmation", () =>
                {
                    var postSignResponse = WalletApi.SignatureVerificationToken.PostKeyConfirmation(new RecoveryTokenChallangeResponse {
                        Email = wallet.WalletAddress, SignedMessage = signToken
                    }, BearerToken);
                    Assert.That(postSignResponse.StatusCode, Is.EqualTo(HttpStatusCode.OK));
                    signedVerificationToken = postSignResponse.ResponseObject.Result.AccessToken;
                });

                Step("POST https://api-test.lykkex.net/api/HotWallet/cashout", () =>
                {
                    var postCashOut = WalletApi.HotWallet.PostCashOut(new HotWalletCashoutOperation
                    {
                        AssetId                     = assetId,
                        DestinationAddress          = DESTNATION_ADDRESS,
                        DestinationAddressExtension = "",
                        Volume = 0.0001
                    }, signedVerificationToken, BearerToken);

                    Assert.That(postCashOut.StatusCode, Does.Not.EqualTo(HttpStatusCode.NotFound).And.Not.EqualTo(HttpStatusCode.InternalServerError).And.Not.EqualTo(HttpStatusCode.BadGateway), "Wrong Cashout Status code");

                    for (int i = 0; i < 2; i++)
                    {
                        signedVerificationToken = GetApi1SignVerToken();
                        postCashOut             = WalletApi.HotWallet.PostCashOut(new HotWalletCashoutOperation
                        {
                            AssetId                     = assetId,
                            DestinationAddress          = DESTNATION_ADDRESS,
                            DestinationAddressExtension = "",
                            Volume = 0.0001
                        }, signedVerificationToken, BearerToken);

                        Assert.That(postCashOut.StatusCode, Does.Not.EqualTo(HttpStatusCode.NotFound).And.Not.EqualTo(HttpStatusCode.InternalServerError).And.Not.EqualTo(HttpStatusCode.BadGateway), "Wrong Cashout Status code");
                    }
                });

                Step("Delay ~ 20min cashout confirmation and waiting fo Finished status", () =>
                {
                    if (!WaitForLatestHistoryResponseGotFinishedState(WalletId, TimeSpan.FromMinutes(20)))
                    {
                        Assert.Fail("Cashout comfirmation does not exist afer 20 minutes");
                    }
                    Assert.That(GetLatestFinishedTransactionId(WalletId), Does.Not.EqualTo(zeroTransactionId), "Latest transaction ID is the same as before test. History service does not know about our transaction. POST cashout failed?");
                });

                Step("Get Final Balance; final balance = GET https://api-test.lykkex.net/api/Wallets assets.id = e58aa37d - dd46 - 4bdb  - bac1 - a6d0d44e6dc9 assets.Balance-> % finalBalance %      initialBalance + finalBalance = %Volume - %feeSize", () =>
                {
                    var wallet         = WalletApi.Wallets.GetWallets(BearerToken);
                    var balances       = apiV2.wallets.GetWalletsBalances(BearerToken).ResponseObject;
                    var walletBalances = balances.First().Balances.ToList();
                    var assetBalance   = walletBalances.Find(b => b.AssetId == assetId);

                    finalBalance = assetBalance.Balance;
                });

                Step("bcn final balance = GET https://ropsten.etherscan.io/address/0x856924997fa22efad8dc75e83acfa916490989a4 . Validate that final balance on ether wallet is initial balance + 20* volume cashout ", () =>
                {
                    var balancePage = apiV2.CustomRequests.GetResponse(EtherBalanceAPIURL);
                    Assert.That(balancePage.StatusCode, Is.EqualTo(HttpStatusCode.OK), "Could not get initial ETHER balance");

                    finalEtherBalance = JsonConvert.DeserializeObject <EtherBalanceObjectModel>(balancePage.Content).result;

                    Assert.That(decimal.Parse(finalEtherBalance), Is.EqualTo(decimal.Parse(initialEtherBalance) + 22 * 100m));
                });
            }
Beispiel #11
0
        public void BuyAssetLimitOrderTest()
        {
            string asset             = "EUR";
            double assetBalance      = 0;
            string assetToBuy        = "BTC";
            double assetToBuyBalance = 0;
            double volume            = 0.0001;
            string assetPair         = "BTCEUR"; //TODO What about vise versa?
            double assetPairPrice    = 0;
            string orderId           = null;
            string token             = null;
            Key    key = null;

            Step($"Login as {email} user", () =>
            {
                var loginStep         = new MobileSteps(walletApi).Login(email, password, pin);
                var encodedPrivateKey = loginStep.encodedPrivateKey;
                var privateKey        = AesUtils.Decrypt(encodedPrivateKey, password);
                token = loginStep.token;
                key   = Key.Parse(privateKey);
            });

            Step("Get current wallets and balances", () =>
            {
                var walltes = walletApi.Wallets.GetWalltes(token)
                              .Validate.StatusCode(HttpStatusCode.OK).Validate.NoApiError()
                              .GetResponseObject().Result;

                var assetBalanceNullable = walltes.Lykke.Assets
                                           .FirstOrDefault(wallet => wallet.Id == asset)?.Balance;
                Assert.That(assetBalanceNullable, Is.Not.Null);
                assetBalance = assetBalanceNullable.Value;
                //TODO: Should 100 eur be enough???
                Assert.That(assetBalance, Is.GreaterThan(100), $"Less than 100 {asset} at the wallet!");

                var assetToBuyBalanceNullable = walltes.Lykke.Assets
                                                .FirstOrDefault(wallet => wallet.Id == assetToBuy)?.Balance;
                Assert.That(assetToBuyBalanceNullable, Is.Not.Null);
                assetToBuyBalance = assetToBuyBalanceNullable.Value;
            });

            Step("Find price to purchase", () =>
            {
                var assetPairRates = walletApi.AssetPairRates.GetById(assetPair, token)
                                     .Validate.StatusCode(HttpStatusCode.OK).Validate.NoApiError()
                                     .GetResponseObject().Result;
                Assert.That(assetPairRates.Rate.Ask, Is.Not.Null);
                assetPairPrice = assetPairRates.Rate.Ask.Value;
            });

            Step($"Buy {assetToBuy} for {asset}", () =>
            {
                string message = walletApi.SignatureVerificationToken
                                 .GetKeyConfirmation(email, token)
                                 .Validate.StatusCode(HttpStatusCode.OK).Validate.NoApiError()
                                 .GetResponseObject().Result?.Message;
                Assert.That(message, Is.Not.Null);

                var signedMessage = key.SignMessage(message);

                string accessToken = walletApi.SignatureVerificationToken
                                     .PostKeyConfirmation(new RecoveryTokenChallangeResponse(email, signedMessage), token)
                                     .Validate.StatusCode(HttpStatusCode.OK).Validate.NoApiError()
                                     .GetResponseObject().Result.AccessToken;
                Assert.That(accessToken, Is.Not.Null);

                orderId = walletApi.HotWallet
                          .PostLimitOrder(new HotWalletLimitOperation
                {
                    AssetId   = assetToBuy,
                    AssetPair = assetPair,
                    Price     = assetPairPrice,
                    Volume    = volume
                }, accessToken, token)
                          .Validate.StatusCode(HttpStatusCode.OK).Validate.NoApiError()
                          .GetResponseObject().Result.Order?.Id;
                Assert.That(orderId, Is.Not.Null);
            });

            Step("Waiting for 1 minute until asset has been sold", () =>
            {
                Assert.That(() => walletApi.LimitOrders.GetOffchainLimitList(token, assetPair)
                            .Validate.StatusCode(HttpStatusCode.OK).Validate.NoApiError()
                            .GetResponseObject().Result.Orders,
                            Is.Empty.After(60 * 1000, 1000));
            });

            Step($"Assert that {assetToBuy} balance has been increased, and {asset} balance decreased", () =>
            {
                Assert.That(walletApi.Wallets.GetWalletsById(assetToBuy, token)
                            .Validate.StatusCode(HttpStatusCode.OK).Validate.NoApiError()
                            .GetResponseObject().Result.Balance,
                            Is.EqualTo(assetToBuyBalance + volume).Within(assetToBuyBalance * 0.01));

                Assert.That(walletApi.Wallets.GetWalletsById(asset, token)
                            .Validate.StatusCode(HttpStatusCode.OK).Validate.NoApiError()
                            .GetResponseObject().Result.Balance,
                            Is.EqualTo(assetBalance - volume * assetPairPrice).Within(assetBalance * 0.01));
            });

            Step("Asserting history", () =>
            {
                Assert.That(() => walletApi.History.GetByAssetId("", token)
                            .Validate.StatusCode(HttpStatusCode.OK).Validate.NoApiError()
                            .GetResponseObject().Result
                            .Any(record => record.Trade?.OrderId == orderId && record.Trade?.Asset == asset),
                            Is.True.After(60 * 1000, 1000));
            });
        }
        /// <summary>
        /// Decrypt an encrypted text.
        /// </summary>
        /// <param name="encryptedText">The encrypted text.</param>
        /// <param name="options">The decryption options.</param>
        /// <returns>Returns a decrypted text.</returns>
        public static string Decrypt(string encryptedText, IDictionary <string, object> options)
        {
            var toDecrypt     = encryptedText;
            var decryptedText = string.Empty;

            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            var decodeFromBase64 = options.ContainsKey("DecodeFromBase64") &&
                                   Convert.ToBoolean(options["DecodeFromBase64"], CultureInfo.InvariantCulture);
            var encodeToBase64 = options.ContainsKey("EncodeToBase64") && Convert.ToBoolean(options["EncodeToBase64"], CultureInfo.InvariantCulture);

            var method = options.ContainsKey("Method") ? options["Method"].ToString() : string.Empty;

            switch (method)
            {
            // RSA
            case "RSA":
                var privateKeyPath = options["PrivateKeyPath"].ToString();

                if (privateKeyPath.StartsWith("\"", StringComparison.InvariantCulture))
                {
                    privateKeyPath = privateKeyPath.Substring(1, privateKeyPath.Length - 1);
                }

                if (privateKeyPath.EndsWith("\"", StringComparison.InvariantCulture))
                {
                    privateKeyPath = privateKeyPath.Substring(0, privateKeyPath.Length - 1);
                }

                decryptedText = decodeFromBase64 ? RsaUtils.Base64DecodeAndDecrypt(toDecrypt, privateKeyPath) : RsaUtils.Decrypt(toDecrypt, privateKeyPath);
                break;

            // AES
            case "AES":
                var key = options["key"].ToString();
                var initializationValue = options["iniValue"].ToString();

                decryptedText = decodeFromBase64 ? AesUtils.Base64DecodeAndDecrypt(toDecrypt, key, initializationValue) : AesUtils.Decrypt(toDecrypt, key, initializationValue);
                break;

            // Base64
            case "Base64":
                decryptedText = GeneralUtils.Base64Decode(toDecrypt);
                break;
            }

            return(encodeToBase64 ? GeneralUtils.Base64Encode(decryptedText) : decryptedText);
        }