From 78ba78c22bb044714ebd0868e7b6b5bf1f22b000 Mon Sep 17 00:00:00 2001
From: Markus Quaritsch <markus.quaritsch@tugraz.at>
Date: Fri, 15 Sep 2017 10:33:31 +0200
Subject: [PATCH] fix: updating canonicalization method works; corrected
 comparison of job hash for report integrity checks

---
 HashingTool/Helper/HashingHelper.cs           |  10 +-
 .../ViewModel/HashComponentDataViewModel.cs   |  23 +-
 HashingTool/ViewModel/HashedXMLFile.cs        |  81 +++++--
 .../VerifyComponentInputDataViewModel.cs      |  12 +-
 .../ViewModel/VerifyResultDataViewModel.cs    |  50 ++--
 .../Views/VerifyComponentInputData.xaml       |   2 +-
 HashingTool/Views/VerifyResults.xaml          | 216 +++++++++++++-----
 7 files changed, 272 insertions(+), 122 deletions(-)

diff --git a/HashingTool/Helper/HashingHelper.cs b/HashingTool/Helper/HashingHelper.cs
index cac69844fc..c3bebafe4d 100644
--- a/HashingTool/Helper/HashingHelper.cs
+++ b/HashingTool/Helper/HashingHelper.cs
@@ -91,10 +91,7 @@ namespace HashingTool.Helper
 				var h = VectoHash.Load(xml);
 				xmlViewModel.DigestValueComputed = h.ComputeHash();
 				xmlViewModel.DigestMethod = h.GetDigestMethod();
