assemblytasmdosbox16-bit

Turbo Assembler 16 BIT Encryption Binary File


I am trying to encrypt binary file. But program does not encrypt anything and it gets errors when writing file on disk. So I dont get encrypted file on disk and program stucks with infinite loop printing unknown symbols. Can you help me out and fix code, please.

.286
.model small
.stack 100h
.DATA

  bufferSize EQU 255
  keyword db bufferSize DUP (0)
  fileContent db bufferSize DUP (0)
  fileNameIn db "INPUT.DOC", 0
  fileNameOut db "OUTPUT.DOC", 0
  fileNameDec db "DECRYPTED.DOC", 0
  bytesCountReadWrite dw 0
  inputms db "Please enter keyword", 0
  emptyinputmsg db "Console input is empty", 0
  cantCreateFileMsg db "Can't create file", 0
  cantWriteFileMsg db "Can't write file", 0
  cantReadFileMsg db "Can't read file", 0
  cantOpenFileMsg db "Can't open file", 0
  handler_input dw 0
  handler_output dw 0
  handler_decrypt dw 0
.CODE
InitSet MACRO
    mov ax, @data   ; Load the segment address of the data segment into AX
    mov ds, ax      ; Set the data segment register (DS) to the value in AX
    mov es, ax      ; Set the extra segment register (ES) to the value in AX
;    xor ax, ax      ; Clear the value in AX by performing an XOR operation with itself
ENDM

GetStrLen MACRO string, strlen
    LOCAL count_bytes, end_count
    pusha
    push si             ; Save SI register on the stack
    mov si, OFFSET string ; SI = offset of the string
    ; Calculate the number of bytes to write
    mov cx, 0              ; Initialize byte count to 0
    count_bytes:
        cmp byte ptr [si], 0  ; Check if end of string
        je end_count          ; If end of string, jump to end_count
        add cx, 1             ; Increment byte count by 1
        add si, 1             ; Move to the next byte
        jmp count_bytes       ; Jump back to count_bytes to process the next character
    end_count:
        mov strlen, cx   ; Store the byte count in the memory location pointed by strlen
        pop si                    ; Restore SI register from the stack
        popa
ENDM
PrintString MACRO string
  LOCAL strlen
  .data
  strlen dw 0
  .code
  GetStrLen string, strlen
  pusha
  mov dx, offset string         ; Load the offset of the string to print into DX
  mov cx, strlen                ; Load the length of the string into CX      
  mov ah, 40h                   ; Set AH to 40h for writing to file or device
  mov bx, 1                     ; Set BX to 1 for standard output handle
  int 21h                       ; Call MS-DOS interrupt 21h to write the string
  popa
ENDM


ReadFileGetReadMsgLen MACRO filename, bytesRead, s, handler_input
  LOCAL readcontent, rt, closeFile, exit_readingfile 
  pusha
  ; check opened file
  mov ax, [handler_input]
  test ax, ax
  jnz readcontent
  ; getting filename
  lea bx, filename
  inc bx
  mov al, [bx]
  xor ah, ah
  add bx, ax
  inc bx
  xor al, al
  mov [bx], al
  ; open file
  lea dx, filename
  add dx, 2
  mov ah, 3dh
  xor al, al
  int 21h
  ; ax - filehandler or error num
  jnc readcontent ; check open error
  PrintString cantOpenFileMsg
  jmp exit_readingfile
readcontent:
  mov [handler_input], ax
  mov bx,ax ; read file
  mov ah, 3fh
  mov cx, bufferSize ; count
  lea dx, s
  int 21h
  jnc rt ; - open,write,read
  PrintString cantReadFileMsg
  jmp exit_readingfile
rt: ; if we read less than buffersize we can close file
  cmp ax, bufferSize
  jne closeFile
closeFile: 
  mov bytesRead, ax
  xor ax, ax
  mov ah, 3eh ; closing file handle
  int 21h
  mov [handler_input], ax
exit_readingfile:
  popa
ENDM



