You are on page 1of 10

Computer Architecture – Assignment 2

Encryption!

Thomas Sampson – Games Software Development – 2Y - 2007


My Encryption Code
Below is the encryption algorithm number 14 (written in x86 assembly), which I was
allocated along with the encryption key „n‟. I have commented my encryption routine
below to explain how it works.

encrypt14: push edx // the value of the edx register is pushed onto the
stack for safe keeping
/*
Inputs: EAX = Encryption Key Value, ECX = Source character to be encrypted
Outputs: EAX = Encrypted character

Before this sub routine was called, the source character (the character being encrypted) was pushed into
the ECX register with the “movsx” (move with sign extension) instruction. Characters are only 8 bits in
length. Therefore the source character only occupies the “CL” region of the EXC register (the last 8
bits of the register). The encryption key was also saved in the EAX register using the “movsx”
instruction, again only occupying the last 8 bits of the register (“AL”).
*/
ror cl,1 // Rotate the 8bit source character in CL one position to the right
ror cl,1 // Rotate the 8bit source character in CL one position to the right

ror cl,1 // Rotate the 8bit source character in CL one position to the right

ror cl,1 // Rotate the 8bit source character in CL one position to the right

push ecx //Push the new rotated/encrypted value of ECX (source character) onto the
stack
add eax,0x55 //The value 55h (or 85 in denary) is added to the EAX register (the
encryption key) and the result over written to the EAX register
mov edx,eax //The value of EAX (encryption key + 55h) is copied into the EDX register
pop eax //The last item on the stack (the scrambled character) is popped off the stack
into the EAX register
xor eax,edx //This compares each bit inside the EAX (scrambled source character)
register with each bit inside the EDX (encryption key + 55h) register,
producing a result of 1 for each set of different bits (e.g. a 0 compared to a 1)
and a result of 0 for each pair of matching bits (e.g. comparing 1 with 1). The
result is then stored inside EAX.
ror al,1 //The 8 bits of AL (final 8 bits of EAX), which represent the result of the
XOR, are rotated one position to the right
ror al,1 //The 8 bits of AL (final 8 bits of EAX), which represent the result of the
XOR, are again rotated one position to the right
not al //Inverts each bit inside the AL section of the EAX register, setting any 0‟s to
1‟s and all 1‟s to 0‟s.
add eax,0x10 //Adds 10h (16 in denary) to the value inside EAX

pop edx // Restored the old value of EDX from the stack to tidy up ready for ending
the sub routine
ret //Uses the return location on the stack to swap the EIP (instruction pointer)
register back to the position from where this sub routine was called.
Implementing the Standard Call mechanism
Instead of using registers to pass parameters to my sub routine, below I have
implemented the standard call procedure which uses the stack to send parameters into
my sub routine.

NOTE: - At this point I am only implementing _stdcall and not optimising any of the code

Part 1

This part of the code is responsible for organising the stack / calling the sub routine,
and resides inside the while loop.

__asm {

push ecx //push or 'save' the value of ecx onto the stack
push edx //push or 'save' the value of edx onto the stack

push EKey; //push parameter 1 (the encryption key) onto the stack
push s_char; //push parameter 2 (the source char) onto the stack

call encrypt14; //call sub routine with result stored in EAX or „AL‟ to be precise

add esp,8; //push the stack pointer back (by 8 as we used 2*4byte paramaters)
mov e_char, al; //move the encrypted character into variable 'e_char'

pop edx; //pop or 'restore' the old value of edx from the stack
pop ecx; //pop or 'restore' the old value of ecx from the stack

}
Part 2

This part of the code is the actual sub routine itself „encrypt14‟ which now gets its
parameters from the stack rather than using registers.