-				var c14N = h.GetCanonicalizationMethods().ToArray();
-				foreach (var c in c14N) {
-					xmlViewModel.CanonicalizationMethods.Add(c);
-				}
+				xmlViewModel.SetCanonicalizationMethod(h.GetCanonicalizationMethods());
 			} catch (Exception e) {
 				xmlViewModel.XMLFile.XMLValidationErrors.Add(e.Message);
 				xmlViewModel.DigestValueComputed = "";
@@ -110,10 +107,7 @@ namespace HashingTool.Helper
 			try {
 				var h = VectoHash.Load(xml);
 				report.DigestMethod = h.GetDigestMethod();
-				var c14N = h.GetCanonicalizationMethods().ToArray();
-				foreach (var c in c14N) {
-					report.CanonicalizationMethods.Add(c);
-				}
+				report.SetCanonicalizationMethod(h.GetCanonicalizationMethods());
 				try {
 					report.DigestValueRead = h.ReadHash();
 				} catch {
diff --git a/HashingTool/ViewModel/HashComponentDataViewModel.cs b/HashingTool/ViewModel/HashComponentDataViewModel.cs
index e5287341b8..7d9df0b825 100644
--- a/HashingTool/ViewModel/HashComponentDataViewModel.cs
+++ b/HashingTool/ViewModel/HashComponentDataViewModel.cs
@@ -62,8 +62,9 @@ namespace HashingTool.ViewModel
 
 		private void SourceChanged(object sender, PropertyChangedEventArgs e)
 		{
-			if (e.PropertyName == "Document" || e.PropertyName == "IsValid")
-			DoComputeHash();
+			if (e.PropertyName == "Document" || e.PropertyName == "IsValid") {
+				DoComputeHash();
+			}
 		}
 
 		private void SaveDocument()
@@ -104,7 +105,7 @@ namespace HashingTool.ViewModel
 				ComponentDataValid = false;
 				DigestValue = "";
 				DigestMethod = "";
-				CanonicalizationMethods.Clear();
+				SetCanonicalizationMethod(new string[] { });
 				return;
 			}
 
@@ -113,7 +114,7 @@ namespace HashingTool.ViewModel
 				ComponentDataValid = false;
 				DigestValue = "";
 				_xmlFile.XMLValidationErrors.Clear();
-				CanonicalizationMethods.Clear();
+				SetCanonicalizationMethod(new string[] { });
 
 				var h = VectoHash.Load(_xmlFile.Document);
 
@@ -152,21 +153,17 @@ namespace HashingTool.ViewModel
 						ms.Flush();
 						ms.Seek(0, SeekOrigin.Begin);
 						var h2 = VectoHash.Load(ms);
-						var c14N = h2.GetCanonicalizationMethods().ToArray();
-						var digestMethod = h2.GetDigestMethod();
-						DigestValue = h.ReadHash();
-						foreach (var c in c14N) {
-							CanonicalizationMethods.Add(c);
-						}
-						RaisePropertyChanged("CanonicalizationMethods");
-						DigestMethod = digestMethod;
+						DigestMethod = h2.GetDigestMethod();
+						DigestValue = h2.ReadHash();
+						SetCanonicalizationMethod(h2.GetCanonicalizationMethods());
 					}
 				}
 			} catch (Exception e) {
 				ComponentDataValid = false;
 				DigestValue = "";
 				_xmlFile.XMLValidationErrors.Add(e.Message);
-				CanonicalizationMethods.Clear();
+				SetCanonicalizationMethod(new string[] { });
+				DigestMethod = "";
 			} finally {
 				_busy = false;
 				_saveCommand.RaiseCanExecuteChanged();
diff --git a/HashingTool/ViewModel/HashedXMLFile.cs b/HashingTool/ViewModel/HashedXMLFile.cs
index eb0db4f57a..cd02b40d9d 100644
--- a/HashingTool/ViewModel/HashedXMLFile.cs
+++ b/HashingTool/ViewModel/HashedXMLFile.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.ComponentModel;
 using System.Linq;
@@ -78,6 +79,15 @@ namespace HashingTool.ViewModel
 
 		public ObservableCollection<string> CanonicalizationMethods { get; private set; }
 
+		public void SetCanonicalizationMethod(IEnumerable<string> c14NMethods)
+		{
+			CanonicalizationMethods.Clear();
+			foreach (var c14N in c14NMethods) {
+				CanonicalizationMethods.Add(c14N);
+			}
+			RaisePropertyChanged("CanonicalizationMethods");
+		}
+
 		public string DigestMethod
 		{
 			get { return _digestMethod; }
@@ -163,9 +173,11 @@ namespace HashingTool.ViewModel
 
 	public class ReportXMLFile : HashedXMLFile
 	{
-		private string _jobDigestValueRead;
-		private string _jobDigestMethod;
-		private string[] _jobCanonicalizationMethod;
+		private string _jobDigestValueReadRead;
+		private string _jobDigestMethodRead;
+		private string[] _jobCanonicalizationMethodRead;
+		private string _jobDigestComputed;
+		private bool _jobDigestValid;
 
 		public ReportXMLFile(string name, Func<XmlDocument, Collection<string>, bool?> contentCheck,
 			Action<XmlDocument, VectoXMLFile> hashValidation = null)
@@ -202,44 +214,69 @@ namespace HashingTool.ViewModel
 					jobc14NMethod = (from XmlNode node in c14NtMethodNodes select node.InnerText).ToArray();
 				}
 			}
-			JobCanonicalizationMethod = jobc14NMethod;
-			JobDigestMethod = jobDigestMethod;
-			JobDigestValue = jobDigest;
+			JobCanonicalizationMethodRead = jobc14NMethod;
+			JobDigestMethodRead = jobDigestMethod;
+			JobDigestValueRead = jobDigest;
 		}
 
