11using System ;
22using IntXLib ;
33using System . Text ;
4+ using System . Security . Cryptography ;
45
56namespace ECDH
67{
78 public class EllipticDiffieHellman
89 {
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" ) ) ;
1015
1116 protected readonly EllipticCurve curve ;
1217 public readonly IntX priv ;
13- protected readonly Point generator , pub ;
18+ protected readonly CurvePoint generator , pub ;
1419
1520
16- public EllipticDiffieHellman ( EllipticCurve curve , Point generator , IntX order , byte [ ] priv = null )
21+ public EllipticDiffieHellman ( EllipticCurve curve , CurvePoint generator , IntX order , byte [ ] priv = null )
1722 {
1823 this . curve = curve ;
1924 this . generator = generator ;
@@ -26,15 +31,15 @@ public EllipticDiffieHellman(EllipticCurve curve, Point generator, IntX order, b
2631 {
2732 byte [ ] p1 = new byte [ 5 /*rand.Next(max.Length) + 1*/ ] ;
2833
29- rand . NextBytes ( p1 ) ;
34+ rand . GetBytes ( p1 ) ;
3035
3136 if ( p1 . Length == max . Length ) p1 [ p1 . Length - 1 ] %= max [ max . Length - 1 ] ;
3237 else p1 [ p1 . Length - 1 ] &= 127 ;
3338
34- this . priv = Helper . FromArray ( p1 ) ;
39+ this . priv = DHHelper . FromArray ( p1 ) ;
3540 } while ( this . priv < 2 ) ;
3641 }
37- else this . priv = Helper . FromArray ( priv ) ;
42+ else this . priv = DHHelper . FromArray ( priv ) ;
3843
3944 // Generate public key
4045 pub = curve . Multiply ( generator , this . priv ) ;
@@ -65,180 +70,16 @@ public byte[] GetSharedSecret(byte[] pK)
6570 Array . Copy ( pK , 4 , p1 , 0 , p1 . Length ) ;
6671 Array . Copy ( pK , 4 + p1 . Length , p2 , 0 , p2 . Length ) ;
6772
68- Point remotePublic = new Point ( Helper . FromArray ( p1 ) , Helper . FromArray ( p2 ) ) ;
73+ CurvePoint remotePublic = new CurvePoint ( DHHelper . FromArray ( p1 ) , DHHelper . FromArray ( p2 ) ) ;
6974
7075 byte [ ] secret = curve . Multiply ( remotePublic , priv ) . X . ToArray ( ) ; // Use the x-coordinate as the shared secret
7176
7277 // 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 ) ;
23879 }
23980 }
24081
241- public static class Helper
82+ public static class DHHelper
24283 {
24384 public static byte [ ] ToArray ( this IntX v )
24485 {
0 commit comments