1: // *************************************************************************
2: // <copyright file="PKCSKeyGenerator.cs" company="Elegant Software Solutions, LLC">
3: // Portions Copyright (C) 2011 Elegant Software Solutions, LLC. All rights reserved worldwide.
4: // </copyright>
5:
6: // PKCSKeyGenerator.cs
7: // Derive key material using PKCS #1 v1.5 algorithm with MD5 hash
8: //
9: // Portions Copyright (C) 2005. Michel I. Gallant
10: // Portions copyright 2006 Richard Smith
11: // Adapted from http://www.jensign.com/JavaScience/dotnet/DeriveKeyM/index.html
12: //
13: // *************************************************************************
14: //
15: // DeriveKeyM.cs
16: //
17: // Derive a key from a pswd and Salt using MD5 and PKCS #5 v1.5 approach
18: // see also: http://www.openssl.org/docs/crypto/EVP_BytesToKey.html
19: // see also: http://java.sun.com/j2se/1.5.0/docs/guide/security/jce/JCERefGuide.html#PBE
20: //
21: // **************************************************************************
22:
23: namespace Demo.Cryptography
24: {
25: using System;
26: using System.IO;
27: using System.Security.Cryptography;
28: using System.Text;
29:
30: /// <summary>
31: /// This class is used to emulate the Java based PBEWithMD5AndDES functionality of the Demo system.
32: /// </summary>
33: public class PKCSKeyGenerator
34: {
35: /// <summary>
36: /// Key used in the encryption algorythm.
37: /// </summary>
38: private byte[] key = new byte[8];
39:
40: /// <summary>
41: /// IV used in the encryption algorythm.
42: /// </summary>
43: private byte[] iv = new byte[8];
44:
45: /// <summary>
46: /// DES Provider used in the encryption algorythm.
47: /// </summary>
48: private DESCryptoServiceProvider des = new DESCryptoServiceProvider();
49:
50: /// <summary>
51: /// Initializes a new instance of the PKCSKeyGenerator class.
52: /// </summary>
53: public PKCSKeyGenerator()
54: {
55: }
56:
57: /// <summary>
58: /// Initializes a new instance of the PKCSKeyGenerator class.
59: /// </summary>
60: /// <param name="keystring">This is the same as the "password" of the PBEWithMD5AndDES method.</param>
61: /// <param name="salt">This is the salt used to provide extra security to the algorythim.</param>
62: /// <param name="iterationsMd5">Fill out iterationsMd5 later.</param>
63: /// <param name="segments">Fill out segments later.</param>
64: public PKCSKeyGenerator(string keystring, byte[] salt, int iterationsMd5, int segments)
65: {
66: this.Generate(keystring, salt, iterationsMd5, segments);
67: }
68:
69: /// <summary>
70: /// Gets the asymetric Key used in the encryption algorythm. Note that this is read only and is an empty byte array.
71: /// </summary>
72: public byte[] Key
73: {
74: get
75: {
76: return this.key;
77: }
78: }
79:
80: /// <summary>
81: /// Gets the initialization vector used in in the encryption algorythm. Note that this is read only and is an empty byte array.
82: /// </summary>
83: public byte[] IV
84: {
85: get
86: {
87: return this.iv;
88: }
89: }
90:
91: /// <summary>
92: /// Gets an ICryptoTransform interface for encryption
93: /// </summary>
94: public ICryptoTransform Encryptor
95: {
96: get
97: {
98: return this.des.CreateEncryptor(this.key, this.iv);
99: }
100: }
101:
102: /// <summary>
103: /// Gets an ICryptoTransform interface for decryption
104: /// </summary>
105: public ICryptoTransform Decryptor
106: {
107: get
108: {
109: return des.CreateDecryptor(key, iv);
110: }
111: }
112:
113: /// <summary>
114: /// Returns the ICryptoTransform interface used to perform the encryption.
115: /// </summary>
116: /// <param name="keystring">This is the same as the "password" of the PBEWithMD5AndDES method.</param>
117: /// <param name="salt">This is the salt used to provide extra security to the algorythim.</param>
118: /// <param name="iterationsMd5">Fill out iterationsMd5 later.</param>
119: /// <param name="segments">Fill out segments later.</param>
120: /// <returns>ICryptoTransform interface used to perform the encryption.</returns>
121: public ICryptoTransform Generate(string keystring, byte[] salt, int iterationsMd5, int segments)
122: {
123: // MD5 bytes
124: int hashLength = 16;
125:
126: // to store contatenated Mi hashed results
127: byte[] keyMaterial = new byte[hashLength * segments];
128:
129: // --- get secret password bytes ----
130: byte[] passwordBytes;
131: passwordBytes = Encoding.UTF8.GetBytes(keystring);
132:
133: // --- contatenate salt and pswd bytes into fixed data array ---
134: byte[] data00 = new byte[passwordBytes.Length + salt.Length];
135:
136: // copy the pswd bytes
137: Array.Copy(passwordBytes, data00, passwordBytes.Length);
138:
139: // concatenate the salt bytes
140: Array.Copy(salt, 0, data00, passwordBytes.Length, salt.Length);
141:
142: // ---- do multi-hashing and contatenate results D1, D2 ... into keymaterial bytes ----
143: MD5 md5 = new MD5CryptoServiceProvider();
144: byte[] result = null;
145:
146: // fixed length initial hashtarget
147: byte[] hashtarget = new byte[hashLength + data00.Length];
148:
149: for (int j = 0; j < segments; j++)
150: {
151: // ---- Now hash consecutively for iterationsMd5 times ------
152: if (j == 0)
153: {
154: // initialize
155: result = data00;
156: }
157: else
158: {
159: Array.Copy(result, hashtarget, result.Length);
160: Array.Copy(data00, 0, hashtarget, result.Length, data00.Length);
161: result = hashtarget;
162: }
163:
164: for (int i = 0; i < iterationsMd5; i++)
165: {
166: result = md5.ComputeHash(result);
167: }
168:
169: // contatenate to keymaterial
170: Array.Copy(result, 0, keyMaterial, j * hashLength, result.Length);
171: }
172:
173: Array.Copy(keyMaterial, 0, this.key, 0, 8);
174: Array.Copy(keyMaterial, 8, this.iv, 0, 8);
175:
176: return this.Encryptor;
177: }
178: }
179: }