-		public string JobDigestMethod
+		public string JobDigestMethodRead
 		{
-			get { return _jobDigestMethod; }
+			get { return _jobDigestMethodRead; }
 			set {
-				if (_jobDigestMethod == value) {
+				if (_jobDigestMethodRead == value) {
 					return;
 				}
-				_jobDigestMethod = value;
-				RaisePropertyChanged("JobDigestMethod");
+				_jobDigestMethodRead = value;
+				RaisePropertyChanged("JobDigestMethodRead");
 			}
 		}
 
-		public string[] JobCanonicalizationMethod
+		public string[] JobCanonicalizationMethodRead
 		{
-			get { return _jobCanonicalizationMethod; }
+			get { return _jobCanonicalizationMethodRead; }
 			set {
-				if (_jobCanonicalizationMethod == value) {
+				if (_jobCanonicalizationMethodRead == value) {
 					return;
 				}
-				_jobCanonicalizationMethod = value;
-				RaisePropertyChanged("JobCanonicalizationMethod");
+				_jobCanonicalizationMethodRead = value;
+				RaisePropertyChanged("JobCanonicalizationMethodRead");
 			}
 		}
 
-		public string JobDigestValue
+		public string JobDigestValueRead
 		{
-			get { return _jobDigestValueRead; }
+			get { return _jobDigestValueReadRead; }
 			internal set {
-				if (_jobDigestValueRead == value) {
+				if (_jobDigestValueReadRead == value) {
+					return;
+				}
+				_jobDigestValueReadRead = value;
+				RaisePropertyChanged("JobDigestValueRead");
+			}
+		}
+
+		public string JobDigestValueComputed
+		{
+			get { return _jobDigestComputed; }
+			set {
+				if (_jobDigestComputed == value) {
+					return;
+				}
+				_jobDigestComputed = value;
+				RaisePropertyChanged("JobDigestValueComputed");
+				JobDigestValid = JobDigestValueComputed == JobDigestValueRead;
+			}
+		}
+
+		public bool JobDigestValid
+		{
+			get { return _jobDigestValid; }
+			set {
+				if (_jobDigestValid == value) {
 					return;
 				}
-				_jobDigestValueRead = value;
-				RaisePropertyChanged("JobDigestValue");
+				_jobDigestValid = value;
+				RaisePropertyChanged("JobDigestValid");
 			}
 		}
 	}
@@ -296,7 +333,7 @@ namespace HashingTool.ViewModel
 				Components.Clear();
 				DigestValueComputed = "";
 				DigestMethod = "";
-				CanonicalizationMethods.Clear();
+				SetCanonicalizationMethod(new string[] { });
 				JobDataValid = false;
 				return;
 			}
diff --git a/HashingTool/ViewModel/VerifyComponentInputDataViewModel.cs b/HashingTool/ViewModel/VerifyComponentInputDataViewModel.cs
index 8ee365ba66..a2479bbc86 100644
--- a/HashingTool/ViewModel/VerifyComponentInputDataViewModel.cs
+++ b/HashingTool/ViewModel/VerifyComponentInputDataViewModel.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Collections.Generic;
 using System.ComponentModel;
 using System.IO;
 using System.Linq;
@@ -9,7 +10,7 @@ using TUGraz.VectoHashing;
 
 namespace HashingTool.ViewModel
 {
-	public class VerifyComponentInputDataViewModel : HashedXMLFile, IMainView
+	public class VerifyComponentInputDataViewModel : HashedXMLFile, IMainView, INotifyPropertyChanged
 	{
 		private bool _componentDataValid;
 
@@ -66,19 +67,18 @@ namespace HashingTool.ViewModel
 				DigestValueComputed = h.ComputeHash();
 				ComponentDataValid = h.ValidateHash();
 				DigestMethod = h.GetDigestMethod();
-				CanonicalizationMethods.Clear();
-				foreach (var c in h.GetCanonicalizationMethods().ToArray()) {
-					CanonicalizationMethods.Add(c);
-				}
+				SetCanonicalizationMethod(h.GetCanonicalizationMethods());
+				
 			} catch (Exception e) {
 				ComponentDataValid = false;
 				DigestValueComputed = "";
 				DigestValueRead = "";
 				Component = "";
-				CanonicalizationMethods.Clear();
+				SetCanonicalizationMethod(new string[] { });
 				DigestMethod = "";
 				_xmlFile.XMLValidationErrors.Add(e.Message);
 			}
 		}
+
 	}
 }