__asm {

encrypt14:

push ebp; //push old base pointer value onto stack


mov ebp, esp; //move base pointer to current stack pointer

//----Main Encrytion Routine----//

mov ecx, dword ptr [ebp+8]; //place the source character in ecx
mov eax, dword ptr [ebp+0Ch]; //place the encryption key in eax

ror cl, 1; //rotate the source character bits right 4 times


ror cl, 1;
ror cl, 1;
ror cl, 1;

push ecx //run main encryption routine (commented previously)


add eax,0x55
mov edx,eax
pop eax
xor eax,edx
ror al,1
ror al,1
not al
add eax,0x10

//--End Main Encryption Routine--//

mov esp, ebp; //set stack pointer back to base pointer


pop ebp; //restore the old base pointer from stack
ret; //end sub routine, also pops return address off the stack

Note: - The encrypted character is returned by storage in the EAX register as this is standard practice
when using the _stdcall mechanism.
Encryption Routine
To work out a method of decrypting the character I first decided to draw a simple
flow chart of how the source character is encrypted, allowing me to reverse the
process.

Source Character  CL Stack

CL pushed onto stack


CL – ROR x 4

Encryption Key  AL

AL – Add 55h

AL – Copied into DL

AL – Now = CL CL popped off of stack

XOR AL with DL

AL =Scrambled source char


DL = Encryption Key + 55h

Result into AL

AL – ROR x 2

NOT AL

AL + 10h

Encrypted key is now in AL


Decryption Routine
From the previous flow chart I could not devise the following decryption routine by
reversing the encryption process.

Encrypted character  AL

Encryption Key  CL

AL subtract 10h

NOT AL

ROL AL x2

CL add 55h

XOR AL with CL

AL =Jumbled Key
CL = Encryption Key + 55h

Result into AL

ROL AL x4

Decrypted key is now in AL


Implementing Decryption Routine in Assembly

I now implemented my decryption routine in x86 assembly, again using the _stdcall
mechanism

Part 1

__asm {

push ecx //push or 'save' the value of ecx onto the stack
push edx; //push or 'save' the value of edx onto the stack

push key; //push parameter 1 (the encryption key) onto the stack
push e_char; //push parameter 2 (the encrypted char) onto the stack

call decrypt14; //call decryption sub routine, with result stored in EAX

add esp,8; //push the stack pointer back (using 8 as we used 2 parameters)
mov e_char, al; //move the encrypted character into variable 'e_char'

pop edx; //pop or 'restore' the old value of edx from the stack
pop ecx; //pop or 'restore' the old value of ecx from the stack

Part 2

__asm {

decrypt14:

push ebp; //push old base pointer value onto stack


mov ebp, esp; //move base pointer to current stack pointer

//----Main Decrytion Routine----//

mov eax, dword ptr [ebp+8]; //put paramater 1 (encrypted char) in EAX
mov ecx, dword ptr [ebp+0Ch]; //put parameter 2 (encryption key) in ECX

sub al, 10h; //minus ten from the encrypted character (to undo add 10h)
not al; //invert encrytped char (to undo previous not operation)
rol al, 2; //rotate left x2 (to undo rotate right x2)
add ecx, 55h; //Add 55h to the encryptio key (we need it in this state)
xor eax, ecx; //Compare (key +55h) with (modified encrypted char)
rol al, 4; //Rotate the aswer right x4 (to undo previous ror x4)

//--End Main Decryption Routine--//

mov esp, ebp; //set stack pointer back to base pointer


pop ebp; //restore the old base pointer from stack
ret; //end sub routine

Note: - The decrypted character is returned by storage in the EAX register as this is standard practice
when using the _stdcall mechanism.
Optimising my code

I will now attempt to optimise the assembly code used in both the encryption and
decryption routines to increase efficiency and reduce the code footprint.

Encryption Routine Optimisation

__asm {
push ecx //push or 'save' the value of ecx onto the stack
push EKey; //push parameter 1 (the encryption key) onto the stack
push s_char; //push parameter 2 (the source char) onto the stack

call encrypt14; //call sub routine with result stored in EAX or „AL‟ to be precise

add esp,8; //push the stack pointer back (by 8 as we used 2*4byte paramaters)
mov e_char, al; //move the encrypted character into variable 'e_char'
pop ecx; //pop or 'restore' the old value of ecx from the stack
}

In the main “encrypt14” routine I removed the use of the register edx, therefore
removed the process of pushing and popping it off the stack when calling the sub
routine. There is no point in saving the value of EDX on the stack and retrieveing it
after the function call, as I am confident that the value of EDX will not be changed
during the sub routine.

__asm {
encrypt14:
push ebp; //push old base pointer value onto stack
mov ebp, esp; //move base pointer to current stack pointer

//----Main Encrytion Routine----//


mov ecx, dword ptr [ebp+8]; //place the source character in ecx
mov eax, dword ptr [ebp+0Ch]; //place the encryption key in eax

Here I used the second operand of “ror” to inform the instruction to do 4 rotations
to the right, instead of repeating the operation 4 times
ror cl, 4; //rotate the source character bits right 4 times
Here I removed the process of pushing ECX onto the stack as it served no relevant
purpose
add al,0x55
Here I removed the process of copying EAX into EDX as it was un-necessary
As a consequence of not putting ECX on the stack, and not using EDX, I can now use
the XOR function on EAX and ECX (this has exactly the same effect as the previous
convoluted method)
xor al,cl
Here I used the second operand of “ror” to inform the instruction to do 2 rotations
to the right, instead of repeating the operation twice
ror al,2
not al
add al,0x10
//--End Main Encryption Routine--//

mov esp, ebp; //set stack pointer back to base pointer


pop ebp; //restore the old base pointer from stack
ret; //end sub routine, also pops return address off the stack

Note: - For all manipulations of EAX and ECX I changed all the references to AL and
CL (the latter byte of the registers). This should make arithmentic and XOR functions
more efficient as they do not have to work with 32 bits of data, only 8.
Decryption Routine Optimisation

__asm {

push ecx //push or 'save' the value of ecx onto the stack
push key; //push parameter 1 (the encryption key) onto the stack
push e_char; //push parameter 2 (the encrypted char) onto the stack

call decrypt14; //call decryption sub routine, with result stored in EAX

add esp,8; //push the stack pointer back (using 8 as we used 2 parameters)
mov e_char, al; //move the encrypted character into variable 'e_char'
pop ecx; //pop or 'restore' the old value of ecx from the stack

Again, here I removed the process of saving and restoring EDX, which takes time
saving the value to the stack (main memory). Again, I made this decision as I am
confident that “decrypt14” does not make use of the EDX register.

__asm {

decrypt14:

push ebp; //push old base pointer value onto stack


mov ebp, esp; //move base pointer to current stack pointer

//----Main Decrytion Routine----//

mov eax, dword ptr [ebp+8]; //put paramater 1 (encrypted char) in EAX
mov ecx, dword ptr [ebp+0Ch]; //put parameter 2 (encryption key) in ECX

sub al, 10h; //minus ten from the encrypted character (to undo add 10h)
not al; //invert encrytped char (to undo previous not operation)
rol al, 2; //rotate left x2 (to undo rotate right x2)
add cl, 55h; //Add 55h to the encryptio key (we need it in this state)
xor al, cl; //Compare (key +55h) with (modified encrypted char)
rol al, 4; //Rotate the aswer right x4 (to undo previous ror x4)

//--End Main Decryption Routine--//

mov esp, ebp; //set stack pointer back to base pointer


pop ebp; //restore the old base pointer from stack
ret; //end sub routine

When I wrote this routine I tried to make it as optimised as possible, however here I have again
changed all references to EAX and ECX to AL and CL to reduce the number of bits being manipulated,
hence increasing efficiency. I have also made use of the second operand of ROR and ROL to group
together these instructions.
Lower Case Conversion

The c++ code is responsible for checking that the string we enter contains ONLY
alpha numeric characters. To do lower case conversion (during decryption) we must
isolate any uppercase characters and convert them.

Uppercase characters lie within the ASCII code region of 0x41  0x5A. In the
assembly code I do two checks to ensure the character lies within these bounds, only
if it meets these conditions will it be converted to lowercase, otherwise the IP will
jump to the end of the decryption routine, bypassing any case conversion.

Lowercase conversion is easy as there is a direct link between lower and uppercase
ASCII codes. Any uppercase ASCII code + 0x20 gives its lowercase equivalent,
(a simple addition to the AL region of the EAX register).

add ecx, 55h;


xor eax, ecx; End of decryption logic
rol al, 4;

cmp al, 41h; // the decrypted characater with 41h


jl fail; //if decrypted char is <41h then jump to „fail‟
cmp al, 5Ah; //compare the decrypted characater with 5Ah
jg fail; //if decrypted char is >5Ah then jump to „fail‟
add al, 20h; //+20h to decrypted char (shift to lower case)

fail: //The decrypted character is NOT a captial

mov esp, ebp; End of decryption sub routine


pop ebp;
ret;

You might also like