/// <summary>
        /// Imports a SQRL identity and stores it in the database.
        /// </summary>
        /// <param name="identity">The <c>SQRLIdentity</c> to be imported.</param>
        /// <param name="setAsCurrentIdentity">If set to <c>true</c>, the imported identity will be
        /// set as the currently active identity after adding it to the database.</param>
        public void ImportIdentity(SQRLIdentity identity, bool setAsCurrentIdentity = true)
        {
            if (identity.Block0 == null)
            {
                throw new InvalidOperationException("The identity does not contain a type 0 block!");
            }

            if (HasIdentity(identity.Block0.UniqueIdentifier.ToHex()))
            {
                throw new InvalidOperationException("The identity already exists in the database!");
            }

            Identity newIdRec = new Identity();

            newIdRec.Name      = identity.IdentityName;
            newIdRec.UniqueId  = identity.Block0.UniqueIdentifier.ToHex();
            newIdRec.GenesisId = identity.Block0.GenesisIdentifier.ToHex();

            // Serialize the identity for storing it in the database.
            // We could use identity.ToByteArray() here, but then we would
            // lose extra information not covered by the S4 format, such
            // as identity name, file path etc.
            newIdRec.DataBytes = SerializeIdentity(identity);

            _db.Identities.Add(newIdRec);
            _db.SaveChanges();

            if (setAsCurrentIdentity)
            {
                SetCurrentIdentity(newIdRec.UniqueId);
            }

            // Finally, fire the IdentityCountChanged event
            IdentityCountChanged?.Invoke(this, new IdentityCountChangedEventArgs(this.IdentityCount));
        }
示例#2
0
        public void FromToByteArrayTest()
        {
            List <Tuple <byte[], bool> > idVectors = new List <Tuple <byte[], bool> >()
            {
                // "Ordinary" identity containing block 1 + 2
                Tuple.Create(Sodium.Utilities.HexToBinary("7371726C646174617D0001002D003DF8C1D0D35425CBABE1ECEA13100FCDA8CE1EE9CC6C88A0F512D5F60991000000F30104050F00B10BC086752714EF4AC4330015268AF7716F8AA231C7F912D217189D37BEC4F82CBFF30D7ADC9ECF361E9236BC5E66FCBB6B75E6B7B23D5543F3DC78B50071C77A6CED382249904789E1F6341A91E9DC490002002FBE0BA95BD8FF50053728A565DD3EEF0995000000E64C5A1EDDB214D6B2886AC3FDA1E831C3DDFDD6405035F69E1AFAD21464C75E98CCD59C5A8BE47E39F2A39F2D10D3BA"), false),
                // Rekeyed 4 times, thus containing a large block 3
                Tuple.Create(Sodium.Utilities.HexToBinary("7371726C646174617D0001002D002943D5681A77E7EE06F6878C830D41F1B39BBBF63A9FA58B2022D4DE0990000000F30104050F00066DBAF9D304A4011E980AE2F43C489AD1F8AAC7EB5397F875C06B231D56AFEC1A398E1A5703FB622DEB645A2E77FF456976A312F07F555C5D3407DB23DD47A777CAB5683564FCB677BA63D93E3AF2F249000200415464EDD9EF881606D85D01EBDF0D21098F00000096FA59AD8B58DE81A4ED00C2516CE80BD65CC1389C0A7A89F85F775DBB455E0AF1CF5757F11B17924DC1EB6863D82C20960003000400B19A77C75B9945BEB48BFCC6494244BC5C025EB9F4501017FF04E41C02B7B65ECA95D164C4465AAC3140292598592E56D9A88FCF787B5189BDFD81E238641CE46B0C97E47D5EBDC4DD16D5748874C8A5BFA82515F50F1577E15A157CDD059695A61BF0538217680019E5D9AF34A1F70054A057BFFC6F505E1859FFDCA2EB418F0F1B3903C78B219BDB5D28620BB1BFEB"), false),
                // .sqrc-File (containing only block 2)
                Tuple.Create(Sodium.Utilities.HexToBinary("7371726C64617461490002002DD4DEA2238AFF0A553C76AADE9488A309960000006CC320A5DF90DEF5E3F8DCF460B6A5490E7C4CABB93926B0B79D850582C88DE1E698A4F03CC93926CA0015D673DB1686"), false),
                // Custom block (contains a block of imaginary type 55, which should be retained)
                Tuple.Create(Sodium.Utilities.HexToBinary("7371726C646174617D0001002D005B6648EBCC4E296A4CBF479E43C67DDBBBCCEBF73E1D5939D18758D3091F000000F30104050F002C6258339401919F4BA3C1B904174BCA18ED3DC25560637D684A2A7C19761709AED12E480CCED7B0D8B21FC13B773578ABA9EC6838B1ED4D110787EFEB9740EFF40536CC5F598A5714EBBF6E2946F0934900020002D86D2A4CEDC1C91951E5410A5DE3CC09200000000752657E822696708F7DCC96D0AD911C0184BD8A06DE16C7509CED8762B53EBAEEA49CB089449204317437BECC5956DB1500370074657374696E67206974206F7574212129"), false),
                // Base64url-encoded identity (indicated by uppercase "SQRLDATA" header)
                Tuple.Create(Sodium.Utilities.HexToBinary("5351524C44415441665141424143304150666A42304E4E554A63757234657A71457841507A616A4F48756E4D6249696739524C5639676D5241414141387745454251384173517641686E556E464F394B78444D414653614B3933467669714978785F6B53306863596E54652D78506773765F4D4E657479657A7A59656B6A6138586D623875327431357265795056564438397834745142787833707337546769535A4248696548324E4271523664784A414149414C37344C715676595F3141464E79696C5A64302D37776D5641414141356B786148743279464E6179694772445F61486F4D6350645F645A41554458326E6872363068526B783136597A4E5763576F766B666A6E796F353874454E4F36"), true)
            };

            foreach (var idVector in idVectors)
            {
                SQRLIdentity id     = SQRLIdentity.FromByteArray(idVector.Item1);
                byte[]       result = id.ToByteArray();

                if (!idVector.Item2)                 // No base 64, straight comparison possible
                {
                    Assert.Equal(idVector.Item1, result);
                }
                else                                 // Take base64url encoding of source vector into account!
                {
                    Assert.Equal(Encoding.UTF8.GetString(idVector.Item1.Skip(8).ToArray()),
                                 Sodium.Utilities.BinaryToBase64(result.Skip(8).ToArray(), Sodium.Utilities.Base64Variant.UrlSafeNoPadding));
                }
            }
        }