WriteFileGetWriteMsgLen MACRO keyword, filename, bytesWrote, str_chunk, handler_output
LOCAL writecontent, encodeContent, rtwrt, closeOutFile
  pusha
  push si
  ; Check opened file
  mov ax, [handler_output]
  test ax,ax
  jnz writecontent
  ; Getting filename
  lea bx, filename
  inc bx
  mov al, [bx]
  xor ah,ah
  add bx, ax
  inc bx
  xor al,al
  mov [bx], al
  ; Create File
  lea dx, filename
  add dx, 2
  mov ah, 3Ch
  xor cx, cx
  int 21h
  jnc writecontent 
  PrintString cantCreateFileMsg
  jmp closeOutFile
writecontent:
  mov [handler_output], ax
  lea si, str_chunk
  ;mov cx, word ptr [str_chunk]
  
  encrypt keyword, str_chunk
  mov bx, [handler_output] ; Write file
  mov ah, 40h
  ;mov cx, [str_chunk] 
  GetStrLen str_chunk, cx
  lea dx, str_chunk
  int 21h
  jnc rtwrt
  PrintString cantWriteFileMsg
  jmp closeOutFile
rtwrt:
  cmp ax, bufferSize
  jne closeOutFile
closeOutFile: 
  mov bytesWrote, ax
  xor ax, ax
  mov ah, 3eh ; Close file
  mov bx, [handler_output]
  int 21h
  xor ax, ax
  mov [handler_output], ax
  popa
ENDM


findX0 MACRO keyword, key0
    LOCAL search_loop, strlen
    .data
    strlen dw 0
    .code
    pusha
    GetStrLen keyword, strlen
    mov al, 0            ; Initialize AL register to 0
    mov bl, 0            ; Initialize BL register to 0
    mov cx, strlen   ; Load the length of the keyword into CX
    mov bx, offset keyword  ; Load the offset of the keyword into BX
    search_loop:
        mov al, [bx]     ; Move the byte at memory location pointed by BX into AL
        add key0, ax     ; Add the value of AX to key0
        rol key0, 8     ; Rotate the bits of key0 to the left by 8 positions
        inc bx           ; Increment BX to point to the next character in the keyword
        loop search_loop ; Decrement CX and repeat the loop until CX becomes 0
    popa
ENDM

encrypt MACRO keyword, message
    LOCAL encrypt_loop, X0, Xi, strlen, encryptedMessage, A, B, M   ; Define local labels for the loop and Xi variable
    .data
    encryptedMessage db bufferSize DUP (0)
    strlen dw 0
    Xi dw ?                  ; Define a word-sized variable Xi
    X0 dw 0
    A EQU 12
    B EQU 25
    M EQU 56
    .code
    findX0 keyword, X0
    GetStrLen message, strlen
    pusha
    push si                  ; Save SI register on the stack
    push di                  ; Save DI register on the stack
    mov ax, X0               ; Move the value of X0 into AX
    mov Xi, ax               ; Move the value of AX into Xi variable
    mov cx, strlen
    mov si, offset message   ; Load the offset of the message into SI
    mov di, offset encryptedMessage  ; Load the offset of the encrypted message into DI
    encrypt_loop:
        mov ax, [si]         ; Move the word at memory location pointed by SI into AX
        xor ax, Xi           ; XOR the word with Xi
        mov [di], byte ptr ax  ; Move the result byte by byte into the encrypted message
        mov ax, Xi           ; Move the value of Xi into AX
        mov bl, A         ; Move the value of Akey into BL
        mul bl               ; Multiply AX by BL
        xor bx, bx           ; Clear BX register
        mov bl, B         ; Move the value of Bkey into BL
        add ax, bx           ; Add BX to AX
        xor bx, bx           ; Clear BX register
        mov bl, M         ; Move the value of Mkey into BL
        div bl               ; Divide AX by BL
        xor bx, bx           ; Clear BX register
        mov byte ptr Xi, ah  ; Move the remainder into Xi
        xor ax, ax           ; Clear AX register
        inc si               ; Increment SI to point to the next word in the message
        inc di               ; Increment DI to point to the next byte in the encrypted message
        loop encrypt_loop    ; Decrement CX and repeat the loop until CX becomes 0
    xor ax, ax
    mov al, encryptedMessage ; Swap messages to return encrypted message
    mov message, al          ; Being stored into origin
    pop di                   ; Restore DI register from the stack
    pop si                   ; Restore SI register from the stack
    popa
