Skip to content

Commit 3f85cf0

Browse files
unknownunknown
authored andcommitted
Password hashing initial version.
1 parent 12aceeb commit 3f85cf0

File tree

7 files changed

+510
-0
lines changed

7 files changed

+510
-0
lines changed

HashingTest/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
*.suo

HashingTest/HashingTest.csproj

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<PropertyGroup>
4+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
5+
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
6+
<ProductVersion>8.0.30703</ProductVersion>
7+
<SchemaVersion>2.0</SchemaVersion>
8+
<ProjectGuid>{8C7D752C-532D-4D12-88B0-048DBF97F9B1}</ProjectGuid>
9+
<OutputType>Exe</OutputType>
10+
<AppDesignerFolder>Properties</AppDesignerFolder>
11+
<RootNamespace>HashingTest</RootNamespace>
12+
<AssemblyName>HashingTest</AssemblyName>
13+
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
14+
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
15+
<FileAlignment>512</FileAlignment>
16+
</PropertyGroup>
17+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
18+
<PlatformTarget>x86</PlatformTarget>
19+
<DebugSymbols>true</DebugSymbols>
20+
<DebugType>full</DebugType>
21+
<Optimize>false</Optimize>
22+
<OutputPath>bin\Debug\</OutputPath>
23+
<DefineConstants>DEBUG;TRACE</DefineConstants>
24+
<ErrorReport>prompt</ErrorReport>
25+
<WarningLevel>4</WarningLevel>
26+
</PropertyGroup>
27+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
28+
<PlatformTarget>x86</PlatformTarget>
29+
<DebugType>pdbonly</DebugType>
30+
<Optimize>true</Optimize>
31+
<OutputPath>bin\Release\</OutputPath>
32+
<DefineConstants>TRACE</DefineConstants>
33+
<ErrorReport>prompt</ErrorReport>
34+
<WarningLevel>4</WarningLevel>
35+
</PropertyGroup>
36+
<ItemGroup>
37+
<Reference Include="System" />
38+
<Reference Include="System.Core" />
39+
<Reference Include="System.Xml.Linq" />
40+
<Reference Include="System.Data.DataSetExtensions" />
41+
<Reference Include="Microsoft.CSharp" />
42+
<Reference Include="System.Data" />
43+
<Reference Include="System.Xml" />
44+
</ItemGroup>
45+
<ItemGroup>
46+
<Compile Include="PBKDF1.cs" />
47+
<Compile Include="PBKDF2.cs" />
48+
<Compile Include="Program.cs" />
49+
<Compile Include="Properties\AssemblyInfo.cs" />
50+
</ItemGroup>
51+
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
52+
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
53+
Other similar extension points exist, see Microsoft.Common.targets.
54+
<Target Name="BeforeBuild">
55+
</Target>
56+
<Target Name="AfterBuild">
57+
</Target>
58+
-->
59+
</Project>

HashingTest/HashingTest.sln

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 11.00
3+
# Visual Studio 2010
4+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HashingTest", "HashingTest.csproj", "{8C7D752C-532D-4D12-88B0-048DBF97F9B1}"
5+
EndProject
6+
Global
7+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
8+
Debug|x86 = Debug|x86
9+
Release|x86 = Release|x86
10+
EndGlobalSection
11+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
12+
{8C7D752C-532D-4D12-88B0-048DBF97F9B1}.Debug|x86.ActiveCfg = Debug|x86
13+
{8C7D752C-532D-4D12-88B0-048DBF97F9B1}.Debug|x86.Build.0 = Debug|x86
14+
{8C7D752C-532D-4D12-88B0-048DBF97F9B1}.Release|x86.ActiveCfg = Release|x86
15+
{8C7D752C-532D-4D12-88B0-048DBF97F9B1}.Release|x86.Build.0 = Release|x86
16+
EndGlobalSection
17+
GlobalSection(SolutionProperties) = preSolution
18+
HideSolutionNode = FALSE
19+
EndGlobalSection
20+
EndGlobal

