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); } }
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); } }
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); }
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()); } } }
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); }
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); } }
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); } } }
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(); }
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); }); }
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 }); }); }