;TMG Keygenme #2  -  160Bit RSA * 2001 Goatass
;---------------------------------------------

.386 
.model flat,stdcall 

option casemap:none 

WinMain proto :DWORD,:DWORD,:DWORD,:DWORD 

      include \masm32\include\windows.inc
      include \masm32\include\user32.inc
      include \masm32\include\kernel32.inc
      include \masm32\include\gdi32.inc
      include \masm32\include\masm32.inc

      includelib \masm32\lib\user32.lib
      includelib \masm32\lib\kernel32.lib
      includelib \masm32\lib\gdi32.lib
      includelib \masm32\lib\masm32.lib

GHND 		=	GMEM_MOVEABLE OR GMEM_ZEROINIT
MINCHARS	=	5
MAXCHARS	=	028h

.data 
hWnd2 dd 0
ClassName db "movingCls",0 
DlgName db "MyKeygen",0 
AppName db "TMG Keygenme #2 160bit RSA | Goatass",0 
szIcon  db "KeyIcon",0

nameerr db "Username must be between 5 and 40 characters long",0
companyerr db "Company must be between 5 and 40 characters long",0
rsaerr db "RSA function returned an error",0

align 4
;first 2 bytes are 160bit/16  (BIGNUM FORMAT)
RSA_n	db	00Ah,00h,0D2h,0E9h,0BFh,09Bh,03Dh,025h,08Eh,047h,09Dh,08Ch,0C2h,03Ch,07Ah,033h,0E1h,0F8h,0EBh,0B3h,0ADh,0B1h,0,0

align 4
;first 2 bytes are 160bit/16  (BIGNUM FORMAT)
RSA_d	db	00Ah,00h,0C6h,054h,06Eh,00Ch,011h,0ACh,0CEh,025h,043h,0DDh,011h,050h,0C4h,0CEh,07Ah,005h,0A4h,0C8h,0FAh,03Dh,0,0

align 4

nlen dd 0
clen dd 0

.data? 
hInstance HINSTANCE ? 
CommandLine LPSTR ? 
szName db 60 dup(?)
szCompany db 60 dup(?)
szKey db 60 dup(?)
szTemp db 60 dup(?)
szBuffer db 60 dup(?)

.const 
IDC_KEY equ 103
IDC_NAME equ 101
IDC_COMPANY equ 102
IDGEN equ 1

.code 
start: 
 
  invoke GetModuleHandle, NULL 
  mov hInstance,eax 
  invoke GetCommandLine
  mov CommandLine,eax 
  invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT 
  invoke ExitProcess,eax 

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD 
  LOCAL wc:WNDCLASSEX 
  LOCAL msg:MSG 
  LOCAL hDlg:HWND 

  mov wc.cbSize,SIZEOF WNDCLASSEX 
  mov wc.style, CS_HREDRAW or CS_VREDRAW 
  mov wc.lpfnWndProc, OFFSET WndProc 
  mov wc.cbClsExtra,NULL 
  mov wc.cbWndExtra,DLGWINDOWEXTRA 
  push hInst 
  pop wc.hInstance 
  mov wc.hbrBackground,COLOR_BTNFACE+1 
  mov wc.lpszMenuName,NULL
  mov wc.lpszClassName,OFFSET ClassName 
  invoke LoadIcon,NULL, OFFSET szIcon          ;IDI_APPLICATION 
  mov wc.hIcon,eax 
  mov wc.hIconSm,eax
  invoke LoadCursor,NULL,IDC_ARROW 
  mov wc.hCursor,eax 
  invoke RegisterClassEx, addr wc 
  invoke CreateDialogParam,hInstance,ADDR DlgName,NULL,NULL,NULL 
  mov hDlg,eax 
  invoke ShowWindow, hDlg,SW_SHOWNORMAL 
  invoke UpdateWindow, hDlg 
  invoke GetDlgItem,hDlg,IDC_NAME
  invoke SetFocus,eax 
  .WHILE TRUE 
    invoke GetMessage, ADDR msg,NULL,0,0 
  .BREAK .IF (!eax) 
    invoke IsDialogMessage, hDlg, ADDR msg 
  .IF eax ==FALSE 
    invoke TranslateMessage, ADDR msg 
    invoke DispatchMessage, ADDR msg 
  .ENDIF 
  .ENDW 
  mov eax,msg.wParam 
  ret 

WinMain endp 

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM 
  mov eax, hWnd
  mov hWnd2, eax
  .IF uMsg==WM_DESTROY 
     invoke PostQuitMessage,NULL 

  .ELSEIF uMsg==WM_COMMAND
         mov eax,wParam        
         mov edx,wParam 
         shr edx,16 
        .IF dx==BN_CLICKED 
        .IF ax==IDGEN

	  call Generate  ;generates key
      
    .ENDIF
    .ENDIF
    .ELSE 
          invoke DefWindowProc,hWnd,uMsg,wParam,lParam 
          ret 
    .ENDIF 
  xor eax,eax 
   
  ret 