diff --git a/HashingTool/ViewModel/VerifyResultDataViewModel.cs b/HashingTool/ViewModel/VerifyResultDataViewModel.cs
index cea7da0bdd..52baf9e984 100644
--- a/HashingTool/ViewModel/VerifyResultDataViewModel.cs
+++ b/HashingTool/ViewModel/VerifyResultDataViewModel.cs
@@ -31,8 +31,10 @@ namespace HashingTool.ViewModel
 
 		private void Update(object sender, PropertyChangedEventArgs e)
 		{
-			RaisePropertyChanged("ManufacturerReportValid");
-			RaisePropertyChanged("CustomerReportReportValid");
+			//RaisePropertyChanged("ManufacturerReportValid");
+			//RaisePropertyChanged("CustomerReportReportValid");
+			UpdateReportJobDigest(_manufacturerReport);
+			UpdateReportJobDigest(_customerReport);
 		}
 
 
@@ -64,21 +66,43 @@ namespace HashingTool.ViewModel
 
 		public ObservableCollection<VectoXMLFile> Files { get; private set; }
 
-		public bool ManufacturerReportValid
+		//public bool ManufacturerReportValid
+		//{
+		//	get {
+		private void UpdateReportJobDigest(ReportXMLFile reportXML)
 		{
-			get {
-				return _manufacturerReport.Valid != null && _manufacturerReport.Valid.Value &&
-						_manufacturerReport.JobDigestValue == _jobFile.DigestValueComputed;
+			if (reportXML.Valid == null || !reportXML.Valid.Value) {
+				reportXML.JobDigestValueComputed = "";
+				return;
 			}
-		}
-
-		public bool CustomerReportReportValid
-		{
-			get {
-				return _customerReport.Valid != null && _customerReport.Valid.Value &&
-						_customerReport.JobDigestValue == _jobFile.DigestValueComputed;
+			try {
+				var h = VectoHash.Load(_jobFile.XMLFile.Document);
+				var jobDigest = h.ComputeHash(reportXML.JobCanonicalizationMethodRead,
+					reportXML.JobDigestMethodRead);
+				reportXML.JobDigestValueComputed = jobDigest;
+			} catch (Exception e) {
+				reportXML.JobDigestValueComputed = "";
 			}
 		}
 
+		//	}
+		//}
+
+		//public bool CustomerReportReportValid
+		//{
+		//	get {
+		//		if (_customerReport.Valid == null || !_customerReport.Valid.Value) {
+		//			return false;
+		//		}
+		//		try {
+		//			var h = VectoHash.Load(_jobFile.XMLFile.Document);
+		//			var jobDigest = h.ComputeHash(_customerReport.JobCanonicalizationMethodRead, _customerReport.JobDigestMethodRead);
+		//			_customerReport.JobDigestValueComputed = jobDigest;
+		//			return _customerReport.JobDigestValueRead == jobDigest;
+		//		} catch (Exception e) {
+		//			return false;
+		//		}
+		//	}
+		//}
 	}
 }
diff --git a/HashingTool/Views/VerifyComponentInputData.xaml b/HashingTool/Views/VerifyComponentInputData.xaml
index 642cef1f27..38531641c7 100644
--- a/HashingTool/Views/VerifyComponentInputData.xaml
+++ b/HashingTool/Views/VerifyComponentInputData.xaml
@@ -50,7 +50,7 @@
 
 					<Label Grid.Row="1" Grid.Column="0" Content="Canonicalization methods:" />
 					<TextBox Grid.Row="1" Grid.Column="1"
-							Text="{Binding CanonicalizationMethods ,Mode=OneWay, Converter={StaticResource CollectionConverter}}"
+							Text="{Binding CanonicalizationMethods, Mode=OneWay, Converter={StaticResource CollectionConverter}}"
 							Margin="10,2" IsReadOnly="True" />
 					
 					<Label Grid.Row="2" Grid.Column="0" Content="Digest method:" />
