Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
6419 hidnplayr 1
;    dh_gex.inc - Diffie Hellman Group exchange
2
;
3
;    Copyright (C) 2015-2016 Jeffrey Amelynck
4
;
5
;    This program is free software: you can redistribute it and/or modify
6
;    it under the terms of the GNU General Public License as published by
7
;    the Free Software Foundation, either version 3 of the License, or
8
;    (at your option) any later version.
9
;
10
;    This program is distributed in the hope that it will be useful,
11
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
12
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
;    GNU General Public License for more details.
14
;
15
;    You should have received a copy of the GNU General Public License
16
;    along with this program.  If not, see .
17
 
18
; https://www.ietf.org/rfc/rfc4419.txt
19
 
20
; TODO: dont convert mpints to little endian immediately.
21
; Or maybe even better, not at all.
22
 
23
proc dh_gex
24
 
25
;----------------------------------------------
26
; >> Send Diffie-Hellman Group Exchange Request
27
 
28
        DEBUGF  1, "Sending GEX\n"
29
        stdcall ssh_send_packet, [socketnum], ssh_gex_req, ssh_gex_req.length, 0
30
        cmp     eax, -1
31
        je      .socket_err
32
 
33
;---------------------------------------------
34
; << Parse Diffie-Hellman Group Exchange Group
35
 
36
        stdcall ssh_recv_packet, [socketnum], rx_buffer, BUFFERSIZE, 0
37
        cmp     eax, -1
38
        je      .socket_err
39
 
40
        cmp     [rx_buffer+ssh_header.message_code], SSH_MSG_KEX_DH_GEX_GROUP
41
        jne     proto_err
42
        DEBUGF  1, "Received GEX group\n"
43
 
44
        mov     esi, rx_buffer+sizeof.ssh_header
45
        mov     edi, dh_p
46
        DEBUGF  1, "DH modulus (p): "
47
        call    mpint_to_little_endian
48
        stdcall mpint_print, dh_p
49
 
50
        DEBUGF  1, "DH base (g): "
51
        mov     edi, dh_g
52
        call    mpint_to_little_endian
53
        stdcall mpint_print, dh_g
54
 
55
;-------------------------------------------
56
; >> Send Diffie-Hellman Group Exchange Init
57
 
58
; generate a random number x, where 1 < x < (p-1)/2
59
        mov     edi, dh_x+4
60
        mov     [dh_x], DH_PRIVATE_KEY_SIZE/8
61
        mov     ecx, DH_PRIVATE_KEY_SIZE/8/4
62
  @@:
63
        push    ecx
64
        call    MBRandom
65
        pop     ecx
66
        stosd
67
        dec     ecx
68
        jnz     @r
69
 
70
; If the highest bit is set, add a zero byte
71
        shl     eax, 1
72
        jnc     @f
73
        mov     byte[edi], 0
74
        inc     dword[dh_x]
75
  @@:
76
 
77
; Fill remaining bytes with zeros       ; TO BE REMOVED ?
78
if ((MAX_BITS-DH_PRIVATE_KEY_SIZE) > 0)
79
        mov     ecx, (MAX_BITS-DH_PRIVATE_KEY_SIZE)/8/4
80
        xor     eax, eax
81
        rep     stosd
82
end if
83
 
84
        DEBUGF  1, "DH x: "
85
        stdcall mpint_length, dh_x;;;;;;;;;;;;;
86
        stdcall mpint_print, dh_x
87
 
88
; Compute e = g^x mod p
89
        stdcall mpint_modexp, dh_e, dh_g, dh_x, dh_p
90
        stdcall mpint_length, dh_e
91
 
92
        DEBUGF  1, "DH e: "
93
        stdcall mpint_print, dh_e
94
 
95
; Create group exchange init packet
96
        mov     edi, tx_buffer+ssh_header.message_code
97
        mov     al, SSH_MSG_KEX_DH_GEX_INIT
98
        stosb
99
        mov     esi, dh_e
100
        call    mpint_to_big_endian
101
 
102
        DEBUGF  1, "Sending GEX init\n"
103
        mov     ecx, dword[tx_buffer+ssh_header.message_code+1]
104
        bswap   ecx
105
        add     ecx, 5
106
        stdcall ssh_send_packet, [socketnum], tx_buffer+ssh_header.message_code, ecx, 0
107
        cmp     eax, -1
108
        je      .socket_err
109
 
110
;---------------------------------------------
111
; << Parse Diffie-Hellman Group Exchange Reply
112
 
113
        stdcall ssh_recv_packet, [socketnum], rx_buffer, BUFFERSIZE, 0
114
        cmp     eax, -1
115
        je      .socket_err
116
 
117
        cmp     [rx_buffer+ssh_header.message_code], SSH_MSG_KEX_DH_GEX_REPLY
118
        jne     .proto_err
119
 
120
        DEBUGF  1, "Received GEX Reply\n"
121
 