ENDM
ReadString MACRO str
LOCAL ReadStringLoop, EndReadString, RetryInput, EndInputLabel
RetryInput:
    mov cx, bufferSize ;max input length for string limited to 255 due 
    mov dx, offset str ;place string itself
    push cx     ; save registers
    push si
    push cx     ; save digit count again
    mov  si,dx      ; point to input buffer
    dec  cx     ; save room for null byte 
ReadStringLoop: 
    mov  ah, 1       ; function: keyboard input
    int  21h        ; DOS returns char in AL
    cmp  al, 0Dh     ; end of line?
    je   EndReadString     ; yes: exit
    mov  [si], al        ; no: store the character
    inc  si     ; increment buffer pointer
    loop ReadStringLoop     ; loop until CX=0
EndReadString: 
    mov  byte ptr [si], 0        ; end with a null byte
    pop  ax     ; original digit count
    sub  ax, cx      ; AX = size of input string
    dec  ax     
    pop  si     ; restore registers
    pop  cx
  ; Check if zero length str
  xor ch, ch
  mov cl, [str+1]
  test cl, cl
  jnz EndInputLabel
  PrintString emptyinputmsg 
  jmp RetryInput
EndInputLabel:
ENDM

ReadingFile PROC
  ReadFileGetReadMsgLen fileNameIn, bytesCountReadWrite, fileContent, handler_input
  RET
ENDP
WritingFile PROC
  WriteFileGetWriteMsgLen keyword, fileNameOut, bytesCountReadWrite, fileContent, handler_output
  RET
ENDP

start:
  InitSet
  PrintString inputms 
  ReadString keyword
  encryptFileLoop:
    CALL ReadingFile
    CALL WritingFile 
    cmp bytesCountReadWrite, bufferSize 
    je encryptFileLoop
  mov ah, 4Ch ; Exit program
  int 21h
end start

I was trying to just read file but it stuck at infinite loop without writing anything back.


