Beispiel #1
0
        public TResponse Send <TResponse>(string httpMethod, object request)
        {
            byte[] cryptKey, authKey, iv;
            AesUtils.CreateCryptAuthKeysAndIv(out cryptKey, out authKey, out iv);

            try
            {
                var encryptedMessage = CreateEncryptedMessage(request, request.GetType().Name, cryptKey, authKey, iv, httpMethod);
                var encResponse      = Client.Send(encryptedMessage);

                var authEncryptedBytes = Convert.FromBase64String(encResponse.EncryptedBody);

                if (!HmacUtils.Verify(authEncryptedBytes, authKey))
                {
                    throw new Exception("Invalid EncryptedBody");
                }

                var decryptedBytes = HmacUtils.DecryptAuthenticated(authEncryptedBytes, cryptKey);

                var responseJson = decryptedBytes.FromUtf8Bytes();
                var response     = responseJson.FromJson <TResponse>();

                return(response);
            }
            catch (WebServiceException ex)
            {
                throw DecryptedException(ex, cryptKey, authKey);
            }
        }
Beispiel #2
0
        public List <TResponse> SendAll <TResponse>(IEnumerable <object> requests)
        {
            byte[] cryptKey, authKey, iv;
            AesUtils.CreateCryptAuthKeysAndIv(out cryptKey, out authKey, out iv);

            try
            {
                var elType           = requests.GetType().GetCollectionType();
                var encryptedMessage = CreateEncryptedMessage(requests, elType.Name + "[]", cryptKey, authKey, iv);
                var encResponse      = Client.Send(encryptedMessage);

                var authEncryptedBytes = Convert.FromBase64String(encResponse.EncryptedBody);

                if (!HmacUtils.Verify(authEncryptedBytes, authKey))
                {
                    throw new Exception("Invalid EncryptedBody");
                }

                var decryptedBytes = HmacUtils.DecryptAuthenticated(authEncryptedBytes, cryptKey);

                var responseJson = decryptedBytes.FromUtf8Bytes();
                var response     = responseJson.FromJson <List <TResponse> >();

                return(response);
            }
            catch (WebServiceException ex)
            {
                throw DecryptedException(ex, cryptKey, authKey);
            }
        }
Beispiel #3
0
        public EncryptedMessage CreateEncryptedMessage(object request, string operationName, byte[] cryptKey, byte[] authKey, byte[] iv, string verb = null)
        {
            this.PopulateRequestMetadata(request);

            if (verb == null)
            {
                verb = HttpMethods.Post;
            }

            var cryptAuthKeys = cryptKey.Combine(authKey);

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

            var timestamp   = DateTime.UtcNow.ToUnixTime();
            var requestBody = timestamp + " " + verb + " " + operationName + " " + request.ToJson();

            var encryptedBytes     = AesUtils.Encrypt(requestBody.ToUtf8Bytes(), cryptKey, iv);
            var authEncryptedBytes = HmacUtils.Authenticate(encryptedBytes, authKey, iv);

            var encryptedMessage = new EncryptedMessage
            {
                KeyId = KeyId,
                EncryptedSymmetricKey = Convert.ToBase64String(authRsaEncCryptAuthKeys),
                EncryptedBody         = Convert.ToBase64String(authEncryptedBytes),
            };

            return(encryptedMessage);
        }
        public EncryptedMessage CreateEncryptedMessage(object request, string operationName, SymmetricAlgorithm aes, string verb = null)
        {
            this.PopulateRequestMetadata(request);

            var aesKeyBytes = aes.Key.Combine(aes.IV);

            var rsaEncAesKeyBytes = RsaUtils.Encrypt(aesKeyBytes, PublicKey);

            if (verb == null)
            {
                verb = HttpMethods.Post;
            }

            var timestamp = DateTime.UtcNow.ToUnixTime();

            var requestBody = timestamp + " " + verb + " " + operationName + " " + JsonServiceClient.ToJson(request);

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

            return(encryptedMessage);
        }