122
;--------------------------------
123
; HASH: string  K_S, the host key
124
        mov     esi, rx_buffer+sizeof.ssh_header
125
        mov     edx, [esi]
126
        bswap   edx
127
        add     edx, 4
128
        lea     ebx, [esi+edx]
129
        push    ebx
130
        call    sha256_update
131
 
132
;--------------------------------------------------------------------------
133
; HASH: uint32  min, minimal size in bits of an acceptable group
134
;       uint32  n, preferred size in bits of the group the server will send
135
;       uint32  max, maximal size in bits of an acceptable group
136
        mov     esi, ssh_gex_req+sizeof.ssh_header-ssh_header.message_code
137
        mov     edx, 12
138
        call    sha256_update
139
 
140
;----------------------------
141
; HASH: mpint   p, safe prime
142
        mov     esi, dh_p
143
        mov     edi, mpint_tmp
144
        call    mpint_to_big_endian
145
        lea     edx, [eax+4]
146
        mov     esi, mpint_tmp
147
        call    sha256_update
148
 
149
;----------------------------------------
150
; HASH: mpint   g, generator for subgroup
151
        mov     esi, dh_g
152
        mov     edi, mpint_tmp
153
        call    mpint_to_big_endian
154
        lea     edx, [eax+4]
155
        mov     esi, mpint_tmp
156
        call    sha256_update
157
 
158
;---------------------------------------------------
159
; HASH: mpint   e, exchange value sent by the client
160
        mov     esi, tx_buffer+sizeof.ssh_header
161
        mov     edx, [esi]
162
        bswap   edx
163
        add     edx, 4
164
        call    sha256_update
165
 
166
;---------------------------------------------------
167
; HASH: mpint   f, exchange value sent by the server
168
        mov     esi, [esp]
169
        mov     edx, [esi]
170
        bswap   edx
171
        add     edx, 4
172
        call    sha256_update
173
        pop     esi
174
 
175
        mov     edi, dh_f
176
        call    mpint_to_little_endian
177
 
178
        DEBUGF  1, "DH f: "
179
        stdcall mpint_print, dh_f
180
 
181
        mov     edi, dh_signature
182
        call    mpint_to_little_endian
183
 
184
        DEBUGF  1, "DH signature: "
185
        stdcall mpint_print, dh_signature
186
 
187
;--------------------------------------
188
; Calculate shared secret K = f^x mod p
189
        stdcall mpint_modexp, rx_buffer, dh_f, dh_x, dh_p
190
        stdcall mpint_length, rx_buffer
191
 
192
        DEBUGF  1, "DH K: "
193
        stdcall mpint_print, rx_buffer
194
 
195
; We always need it in big endian order, so store it as such.
196
        mov     edi, dh_K
197
        mov     esi, rx_buffer
198
        call    mpint_to_big_endian
199
        mov     [dh_K.length], eax
200
 
201
;-----------------------------------
202
; HASH: mpint   K, the shared secret
203
        mov     edx, [dh_K.length]
204
        add     edx, 4
205
        mov     esi, dh_K
206
        call    sha256_update
207
 
208
;-------------------------------
209
; Finalize the exchange hash (H)
210
        mov     edi, dh_H
211
        call    sha256_final
212
 
213
        DEBUGF  1, "Exchange hash H: "
214
        stdcall dump_256bit_hex, dh_H
215
 
216
; TODO: skip this block when re-keying
217
        mov     esi, dh_H
218
        mov     edi, session_id
219
        mov     ecx, 32/4
220
        rep movsd
221
 
222
;---------------
223
; Calculate keys
224
 
225
; TODO: re-use partial hash of K and H
226
 
227
;---------------------------------------------------------------
228
; Initial IV client to server: HASH(K || H || "A" || session_id)
229
 
230
        call    sha256_init
231
        mov     edx, [dh_K.length]
232
        add     edx, 4
233
        mov     esi, dh_K
234
        call    sha256_update
235
        mov     edx, 32
236
        mov     esi, dh_H
237
        call    sha256_update
238
        mov     edx, 1
239
        mov     esi, str_A
240
        call    sha256_update
241
        mov     edx, 32
242
        mov     esi, session_id
243
        call    sha256_update
244
        mov     edi, tx_iv
245
        call    sha256_final
246
 
247
        DEBUGF  1, "Remote IV: "
248
        stdcall dump_256bit_hex, tx_iv
249
 
250
;---------------------------------------------------------------
251
; Initial IV server to client: HASH(K || H || "B" || session_id)
252
 
253
        call    sha256_init
254
        mov     edx, [dh_K.length]
255
        add     edx, 4
256
        mov     esi, dh_K
257
        call    sha256_update
258
        mov     edx, 32
259
        mov     esi, dh_H
260
        call    sha256_update
261
        mov     edx, 1
262
        mov     esi, str_B
263
        call    sha256_update
264
        mov     edx, 32
265
        mov     esi, session_id
266
        call    sha256_update
267
        mov     edi, rx_iv
