1 /**
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0.
4 */
5
6 #include <aws/external/gtest.h>
7
8 #include <aws/core/utils/HashingUtils.h>
9 #include <aws/core/utils/memory/stl/AWSStringStream.h>
10
11
12 using namespace Aws::Utils;
13
TEST(HashingUtilsTest,TestBase64Encoding)14 TEST(HashingUtilsTest, TestBase64Encoding)
15 {
16 //these are the standard testing vectors from RFC 4648
17 Aws::String test1 = HashingUtils::Base64Encode(ByteBuffer((unsigned char*)"", 0));
18 ASSERT_STREQ("", test1.c_str());
19
20 Aws::String test2 = HashingUtils::Base64Encode(ByteBuffer((unsigned char*) "f", 1));
21 ASSERT_STREQ("Zg==", test2.c_str());
22
23 Aws::String test3 = HashingUtils::Base64Encode(ByteBuffer((unsigned char*) "fo", 2));
24 ASSERT_STREQ("Zm8=", test3.c_str());
25
26 Aws::String test4 = HashingUtils::Base64Encode(ByteBuffer((unsigned char*) "foo", 3));
27 ASSERT_STREQ("Zm9v", test4.c_str());
28
29 Aws::String test5 = HashingUtils::Base64Encode(ByteBuffer((unsigned char*) "foob", 4));
30 ASSERT_STREQ("Zm9vYg==", test5.c_str());
31
32 Aws::String test6 = HashingUtils::Base64Encode(ByteBuffer((unsigned char*) "fooba", 5));
33 ASSERT_STREQ("Zm9vYmE=", test6.c_str());
34
35 Aws::String test7 = HashingUtils::Base64Encode(ByteBuffer((unsigned char*) "foobar", 6));
36 ASSERT_STREQ("Zm9vYmFy", test7.c_str());
37 }
38
TEST(HashingUtilsTest,TestBase64Decoding)39 TEST(HashingUtilsTest, TestBase64Decoding)
40 {
41 //these are the standard testing vectors from RFC 4648
42 ByteBuffer test0 = HashingUtils::Base64Decode("");
43 ASSERT_EQ(ByteBuffer((unsigned char*)"", 0), test0);
44
45 ByteBuffer test1 = HashingUtils::Base64Decode("X");
46 ASSERT_EQ(ByteBuffer((unsigned char*)"", 0), test1);
47
48 ByteBuffer test2 = HashingUtils::Base64Decode("Zg==");
49 ASSERT_EQ(ByteBuffer((unsigned char*)"f", 1), test2);
50
51 ByteBuffer test3 = HashingUtils::Base64Decode("Zm8=");
52 ASSERT_EQ(ByteBuffer((unsigned char*) "fo", 2), test3);
53
54 ByteBuffer test4 = HashingUtils::Base64Decode("Zm9v");
55 ASSERT_EQ(ByteBuffer((unsigned char*) "foo", 3), test4);
56
57 ByteBuffer test5 = HashingUtils::Base64Decode("Zm9vYg==");
58 ASSERT_EQ(ByteBuffer((unsigned char*) "foob", 4), test5);
59
60 ByteBuffer test6 = HashingUtils::Base64Decode("Zm9vYmE=");
61 ASSERT_EQ(ByteBuffer((unsigned char*) "fooba", 5), test6);
62
63 ByteBuffer test7 = HashingUtils::Base64Decode("Zm9vYmFy");
64 ASSERT_EQ(ByteBuffer((unsigned char*) "foobar", 6), test7);
65 }
66
TEST(HashingUtilsTest,TestHexEncodingDecoding)67 TEST(HashingUtilsTest, TestHexEncodingDecoding)
68 {
69 unsigned char beforeHexEncoding[32] =
70 { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C,
71 0x0D, 0x0E, 0x0F, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x78, 0x69,
72 0x5A, 0x4B, 0x3C, 0x2D, 0x1E, 0x0F, 0x10, 0x00 };
73
74 Aws::String hexEncodedValue = HashingUtils::HexEncode(ByteBuffer(beforeHexEncoding, 32));
75
76 const char* afterEncoding =
77 "0102030405060708090a0b0c0d0e0f1122334455667778695a4b3c2d1e0f1000";
78 ASSERT_STREQ(afterEncoding, hexEncodedValue.c_str());
79
80 ByteBuffer hexBuffer(beforeHexEncoding, 32);
81 ASSERT_EQ(hexBuffer, HashingUtils::HexDecode(afterEncoding));
82 }
83
TEST(HashingUtilsTest,TestSHA256HMAC)84 TEST(HashingUtilsTest, TestSHA256HMAC)
85 {
86 const char* toHash = "TestHash";
87 const char* secret = "TestSecret";
88
89 ByteBuffer digest = HashingUtils::CalculateSHA256HMAC(
90 ByteBuffer((unsigned char*) toHash, 8), ByteBuffer((unsigned char*) secret, 10));
91
92 Aws::String computedHashAsHex = HashingUtils::HexEncode(digest);
93
94 ASSERT_EQ(32uL, digest.GetLength());
95 EXPECT_STREQ("43cf04fa24b873a456670d34ef9af2cb7870483327b5767509336fa66fb7986c", computedHashAsHex.c_str());
96 }
97
TEST(HashingUtilsTest,TestSHA256FromString)98 TEST(HashingUtilsTest, TestSHA256FromString)
99 {
100 Aws::String toHash = "TestToHash";
101
102 ByteBuffer digest = HashingUtils::CalculateSHA256(toHash);
103 ASSERT_EQ(32uL, digest.GetLength());
104
105 Aws::String base64Hash = HashingUtils::Base64Encode(digest);
106 EXPECT_STREQ("No9GqyFhBA5QWj9+YUchjN83IByaCH5Lqji0McSOKyg=", base64Hash.c_str());
107
108 // SHA256 results come from https://www.di-mgt.com.au/sha_testvectors.html
109 EXPECT_STREQ(HashingUtils::HexEncode(HashingUtils::CalculateSHA256("")).c_str(),
110 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
111
112 EXPECT_STREQ(HashingUtils::HexEncode(HashingUtils::CalculateSHA256("abc")).c_str(),
113 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
114
115 EXPECT_STREQ(HashingUtils::HexEncode(HashingUtils::CalculateSHA256(
116 "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu")).c_str(),
117 "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1");
118 }
119
TEST(HashingUtilsTest,TestSHA1FromString)120 TEST(HashingUtilsTest, TestSHA1FromString)
121 {
122 Aws::String toHash = "TestToHash";
123
124 ByteBuffer digest = HashingUtils::CalculateSHA1(toHash);
125 ASSERT_EQ(20uL, digest.GetLength());
126
127 // SHA1 results come from https://www.di-mgt.com.au/sha_testvectors.html
128 EXPECT_STREQ(HashingUtils::HexEncode(HashingUtils::CalculateSHA1("")).c_str(),
129 "da39a3ee5e6b4b0d3255bfef95601890afd80709");
130
131 EXPECT_STREQ(HashingUtils::HexEncode(HashingUtils::CalculateSHA1("abc")).c_str(),
132 "a9993e364706816aba3e25717850c26c9cd0d89d");
133
134 EXPECT_STREQ(HashingUtils::HexEncode(HashingUtils::CalculateSHA1(
135 "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu")).c_str(),
136 "a49b2446a02c645bf419f995b67091253a04a259");
137 }
138
TEST(HashingUtilsTest,TestSHA1FromStream)139 TEST(HashingUtilsTest, TestSHA1FromStream)
140 {
141 Aws::StringStream toHash;
142 toHash << "TestToHash";
143
144 ByteBuffer digest = HashingUtils::CalculateSHA1(toHash);
145 ASSERT_EQ(20uL, digest.GetLength());
146
147 // SHA1 results come from https://www.di-mgt.com.au/sha_testvectors.html
148 toHash.str("");
149 toHash.clear();
150 toHash << "";
151 EXPECT_STREQ(HashingUtils::HexEncode(HashingUtils::CalculateSHA1(toHash)).c_str(),
152 "da39a3ee5e6b4b0d3255bfef95601890afd80709");
153
154 toHash.str("");
155 toHash.clear();
156 toHash << "abc";
157 EXPECT_STREQ(HashingUtils::HexEncode(HashingUtils::CalculateSHA1(toHash)).c_str(),
158 "a9993e364706816aba3e25717850c26c9cd0d89d");
159
160 toHash.str("");
161 toHash.clear();
162 toHash << "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu";
163 EXPECT_STREQ(HashingUtils::HexEncode(HashingUtils::CalculateSHA1(toHash)).c_str(),
164 "a49b2446a02c645bf419f995b67091253a04a259");
165 }
166
TEST(HashingUtilsTest,TestSHA256FromStream)167 TEST(HashingUtilsTest, TestSHA256FromStream)
168 {
169 Aws::StringStream toHash;
170 toHash << "TestToHash";
171
172 ByteBuffer digest = HashingUtils::CalculateSHA256(toHash);
173 ASSERT_EQ(32uL, digest.GetLength());
174
175 Aws::String base64Hash = HashingUtils::Base64Encode(digest);
176 EXPECT_STREQ("No9GqyFhBA5QWj9+YUchjN83IByaCH5Lqji0McSOKyg=", base64Hash.c_str());
177
178 // SHA256 results come from https://www.di-mgt.com.au/sha_testvectors.html
179 toHash.str("");
180 toHash.clear();
181 EXPECT_STREQ(HashingUtils::HexEncode(HashingUtils::CalculateSHA256(toHash)).c_str(),
182 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
183
184 toHash.str("");
185 toHash.clear();
186 toHash << "abc";
187 EXPECT_STREQ(HashingUtils::HexEncode(HashingUtils::CalculateSHA256(toHash)).c_str(),
188 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
189
190 toHash.str("");
191 toHash.clear();
192 toHash << "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu";
193 EXPECT_STREQ(HashingUtils::HexEncode(HashingUtils::CalculateSHA256(toHash)).c_str(),
194 "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1");
195 }
196
TEST(HashingUtilsTest,TestSHA256TreeHashEqualsSHA256FromStringWhenSizeLessEqualThanOneMB)197 TEST(HashingUtilsTest, TestSHA256TreeHashEqualsSHA256FromStringWhenSizeLessEqualThanOneMB)
198 {
199 Aws::Vector<Aws::String> strVec;
200 strVec.push_back("");
201 strVec.push_back("abc");
202 strVec.push_back("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
203 strVec.push_back("TestToHash");
204 strVec.push_back(Aws::String(1024 * 1024 - 1, 'A'));
205 strVec.push_back(Aws::String(1024 * 1024, 'A'));
206 for (size_t i = 0; i < strVec.size(); i++)
207 {
208 ByteBuffer sha256Digest = HashingUtils::CalculateSHA256(strVec[i]);
209 ByteBuffer sha256TreeHashDigest = HashingUtils::CalculateSHA256TreeHash(strVec[i]);
210 ASSERT_EQ(32uL, sha256Digest.GetLength());
211 ASSERT_EQ(32uL, sha256TreeHashDigest.GetLength());
212
213 Aws::String base64Hash = HashingUtils::Base64Encode(sha256Digest);
214 Aws::String base64TreeHash = HashingUtils::Base64Encode(sha256TreeHashDigest);
215
216 EXPECT_STREQ(base64Hash.c_str(), base64TreeHash.c_str());
217 }
218 }
219
TEST(HashingUtilsTest,TestSHA256TreeHashFromStringWhenSizeMoreThanOneMB)220 TEST(HashingUtilsTest, TestSHA256TreeHashFromStringWhenSizeMoreThanOneMB)
221 {
222 // All cases are generated by java example code supplied at:
223 // http://docs.aws.amazon.com/amazonglacier/latest/dev/checksum-calculations.html#checksum-calculations-examples
224 // 2MB buffer filled with char '0'
225 Aws::String TwoMBStr(1024 * 1024 * 2, '0');
226 EXPECT_STREQ("489117033ee4cf06991b60ce56830ac409862a6ec8afdfb3b510e8fad3b80d24", HashingUtils::HexEncode(HashingUtils::CalculateSHA256TreeHash(TwoMBStr)).c_str());
227 // 3MB
228 Aws::String ThreeMBStr(1024 * 1024 * 3, '0');
229 EXPECT_STREQ("940257b3e0d13f92c98dc3fc32182e3acd07a81fe82f2b2dcd1802e1eedc5a3c", HashingUtils::HexEncode(HashingUtils::CalculateSHA256TreeHash(ThreeMBStr)).c_str());
230 // 4MB
231 Aws::String FourMBStr(1024 * 1024 * 4, '0');
232 EXPECT_STREQ("0c2c286faeadbb8ef7aab5e1198af77b1c00d6ff634a739f0e4d55ea3a40ad2d", HashingUtils::HexEncode(HashingUtils::CalculateSHA256TreeHash(FourMBStr)).c_str());
233 // 5.5MB
234 Aws::String FivePointFiveMBStr(5767168, '0');
235 EXPECT_STREQ("154e26c78fd74d0c2c9b3cc4644191619dc4f2cd539ae2a74d5fd07957a3ee6a", HashingUtils::HexEncode(HashingUtils::CalculateSHA256TreeHash(FivePointFiveMBStr)).c_str());
236 // 8MB
237 Aws::String EightMBStr(1024 * 1024 * 8, '0');
238 EXPECT_STREQ("ff9ea39186cb33cd5ade7aca078e297a1622f8c1abdd4cc47bcbf66dc5877e1f", HashingUtils::HexEncode(HashingUtils::CalculateSHA256TreeHash(EightMBStr)).c_str());
239 }
240
TEST(HashingUtilsTest,TestSHA256TreeHashEqualsSHA256FromStreamWhenSizeLessEqualThanOneMB)241 TEST(HashingUtilsTest, TestSHA256TreeHashEqualsSHA256FromStreamWhenSizeLessEqualThanOneMB)
242 {
243 Aws::Vector<Aws::StringStream> streamVec(6);
244 streamVec[0] << "";
245 streamVec[1] << "abc";
246 streamVec[2] << "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu";
247 streamVec[3] << "TestToHash";
248 streamVec[4] << Aws::String(1024 * 1024 - 1, 'A');
249 streamVec[5] << Aws::String(1024 * 1024, 'A');
250 for (size_t i = 0; i < streamVec.size(); i++)
251 {
252 ByteBuffer sha256Digest = HashingUtils::CalculateSHA256(streamVec[i]);
253 ByteBuffer sha256TreeHashDigest = HashingUtils::CalculateSHA256TreeHash(streamVec[i]);
254 ASSERT_EQ(32uL, sha256Digest.GetLength());
255 ASSERT_EQ(32uL, sha256TreeHashDigest.GetLength());
256
257 Aws::String base64Hash = HashingUtils::Base64Encode(sha256Digest);
258 Aws::String base64TreeHash = HashingUtils::Base64Encode(sha256TreeHashDigest);
259
260 EXPECT_STREQ(base64Hash.c_str(), base64TreeHash.c_str());
261 }
262 }
263
TEST(HashingUtilsTest,TestSHA256TreeHashFromStreamWhenSizeMoreThanOneMB)264 TEST(HashingUtilsTest, TestSHA256TreeHashFromStreamWhenSizeMoreThanOneMB)
265 {
266 // All cases are generated by java example code supplied at:
267 // http://docs.aws.amazon.com/amazonglacier/latest/dev/checksum-calculations.html#checksum-calculations-examples
268 // 2MB buffer filled with char '0'
269 Aws::StringStream TwoMBStream;
270 TwoMBStream << Aws::String(1024 * 1024 * 2, '0');
271 EXPECT_STREQ("489117033ee4cf06991b60ce56830ac409862a6ec8afdfb3b510e8fad3b80d24", HashingUtils::HexEncode(HashingUtils::CalculateSHA256TreeHash(TwoMBStream)).c_str());
272 // 3MB
273 Aws::StringStream ThreeMBStream;
274 ThreeMBStream << Aws::String(1024 * 1024 * 3, '0');
275 EXPECT_STREQ("940257b3e0d13f92c98dc3fc32182e3acd07a81fe82f2b2dcd1802e1eedc5a3c", HashingUtils::HexEncode(HashingUtils::CalculateSHA256TreeHash(ThreeMBStream)).c_str());
276 // 4MB
277 Aws::StringStream FourMBStream;
278 FourMBStream << Aws::String(1024 * 1024 * 4, '0');
279 EXPECT_STREQ("0c2c286faeadbb8ef7aab5e1198af77b1c00d6ff634a739f0e4d55ea3a40ad2d", HashingUtils::HexEncode(HashingUtils::CalculateSHA256TreeHash(FourMBStream)).c_str());
280 // 5.5MB
281 Aws::StringStream FivePointFiveMBStream;
282 FivePointFiveMBStream << Aws::String(5767168, '0');
283 EXPECT_STREQ("154e26c78fd74d0c2c9b3cc4644191619dc4f2cd539ae2a74d5fd07957a3ee6a", HashingUtils::HexEncode(HashingUtils::CalculateSHA256TreeHash(FivePointFiveMBStream)).c_str());
284 // 8MB
285 Aws::StringStream EightMBStream;
286 EightMBStream << Aws::String(1024 * 1024 * 8, '0');
287 EXPECT_STREQ("ff9ea39186cb33cd5ade7aca078e297a1622f8c1abdd4cc47bcbf66dc5877e1f", HashingUtils::HexEncode(HashingUtils::CalculateSHA256TreeHash(EightMBStream)).c_str());
288 }
289
TestMD5FromString(const char * value,const char * expectedBase64Hash)290 static void TestMD5FromString(const char* value, const char* expectedBase64Hash)
291 {
292 Aws::String source(value);
293
294 ByteBuffer digest = HashingUtils::CalculateMD5(source);
295 ASSERT_EQ(16uL, digest.GetLength());
296
297 Aws::String base64Hash = HashingUtils::Base64Encode(digest);
298 ASSERT_STREQ(expectedBase64Hash, base64Hash.c_str());
299 }
300
TEST(HashingUtilsTest,TestMD5FromString)301 TEST(HashingUtilsTest, TestMD5FromString)
302 {
303 // "" -> d41d8cd98f00b204e9800998ecf8427e -> 1B2M2Y8AsgTpgAmY7PhCfg== (base 64)
304 TestMD5FromString( "", "1B2M2Y8AsgTpgAmY7PhCfg==" );
305
306 // "a" -> 0cc175b9c0f1b6a831c399e269772661 -> DMF1ucDxtqgxw5niaXcmYQ== (base 64)
307 TestMD5FromString( "a", "DMF1ucDxtqgxw5niaXcmYQ==" );
308
309 // "abc" -> 900150983cd24fb0d6963f7d28e17f72 -> kAFQmDzST7DWlj99KOF/cg== (base 64)
310 TestMD5FromString( "abc", "kAFQmDzST7DWlj99KOF/cg==" );
311
312 // "message digest" -> f96b697d7cb7938d525a2f31aaf161d0 -> +WtpfXy3k41SWi8xqvFh0A== (base 64)
313 TestMD5FromString( "message digest", "+WtpfXy3k41SWi8xqvFh0A==" );
314
315 // "abcdefghijklmnopqrstuvwxyz" -> c3fcd3d76192e4007dfb496cca67e13b -> w/zT12GS5AB9+0lsymfhOw== (base 64)
316 TestMD5FromString( "abcdefghijklmnopqrstuvwxyz", "w/zT12GS5AB9+0lsymfhOw==" );
317
318 // "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" -> d174ab98d277d9f5a5611c2c9f419d9f -> 0XSrmNJ32fWlYRwsn0Gdnw== (base 64)
319 TestMD5FromString( "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "0XSrmNJ32fWlYRwsn0Gdnw==" );
320
321 // "12345678901234567890123456789012345678901234567890123456789012345678901234567890" -> 57edf4a22be3c955ac49da2e2107b67a -> V+30oivjyVWsSdouIQe2eg== (base 64)
322 TestMD5FromString( "12345678901234567890123456789012345678901234567890123456789012345678901234567890", "V+30oivjyVWsSdouIQe2eg==" );
323 }
324
TestMD5FromStream(const char * value,const char * expectedBase64Hash)325 static void TestMD5FromStream(const char* value, const char* expectedBase64Hash)
326 {
327 Aws::StringStream stream;
328
329 stream.str(value);
330 ByteBuffer digest = HashingUtils::CalculateMD5(stream);
331 ASSERT_EQ(16uL, digest.GetLength());
332
333 Aws::String base64Hash = HashingUtils::Base64Encode(digest);
334 ASSERT_STREQ(expectedBase64Hash, base64Hash.c_str());
335 }
336
TEST(HashingUtilsTest,TestMD5FromStream)337 TEST(HashingUtilsTest, TestMD5FromStream)
338 {
339 // "" -> d41d8cd98f00b204e9800998ecf8427e -> 1B2M2Y8AsgTpgAmY7PhCfg== (base 64)
340 TestMD5FromStream( "", "1B2M2Y8AsgTpgAmY7PhCfg==" );
341
342 // "a" -> 0cc175b9c0f1b6a831c399e269772661 -> DMF1ucDxtqgxw5niaXcmYQ== (base 64)
343 TestMD5FromStream( "a", "DMF1ucDxtqgxw5niaXcmYQ==" );
344
345 // "abc" -> 900150983cd24fb0d6963f7d28e17f72 -> kAFQmDzST7DWlj99KOF/cg== (base 64)
346 TestMD5FromStream( "abc", "kAFQmDzST7DWlj99KOF/cg==" );
347
348 // "message digest" -> f96b697d7cb7938d525a2f31aaf161d0 -> +WtpfXy3k41SWi8xqvFh0A== (base 64)
349 TestMD5FromStream( "message digest", "+WtpfXy3k41SWi8xqvFh0A==" );
350
351 // "abcdefghijklmnopqrstuvwxyz" -> c3fcd3d76192e4007dfb496cca67e13b -> w/zT12GS5AB9+0lsymfhOw== (base 64)
352 TestMD5FromStream( "abcdefghijklmnopqrstuvwxyz", "w/zT12GS5AB9+0lsymfhOw==" );
353
354 // "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" -> d174ab98d277d9f5a5611c2c9f419d9f -> 0XSrmNJ32fWlYRwsn0Gdnw== (base 64)
355 TestMD5FromStream( "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "0XSrmNJ32fWlYRwsn0Gdnw==" );
356
357 // "12345678901234567890123456789012345678901234567890123456789012345678901234567890" -> 57edf4a22be3c955ac49da2e2107b67a -> V+30oivjyVWsSdouIQe2eg== (base 64)
358 TestMD5FromStream( "12345678901234567890123456789012345678901234567890123456789012345678901234567890", "V+30oivjyVWsSdouIQe2eg==" );
359 }
360
361