I’m attempting to implement the TEA algorithm in assembly language (8086 TASM). However, I’m encountering difficulties in two areas
String Input: I need assistance in implementing a mechanism to input strings from the user within my assembly program.
Hexadecimal Conversion: After obtaining user input, I aim to convert each letter of the input string into its corresponding hexadecimal representation to prepare it for TEA encryption. I’m seeking guidance on how to accomplish this conversion efficiently.
Encrypted Message Decryption: Following encryption using the TEA algorithm, I’m encountering difficulty in converting the resulting encrypted message back into readable string letters. I require assistance in decrypting and converting the encrypted message into its original form.
I’ve successfully implemented the encrypt and decrypt functions for the TEA algorithm. These functions seem to perform encryption and decryption operations correctly. However, I’m stuck at handling string input and converting them into a format suitable for encryption. Additionally, after encryption, the output contains unknown symbols, and I need assistance in converting it into readable encrypted strings.
Here is my encrypt / decrypt functions:
proc encrypt
pusha
mov cx, 32
encryptLoop:
; sum += delta
mov ax, [delta]
add [sum], ax
xor eax,eax
; ((p2 << 4) + k0)
mov dx, [p2]
shl dx, 4
add dx, [k0]
; (p2 + sum)
mov bx, [p2]
add bx, [sum]
; ((p2 << 4) + k0) ^ (p2 + sum)
xor dx, bx
xor bx, bx
; ((p2 >> 5) + k1)
mov bx, [p2]
shr bx, 5
add bx, [k1]
; ((p2 << 4) + k0) ^ (p2 + sum) ^ ((p2 >> 5) + k1)
xor dx, bx
add [pe1], dx
; ((p1 << 4) + k2)
mov dx, [p1]
shl dx, 4
add dx, [k2]
; (p1 + sum)
mov bx, [p1]
add bx, [sum]
; ((p0 << 4) + k2) ^ (p0 + sum)
xor dx, bx
xor bx, bx
; ((p1 >> 5 ) + k3)
mov bx,[p1]
shr bx, 5
add bx, [k3]
; ((p0 << 4) + k2) ^ (p0 + sum) ^ ((p1 >> 5 ) + k3)
xor dx, bx
add [pe2], dx
loop encryptLoop
popa
ret
endp encrypt
proc decrypt
pusha
mov cx, 32
decryptLoop:
; ((p1 << 4) + k2)
mov dx, [p1]
shl dx, 4
add dx, [k2]
; (p1 + sum)
mov bx, [p1]
add bx, [sum]
; ((p0 << 4) + k2) ^ (p0 + sum)
xor dx, bx
xor bx, bx
; ((p1 >> 5 ) + k3)
mov bx,[p1]
shr bx, 5
add bx, [k3]
; ((p0 << 4) + k2) ^ (p0 + sum) ^ ((p1 >> 5 ) + k3)
xor dx, bx
sub [pe2], dx
xor ax,ax
; ((p2 << 4) + k0)
mov dx, [p2]
shl dx, 4
add dx, [k0]
; (p2 + sum)
mov bx, [p2]
add bx, [sum]
; ((p1 << 4) + k0) ^ (p1 + sum)
xor dx, bx
xor bx, bx
; ((p2 >> 5) + k1)
mov bx, [p2]
shr bx, 5
add bx, [k1]
; ((p2 << 4) + k0) ^ (p2 + sum) ^ ((p2 >> 5) + k1)
xor dx, bx
sub [pe1], dx
; sum -= delta
mov ax, [delta]
sub [sum], ax
loop decryptLoop
popa
ret
endp decrypt
DS section:
delta dw 79b9h ; 79b9h for 16 bits, 9e3779b9h for 32 bits
sum dw 0
p1 dw 0
p2 dw 0
k0 dw 0
k1 dw 0
k2 dw 0
k3 dw 0
; Two part of the plaintext after encryption
pe1 dw 0
pe2 dw 0
Edit: Hope I understood this algorithm correctly. ;)
First answer:
Memory looks like this before calling to encryption:
Delta: 9e3779b9h
p1 : 20656349h = 'Ice '
p2 : 21414554h = 'TEA!'
k1 : 00000016h = 22
k2 : 0000000bh = 11
k3 : 00000021h = 33
k4 : 00000003h = 3
-d ds:0
0EED:0000 B9 79 37 9E 00 00 00 00-49 63 65 20 54 45 41 21 .y7.....Ice TEA!
0EED:0010 16 00 00 00 0B 00 00 00-21 00 00 00 03 00 00 00 ........!.......
After encryption:
Delta: 9e3779b9h
p1 : c6ef3720h (encrypted)
p2 : c96bcfebh (encrypted)
k1 : 00000016h = 22
k2 : 0000000bh = 11
k3 : 00000021h = 33
k4 : 00000003h = 3
-d ds:0
0EED:0000 B9 79 37 9E 20 37 EF C6-7A D0 EA DC 1E FC 4C 9A .y7. 7..z.....L.
0EED:0010 16 00 00 00 0B 00 00 00-21 00 00 00 03 00 00 00 ........!.......
Now decryption
, back to normal:
Delta: 9e3779b9h
p1 : 20656349h = 'Ice '
p2 : 21414554h = 'TEA!'
k1 : 00000016h = 22
k2 : 0000000bh = 11
k3 : 00000021h = 33
k4 : 00000003h = 3
-d ds:0
0EED:0000 B9 79 37 9E 00 00 00 00-49 63 65 20 54 45 41 21 .y7.....Ice TEA!
0EED:0010 16 00 00 00 0B 00 00 00-21 00 00 00 03 00 00 00 ........!.......
I used hardcoded values for p1,p2,k0,k1,k2,k3
.
Update 1:
I added:
print_text proc
- shows string in console, string offset should be in si
user_input proc
- takes data from user
check_chars proc
- we want only right chars
plain_txt_buffer
size is 32 bytes + 1 byte for 0dh
.
If user enters 32 chars 0dh
will be added automatically at the end of the buffer.
Update 2:
input_flag
inside user_input proc
and check_chars
controls which data set is used:
1 - data set for plain_text , 20h - 7fh, enter, backspace
2 - data set for keys, only digits 30h - 39h, enter, backspace
keys_buffer
size is 10 bytes + 1 byte for 0dh
.
If user enters 10 chars 0dh
will be added automatically at the end of the buffer.
Update 3:
k0,k1,k2,k3
, ascii string to 32-bit value.keys_buffer
because program uses same memory to calculate all the keys.Update 4:
Here is the updated code:
.386
ideal
model small
stack 256
segment datasg
plain_txt_buffer db 33 dup(0) ; store user's text
pt_buffer_size db $ - plain_txt_buffer - 1 ; size of the buffer without 0dh
keys_buffer db 11 dup(0) ; store user's keys
k_buffer_size db $ - keys_buffer - 1 ; size of the buffer without 0dh
enc_buffer db 32 dup(0) ; encrypted txt buffer
;enc_buffer_size db $ - enc_buffer ; not used in the code
dec_buffer db 32 dup(0) ; decrypted txt buffer
;dec_buffer_size db $ - dec_buffer ; not used in the code
chars_in_buffer db 0 ; how many chars user entered, used in key32bit proc
input_flag dw 1 ; 1 - plain text data set, [20h ... 7fh], enter, backspace
; 2 - keys data set, only digits, enter, backspace
delta dd 9e3779b9h ; 9e3779b9h for 32 bits
sum dd 0
p1 dd 20656349h
p2 dd 21414554h
k0 dd 65536 ; [0 ... 4,294,967,295], 32-bit keys
k1 dd 255
k2 dd 0ff000000h
k3 dd 10000000h
plain_txt_msg db "Plain text: ",0 ; some screen messages
keys_msg db 0dh,0ah,"Enter keys: ",0
key_num db "k[ ",30h," ] = ",0
wait_for_key db 0dh,0ah,0ah,"Press any key to exit the app... ",0
newline db 0dh,0ah,0
key128bit db 0dh,0ah,"128-bit key: ",0
table_header db 0dh,0ah,0ah,"|Cycle|Plain Text |Encryption |Decryption |",0
table_row db 0dh,0ah,"| | | | |",0
cycle_num db "<",07h,30h,0eh,">",07h ; char + attribute
text_mode_mem dw 0b800h ; text mode vodeo mem address
pt_buffer_start dw 0018h ; 0b800h:0018h, text_mode_mem + 24 bytes, write plain text here
k_buffer_start dw 00cah ; 0b800h:00cah, text_mode_mem + 202 bytes, write keys here
trimmed_value dw 00ddh ; last digit will be red color if not fit in 32 bits
ends
assume ds:datasg,cs:code
segment code
start:
mov ax,datasg ; load ds
mov ds,ax
mov ax,[text_mode_mem] ; set es to text mode address
mov es,ax
mov ax,3 ; text mode
int 10h
mov ah,01h ; hide cursor
mov cx,2000h
int 10h
;------------------------- input plain txt
mov si, offset plain_txt_msg ; "Plain text: "
call print_text
mov di, offset plain_txt_buffer ; store plain text here
mov bx,[pt_buffer_start] ; address in video memory of the plain_text_buffer
call user_input ; take chars from a user
;------------------------- input keys
mov si, offset keys_msg ; "Enter keys: "
call print_text
mov bx,[k_buffer_start] ; address in video memory of the keys_buffer
mov [word input_flag],2 ; change data set to digits
mov cx,4 ; read 4 keys
mov dx,010ch ; cursor position
enter_keys:
mov di, offset keys_buffer ; write keys here
push dx ; save cursor position
push bx ; save video memory offset of the current key 0,1,2,3
mov ah,2 ; set cursor position
mov bh,0
int 10h ; BIOS video interrupt
pop bx
push bx
mov si, offset key_num ; print key number, "k[ ",30h," ] = "
push si ; save, lodsb inside print_text changes si
call print_text
call user_input ; take ascii digits from a user
pop si ; restore
call key32bit ; convert ascii digits to 32bit and clear keys_buffer
pop bx ; current key position
add bx,160 ; move to the next key
mov si, offset newline ; go to new line
call print_text
pop dx ; restore cursor position
inc dh ; next row
dec cx ; decrement loop counter
jnz enter_keys ; enter next key
;-----------------------show 128 bit key
mov si,offset key128bit ; "128-bit key: "
call print_text
call print128key ; this proc prints full key in hex format
;----------------------------------------
call remove_0dh ; remove 0dh from plain_txt_buffer
mov cx,4 ; run encryption 4 times
mov si, offset plain_txt_buffer ; offsets to buffers
mov di, offset enc_buffer
mov bx, offset dec_buffer
cycle_enc_dec: ; start encryption - decryption cycle
push bx
mov eax, [si] ; p1,take 4 bytes from plain_txt_buffer
mov [p1],eax ; p1,p2 are used inside enc and dec procs
add si,4 ; move to p2
mov eax, [si] ; p2,take 4 bytes from plain_txt_buffer
mov [p2],eax ;
call encrypt ; start encryption
mov eax,[p1] ; take decrypted 2 x 4 bytes and store them inside enc_buffer
mov [di],eax ; p1
add di,4 ; move to p2
mov eax,[p2]
mov [di],eax ; p2
;-------------------------------------
call decrypt ; start decryption
pop bx ; pop dec_buffer address
mov eax,[p1] ; and save p1 and p2 inside
mov [bx],eax
add bx,4
mov eax,[p2]
mov [bx],eax
add si,4 ; next 2 x 4 bytes of plain text
add di,4 ; move 8 bytes inside encryption buffer
add bx,4 ; move 8 bytes inside decryption buffer
mov [dword sum],0 ; reset sum
dec cx ; decrement cycles
jnz cycle_enc_dec ; go to next cycle
;------ data is in memory, now show results
mov si, offset table_header ; |Cycle|Plain Text |Encryption |Decryption |
call print_text
mov cx,13 ; print 13 rows
show_table:
mov si, offset table_row
call print_text
dec cx
jnz show_table
call print_data ; show all data,number of cycle, plain text, enrypted text
; and after decryption, back to original message
;------------------------- end app
mov si,offset wait_for_key
call print_text
mov ah,0
int 16h
mov ax,3 ; clear screen
int 10h
mov ax,4c00h
int 21h
;----------------------------------------
; print128key
; prints full key in hex format
proc print128key
mov di,986 ; screen offset, start printing at this location
mov si, offset k0 ; offset of first key, all the keys are in memory together
; k1 = k0 + 4 bytes
; k2 = k0 + 8 bytes
; k3 = k0 + 12 bytes
add si,3 ; bytes in memory are in litlle endian format
; translate to human readable form
mov dx,4 ; print 4 keys
one_of_the_4_parts:
mov cx,4 ; 4 bytes each
byte_inside:
mov al,[si] ; each byte of the key
call char2hex ; print 2 hex values
dec si ; offset of the next byte of the key
dec cx ; bytes left
jnz byte_inside
add si,8 ; move to the next part
add di,2 ; insert space
dec dx ; parts left
jnz one_of_the_4_parts
ret
endp print128key
;----------------------------------------
; print_data
; prints result of encrypton and decryption
proc print_data
push bp
mov bp, sp
mov cx,4 ; 4 rows
mov di,1604 ; memory offset of the first table row
mov [word bp-2],offset plain_txt_buffer
mov [word bp-4],offset enc_buffer
mov [word bp-6],offset dec_buffer
sub sp,6
show_rows:
push cx
;cycle column
mov si,offset cycle_num ; print cycle number
mov cx,6
rep movsb
add [byte si-4],1 ; modify row number
;plain text column
add di,4
mov si, [bp-2]
mov cx,8
plain_text_column:
mov al,[si] ; char from plain_txt_buffer
mov [es:di],al
add di,1
mov dl,15 ; white color
mov [es:di],dl
add di,159
call char2hex
sub di,160
inc si ; take next char
dec cx
jnz plain_text_column
mov [bp-2],si ; save current plain_txt_buffer offset
;encryption column
add di,2
mov si, [bp-4]
mov cx,8
enc_column:
mov al,[si] ; char from enc_buffer
mov [es:di],al
add di,1
mov dl,10 ; light green color
mov [es:di],dl
add di,159
call char2hex
sub di,160
inc si ; take next char
dec cx
jnz enc_column
mov [bp-4],si ; save current enc_buffer offset
;decryption column
add di,2
mov si, [bp-6]
mov cx,8
dec_column:
mov al,[si] ; char from dec_buffer
mov [es:di],al
add di,1
mov dl,13 ; purple color
mov [es:di],dl
add di,159
call char2hex
sub di,160
inc si ; take next char
dec cx
jnz dec_column
mov [bp-6],si ; save current enc_buffer offset
add di,370 ; go next row
pop cx
dec cx
jnz show_rows
add sp,6
pop bp
ret
endp print_data
;----------------------------------------
; remove_0dh
; removes 0dh from plain text buffer
; we want only plain text
proc remove_0dh
mov di,offset plain_txt_buffer
search_for_0dh:
cmp [byte di],0dh
jz search_done
inc di ; next address of the char
jmp search_for_0dh
search_done:
mov [byte di],0 ; remove 0dh
ret
endp remove_0dh
;----------------------------------------
; char2hex
; prints byte as sequence of 2 hex values
proc char2hex
; al - char
push cx ; save previous loop's counter
push ax ; char will change after shr, save it
mov bl,2 ; process 2 nibbles
shr al,4 ; al = xxxxxxxx, - shr,4 - 0000xxxx, higher half moved to lower half
hex_2:
cmp al,10
jae print_letter
add al,30h ; print_digit
jmp to_mem
print_letter:
add al,37h
to_mem:
mov [es:di],al ; move to mem
add di,1 ; move to the attribute byte
mov cl,3 ; turquoise color
mov [es:di],cl ; change char attribute
inc di
dec bl
jz done_printing
pop ax
and al,0fh ; al = 0000xxxx, lower half
jmp hex_2
done_printing:
pop cx
ret
endp char2hex
;----------------------------------------
; convert ascii string to 32bit value
; and save in var k0,k1,k2,k3
proc key32bit
push cx
mov di, offset keys_buffer ; ascii digit key is stored here
; calculate offset of k0,k1,k2,k3
add si,3 ; take number of the key from string key_num
xor ah,ah ; ah = 0
mov al,[byte si] ; al = 30h,31h,32h,33h
push ax ; save
sub al,30h ; al = 0,1,2,3
shl ax,2 ; calculat desired offset k0 = 0,k1 = 4,k2 = 8,k3 = 12 bytes
mov bx,ax
pop ax ; restore
inc al ; al = 31h,32h,33h,34h
mov [byte si],al ; next key number
mov si,offset k0
add si,bx ; [si] here will be each key
push si ; save address
xor ch,ch ;
mov cl,[chars_in_buffer] ; number of digits in the buffer
mov ebx,0 ; after all the calculations 32bit key will be stored here
cmp cl,0 ; no digits, only 0dh
jz end_of_data
cmp cl,1 ; 1 digits
jz last_digit
add di,cx ; location of enter in the buffer
mov [byte di],30h ; remove 0dh
sub di,cx ; go back to start of the buffer
dec cx ; these digits will be mul by 10, last one will be added
mov esi,10
key_in_the_buffer:
xor eax,eax ; eax = 0
mov al,[di] ; [di] - ascii digit
sub al,'0' ; al = [0...9]
add eax,ebx
mul esi ; mul by 10
jc key_too_big_2
mov ebx,eax
inc di
dec cx
jnz key_in_the_buffer
last_digit:
xor eax,eax ; eax = 0
mov al,[di] ; [di] - ascii digit
sub al,'0' ; al = [0...9]
add eax,ebx
jc key_too_big
mov ebx,eax
jmp end_of_data
key_too_big_2:
push di
mov al,0ch ; red digit
mov di, [trimmed_value]
mov [es:di],al
pop di
jmp last_digit
key_too_big:
mov al,0ch ; red digit
mov di, [trimmed_value]
mov [es:di],al
end_of_data:
pop si
mov [si],ebx ; save 32bit key to memory
mov di, [trimmed_value] ;
cmp [byte chars_in_buffer],0; is buffer empty?
jnz key_is_visible
mov al,'0' ; '0' if user pressed only enter
sub di,19 ; move to the left
mov [es:di],al ; show '0'
add di,19 ; go back, code uses last value of trimmed_value
key_is_visible:
add di,160 ; next location of "bad" digit
mov [trimmed_value],di
;---------------------------------------
mov di, offset keys_buffer ; clear buffer
mov cx,11
mov dl,0
clear_keys_buffer:
mov [di],dl
inc di
dec cx
jnz clear_keys_buffer
pop cx
ret
endp key32bit
;----------------------------------------
; data encryption
proc encrypt
pusha
mov cx, 32
encryptLoop:
; sum += delta
mov eax, [delta]
add [sum], eax
xor eax,eax
; ((p2 << 4) + k0)
mov edx, [p2]
shl edx, 4
add edx, [k0]
; (p2 + sum)
mov ebx, [p2]
add ebx, [sum]
; ((p2 << 4) + k0) ^ (p2 + sum)
xor edx, ebx
xor ebx, ebx
; ((p2 >> 5) + k1)
mov ebx, [p2]
shr ebx, 5
add ebx, [k1]
; ((p2 << 4) + k0) ^ (p2 + sum) ^ ((p2 >> 5) + k1)
xor edx, ebx
;---
add [p1],edx
;add [pe1], edx
; ((p1 << 4) + k2)
mov edx, [p1]
shl edx, 4
add edx, [k2]
; (p1 + sum)
mov ebx, [p1]
add ebx, [sum]
; ((p0 << 4) + k2) ^ (p0 + sum)
xor edx, ebx
xor ebx, ebx
; ((p1 >> 5 ) + k3)
mov ebx,[p1]
shr ebx, 5
add ebx, [k3]
; ((p0 << 4) + k2) ^ (p0 + sum) ^ ((p1 >> 5 ) + k3)
xor edx, ebx
add [p2],edx
;add [pe2], edx
loop encryptLoop
popa
ret
endp encrypt
;----------------------------------------
; data dencryption
proc decrypt
pusha
mov cx, 32
decryptLoop:
; ((p1 << 4) + k2)
mov edx, [p1]
shl edx, 4
add edx, [k2]
; (p1 + sum)
mov ebx, [p1]
add ebx, [sum]
; ((p1 << 4) + k2) ^ (p1 + sum)
xor edx, ebx
xor ebx, ebx
; ((p1 >> 5) + k3)
mov ebx, [p1]
shr ebx, 5
add ebx, [k3]
; ((p1 << 4) + k0) ^ (p2 + sum) ^ ((p1 >> 5) + k3)
xor edx, ebx
sub [p2], edx
; ((p2 << 4) + k0)
mov edx, [p2]
shl edx, 4
add edx, [k0]
; (p2 + sum)
mov ebx, [p2]
add ebx, [sum]
; ((p2 << 4) + k0) ^ (p2 + sum)
xor edx, ebx
xor ebx, ebx
; ((p2 >> 5 ) + k1)
mov ebx,[p2]
shr ebx, 5
add ebx, [k1]
; ((p2 << 4) + k0) ^ (p2 + sum) ^ ((p2 >> 5 ) + k1)
xor edx, ebx
sub [p1], edx
; sum -= delta
mov eax, [delta]
sub [sum], eax
loop decryptLoop
popa
ret
endp decrypt
;----------------------------------------
; data input, buffer operations
; di - offset to buffer
proc user_input
mov dh,0 ; chars counter
mov dl,0 ; flag
mov si,[input_flag] ; switch between data sets
; if keys we need only digits
; if plain text we want more chars
new_char:
mov ah,0 ; wait for key
int 16h ; BIOS keyboard interrupt
;----------------------------------------
call check_chars ; we want chars from set 1 or set 2
; check flag
cmp dl,0 ; 0 - data set 1 - keys (20h - 7fh)
jz char_ok ; or data set 2 - keys (30h - 39h)
cmp dl,1 ; 1 - wrong char, do nothing
jz reset_flag
cmp dl,2 ; 2 - backspace, delete char
jz key_backspace
cmp dl,3 ; 3 - enter, accept string
jz insert_0dh
;----------------------------------------
char_ok:
mov [di],al ; write to buffer
inc di ; next position in buffer
mov [es:bx],al ; write to video mem
add bx,2 ; next offset in video mem
inc dh ; count chars
cmp si,1 ; switch between data sets
jz plain_txt_ds
cmp dh,[k_buffer_size] ; is keys_bufferr full?
jz insert_0dh ; yes, we are done here
jmp new_char ; no, enter next char
plain_txt_ds:
cmp dh,[pt_buffer_size] ; is plain_text_buffer full?
jz insert_0dh ; yes, we are done here
jmp new_char ; no, enter next char
;----------------------------------------
key_backspace:
cmp dh,0 ; is buffer empty?
jz reset_flag ; yes
; no
dec di ; move buffer pointer to the left
dec dh ; decrease number of the chars in the buffer
mov al,0 ;
mov [di],al ; delete char in buffer
sub bx,2 ; and clear char on the screen too
mov al,0 ;
mov [byte es:bx],0 ; remove char from video mem
reset_flag:
mov dl,0
jmp new_char
insert_0dh:
mov al,0dh ; insert enter
mov [di],al ; at the end of the string
mov [chars_in_buffer],dh; used in key32bit proc
ret
endp user_input
;----------------------------------------
; check_chars
; proc accepts only chars from data set 1 and 2
proc check_chars
enter_key:
cmp al,0dh ; enter
mov dl,3 ; flag = 2, accept entered data
jz checking_done
backspace:
cmp al,08h ; backspace
mov dl,2 ; flag = 3, delete previous char
jz checking_done
cmp si, 1 ; plain text data set
jz plain_txt_data_set
from_30h: ; keys data set
cmp al,30h ; 0
jb wrong_char
to_39h:
cmp al,39h ; 9
ja wrong_char
mov dl,0 ; flag = 0, all good
jmp checking_done
plain_txt_data_set:
from_20h:
cmp al,20h ; space
jb wrong_char
to_7eh:
cmp al,7eh ; tilde
ja wrong_char
mov dl,0 ; flag = 0, all good
jmp checking_done
wrong_char:
mov dl,1 ; flag = 1, wrong char
checking_done:
ret
endp check_chars
;----------------------------------------
; print string
proc print_text
next_letter:
mov ah,0eh
lodsb ; al = ds:[si]
or al,al
jz done
int 10h
jmp next_letter
done:
ret
endp print_text
ends
end start