示例#3
0
        /// <summary>
        /// Creates a QuickPass from the given <paramref name="password"/> and
        /// <paramref name="imk"/> using the QuickPass settings stored in
        /// <paramref name="identity"/>, stores it in memory and establishes a
        /// timer that will clear the QuickPass after the timeout set forth in
        /// <paramref name="identity"/>'s QuickPass settings.
        /// </summary>
        /// <param name="password">The full identity master password.</param>
        /// <param name="imk">The identity's unencrypted Identity Master Key (IMK).</param>
        /// <param name="ilk">The identity's unencrypted Identity Lock Key (ILK).</param>
        /// <param name="identity">The identity that the QuickPass should be set for.</param>
        /// <param name="progress">An object implementing the IProgress interface for tracking the operation's progress (optional).</param>
        /// <param name="progressText">A string representing a text descrition for the progress indicator (optional).</param>
        public async void SetQuickPass(string password, byte[] imk, byte[] ilk, SQRLIdentity identity, IProgress <KeyValuePair <int, string> > progress = null, string progressText = null)
        {
            if (string.IsNullOrEmpty(password))
            {
                Log.Warning("Can't use QuickPass on an empty password, aborting SetQuickPass()!");
                return;
            }

            QuickPassItem qpi = new QuickPassItem()
            {
                EstablishedDate               = DateTime.Now,
                QuickPassLength               = identity.Block1.HintLength,
                IdentityUniqueId              = identity.Block0.UniqueIdentifier.ToHex(),
                ScryptRandomSalt              = SodiumCore.GetRandomBytes(16),
                Nonce                         = SodiumCore.GetRandomBytes(24),
                QuickPassTimeoutSecs          = identity.Block1.PwdTimeoutMins * 60,
                ClearQuickPassOnIdle          = identity.Block1.OptionFlags.ClearQuickPassOnIdle,
                ClearQuickPassOnSleep         = identity.Block1.OptionFlags.ClearQuickPassOnSleep,
                ClearQuickPassOnSwitchingUser = identity.Block1.OptionFlags.ClearQuickPassOnSwitchingUser,
                Timer                         = new Timer()
            };

            qpi.Timer.Enabled   = false;
            qpi.Timer.AutoReset = false; // Dont restart timer after calling elapsed
            qpi.Timer.Interval  = QP_GENERAL_TIMEOUT_SEC;
            qpi.Timer.Elapsed  += QuickPassTimerElapsed;

            string quickPass = password.Substring(0, qpi.QuickPassLength);

            var enScryptResult = await SQRL.EnScryptTime(
                quickPass,
                qpi.ScryptRandomSalt,
                (int)Math.Pow(2, 9),
                QP_KEYDERIV_SEC,
                progress,
                progressText);

            qpi.ScryptIterationCount = enScryptResult.IterationCount;
            qpi.EncryptedImk         = StreamEncryption.Encrypt(imk, qpi.Nonce, enScryptResult.Key);
            qpi.EncryptedIlk         = StreamEncryption.Encrypt(ilk, qpi.Nonce, enScryptResult.Key);

            // If we already have a QuickPass entry for this identity, remove it first
            if (HasQuickPass(qpi.IdentityUniqueId))
            {
                ClearQuickPass(qpi.IdentityUniqueId, QuickPassClearReason.Unspecified);
            }

            // Now, add the QuickPass item to our list and start the timer
            lock (_dataSyncObj)
            {
                _quickPassItems.Add(qpi.IdentityUniqueId, qpi);
                qpi.Timer.Start();
            }

            Log.Information("QuickPass set for identity {IdentityUniqueId}",
                            qpi.IdentityUniqueId);
        }
