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 WebServiceException DecryptedException(WebServiceException ex, byte[] cryptKey, byte[] authKey) { //Encrypted Messsage Exceptions are always written with 400 BadRequest if (ex.StatusCode != (int)HttpStatusCode.BadRequest) { if (ex.ResponseStatus == null) { ex.ResponseDto = ex.ResponseBody.FromJson <ErrorResponse>(); } return(ex); } var encResponse = ex.ResponseDto as EncryptedMessageResponse; if (encResponse != null) { var authEncryptedBytes = Convert.FromBase64String(encResponse.EncryptedBody); if (!HmacUtils.Verify(authEncryptedBytes, authKey)) { throw new Exception("EncryptedBody is Invalid"); } var responseBytes = HmacUtils.DecryptAuthenticated(authEncryptedBytes, cryptKey); var responseJson = responseBytes.FromUtf8Bytes(); var errorResponse = responseJson.FromJson <ErrorResponse>(); ex.ResponseDto = errorResponse; } return(ex); }
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); }); }