Beispiel #5
0
        public static byte[] DecryptAuthenticated(byte[] authEncryptedBytes, byte[] cryptKey)
        {
            if (cryptKey == null || cryptKey.Length != KeySizeBytes)
            {
                throw new ArgumentException($"CryptKey needs to be {KeySize} bits", nameof(cryptKey));
            }

            //Grab IV from message
            var iv = new byte[AesUtils.BlockSizeBytes];

            Buffer.BlockCopy(authEncryptedBytes, 0, iv, 0, iv.Length);

            using (var aes = AesUtils.CreateSymmetricAlgorithm())
            {
                using (var decrypter = aes.CreateDecryptor(cryptKey, iv))
                    using (var decryptedStream = new MemoryStream())
                    {
                        using (var decrypterStream = new CryptoStream(decryptedStream, decrypter, CryptoStreamMode.Write))
                            using (var writer = new BinaryWriter(decrypterStream))
                            {
                                //Decrypt Cipher Text from Message
                                writer.Write(
                                    authEncryptedBytes,
                                    iv.Length,
                                    authEncryptedBytes.Length - iv.Length - KeySizeBytes);
                            }

                        return(decryptedStream.ToArray());
                    }
            }
        }
Beispiel #6
0
        public static void WriteEncryptedError(IRequest req, byte[] cryptKey, byte[] authKey, byte[] iv, Exception ex, string description = null)
        {
            var error = new ErrorResponse
            {
                ResponseStatus = ex.ToResponseStatus()
            };

            var responseBodyBytes  = error.ToJson().ToUtf8Bytes();
            var encryptedBytes     = AesUtils.Encrypt(responseBodyBytes, cryptKey, iv);
            var authEncryptedBytes = HmacUtils.Authenticate(encryptedBytes, authKey, iv);

            var httpError = ex as IHttpError;

            req.Response.StatusCode        = (int)HttpStatusCode.BadRequest;
            req.Response.StatusDescription = description ?? (httpError != null ? httpError.ErrorCode : ex.GetType().Name);

            var errorResponse = new EncryptedMessageResponse
            {
                EncryptedBody = Convert.ToBase64String(authEncryptedBytes)
            };

            req.Response.ContentType = MimeTypes.Json;
            req.Response.Write(errorResponse.ToJson());
            req.Response.EndRequest();
        }
        public WebServiceException DecryptedException(WebServiceException ex, SymmetricAlgorithm aes)
        {
            var encResponse = ex.ResponseDto as EncryptedMessageResponse;

            if (encResponse != null)
            {
                var responseJson  = AesUtils.Decrypt(encResponse.EncryptedBody, aes.Key, aes.IV);
                var errorResponse = JsonServiceClient.FromJson <ErrorResponse>(responseJson);
                ex.ResponseDto = errorResponse;
            }

            return(ex);
        }
Beispiel #8
0
        public void Publish(object request)
        {
            byte[] cryptKey, authKey, iv;
            AesUtils.CreateCryptAuthKeysAndIv(out cryptKey, out authKey, out iv);

            try
            {
                var encryptedMessage = CreateEncryptedMessage(request, request.GetType().Name, cryptKey, authKey, iv);
                Client.SendOneWay(encryptedMessage);
            }
            catch (WebServiceException ex)
            {
                throw DecryptedException(ex, cryptKey, authKey);
            }
        }
