Ostatnio w wolnych chwilach pracuje nad protokołem OAuth dla Pocket Blip-a wraz z Filipem Tepperem z Blip.pl, który był tak miły i udostępnił mi jedno konto testowe. Problemy pojawiły się już na początku bo w bibliotekach Compact Framework brakuje implementacji HMAC-SHA1. Chciałem sprawę rozwiązać przez użycie OPENNETCF, które mają ten algorytm zaimplementowany, ale niestety pojawiały się błędy których nijak nie mogłem rozwiązać, bo sypały je biblioteki CF-a.
Dlatego jak w poprzednim artykule o PointF rozwiązałem problem używając Reflector-a i dzięki drobnym poprawkom klasa działa lepiej i się nie sypie jak wersja z OPENNETCF:
namespace System.Security.Cryptography
{
public abstract class KeyedHashAlgorithm : HashAlgorithm
{
// Fields
protected byte[] KeyValue;
// Methods
protected KeyedHashAlgorithm()
{
}
public static KeyedHashAlgorithm Create()
{
return Create("System.Security.Cryptography.KeyedHashAlgorithm");
}
public static KeyedHashAlgorithm Create(string algName)
{
return (KeyedHashAlgorithm)CryptoConfig.CreateFromName(algName);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (this.KeyValue != null)
{
Array.Clear(this.KeyValue, 0, this.KeyValue.Length);
}
this.KeyValue = null;
}
base.Dispose(disposing);
}
// Properties
public virtual byte[] Key
{
get
{
return (byte[])this.KeyValue.Clone();
}
set
{
if (base.State != 0)
{
throw new CryptographicException("Cryptography_HashKeySet");
}
this.KeyValue = (byte[])value.Clone();
}
}
}
public abstract class HMAC : KeyedHashAlgorithm
{
// Fields
private int blockSizeValue = 0x40;
internal HashAlgorithm m_hash1;
internal HashAlgorithm m_hash2;
private bool m_hashing;
internal string m_hashName;
private byte[] m_inner;
private byte[] m_outer;
// Methods
protected HMAC()
{
}
public static HMAC Create()
{
return Create("System.Security.Cryptography.HMAC");
}
public static HMAC Create(string algorithmName)
{
return (HMAC)CryptoConfig.CreateFromName(algorithmName);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (this.m_hash1 != null)
{
this.m_hash1.Clear();
}
if (this.m_hash2 != null)
{
this.m_hash2.Clear();
}
if (this.m_inner != null)
{
Array.Clear(this.m_inner, 0, this.m_inner.Length);
}
if (this.m_outer != null)
{
Array.Clear(this.m_outer, 0, this.m_outer.Length);
}
}
base.Dispose(disposing);
}
protected override void HashCore(byte[] rgb, int ib, int cb)
{
if (!this.m_hashing)
{
this.m_hash1.TransformBlock(this.m_inner, 0, this.m_inner.Length, this.m_inner, 0);
this.m_hashing = true;
}
this.m_hash1.TransformBlock(rgb, ib, cb, rgb, ib);
}
protected override byte[] HashFinal()
{
if (!this.m_hashing)
{
this.m_hash1.TransformBlock(this.m_inner, 0, this.m_inner.Length, this.m_inner, 0);
this.m_hashing = true;
}
this.m_hash1.TransformFinalBlock(new byte[0], 0, 0);
byte[] hashValue = this.m_hash1.Hash;
this.m_hash2.TransformBlock(this.m_outer, 0, this.m_outer.Length, this.m_outer, 0);
this.m_hash2.TransformBlock(hashValue, 0, hashValue.Length, hashValue, 0);
this.m_hashing = false;
this.m_hash2.TransformFinalBlock(new byte[0], 0, 0);
return this.m_hash2.Hash;
}
public override void Initialize()
{
this.m_hash1.Initialize();
this.m_hash2.Initialize();
this.m_hashing = false;
}
internal void InitializeKey(byte[] key)
{
this.m_inner = null;
this.m_outer = null;
if (key.Length > this.BlockSizeValue)
{
base.KeyValue = this.m_hash1.ComputeHash(key);
}
else
{
base.KeyValue = (byte[])key.Clone();
}
this.UpdateIOPadBuffers();
}
private void UpdateIOPadBuffers()
{
int num;
if (this.m_inner == null)
{
this.m_inner = new byte[this.BlockSizeValue];
}
if (this.m_outer == null)
{
this.m_outer = new byte[this.BlockSizeValue];
}
for (num = 0; num < this.BlockSizeValue; num++)
{
this.m_inner[num] = 0x36;
this.m_outer[num] = 0x5c;
}
for (num = 0; num < base.KeyValue.Length; num++)
{
this.m_inner[num] = (byte)(this.m_inner[num] ^ base.KeyValue[num]);
this.m_outer[num] = (byte)(this.m_outer[num] ^ base.KeyValue[num]);
}
}
// Properties
protected int BlockSizeValue
{
get
{
return this.blockSizeValue;
}
set
{
this.blockSizeValue = value;
}
}
public string HashName
{
get
{
return this.m_hashName;
}
set
{
if (this.m_hashing)
{
throw new CryptographicException("Cryptography_HashNameSet");
}
this.m_hashName = value;
this.m_hash1 = HashAlgorithm.Create(this.m_hashName);
this.m_hash2 = HashAlgorithm.Create(this.m_hashName);
}
}
public override byte[] Key
{
get
{
return (byte[])base.KeyValue.Clone();
}
set
{
if (this.m_hashing)
{
throw new CryptographicException("Cryptography_HashKeySet");
}
this.InitializeKey(value);
}
}
}
public class HMACSHA1 : HMAC
{
public HMACSHA1(byte[] key)
: this(key, false)
{
}
public HMACSHA1(byte[] key, bool useManagedSha1)
{
base.m_hashName = "SHA1";
if (useManagedSha1)
{
base.m_hash1 = new SHA1Managed();
base.m_hash2 = new SHA1Managed();
}
else
{
base.m_hash1 = new SHA1CryptoServiceProvider();
base.m_hash2 = new SHA1CryptoServiceProvider();
}
base.HashSizeValue = 160;
base.InitializeKey(key);
}
}
}
Dla zainteresowanych klasę zmieniłem z miejscach gdzie pobierana jest wartość HashAlgorithm-u (this.m_hash1.Hash) oraz wszędzie tam gdzie znajdują się opisy błedów (za leniwy jestem aby je wyciągać z Resources
.



Ian
/ 2010-03-29Thank you very much – this was really helpful