* FileSystemInfo.cs: corrected COM visibility of UTC properties
[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 using System;
14 using System.Security.Cryptography;
15 using Mono.Math;
16
17 namespace Mono.Security.Cryptography {
18         /// <summary>
19         /// Implements the Diffie-Hellman algorithm.
20         /// </summary>
21         public sealed class DiffieHellmanManaged : DiffieHellman {
22                 /// <summary>
23                 /// Initializes a new <see cref="DiffieHellmanManaged"/> instance.
24                 /// </summary>
25                 /// <remarks>The default length of the shared secret is 1024 bits.</remarks>
26                 public DiffieHellmanManaged() : this(1024, 160, DHKeyGeneration.Static) {}
27                 /// <summary>
28                 /// Initializes a new <see cref="DiffieHellmanManaged"/> instance.
29                 /// </summary>
30                 /// <param name="bitlen">The length, in bits, of the public P parameter.</param>
31                 /// <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>
32                 /// <param name="keygen">One of the <see cref="DHKeyGeneration"/> values.</param>
33                 /// <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>
34                 /// <exception cref="ArgumentException">The specified bit length is invalid.</exception>
35                 public DiffieHellmanManaged(int bitlen, int l, DHKeyGeneration keygen) {
36                         if (bitlen < 256 || l < 0)
37                                 throw new ArgumentException();
38                         BigInteger p, g;
39                         GenerateKey(bitlen, keygen, out p, out g);
40                         Initialize(p, g, null, l, false);
41                 }
42                 /// <summary>
43                 /// Initializes a new <see cref="DiffieHellmanManaged"/> instance.
44                 /// </summary>
45                 /// <param name="p">The P parameter of the Diffie-Hellman algorithm. This is a public parameter.</param>
46                 /// <param name="g">The G parameter of the Diffie-Hellman algorithm. This is a public parameter.</param>
47                 /// <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>
48                 /// <exception cref="ArgumentNullException"><paramref name="p"/> or <paramref name="g"/> is a null reference (<b>Nothing</b> in Visual Basic).</exception>
49                 /// <exception cref="CryptographicException"><paramref name="p"/> or <paramref name="g"/> is invalid.</exception>
50                 public DiffieHellmanManaged(byte[] p, byte[] g, byte[] x) {
51                         if (p == null || g == null)
52                                 throw new ArgumentNullException();
53                         if (x == null)
54                                 Initialize(new BigInteger(p), new BigInteger(g), null, 0, true);
55                         else
56                                 Initialize(new BigInteger(p), new BigInteger(g), new BigInteger(x), 0, true);
57                 }
58                 /// <summary>
59                 /// Initializes a new <see cref="DiffieHellmanManaged"/> instance.
60                 /// </summary>
61                 /// <param name="p">The P parameter of the Diffie-Hellman algorithm.</param>
62                 /// <param name="g">The G parameter of the Diffie-Hellman algorithm.</param>
63                 /// <param name="l">The length, in bits, of the private value. If 0 is specified, the default value will be used.</param>
64                 /// <exception cref="ArgumentNullException"><paramref name="p"/> or <paramref name="g"/> is a null reference (<b>Nothing</b> in Visual Basic).</exception>
65                 /// <exception cref="ArgumentException"><paramref name="l"/> is invalid.</exception>
66                 /// <exception cref="CryptographicException"><paramref name="p"/> or <paramref name="g"/> is invalid.</exception>
67                 public DiffieHellmanManaged(byte[] p, byte[] g, int l) {
68                         if (p == null || g == null)
69                                 throw new ArgumentNullException();
70                         if (l < 0)
71                                 throw new ArgumentException();
72                         Initialize(new BigInteger(p), new BigInteger(g), null, l, true);
73                 }
74
75                 // initializes the private variables (throws CryptographicException)
76                 private void Initialize(BigInteger p, BigInteger g, BigInteger x, int secretLen, bool checkInput) {
77                         if (checkInput) {
78                                 if (!p.isProbablePrime() || g <= 0 || g >= p || (x != null && (x <= 0 || x > p - 2)))
79                                         throw new CryptographicException();
80                         }
81                         // default is to generate a number as large as the prime this
82                         // is usually overkill, but it's the most secure thing we can
83                         // do if the user doesn't specify a desired secret length ...
84                         if (secretLen == 0)
85                                 secretLen = p.bitCount();
86                         m_P = p;
87                         m_G = g;
88                         if (x == null) {
89                                 BigInteger pm1 = m_P - 1;
90                                 for(m_X = BigInteger.genRandom(secretLen); m_X >= pm1 || m_X == 0; m_X = BigInteger.genRandom(secretLen)) {}
91                         } else {
92                                 m_X = x;
93                         }
94                 }
95                 /// <summary>
96                 /// Creates the key exchange data.
97                 /// </summary>
98                 /// <returns>The key exchange data to be sent to the intended recipient.</returns>
99                 public override byte[] CreateKeyExchange() {
100                         BigInteger y = m_G.modPow(m_X, m_P);
101                         byte[] ret = y.getBytes();
102                         y.Clear();
103                         return ret;
104                 }
105                 /// <summary>
106                 /// Extracts secret information from the key exchange data.
107                 /// </summary>
108                 /// <param name="keyEx">The key exchange data within which the shared key is hidden.</param>
109                 /// <returns>The shared key derived from the key exchange data.</returns>
110                 public override byte[] DecryptKeyExchange(byte[] keyEx) {
111                         BigInteger pvr = new BigInteger(keyEx);
112                         BigInteger z = pvr.modPow(m_X, m_P);
113                         byte[] ret = z.getBytes();
114                         z.Clear();
115                         return ret;
116                 }
117                 /// <summary>
118                 /// Gets the name of the key exchange algorithm.
119                 /// </summary>
120                 /// <value>The name of the key exchange algorithm.</value>
121                 public override string KeyExchangeAlgorithm {
122                         get {
123                                 return "1.2.840.113549.1.3"; // PKCS#3 OID
124                         }
125                 }
126                 /// <summary>
127                 /// Gets the name of the signature algorithm.
128                 /// </summary>
129                 /// <value>The name of the signature algorithm.</value>
130                 public override string SignatureAlgorithm {
131                         get {
132                                 return null;
133                         }
134                 }
135                 // clear keys
136                 protected override void Dispose(bool disposing) {
137                         if (!m_Disposed) {
138                                 m_P.Clear();
139                                 m_G.Clear();
140                                 m_X.Clear();
141                         }
142                         m_Disposed = true;
143                 }
144                 /// <summary>
145                 /// Exports the <see cref="DHParameters"/>.
146                 /// </summary>
147                 /// <param name="includePrivateParameters"><b>true</b> to include private parameters; otherwise, <b>false</b>.</param>
148                 /// <returns>The parameters for <see cref="DiffieHellman"/>.</returns>
149                 public override DHParameters ExportParameters(bool includePrivateParameters) {
150                         DHParameters ret = new DHParameters();
151                         ret.P = m_P.getBytes();
152                         ret.G = m_G.getBytes();
153                         if (includePrivateParameters) {
154                                 ret.X = m_X.getBytes();
155                         }
156                         return ret;
157                 }
158                 /// <summary>
159                 /// Imports the specified <see cref="DHParameters"/>.
160                 /// </summary>
161                 /// <param name="parameters">The parameters for <see cref="DiffieHellman"/>.</param>
162                 /// <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>
163                 public override void ImportParameters(DHParameters parameters) {
164                         if (parameters.P == null)
165                                 throw new CryptographicException("Missing P value.");
166                         if (parameters.G == null)
167                                 throw new CryptographicException("Missing G value.");
168
169                         BigInteger p = new BigInteger(parameters.P), g = new BigInteger(parameters.G), x = null;
170                         if (parameters.X != null) {
171                                 x = new BigInteger(parameters.X);
172                         }
173                         Initialize(p, g, x, 0, true);
174                 }
175                 ~DiffieHellmanManaged() {
176                         Dispose(false);
177                 }
178
179                 //TODO: implement DH key generation methods
180                 private void GenerateKey(int bitlen, DHKeyGeneration keygen, out BigInteger p, out BigInteger g) {
181                         if (keygen == DHKeyGeneration.Static) {
182                                 if (bitlen == 768)
183                                         p = new BigInteger(m_OAKLEY768);
184                                 else if (bitlen == 1024)
185                                         p = new BigInteger(m_OAKLEY1024);
186                                 else if (bitlen == 1536)
187                                         p = new BigInteger(m_OAKLEY1536);
188                                 else
189                                         throw new ArgumentException("Invalid bit size.");
190                                 g = new BigInteger(22); // all OAKLEY keys use 22 as generator
191                         //} else if (keygen == DHKeyGeneration.SophieGermain) {
192                         //      throw new NotSupportedException(); //TODO
193                         //} else if (keygen == DHKeyGeneration.DSA) {
194                                 // 1. Let j = (p - 1)/q.
195                                 // 2. Set h = any integer, where 1 < h < p - 1
196                                 // 3. Set g = h^j mod p
197                                 // 4. If g = 1 go to step 2
198                         //      BigInteger j = (p - 1) / q;
199                         } else { // random
200                                 p = BigInteger.genPseudoPrime(bitlen);
201                                 g = new BigInteger(3); // always use 3 as a generator
202                         }
203                 }
204
205                 private BigInteger m_P;
206                 private BigInteger m_G;
207                 private BigInteger m_X;
208                 private bool m_Disposed;
209
210                 private static byte[] m_OAKLEY768 = new byte[] {
211                         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
212                         0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
213                         0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
214                         0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
215                         0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
216                         0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
217                         0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
218                         0xA6, 0x3A, 0x36, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
219                 };
220                 private static byte[] m_OAKLEY1024 = new byte[] {
221                         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
222                         0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
223                         0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
224                         0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
225                         0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
226                         0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
227                         0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
228                         0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
229                         0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
230                         0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
231                         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
232                 };
233                 private static byte[] m_OAKLEY1536 = new byte[] {
234                         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
235                         0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
236                         0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
237                         0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
238                         0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
239                         0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
240                         0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
241                         0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
242                         0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
243                         0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
244                         0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36,
245                         0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
246                         0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56,
247                         0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
248                         0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08,
249                         0xCA, 0x23, 0x73, 0x27, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
250                 };
251         }
252 }