Beispiel #9
0
        public void PublishAll(IEnumerable <object> requests)
        {
            byte[] cryptKey, authKey, iv;
            AesUtils.CreateCryptAuthKeysAndIv(out cryptKey, out authKey, out iv);

            try
            {
                var elType           = requests.GetType().GetCollectionType();
                var encryptedMessage = CreateEncryptedMessage(requests, elType.Name + "[]", cryptKey, authKey, iv);
                Client.SendOneWay(encryptedMessage);
            }
            catch (WebServiceException ex)
            {
                throw DecryptedException(ex, cryptKey, authKey);
            }
        }
        public TResponse Send <TResponse>(string httpMethod, object request)
        {
            using (var aes = new AesManaged {
                KeySize = AesUtils.KeySize
            })
            {
                try
                {
                    var encryptedMessage = CreateEncryptedMessage(request, request.GetType().Name, aes, httpMethod);
                    var encResponse      = Client.Send(encryptedMessage);

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

                    return(response);
                }
                catch (WebServiceException ex)
                {
                    throw DecryptedException(ex, aes);
                }
            }
        }
        public List <TResponse> SendAll <TResponse>(IEnumerable <IReturn <TResponse> > requests)
        {
            using (var aes = new AesManaged {
                KeySize = AesUtils.KeySize
            })
            {
                try
                {
                    var elType           = requests.GetType().GetCollectionType();
                    var encryptedMessage = CreateEncryptedMessage(requests, elType.Name + "[]", aes);
                    var encResponse      = Client.Send(encryptedMessage);

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

                    return(response);
                }
                catch (WebServiceException ex)
                {
                    throw DecryptedException(ex, aes);
                }
            }
        }
Beispiel #12
0
        public static void WriteEncryptedError(IRequest req, byte[] aesKey, byte[] iv, Exception ex, string description = null)
        {
            var error = new ErrorResponse {
                ResponseStatus = ex.ToResponseStatus()
            };

            var responseBody  = error.ToJson();
            var encryptedBody = AesUtils.Encrypt(responseBody, aesKey, iv);

            var httpError = ex as IHttpError;

            req.Response.StatusCode        = (int)HttpStatusCode.BadRequest;
            req.Response.StatusDescription = description ?? (httpError != null ? httpError.ErrorCode : ex.GetType().Name);

            var errorResponse = new EncryptedMessageResponse
            {
                EncryptedBody = encryptedBody
            };

            req.Response.ContentType = MimeTypes.Json;
            req.Response.Write(errorResponse.ToJson());
            req.Response.EndRequest();
        }
