2 // DiffieHellmanManaged.cs: Implements the Diffie-Hellman key agreement algorithm
5 // Pieter Philippaerts (Pieter@mentalis.org)
7 // (C) 2003 The Mentalis.org Team (http://www.mentalis.org/)
10 // - PKCS#3 [http://www.rsasecurity.com/rsalabs/pkcs/pkcs-3/]
14 using System.Security.Cryptography;
17 namespace Mono.Security.Cryptography {
19 /// Implements the Diffie-Hellman algorithm.
21 public sealed class DiffieHellmanManaged : DiffieHellman {
23 /// Initializes a new <see cref="DiffieHellmanManaged"/> instance.
25 /// <remarks>The default length of the shared secret is 1024 bits.</remarks>
26 public DiffieHellmanManaged() : this(1024, 160, DHKeyGeneration.Static) {}
28 /// Initializes a new <see cref="DiffieHellmanManaged"/> instance.
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();
39 GenerateKey(bitlen, keygen, out p, out g);
40 Initialize(p, g, null, l, false);
43 /// Initializes a new <see cref="DiffieHellmanManaged"/> instance.
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();
54 Initialize(new BigInteger(p), new BigInteger(g), null, 0, true);
56 Initialize(new BigInteger(p), new BigInteger(g), new BigInteger(x), 0, true);
59 /// Initializes a new <see cref="DiffieHellmanManaged"/> instance.
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();
71 throw new ArgumentException();
72 Initialize(new BigInteger(p), new BigInteger(g), null, l, true);
75 // initializes the private variables (throws CryptographicException)
76 private void Initialize(BigInteger p, BigInteger g, BigInteger x, int secretLen, bool checkInput) {
78 if (!p.isProbablePrime() || g <= 0 || g >= p || (x != null && (x <= 0 || x > p - 2)))
79 throw new CryptographicException();
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 ...
85 secretLen = p.bitCount();
89 BigInteger pm1 = m_P - 1;
90 for(m_X = BigInteger.genRandom(secretLen); m_X >= pm1 || m_X == 0; m_X = BigInteger.genRandom(secretLen)) {}
96 /// Creates the key exchange data.
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();
106 /// Extracts secret information from the key exchange data.
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();
118 /// Gets the name of the key exchange algorithm.
120 /// <value>The name of the key exchange algorithm.</value>
121 public override string KeyExchangeAlgorithm {
123 return "1.2.840.113549.1.3"; // PKCS#3 OID
127 /// Gets the name of the signature algorithm.
129 /// <value>The name of the signature algorithm.</value>
130 public override string SignatureAlgorithm {
136 protected override void Dispose(bool disposing) {
145 /// Exports the <see cref="DHParameters"/>.
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();
159 /// Imports the specified <see cref="DHParameters"/>.
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.");
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);
173 Initialize(p, g, x, 0, true);
175 ~DiffieHellmanManaged() {
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) {
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);
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;
200 p = BigInteger.genPseudoPrime(bitlen);
201 g = new BigInteger(3); // always use 3 as a generator
205 private BigInteger m_P;
206 private BigInteger m_G;
207 private BigInteger m_X;
208 private bool m_Disposed;
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
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
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