Skip to content

Commit 5ad4bfb

Browse files
committed
fix EvilBeaver#1683: инкрементальное ХешированиеДанных без захвата файлов
1 parent d201b54 commit 5ad4bfb

3 files changed

Lines changed: 137 additions & 90 deletions

File tree

src/OneScript.StandardLibrary/Hash/Crc32.cs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,31 @@ protected override void HashCore(byte[] array, int ibStart, int cbSize)
6969
protected override byte[] HashFinal()
7070
{
7171
var result = BitConverter.GetBytes(~_crc);
72-
if (BitConverter.IsLittleEndian)
73-
Array.Reverse(result);
7472

7573
HashValue = result;
7674
return result;
77-
}
78-
75+
}
76+
77+
#region IncrementalHash
78+
public void AppendData(byte[] array)
79+
{
80+
HashCore(array, 0, array.Length);
81+
}
82+
83+
public void AppendData(byte[] array, int offset, int count)
84+
{
85+
HashCore(array, offset, count);
86+
}
87+
88+
public byte[] GetCurrentHash()
89+
{
90+
return BitConverter.GetBytes(~_crc);
91+
}
92+
93+
public UInt32 GetCurrentHashAsUInt32()
94+
{
95+
return ~_crc;
96+
}
97+
#endregion
7998
}
8099
}

src/OneScript.StandardLibrary/Hash/HashImpl.cs

Lines changed: 106 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -5,46 +5,39 @@ This Source Code Form is subject to the terms of the
55
at http://mozilla.org/MPL/2.0/.
66
----------------------------------------------------------*/
77

8-
using System;
9-
using System.IO;
10-
using System.Security.Cryptography;
11-
using System.Text;
128
using OneScript.Contexts;
139
using OneScript.Exceptions;
1410
using OneScript.StandardLibrary.Binary;
1511
using OneScript.Values;
1612
using ScriptEngine.Machine;
1713
using ScriptEngine.Machine.Contexts;
14+
using System;
15+
using System.IO;
16+
using System.Security.Cryptography;
17+
using System.Text;
1818

