KeyValidator类提供一个基于对称密钥的验证器,该章节将介绍KeyValidator设计的以下几个方面:
问题描述
设计目标、权衡和问题
解决方案描述
具体实现
问题描述
一个通常使用的验证方法是使用对称密钥进行签名和验证数据。为了支持这项技术,必须实现一个基于对称密钥的验证器。
设计目标、权衡和问题
1. KeyValidator应该支持由.net的KeyedHashAlgorithm类支持的对称密钥。
2. 开发人员应该能够在应用程序升级器的配置文件中指定密钥,该密钥应该用base64字符串存储。如果没有密钥被指定,KeyValidator会抛出一个异常。
解决方案描述
KeyValidator类派生自IValidator接口,它使用.net的KeyedHashAlgorithm类基于一个对称密钥生成和验证签名。
具体实现
KeyValidator类由
Microsoft.ApplicationBlocks.ApplicationUpdater.Validators命名空间实现。
实现KeyValidator需要考虑四个方面:
1. 密钥初始化
2. 签名
3. 验证
4. KeyValidator配置
密钥初始化
1. Init方法用于从应用程序升级器配置文件传递<validator>元素给KeyValidator类。该元素应该包含<key>子元素,该元素中以base64字符串存储密钥。<key>元素用于初始化验证密钥,该初始化过程代码在下面的代码片断中。
[VB.NET]
Sub Init()
Sub Init (ByVal config As XmlNode) Implements IValidator.Init
Dim keyNode As XmlNode = config.SelectSingleNode( "key" )
_key = ExtractKeyFromNode (keyNode)
If _key Is Nothing Then
'Throw a cryptographic exception
End If
End Sub
[C#]
void
IValidator.Init( XmlNode config )

{
XmlNode keyNode = config.SelectSingleNode( "key" );
_key = ExtractKeyFromNode( keyNode );
if ( null == _key )

{
// Throw a cryptographic exception
}
}
2. Init方法使用一个ExtractKeyFromNode私有函数解析位于配置文件中的base64加密的字符串,并且返回一个byte数组。下面的代码展示了ExtractKeyFromNode函数。
[VB.NET]
Private
Function ExtractKeyFromNode()
Function ExtractKeyFromNode(ByVal keyNode As XmlNode) As Byte()
Dim key As Byte() = Nothing
If keyNode Is Nothing Then
Return Nothing
End If
Try
key = Convert.FromBase64String(keyNode.InnerText)
Catch e As Exception
'exception handling code
End Try
Return key
End Function
[C#]
private
byte
[] ExtractKeyFromNode( XmlNode keyNode )

{
byte[] key = null;
if ( null == keyNode )

{
return null;
}
try

{
key = Convert.FromBase64String( keyNode.InnerText );
}
catch( Exception e )

{
// exception handling code
}
return key;
}
签名
重载的Sign方法使用KeyedHashAlgorithm类生成hashed签名,下面的代码片断展示了这一过程:
[VB.NET]
Overloads
Function Sign()
Function Sign(ByVal filePath As String, ByVal key As String) As String _
Implements IValidator.Sign
Dim outSignature As Byte() = Nothing
Dim fs As FileStream = Nothing
Try
fs = New FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)
Dim kha As KeyedHashAlgorithm = KeyedHashAlgorithm.Create()
kha.Key = Convert.FromBase64String(key)
outSignature = kha.ComputeHash(fs)
Catch e As Exception
' exception handling code
Finally
If Not (fs Is Nothing) Then
fs.Close()
End If
End Try
Return Convert.ToBase64String(outSignature)
End Function

Overloads
Function Sign()
Function Sign(ByVal xml As XmlNode, ByVal key As String) As String _
Implements IValidator.Sign
Dim outSignature As Byte() = Nothing
Dim xmlNodeByte As Byte() = Nothing
xmlNodeByte = Encoding.Unicode.GetBytes(Xml.InnerXml)
Try
Dim kha As KeyedHashAlgorithm = KeyedHashAlgorithm.Create()
kha.Key = Convert.FromBase64String(key)
outSignature = kha.ComputeHash(xmlNodeByte)
Catch e As Exception
'exception handling code
End Try
Return Convert.ToBase64String(outSignature)
End Function
[C#]
string
IValidator.Sign(
string
filePath,
string
key )

{
byte[] outSignature = null;
FileStream fs = null;
try

{
fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
KeyedHashAlgorithm kha = KeyedHashAlgorithm.Create();
kha.Key = Convert.FromBase64String( key );
outSignature = kha.ComputeHash( fs );
}
catch( Exception e )

{
// exception handling code
}
finally
if ( null != fs )

{
fs.Close();
}
}
return
Convert.ToBase64String( outSignature );
}
string
IValidator.Sign( XmlNode xml,
string
key )

{
byte[] outSignature = null;
byte[] xmlNodeByte = null;
xmlNodeByte = Encoding.Unicode.GetBytes( xml.InnerXml );
try

{
KeyedHashAlgorithm kha = KeyedHashAlgorithm.Create();
kha.Key = Convert.FromBase64String( key );
outSignature = kha.ComputeHash( xmlNodeByte );
}
catch( Exception e )

{
// exception handling code
}
return Convert.ToBase64String( outSignature );
}
验证
Validate方法使用相同的KeyedHashAlgorithm验证签名和密钥,该密钥用于生成签名。Validate方法在下面的代码片断中实现:
[VB.NET]
Overloads
Function Validate()
Function Validate(ByVal filePath As String, ByVal signature As String) _
As Boolean Implements IValidator.Validate
Dim inSignature As Byte() = Nothing
Dim outSignature As Byte() = Nothing
inSignature = Convert.FromBase64String(signature)
Dim fs As New FileStream(filePath, FileMode.Open)
Try
Dim kha As KeyedHashAlgorithm = KeyedHashAlgorithm.Create()
kha.Key = _key
outSignature = kha.ComputeHash(fs)
Finally
fs.Close()
End Try
Return compareKeys(outSignature, inSignature)
End Function

Overloads
Function Validate()
Function Validate(ByVal xml As XmlNode, ByVal signature As String) _
As Boolean Implements IValidator.Validate
Dim inSignature As Byte() = Nothing
Dim outSignature As Byte() = Nothing
Dim xmlNodeByte As Byte() = Nothing
xmlNodeByte = Encoding.Unicode.GetBytes(Xml.InnerXml)
inSignature = Convert.FromBase64String(signature)
Dim kha As KeyedHashAlgorithm = KeyedHashAlgorithm.Create()
kha.Key = _key
outSignature = kha.ComputeHash(xmlNodeByte)
Return compareKeys(outSignature, inSignature)
End Function
[C#]
bool
IValidator.Validate(
string
filePath,
string
signature )

{
byte[] inSignature = null;
byte[] outSignature = null;
inSignature = Convert.FromBase64String( signature );
using ( FileStream fs = new FileStream( filePath, FileMode.Open ) )

{
KeyedHashAlgorithm kha = KeyedHashAlgorithm.Create();
kha.Key = _key;
outSignature = kha.ComputeHash( fs );
}
return compareKeys( outSignature, inSignature );
}
bool
IValidator.Validate( XmlNode xml,
string
signature )

{
byte[] inSignature = null;
byte[] outSignature = null;
byte[] xmlNodeByte = null;
xmlNodeByte = Encoding.Unicode.GetBytes( xml.InnerXml );
inSignature = Convert.FromBase64String( signature );
KeyedHashAlgorithm kha = KeyedHashAlgorithm.Create();
kha.Key = _key;
outSignature = kha.ComputeHash( xmlNodeByte );
return compareKeys( outSignature, inSignature );
}
这两个Validate的重载方法使用一个私有的compareKeys来确认签名匹配。compareKeys函数在下面的代码中实现:
[VB.NET]
Private
Function compareKeys()
Function compareKeys(ByVal firstKey() As Byte, ByVal secondKey() As Byte) _
As Boolean
If firstKey.Length <> secondKey.Length Then
Return False
End If
Dim i As Integer
For i = 0 To firstKey.Length - 1
If firstKey(i) <> secondKey(i) Then
Return False
End If
Next i
Return True
End Function
[C#]
private
bool
compareKeys(
byte
[] firstKey,
byte
[] secondKey )

{
if( firstKey.Length != secondKey.Length ) return false;
for( int i = 0 ; i < firstKey.Length; i++ )

{
if( firstKey[ i ] != secondKey[ i ] ) return false;
}
return true;
}
KeyValidator配置
为了使用KeyValidator,你必须在应用程序升级器配置文件中包含一个<validator>元素,指定KeyValidator集合和类型的全名,以及你要使用的base64加密密钥。一个<validator>配置元素的例子如下所示:
<
validator
type
="Microsoft.ApplicationBlocks.ApplicationUpdater.Validators.KeyValidator"
assembly
="Microsoft.ApplicationBlocks.ApplicationUpdater,Version=1.0.0.0, Culture=neutral,PublicKeyToken=null"
>
<
key
>
ACQAAASAAACUAAAABgIAAAAkAABS[etc.]
</
key
>
</
validator
>