WndProc endp 

;------------------------------------------------------------------------------
;###################### MANIPULATE NAME AND COMPANY ###########################
;------------------------------------------------------------------------------
;Code ripped out of the Keygenme

Mangle PROC
   mov     edi, offset szBuffer
   mov     word ptr [edi],0Ah
   add     edi, 2
   xor     eax, eax
   push    5
   pop     ecx
   rep stosd
   dec     eax
   mov     esi, offset szName
   mov     edi, offset szBuffer
   mov     word ptr [edi],0Ah
   add     edi, 2
   mov     ecx, nlen
   xor     edx, edx
 
loc_4012AA:                             ; CODE XREF: sub_401187+159j
   lodsb
   xor     ah, al
   imul    eax, 89177313h
   and     eax, 55AA55AAh
   imul    eax, 12299381h
   xor     eax, 0AA55AA11h
   imul    eax, 61h
   xor     ah, al
   or      eax, 10030118h
   imul    eax, 988279h
   rcl     eax, cl
   xor     [edi+edx], eax
   add     edx, 3
   and     edx, 0Fh
   inc     edx
   dec     ecx
   jg      short loc_4012AA
   mov     esi, offset szCompany
   mov     edi, offset szBuffer
   mov     word ptr [edi],0Ah
   add     edi, 2
   mov     ecx, clen
   xor     edx, edx
 
loc_4012F1:                             ; CODE XREF: sub_401187+1A0j
   lodsb
   sub     ah, al
   imul    eax, 89157313h
   and     eax, 55AA55AAh
   imul    eax, 12299387h
   or      eax, 0AA55AA11h
   imul    eax, 61h
   xor     eax, 10010114h
   imul    eax, 7918279h
   xor     ah, al
   rcr     eax, cl
   xor     [edi+edx], eax
   add     edx, 3
   and     edx, 0Fh
   inc     edx
   dec     ecx
   jg      short loc_4012F1
   sub     eax, [edi+8]
   imul    eax, 34814815h
   add     [edi+10h], eax
   shr     eax, 0Bh
   and     eax, 3
   mov     [edi], al
   ret
Mangle ENDP

;------------------------------------------------------------------------------
;############################ GENERATE KEY ####################################
;------------------------------------------------------------------------------


Generate PROC
	invoke GetDlgItemText, hWnd2, IDC_NAME, ADDR szName, MAXCHARS+1
	cmp	eax, MINCHARS
	jl	@@nameerr
	mov	nlen, eax	
	invoke GetDlgItemText, hWnd2, IDC_COMPANY, ADDR szCompany, MAXCHARS+1
	cmp	eax, MINCHARS
	jl	@@companyerr
	mov	clen, eax	

    call Mangle           ;mangles name and company to create our M

; Keygenme uses the scheme: Serial = (Mangle(Name+Company)) ^ d mod n
    push 028h               ;length of message to enc/dec
    push offset szTemp      ;return buffer
    push offset szBuffer    ;string to encrypt/decrypt
    push offset RSA_n       ;n
    push offset RSA_d       ;decryption exponent
    call RSA_PRIVATE_ENCRYPT

; Convert result to ASCII
    cmp eax, -1
    jz @@rsaerr
	lea	edi, szKey
	lea	esi, szTemp
	movzx	ecx, word ptr[esi]
	add	ecx, ecx
	inc	esi
	inc	esi
@@l1:	xor	eax, eax
	lodsb	
	mov	bl, al
	and	ebx, 15
	shr	eax, 4
	mov	al, cctab[eax]
	mov	ah, cctab[ebx]
	stosw
	dec	ecx
	jg	@@l1
	and	byte ptr[edi], 0

;------------------------------------------------------------------------------
	invoke SetDlgItemText, hWnd2, IDC_KEY, ADDR szKey

fzk:
	xor	eax, eax
	RET

@@nameerr:
	invoke SetDlgItemText, hWnd2, IDC_NAME, ADDR nameerr
	jmp	fzk

@@companyerr:
	invoke SetDlgItemText, hWnd2, IDC_COMPANY, ADDR companyerr
	jmp	fzk

@@rsaerr:
	invoke SetDlgItemText, hWnd2, IDC_KEY, ADDR rsaerr
	jmp	fzk

cctab	db	"0123456789ABCDEF"

Generate ENDP

;---------------------------------------------------------------------------
;####################### RSA CODE ##########################################
;################## THANKS tHE EGOiSTE #####################################
;*--------------------------------------------------------------------------*
; Function:    int RSA_PRIVATE_ENCRYPT (P1,P2,P3,P4,P5);
;
; Description: Calculates C=M ^ D MOD N
;
; Parameters:  P1) pointer to private exponent D
;              P2) pointer to modulus N
;              P3) pointer to message M   (source buffer/plaintext)
;              P4) pointer to ciphertext  (destination buffer)
;              P5) length of M [Bytes]
; Returns:      0 = OK
;              -1 = ERROR
; Notes:       D and N have to be in Bignum format used by the
;              math routines. I.e. that the first WORD represents
;              the SIZE of the following number in BITS divided by 16 !
;              M will be converted to Bignum format automatically.
;              Ciphertext is in Bignum format with corrected byte order. 
;              Base for Big numbers is 16
;*--------------------------------------------------------------------------*
RSA_PRIVATE_ENCRYPT proc lpD:DWORD, lpN:DWORD, lpM:DWORD, lpC:DWORD, ml:DWORD

