diff options
author | Sebastien Pouliot <sebastien@ximian.com> | 2002-10-13 22:38:54 +0400 |
---|---|---|
committer | Sebastien Pouliot <sebastien@ximian.com> | 2002-10-13 22:38:54 +0400 |
commit | 053b98da026216f1e62e177e019bfbb45b169fc6 (patch) | |
tree | b2088d1d4952059862f3fe11853c41e5f2912cbc /mcs | |
parent | 9220e111890479cad968c1b3aa68b134c88fc286 (diff) |
2002-10-13 Sebastien Pouliot <spouliot@videotron.ca>
* HashAlgorithm.cs: Added Dispose() to HashAlgorithm because it
inherits ICryptoTransform
* KeyedHashAlgorithm.cs: New implementation
* HMACSHA1.cs: New (include a generic HMACAlgorithm as internal class)
* MACTripleDES.cs: New (missing core implementation on generic MACAlgorithm)
* CryptoStream.cs: Added limited functionalities to support HMACSHA1
svn path=/trunk/mcs/; revision=8221
Diffstat (limited to 'mcs')
5 files changed, 606 insertions, 120 deletions
diff --git a/mcs/class/corlib/System.Security.Cryptography/ChangeLog b/mcs/class/corlib/System.Security.Cryptography/ChangeLog index faaabd8238e..fffa2f30ba2 100644 --- a/mcs/class/corlib/System.Security.Cryptography/ChangeLog +++ b/mcs/class/corlib/System.Security.Cryptography/ChangeLog @@ -1,3 +1,18 @@ +2002-10-13 Sebastien Pouliot <spouliot@videotron.ca> + + * HashAlgorithm.cs: Added Dispose() to HashAlgorithm because it + inherits ICryptoTransform + * KeyedHashAlgorithm.cs: New implementation + * HMACSHA1.cs: New (include a generic HMACAlgorithm as internal class) + * MACTripleDES.cs: New (missing core implementation on generic MACAlgorithm) + * CryptoStream.cs: Added limited functionalities to support HMACSHA1 + +2002-10-12 Sebastien Pouliot <spouliot@videotron.ca> + + * DSA.cs: changed constructor to public from internal (like MS) + * HashAlgorithm.cs: Completed ComputeHash methods + * SHA1.cs: Added HashSizeValue = 160 + 2002-10-12 Sebastien Pouliot <spouliot@videotron.ca> * ICryptoTransform.cs: Now inherits from IDisposable diff --git a/mcs/class/corlib/System.Security.Cryptography/CryptoStream.cs b/mcs/class/corlib/System.Security.Cryptography/CryptoStream.cs index 6dad1ca628d..0f4df3c6cf3 100755 --- a/mcs/class/corlib/System.Security.Cryptography/CryptoStream.cs +++ b/mcs/class/corlib/System.Security.Cryptography/CryptoStream.cs @@ -1,120 +1,137 @@ -//
-// System.Security.Cryptography CryptoStream.cs
-//
-// Author:
-// Thomas Neidhart (tome@sbox.tugraz.at)
-//
-
-using System;
-using System.IO;
-
-namespace System.Security.Cryptography
-{
-
- public class CryptoStream : Stream
- {
- private CryptoStreamMode _mode;
-
- public CryptoStream(Stream stream, ICryptoTransform transform, CryptoStreamMode mode)
- {
- _mode = mode;
- }
-
- public override bool CanRead
- {
- get {
- switch (_mode) {
- case CryptoStreamMode.Read:
- return true;
-
- case CryptoStreamMode.Write:
- return false;
-
- default:
- return false;
- }
- }
- }
-
- public override bool CanSeek
- {
- get {
- return false;
- }
- }
-
- public override bool CanWrite
- {
- get {
- switch (_mode) {
- case CryptoStreamMode.Read:
- return false;
-
- case CryptoStreamMode.Write:
- return true;
-
- default:
- return false;
- }
- }
- }
-
- public override long Length
- {
- get {
- throw new NotSupportedException("Length property not supported by CryptoStream");
- }
- }
-
- public override long Position
- {
- get {
- throw new NotSupportedException("Position property not supported by CryptoStream");
- }
- set {
- throw new NotSupportedException("Position property not supported by CryptoStream");
- }
- }
-
- [MonoTODO]
- public override int Read(byte[] buffer, int offset, int count)
- {
- // TODO: implement
- return 0;
- }
-
- [MonoTODO]
- public override void Write(byte[] buffer, int offset, int count)
- {
- // TODO: implement
- }
-
- [MonoTODO]
- public override void Flush()
- {
- // TODO: implement
- }
-
- [MonoTODO]
- public void FlushFinalBlock()
- {
- if (_mode != CryptoStreamMode.Write)
- throw new NotSupportedException("cannot flush a non-writeable CryptoStream");
-
- // TODO: implement
- }
-
- public override long Seek(long offset, SeekOrigin origin)
- {
- throw new NotSupportedException("cannot seek a CryptoStream");
- }
-
- public override void SetLength(long value)
- {
- // LAMESPEC: should throw NotSupportedException like Seek??
- return;
- }
-
- } // CryptoStream
-
-} // System.Security.Cryptography
+// +// System.Security.Cryptography CryptoStream.cs +// +// Author: +// Thomas Neidhart (tome@sbox.tugraz.at) +// Sebastien Pouliot (spouliot@motus.com) +// +// Portions (C) 2002 Motus Technologies Inc. (http://www.motus.com) +// + +using System; +using System.IO; + +namespace System.Security.Cryptography { + +public class CryptoStream : Stream { + private Stream _stream; + private ICryptoTransform _transform; + private CryptoStreamMode _mode; + + public CryptoStream(Stream stream, ICryptoTransform transform, CryptoStreamMode mode) + { + _stream = stream; + _transform = transform; + _mode = mode; + } + + ~CryptoStream () + { + Dispose (false); + } + + public override bool CanRead { + get { return (_mode == CryptoStreamMode.Read); } + } + + public override bool CanSeek { + get { return false; } + } + + public override bool CanWrite { + get { return (_mode == CryptoStreamMode.Write); } + } + + public override long Length { + get { + throw new NotSupportedException("Length property not supported by CryptoStream"); + } + } + + public override long Position { + get { + throw new NotSupportedException("Position property not supported by CryptoStream"); + } + set { + throw new NotSupportedException("Position property not supported by CryptoStream"); + } + } + + public void Clear () + { + Dispose (true); + } + + [MonoTODO("Limited support for HMACSHA1")] + public override void Close () + { + if (_mode != CryptoStreamMode.Write) + throw new NotSupportedException (); + // TODO: limited implemention for HMACSHA1 + byte[] buffer = new byte [0]; + _transform.TransformFinalBlock (buffer, 0, 0); + if (_stream != null) + _stream.Close(); + } + + [MonoTODO] + public override int Read (byte[] buffer, int offset, int count) + { + if (_mode != CryptoStreamMode.Read) + throw new NotSupportedException (); + if ((offset < 0) || (count < 0)) + throw new ArgumentOutOfRangeException (); + if (offset + count > buffer.Length) + throw new ArgumentException (); + // TODO: implement + return 0; + } + + [MonoTODO("Limited support for HMACSHA1")] + public override void Write (byte[] buffer, int offset, int count) + { + if (_mode != CryptoStreamMode.Write) + throw new NotSupportedException (); + if ((offset < 0) || (count < 0)) + throw new ArgumentOutOfRangeException (); + if (offset + count > buffer.Length) + throw new ArgumentException (); + // TODO: limited implemention for HMACSHA1 + byte[] output = new byte [count]; + _transform.TransformBlock (buffer, offset, count, output, 0); + } + + [MonoTODO] + public override void Flush () + { + if (_mode != CryptoStreamMode.Write) + throw new NotSupportedException ("cannot flush a non-writeable CryptoStream"); + // TODO: implement + } + + [MonoTODO] + public void FlushFinalBlock () + { + if (_mode != CryptoStreamMode.Write) + throw new NotSupportedException ("cannot flush a non-writeable CryptoStream"); + // TODO: implement + } + + public override long Seek (long offset, SeekOrigin origin) + { + throw new NotSupportedException ("cannot Seek a CryptoStream"); + } + + // LAMESPEC: Exception NotSupportedException not documented + public override void SetLength (long value) + { + throw new NotSupportedException ("cannot SetLength a CryptoStream"); + } + + protected virtual void Dispose (bool disposing) + { + } + +} // CryptoStream + +} // System.Security.Cryptography diff --git a/mcs/class/corlib/System.Security.Cryptography/HMACSHA1.cs b/mcs/class/corlib/System.Security.Cryptography/HMACSHA1.cs new file mode 100644 index 00000000000..71b12fd2c97 --- /dev/null +++ b/mcs/class/corlib/System.Security.Cryptography/HMACSHA1.cs @@ -0,0 +1,221 @@ +// +// HMACSHA1.cs: Handles HMAC with SHA-1 +// +// Author: +// Sebastien Pouliot (spouliot@motus.com) +// +// (C) 2002 Motus Technologies Inc. (http://www.motus.com) +// + +using System; +using System.IO; +using System.Security.Cryptography; + +namespace System.Security.Cryptography { + +// References: +// a. FIPS PUB 198: The Keyed-Hash Message Authentication Code (HMAC), 2002 March. +// http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf +// b. Internet RFC 2104, HMAC, Keyed-Hashing for Message Authentication +// (include C source for HMAC-MD5) +// http://www.ietf.org/rfc/rfc2104.txt +// c. IETF RFC2202: Test Cases for HMAC-MD5 and HMAC-SHA-1 +// (include C source for HMAC-MD5 and HAMAC-SHA1) +// http://www.ietf.org/rfc/rfc2202.txt +// d. ANSI X9.71, Keyed Hash Message Authentication Code. +// not free :-( +// http://webstore.ansi.org/ansidocstore/product.asp?sku=ANSI+X9%2E71%2D2000 + +// Generic HMAC mechanisms - most of HMAC work is done in here. +// It should work with any hash function e.g. MD5 for HMACMD5 (RFC2104) +internal class HMACAlgorithm { + private byte[] key; + private byte[] hash; + private HashAlgorithm algo; + private string hashName; + private CryptoStream stream; + + public HMACAlgorithm (string algoName) + { + CreateHash (algoName); + } + + ~HMACAlgorithm () + { + Dispose (); + } + + private void CreateHash (string algoName) + { + algo = (HashAlgorithm) CryptoConfig.CreateFromName (algoName); + hashName = algoName; + } + + public void Dispose () + { + ZeroizeKey (); + } + + public HashAlgorithm Algo { + get { return algo; } + } + + public string HashName { + get { return hashName; } + set { + // only if its not too late for a change + if (stream == null) + CreateHash (value); + } + } + + public byte[] HashValue { + get { return hash; } + } + + public byte[] Key { + get { return key; } + set { + if ((value != null) && (value.Length > 64)) + key = algo.ComputeHash (value); + else + key = (byte[]) value.Clone(); + } + } + + public void Initialize () + { + hash = null; + } + + private byte[] KeySetup (byte[] key, byte padding) + { + byte[] buf = new byte [64]; + + for (int i = 0; i < key.Length; ++i) + buf [i] = (byte) ((byte) key [i] ^ padding); + + for (int i = key.Length; i < 64; ++i) + buf [i] = padding; + + return buf; + } + + public void Core (byte[] rgb, int ib, int cb) + { + if (stream == null) { + byte[] buf = KeySetup (key, 0x36); + algo.Initialize (); + stream = new CryptoStream (Stream.Null, algo, CryptoStreamMode.Write); + stream.Write (buf, 0, buf.Length); + } + stream.Write (rgb, ib, cb); + } + + public byte[] Final () + { + stream.Close (); + stream = null; + byte[] intermediate = algo.Hash; + byte[] buf = KeySetup (key, 0x5C); + + algo.Initialize (); + stream = new CryptoStream (Stream.Null, algo, CryptoStreamMode.Write); + stream.Write (buf, 0, buf.Length); + stream.Write (intermediate, 0, intermediate.Length); + stream.Close (); + stream = null; + + hash = algo.Hash; + algo.Clear (); + return hash; + } + + // Note: this key is different (well most of the time) from the key + // used in KeyHashAlgorithm (this one may be padded or hashed). So + // it need to be zeroized independently. + public void ZeroizeKey () + { + if (key != null) + Array.Clear (key, 0, key.Length); + } +} + +public class HMACSHA1: KeyedHashAlgorithm { + private HMACAlgorithm hmac; + + public HMACSHA1 () : base () + { + hmac = new HMACAlgorithm ("SHA1"); + HashSizeValue = 160; + GenerateKey(); + } + + public HMACSHA1 (byte[] rgbKey) + { + hmac = new HMACAlgorithm ("SHA1"); + HashSizeValue = 160; + hmac.Key = rgbKey; + } + + ~HMACSHA1 () + { + Dispose (false); + } + + public override byte[] Key { + get { return base.Key; } + set { + hmac.Key = value; + base.Key = value; + } + } + + public string HashName { + get { return hmac.HashName; } + set { hmac.HashName = value; } + } + + protected override void Dispose (bool disposing) + { + if (hmac != null) + hmac.Dispose(); + base.Dispose (disposing); + } + + // generate a random 64 bits key + private void GenerateKey () + { + KeyValue = new byte[8]; + RandomNumberGenerator rng = RandomNumberGenerator.Create(); + rng.GetBytes (KeyValue); + hmac.Key = KeyValue; + } + + public override void Initialize () + { + State = 0; + hmac.Initialize (); + } + + protected override void HashCore (byte[] rgb, int ib, int cb) + { + if (State == 0) { + // let us throw an exception if hash name is invalid + // for HMACSHA1 (obviously this can't be done by the + // generic HMAC class) + if (! (hmac.Algo is SHA1)) + throw new InvalidCastException (); + } + State = 1; + hmac.Core (rgb, ib, cb); + } + + protected override byte[] HashFinal () + { + State = 0; + return hmac.Final (); + } +} + +}
\ No newline at end of file diff --git a/mcs/class/corlib/System.Security.Cryptography/KeyedHashAlgorithm.cs b/mcs/class/corlib/System.Security.Cryptography/KeyedHashAlgorithm.cs new file mode 100644 index 00000000000..682dcb3d49d --- /dev/null +++ b/mcs/class/corlib/System.Security.Cryptography/KeyedHashAlgorithm.cs @@ -0,0 +1,73 @@ +// +// KeyedHashAlgorithm.cs: Handles keyed hash and MAC classes. +// +// Author: +// Sebastien Pouliot (spouliot@motus.com) +// +// (C) 2002 Motus Technologies Inc. (http://www.motus.com) +// + +using System; +using System.Security.Cryptography; + +namespace System.Security.Cryptography { + +public abstract class KeyedHashAlgorithm : HashAlgorithm { + + protected byte[] KeyValue; + + protected KeyedHashAlgorithm () : base () + { + // create a random 64 bits key + } + + ~KeyedHashAlgorithm () + { + Dispose (false); + } + + public virtual byte[] Key { + get { + return (byte[]) KeyValue.Clone (); + } + set { + // can't change the key during a hashing ops + if (State != 0) + throw new CryptographicException (); + // zeroize current key material for security + ZeroizeKey (); + // copy new key + KeyValue = (byte[]) value.Clone (); + } + } + + protected override void Dispose (bool disposing) + { + // zeroize key material for security + ZeroizeKey(); + // dispose managed resources + // none so far + // dispose unmanaged resources + // none so far + // calling base class HashAlgorithm + base.Dispose (disposing); + } + + private void ZeroizeKey() + { + if (KeyValue != null) + Array.Clear (KeyValue, 0, KeyValue.Length); + } + + public static new KeyedHashAlgorithm Create () + { + return Create ("System.Security.Cryptography.KeyedHashAlgorithm"); + } + + public static new KeyedHashAlgorithm Create (string algName) + { + return (KeyedHashAlgorithm) CryptoConfig.CreateFromName (algName); + } +} + +}
\ No newline at end of file diff --git a/mcs/class/corlib/System.Security.Cryptography/MACTripleDES.cs b/mcs/class/corlib/System.Security.Cryptography/MACTripleDES.cs new file mode 100644 index 00000000000..5a051af481c --- /dev/null +++ b/mcs/class/corlib/System.Security.Cryptography/MACTripleDES.cs @@ -0,0 +1,160 @@ +// +// MACTripleDES.cs: Handles MAC with TripleDES +// +// Author: +// Sebastien Pouliot (spouliot@motus.com) +// +// (C) 2002 Motus Technologies Inc. (http://www.motus.com) +// + +using System; +using System.IO; +using System.Security.Cryptography; + +namespace System.Security.Cryptography { + +// References: +// a. FIPS PUB 81: DES MODES OF OPERATION +// MAC: Appendix F (MACDES not MACTripleDES but close enough ;-) +// http://www.itl.nist.gov/fipspubs/fip81.htm + +// Generic MAC mechanims - most of the work is done in here +// It should work with any symmetric algorithm function e.g. DES for MACDES (fips81) +internal class MACAlgorithm { + protected SymmetricAlgorithm algo; + private ICryptoTransform enc; + private CryptoStream stream; + private MemoryStream ms; + private int BlockSize; // in bytes (not in bits) + + public MACAlgorithm (string algoName, CipherMode algoMode) + { + if ((algoMode != CipherMode.CBC) && (algoMode != CipherMode.CFB)) + throw new CryptographicException(); + + algo = (SymmetricAlgorithm) CryptoConfig.CreateFromName (algoName); + algo.Mode = algoMode; + algo.Padding = PaddingMode.Zeros; + BlockSize = (algo.BlockSize >> 3); + } + + ~MACAlgorithm () + { + Dispose (); + } + + public void Dispose () + { + ZeroizeKey (); + // algo.Clear (); not yet present in SymmetricAlgorithm + } + + public SymmetricAlgorithm Algo { + get { return algo; } + } + + public byte[] Key { + get { return algo.Key; } + set { algo.Key = value; } + } + + public byte[] IV { + get { return algo.IV; } + set { algo.IV = value; } + } + + [MonoTODO()] + public void Initialize () + { + if (algo.Mode == CipherMode.CBC) + algo.IV = new Byte [BlockSize]; + enc = algo.CreateEncryptor(); + // TODO Change MemoryStream (unrealistic for big continuous streams) + ms = new MemoryStream (); + stream = new CryptoStream (ms, enc, CryptoStreamMode.Write); + } + + [MonoTODO("")] + public void Core (byte[] rgb, int ib, int cb) + { + if (enc == null) + Initialize (); + + stream.Write (rgb, ib, cb); + } + + [MonoTODO("How should it finish? encrypting the last block?")] + public byte[] Final () + { + stream.FlushFinalBlock (); + byte[] mac = new byte [BlockSize]; + ms.Position -= BlockSize; + ms.Read (mac, 0, BlockSize); + return mac; + } + + public void ZeroizeKey () + { + // well maybe the algo did it - but better twice than none + if (algo.Key != null) + Array.Clear (algo.Key, 0, algo.Key.Length); + } +} + +// LAMESPEC: MACTripleDES == MAC-CBC using TripleDES (not MAC-CFB). +// LAMESPEC: Unlike FIPS81 or FIPS113 the result is encrypted twice (ANSI like?) +public class MACTripleDES: KeyedHashAlgorithm { + private MACAlgorithm mac; + + public MACTripleDES () + { + mac = new MACAlgorithm ("TripleDES", CipherMode.CBC); + HashSizeValue = mac.Algo.BlockSize; + } + + public MACTripleDES (byte[] rgbKey) + { + MACAlgorithm mac = new MACAlgorithm ("TripleDES", CipherMode.CBC); + HashSizeValue = mac.Algo.BlockSize; + mac.Key = rgbKey; + } + + public MACTripleDES (string strTripleDES, byte[] rgbKey) + { + MACAlgorithm mac = new MACAlgorithm (strTripleDES, CipherMode.CBC); + HashSizeValue = mac.Algo.BlockSize; + mac.Key = rgbKey; + } + + ~MACTripleDES () + { + Dispose (false); + } + + protected override void Dispose (bool disposing) + { + if (mac != null) + mac.Dispose(); + base.Dispose (disposing); + } + + public override void Initialize () + { + State = 0; + mac.Initialize (); + } + + protected override void HashCore (byte[] rgb, int ib, int cb) + { + State = 1; + mac.Core (rgb, ib, cb); + } + + protected override byte[] HashFinal () + { + State = 0; + return mac.Final (); + } +} + +}
\ No newline at end of file |