diff --git a/HashingTool/Views/VerifyResults.xaml b/HashingTool/Views/VerifyResults.xaml
index c21c99e5e5..b42b13e957 100644
--- a/HashingTool/Views/VerifyResults.xaml
+++ b/HashingTool/Views/VerifyResults.xaml
@@ -72,16 +72,16 @@
 		</DataTemplate>
 
 		<DataTemplate x:Key="ExpanderContentJobFile" DataType="viewModel:VectoXMLFile">
-			<Grid>
+			<Grid Grid.IsSharedSizeScope="True">
 				<Grid.RowDefinitions>
 					<RowDefinition />
 					<RowDefinition />
 					<RowDefinition />
 					<RowDefinition />
-					<RowDefinition/>
+					<RowDefinition />
 				</Grid.RowDefinitions>
 				<Grid.ColumnDefinitions>
-					<ColumnDefinition Width="Auto" />
+					<ColumnDefinition Width="Auto" SharedSizeGroup="LabelsShareGroup" />
 					<ColumnDefinition Width="*" />
 				</Grid.ColumnDefinitions>
 				<StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2">
@@ -132,20 +132,13 @@
 		</DataTemplate>
 
 		<DataTemplate x:Key="ExpanderContentReport" DataType="viewModel:ReportXMLFile">
-			<Grid>
+			<Grid Grid.IsSharedSizeScope="True">
 				<Grid.RowDefinitions>
 					<RowDefinition />
 					<RowDefinition />
 					<RowDefinition />
-					<RowDefinition />
-					<RowDefinition />
-					<RowDefinition/>
-					<RowDefinition/>
 				</Grid.RowDefinitions>
-				<Grid.ColumnDefinitions>
-					<ColumnDefinition Width="Auto" />
-					<ColumnDefinition Width="*" />
-				</Grid.ColumnDefinitions>
+
 				<StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2">
 					<Label>
 						<Label.Content>
@@ -176,59 +169,164 @@
 					</Button>
 				</StackPanel>
 
-				<Label Grid.Row="1" Grid.Column="0" Content="Job CanonicalizationMethod:" />
-				<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding JobCanonicalizationMethod, Mode=OneWay, Converter={StaticResource CollectionConverter}}"
-						Margin="10,2" IsReadOnly="True" />
+				<GroupBox Grid.Row="1" Header="Report Integrity" Margin="0,0,0,5" Style="{DynamicResource CustomGroupboxStyle}">
+					<Grid>
+						<Grid.ColumnDefinitions>
+							<ColumnDefinition Width="Auto" SharedSizeGroup="LabelsShareGroup" />
+							<ColumnDefinition Width="*" />
+						</Grid.ColumnDefinitions>
+						<Grid.RowDefinitions>
+							<RowDefinition />
+							<RowDefinition />
+							<RowDefinition />
+							<RowDefinition />
+						</Grid.RowDefinitions>
 
-				<Label Grid.Row="2" Grid.Column="0" Content="Job Digest Method:" />
-				<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding JobDigestMethod, Mode=OneWay}"
-						Margin="10,2" IsReadOnly="True" />
-				
-				<Label Grid.Row="3" Grid.Column="0" Content="Job Digest Value:"
-						Style="{StaticResource DigestValueLabelStyle}" />
-				<TextBox Grid.Row="3" Grid.Column="1" Text="{Binding JobDigestValue, Mode=OneWay}"
-						Margin="10,2" IsReadOnly="True" Style="{StaticResource DigestValueTextboxStyle}" />
+						<Label Grid.Row="0" Grid.Column="0" Content="Canonicalization methods:" />
+						<TextBox Grid.Row="0" Grid.Column="1"
+								Text="{Binding CanonicalizationMethods, Mode=OneWay , Converter={StaticResource CollectionConverter}}"
+								Margin="10,2" IsReadOnly="True" />
 