示例#4
0
        /// <summary>
        /// Creates a PDF document displaying the given identity as QR code and text and
        /// providing some guidance for the user.
        /// </summary>
        /// <param name="fileName">The full file name (including the path) for the document.</param>
        /// <param name="identity">The identity for which to create the document.</param>
        /// <param name="blockTypes">Spciefies a list of block types to include.</param>
        public static void CreateIdentityDocument(string fileName, SQRLIdentity identity, List <ushort> blockTypes)
        {
            if (string.IsNullOrEmpty(fileName) ||
                identity == null ||
                blockTypes == null ||
                blockTypes.Count < 1)
            {
                throw new ArgumentException(string.Format("{0}, {1} and {2} must be specified and valid!",
                                                          nameof(fileName), nameof(identity), nameof(blockTypes)));
            }

            _pageNr = 0;
            string title = "\"" + identity.IdentityName + "\" " + _loc.GetLocalizationValue("FileDialogFilterName");
            string identityEncryptionMessage = blockTypes.Contains(1) ?
                                               _loc.GetLocalizationValue("IdentityDocEncMsgPassword") :
                                               _loc.GetLocalizationValue("IdentityDocEncMsgRC");
            string textualIdentityMessage = _loc.GetLocalizationValue("IdentityDocumentTextualIdentityMessage");
            string guidanceMessage        = _loc.GetLocalizationValue("IdentityDocumentGuidanceMessage");
            var    identityBytes          = identity.ToByteArray(includeHeader: true, blockTypes);
            string textualIdentity        = SQRL.GenerateTextualIdentityBase56(identityBytes);

            var metadata = new SKDocumentPdfMetadata
            {
                Author          = _assemblyName,
                Creation        = DateTime.Now,
                Creator         = _assemblyName,
                Keywords        = "SQRL,Identity",
                Modified        = DateTime.Now,
                Producer        = "SkiaSharp",
                Subject         = "SQRL Identity Document",
                Title           = "SQRL Identity Document",
                EncodingQuality = 300,
                RasterDpi       = 300
            };

            using (SKBitmap qrCode = CreateQRCode(identityBytes))
                using (var stream = new SKFileWStream(fileName))
                    using (_document = SKDocument.CreatePdf(stream, metadata))
                    {
                        StartNextPage();

                        float qrCodeWidth  = (qrCode.Width <= QRCODE_MAX_SIZE) ? qrCode.Width : QRCODE_MAX_SIZE;
                        float qrCodeHeight = (qrCode.Height <= QRCODE_MAX_SIZE) ? qrCode.Height : QRCODE_MAX_SIZE;

                        DrawTextBlock(title, _fontBold, 23, SKColors.Black, 10f);
                        DrawTextBlock(identityEncryptionMessage, _fontRegular, 12, SKColors.DarkGray, -5f, SKTextAlign.Left, 1.3f);
                        DrawBitmap(qrCode, SKTextAlign.Center, qrCodeWidth, qrCodeHeight, 15f);
                        DrawTextBlock(textualIdentityMessage, _fontRegular, 12, SKColors.DarkGray, 10f, SKTextAlign.Left, 1.3f);
                        DrawTextBlock(textualIdentity, _fontMonoBold, 12, SKColors.Black, 15f, SKTextAlign.Center, 1.3f);;
                        DrawTextBlock(guidanceMessage, _fontRegular, 12, SKColors.DarkGray, 0f, SKTextAlign.Left, 1.3f);

                        EndPage();
                        _document.Close();
                    }
        }
        /// <summary>
        /// The constructor is private because <c>IdentityManager</c>
        /// implements the singleton pattern. To get an instance, use
        /// <c>IdentityManager.Instance</c> instead.
        /// </summary>
        private IdentityManager()
        {
            _db = new SQRLDBContext();
            _currentIdentityDB = GetIdentityInternal(GetUserData().LastLoadedIdentity);
            if (_currentIdentityDB != null)
            {
                _currentIdentity = DeserializeIdentity(_currentIdentityDB.DataBytes);
            }

            _log.Information("IdentityManager initialized.");
        }
        /// <summary>
        /// Serializes a <c>SQRLIdentity</c> object to a byte array.
        /// </summary>
        /// <param name="identity">The identity to be serialized.</param>
        private byte[] SerializeIdentity(SQRLIdentity identity)
        {
            byte[]     identityBtes;
            IFormatter formatter = new BinaryFormatter();

            using (MemoryStream stream = new MemoryStream())
            {
                formatter.Serialize(stream, identity);
                identityBtes = stream.ToArray();
            }
            return(identityBtes);
        }
        /// <summary>
        /// Writes changes made to the given <paramref name="identity"/> back to the database.
        /// </summary>
        /// <param name="identity">The changed identity which should be updated in the database.</param>
        public void UpdateIdentity(SQRLIdentity identity)
        {
            Identity id = GetIdentityInternal(identity.Block0?.UniqueIdentifier.ToHex());

            if (id == null)
            {
                throw new ArgumentException("This identity does not exist!", nameof(identity));
            }

            id.DataBytes = SerializeIdentity(identity);
            _db.SaveChanges();
        }
