Microsoft Updater Application Block 1.4.3 KeyValidator类设计 [翻译]

Microsoft Updater Application Block KeyValidator类设计

译者: Tony Qu

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 (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(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(ByVal filePath As StringByVal key As StringAs 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 NothingThen
      fs.Close()
     
End If
   
End Try
   
Return Convert.ToBase64String(outSignature)
End Function

 
Overloads   Function Sign(ByVal xml As XmlNode, ByVal key As StringAs 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(ByVal filePath As StringByVal 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(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(ByVal firstKey() As ByteByVal 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;
  
forint 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 >

你可能感兴趣的:(application)