-				<Label Grid.Row="4" Grid.Column="0" Content="Canonicalization methods:" />
-				<TextBox Grid.Row="4" Grid.Column="1"
-						Text="{Binding CanonicalizationMethods, Mode=OneWay , Converter={StaticResource CollectionConverter}}"
-						Margin="10,2" IsReadOnly="True" />
+						<Label Grid.Row="1" Grid.Column="0" Content="Digest method:" />
+						<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding DigestMethod, Mode=OneWay}" Margin="10,2" IsReadOnly="True" />
 
-				<Label Grid.Row="5" Grid.Column="0" Content="Digest Value read:" Style="{StaticResource DigestValueLabelStyle}" />
-				<TextBox Grid.Row="5" Grid.Column="1" Text="{Binding DigestValueRead}" Margin="10,2" IsReadOnly="True">
-					<TextBox.Style>
-						<Style TargetType="TextBox" BasedOn="{StaticResource DigestValueTextboxStyle}">
-							<Style.Triggers>
-								<DataTrigger Binding="{Binding Valid}" Value="True">
-									<Setter Property="Foreground" Value="{StaticResource Color.SuccessGreen}" />
-								</DataTrigger>
-								<DataTrigger Binding="{Binding Valid}" Value="False">
-									<Setter Property="Foreground" Value="{StaticResource Color.ErrorRed}" />
-								</DataTrigger>
-							</Style.Triggers>
-						</Style>
-					</TextBox.Style>
-				</TextBox>
+						<Label Grid.Row="2" Grid.Column="0" Content="Digest Value read:" Style="{StaticResource DigestValueLabelStyle}" />
+						<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding DigestValueRead}" Margin="10,2" IsReadOnly="True">
+							<TextBox.Style>
+								<Style TargetType="TextBox" BasedOn="{StaticResource DigestValueTextboxStyle}">
+									<Style.Triggers>
+										<DataTrigger Binding="{Binding Valid}" Value="True">
+											<Setter Property="Foreground" Value="{StaticResource Color.SuccessGreen}" />
+										</DataTrigger>
+										<DataTrigger Binding="{Binding Valid}" Value="False">
+											<Setter Property="Foreground" Value="{StaticResource Color.ErrorRed}" />
+										</DataTrigger>
+									</Style.Triggers>
+								</Style>
+							</TextBox.Style>
+						</TextBox>
 