Beispiel #13
0
        public void Register(IAppHost appHost)
        {
            if (PrivateKey == null)
            {
                PrivateKey = RsaUtils.CreatePrivateKeyParams();
            }

            appHost.RegisterService(typeof(EncryptedMessagesService), PublicKeyPath);

            PrivateKeyModulusMap = new Dictionary <string, RSAParameters>
            {
                { Convert.ToBase64String(PrivateKey.Value.Modulus), PrivateKey.Value },
            };
            foreach (var fallbackKey in FallbackPrivateKeys)
            {
                PrivateKeyModulusMap[Convert.ToBase64String(fallbackKey.Modulus)] = fallbackKey;
            }

            appHost.RequestConverters.Add((req, requestDto) =>
            {
                var encRequest = requestDto as EncryptedMessage;
                if (encRequest == null)
                {
                    return(null);
                }

                var cryptKey        = new byte[AesUtils.KeySizeBytes];
                var authKey         = new byte[AesUtils.KeySizeBytes];
                var iv              = new byte[AesUtils.BlockSizeBytes];
                const int tagLength = HmacUtils.KeySizeBytes;
                try
                {
                    var privateKey = GetPrivateKey(encRequest.KeyId);
                    if (Equals(privateKey, default(RSAParameters)))
                    {
                        WriteUnencryptedError(req, HttpError.NotFound(ErrorKeyNotFound.Fmt(encRequest.KeyId, PublicKeyPath)), "KeyNotFoundException");
                        return(null);
                    }

                    var authRsaEncCryptKey = Convert.FromBase64String(encRequest.EncryptedSymmetricKey);

                    var rsaEncCryptAuthKeys = new byte[authRsaEncCryptKey.Length - iv.Length - tagLength];

                    Buffer.BlockCopy(authRsaEncCryptKey, 0, iv, 0, iv.Length);
                    Buffer.BlockCopy(authRsaEncCryptKey, iv.Length, rsaEncCryptAuthKeys, 0, rsaEncCryptAuthKeys.Length);

                    var cryptAuthKeys = RsaUtils.Decrypt(rsaEncCryptAuthKeys, privateKey);

                    Buffer.BlockCopy(cryptAuthKeys, 0, cryptKey, 0, cryptKey.Length);
                    Buffer.BlockCopy(cryptAuthKeys, cryptKey.Length, authKey, 0, authKey.Length);

                    //Needs to be after cryptKey,authKey populated
                    if (nonceCache.ContainsKey(iv))
                    {
                        throw HttpError.Forbidden(ErrorNonceSeen);
                    }

                    var now = DateTime.UtcNow;
                    nonceCache.TryAdd(iv, now.Add(MaxRequestAge));

                    if (!HmacUtils.Verify(authRsaEncCryptKey, authKey))
                    {
                        throw new Exception("EncryptedSymmetricKey is Invalid");
                    }

                    var authEncryptedBytes = Convert.FromBase64String(encRequest.EncryptedBody);

                    if (!HmacUtils.Verify(authEncryptedBytes, authKey))
                    {
                        throw new Exception("EncryptedBody is Invalid");
                    }

                    var requestBodyBytes = HmacUtils.DecryptAuthenticated(authEncryptedBytes, cryptKey);
                    var requestBody      = requestBodyBytes.FromUtf8Bytes();

                    if (string.IsNullOrEmpty(requestBody))
                    {
                        throw new ArgumentNullException("EncryptedBody");
                    }

                    var parts    = requestBody.SplitOnFirst(' ');
                    var unixTime = int.Parse(parts[0]);

                    var minRequestDate = now.Subtract(MaxRequestAge);
                    if (unixTime.FromUnixTime() < minRequestDate)
                    {
                        throw HttpError.Forbidden(ErrorRequestTooOld);
                    }

                    DateTime expiredEntry;
                    nonceCache.Where(x => now > x.Value).ToList()
                    .Each(entry => nonceCache.TryRemove(entry.Key, out expiredEntry));

                    parts = parts[1].SplitOnFirst(' ');
                    req.Items[Keywords.InvokeVerb] = parts[0];

                    parts             = parts[1].SplitOnFirst(' ');
                    var operationName = parts[0];
                    var requestJson   = parts[1];

                    var requestType = appHost.Metadata.GetOperationType(operationName);
                    var request     = JsonSerializer.DeserializeFromString(requestJson, requestType);

                    req.Items[RequestItemsCryptKey] = cryptKey;
                    req.Items[RequestItemsAuthKey]  = authKey;
                    req.Items[RequestItemsIv]       = iv;

                    return(request);
                }
                catch (Exception ex)
                {
                    WriteEncryptedError(req, cryptKey, authKey, iv, ex, ErrorInvalidMessage);
                    return(null);
                }
            });

            appHost.ResponseConverters.Add((req, response) =>
            {
                object oCryptKey, oAuthKey, oIv;
                if (!req.Items.TryGetValue(RequestItemsCryptKey, out oCryptKey) ||
                    !req.Items.TryGetValue(RequestItemsAuthKey, out oAuthKey) ||
                    !req.Items.TryGetValue(RequestItemsIv, out oIv))
                {
                    return(null);
                }

                req.Response.ClearCookies();

                var ex = response as Exception;
                if (ex != null)
                {
                    WriteEncryptedError(req, (byte[])oCryptKey, (byte[])oAuthKey, (byte[])oIv, ex);
                    return(null);
                }

                var responseBodyBytes  = response.ToJson().ToUtf8Bytes();
                var encryptedBytes     = AesUtils.Encrypt(responseBodyBytes, (byte[])oCryptKey, (byte[])oIv);
                var authEncryptedBytes = HmacUtils.Authenticate(encryptedBytes, (byte[])oAuthKey, (byte[])oIv);

                var encResponse = new EncryptedMessageResponse
                {
                    EncryptedBody = Convert.ToBase64String(authEncryptedBytes)
                };
                return(encResponse);
            });
        }