LOCAL	mem_D:DWORD, mem_N:DWORD, mem_M:DWORD, mem_Temp:DWORD,\
	mem_Temp2:DWORD, mem_Result:DWORD, Bitpos:DWORD, cnt:DWORD,\
	expbits:DWORD, isodd:DWORD

;USES	ebx,esi,edi

	and	isodd, 0
	mov	esi, lpD
	cmp	word ptr[esi], 0
	jle	@@err
	mov	eax, ml
	shr	eax, 1
	jnc	@@ncs
	inc	eax
	inc	isodd
@@ncs:	mov	esi, lpN
	cmp	word ptr[esi], 0
	jle	@@err
	test	ax, ax
	jz	@@err
;	cmp	[esi], ax
;	jl	@@err				; checks if M > N   very weak if it is

	invoke VirtualAlloc, 0, 4160, MEM_COMMIT, PAGE_READWRITE
	test	eax, eax
	jz	@@err
	mov	mem_D, eax
	add	eax, 520
	mov	mem_N, eax
	add	eax, 520
	mov	mem_M, eax
	mov	edi, eax
	add	eax, 520
	mov	mem_Temp, eax
	add	eax, 1040
	mov	mem_Temp2, eax
	add	eax, 520
	mov	mem_Result, eax
	and	word ptr[eax], 0		; virtualalloc set this 0 already, but i'm running in paranoia mode :P

;	mov	ebx, ml            ;convert M to BIGNUM format
;	shr	ebx, 1             ;not needed in our case it's already in that format
;	adc	ebx, 0
;	mov	[edi], bx
;	inc	edi
;	inc	edi
;	mov	ecx, ebx
;	mov	esi, lpM
;	cld
;	rep	movsw

	mov	edi, mem_M
	mov	esi, lpM
	movzx	ecx, word ptr[esi]
	inc	ecx
	rep	movsw

	mov	edi, mem_N
	mov	esi, lpN
	movzx	ecx, word ptr[esi]
	inc	ecx
	rep	movsw

	mov	edi, mem_D
	mov	esi, lpD
	movzx	ecx, word ptr[esi]
	mov	eax, ecx
	shl	eax, 4
	mov	expbits, eax
	inc	ecx
	rep	movsw

	push 0
	push mem_N
	call	REV_BIGNUM;, mem_N, 0		; byte order reversing needed in order to get math. correct results
	push isodd
	push mem_M
	call	REV_BIGNUM;, mem_M, isodd	; ''
	push 0
	push mem_D
	call	REV_BIGNUM;, mem_D, 0		; ''

	mov	esi, mem_M
	mov	edi, mem_Temp
	movzx	ecx, word ptr[esi]
	inc	ecx
	rep	movsw

	xor	edi, edi
	mov	Bitpos, edi			; initialize bitcounter
	jmp	@@l2
@@l1:	
;
;	mem_Temp = mem_Temp ^ 2 
;
	push mem_Temp
	push mem_Temp
	call	BiG_SQR;, mem_Temp, mem_Temp