-				<Label Grid.Row="6" Grid.Column="0" Content="Digest Value computed:" Style="{StaticResource DigestValueLabelStyle}" />
-				<TextBox Grid.Row="6" Grid.Column="1" Text="{Binding DigestValueComputed}" Margin="10,2" IsReadOnly="True">
-					<TextBox.Style>
-						<Style TargetType="TextBox" BasedOn="{StaticResource DigestValueTextboxStyle}">
-							<Style.Triggers>
-								<DataTrigger Binding="{Binding Valid}" Value="True">
-									<Setter Property="Foreground" Value="{StaticResource Color.SuccessGreen}" />
-								</DataTrigger>
-								<DataTrigger Binding="{Binding Valid}" Value="False">
+						<Label Grid.Row="3" Grid.Column="0" Content="Digest Value computed:"
+								Style="{StaticResource DigestValueLabelStyle}" />
+						<TextBox Grid.Row="3" Grid.Column="1" Text="{Binding DigestValueComputed}" Margin="10,2" IsReadOnly="True">
+							<TextBox.Style>
+								<Style TargetType="TextBox" BasedOn="{StaticResource DigestValueTextboxStyle}">
+									<Style.Triggers>
+										<DataTrigger Binding="{Binding Valid}" Value="True">
+											<Setter Property="Foreground" Value="{StaticResource Color.SuccessGreen}" />
+										</DataTrigger>
+										<DataTrigger Binding="{Binding Valid}" Value="False">
+											<Setter Property="Foreground" Value="{StaticResource Color.ErrorRed}" />
+										</DataTrigger>
+									</Style.Triggers>
+								</Style>
+							</TextBox.Style>
+						</TextBox>
+					</Grid>
+				</GroupBox>
+				<GroupBox Grid.Row="2" Header="Job Integrity" Style="{DynamicResource CustomGroupboxStyle}">
+					<Grid>
+						<Grid.ColumnDefinitions>
+							<ColumnDefinition Width="Auto" SharedSizeGroup="LabelsShareGroup" />
+							<ColumnDefinition Width="*" />
+						</Grid.ColumnDefinitions>
+						<Grid.RowDefinitions>
+							<RowDefinition />
+							<RowDefinition />
+							<RowDefinition />
+							<RowDefinition />
+						</Grid.RowDefinitions>
+						<Label Grid.Row="0" Grid.Column="0" Content="Job CanonicalizationMethod:" />
+						<TextBox Grid.Row="0" Grid.Column="1"
+								Text="{Binding JobCanonicalizationMethodRead, Mode=OneWay, Converter={StaticResource CollectionConverter}}"
+								Margin="10,2" IsReadOnly="True" />
+
+						<Label Grid.Row="1" Grid.Column="0" Content="Job Digest Method:" />
+						<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding JobDigestMethodRead, Mode=OneWay}"
+								Margin="10,2" IsReadOnly="True" />
+
+						<Label Grid.Row="2" Grid.Column="0" Content="Job Digest Value Read:"
+								Style="{StaticResource DigestValueLabelStyle}" />
+						<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding JobDigestValueRead, Mode=OneWay}"
+								Margin="10,2" IsReadOnly="True">
+							<TextBox.Style>
+								<Style TargetType="TextBox" BasedOn="{StaticResource DigestValueTextboxStyle}">
 									<Setter Property="Foreground" Value="{StaticResource Color.ErrorRed}" />
-								</DataTrigger>
-							</Style.Triggers>
-						</Style>
-					</TextBox.Style>
-				</TextBox>
+									<Style.Triggers>
+										<DataTrigger Binding="{Binding JobDigestValid}" Value="True">
+											<Setter Property="Foreground" Value="{StaticResource Color.SuccessGreen}" />
+										</DataTrigger>
+									</Style.Triggers>
+								</Style>
+							</TextBox.Style>
+						</TextBox>
 
+						<Label Grid.Row="3" Grid.Column="0" Content="Job Digest Value Computed:"
+								Style="{StaticResource DigestValueLabelStyle}" />
+						<TextBox Grid.Row="3" Grid.Column="1" Text="{Binding JobDigestValueComputed, Mode=OneWay}"
+								Margin="10,2" IsReadOnly="True">
+							<TextBox.Style>
+								<Style TargetType="TextBox" BasedOn="{StaticResource DigestValueTextboxStyle}">
+									<Setter Property="Foreground" Value="{StaticResource Color.ErrorRed}" />
+									<Style.Triggers>
+										<DataTrigger Binding="{Binding JobDigestValid}" Value="True">
+											<Setter Property="Foreground" Value="{StaticResource Color.SuccessGreen}" />
+										</DataTrigger>
+									</Style.Triggers>
+								</Style>
+							</TextBox.Style>
+						</TextBox>
+					</Grid>
+				</GroupBox>
 			</Grid>
 		</DataTemplate>
 