Beispiel #14
0
        public void Register(IAppHost appHost)
        {
            if (PrivateKey == null)
            {
                PrivateKey = RsaUtils.CreatePrivateKeyParams();
            }

            appHost.RegisterService(typeof(EncryptedMessagesService), PublicKeyPath);

            appHost.RequestConverters.Add((req, requestDto) =>
            {
                var encRequest = requestDto as EncryptedMessage;
                if (encRequest == null)
                {
                    return(null);
                }

                byte[] aesKey = null;
                byte[] iv     = null;
                try
                {
                    var rsaEncAesKeyBytes = RsaUtils.Decrypt(Convert.FromBase64String(encRequest.EncryptedSymmetricKey), PrivateKey.Value);

                    aesKey = new byte[AesUtils.KeySize / 8];
                    iv     = new byte[AesUtils.IvSize / 8];

                    Buffer.BlockCopy(rsaEncAesKeyBytes, 0, aesKey, 0, aesKey.Length);
                    Buffer.BlockCopy(rsaEncAesKeyBytes, aesKey.Length, iv, 0, iv.Length);

                    if (nonceCache.ContainsKey(iv))
                    {
                        throw HttpError.Forbidden(ErrorNonceSeen);
                    }

                    var now = DateTime.UtcNow;
                    nonceCache.TryAdd(iv, now.Add(MaxRequestAge));

                    var requestBodyBytes = AesUtils.Decrypt(Convert.FromBase64String(encRequest.EncryptedBody), aesKey, iv);
                    var requestBody      = requestBodyBytes.FromUtf8Bytes();

                    if (string.IsNullOrEmpty(requestBody))
                    {
                        throw new ArgumentNullException("EncryptedBody");
                    }

                    var parts    = requestBody.SplitOnFirst(' ');
                    var unixTime = int.Parse(parts[0]);

                    var minRequestDate = now.Subtract(MaxRequestAge);
                    if (unixTime.FromUnixTime() < minRequestDate)
                    {
                        throw HttpError.Forbidden(ErrorRequestTooOld);
                    }

                    DateTime expiredEntry;
                    nonceCache.Where(x => now > x.Value).ToList()
                    .Each(entry => nonceCache.TryRemove(entry.Key, out expiredEntry));

                    parts = parts[1].SplitOnFirst(' ');
                    req.Items[Keywords.InvokeVerb] = parts[0];

                    parts             = parts[1].SplitOnFirst(' ');
                    var operationName = parts[0];
                    var requestJson   = parts[1];

                    var requestType = appHost.Metadata.GetOperationType(operationName);
                    var request     = JsonSerializer.DeserializeFromString(requestJson, requestType);

                    req.Items[RequestItemsAesKey] = aesKey;
                    req.Items[RequestItemsIv]     = iv;

                    return(request);
                }
                catch (Exception ex)
                {
                    WriteEncryptedError(req, aesKey, iv, ex, ErrorInvalidMessage);
                    return(null);
                }
            });

            appHost.ResponseConverters.Add((req, response) =>
            {
                object oAesKey;
                object oIv;
                if (!req.Items.TryGetValue(RequestItemsAesKey, out oAesKey) ||
                    !req.Items.TryGetValue(RequestItemsIv, out oIv))
                {
                    return(null);
                }

                req.Response.ClearCookies();

                var ex = response as Exception;
                if (ex != null)
                {
                    WriteEncryptedError(req, (byte[])oAesKey, (byte[])oIv, ex);
                    return(null);
                }

                var responseBody  = response.ToJson();
                var encryptedBody = AesUtils.Encrypt(responseBody, (byte[])oAesKey, (byte[])oIv);
                return(new EncryptedMessageResponse
                {
                    EncryptedBody = encryptedBody
                });
            });
        }