public async Task <ActionResult> ChangePrism([FromRoute] Guid uid, [FromRoute] string prism, [FromRoute] string prismAuth, [FromRoute] string token, [FromQuery] bool withCmk = false)
        {
            var tran    = TranToken.Parse(FromBase64(token));
            var toCheck = uid.ToByteArray().Concat(FromBase64(prism)).Concat(FromBase64(prismAuth)).ToArray();

            var account = await _manager.GetById(uid);

            if (account == null)
            {
                return(_logger.Log(Unauthorized($"Unsuccessful change password for {uid}"),
                                   $"Unsuccessful change password for {uid}. Account was not found"));
            }

            var authKey = withCmk ? account.CmkiAuth : account.PrismiAuth;

            if (!tran.Check(authKey, toCheck))
            {
                return(_logger.Log(Unauthorized($"Unsuccessful change password for {uid}"),
                                   $"Unsuccessful change password for {uid} with {token}"));
            }

            _logger.LogInformation($"Change password for {uid}", uid);

            account.Prismi     = GetBigInteger(prism);
            account.PrismiAuth = AesKey.Parse(FromBase64(prismAuth));

            await _manager.SetOrUpdate(account);

            return(Ok());
        }
        public async Task <ActionResult> TestCipher([FromRoute] Guid vuid, [FromRoute] string token, [FromRoute] string ciphertext)
        {
            var tran   = TranToken.Parse(FromBase64(token));
            var cipher = FromBase64(ciphertext);
            var plain  = await Decrypt(vuid, cipher);

            if (!tran.Check(Config.SecretKey, vuid.ToByteArray()))
            {
                await Repo.RollbackUser(vuid);

                return(BadRequest("Invalid token"));
            }

            if (!Utils.Equals(plain, Utils.Hash(tran.ToByteArray())))
            {
                await Repo.RollbackUser(vuid);

                return(BadRequest("Invalid decryption"));
            }

            await Repo.ConfirmUser(vuid);

            Logger.LogInformation($"Successful account creation for {vuid}", vuid);
            return(Ok());
        }
        public async Task <ActionResult> Challenge([FromRoute] Guid vuid, [FromRoute] Guid keyId)
        {
            var account = await _managerCvk.GetById(vuid);

            if (account == null)
            {
                _logger.LogInformation("Decryption challenge denied for vuid {0} with keyId {1}: account not found.", vuid, keyId);
                return(BadRequest($"Denied Challenge for {keyId}"));
            }

            var token = TranToken.Generate(account.CvkiAuth);

            var keyPub = await _keyIdManager.GetById(keyId);

            if (keyPub == null)
            {
                _logger.LogInformation("Decryption challenge denied for vuid {0} with keyId {1}: keyId not found.", vuid, keyId);
                return(BadRequest($"Denied Challenge for {keyId}"));
            }

            _logger.LogInformation("Decryption challenge granted for vuid {0} with keyId {1}", vuid, keyId);
            var cipher = keyPub.Key.Encrypt(token.GenKey(account.CvkiAuth));

            return(Ok(new { Token = token.ToString(), Challenge = cipher.ToString() }));
        }
        public async Task <ActionResult <SignupRsponse> > SignUp([FromRoute] Guid vuid, [FromBody] SignupRequest data)
        {
            var authKey = AesKey.Parse(data.Auth);
            var guids   = await data.GetUrlIds();

            var signatures = guids.Select(orkId => orkId.ToByteArray().Concat(vuid.ToByteArray()))
                             .Select(msg => Config.PrivateKey.Sign(msg.ToArray())).ToList();

            await Repo.CreateUser(vuid, authKey, data.OrkUrls);

            Logger.LogInformation($"Account created for {vuid}", vuid);
            return(new SignupRsponse {
                Token = TranToken.Generate(Config.SecretKey, vuid.ToByteArray()).ToByteArray(),
                Signatures = signatures
            });
        }
        public async Task <ActionResult <string> > SignIn([FromRoute] Guid vuid, [FromRoute] string token)
        {
            var tran = TranToken.Parse(FromBase64(token));

            var authKey = await Repo.GetKey(vuid);

            if (authKey == null)
            {
                return(BadRequest("User or invalid signature"));
            }

            if (!tran.OnTime || !tran.Check(authKey, vuid.ToByteArray()))
            {
                return(BadRequest("User or invalid signature"));
            }

            Logger.LogInformation($"successful login for {vuid}", vuid, token);
            return(GenerateToken(vuid));
        }
        public async Task <ActionResult <byte[]> > GetCvk([FromRoute] Guid vuid, [FromRoute] string token, [FromHeader] Guid tranid)
        {
            var tran = TranToken.Parse(FromBase64(token));

            var account = await _managerCvk.GetById(vuid);

            if (account == null || !tran.Check(account.CvkiAuth, vuid.ToByteArray()))
            {
                _logger.LoginUnsuccessful(ControllerContext.ActionDescriptor.ControllerName, tranid, vuid, $"Unsuccessful login for {vuid} with {token}");
                return(Unauthorized($"Invalid account or signature"));
            }

            if (!tran.OnTime)
            {
                _logger.LoginUnsuccessful(ControllerContext.ActionDescriptor.ControllerName, tranid, vuid, $"Expired token: {token}");
                return(StatusCode(408, new TranToken().ToString()));
            }

            _logger.LoginSuccessful(ControllerContext.ActionDescriptor.ControllerName, tranid, vuid, $"Returning cvk from {vuid}");
            return(account.CvkiAuth.Encrypt(account.CVKi.ToByteArray(true, true)));
        }
        public async Task <ActionResult> Authenticate([FromRoute] Guid uid, [FromRoute] C25519Point point, [FromRoute] string token, [FromHeader] Guid tranid)
        {
            if (!token.FromBase64UrlString(out byte[] bytesToken))
            {
                _logger.LoginUnsuccessful(ControllerContext.ActionDescriptor.ControllerName, tranid, uid, $"Authenticate: Invalid token format for {uid}");
                return(Unauthorized());
            }

            var tran    = TranToken.Parse(bytesToken);
            var account = await _manager.GetById(uid);

            if (account == null || tran == null || !tran.Check(account.PrismiAuth, uid.ToByteArray()))
            {
                if (account == null)
                {
                    _logger.LoginUnsuccessful(ControllerContext.ActionDescriptor.ControllerName, tranid, uid, $"Authenticate: Account {uid} does not exist");
                }
                else
                {
                    _logger.LoginUnsuccessful(ControllerContext.ActionDescriptor.ControllerName, tranid, uid, $"Authenticate: Invalid token for {uid}");
                }

                return(Unauthorized("Invalid account or signature"));
            }

            if (!tran.OnTime)
            {
                _logger.LoginUnsuccessful(ControllerContext.ActionDescriptor.ControllerName, tranid, uid, $"Authenticate: Expired token for {uid}");
                return(StatusCode(418, new TranToken().ToString()));
            }

            _logger.LoginSuccessful(ControllerContext.ActionDescriptor.ControllerName, tranid, uid, $"Authenticate: Successful login for {uid}");
            var cvkAuthi = (point * account.Cmki).ToByteArray();

            return(Ok(account.PrismiAuth.EncryptStr(cvkAuthi)));
        }
        public async Task <ActionResult> Decrypt([FromRoute] Guid vuid, [FromRoute] Guid keyId, [FromBody] string data, string token, string sign)
        {
            var msgErr  = $"Denied data decryption belonging to {vuid}";
            var account = await _managerCvk.GetById(vuid);

            var tran = TranToken.Parse(Convert.FromBase64String(token.DecodeBase64Url()));

            if (!tran.Check(account.CvkiAuth))
            {
                _logger.LogInformation("Decryption denied for vuid {0} with keyId {1}: Invalid token.", vuid, keyId);
                return(BadRequest(msgErr));
            }

            var keyPub = await _keyIdManager.GetById(keyId);

            if (keyPub == null)
            {
                _logger.LogInformation("Decryption denied for vuid {0} with keyId {1}: keyId not found.", vuid, keyId);
                return(BadRequest(msgErr));
            }

            var buffers = GetBytes(data);

            if (buffers.Any(bff => !Cipher.CheckAsymmetric(bff, account.CvkPub)))
            {
                _logger.LogInformation("Decryption denied for vuid {0} with keyId {1}: Invalid asymmetric data.", vuid, keyId);
                return(BadRequest(msgErr));
            }

            var tags  = buffers.Select(bff => Cipher.GetTag(bff)).Distinct().ToList();
            var rules = (await _ruleManager.GetSetBy(account.VuId, tags, keyPub.Id)).Where(rl => rl.Eval()).ToList();

            if (!tags.All(tag => rules.Where(rule => tag == rule.Tag).Any(rule => rule.IsAllowed)))
            {
                _logger.LogInformation("Decryption denied for vuid {0} with keyId {1}: No rule to allow decryption. Tags: " + string.Join(' ', tags), vuid, keyId);
                return(BadRequest(msgErr));
            }

            if (tags.Any(tag => rules.Where(rule => tag == rule.Tag).Any(rule => rule.IsDenied)))
            {
                _logger.LogInformation("Decryption denied for vuid {0} with keyId {1}: Denied by rule", vuid, keyId);
                return(BadRequest(msgErr));
            }

            var bufferSign = Convert.FromBase64String(sign.DecodeBase64Url());
            var sessionKey = tran.GenKey(account.CvkiAuth);

            if (!Utils.Equals(sessionKey.Hash(buffers.SelectMany(bff => bff).ToArray()), bufferSign))
            {
                _logger.LogInformation("Decryption denied for vuid {0} with keyId {1}: Invalid symmetric data signature.", vuid, keyId);
                return(BadRequest(msgErr));
            }

            var c1s = buffers.Select(bff => Cipher.GetCipherC1(bff)).ToList();

            if (c1s.Any(c1 => !c1.IsValid))
            {
                _logger.LogInformation("Decryption denied for vuid {0} with keyId {1}: Invalid data point.", vuid, keyId);
                return(BadRequest(msgErr));
            }

            _logger.LogInformation("Decryption granted for vuid {0} with keyId {1}", vuid, keyId);
            var partials = c1s.Select(c1 => (c1 * account.CVKi).ToByteArray())
                           .Select(bff => Convert.ToBase64String(sessionKey.Encrypt(bff)));

            return(Ok(string.Join(Environment.NewLine, partials)));
        }