public UserData registerUser(string username, string password)
        {
            // PBKDF2
            string pwsalt = "";
            string pwhash = "";
            // password hash
            using (var db = new Rfc2898DeriveBytes(password, SALT_SIZE, ITERATIONS))
            {
                pwsalt = Convert.ToBase64String(db.Salt);
                pwhash = Convert.ToBase64String(db.GetBytes(KEY_SIZE));

            }
            // KEK
            string keksalt = "";
            string kek = "";
            // kek generation
            using (var db = new Rfc2898DeriveBytes(password, SALT_SIZE, ITERATIONS))
            {
                keksalt = Convert.ToBase64String(db.Salt);
                kek = Convert.ToBase64String(db.GetBytes(KEY_SIZE));
            }
            // RSA
            string publickey;
            string privatekey;
            string privateiv;
            string encryptedprivatekey;
            // Generate RSA key pair
            using (var rsa = new RSACryptoServiceProvider(RSA_SIZE))
            {
                try
                {
                    privatekey = rsa.ToXmlString(true);
                    publickey = rsa.ToXmlString(false);
                }
                finally
                {
                    // IMPORTANT, avoid storing key in windows store
                    rsa.PersistKeyInCsp = false;
                }
            }
            byte[] privatekeyb = Encoding.UTF8.GetBytes(privatekey);

            /*
            logF("register user {0} , password {1}", username, password);
            log("");
            logF("kek {0}", kek);
            log("");
            logF("privatekey {0}", privatekey);
            log("");
            */
            using (var cipher = new AesManaged())
            {
                cipher.Mode = CipherMode.CBC;
                cipher.KeySize = 128;
                cipher.BlockSize = 128;
                cipher.Padding = PaddingMode.PKCS7;
                //
                cipher.GenerateIV();
                privateiv = Convert.ToBase64String(cipher.IV);
                cipher.Key = Convert.FromBase64String(kek);
                cipher.IV = Convert.FromBase64String(privateiv);
                using (ICryptoTransform encryptor = cipher.CreateEncryptor(cipher.Key,cipher.IV))
                {
                    using (MemoryStream to = new MemoryStream())
                    {
                        using (CryptoStream writer = new CryptoStream(to, encryptor, CryptoStreamMode.Write))
                        {

                            writer.Write(privatekeyb, 0, privatekeyb.Length);
                            writer.FlushFinalBlock();
                            encryptedprivatekey = Convert.ToBase64String(to.ToArray());
                        }
                    }
                }

                cipher.Clear();
            }

            UserData ud = new UserData()
            {
                username = username,
                passwordSalt = pwsalt,
                passwordHash = pwhash,
                KEKSalt = keksalt,
                privateIV = privateiv,
                publicKey = publickey,
                encryptedPrivateKey = encryptedprivatekey
            };
            return ud;
        }
        /*
        private void writeObject(SslStream sslStream, object obj)
        {

            byte[] userDataBytes;
            MemoryStream ms = new MemoryStream();
            BinaryFormatter bf1 = new BinaryFormatter();
            bf1.Serialize(ms, obj);
            userDataBytes = ms.ToArray();
            byte[] userDataLen = BitConverter.GetBytes((Int32)userDataBytes.Length);
            sslStream.Write(userDataLen, 0, 4);
            sslStream.Write(userDataBytes, 0, userDataBytes.Length);
            logF("Sent an object of type {0} length {1}:", obj.GetType(), userDataBytes.Length);
            log(Util.XmlSerializeToString(obj));
        }

        private object readObject(SslStream sslStream)
        {
            byte[] readMsgLen = new byte[4];
            int dataRead = 0;
            do
            {
                dataRead += sslStream.Read(readMsgLen, 0, 4 - dataRead);
            } while (dataRead < 4);

            int dataLen = BitConverter.ToInt32(readMsgLen,0);
            logF("header: message length {0}", dataLen);
            if(dataLen == 0)
            {
                return null;
            }
            byte[] readMsgData = new byte[dataLen];

            int len = dataLen;
            dataRead = 0;
            do
            {
                dataRead += sslStream.Read(readMsgData, dataRead, len - dataRead);

            } while (dataRead < len);
            logF("received {0} bytes", len) ;
            //deserialize
            MemoryStream ms = new MemoryStream(readMsgData);
            BinaryFormatter bf1 = new BinaryFormatter();
            ms.Position = 0;
            object rawObj = bf1.Deserialize(ms);
            log(Util.XmlSerializeToString(rawObj));
            return rawObj;
        }*/
        public SecureCalendar registerCalendar(string username, string password, UserData userdata)
        {
            SecureCalendar sc = new SecureCalendar() { };

            // KEK
            string FEK = "";
            string events = "10:00 Dev team meeting. 20:00 Son birthday party";

            // kek generation
            using (var db = new Rfc2898DeriveBytes(password, SALT_SIZE, ITERATIONS))
            {
                db.Salt = Convert.FromBase64String(userdata.KEKSalt);
                FEK = Convert.ToBase64String(db.GetBytes(KEY_SIZE));
            }
            // generate KEK
            using (var cipher = new AesManaged())
            {
                cipher.Mode = CipherMode.CBC;
                cipher.KeySize = KEY_SIZE * 8;
                cipher.GenerateKey();
                cipher.GenerateIV();
                FEK = Convert.ToBase64String(cipher.Key);
                sc.IV = Convert.ToBase64String(cipher.IV);
                using (ICryptoTransform encryptor = cipher.CreateEncryptor(
                    cipher.Key,
                    cipher.IV))
                {
                    using (MemoryStream to = new MemoryStream())
                    {
                        using (CryptoStream writer = new CryptoStream(to, encryptor, CryptoStreamMode.Write))
                        {
                            byte[] x = Encoding.UTF8.GetBytes(Util.XmlSerializeToString(events));
                            writer.Write(x, 0, x.Length);
                            writer.FlushFinalBlock();
                            sc.encryptedEvents = Convert.ToBase64String(to.ToArray());
                        }
                    }
                }
                cipher.Clear();
            }
            //Encode FEK with public key
            RSACryptoServiceProvider rsaPublic = new RSACryptoServiceProvider();
            rsaPublic.FromXmlString(userdata.publicKey);
            byte[] eFEKb = rsaPublic.Encrypt(Convert.FromBase64String(FEK), false);
            string eFEK = Convert.ToBase64String(eFEKb);
            sc.keys.Add(new EncryptedFileEncryptionKey() {
                username = username,
                eFEK = eFEK
            });
            return sc;
        }