public byte[] Unprotect(byte[] protectedData)
        {
            protectedData = protectedData.UnGZip();

            var cacheKey = protectedData.ToBase64String();

            return(CachedDecrptedData.GetOrAdd(cacheKey, (key) =>
            {
                var keyLength = protectedData.First();
                var encryptionKeyReference = protectedData.Skip(1).Take(keyLength).ToArray();
                var dataPart = protectedData.Skip(1 + keyLength).ToArray();

                var encryptionKey = DataKeyService.GetEncryptionKey(encryptionKeyReference);
                return CreateProtector(encryptionKey).Unprotect(dataPart);
            }));
        }
        public byte[] Protect(byte[] plaintext)
        {
            var key = Task.Factory.RunSync(() => DataKeyService.GenerateKey());

            var encryptedData = CreateProtector(key.EncryptionKey).Protect(plaintext);

            // To make it secure, we should combine the key's length, the key and the cipher data.
            var cipher = key.EncryptionKeyReference;

            if (cipher.Length > byte.MaxValue)
            {
                throw new Exception("Cipher key is longer than a byte!");
            }

            return(new byte[] { (byte)cipher.Length }
                   .Concat(cipher, encryptedData).ToArray().GZip());
        }