;
;	mem_Temp = mem_Temp MOD mem_N */* mem_Temp2 used as Dummy to hold quotient (which is of no use here)
;
	push mem_Temp
	push mem_Temp2
	push mem_N
	push mem_Temp
	call	BiG_DIV;, mem_Temp, mem_N, mem_Temp2, mem_Temp

	dec	cnt
	jg	@@l1
	mov	esi, mem_Temp
	mov	edi, mem_Result
	cmp	word ptr[edi], 0
	jnz	@@nff
	movzx	ecx, word ptr[esi]
	inc	ecx
	cld
	rep	movsw
	jmp	@@tal
@@nff:
	push mem_Result
	push mem_Temp
	push mem_Result
	call	BiG_MUL;, mem_Result, mem_Temp, mem_Result
	push mem_Result
	push mem_Temp2
	push mem_N
	push mem_Result
	call	BiG_DIV;, mem_Result, mem_N, mem_Temp2, mem_Result

@@tal:	mov	edi, Bitpos
@@l2:	inc	Bitpos
	mov	eax, expbits
	cmp	Bitpos, eax 
	jge	@@exit

	mov	eax, Bitpos 
	xor	edx, edx
	push	8
	pop	ebx
	div	ebx
	mov	esi, mem_D
	mov	bl, [esi+eax+2]
	push	1
	pop	eax
	mov	ecx, edx
	shl	eax, cl
	test	bl, al				; bit set ?
	jz	@@l2				; no -> test next
	mov	eax, Bitpos 
	sub	eax, edi			; calc. delta
	mov	cnt, eax			; init square counter
	jmp	@@l1	
@@exit:
;
; Test if final mul. is needed - thus when D is odd
;
	mov	esi, mem_D
	test	byte ptr[esi+2], 1
	jz	@@done
	push mem_Result
	push mem_M
	push mem_Result
	call	BiG_MUL;, mem_Result, mem_M, mem_Result
	push mem_Result
	push mem_Temp2
	push mem_N
	push mem_Result
	call	BiG_DIV;, mem_Result, mem_N, mem_Temp2, mem_Result
@@done:	
	push 0
	push mem_Result
	call	REV_BIGNUM;, mem_Result, 0
	mov	esi, mem_Result
	mov	edi, lpC
	movzx	ecx, word ptr[esi]
	inc	ecx
	rep	movsw	
	invoke	VirtualFree, mem_D, 4160, MEM_DECOMMIT
	RET
@@err:	mov	esi, lpC
	and	word ptr[esi], 0	
	or 	eax, -1
	RET
RSA_PRIVATE_ENCRYPT endp


;*---------------------------------------------------*
; Function:    void REV_BIGNUM(P1,P2);
;
; Description: Reverses byteorder of a Bignum
;
; Parameters:  P1) pointer to Bignumber
;              P2) Message Odd/Even signal 
; Notes:       P2 added for this keygen only!
; Returns:     Always 0
;              Stack Restored on Exit
;*---------------------------------------------------*
REV_BIGNUM proc
	push	ebp		
	mov	ebp, esp
	sub	esp, 520
	mov	edi, esp
	push	ebx
	push	edi
	push	esi
	mov	esi, [ebp+8]
	movzx	ecx, word ptr[esi]
	cmp	ecx, 256
	jg	@@out
	inc	esi
	inc	esi
	push	esi
	lea	edx, [ecx*2]
	cld
	rep	movsw
	lea	esi, [edi-1]
	pop	edi
	mov	ecx, edx
	sub	esi, [ebp+12]
	sub	ecx, [ebp+12]
	std
@@l1:	lodsb
	mov	[edi], al
	inc	edi
	dec	ecx
	jg	@@l1
	cld	
@@out:	pop	esi
	pop	edi
	pop	ebx
	mov	esp, ebp
	pop	ebp
	xor	eax, eax
	RET	8
REV_BIGNUM endp


;*-------------------------------------------------------*
; Function:    int BiG_DIV(P1,P2,P3,P4);
; Description: 
; Parameters:  P1) pointer to Bignum to divide
;              P2) pointer to Divisor
;              P3) pointer to Quotient  (dest. Buffer 1)
;              P4) pointer to Remainder (dest. Buffer 2)
; Returns:   0 = OK 
;           -1 = Error (e.g. Div. by Zero)
;              Stack Restored on Exit
;*-------------------------------------------------------*
BiG_DIV proc
	push	ebp		
	mov	ebp, esp
	sub	esp, 2600			; free some space on stack..badly needed for local copies :)
	mov	eax, esp
	push	ebx
	push	edi
	push	esi
	mov	ebx, eax			; save start address

	mov	esi, [ebp+8]	
	mov	edi, [ebp+12]	
	mov	ax, [esi]	
	mov	dx, [edi]	
	test	dx, dx
	jz	@@dbzerr			; division by zero error

	push	edi		
	mov	edi, ebx	
	xor	ecx, ecx
	mov	cx, ax		
	shr	cx, 1
	adc	cx, 0
	cld
	rep	movsd			
	movsw			
	mov	cx, ax
	add	cx, cx
	lea	edi, [ebx+ecx+2]
	and	word ptr [edi], 0

	pop	esi		
	lea	edi, [ebx+1030]
	xor	ecx, ecx
	mov	cx, dx		
	shr	cx, 1
	adc	cx, 0
	cld
	rep	movsd			
	movsw			
	mov	cx, dx
	add	cx, cx
	lea	edi, [ebx+ecx+1032]
	and	word ptr [edi], 0

	push	ebp		
	mov	ebp, ebx		

	xor	eax, eax
	xor	ecx, ecx
	mov	ax, [ebp]	
	test	ax, ax
	jz	@@goon
	add	eax, eax
;
; Remove leading zeros		
;
	mov	esi, eax
@@l1:	cmp	word ptr [ebp+esi], 0
	jnz	@@inzo1
	sub	esi, 2		
	jnz	@@l1
@@inzo1:
	shr	esi, 1		
	mov	eax, esi		
	mov	word ptr [ebp], ax
@@goon:
	mov	ax, [ebp+1030]	
	test	ax, ax
	jz	@@isdo
	add	eax, eax
				
	mov	esi, eax
@@l2:	cmp	word ptr [ebp+esi+1030], 0
	jnz	@@inzo2
	sub	esi, 2		
	jnz	@@l2	
@@inzo2:
	shr	esi, 1		
	mov	eax, esi		
	mov	[ebp+1030], ax	

@@isdo:	test	ax, ax
	jnz	@@w4
	pop	ebp
	jmp	@@dbzerr
@@w4:	cmp	word ptr [ebp], 0
	jnz	@@w5
	pop	ebp
	jmp	@@zerdiv

@@w5:	xor	ecx, ecx
	mov	cx, [ebp]
	cmp	cx, [ebp+1030]	
	jc	@@dab
	jnz	@@dchs		
	mov	eax, ecx		
	add	eax, eax
	lea	esi, [ebp]
	lea	edi, [ebp+1030]
	add	esi, eax		
	add	edi, eax		
	std
	repz	cmpsw
	cld
	jc	@@dab		
@@dchs:
	mov	ax, [ebp+1030]
	shr	ax, 1
	adc	ax, 0
	cmp	ax, 1		
	jz	@@shdiv		
;
; Start division
;
	xor	eax, eax
	mov	ax, [ebp+1030]
	shr	ax, 1
	adc	ax, 0
	mov	esi, eax
	shl	esi, 2
	sub	esi, 2		
	cmp	esi, 10		
	jb	@@dm1a		

	mov	ebx, [ebp+esi+1030]	
	mov	eax, [ebp+esi+1026]
	mov	edx, [ebp+esi+1022]

	xor	ecx, ecx
@@l3:	cmp	ebx, 80000000h			; check for 2^31 overflow
	jae	@@dm2
	inc	cx
	clc
	rcl	edx, 1
	rcl	eax, 1
	rcl	ebx, 1		
	jmp	@@l3

@@dm1a:	mov	ebx, [ebp+esi+1030]	
	mov	eax, [ebp+esi+1026]

	xor	ecx, ecx			; init cnt
@@l4:	cmp	ebx, 80000000h	
	jae	@@dm2		
	inc	cx
	clc
	rcl	eax, 1
	rcl	ebx, 1		
	jmp	@@l4

@@dm2:	mov	[ebp+2578], cx			; save exp.
	mov	[ebp+2570], ebx	
	mov	[ebp+2574], eax	

@@dm3:	inc	word ptr [ebp]	
	inc	word ptr [ebp]
	xor	eax, eax
	mov	ax, [ebp]
	shr	ax, 1
	adc	ax, 0
	mov	esi, eax
	shl	esi, 2
	sub	esi, 2
	mov	dword ptr [ebp+esi], 0

	xor	eax, eax
	mov	ax, [ebp+1030]
	shr	ax, 1
	adc	ax, 0
	mov	esi, eax
	shl	esi, 2
	sub	esi, 2		

	xor	ecx, ecx
	mov	cx, [ebp]
	shr	cx, 1
	adc	cx, 0
	mov	edi, ecx
	shl	edi, 2
	sub	edi, 2		
	push	edi
	sub	edi, esi	
	inc	edi		
	mov	ecx, edi
	shr	ecx, 2		
	pop	esi		
	sub	edi, 3		
	push	edi		
;
; Division loop
;
@@sdm:	cmp	esi, 14
	jb	@@dib
	push	edi
	mov	edx, [ebp+esi]	
	mov	eax, [ebp+esi-4]
	mov	ebx, [ebp+esi-8]
	mov	edi, [ebp+esi-12]
	push	ecx
	mov	cx, [ebp+2578]
@@l5:	test	cx, cx
	jz	@@w6
	rcl	edi, 1
	rcl	ebx, 1
	rcl	eax, 1
	rcl	edx, 1
	dec	cx
	jmp	@@l5
@@w6:	pop	ecx
	pop	edi
	jmp	@@cqd

@@dib:	mov	edx, [ebp+esi]	
	mov	eax, [ebp+esi-4]
	mov	ebx, [ebp+esi-8]
	push	ecx
	mov	cx, [ebp+2578]
@@l6:	cmp	cx, 0
	jz	@@w7
	rcl	ebx, 1
	rcl	eax, 1
	rcl	edx, 1
	dec	cx
	jmp	@@l6
@@w7:	pop	ecx

@@cqd:	mov	[ebp+2582], eax
	mov	[ebp+2586], ebx
	mov	ebx, [ebp+2570]
	cmp	ebx, edx
	jz	@@bm1

	div	ebx			; eax => mv

	mov	[ebp+2566], eax
	test	eax, eax
	jnz	@@w8
	jmp	@@dml
@@bm1:	xor	eax, eax
	dec	eax
	mov	[ebp+2566], eax
	mov	edx, [ebp+2582]
	add	edx, [ebp+2570]
	jc	@@sdo
@@w8:	mov	ebx, edx
	mul	dword ptr [ebp+2574]
	cmp	edx, ebx
	jb	@@sdo
	ja	@@w9	
	cmp	eax, [ebp+2586] 
	jbe	@@sdo

@@w9:	dec	dword ptr [ebp+2566]	; correct mv
	add	ebx, [ebp+2570]
	jc	@@sdo	
	sub	eax, [ebp+2574]
	sbb	edx, 0
	cmp	edx, ebx
	jb	@@sdo
	ja	@@w9
	cmp	eax, [ebp+2586]
	ja	@@w9

@@sdo:	push	ecx		
	push	esi		
	push	edi		
	mov	cx,  [ebp+1030]	
	shr	cx, 1
	adc	cx, 0
	mov	ebx, [ebp+2566]	
; MulSub()
	push	2
	pop	esi
	xor	edx, edx			; rem. dummy
@@msl:	push	edx
	mov	eax, ebx		
	mul	dword ptr [ebp+esi+1030]
	sub	[ebp+edi], eax
	adc	edx, 0		
	pop	eax
	sub	[ebp+edi], eax
	adc	edx, 0		
	add	edi, 4
	add	esi, 4
	loop	@@msl
	sub	[ebp+edi], edx
	jnc	@@dnc		
; Correct on cs
	pop	edi
	push	edi
	xor	ecx, ecx
	mov	cx, [ebp+1030]	
	shr	cx, 1
	adc	cx, 0
	push	2
	pop	esi
	clc
@@sdw:	mov	eax, [ebp+esi+1030]	
	adc	[ebp+edi], eax	
	add	edi, 4
	add	esi, 4
	loop	@@sdw		
	jnc	@@sdx
	inc	dword ptr [ebp+edi]
@@sdx:	dec	dword ptr [ebp+2566]

@@dnc:	pop	edi		
	pop	esi
	pop	ecx
@@dml:	mov	eax, [ebp+2566]	
	mov	[ebp+edi+1546], eax	
	sub	edi, 4
	sub	esi, 4
	dec	ecx		
	jz	@@sdz
	jmp	@@sdm

@@sdz:	pop	edi		
	add	edi, 2		
	xor	eax, eax
@@l7:	cmp	ax, [ebp+edi+1546]	
	jnz	@@sdr
	sub	edi, 2
	jnz	@@l7
@@sdr:	mov	edx, edi
	shr	edx, 1		
	mov	[ebp+1546], dx	
; Check for rem. len
	xor	eax, eax
	mov	ax, [ebp+1030]
	mov	ecx, eax
	add	ax, ax
	mov	edi, eax
	xor	ebx, ebx
	add	edi, 2
@@sdu:	sub	edi, 2
	cmp	[ebp+edi], bx
	loopz	@@sdu
	jz	@@sdv		
	inc	cx		
@@sdv:	mov	[ebp], cx	

; Save results
@@savd:	mov	esi, ebp
	mov	ebx, ebp
	pop	ebp
	push	esi
	add	esi, 1546
	mov	edi, [ebp+16]	
	xor	ecx, ecx
	mov	cx, [esi]
	shr	cx, 1
	adc	cx, 0
	cld
	test	cx, cx
	jz	@@quot0
	rep	movsd
@@quot0:
	movsw
	pop	esi
@@drs:
	mov	edi, [ebp+20]
	xor	ecx, ecx
	mov	cx, [esi]
	shr	cx, 1
	adc	cx, 0
	cld
	test	ecx, ecx
	jz	@@rem0
	rep	movsd
@@rem0:
	movsw
	xor	eax, eax
@@rfdiv:
	pop	esi
	pop	edi
	pop	ebx
	mov	esp, ebp
	pop	ebp
	RET	16				; restore stack / get rid of parameters

@@zerdiv:
	xor	eax, eax
	mov	edi, [ebp+20]	
	mov	esi, [ebp+16]	
	mov	[edi], ax	
	mov	[esi], ax	
	jmp	@@rfdiv

@@dbzerr:
	or	eax, -1				; return error
	jmp	@@rfdiv	

@@dab:	mov	esi, ebp
	mov	ebx, ebp
	pop	ebp
	mov	edi, [ebp+16]
	mov	word ptr [edi], 0
	jmp	@@drs	

@@shdiv:
	xor	ecx, ecx
	mov	cx, [ebp]
	shr	cx, 1
	adc	cx, 0
	mov	edi, ecx
	shl	edi, 2
	sub	edi, 2
	xor	edx, edx
	mov	ebx, [ebp+1032]
@@dsh1:	mov	eax, [ebp+edi]
	div	ebx
	mov	[ebp+edi+1546], eax
	sub	edi, 4
	loop	@@dsh1
@@dsh2:	xor	ecx, ecx
	mov	cx, [ebp]
	mov	esi, ecx
	add	esi, esi
@@l8:	mov	bx, [ebp+esi+1546]
	test	bx, bx
	jnz	@@dsh3
	dec	esi
	dec	esi
	dec	ecx
	test	cx, cx
	jnz	@@l8
@@dsh3:	mov	[ebp+1546], cx
	mov	[ebp+2], edx
	mov	word ptr [ebp], 2
	cmp	word ptr [ebp+4], 0
	jnz	@@dst
	mov	word ptr [ebp], 1
	cmp	word ptr [ebp+2], 0
	jnz	@@dst
	and	word ptr [ebp], 0
@@dst:	jmp	@@savd
BiG_DIV  endp

;*-------------------------------------------------------*
; Function:    void BiG_SQR(P1,P2);
;
; Description: Calculates Square of a given X => X*X 
;              (Faster than BiG_MUL !)
; Parameters:  P1) pointer to Bignum to square
;              P2) pointer to (result)buffer
; Returns:     Always 0
;              Stack Restored on Exit
;*-------------------------------------------------------*
BiG_SQR proc
	push	ebp		
	mov	ebp, esp
	sub	esp, 1560
	mov	eax, esp
	push	ebx
	push	edi
	push	esi
	mov	ebx, eax		

	mov	esi, [ebp+8]		
	mov	dx, [esi]	
	test	dx, dx
	jz	@@pow0

	lea	edi, [ebx]	
	xor	ecx, ecx
	mov	cx, dx		
	cld
	rep	movsw			
	movsw			
	and	word ptr [edi], 0

	push	ebp		
	mov	ebp, ebx		
; Kill leading 0s
	xor	eax, eax
	mov	ax, [ebp]	
	test	ax, ax
	jz	@@goon
	add	eax, eax
	mov	esi, eax			; obase
@@l1:	cmp	word ptr [ebp+esi], 0
	jnz	@@inzo1		
	sub	esi, 2		
	jnz	@@l1		
@@inzo1:
	shr	esi, 1		
	mov	eax, esi		
	mov	[ebp], ax	

@@goon:	test	ax, ax
	jnz	@@mpow2
	pop	ebp
	jmp	@@pow0
@@mpow2:
	xor	ecx, ecx
	mov	cx, [ebp]	
	shr	cx, 1
	adc	cx, 0
	cmp	cx, 1
	jz	@@regpow

	xor	eax, eax
	push	2
	pop	esi
@@lsqrW:
	mov	[ebp+esi+520], eax
	add	esi, 4
	loop	@@lsqrW

	push	2
	pop	esi
	xor	ecx, ecx
	mov	cx, [ebp]	
	shr	cx, 1
	jc	@@lsqrV
	dec	cx		
@@lsqrV:
	push	ecx		

	mov	edi, esi		
	add	edi, 4			
	xor	ecx, ecx
	mov	cx, [ebp]	
	shr	cx, 1			
	adc	cx, 0
	push	esi
	add	esi, 2			
	shr	esi, 2			
	sub	ecx, esi
	pop	esi		
	xor	edx, edx
	mov	ebx, [ebp+esi]	
	add	esi, edi		
@@lsqrU:
	push	ecx		
	mov	ecx, edx		
	mov	eax, ebx			
	mul	dword ptr [ebp+edi]
	add	eax, ecx		
	adc	edx, 0
	add	[ebp+esi+518], eax
	adc	edx, 0		
	add	edi, 4		
	add	esi, 4		
	pop	ecx		
	loop	@@lsqrU

	mov	[ebp+esi+518], edx
	sub	esi, edi		
	add	esi, 4		
	pop	ecx		
	loop	@@lsqrV

	add	esi, edi
	and	dword ptr [ebp+esi+518], 0 
	and	dword ptr [ebp+esi+522], 0 
; tempres = tempres * 2
	push	6				; skip 0 part
	pop	esi
	xor	ecx, ecx
	mov	cx, [ebp]
@@tr2l:
	rcl	dword ptr[ebp+esi+520], 1
	inc	esi				; inc doesn't affest c flag. so better don't change it to add  ,4 ;)
	inc	esi
	inc	esi
	inc	esi
	loop	@@tr2l
; Add squares
	mov	cx, [ebp]
	add	cx, cx
	mov	[ebp+520], cx
	push	2
	pop	esi
	mov	edi, esi
	mov	cx, [ebp]	
	shr	cx, 1			
	adc	cx, 0
	xor	eax, eax
	pushf				; dummy
@@lsqr2:
	mov	eax, [ebp+esi]
	mul	eax		
	popf
	adc	[ebp+edi+520], eax
	adc	[ebp+edi+524], edx
	pushf
	add	esi, 4
	add	edi, 8
	loop	@@lsqr2
	popf				; stack corr. only
	jmp	@@lsqrX

@@regpow:
	mov	eax, [ebp+2]
	mul	eax
	mov	[ebp+522], eax 
	mov	[ebp+526], edx 
	mov	word ptr [ebp+520], 4
@@lsqrX:
	xor	eax, eax
	mov	ax, [ebp+520]
	mov	edi, eax
	add	edi, edi
	cmp	word ptr [ebp+edi+520], 0
	jnz	@@lsqrY
	dec	word ptr [ebp+520]
	jmp	@@lsqrX
@@lsqrY:
	lea	esi, [ebp+520]
	mov	ebx, ebp
	pop	ebp
	mov	edi, [ebp+12]
	xor	ecx, ecx
	mov	cx, [esi]
	shr	cx, 1
	adc	cx, 0
	jz	@@w5
	cld
	rep	movsd
@@w5:	movsw

@@rfsq:						; return from square :P
	pop	esi
	pop	edi
	pop	ebx
	mov	esp, ebp
	pop	ebp
	xor	eax, eax
	RET	8				; restore stack / get rid of parameters
@@pow0:
	mov	esi, [ebp+12]
	and	word ptr [esi],	0		; set bignum 0
	jmp	@@rfsq
BiG_SQR  endp


;*-------------------------------------------------------*
; Function:    void BiG_MUL(P1,P2,P3);
; Description: 
; Parameters:  P1) pointer to Bignum factor 1
;              P2) pointer to Bignum factor 2
;              P2) pointer to (result)buffer
; Returns:     Always 0
;              Stack Restored on Exit
;*-------------------------------------------------------*
BiG_MUL	proc
	push	ebp		
	mov	ebp, esp
	sub	esp, 2200	
	cld
	mov	eax, esp		
	push	edi
	push	esi
	push	ebx
	mov	ebx, eax

	xor	eax, eax
	xor	edx, edx
	mov	esi, [ebp+8]		
	mov	edi, [ebp+12]		
	mov	ax, [esi]
	mov	dx, [edi]

	test	ax, ax
	jz	@@mul0
	test	dx, dx
	jz	@@mul0

	push	edi		
	lea	edi, [ebx+520]	
	xor	ecx, ecx
	mov	cx, ax		
	rep	movsw			
	movsw			
	and	word ptr [edi], 0

	pop	esi		
	lea	edi, [ebx]	
	mov	cx, dx		
	rep	movsw		
	movsw			
	and	word ptr [edi], 0

	push	ebp		
	mov	ebp, ebx		

	xor	eax, eax
	mov	ax, [ebp+520]	
	test	ax, ax
	jz	@@goon
	add	eax, eax
	mov	esi, eax
@@l1:	cmp	word ptr [ebp+esi+520], 0
	jnz	@@inzo1
	sub	esi, 2		
	jnz	@@l1
@@inzo1:
	shr	esi, 1		
	mov	eax, esi		
	mov	520[ebp], ax	
@@goon:
	mov	ax, [ebp]	
	test	ax, ax
	jz	@@iszer
	add	eax, eax
	mov	esi, eax
@@l2:	cmp	word ptr [ebp+esi], 0
	jnz	@@inzo2
	sub	esi, 2		
	jnz	@@l2		
@@inzo2:
	shr	esi, 1		
	mov	eax, esi		
	mov	[ebp], ax	

@@iszer:
	test	ax, ax
	jnz	@@w1
	pop	ebp
	jmp	@@mul0
@@w1:	cmp	word ptr [ebp+520], 0
	jnz	@@w2
	pop	ebp
	jmp	@@mul0
; start
@@w2:	push	2
	pop	esi
	mov	cx, dx		
	shr	cx, 1
	adc	cx, 0
	xor	eax, eax
@@mxx:
	mov	[ebp+esi+1040], eax
	add	esi, 4
	loop	@@mxx
	mov	esi, 2		
	xor	ecx, ecx
	mov	cx, [ebp+520]	
	shr	cx, 1
	adc	cx, 0
; outter loop
@@mxw:	push	ecx		
	mov	edi, 2		
	mov	cx, [ebp]	
	shr	cx, 1
	adc	cx, 0

	xor	edx, edx			; dummy 
	mov	ebx, [ebp+esi+520]	
	add	esi, edi
; inner loop
@@mxy:	push	ecx		
	mov	ecx, edx		
	mov	eax, ebx
	mul	dword ptr [ebp+edi]
	add	eax, ecx		
	adc	edx, 0
	add	[ebp+esi+1038], eax
	adc	edx, 0		
	add	edi, 4		
	add	esi, 4		
	pop	ecx		
	loop	@@mxy

	mov	[ebp+esi+1038], edx
	sub	esi, edi		
	add	esi, 4		
	pop	ecx		
	loop	@@mxw

	add	esi, edi
	sub	esi, 4
@@mxz:
	cmp	word ptr [ebp+esi+1040], 0
	jnz	@@mxv
	sub	esi, 2
	jmp	@@mxz
@@mxv:
	mov	ecx, esi
	shr	ecx, 1
	mov	[ebp+1040], cx
;Save result
	lea	esi, [ebp+1040]
	mov	ebx, ebp
	pop	ebp
	mov	edi, [ebp+16]
	test	cx, cx
	jz	@@w3
	cld
	rep	movsw
@@w3:	movsw

@@rfmul:
	pop	ebx
	pop	esi		
	pop	edi
	mov	esp, ebp
	pop	ebp
	xor	eax,  eax
	RET	12				; restore stack / get rid of parameters
@@mul0:
	mov	esi, [ebp+16]
	and	word ptr [esi], 0		; clear bignum
	jmp	@@rfmul
BiG_MUL  endp

;---------------------------------------------------------------------------------------	
end start