1919
namespace OneScript.StandardLibrary.Hash
20-
{
20+
{
2121
[ContextClass("ХешированиеДанных", "DataHashing")]
22-
public class HashImpl : AutoContext<HashImpl>, IDisposable
23-
{
24-
private HashAlgorithm _provider;
25-
private HashFunctionEnum _enumValue;
26-
private CombinedStream _toCalculate=new CombinedStream();
22+
public class HashImpl : AutoContext<HashImpl>
23+
{
24+
private const int BUFFER_SIZE = (1024 * 32);
25+
26+
private readonly Crc32 _crc32;
27+
private readonly IncrementalHash _provider;
28+
private readonly HashFunctionEnum _enumValue;
2729
private bool _calculated;
2830
private byte[] _hash;
2931

30-
public HashImpl(HashAlgorithm provider, HashFunctionEnum enumValue)
32+
public HashImpl(IncrementalHash provider, HashFunctionEnum enumValue)
3133
{
3234
_provider = provider;
3335
_enumValue = enumValue;
3436
_calculated = false;
35-
}
36-
37-
public byte[] InternalHash
38-
{
39-
get
40-
{
41-
if (!_calculated)
42-
{
43-
_hash = _provider.ComputeHash(_toCalculate);
44-
_calculated = true;
45-
}
46-
return _hash;
47-
}
37+
if (enumValue == HashFunctionEnum.CRC32 || provider==null)
38+
{
39+
_crc32 = new Crc32();
40+
}
4841
}
4942

5043
[ContextProperty("ХешФункция", "HashFunction")]
@@ -55,52 +48,100 @@ public IValue Hash
5548
{
5649
get
5750
{
58-
if (_provider is Crc32)
59-
{
60-
var buffer = new byte[4];
61-
Array.Copy(InternalHash, buffer, 4);
62-
if (BitConverter.IsLittleEndian)
63-
Array.Reverse(buffer);
64-
var ret = BitConverter.ToUInt32(buffer, 0);
65-
return ValueFactory.Create((decimal)ret);
66-
}
67-
return new BinaryDataContext(InternalHash);
51+
if(!_calculated)
52+
return ValueFactory.Create(0);
53+
54+
if (_crc32 != null)
55+
return ValueFactory.Create(_crc32.GetCurrentHashAsUInt32());
56+
57+
return new BinaryDataContext(_hash);
6858
}
6959
}
7060

7161
[ContextProperty("ХешСуммаСтрокой", "HashSumOfString")]
7262
public string HashString
7363
{
7464
get
75-
{
65+
{
66+
if (_crc32 != null)
67+
return _crc32.GetCurrentHashAsUInt32().ToString("X8");
68+
7669
var sb = new StringBuilder();
77-
for (int i = 0; i < InternalHash.Length; i++)
78-
sb.Append(InternalHash[i].ToString("X2"));
70+
for (int i = 0; i < _hash.Length; i++)
71+
sb.Append(_hash[i].ToString("X2"));
7972
return sb.ToString();
8073
}
8174
}
8275

76+
private void AppendData(byte[] data)
77+
{
78+
AppendData(data, data.Length);
79+
}
80+
81+
private void AppendData(byte[] data, int count)
82+
{
83+
if (_crc32 != null)
84+
{
85+
_crc32.AppendData(data,0,count);
86+
}
87+
else
88+
{
89+
_provider.AppendData(data,0,count);
90+
_hash = _provider.GetCurrentHash();
91+
}
92+
93+
_calculated = true;
94+
}
95+
96+
private void AppendStream(Stream stream)
97+
{
98+
var buffer = new byte[BUFFER_SIZE];
99+
while (true)
100+
{
101+
var read = stream.Read(buffer,0, BUFFER_SIZE);
102+
if (read == 0)
103+
break;
104+
105+
AppendData(buffer, read);
106+
}
107+
}
108+
109+
private void AppendStream(Stream stream, int count)
110+
{
111+
int bufSize = Math.Min(BUFFER_SIZE, count);
112+
var buffer = new byte[bufSize];
113+
int toRead = count;
114+
while (toRead > 0)
115+
{
116+
var read = stream.Read(buffer,0, Math.Min(toRead, bufSize));
117+
if (read == 0)
118+
break;
119+
120+
AppendData(buffer, read);
121+
toRead -= read;
122+
}
123+
}
83124

84125
[ContextMethod("Добавить", "Append")]
85-
public void Append(BslValue toAdd, uint count = 0)
126+
public void Append(BslValue toAdd, int count = 0)
86127
{
87128
switch (toAdd)
88129
{
89130
case BslStringValue s:
90-
AddStream(new MemoryStream(Encoding.UTF8.GetBytes((string)s)));
131+
AppendData(Encoding.UTF8.GetBytes((string)s));
91132
break;
92-
case BslObjectValue obj when obj is IStreamWrapper wrapper:
133+
case IStreamWrapper wrapper:
93134
var stream = wrapper.GetUnderlyingStream();
94-
var readByte = (int)Math.Min(count == 0 ? stream.Length : count, stream.Length - stream.Position);
95-
var buffer = new byte[readByte];
96-
stream.Read(buffer, 0, readByte);
97-
AddStream(new MemoryStream(buffer));
135+
if (count == 0)
136+
AppendStream(stream);
137+
else
138+
AppendStream(stream, count);
98139
break;
99-
case BslObjectValue obj when obj is BinaryDataContext binaryData:
100-
AddStream(binaryData.GetStream());
140+
case BinaryDataContext binaryData:
141+
AppendStream(binaryData.GetStream());
101142
break;
102143
default:
103-
throw RuntimeException.InvalidArgumentType(nameof(toAdd));
144+
throw RuntimeException.InvalidNthArgumentType(1);
104145
}
105146
}
106147

@@ -109,52 +150,33 @@ public void AppendFile(string path)
109150
{
110151
if (!File.Exists(path))
111152
throw RuntimeException.InvalidArgumentType();
112-
AddStream(new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
153+
var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
154+
AppendStream(stream);
155+
stream.Close();
113156
}
114157

115-
[ContextMethod("Очистить", "Clear")]
116-
public void Clear()
117-
{
118-
_toCalculate.Close();
119-
_toCalculate.Dispose();
120-
_toCalculate = new CombinedStream();
121-
_calculated = false;
122-
}
123-
124-
125158
[ScriptConstructor(Name = "По указанной хеш-функции")]
126159
public static HashImpl Constructor(HashFunctionEnum providerEnum)
127-
{
128-
var objectProvider = GetProvider(providerEnum);
160+
{
161+
if (providerEnum == HashFunctionEnum.CRC32)
162+
return new HashImpl(null, providerEnum);
163+
164+
var objectProvider = IncrementalHash.CreateHash(GetAlgorithmName(providerEnum));
129165
return new HashImpl(objectProvider, providerEnum);
130166
}
131167

132-
private static HashAlgorithm GetProvider(HashFunctionEnum algo)
168+
private static HashAlgorithmName GetAlgorithmName(HashFunctionEnum algo)
133169
{
134-
switch (algo)
135-
{
136-
case HashFunctionEnum.CRC32:
137-
return new Crc32();
138-
default:
139-
var ret = HashAlgorithm.Create(algo.ToString());
140-
if (ret == null)
141-
throw RuntimeException.InvalidArgumentType();
142-
return ret;
143-
}
170+
return algo switch
171+
{
172+
HashFunctionEnum.MD5 => HashAlgorithmName.MD5,
173+
HashFunctionEnum.SHA1 => HashAlgorithmName.SHA1,
174+
HashFunctionEnum.SHA256 => HashAlgorithmName.SHA256,
175+
HashFunctionEnum.SHA384 => HashAlgorithmName.SHA384,
176+
HashFunctionEnum.SHA512 => HashAlgorithmName.SHA512,
177+
_ => throw RuntimeException.InvalidArgumentValue()
178+
};
144179
}
145180

146-
public void Dispose()
147-
{
148-
_toCalculate.Close();
149-
_toCalculate.Dispose();
150-
}
151-
152-
private void AddStream(Stream stream)
153-
{
154-
_toCalculate.AddStream(stream);
155-
_toCalculate.Seek(0, SeekOrigin.Begin);
156-
_calculated = false;
157-
158-
}
159181
}
160182
}

tests/hash.os

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
Провайдер.Добавить("456");
8080
Провайдер.Добавить("789");
8181

82+
юТест.ПроверитьРавенство(3421780262,Провайдер.ХешСумма);
8283
юТест.ПроверитьРавенство("CBF43926",Провайдер.ХешСуммаСтрокой);
8384
КонецПроцедуры
8485

@@ -93,11 +94,16 @@
9394
Провайдер = Новый ХешированиеДанных(ХешФункция.MD5);
9495
Провайдер.ДобавитьФайл(Файл);
9596

96-
Провайдер2 = Новый ХешированиеДанных(ХешФункция.MD5);
97+
Провайдер2 = Новый ХешированиеДанных(ХешФункция.CRC32);
9798
Провайдер2.ДобавитьФайл(Файл);
99+
100+
УдалитьФайлы(Файл);
98101

99102
Запись = Новый ЗаписьТекста(Файл);
100-
Запись.Записать("Привет");
103+
Запись.Записать("Привет!");
101104
Запись.Закрыть();
105+
106+
юТест.ПроверитьРавенство("56 45 D3 0C 39 EA 90 18 D1 CA B7 7D 5F 37 0A 8C",Строка(Провайдер.ХешСумма));
107+
юТест.ПроверитьРавенство(3139669858,Провайдер2.ХешСумма);
102108

103109
КонецПроцедуры

0 commit comments

Comments
 (0)