1
1
using System ;
2
2
using IntXLib ;
3
3
using System . Text ;
4
+ using System . Security . Cryptography ;
4
5
5
6
namespace ECDH
6
7
{
7
8
public class EllipticDiffieHellman
8
9
{
9
- protected static readonly Random rand = new Random ( ) ;
10
+ protected static readonly RNGCryptoServiceProvider rand = new RNGCryptoServiceProvider ( ) ;
11
+ public static readonly IntX DEFAULT_PRIME = ( new IntX ( 1 ) << 255 ) - 19 ;
12
+ public static readonly IntX DEFAULT_ORDER = ( new IntX ( 1 ) << 252 ) + IntX . Parse ( "27742317777372353535851937790883648493" ) ;
13
+ public static readonly EllipticCurve DEFAULT_CURVE = new EllipticCurve ( 486662 , 1 , DEFAULT_PRIME , EllipticCurve . CurveType . Montgomery ) ;
14
+ public static readonly CurvePoint DEFAULT_GENERATOR = new CurvePoint ( 9 , IntX . Parse ( "14781619447589544791020593568409986887264606134616475288964881837755586237401" ) ) ;
10
15
11
16
protected readonly EllipticCurve curve ;
12
17
public readonly IntX priv ;
13
- protected readonly Point generator , pub ;
18
+ protected readonly CurvePoint generator , pub ;
14
19
15
20
16
- public EllipticDiffieHellman ( EllipticCurve curve , Point generator , IntX order , byte [ ] priv = null )
21
+ public EllipticDiffieHellman ( EllipticCurve curve , CurvePoint generator , IntX order , byte [ ] priv = null )
17
22
{
18
23
this . curve = curve ;
19
24
this . generator = generator ;
@@ -26,15 +31,15 @@ public EllipticDiffieHellman(EllipticCurve curve, Point generator, IntX order, b
26
31
{
27
32
byte [ ] p1 = new byte [ 5 /*rand.Next(max.Length) + 1*/ ] ;
28
33
29
- rand . NextBytes ( p1 ) ;
34
+ rand . GetBytes ( p1 ) ;
30
35
31
36
if ( p1 . Length == max . Length ) p1 [ p1 . Length - 1 ] %= max [ max . Length - 1 ] ;
32
37
else p1 [ p1 . Length - 1 ] &= 127 ;
33
38
34
- this . priv = Helper . FromArray ( p1 ) ;
39
+ this . priv = DHHelper . FromArray ( p1 ) ;
35
40
} while ( this . priv < 2 ) ;
36
41
}
37
- else this . priv = Helper . FromArray ( priv ) ;
42
+ else this . priv = DHHelper . FromArray ( priv ) ;
38
43
39
44
// Generate public key
40
45
pub = curve . Multiply ( generator , this . priv ) ;
@@ -65,180 +70,16 @@ public byte[] GetSharedSecret(byte[] pK)
65
70
Array . Copy ( pK , 4 , p1 , 0 , p1 . Length ) ;
66
71
Array . Copy ( pK , 4 + p1 . Length , p2 , 0 , p2 . Length ) ;
67
72
68
- Point remotePublic = new Point ( Helper . FromArray ( p1 ) , Helper . FromArray ( p2 ) ) ;
73
+ CurvePoint remotePublic = new CurvePoint ( DHHelper . FromArray ( p1 ) , DHHelper . FromArray ( p2 ) ) ;
69
74
70
75
byte [ ] secret = curve . Multiply ( remotePublic , priv ) . X . ToArray ( ) ; // Use the x-coordinate as the shared secret
71
76
72
77
// PBKDF2-HMAC-SHA1 (Common shared secret generation method)
73
- return PBKDF2 ( HMAC_SHA1 , secret , Encoding . UTF8 . GetBytes ( "P1sN0R4inb0wPl5P1sPls" ) , 1024 , 32 ) ;
74
- }
75
-
76
-
77
- public delegate byte [ ] PRF ( byte [ ] key , byte [ ] salt ) ;
78
- private static byte [ ] PBKDF2 ( PRF function , byte [ ] password , byte [ ] salt , int iterations , int dklen )
79
- {
80
- byte [ ] dk = new byte [ 0 ] ; // Create a placeholder for the derived key
81
- uint iter = 1 ; // Track the iterations
82
- while ( dk . Length < dklen )
83
- {
84
- // F-function
85
- // The F-function (PRF) takes the amount of iterations performed in the opposite endianness format from what C# uses, so we have to swap the endianness
86
- byte [ ] u = function ( password , Concatenate ( salt , WriteToArray ( new byte [ 4 ] , SwapEndian ( iter ) , 0 ) ) ) ;
87
- byte [ ] ures = new byte [ u . Length ] ;
88
- Array . Copy ( u , ures , u . Length ) ;
89
- for ( int i = 1 ; i < iterations ; ++ i )
90
- {
91
- // Iteratively apply the PRF
92
- u = function ( password , u ) ;
93
- for ( int j = 0 ; j < u . Length ; ++ j ) ures [ j ] ^= u [ j ] ;
94
- }
95
-
96
- // Concatenate the result to the dk
97
- dk = Concatenate ( dk , ures ) ;
98
-
99
- ++ iter ;
100
- }
101
-
102
- // Clip all bytes past what we needed (yes, that's really what the standard is)
103
- if ( dk . Length != dklen )
104
- {
105
- var t1 = new byte [ dklen ] ;
106
- Array . Copy ( dk , t1 , Math . Min ( dklen , dk . Length ) ) ;
107
- return t1 ;
108
- }
109
- return dk ;
110
- }
111
- public delegate byte [ ] HashFunction ( byte [ ] message ) ;
112
- private static byte [ ] HMAC ( byte [ ] key , byte [ ] message , HashFunction func , int blockSizeBytes )
113
- {
114
- if ( key . Length > blockSizeBytes ) key = func ( key ) ;
115
- else if ( key . Length < blockSizeBytes )
116
- {
117
- byte [ ] b = new byte [ blockSizeBytes ] ;
118
- Array . Copy ( key , b , key . Length ) ;
119
- key = b ;
120
- }
121
-
122
- byte [ ] o_key_pad = new byte [ blockSizeBytes ] ; // Outer padding
123
- byte [ ] i_key_pad = new byte [ blockSizeBytes ] ; // Inner padding
124
- for ( int i = 0 ; i < blockSizeBytes ; ++ i )
125
- {
126
- // Combine padding with key
127
- o_key_pad [ i ] = ( byte ) ( key [ i ] ^ 0x5c ) ;
128
- i_key_pad [ i ] = ( byte ) ( key [ i ] ^ 0x36 ) ;
129
- }
130
- return func ( Concatenate ( o_key_pad , func ( Concatenate ( message , i_key_pad ) ) ) ) ;
131
- }
132
- private static byte [ ] HMAC_SHA1 ( byte [ ] key , byte [ ] message ) => HMAC ( key , message , SHA1 , 20 ) ;
133
- private static byte [ ] Concatenate ( params byte [ ] [ ] bytes )
134
- {
135
- int alloc = 0 ;
136
- foreach ( byte [ ] b in bytes ) alloc += b . Length ;
137
- byte [ ] result = new byte [ alloc ] ;
138
- alloc = 0 ;
139
- for ( int i = 0 ; i < bytes . Length ; ++ i )
140
- {
141
- Array . Copy ( bytes [ i ] , 0 , result , alloc , bytes [ i ] . Length ) ;
142
- alloc += bytes [ i ] . Length ;
143
- }
144
- return result ;
145
- }
146
- public static byte [ ] SHA1 ( byte [ ] message )
147
- {
148
- // Initialize buffers
149
- uint h0 = 0x67452301 ;
150
- uint h1 = 0xEFCDAB89 ;
151
- uint h2 = 0x98BADCFE ;
152
- uint h3 = 0x10325476 ;
153
- uint h4 = 0xC3D2E1F0 ;
154
-
155
- // Pad message
156
- int ml = message . Length + 1 ;
157
- byte [ ] msg = new byte [ ml + ( ( 960 - ( ml * 8 % 512 ) ) % 512 ) / 8 + 8 ] ;
158
- Array . Copy ( message , msg , message . Length ) ;
159
- msg [ message . Length ] = 0x80 ;
160
- long len = message . Length * 8 ;
161
- for ( int i = 0 ; i < 8 ; ++ i ) msg [ msg . Length - 1 - i ] = ( byte ) ( ( len >> ( i * 8 ) ) & 255 ) ;
162
- //Support.WriteToArray(msg, message.Length * 8, msg.Length - 8);
163
- //for (int i = 0; i <4; ++i) msg[msg.Length - 5 - i] = (byte)(((message.Length*8) >> (i * 8)) & 255);
164
-
165
- int chunks = msg . Length / 64 ;
166
-
167
- // Perform hashing for each 512-bit block
168
- for ( int i = 0 ; i < chunks ; ++ i )
169
- {
170
-
171
- // Split block into words
172
- uint [ ] w = new uint [ 80 ] ;
173
- for ( int j = 0 ; j < 16 ; ++ j )
174
- w [ j ] |= ( uint ) ( ( msg [ i * 64 + j * 4 ] << 24 ) | ( msg [ i * 64 + j * 4 + 1 ] << 16 ) | ( msg [ i * 64 + j * 4 + 2 ] << 8 ) | ( msg [ i * 64 + j * 4 + 3 ] << 0 ) ) ;
175
-
176
- // Expand words
177
- for ( int j = 16 ; j < 80 ; ++ j )
178
- w [ j ] = Rot ( w [ j - 3 ] ^ w [ j - 8 ] ^ w [ j - 14 ] ^ w [ j - 16 ] , 1 ) ;
179
-
180
- // Initialize chunk-hash
181
- uint
182
- a = h0 ,
183
- b = h1 ,
184
- c = h2 ,
185
- d = h3 ,
186
- e = h4 ;
187
-
188
- // Do hash rounds
189
- for ( int t = 0 ; t < 80 ; ++ t )
190
- {
191
- uint tmp = ( ( a << 5 ) | ( a >> ( 27 ) ) ) +
192
- ( // Round-function
193
- t < 20 ? ( b & c ) | ( ( ~ b ) & d ) :
194
- t < 40 ? b ^ c ^ d :
195
- t < 60 ? ( b & c ) | ( b & d ) | ( c & d ) :
196
- /*t<80*/ b ^ c ^ d
197
- ) +
198
- e +
199
- ( // K-function
200
- t < 20 ? 0x5A827999 :
201
- t < 40 ? 0x6ED9EBA1 :
202
- t < 60 ? 0x8F1BBCDC :
203
- /*t<80*/ 0xCA62C1D6
204
- ) +
205
- w [ t ] ;
206
- e = d ;
207
- d = c ;
208
- c = Rot ( b , 30 ) ;
209
- b = a ;
210
- a = tmp ;
211
- }
212
- h0 += a ;
213
- h1 += b ;
214
- h2 += c ;
215
- h3 += d ;
216
- h4 += e ;
217
- }
218
-
219
- return WriteContiguous ( new byte [ 20 ] , 0 , SwapEndian ( h0 ) , SwapEndian ( h1 ) , SwapEndian ( h2 ) , SwapEndian ( h3 ) , SwapEndian ( h4 ) ) ;
220
- }
221
-
222
- private static uint Rot ( uint val , int by ) => ( val << by ) | ( val >> ( 32 - by ) ) ;
223
-
224
- // Swap endianness of a given integer
225
- private static uint SwapEndian ( uint value ) => ( uint ) ( ( ( value >> 24 ) & ( 255 << 0 ) ) | ( ( value >> 8 ) & ( 255 << 8 ) ) | ( ( value << 8 ) & ( 255 << 16 ) ) | ( ( value << 24 ) & ( 255 << 24 ) ) ) ;
226
-
227
- private static byte [ ] WriteToArray ( byte [ ] target , uint data , int offset )
228
- {
229
- for ( int i = 0 ; i < 4 ; ++ i )
230
- target [ i + offset ] = ( byte ) ( ( data >> ( i * 8 ) ) & 255 ) ;
231
- return target ;
232
- }
233
-
234
- private static byte [ ] WriteContiguous ( byte [ ] target , int offset , params uint [ ] data )
235
- {
236
- for ( int i = 0 ; i < data . Length ; ++ i ) WriteToArray ( target , data [ i ] , offset + i * 4 ) ;
237
- return target ;
78
+ return new Rfc2898DeriveBytes ( secret , Encoding . UTF8 . GetBytes ( "P1sN0R4inb0wPl5P1sPls" ) , 1000 ) . GetBytes ( 32 ) ;
238
79
}
239
80
}
240
81
241
- public static class Helper
82
+ public static class DHHelper
242
83
{
243
84
public static byte [ ] ToArray ( this IntX v )
244
85
{
0 commit comments