1 /* 2 KeePass Password Safe - The Open-Source Password Manager 3 Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de> 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 using System; 21 using System.Collections.Generic; 22 using System.Diagnostics; 23 using System.IO; 24 using System.Text; 25 26 #if !KeePassUAP 27 using System.Security.Cryptography; 28 #endif 29 30 using KeePassLib.Utility; 31 32 namespace KeePassLib.Cryptography 33 { 34 public sealed class HashingStreamEx : Stream 35 { 36 private readonly Stream m_sBaseStream; 37 private readonly bool m_bWriting; 38 private HashAlgorithm m_hash; 39 40 private byte[] m_pbFinalHash = null; 41 42 public byte[] Hash 43 { 44 get { return m_pbFinalHash; } 45 } 46 47 public override bool CanRead 48 { 49 get { return !m_bWriting; } 50 } 51 52 public override bool CanSeek 53 { 54 get { return false; } 55 } 56 57 public override bool CanWrite 58 { 59 get { return m_bWriting; } 60 } 61 62 public override long Length 63 { 64 get { return m_sBaseStream.Length; } 65 } 66 67 public override long Position 68 { 69 get { return m_sBaseStream.Position; } 70 set { Debug.Assert(false); throw new NotSupportedException(); } 71 } 72 HashingStreamEx(Stream sBaseStream, bool bWriting, HashAlgorithm hashAlgorithm)73 public HashingStreamEx(Stream sBaseStream, bool bWriting, HashAlgorithm hashAlgorithm) 74 { 75 if(sBaseStream == null) throw new ArgumentNullException("sBaseStream"); 76 77 m_sBaseStream = sBaseStream; 78 m_bWriting = bWriting; 79 80 #if !KeePassLibSD 81 m_hash = (hashAlgorithm ?? new SHA256Managed()); 82 #else // KeePassLibSD 83 m_hash = null; 84 85 try { m_hash = HashAlgorithm.Create("SHA256"); } 86 catch(Exception) { } 87 try { if(m_hash == null) m_hash = HashAlgorithm.Create(); } 88 catch(Exception) { } 89 #endif 90 if(m_hash == null) { Debug.Assert(false); return; } 91 92 // Validate hash algorithm 93 if(!m_hash.CanTransformMultipleBlocks) 94 { 95 Debug.Assert(false); 96 m_hash = null; 97 } 98 } 99 Dispose(bool disposing)100 protected override void Dispose(bool disposing) 101 { 102 if(disposing) 103 { 104 if(m_hash != null) 105 { 106 try 107 { 108 m_hash.TransformFinalBlock(MemUtil.EmptyByteArray, 0, 0); 109 m_pbFinalHash = m_hash.Hash; 110 m_hash.Clear(); 111 } 112 catch(Exception) { Debug.Assert(false); } 113 114 m_hash = null; 115 } 116 117 m_sBaseStream.Close(); 118 } 119 120 base.Dispose(disposing); 121 } 122 Flush()123 public override void Flush() 124 { 125 m_sBaseStream.Flush(); 126 } 127 Seek(long lOffset, SeekOrigin soOrigin)128 public override long Seek(long lOffset, SeekOrigin soOrigin) 129 { 130 Debug.Assert(false); 131 throw new NotSupportedException(); 132 } 133 SetLength(long lValue)134 public override void SetLength(long lValue) 135 { 136 Debug.Assert(false); 137 throw new NotSupportedException(); 138 } 139 Read(byte[] pbBuffer, int nOffset, int nCount)140 public override int Read(byte[] pbBuffer, int nOffset, int nCount) 141 { 142 if(m_bWriting) { Debug.Assert(false); throw new InvalidOperationException(); } 143 144 int nRead = m_sBaseStream.Read(pbBuffer, nOffset, nCount); 145 int nPartialRead = nRead; 146 while((nRead < nCount) && (nPartialRead != 0)) 147 { 148 nPartialRead = m_sBaseStream.Read(pbBuffer, nOffset + nRead, 149 nCount - nRead); 150 nRead += nPartialRead; 151 } 152 153 #if DEBUG 154 byte[] pbOrg = new byte[pbBuffer.Length]; 155 Array.Copy(pbBuffer, pbOrg, pbBuffer.Length); 156 #endif 157 158 if((m_hash != null) && (nRead > 0)) 159 m_hash.TransformBlock(pbBuffer, nOffset, nRead, pbBuffer, nOffset); 160 161 #if DEBUG 162 Debug.Assert(MemUtil.ArraysEqual(pbBuffer, pbOrg)); 163 #endif 164 165 return nRead; 166 } 167 Write(byte[] pbBuffer, int nOffset, int nCount)168 public override void Write(byte[] pbBuffer, int nOffset, int nCount) 169 { 170 if(!m_bWriting) { Debug.Assert(false); throw new InvalidOperationException(); } 171 172 #if DEBUG 173 byte[] pbOrg = new byte[pbBuffer.Length]; 174 Array.Copy(pbBuffer, pbOrg, pbBuffer.Length); 175 #endif 176 177 if((m_hash != null) && (nCount > 0)) 178 m_hash.TransformBlock(pbBuffer, nOffset, nCount, pbBuffer, nOffset); 179 180 #if DEBUG 181 Debug.Assert(MemUtil.ArraysEqual(pbBuffer, pbOrg)); 182 #endif 183 184 m_sBaseStream.Write(pbBuffer, nOffset, nCount); 185 } 186 } 187 } 188