assemblycaesar-ciphermasm32

How can I fix my Caesar Cipher implementation in assembly language to read multi-digit keys?


My code implements the Caesar Cipher, it asks the user the name of the input file which contains the string i want to be encrypted/decrypted, the name of the output file and the key/cipher, my problem is that it is only reading the first number of the key, if i give it a number with two digits as a key then it only reads the first, like 14, 15, it only reads the 1. How can i fix this? Here is the code:

.686
.model flat, stdcall
option casemap:none

include \masm32\include\windows.inc
include \masm32\include\masm32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\kernel32.lib

.data
    ; Strings do menu e prompts
    menuTitle       db "Cifra de Cesar",13,10,0
    option1         db "1. Descriptografar",13,10
    option2         db "2. Criptografar",13,10
    option3         db "3. Criptoanalise",13,10
    option4         db "4. Sair",13,10
    menuPrompt      db "Escolha uma opcao:",0

    filePrompt      db "Digite o nome do arquivo de entrada:",0
    outFilePrompt   db "Digite o nome do arquivo de saida:",0
    keyPrompt       db "Digite a chave (1 a 20):",0
    
    ; Buffers e variáveis auxiliares
    inputFileBuffer  db 10240 dup(0)
    outputFileBuffer db 10240 dup(0)
    outputBuffer    db 10240 dup(0)
    userInputBuffer db 256 dup(0)
    buffer          db 512 dup(0)
    keyBuffer       db 256 dup(0)
    console_count   dd 0
    inputHandle     dd 0
    outputHandle    dd 0
    bytesRead       dd 0
    bytesWritten    dd 0    

.code
start:
    ; Obtém os handles de entrada e saída padrão
    invoke GetStdHandle, STD_INPUT_HANDLE
    mov inputHandle, eax

    invoke GetStdHandle, STD_OUTPUT_HANDLE
    mov outputHandle, eax
    

menuLoop:
    ; Exibe o menu de opções e lê a escolha do usuário
    invoke WriteConsole, outputHandle, addr menuTitle, sizeof menuTitle, addr console_count, NULL
    invoke WriteConsole, outputHandle, addr option1, sizeof option1, addr console_count, NULL
    invoke WriteConsole, outputHandle, addr option2, sizeof option2, addr console_count, NULL
    invoke WriteConsole, outputHandle, addr option3, sizeof option3, addr console_count, NULL
    invoke WriteConsole, outputHandle, addr option4, sizeof option4, addr console_count, NULL
    invoke WriteConsole, outputHandle, addr menuPrompt, sizeof menuPrompt, addr console_count, NULL
    invoke ReadConsole, inputHandle, addr userInputBuffer, sizeof userInputBuffer, addr console_count, NULL

    ; Verifica a opção escolhida e executa a ação correspondente
    mov al, byte ptr [userInputBuffer]
    cmp al, '4'
    je exitProgram

    cmp al, '1'
    je descriptografar
    cmp al, '2'
    je criptografar
    cmp al, '3'
    je criptoanalise

    jmp menuLoop

descriptografar:
    ; Solicita e lê os nomes dos arquivos de entrada, saída e chave
    invoke StdOut, addr filePrompt
    invoke StdIn, addr inputFileBuffer, 10240

    invoke StdOut, addr outFilePrompt
    invoke StdIn, addr outputFileBuffer, 10240

    invoke StdOut, addr keyPrompt
    invoke StdIn, addr keyBuffer, 256

    invoke atodw, addr keyBuffer
    mov ecx, eax

    invoke CreateFile, addr inputFileBuffer, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
    mov edi, eax

    invoke CreateFile, addr outputFileBuffer, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL
    mov ebx, eax

    invoke ReadFile, edi, addr buffer, sizeof buffer, addr bytesRead, NULL
    

    xor ecx, ecx
    mov cl, byte ptr [bytesRead]

    lea edi, [buffer]
    mov esi, edi

    @@loop1:
        mov al, byte ptr [esi]
        sub al, byte ptr [keyBuffer]
        mov byte ptr [edi], al

        inc esi
        inc edi

        loop @@loop1

    ; Atualize o valor de ecx para o número correto de bytes lidos
    mov ecx, [bytesRead]

    invoke WriteFile, ebx, addr buffer, ecx, addr bytesWritten, NULL

    invoke CloseHandle, edi
    invoke CloseHandle, ebx

    jmp menuLoop

criptografar:
    invoke StdOut, addr filePrompt
    invoke StdIn, addr inputFileBuffer, 10240

    invoke StdOut, addr outFilePrompt
    invoke StdIn, addr outputFileBuffer, 10240

    invoke StdOut, addr keyPrompt
    invoke StdIn, addr keyBuffer, 256

    invoke atodw, addr keyBuffer
    mov ecx, eax

    invoke CreateFile, addr inputFileBuffer, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL

    mov edi, eax

    invoke CreateFile, addr outputFileBuffer, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL

    mov ebx, eax

    invoke ReadFile, edi, addr buffer, sizeof buffer, addr bytesRead, NULL

    xor ecx, ecx
    mov cl, byte ptr [bytesRead]

    lea edi, [buffer]
    mov esi, edi

    @@loop2:
        mov al, byte ptr [esi]
        add al, byte ptr [keyBuffer]
        mov byte ptr [edi], al

        inc esi
        inc edi

        loop @@loop2

    ; Atualize o valor de ecx para o número correto de bytes lidos
    mov ecx, [bytesRead]

    invoke WriteFile, ebx, addr buffer, ecx, addr bytesWritten, NULL

    invoke CloseHandle, edi
    invoke CloseHandle, ebx

    jmp menuLoop

criptoanalise:
    invoke StdOut, addr filePrompt
    invoke StdIn, addr inputFileBuffer, 256

    jmp menuLoop

exitProgram:
    invoke ExitProcess, 0

end start

I think the problem is with the atodw function:

invoke StdOut, addr keyPrompt
invoke StdIn, addr keyBuffer, 256

invoke atodw, addr keyBuffer
mov ecx, eax

Solution

  • invoke atodw, addr keyBuffer
    mov eax, eax
    

    mov eax, eax There's little point in moving EAX to EAX

    Seeing how you use the key (sub al, byte ptr [keyBuffer] and add al, byte ptr [keyBuffer]), you should write:

    invoke atodw, addr keyBuffer
    mov    byte ptr [keyBuffer], al
    

    There's more going on here!

    xor ecx, ecx
    mov cl, byte ptr [bytesRead]
    

    BytesRead is a dword that is limited to 512 (sizeof buffer). You should not be reading this as a byte! You risk loosing 256 or 512 bytes from doing so!
    Simply write mov ecx, [bytesRead]

    lea edi, [buffer]
    ...              <<< the loop
    invoke CloseHandle, edi
    invoke CloseHandle, ebx
    

    You won't be able to successfully close the file once the handle in EDI gets destroyed by using that register in the loop(s).
    You could preserve the handle on the stack:

    lea  edi, [buffer]
    push edi
    ...              <<< the loop
    pop  edi
    invoke CloseHandle, edi
    invoke CloseHandle, ebx