+		<BorderGapMaskConverter x:Key="BorderGapMaskConverter" />
+
+		<Style x:Key="CustomGroupboxStyle" TargetType="{x:Type GroupBox}">
+			<Setter Property="BorderBrush" Value="#D5DFE5" />
+			<Setter Property="BorderThickness" Value="1" />
+			<Setter Property="Template">
+				<Setter.Value>
+					<ControlTemplate TargetType="{x:Type GroupBox}">
+						<Grid SnapsToDevicePixels="true">
+							<Grid.ColumnDefinitions>
+								<ColumnDefinition Width="6" />
+								<ColumnDefinition Width="Auto" />
+								<ColumnDefinition Width="*" />
+								<ColumnDefinition Width="6" />
+							</Grid.ColumnDefinitions>
+							<Grid.RowDefinitions>
+								<RowDefinition Height="Auto" />
+								<RowDefinition Height="Auto" />
+								<RowDefinition Height="*" />
+								<RowDefinition Height="6" />
+							</Grid.RowDefinitions>
+							<Border BorderBrush="Transparent" BorderThickness="{TemplateBinding BorderThickness}"
+									Background="{TemplateBinding Background}" Grid.ColumnSpan="4" Grid.Column="0" CornerRadius="4" Grid.Row="1"
+									Grid.RowSpan="3" />
+							<Border BorderBrush="White" BorderThickness="{TemplateBinding BorderThickness}" Grid.Column="0"
+									Grid.ColumnSpan="4" CornerRadius="2" Grid.Row="1" Grid.RowSpan="3">
+								<Border.OpacityMask>
+									<MultiBinding ConverterParameter="7" Converter="{StaticResource BorderGapMaskConverter}">
+										<Binding ElementName="Header" Path="ActualWidth" />
+										<Binding Path="ActualWidth" RelativeSource="{RelativeSource Self}" />
+										<Binding Path="ActualHeight" RelativeSource="{RelativeSource Self}" />
+									</MultiBinding>
+								</Border.OpacityMask>
+							</Border>
+							<Border x:Name="Header" Grid.Column="1" Padding="3,1,3,0" Grid.Row="0" Grid.RowSpan="2">
+								<ContentPresenter ContentSource="Header" RecognizesAccessKey="True"
+												SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
+							</Border>
+							<ContentPresenter Grid.ColumnSpan="2" Grid.Column="1" Margin="{TemplateBinding Padding}" Grid.Row="2"
+											SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
+						</Grid>
+					</ControlTemplate>
+				</Setter.Value>
+			</Setter>
+		</Style>
+
 	</UserControl.Resources>
 
 	<DockPanel>
@@ -246,7 +344,7 @@
 			</Grid.RowDefinitions>
 
 			<ScrollViewer Grid.Row="0" VerticalScrollBarVisibility="Auto" HorizontalAlignment="Stretch"
-						Margin="10,0,10,10" Background="{x:Static SystemColors.ControlLightBrush}">
+						Margin="10,0,10,10" Background="{x:Static SystemColors.ControlLightBrush}" Grid.IsSharedSizeScope="True">
 
 				<ItemsControl ItemsSource="{Binding Files}" Name="lstInput" Margin="3">
 					<ItemsControl.ItemContainerStyle>
@@ -328,7 +426,7 @@
 						<Style TargetType="ContentControl">
 							<Setter Property="ContentTemplate" Value="{StaticResource Icon_NOK}" />
 							<Style.Triggers>
-								<DataTrigger Binding="{Binding ManufacturerReportValid}" Value="True">
+								<DataTrigger Binding="{Binding ManufacturerReport.JobDigestValid}" Value="True">
 									<Setter Property="ContentTemplate" Value="{StaticResource Icon_OK}" />
 								</DataTrigger>
 							</Style.Triggers>
@@ -349,7 +447,7 @@
 						<Style TargetType="ContentControl">
 							<Setter Property="ContentTemplate" Value="{StaticResource Icon_NOK}" />
 							<Style.Triggers>
-								<DataTrigger Binding="{Binding CustomerReportReportValid}" Value="True">
+								<DataTrigger Binding="{Binding CustomerReport.JobDigestValid}" Value="True">
 									<Setter Property="ContentTemplate" Value="{StaticResource Icon_OK}" />
 								</DataTrigger>
 							</Style.Triggers>
-- 
GitLab