示例#8
0
        /// <summary>
        /// Creates a PDF document displaying the given identity as QR code and text and
        /// providing some guidance for the user.
        /// </summary>
        /// <param name="fileName">The full file name (including the path) for the document.</param>
        /// <param name="identity">The identity for which to create the document.</param>
        /// <param name="blockTypes">Spciefies a list of block types to include.</param>
        public static void CreateIdentityDocument(string fileName, SQRLIdentity identity, List <ushort> blockTypes)
        {
            if (string.IsNullOrEmpty(fileName) || identity == null)
            {
                throw new ArgumentException(string.Format("{0} and {1} must be specified and valid!",
                                                          nameof(fileName), nameof(identity)));
            }

            float  yPos                   = MARGIN_TOP;
            string title                  = "\"" + identity.IdentityName + "\" " + _loc.GetLocalizationValue("FileDialogFilterName");
            string qrCodeMessage          = _loc.GetLocalizationValue("IdentityDocumentQRCodeMessage");
            string textualIdentityMessage = _loc.GetLocalizationValue("IdentityDocumentTextualIdentityMessage");
            string guidanceMessage        = _loc.GetLocalizationValue("IdentityDocumentGuidanceMessage");
            var    identityBytes          = identity.ToByteArray(includeHeader: true, blockTypes);
            string textualIdentity        = SQRL.GenerateTextualIdentityBase56(identityBytes);

            var metadata = new SKDocumentPdfMetadata
            {
                Author          = _assemblyName,
                Creation        = DateTime.Now,
                Creator         = _assemblyName,
                Keywords        = "SQRL,Identity",
                Modified        = DateTime.Now,
                Producer        = "SkiaSharp",
                Subject         = "SQRL Identity Document",
                Title           = "SQRL Identity Document",
                EncodingQuality = 300,
                RasterDpi       = 300
            };

            using (SKBitmap qrCode = CreateQRCode(identityBytes))
                using (var stream = new SKFileWStream(fileName))
                    using (var document = SKDocument.CreatePdf(stream, metadata))
                        using (var canvas = document.BeginPage(PAGE_WIDTH, PAGE_HEIGHT))
                        {
                            float qrCodeWidth  = (qrCode.Width <= QRCODE_MAX_SIZE) ? qrCode.Width : QRCODE_MAX_SIZE;
                            float qrCodeHeight = (qrCode.Height <= QRCODE_MAX_SIZE) ? qrCode.Height : QRCODE_MAX_SIZE;
                            float qrCodeXPos   = PAGE_WIDTH / 2 - qrCodeWidth / 2;

                            yPos += 10 + DrawTextBlock(canvas, title, yPos, _fontBold, 23, SKColors.Black);
                            yPos += -15 + DrawTextBlock(canvas, qrCodeMessage, yPos, _fontRegular, 12, SKColors.DarkGray, SKTextAlign.Left, 1.3f);
                            canvas.DrawBitmap(qrCode, new SKRect(qrCodeXPos, yPos, qrCodeXPos + qrCodeWidth, yPos + qrCodeHeight));
                            yPos += qrCodeHeight + 15;
                            yPos += 10 + DrawTextBlock(canvas, textualIdentityMessage, yPos, _fontRegular, 12, SKColors.DarkGray, SKTextAlign.Left, 1.3f);
                            yPos += 15 + DrawTextBlock(canvas, textualIdentity, yPos, _fontMonoBold, 12, SKColors.Black, SKTextAlign.Center, 1.3f);
                            yPos += 00 + DrawTextBlock(canvas, guidanceMessage, yPos, _fontRegular, 12, SKColors.DarkGray, SKTextAlign.Left, 1.3f);
                            DrawFooter(canvas);

                            document.EndPage();
                            document.Close();
                        }
        }