HashingTest/PBKDF1.cs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
PBKDF1 Implementation of http://www.ietf.org/rfc/rfc2898.txt
3+
Dror Gluska 2012
4+
5+
*/
6+
7+
using System;
8+
using System.Collections.Generic;
9+
using System.Linq;
10+
using System.Text;
11+
using System.Security.Cryptography;
12+
13+
namespace HashingTest
14+
{
15+
/// <summary>
16+
/// PBKDF1 key derivation
17+
/// <para>http://www.ietf.org/rfc/rfc2898.txt</para>
18+
/// </summary>
19+
public class PBKDF1
20+
{
21+
/// <summary>
22+
/// Retrieves MD5 hashed PBKDF1
23+
/// </summary>
24+
public static byte[] MD5GetBytes(byte[] password,
25+
byte[] salt, int iterations, int howManyBytes)
26+
{
27+
return ComputePBKDF1(new MD5CryptoServiceProvider(), password, salt, iterations, howManyBytes);
28+
}
29+
30+
/// <summary>
31+
/// Retrieves SHA1 hashed PBKDF1
32+
/// </summary>
33+
public static byte[] SHA1GetBytes(byte[] password,
34+
byte[] salt, int iterations, int howManyBytes)
35+
{
36+
return ComputePBKDF1(new SHA1Managed(), password, salt, iterations, howManyBytes);
37+
}
38+
39+
/// <summary>
40+
/// Computes password + salt hashed by hashAlgo for a number of iterations and retrieve howManyBytes from the resulting hash.
41+
/// </summary>
42+
private static byte[] ComputePBKDF1(HashAlgorithm hashAlgo, byte[] password, byte[] salt, int iterations, int howManyBytes)
43+
{
44+
if (howManyBytes > (hashAlgo.HashSize/8))
45+
throw new ArgumentOutOfRangeException("howManyBytes should be smaller than " + (hashAlgo.HashSize/8).ToString());
46+
47+
byte[] passandsalt = new byte[password.Length + salt.Length];
48+
Array.Copy(password, 0, passandsalt, 0, password.Length);
49+
Array.Copy(salt, 0, passandsalt, password.Length, salt.Length);
50+
51+
var hash = hashAlgo.ComputeHash(passandsalt);
52+
53+
for (int i = 1; i < iterations; i++)
54+
hash = hashAlgo.ComputeHash(hash);
55+
56+
byte[] hashsubset = new byte[howManyBytes];
57+
Array.Copy(hash, hashsubset, howManyBytes);
58+
return hashsubset;
59+
}
60+
}
61+
}

