Fix the build
[mono.git] / mcs / class / Mono.Security / Mono.Security.Cryptography / DiffieHellmanManaged.cs
1 //
2 // DiffieHellmanManaged.cs: Implements the Diffie-Hellman key agreement algorithm
3 //
4 // Author:
5 //      Pieter Philippaerts (Pieter@mentalis.org)
6 //
7 // (C) 2003 The Mentalis.org Team (http://www.mentalis.org/)
8 //
9 //   References:
10 //     - PKCS#3  [http://www.rsasecurity.com/rsalabs/pkcs/pkcs-3/]
11 //
12
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 // 
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 // 
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33
34 using System;
35 using System.Security.Cryptography;
36 using Mono.Math;
37
38 namespace Mono.Security.Cryptography {
39         /// <summary>
40         /// Implements the Diffie-Hellman algorithm.
41         /// </summary>
42         public sealed class DiffieHellmanManaged : DiffieHellman {
43                 /// <summary>
44                 /// Initializes a new <see cref="DiffieHellmanManaged"/> instance.
45                 /// </summary>
46                 /// <remarks>The default length of the shared secret is 1024 bits.</remarks>
47                 public DiffieHellmanManaged() : this(1024, 160, DHKeyGeneration.Static) {}
48                 /// <summary>
49                 /// Initializes a new <see cref="DiffieHellmanManaged"/> instance.
50                 /// </summary>
51                 /// <param name="bitLength">The length, in bits, of the public P parameter.</param>
52                 /// <param name="l">The length, in bits, of the secret value X. This parameter can be set to 0 to use the default size.</param>
53                 /// <param name="method">One of the <see cref="DHKeyGeneration"/> values.</param>
54                 /// <remarks>The larger the bit length, the more secure the algorithm is. The default is 1024 bits. The minimum bit length is 128 bits.<br/>The size of the private value will be one fourth of the bit length specified.</remarks>
55                 /// <exception cref="ArgumentException">The specified bit length is invalid.</exception>
56                 public DiffieHellmanManaged(int bitLength, int l, DHKeyGeneration method) {
57                         if (bitLength < 256 || l < 0)
58                                 throw new ArgumentException();
59                         BigInteger p, g;
60                         GenerateKey (bitLength, method, out p, out g);
61                         Initialize(p, g, null, l, false);
62                 }
63                 /// <summary>
64                 /// Initializes a new <see cref="DiffieHellmanManaged"/> instance.
65                 /// </summary>
66                 /// <param name="p">The P parameter of the Diffie-Hellman algorithm. This is a public parameter.</param>
67                 /// <param name="g">The G parameter of the Diffie-Hellman algorithm. This is a public parameter.</param>
68                 /// <param name="x">The X parameter of the Diffie-Hellman algorithm. This is a private parameter. If this parameters is a null reference (<b>Nothing</b> in Visual Basic), a secret value of the default size will be generated.</param>
69                 /// <exception cref="ArgumentNullException"><paramref name="p"/> or <paramref name="g"/> is a null reference (<b>Nothing</b> in Visual Basic).</exception>
70                 /// <exception cref="CryptographicException"><paramref name="p"/> or <paramref name="g"/> is invalid.</exception>
71                 public DiffieHellmanManaged(byte[] p, byte[] g, byte[] x) {
72                         if (p == null || g == null)
73                                 throw new ArgumentNullException();
74                         if (x == null)
75                                 Initialize(new BigInteger(p), new BigInteger(g), null, 0, true);
76                         else
77                                 Initialize(new BigInteger(p), new BigInteger(g), new BigInteger(x), 0, true);
78                 }
79                 /// <summary>
80                 /// Initializes a new <see cref="DiffieHellmanManaged"/> instance.
81                 /// </summary>
82                 /// <param name="p">The P parameter of the Diffie-Hellman algorithm.</param>
83                 /// <param name="g">The G parameter of the Diffie-Hellman algorithm.</param>
84                 /// <param name="l">The length, in bits, of the private value. If 0 is specified, the default value will be used.</param>
85                 /// <exception cref="ArgumentNullException"><paramref name="p"/> or <paramref name="g"/> is a null reference (<b>Nothing</b> in Visual Basic).</exception>
86                 /// <exception cref="ArgumentException"><paramref name="l"/> is invalid.</exception>
87                 /// <exception cref="CryptographicException"><paramref name="p"/> or <paramref name="g"/> is invalid.</exception>
88                 public DiffieHellmanManaged(byte[] p, byte[] g, int l) {
89                         if (p == null || g == null)
90                                 throw new ArgumentNullException();
91                         if (l < 0)
92                                 throw new ArgumentException();
93                         Initialize(new BigInteger(p), new BigInteger(g), null, l, true);
94                 }
95
96                 // initializes the private variables (throws CryptographicException)
97                 private void Initialize(BigInteger p, BigInteger g, BigInteger x, int secretLen, bool checkInput) {
98                         if (checkInput) {
99                                 if (!p.IsProbablePrime() || g <= 0 || g >= p || (x != null && (x <= 0 || x > p - 2)))
100                                         throw new CryptographicException();
101                         }
102                         // default is to generate a number as large as the prime this
103                         // is usually overkill, but it's the most secure thing we can
104                         // do if the user doesn't specify a desired secret length ...
105                         if (secretLen == 0)
106                                 secretLen = p.BitCount();
107                         m_P = p;
108                         m_G = g;
109                         if (x == null) {
110                                 BigInteger pm1 = m_P - 1;
111                                 for(m_X = BigInteger.GenerateRandom(secretLen); m_X >= pm1 || m_X == 0; m_X = BigInteger.GenerateRandom(secretLen)) {}
112                         } else {
113                                 m_X = x;
114                         }
115                 }
116                 /// <summary>
117                 /// Creates the key exchange data.
118                 /// </summary>
119                 /// <returns>The key exchange data to be sent to the intended recipient.</returns>
120                 public override byte[] CreateKeyExchange() {
121                         BigInteger y = m_G.ModPow(m_X, m_P);
122                         byte[] ret = y.GetBytes();
123                         y.Clear();
124                         return ret;
125                 }
126                 /// <summary>
127                 /// Extracts secret information from the key exchange data.
128                 /// </summary>
129                 /// <param name="keyEx">The key exchange data within which the shared key is hidden.</param>
130                 /// <returns>The shared key derived from the key exchange data.</returns>
131                 public override byte[] DecryptKeyExchange(byte[] keyEx) {
132                         BigInteger pvr = new BigInteger(keyEx);
133                         BigInteger z = pvr.ModPow(m_X, m_P);
134                         byte[] ret = z.GetBytes();
135                         z.Clear();
136                         return ret;
137                 }
138                 /// <summary>
139                 /// Gets the name of the key exchange algorithm.
140                 /// </summary>
141                 /// <value>The name of the key exchange algorithm.</value>
142                 public override string KeyExchangeAlgorithm {
143                         get {
144                                 return "1.2.840.113549.1.3"; // PKCS#3 OID
145                         }
146                 }
147                 /// <summary>
148                 /// Gets the name of the signature algorithm.
149                 /// </summary>
150                 /// <value>The name of the signature algorithm.</value>
151                 public override string SignatureAlgorithm {
152                         get {
153                                 return null;
154                         }
155                 }
156                 // clear keys
157                 protected override void Dispose(bool disposing) {
158                         if (!m_Disposed) {
159                                 m_P.Clear();
160                                 m_G.Clear();
161                                 m_X.Clear();
162                         }
163                         m_Disposed = true;
164                 }
165                 /// <summary>
166                 /// Exports the <see cref="DHParameters"/>.
167                 /// </summary>
168                 /// <param name="includePrivateParameters"><b>true</b> to include private parameters; otherwise, <b>false</b>.</param>
169                 /// <returns>The parameters for <see cref="DiffieHellman"/>.</returns>
170                 public override DHParameters ExportParameters(bool includePrivateParameters) {
171                         DHParameters ret = new DHParameters();
172                         ret.P = m_P.GetBytes();
173                         ret.G = m_G.GetBytes();
174                         if (includePrivateParameters) {
175                                 ret.X = m_X.GetBytes();
176                         }
177                         return ret;
178                 }
179                 /// <summary>
180                 /// Imports the specified <see cref="DHParameters"/>.
181                 /// </summary>
182                 /// <param name="parameters">The parameters for <see cref="DiffieHellman"/>.</param>
183                 /// <exception cref="CryptographicException"><paramref name="P"/> or <paramref name="G"/> is a null reference (<b>Nothing</b> in Visual Basic) -or- <paramref name="P"/> is not a prime number.</exception>
184                 public override void ImportParameters(DHParameters parameters) {
185                         if (parameters.P == null)
186                                 throw new CryptographicException("Missing P value.");
187                         if (parameters.G == null)
188                                 throw new CryptographicException("Missing G value.");
189
190                         BigInteger p = new BigInteger(parameters.P), g = new BigInteger(parameters.G), x = null;
191                         if (parameters.X != null) {
192                                 x = new BigInteger(parameters.X);
193                         }
194                         Initialize(p, g, x, 0, true);
195                 }
196                 ~DiffieHellmanManaged() {
197                         Dispose(false);
198                 }
199
200                 //TODO: implement DH key generation methods
201                 private void GenerateKey(int bitlen, DHKeyGeneration keygen, out BigInteger p, out BigInteger g) {
202                         if (keygen == DHKeyGeneration.Static) {
203                                 if (bitlen == 768)
204                                         p = new BigInteger(m_OAKLEY768);
205                                 else if (bitlen == 1024)
206                                         p = new BigInteger(m_OAKLEY1024);
207                                 else if (bitlen == 1536)
208                                         p = new BigInteger(m_OAKLEY1536);
209                                 else
210                                         throw new ArgumentException("Invalid bit size.");
211                                 g = new BigInteger(22); // all OAKLEY keys use 22 as generator
212                         //} else if (keygen == DHKeyGeneration.SophieGermain) {
213                         //      throw new NotSupportedException(); //TODO
214                         //} else if (keygen == DHKeyGeneration.DSA) {
215                                 // 1. Let j = (p - 1)/q.
216                                 // 2. Set h = any integer, where 1 < h < p - 1
217                                 // 3. Set g = h^j mod p
218                                 // 4. If g = 1 go to step 2
219                         //      BigInteger j = (p - 1) / q;
220                         } else { // random
221                                 p = BigInteger.GeneratePseudoPrime(bitlen);
222                                 g = new BigInteger(3); // always use 3 as a generator
223                         }
224                 }
225
226                 private BigInteger m_P;
227                 private BigInteger m_G;
228                 private BigInteger m_X;
229                 private bool m_Disposed;
230
231                 private static byte[] m_OAKLEY768 = new byte[] {
232                         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
233                         0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
234                         0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
235                         0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
236                         0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
237                         0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
238                         0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
239                         0xA6, 0x3A, 0x36, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
240                 };
241                 private static byte[] m_OAKLEY1024 = new byte[] {
242                         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
243                         0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
244                         0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
245                         0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
246                         0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
247                         0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
248                         0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
249                         0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
250                         0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
251                         0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
252                         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
253                 };
254                 private static byte[] m_OAKLEY1536 = new byte[] {
255                         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
256                         0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
257                         0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
258                         0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
259                         0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
260                         0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
261                         0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
262                         0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
263                         0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
264                         0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
265                         0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36,
266                         0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
267                         0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56,
268                         0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
269                         0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08,
270                         0xCA, 0x23, 0x73, 0x27, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
271                 };
272         }
273 }