示例#9
0
 /// <summary>
 /// Called from various methods to load DB and initialize defaults.
 /// </summary>
 public void Initialize()
 {
     _db = SQRLDBContext.Instance;
     _currentIdentityDB = GetIdentityInternal(_appSettings.LastLoadedIdentity);
     if (_currentIdentityDB != null)
     {
         _currentIdentity = DeserializeIdentity(_currentIdentityDB.DataBytes);
     }
     else
     {
         _currentIdentity = null;
     }
 }
        public async void IUKRescueCodeEncryptDecryptTest()
        {
            for (int i = 0; i < 10; i++)
            {
                SQRLIdentity identity = new SQRLIdentity();
                byte[]       iuk      = SQRL.CreateIUK();

                string rescueCode = SQRL.CreateRescueCode();
                identity = await SQRL.GenerateIdentityBlock2(iuk, rescueCode, identity);

                var decryptResult = await SQRL.DecryptBlock2(identity, rescueCode);

                Assert.Equal(Sodium.Utilities.BinaryToHex(iuk), Sodium.Utilities.BinaryToHex(decryptResult.Iuk));
            }
        }
        public async void LMKILKPasswordEncryptDecryptTest()
        {
            for (int i = 0; i < 50; i++)
            {
                SQRLIdentity identity = new SQRLIdentity();
                byte[]       iuk      = SQRL.CreateIUK();
                string       password = Sodium.Utilities.BinaryToHex(Sodium.SodiumCore.GetRandomBytes(32), Sodium.Utilities.HexFormat.None, Sodium.Utilities.HexCase.Lower);

                identity = await SQRL.GenerateIdentityBlock1(iuk, password, identity);

                byte[] imk           = SQRL.CreateIMK(iuk);
                byte[] ilk           = SQRL.CreateILK(iuk);
                var    decryptedData = await SQRL.DecryptBlock1(identity, password);

                Assert.Equal(Sodium.Utilities.BinaryToHex(imk), Sodium.Utilities.BinaryToHex(decryptedData.Imk));
                Assert.Equal(Sodium.Utilities.BinaryToHex(ilk), Sodium.Utilities.BinaryToHex(decryptedData.Ilk));
            }
        }
        /// <summary>
        /// Tries setting the identity with the given <paramref name="uniqueId"/> as
        /// the currently active identity. If the currently selected identity should
        /// be unspecified, just pass <c>null</c> for the <paramref name="uniqueId"/>.
        /// </summary>
        /// <param name="uniqueId">The unique id of the identity to be set active.</param>
        public void SetCurrentIdentity(string uniqueId)
        {
            if (_currentIdentityDB?.UniqueId == uniqueId)
            {
                return;
            }

            Identity id = null;

            if (uniqueId != null)
            {
                // Fetch the identity from the database
                id = GetIdentityInternal(uniqueId);
                if (id == null)
                {
                    throw new ArgumentException("No matching identity found!", nameof(uniqueId));
                }

                // Set it as currently active identity
                _currentIdentityDB = id;
                _currentIdentity   = DeserializeIdentity(_currentIdentityDB.DataBytes);

                // Save the last active identity unique id in the database
                GetUserData().LastLoadedIdentity = id.UniqueId;
                _db.SaveChanges();
            }
            else
            {
                _currentIdentityDB = null;
                _currentIdentity   = null;
            }

            // And finally fire the IdentityChanged event
            IdentityChanged?.Invoke(this, new IdentityChangedEventArgs(
                                        _currentIdentity,
                                        (id != null) ? id.Name : "",
                                        (id != null) ? id.UniqueId : ""));
        }