HashingTest/PBKDF2.cs

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/*
2+
PBKDF2 key derivation
3+
implementation of PKCS#5 v2.0
4+
Password Based Key Derivation Function 2
5+
http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/index.html
6+
For the HMAC function, see RFC 2104
7+
http://www.ietf.org/rfc/rfc2104.txt
8+
Keith Brown
9+
10+
Change log:
11+
2004 Keith Brown - initial version
12+
2012-09-01 Dror Gluska - change to SHA1 instead of SHA256 and add ability to pass the hashing function to the main function.
13+
14+
15+
*/
16+
17+
using System;
18+
using System.Collections.Generic;
19+
using System.Linq;
20+
using System.Text;
21+
using System.Security.Cryptography;
22+
23+
namespace HashingTest
24+
{
25+
/// <summary>
26+
/// PBKDF2 Password-Based Key Derivation Function 2
27+
/// </summary>
28+
class PBKDF2
29+
{
30+
// SHA-256 has a 512-bit block size and gives a 256-bit output
31+
const int BLOCK_SIZE_IN_BYTES = 64;
32+
const byte IPAD = 0x36;
33+
const byte OPAD = 0x5C;
34+
35+
public static byte[] SHA1GetBytes(byte[] password, byte[] salt, int iterations, int howManyBytes)
36+
{
37+
return GetBytes(new SHA1Managed(), password, salt, iterations, howManyBytes);
38+
}
39+
40+
public static byte[] GetBytes(HashAlgorithm hashAlgo, byte[] password,
41+
byte[] salt, int iterations, int howManyBytes)
42+
{
43+
HashAlgorithm innerHash = hashAlgo;
44+
HashAlgorithm outerHash = hashAlgo;
45+
46+
var HASH_SIZE_IN_BYTES = (innerHash.HashSize/8);
47+
48+
// round up
49+
uint cBlocks = (uint)((howManyBytes +
50+
HASH_SIZE_IN_BYTES - 1) / HASH_SIZE_IN_BYTES);
51+
52+
// seed for the pseudo-random fcn: salt + block index
53+
byte[] saltAndIndex = new byte[salt.Length + 4];
54+
Array.Copy(salt, 0, saltAndIndex, 0, salt.Length);
55+
56+
byte[] output = new byte[cBlocks * HASH_SIZE_IN_BYTES];
57+
int outputOffset = 0;
58+
59+
60+
61+
// HMAC says the key must be hashed or padded with zeros
62+
// so it fits into a single block of the hash in use
63+
if (password.Length > BLOCK_SIZE_IN_BYTES)
64+
{
65+
password = innerHash.ComputeHash(password);
66+
}
67+
byte[] key = new byte[BLOCK_SIZE_IN_BYTES];
68+
Array.Copy(password, 0, key, 0, password.Length);
69+
70+
byte[] InnerKey = new byte[BLOCK_SIZE_IN_BYTES];
71+
byte[] OuterKey = new byte[BLOCK_SIZE_IN_BYTES];
72+
for (int i = 0; i < BLOCK_SIZE_IN_BYTES; ++i)
73+
{
74+
InnerKey[i] = (byte)(key[i] ^ IPAD);
75+
OuterKey[i] = (byte)(key[i] ^ OPAD);
76+
}
77+
78+
// for each block of desired output
79+
for (int iBlock = 0; iBlock < cBlocks; ++iBlock)
80+
{
81+
// seed HMAC with salt & block index
82+
_incrementBigEndianIndex(saltAndIndex, salt.Length);
83+
byte[] U = saltAndIndex;
84+
85+
for (int i = 0; i < iterations; ++i)
86+
{
87+
// simple implementation of HMAC-SHA-256
88+
innerHash.Initialize();
89+
innerHash.TransformBlock(InnerKey, 0,
90+
BLOCK_SIZE_IN_BYTES, InnerKey, 0);
91+
innerHash.TransformFinalBlock(U, 0, U.Length);
92+
93+
byte[] temp = innerHash.Hash;
94+
95+
outerHash.Initialize();
96+
outerHash.TransformBlock(OuterKey, 0,
97+
BLOCK_SIZE_IN_BYTES, OuterKey, 0);
98+
outerHash.TransformFinalBlock(temp, 0, temp.Length);
99+
100+
U = outerHash.Hash; // U = result of HMAC
101+
102+
// xor result into output buffer
103+
_xorByteArray(U, 0, HASH_SIZE_IN_BYTES,
104+
output, outputOffset);
105+
}
106+
outputOffset += HASH_SIZE_IN_BYTES;
107+
}
108+
byte[] result = new byte[howManyBytes];
109+
Array.Copy(output, 0, result, 0, howManyBytes);
110+
return result;
111+
}
112+
// treat the four bytes starting at buf[offset]
113+
// as a big endian integer, and increment it
114+
static void _incrementBigEndianIndex(byte[] buf, int offset)
115+
{
116+
unchecked
117+
{
118+
if (0 == ++buf[offset + 3])
119+
if (0 == ++buf[offset + 2])
120+
if (0 == ++buf[offset + 1])
121+
if (0 == ++buf[offset + 0])
122+
throw new OverflowException();
123+
}
124+
}
125+
static void _xorByteArray(byte[] src,
126+
int srcOffset, int cb, byte[] dest, int destOffset)
127+
{
128+
int end = checked(srcOffset + cb);
129+
while (srcOffset != end)
130+
{
131+
dest[destOffset] ^= src[srcOffset];
132+
++srcOffset;
133+
++destOffset;
134+
}
135+
}
136+
}
137+
}

0 commit comments

Comments
 (0)