268
        call    sha256_final
269
 
270
        DEBUGF  1, "Local IV: "
271
        stdcall dump_256bit_hex, rx_iv
272
 
273
;-------------------------------------------------------------------
274
; Encryption key client to server: HASH(K || H || "C" || session_id)
275
 
276
        call    sha256_init
277
        mov     edx, [dh_K.length]
278
        add     edx, 4
279
        mov     esi, dh_K
280
        call    sha256_update
281
        mov     edx, 32
282
        mov     esi, dh_H
283
        call    sha256_update
284
        mov     edx, 1
285
        mov     esi, str_C
286
        call    sha256_update
287
        mov     edx, 32
288
        mov     esi, session_id
289
        call    sha256_update
290
        mov     edi, tx_enc_key
291
        call    sha256_final
292
 
293
        DEBUGF  1, "Remote key: "
294
        stdcall dump_256bit_hex, tx_enc_key
295
 
296
;-------------------------------------------------------------------
297
; Encryption key server to client: HASH(K || H || "D" || session_id)
298
 
299
        call    sha256_init
300
        mov     edx, [dh_K.length]
301
        add     edx, 4
302
        mov     esi, dh_K
303
        call    sha256_update
304
        mov     edx, 32
305
        mov     esi, dh_H
306
        call    sha256_update
307
        mov     edx, 1
308
        mov     esi, str_D
309
        call    sha256_update
310
        mov     edx, 32
311
        mov     esi, session_id
312
        call    sha256_update
313
        mov     edi, rx_enc_key
314
        call    sha256_final
315
 
316
        DEBUGF  1, "Local key: "
317
        stdcall dump_256bit_hex, rx_enc_key
318
 
319
;------------------------------------------------------------------
320
; Integrity key client to server: HASH(K || H || "E" || session_id)
321
 
322
        call    sha256_init
323
        mov     edx, [dh_K.length]
324
        add     edx, 4
325
        mov     esi, dh_K
326
        call    sha256_update
327
        mov     edx, 32
328
        mov     esi, dh_H
329
        call    sha256_update
330
        mov     edx, 1
331
        mov     esi, str_E
332
        call    sha256_update
333
        mov     edx, 32
334
        mov     esi, session_id
335
        call    sha256_update
336
        mov     edi, tx_int_key
337
        call    sha256_final
338
 
339
        DEBUGF  1, "Remote Integrity key: "
340
        stdcall dump_256bit_hex, tx_int_key
341
 
342
;------------------------------------------------------------------
343
; Integrity key server to client: HASH(K || H || "F" || session_id)
344
 
345
        call    sha256_init
346
        mov     edx, [dh_K.length]
347
        add     edx, 4
348
        mov     esi, dh_K
349
        call    sha256_update
350
        mov     edx, 32
351
        mov     esi, dh_H
352
        call    sha256_update
353
        mov     edx, 1
354
        mov     esi, str_F
355
        call    sha256_update
356
        mov     edx, 32
357
        mov     esi, session_id
358
        call    sha256_update
359
        mov     edi, rx_int_key
360
        call    sha256_final
361
 
362
        DEBUGF  1, "Local Integrity key: "
363
        stdcall dump_256bit_hex, rx_int_key
364
 
365
;-------------------------------------
366
; << Parse Diffie-Hellman New Keys MSG
367
 
368
        stdcall ssh_recv_packet, [socketnum], rx_buffer, BUFFERSIZE, 0
369
        cmp     eax, -1
370
        je      .socket_err
371
 
372
        cmp     [rx_buffer+ssh_header.message_code], SSH_MSG_NEWKEYS
373
        jne     .proto_err
374
 
375
        DEBUGF  1, "Received New Keys\n"
376
 
377
;-------------------------------
378
; >> Reply with New Keys message
379
 
380
        stdcall ssh_send_packet, [socketnum], ssh_new_keys, ssh_new_keys.length, 0
381
 
382
        xor     eax, eax
383
        ret
384
 
385
  .socket_err:
386
        DEBUGF  2, "Socket error during key exchange!\n"
387
        mov     eax, 1
388
        ret
389
 
390
  .proto_err:
391
        DEBUGF  2, "Protocol error during key exchange!\n"
392
        mov     eax, 2
393
        ret
394
 
395
endp
396
 
397
proc dump_256bit_hex _ptr
398
        pushad
399
 
400
        mov     esi, [_ptr]
401
        mov     ecx, 8
402
  .next_dword:
403
        lodsd
404
        bswap   eax
405
        DEBUGF  1,'%x',eax
406
        loop    .next_dword
407
        DEBUGF  1,'\n'
408
 
409
        popad
410
        ret
411
endp
412
 
413
iglobal
414
 
415
        str_A   db 'A'
416
        str_B   db 'B'
417
        str_C   db 'C'
418
        str_D   db 'D'
419
        str_E   db 'E'
420
        str_F   db 'F'
421
 
422
endg