summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/Security/Cryptography/mactripleDES.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/src/System/Security/Cryptography/mactripleDES.cs')
-rw-r--r--src/mscorlib/src/System/Security/Cryptography/mactripleDES.cs247
1 files changed, 247 insertions, 0 deletions
diff --git a/src/mscorlib/src/System/Security/Cryptography/mactripleDES.cs b/src/mscorlib/src/System/Security/Cryptography/mactripleDES.cs
new file mode 100644
index 0000000000..5f27fd6bf7
--- /dev/null
+++ b/src/mscorlib/src/System/Security/Cryptography/mactripleDES.cs
@@ -0,0 +1,247 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+// See: http://www.itl.nist.gov/fipspubs/fip81.htm for a spec
+
+namespace System.Security.Cryptography {
+ using System.IO;
+ using System.Diagnostics.Contracts;
+
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public class MACTripleDES : KeyedHashAlgorithm
+ {
+ // Output goes to HashMemorySink since we don't care about the actual data
+ private ICryptoTransform m_encryptor;
+ private CryptoStream _cs;
+ private TailStream _ts;
+ private const int m_bitsPerByte = 8;
+ private int m_bytesPerBlock;
+ private TripleDES des;
+
+ //
+ // public constructors
+ //
+
+ public MACTripleDES() {
+ KeyValue = new byte[24];
+ Utils.StaticRandomNumberGenerator.GetBytes(KeyValue);
+
+ // Create a TripleDES encryptor
+ des = TripleDES.Create();
+ HashSizeValue = des.BlockSize;
+
+ m_bytesPerBlock = des.BlockSize/m_bitsPerByte;
+ // By definition, MAC-CBC-3DES takes an IV=0. C# zero-inits arrays,
+ // so all we have to do here is define it.
+ des.IV = new byte[m_bytesPerBlock];
+ des.Padding = PaddingMode.Zeros;
+
+ m_encryptor = null;
+ }
+
+ public MACTripleDES(byte[] rgbKey)
+ : this("System.Security.Cryptography.TripleDES",rgbKey) {}
+
+ public MACTripleDES(String strTripleDES, byte[] rgbKey) {
+ // Make sure we know which algorithm to use
+ if (rgbKey == null)
+ throw new ArgumentNullException("rgbKey");
+ Contract.EndContractBlock();
+ // Create a TripleDES encryptor
+ if (strTripleDES == null) {
+ des = TripleDES.Create();
+ } else {
+ des = TripleDES.Create(strTripleDES);
+ }
+
+ HashSizeValue = des.BlockSize;
+ // Stash the key away
+ KeyValue = (byte[]) rgbKey.Clone();
+
+ m_bytesPerBlock = des.BlockSize/m_bitsPerByte;
+ // By definition, MAC-CBC-3DES takes an IV=0. C# zero-inits arrays,
+ // so all we have to do here is define it.
+ des.IV = new byte[m_bytesPerBlock];
+ des.Padding = PaddingMode.Zeros;
+
+ m_encryptor = null;
+ }
+
+ public override void Initialize() {
+ m_encryptor = null;
+ }
+
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public PaddingMode Padding {
+ get { return des.Padding; }
+ set {
+ if ((value < PaddingMode.None) || (PaddingMode.ISO10126 < value))
+ throw new CryptographicException(Environment.GetResourceString("Cryptography_InvalidPaddingMode"));
+ des.Padding = value;
+ }
+ }
+
+ //
+ // protected methods
+ //
+
+ protected override void HashCore(byte[] rgbData, int ibStart, int cbSize) {
+ // regenerate the TripleDES object before each call to ComputeHash
+ if (m_encryptor == null) {
+ des.Key = this.Key;
+ m_encryptor = des.CreateEncryptor();
+ _ts = new TailStream(des.BlockSize / 8); // 8 bytes
+ _cs = new CryptoStream(_ts, m_encryptor, CryptoStreamMode.Write);
+ }
+
+ // Encrypt using 3DES
+ _cs.Write(rgbData, ibStart, cbSize);
+ }
+
+ protected override byte[] HashFinal() {
+ // If Hash has been called on a zero buffer
+ if (m_encryptor == null) {
+ des.Key = this.Key;
+ m_encryptor = des.CreateEncryptor();
+ _ts = new TailStream(des.BlockSize / 8); // 8 bytes
+ _cs = new CryptoStream(_ts, m_encryptor, CryptoStreamMode.Write);
+ }
+
+ // Finalize the hashing and return the result
+ _cs.FlushFinalBlock();
+ return _ts.Buffer;
+ }
+
+ // IDisposable methods
+ protected override void Dispose(bool disposing) {
+ if (disposing) {
+ // dispose of our internal state
+ if (des != null)
+ des.Clear();
+ if (m_encryptor != null)
+ m_encryptor.Dispose();
+ if (_cs != null)
+ _cs.Clear();
+ if (_ts != null)
+ _ts.Clear();
+ }
+ base.Dispose(disposing);
+ }
+ }
+
+ //
+ // TailStream is another utility class -- it remembers the last n bytes written to it
+ // This is useful for MAC-3DES since we need to capture only the result of the last block
+
+ internal sealed class TailStream : Stream {
+ private byte[] _Buffer;
+ private int _BufferSize;
+ private int _BufferIndex = 0;
+ private bool _BufferFull = false;
+
+ public TailStream(int bufferSize) {
+ _Buffer = new byte[bufferSize];
+ _BufferSize = bufferSize;
+ }
+
+ public void Clear() {
+ Close();
+ }
+
+ protected override void Dispose(bool disposing) {
+ try {
+ if (disposing) {
+ if (_Buffer != null) {
+ Array.Clear(_Buffer, 0, _Buffer.Length);
+ }
+ _Buffer = null;
+ }
+ }
+ finally {
+ base.Dispose(disposing);
+ }
+ }
+
+ public byte[] Buffer {
+ get { return (byte[]) _Buffer.Clone(); }
+ }
+
+ public override bool CanRead {
+ [Pure]
+ get { return false; }
+ }
+
+ public override bool CanSeek {
+ [Pure]
+ get { return false; }
+ }
+
+ public override bool CanWrite {
+ [Pure]
+ get { return _Buffer != null; }
+ }
+
+ public override long Length {
+ get { throw new NotSupportedException(Environment.GetResourceString("NotSupported_UnseekableStream")); }
+ }
+
+ public override long Position {
+ get { throw new NotSupportedException(Environment.GetResourceString("NotSupported_UnseekableStream")); }
+ set { throw new NotSupportedException(Environment.GetResourceString("NotSupported_UnseekableStream")); }
+ }
+
+ public override void Flush() {
+ return;
+ }
+
+ public override long Seek(long offset, SeekOrigin origin) {
+ throw new NotSupportedException(Environment.GetResourceString("NotSupported_UnseekableStream"));
+ }
+
+ public override void SetLength(long value) {
+ throw new NotSupportedException(Environment.GetResourceString("NotSupported_UnseekableStream"));
+ }
+
+ public override int Read(byte[] buffer, int offset, int count) {
+ throw new NotSupportedException(Environment.GetResourceString("NotSupported_UnreadableStream"));
+ }
+
+ public override void Write(byte[] buffer, int offset, int count) {
+ if (_Buffer == null)
+ throw new ObjectDisposedException("TailStream");
+
+ // If no bytes to write, then return
+ if (count == 0) return;
+ // The most common case will be when we have a full buffer
+ if (_BufferFull) {
+ // if more bytes are written in this call than the size of the buffer,
+ // just remember the last _BufferSize bytes
+ if (count > _BufferSize) {
+ System.Buffer.InternalBlockCopy(buffer, offset+count-_BufferSize, _Buffer, 0, _BufferSize);
+ return;
+ } else {
+ // move _BufferSize - count bytes left, then copy the new bytes
+ System.Buffer.InternalBlockCopy(_Buffer, _BufferSize - count, _Buffer, 0, _BufferSize - count);
+ System.Buffer.InternalBlockCopy(buffer, offset, _Buffer, _BufferSize - count, count);
+ return;
+ }
+ } else {
+ // buffer isn't full yet, so more cases
+ if (count > _BufferSize) {
+ System.Buffer.InternalBlockCopy(buffer, offset+count-_BufferSize, _Buffer, 0, _BufferSize);
+ _BufferFull = true;
+ return;
+ } else if (count + _BufferIndex >= _BufferSize) {
+ System.Buffer.InternalBlockCopy(_Buffer, _BufferIndex+count-_BufferSize, _Buffer, 0, _BufferSize - count);
+ System.Buffer.InternalBlockCopy(buffer, offset, _Buffer, _BufferIndex, count);
+ _BufferFull = true;
+ return;
+ } else {
+ System.Buffer.InternalBlockCopy(buffer, offset, _Buffer, _BufferIndex, count);
+ _BufferIndex += count;
+ return;
+ }
+ }
+ }
+ }
+}