示例#13
0
        static async Task Main(string[] args)
        {
            SQRL sqrl = SQRL.GetInstance(true);


            Console.WriteLine("Importing Identity");
            var progress = new Progress <KeyValuePair <int, string> >(percent =>
            {
                Console.WriteLine($"{percent.Value}: {percent.Key}%");
            });

            SQRLIdentity newId = SQRLIdentity.FromFile(Path.Combine(@"C:\Users\jose\Downloads\SQRL-Test-Identity-Resources\", @"Spec-Vectors-Identity.sqrl"));
            //SQRLIdentity newId = SQRLIdentity.FromFile(Path.Combine(Directory.GetCurrentDirectory(), @"980591756918003626376697.sqrl"));

            SQRLOpts optsFlags = (sqrl.cps != null && sqrl.cps.Running ? SQRLOpts.SUK | SQRLOpts.CPS : SQRLOpts.SUK);


            SQRLOptions opts = new SQRLOptions(optsFlags);
            bool        run  = true;


            var block1Keys = await SQRL.DecryptBlock1(newId, "Zingo-Bingo-Slingo-Dingo", progress);

            if (block1Keys.DecryptionSucceeded)
            {
                try
                {
                    do
                    {
                        Console.WriteLine("Enter SQRL URL:");
                        string url        = Console.ReadLine();
                        Uri    requestURI = new Uri(url);
                        string AltID      = "";


                        var siteKvp = SQRL.CreateSiteKey(requestURI, AltID, block1Keys.Imk);
                        Dictionary <byte[], PriorSiteKeysResult> priorSiteKeys = null;
                        if (newId.Block3 != null && newId.Block3.Edition > 0)
                        {
                            byte[]        decryptedBlock3 = SQRL.DecryptBlock3(block1Keys.Imk, newId, out bool allGood);
                            List <byte[]> oldIUKs         = new List <byte[]>();
                            if (allGood)
                            {
                                int skip = 0;
                                int ct   = 0;
                                while (skip < decryptedBlock3.Length)
                                {
                                    oldIUKs.Add(decryptedBlock3.Skip(skip).Take(32).ToArray());
                                    skip += 32;
                                    ;
                                    if (++ct >= 3)
                                    {
                                        break;
                                    }
                                }

                                SQRL.ZeroFillByteArray(ref decryptedBlock3);
                                priorSiteKeys = SQRL.CreatePriorSiteKeys(oldIUKs, requestURI, AltID);
                                oldIUKs.Clear();
                            }
                        }

                        //SQRL.ZeroFillByteArray(ref decryptedData.Item2);
                        //decryptedData.Item2.ZeroFill();
                        var serverRespose = SQRL.GenerateQueryCommand(requestURI, siteKvp, opts, null, 0, priorSiteKeys);

                        if (!serverRespose.CommandFailed)
                        {
                            if (!serverRespose.CurrentIDMatch && !serverRespose.PreviousIDMatch)
                            {
                                StringBuilder additionalData = null;
                                if (!string.IsNullOrEmpty(serverRespose.SIN))
                                {
                                    additionalData = new StringBuilder();
                                    byte[] ids = SQRL.CreateIndexedSecret(requestURI, AltID, block1Keys.Imk,
                                                                          Encoding.UTF8.GetBytes(serverRespose.SIN));
                                    additionalData.AppendLineWindows($"ins={Sodium.Utilities.BinaryToBase64(ids, Utilities.Base64Variant.UrlSafeNoPadding)}");
                                }
                                Console.WriteLine("The site doesn't recognize this ID, would you like to proceed and create one? (Y/N)");
                                if (Console.ReadLine().StartsWith("Y", StringComparison.OrdinalIgnoreCase))
                                {
                                    serverRespose = SQRL.GenerateNewIdentCommand(serverRespose.NewNutURL, siteKvp,
                                                                                 serverRespose.FullServerRequest, block1Keys.Ilk, opts, additionalData);
                                }
                            }
                            else if (serverRespose.PreviousIDMatch)
                            {
                                byte[] ursKey = null;
                                ursKey = SQRL.GetURSKey(serverRespose.PriorMatchedKey.Key, Sodium.Utilities.Base64ToBinary(
                                                            serverRespose.SUK, string.Empty, Sodium.Utilities.Base64Variant.UrlSafeNoPadding));

                                StringBuilder additionalData = null;
                                if (!string.IsNullOrEmpty(serverRespose.SIN))
                                {
                                    additionalData = new StringBuilder();
                                    byte[] ids = SQRL.CreateIndexedSecret(requestURI, AltID, block1Keys.Imk, Encoding.UTF8.GetBytes(serverRespose.SIN));
                                    additionalData.AppendLineWindows($"ins={Sodium.Utilities.BinaryToBase64(ids, Utilities.Base64Variant.UrlSafeNoPadding)}");
                                    byte[] pids = SQRL.CreateIndexedSecret(serverRespose.PriorMatchedKey.Value.SiteSeed, Encoding.UTF8.GetBytes(serverRespose.SIN));
                                    additionalData.AppendLineWindows($"pins={Sodium.Utilities.BinaryToBase64(pids, Utilities.Base64Variant.UrlSafeNoPadding)}");
                                }
                                serverRespose = SQRL.GenerateIdentCommandWithReplace(
                                    serverRespose.NewNutURL, siteKvp, serverRespose.FullServerRequest, block1Keys.Ilk,
                                    ursKey, serverRespose.PriorMatchedKey.Value.KeyPair, opts, additionalData);
                            }
                            else if (serverRespose.CurrentIDMatch)
                            {
                                int askResponse = 0;
                                if (serverRespose.HasAsk)
                                {
                                    Console.WriteLine(serverRespose.AskMessage);
                                    Console.WriteLine($"Enter 1 for {serverRespose.GetAskButtons[0]} or 2 for {serverRespose.GetAskButtons[1]}");
                                    int resp;
                                    do
                                    {
                                        string response = Console.ReadLine();
                                        int.TryParse(response, out resp);

                                        if (resp == 0)
                                        {
                                            Console.WriteLine("Invalid Entry, please enter 1 or 2 as shown above");
                                        }
                                    } while (resp == 0);
                                    askResponse = resp;
                                }

                                StringBuilder addClientData = null;
                                if (askResponse > 0)
                                {
                                    addClientData = new StringBuilder();
                                    addClientData.AppendLineWindows($"btn={askResponse}");
                                }

                                if (serverRespose.SQRLDisabled)
                                {
                                    Console.WriteLine("SQRL Is Disabled, to Continue you must enable it. Do you want to? (Y/N)");
                                    if (Console.ReadLine().StartsWith("Y", StringComparison.OrdinalIgnoreCase))
                                    {
                                        Console.WriteLine("Enter your Rescue Code (No Sapces or Dashes)");
                                        string rescueCode = Console.ReadLine().Trim();
                                        progress = new Progress <KeyValuePair <int, string> >(percent =>
                                        {
                                            Console.WriteLine($"Decrypting with Rescue Code: {percent.Key}%");
                                        });
                                        var iukData = await SQRL.DecryptBlock2(newId, rescueCode, progress);

                                        if (iukData.DecryptionSucceeded)
                                        {
                                            byte[] ursKey = null;
                                            ursKey = SQRL.GetURSKey(iukData.Iuk, Sodium.Utilities.Base64ToBinary(serverRespose.SUK, string.Empty, Sodium.Utilities.Base64Variant.UrlSafeNoPadding));

                                            iukData.Iuk.ZeroFill();
                                            serverRespose = SQRL.GenerateEnableCommand(serverRespose.NewNutURL, siteKvp, serverRespose.FullServerRequest, ursKey, addClientData, opts);
                                        }
                                        else
                                        {
                                            throw new Exception("Failed to Decrypt Block 2, Invalid Rescue Code");
                                        }
                                    }
                                }

                                Console.WriteLine("Which Command Would you like to Issue?:");
                                Console.WriteLine("*********************************************");
                                Console.WriteLine("0- Ident (Default/Enter) ");
                                Console.WriteLine("1- Disable ");
                                Console.WriteLine("2- Remove ");
                                Console.WriteLine("3- Cancel ");
                                Console.WriteLine("4- Re-Key ");
                                Console.WriteLine("10- Quit ");
                                Console.WriteLine("*********************************************");
                                var value = Console.ReadLine();
                                int.TryParse(value, out int selection);

                                switch (selection)
                                {
                                case 0:
                                {
                                    serverRespose = SQRL.GenerateSQRLCommand(SQRLCommands.ident, serverRespose.NewNutURL, siteKvp, serverRespose.FullServerRequest, addClientData, opts);
                                    if (sqrl.cps != null && sqrl.cps.PendingResponse)
                                    {
                                        sqrl.cps.cpsBC.Add(new Uri(serverRespose.SuccessUrl));
                                    }
                                }
                                break;

                                case 1:
                                {
                                    Console.WriteLine("This will disable all use of this SQRL Identity on the server, are you sure you want to proceed?: (Y/N)");
                                    if (Console.ReadLine().StartsWith("Y", StringComparison.OrdinalIgnoreCase))
                                    {
                                        serverRespose = SQRL.GenerateSQRLCommand(SQRLCommands.disable, serverRespose.NewNutURL, siteKvp, serverRespose.FullServerRequest, addClientData, opts);
                                        if (sqrl.cps != null && sqrl.cps.PendingResponse)
                                        {
                                            sqrl.cps.cpsBC.Add(sqrl.cps.Can);
                                        }
                                    }
                                }
                                break;

                                case 2:
                                {
                                    Console.WriteLine("Enter your Rescue Code (No Sapces or Dashes)");
                                    string rescueCode = Console.ReadLine().Trim();
                                    progress = new Progress <KeyValuePair <int, string> >(percent =>
                                        {
                                            Console.WriteLine($"Decrypting with Rescue Code: {percent.Key}%");
                                        });
                                    var iukData = await SQRL.DecryptBlock2(newId, rescueCode);

                                    if (iukData.DecryptionSucceeded)
                                    {
                                        byte[] ursKey = SQRL.GetURSKey(iukData.Iuk, Sodium.Utilities.Base64ToBinary(serverRespose.SUK, string.Empty, Sodium.Utilities.Base64Variant.UrlSafeNoPadding));
                                        iukData.Iuk.ZeroFill();
                                        serverRespose = SQRL.GenerateSQRLCommand(SQRLCommands.remove, serverRespose.NewNutURL, siteKvp, serverRespose.FullServerRequest, addClientData, opts, null, ursKey);
                                        if (sqrl.cps != null && sqrl.cps.PendingResponse)
                                        {
                                            sqrl.cps.cpsBC.Add(sqrl.cps.Can);
                                        }
                                    }
                                    else
                                    {
                                        throw new Exception("Failed to Decrypt Block 2, Invalid Rescue Code");
                                    }
                                }
                                break;

                                case 3:
                                {
                                    if (sqrl.cps != null && sqrl.cps.PendingResponse)
                                    {
                                        sqrl.cps.cpsBC.Add(sqrl.cps.Can);
                                    }
                                }
                                break;

                                default:
                                {
                                    Console.WriteLine("bye");
                                    run = false;
                                }
                                break;
                                }
                            }
                        }
                    } while (run);
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Error: {ex.ToString()}");
                }
            }
            else
            {
                Console.WriteLine("Failed to Decrypt Block 1, bad password!");
            }
        }
 public IdentityChangedEventArgs(SQRLIdentity identity, string identityName, string identityUniqueId)
 {
     this.Identity         = identity;
     this.IdentityName     = identityName;
     this.IdentityUniqueId = identityUniqueId;
 }
 /// <summary>
 /// Creates a new <c>NewIdentityVerifyViewModel</c> intance and performs
 /// some initialization tasks.
 /// </summary>
 /// <param name="identity">The newly created identity to be verified.</param>
 /// <param name="password">The identity's master password set by the user.</param>
 public NewIdentityVerifyViewModel(SQRLIdentity identity, string password)
 {
     Init();
     this.Identity = identity;
     this.Password = password;
 }