Solution

  • How program works:

    a) reads from console to buffer keyword

    b) try to open input.doc, but there is no such file in folder. After ah = 3dh, ax = 2, file not found

    c) writes to output.doc from fileContent buffer, which contains only zeros.


    1. First problem occurs in ReadFileGetReadMsgLen MACRO. bx contains filename offset, but after that there is inc bx. So file name will be (I)NPUT.DOC. This code just puts 0 inside messages. So only part of text will appear on screen, because 0 marks end of string. Can't creat and Can't wri. Same code is in WriteFileGetWriteMsgLen MACRO.

       lea bx, filename    ; 0202h
       inc bx          ; 0203h
       mov al, [bx]        ; al = 4eh = 'N'
       xor ah, ah      ; ah = 0
       add bx, ax      ; bx = 0203h + 004eh = 0251h
       inc bx          ; bx = 0252h    
       xor al,al       ; al = 0
       mov [bx], al        ; [0251] = 0
      
    2. Program can't open INPUT.DOC, because there is no file. Program should use service 5bh at the begining of ReadFileGetReadMsgLen MACRO to create file or open existing file.

    3. Service 3dh works fine now because file was created with 5bh

    4. dx contains (IN)PUT.DOC. No such file exists.

      lea dx, filename    ; dx = 0202h
      add dx, 2       ; dx = 0204h
      mov ah, 3dh
      xor al, al
      int 21h
      
    5. Service 3fh reads 0 bytes because there is no data in file input.doc. Maybe idea was to read from console to keyword buffer and save this to file input.doc. I added proc which does that Keyword2InputFile.

    6. And then read from INPUT.DOC to fileContent buffer. Well, program could just copy keyword to fileContent.

    7. WriteFileGetWriteMsgLen MACRO. Same problems as above.

    8. Encrypt MACRO, mov al, encryptedMessage, mov message, al, it's just insertion of one byte 4b, I think code should return offset to encryptedMessage in dx, because we use dx service 40h after encyption.

    9. Inside GetStrLen str_chunk, cx, cx = 6 but popa restores old value. So only 2 bytes will be saved to OUTPUT.DOC. I used di here to store str_chunk length.

    Code:

    .286
    .model small
    .stack 100h
    
    .DATA
      bufferSize EQU 255
      keyword db bufferSize DUP (0)
      fileContent db bufferSize DUP (0)
      fileNameIn db "INPUT.DOC", 0
      fileNameOut db "OUTPUT.DOC", 0
      fileNameDec db "DECRYPTED.DOC", 0
      bytesCountReadWrite dw 0
      
      inputms db "Please enter keyword: ", 0
      emptyinputmsg db "Console input is empty", 0
      cantCreateFileMsg db "Can't create file", 0
      cantWriteFileMsg db "Can't write file", 0
      cantReadFileMsg db "Can't read file", 0
      cantOpenFileMsg db "Can't open file", 0
      handler_input dw 0
      handler_output dw 0
      handler_decrypt dw 0
      
    .CODE
    InitSet MACRO
        mov ax, @data   ; Load the segment address of the data segment into AX
        mov ds, ax      ; Set the data segment register (DS) to the value in AX
        mov es, ax      ; Set the extra segment register (ES) to the value in AX
    ;    xor ax, ax      ; Clear the value in AX by performing an XOR operation with itself
    ENDM
    
    GetStrLen MACRO string, strlen
        LOCAL count_bytes, end_count
    ;    pusha
        push si             ; Save SI register on the stack
        mov si, OFFSET string ; SI = offset of the string
        ; Calculate the number of bytes to write
        mov cx, 0              ; Initialize byte count to 0
        count_bytes:
            cmp byte ptr [si], 0  ; Check if end of string
            je end_count          ; If end of string, jump to end_count
            add cx, 1             ; Increment byte count by 1
            add si, 1             ; Move to the next byte
            jmp count_bytes       ; Jump back to count_bytes to process the next character
        end_count:
            mov strlen, cx   ; Store the byte count in the memory location pointed by strlen
            pop si                    ; Restore SI register from the stack
    ;        popa
    ENDM
    
    PrintString MACRO string
      LOCAL strlen
      .data
      strlen dw 0
      .code
      GetStrLen string, strlen
      pusha
      mov dx, offset string         ; Load the offset of the string to print into DX
      mov cx, strlen                ; Load the length of the string into CX      
      mov ah, 40h                   ; Set AH to 40h for writing to file or device
      mov bx, 1                     ; Set BX to 1 for standard output handle
      int 21h                       ; Call MS-DOS interrupt 21h to write the string
      popa
    ENDM
    
    ReadFileGetReadMsgLen MACRO filename, bytesRead, s, handler_input
      LOCAL readcontent, rt, closeFile, exit_readingfile 
      
      ;fileNameIn, bytesCountReadWrite, fileContent, handler_input
      
      pusha
      ; check opened file
      mov ax, [handler_input]
      test ax, ax
      jnz readcontent
      
      mov ah, 5bh                   ; create file
      lea dx, offset filename
      mov cx,2
      int 21h
      
      cmp ax,50h                    ; file exists?
      jne save_file_handle          ; new file created
      jmp file_exists
      
      save_file_handle:
        mov [handler_input], ax
      
        mov bx,ax
        mov ah, 3eh ; closing file handle
       int 21h
       
       file_exists: 
      ; getting filename
    ;  lea bx, filename             ; INPUT.DOC
    ;  inc bx                       ; NPUT.DOC
    ;  mov al, [bx]
    ;  xor ah, ah
    ;  add bx, ax
    ;  inc bx
    ;  xor al, al
    ;  mov [bx], al
      
      ; open file
      lea dx, filename
    ;  add dx, 2
      mov ah, 3dh
      xor al, al
      int 21h
      ; ax - filehandler or error num
      jnc readcontent ; check open error
      PrintString cantOpenFileMsg
      jmp exit_readingfile
      
    readcontent:
      mov [handler_input], ax
      mov bx, ax ; read file
      mov ah, 3fh
      mov cx, bufferSize ; count
      lea dx, s             ; read to fileContent
      int 21h
      jnc closeFile     ; data saved in input.doc, close file
    
      PrintString cantReadFileMsg
      jmp exit_readingfile
      
    closeFile: 
      mov bytesRead, ax
      mov bx,[handler_input]
      xor ax, ax
      mov ah, 3eh ; closing file handle
      int 21h
    ;  mov [handler_input], ax
    exit_readingfile:
      popa
    ENDM
    
    WriteFileGetWriteMsgLen MACRO keyword, filename, bytesWrote, str_chunk, handler_output
        LOCAL writecontent, encodeContent, rtwrt, closeOutFile
        
        ;keyword, fileNameOut, bytesCountReadWrite, fileContent, handler_output
    
      pusha
      ; check opened file
      mov ax, [handler_output]
      test ax, ax
      jnz writecontent
      
      mov ah, 5bh                   ; create file
      lea dx, offset filename
      mov cx, 2
      int 21h
      
      cmp ax,50h                    ; file exists?
      jne save_file_handle          ; new file created
      jmp file_exists
      
      save_file_handle:
        mov [handler_output], ax
      
        mov bx, ax
        mov ah, 3eh ; closing file handle
       int 21h
       
       file_exists: 
      ; getting filename
    ;  lea bx, filename             ; OUTPUT.DOC
    ;  inc bx                       ; UTPUT.DOC
    ;  mov al, [bx]
    ;  xor ah, ah
    ;  add bx, ax
    ;  inc bx
    ;  xor al, al
    ;  mov [bx], al
      
      ; open file
      lea dx, filename
    ;  add dx, 2
      mov ah, 3ch
      mov cx, 2
      int 21h
    
        jnc writecontent 
        PrintString cantCreateFileMsg
        jmp exit_writingfile
        
    writecontent:
        mov [handler_output],ax
        lea si, str_chunk           ;filecontent buffer
        ;mov cx, word ptr [str_chunk]
      
        encrypt keyword, str_chunk
        mov bx, [handler_output] ; Write file
        mov ah, 40h
        ;mov cx, [str_chunk] 
        GetStrLen str_chunk, di
        mov cx, di
        ;lea dx, str_chunk
        int 21h
        jnc rtwrt
        PrintString cantWriteFileMsg
        jmp closeOutFile
        
        rtwrt:
            cmp ax, bufferSize
            jne closeOutFile
            
    closeOutFile: 
        mov bytesWrote, ax
        xor ax, ax
        mov ah, 3eh ; Close file
        mov bx, ax
        int 21h
        xor ax, ax
        mov [handler_output], ax
        
        exit_writingfile:
        popa
    ENDM
    
    findX0 MACRO keyword, key0
        LOCAL search_loop, strlen
        .data
        strlen dw 0
        .code
        pusha
        GetStrLen keyword, strlen
        mov al, 0            ; Initialize AL register to 0
        mov bl, 0            ; Initialize BL register to 0
        mov cx, strlen   ; Load the length of the keyword into CX
        mov bx, offset keyword  ; Load the offset of the keyword into BX
        search_loop:
            mov al, [bx]     ; Move the byte at memory location pointed by BX into AL
            add key0, ax     ; Add the value of AX to key0
            rol key0, 8     ; Rotate the bits of key0 to the left by 8 positions
            inc bx           ; Increment BX to point to the next character in the keyword
            loop search_loop ; Decrement CX and repeat the loop until CX becomes 0
        popa
    ENDM
    
    encrypt MACRO keyword, message          ;1
        LOCAL encrypt_loop, X0, Xi, strlen, encryptedMessage, A, B, M   ; Define local labels for the loop and Xi variable
        .data
        
        ;keyword, str_chunk
        
        encryptedMessage db bufferSize DUP (0)
        strlen dw 0
        Xi dw ?                  ; Define a word-sized variable Xi
        X0 dw 0
        A EQU 12
        B EQU 25
        M EQU 56
        .code
        findX0 keyword, X0
        GetStrLen message, strlen
    ;    pusha
    ;    push si                  ; Save SI register on the stack
    ;    push di                  ; Save DI register on the stack
        mov ax, X0               ; Move the value of X0 into AX
        mov Xi, ax               ; Move the value of AX into Xi variable
        mov cx, strlen
        mov si, offset message   ; Load the offset of the message into SI
        mov di, offset encryptedMessage  ; Load the offset of the encrypted message into DI
        encrypt_loop:
            mov ax, [si]         ; Move the word at memory location pointed by SI into AX
            xor ax, Xi           ; XOR the word with Xi
            mov [di], al            ; or ax ah ??  byte ptr ax  ; Move the result byte by byte into the encrypted message
            mov ax, Xi           ; Move the value of Xi into AX
            mov bl, A         ; Move the value of Akey into BL
            mul bl               ; Multiply AX by BL
            xor bx, bx           ; Clear BX register
            mov bl, B         ; Move the value of Bkey into BL
            add ax, bx           ; Add BX to AX
            xor bx, bx           ; Clear BX register
            mov bl, M         ; Move the value of Mkey into BL
            div bl               ; Divide AX by BL
            xor bx, bx           ; Clear BX register
            mov byte ptr Xi, ah  ; Move the remainder into Xi
            xor ax, ax           ; Clear AX register
            inc si               ; Increment SI to point to the next word in the message
            inc di               ; Increment DI to point to the next byte in the encrypted message
            loop encrypt_loop    ; Decrement CX and repeat the loop until CX becomes 0
        xor ax, ax
        mov dx, offset encryptedMessage ; Swap messages to return encrypted message
    ;    mov msg_off, dx          ; Being stored into origin
    ;    pop di                   ; Restore DI register from the stack
     ;   pop si                   ; Restore SI register from the stack
    ;    popa
    ENDM
    
    ReadString MACRO str
    LOCAL ReadStringLoop, EndReadString, RetryInput, EndInputLabel
    
    RetryInput:
        mov cx, bufferSize          ;max input length for string limited to 255 due 
        mov dx, offset str          ;place string itself
        push cx                     ; save registers
        push si
        push cx                         ; save digit count again
        mov  si,dx                     ; point to input buffer
        dec  cx                     ; save room for null byte 
        
    ReadStringLoop: 
        mov  ah, 1                  ; function: keyboard input
        int  21h                        ; DOS returns char in AL
        cmp  al, 0Dh                    ; end of line?
        je   EndReadString          ; yes: exit
        mov  [si], al                   ; no: store the character
        inc  si                     ; increment buffer pointer
        loop ReadStringLoop             ; loop until CX=0
        
    EndReadString: 
        mov  byte ptr [si], 0        ; end with a null byte
        pop  ax                       ; original digit count
        sub  ax, cx                   ; AX = size of input string
        dec  ax     
        pop  si                   ; restore registers
        pop  cx
                                      ; Check if zero length str
        xor ch, ch                    ; First element of keyword is 0dh 
        mov cl, [str+1]
        test cl, cl
        jnz EndInputLabel
        PrintString emptyinputmsg 
        jmp RetryInput
        
        EndInputLabel:
    ENDM
    
    ReadingFile PROC
      ReadFileGetReadMsgLen fileNameIn, bytesCountReadWrite, fileContent, handler_input
      RET
    ReadingFile ENDP
    
    WritingFile PROC
      WriteFileGetWriteMsgLen keyword, fileNameOut, bytesCountReadWrite, fileContent, handler_output
      RET
    WritingFile ENDP
    
    start:
      InitSet                                   ; ok
      PrintString inputms                       ; ok
      ReadString keyword                        ; ok
      
      call Keyword2InputFile
      
      encryptFileLoop:
        CALL ReadingFile
        CALL WritingFile 
        cmp bytesCountReadWrite, bufferSize 
        je encryptFileLoop
      mov ah, 4Ch ; Exit program
      int 21h
      
    Keyword2InputFile proc  
        pusha
        
        mov ah, 5bh                     ; create file
        lea dx, offset fileNameIn       ; INPUT.DOC
        mov cx, 2                       ; attrib rw
        int 21h
      
        cmp ax,50h                      ; file exists?
        jne new_file_created            ; new file created
        jmp open_input_file ; file already exits
      
        new_file_created:
            mov [handler_input], ax     ; save handle
            jmp copy_keyword_2_input_doc
            
       open_input_file:     
            mov ah, 3dh                 ; open file
            mov al, 2                   ; attrib rw     
            lea dx, fileNameIn
            int 21h
           mov [handler_input], ax     
       
       copy_keyword_2_input_doc:
            mov bx, ax 
            mov ah, 40h
            mov cx, bufferSize
            lea dx, keyword
            int 21h
    
        mov bx, [handler_input]
        mov ah, 3eh                     ; close file
        int 21h
    
        xor ax,ax
        mov [handler_input], ax
        popa
        ret
    Keyword2InputFile endp  
    end start