A-level Computing 2009/AQA/Problem Solving, Programming, Data Representation and Practical Exercise/Skeleton code/2013 Exam/Section D
Potential QuestionsEdit
1. You could be asked to add an "r." function to reset the Plaintext and the Ciphertext variables.
This is the VB.net Solution
Answer:
'Added to the end of the case select in sub 'Main':
Case "r"
Ciphertext = ""
Plaintext = ""
'If option 'r' is selected, an empty string will be assigned to both variables.
'Added to Sub 'DisplayMenu':
Console.WriteLine("RESET")
Console.WriteLine(" r. reset the plaintext & ciphertext")
This is the Python Solution
Answer:
#Add this to the appropriate place in the DisplayMenu function
print "RESET"
print " r. reset the plaintext & ciphertext"
#Then add this to the while Choice != 'q': loop:
elif Choice == 'r':
Ciphertext = ''
Plaintext = ''
2. There is unnecessary code in the EveryNthCharacterSteganography function and GetTextFromFile. There is no need to pass the CurrentPosition twice from the EveryNthCharacterSteganography function. In the GetTextFromFile function this means the second loop is not required as it means the start and end position are the same thing. Of course it could mean that you will be asked to add a variable in which the user will set how many characters should be grabbed from the file each time. The loop, although not needed right now would then be needed and current position, currentposition+numberofcharacters would be passed through instead
This is the Pascal/Delphi solution:
Answer:
Amend the call to GetTextFromFile from EveryNthCharacterSteganography function so that it only passes the current position once. Then amend GetTextFromFile to this:
Function GetTextFromFile(StartPosition: Integer) : String;
//get rid of the end position above
Var
CharacterFromFile : Char;
TextFromFile : String;
Count : Integer;
CurrentFile : TextFile;
Begin
AssignFile(CurrentFile, 'diary.txt');
Reset(CurrentFile);
//amend the code so that there is only one loop:
If StartPosition > 1
Then
For Count := 1 To StartPosition-1
Do Read(CurrentFile, CharacterFromFile);
Read(CurrentFile, CharacterFromFile);
TextFromFile := CharacterFromFile;
CloseFile(CurrentFile);
GetTextFromFile := TextFromFile;
This is the Vb.Net solution:
Answer:
Amend the call to GetTextFromFile from EveryNthCharacterSteganography function so that it only passes the current position once. Then amend GetTextFromFile to this:
Function GetTextFromFile(ByVal StartPosition As Integer) As String
Dim CharacterFromFile As Char
Dim TextFromFile As String
Dim Count As Integer
FileOpen(1, "diary.txt", OpenMode.Binary)
For Count = 1 To StartPosition - 1
FileGet(1, CharacterFromFile)
Next
TextFromFile = ""
FileGet(1, CharacterFromFile)
TextFromFile = TextFromFile & CharacterFromFile
FileClose(1)
GetTextFromFile = TextFromFile
End Function
3. Currently the menu option will not accept capital letters. Modify the code to allow this.
This is the Visual Basic solution:
Answer:
Function GetMenuChoice() As Char
Dim MenuChoice As Char
MenuChoice = Console.ReadLine
Console.WriteLine()
'The "Lcase" function converts the content of "MenuChoice" to the lower case
GetMenuChoice = LCase(MenuChoice)
End Function
Alternative answer
Function GetMenuChoice() As Char
Dim MenuChoice As Char
' add .ToLower to the console.readline statement
MenuChoice = Console.ReadLine.ToLower
Console.WriteLine()
GetMenuChoice = MenuChoice
End Function
This is the Pascal/Delphi solution:
Answer:
Function GetMenuChoice : Char;
Var
MenuChoice : Char;
Begin
Readln(MenuChoice);
Writeln;
GetMenuChoice := Lowercase(MenuChoice);
End;
Alternate Solution
Case Choice Of
'a', 'A' : Plaintext := GetTextFromUser;
'b', 'B' : DisplayPlaintext(Plaintext);
'd', 'D' : Ciphertext := GetTextFromUser;
'e', 'E' : DisplayCiphertext(Ciphertext);
'g', 'G' : Begin
DisplayPlaintext(Plaintext);
AmountToShift := GetKeyForCaesarCipher;
Ciphertext := UseCaesarCipher(Plaintext, AmountToShift);
DisplayCiphertext(Ciphertext);
End;
'h', 'H' : Begin
DisplayPlaintext(Plaintext);
SizeOfRailFence := GetSizeOfRailFence;
Ciphertext := EncryptUsingRailFence(Plaintext, SizeOfRailFence);
DisplayCiphertext(Ciphertext);
End;
'j', 'J' : Begin
DisplayCiphertext(Ciphertext);
AmountToShift := -GetKeyForCaesarCipher;
Plaintext := UseCaesarCipher(Ciphertext, AmountToShift);
DisplayPlaintext(Plaintext);
End;
'k', 'K' : Begin
DisplayCiphertext(Ciphertext);
SizeOfRailFence := GetSizeOfRailFence;
Plaintext := DecryptUsingRailFence(Ciphertext, SizeOfRailFence);
DisplayPlaintext(Plaintext);
End;
'n', 'N' : Begin
GetPositionsToUse(StartPosition, EndPosition);
N := GetValueForN;
Plaintext := EveryNthCharacterSteganography(StartPosition, EndPosition, N);
DisplayPlaintext(Plaintext);
End;
End;
If Choice = 'q'
Then
Begin
Quit:= TRUE;
Writeln('Press enter key to continue');
Readln;
End;
If Choice = 'Q'
Then
Begin
Quit:= TRUE;
Writeln('Press enter key to continue');
Readln;
End;
Until Quit = TRUE;
This is the Python solution:
Answer:
Choice = (GetMenuChoice()).lower()
4. You may be asked to validate the users choice to make sure it is valid.
This is the Visual Basic Solution:
Answer:
Dim AcceptedChoices As String = "abdeghjknq" ' Create a list of accepted choices
Dim MenuChoice As Char ' Create a variable to store the users input
Dim ValidChoice As Boolean ' Create a boolean to store whether the input is valid
Do ' Do loop <--- Will loop through at least once
MenuChoice = Console.ReadLine.ToLower ' Read the users input and store it in MenuChoice
ValidChoice = AcceptedChoices.Contains(MenuChoice) ' Check if the MenuChoice exists in the list of acceptable choices and save it as a boolean
If Not ValidChoice Then ' If the entered choice is not valid
Console.WriteLine("Invalid Choice") ' Tell the user the choice is invalid
End If ' Finish validity check
Loop Until ValidChoice ' Keep looping until the entered choice is valid
Console.WriteLine() ' Insert a blank line
GetMenuChoice = MenuChoice ' Return the users entered choice
Or, if you don't want to waste a load of time doing a pointless loop where the code needs to be changed every time if a new menu choice is added, look below:
To validate the user's choice:
However, the above choice is better because it constantly prompts the user to enter a new choice until a valid one is entered. Using the example below means you will have to close the program and start it up again if you enter an invalid choice which is stupid and will not get you any marks as it only tells the user their choice is invalid and does not prompt them to enter a valid one!
Actually, you are wrong. The menu loops until;
Loop Until Choice = "q"
Therefore it does actually work as the menu will just loop again. Actually try it!
Case "q"
Console.WriteLine("")
Case Else
Console.WriteLine("Choice is not valid")
' This message comes up for all other characters that are not in the "Select Case Choice"
To validate the user's choice:
Case "q"
Case Else
Console.WriteLine("Invalid input")
This is the Pascal/Delphi solution:
Answer:
Function ValidateText (usrtext:string):Boolean;
var
validate:Boolean;
Validinput:string;
count: integer;
Begin
validinput := 'abdeghjknq';
validate:=FALSE;
repeat
begin
if usrtext[1] = validinput[count] then
validate:=TRUE;
count:= count +1;
end;
until count = 10;
ValidateText:= validate;
end;
Alternatively, using a set:
function ChoiceIsValid(Choice:string):boolean;
var
valid:boolean;
begin
if choice[1] in ['a','b','d','e','g','h','j','k','n','q'] then
valid:=true
else
valid:=false;
ChoiceIsValid:=valid;
end;
5. The Caesar Cipher Encryption does not work for keys lower than -26. Fix this. Nor of course for keys over +26
This is the Visual Basic Solution:
Answer:
Function ApplyShiftToASCIICodeForCharacter(ByVal ASCIICode As Integer, ByVal AmountToShift As Integer) As Integer
Dim NewASCIICode As Integer
Dim TypeOfCharacter As String
TypeOfCharacter = GetTypeOfCharacter(ASCIICode)
'The following line uses modulo arithmetic to get the remainder of the input after it is divided by 26
'This is because at values above 26, it simply cycles back through the alphabet. F0r values below -26 it
'cycles back to the negative number ie (-28 Mod 26 = -2)
AmountToShift = AmountToShift Mod 26
If TypeOfCharacter <> "Other" Then
If TypeOfCharacter = "Upper" Then
'add 26 to cancel effect of negative keys
NewASCIICode = ((26 + ASCIICode - Asc("A") + AmountToShift) Mod 26) + Asc("A")
Else
'add 26 to cancel effect of negative keys
NewASCIICode = ((26 + ASCIICode - Asc("a") + AmountToShift) Mod 26) + Asc("a")
End If
Else
NewASCIICode = ASCIICode
End If
ApplyShiftToASCIICodeForCharacter = NewASCIICode
End Function
This is the Pascal/Delphi Solution
Answer:
Function ApplyShiftToASCIICodeForCharacter(ASCIICode, AmountToShift : Integer) : Integer;
Var
NewASCIICode : Integer;
TypeOfCharacter : String;
Begin
amounttoshift := amounttoshift mod 26;
TypeOfCharacter := GetTypeOfCharacter(ASCIICode);
If TypeOfCharacter <> 'Other'
Then
If TypeOfCharacter = 'Upper'
Then NewASCIICode := ((26 + ASCIICode - Ord('A') + AmountToShift) Mod 26) + Ord('A')
Else NewASCIICode := ((26 + ASCIICode - Ord('a') + AmountToShift) Mod 26) + Ord('a')
Else NewASCIICode := ASCIICode;
ApplyShiftToASCIICodeForCharacter := NewASCIICode;
End;
6. If a Zero or negative value of N is used the program will get stuck in an infinite loop - preventing this by requiring a positive value to be entered is easy and quite possible they will ask.
This is the Pascal/Delphi Solution
Answer:
Function GetValueForN : Integer;
Var
N : Integer;
Begin
repeat
Write('Enter the value of n: ');
Readln(N);
GetValueForN := N;
until N > 0;
End;
This is the Visual Basic Solution
Answer:
Function GetValueForN() As Integer
Dim N As Integer
Console.Write("Enter the value of n: ")
'The following Do loop repeats itself until the value for n is larger than 0
Do
N = Console.ReadLine
If N <= 0 Then
Console.WriteLine("Please enter a number greater than 0 for N")
End If
loop until N > 0
GetValueForN = N
End Function
7. There are several other examples where the range of an integer input is not checked but ought to be: StartPosition should be positive, EndPosition should be greater than StartPosition, the Caesar key should be between 1 and 25. These could all be straightforward questions. Perhaps write a generic range-checking function?
This is the Pascal/Delphi solution. It is a general function that can be called anywhere you need to check a number. It returns 0 if the number is not valid. This means it returns 0 if it is not a number and 0 if it is the number 0. This is because 0 is invalid even it if is a number as all of the numbers required in the system should be greater than 0.
Answer:
Function checkValidNumber(numberToCheck:string):integer;
var
convertedNumber:integer; //string number converted to an integer
begin
{try to see if the number is an integer. If it is and is above 0 assign it to
checkValidNumber }
try
convertednumber:=strToInt(NumberToCheck);
if convertedNumber>0 then
checkValidNumber := convertedNumber
else
checkValidNumber:=0;
except
//if itis not set checkValidNumber to 0.
checkValidNumber:=0;
end;
end;
An alternate form uses the Val procedure to avoid creating an exception
Function checkValidNumber(numberToCheck:string):integer;
var
convertedNumber:integer; //string number converted to an integer
code:integer;
begin
{try to see if the number is an integer. If it is and is above 0 assign it to
checkValidNumber }
val(NumberToCheck,convertednumber,code);
if code>0 then
checkValidNumber := 0;
else
checkValidNumber:=convertednumber;
end;
You can then call this anywhere eg as part of GetSizeOfRailFence. GetSizeOfRailFence has also been amended here to ensure that either plaintext or ciphertext exist, depending on what option the user has selected from the menu. I deemed the rail fence size invalid if no ciperh/plaint text existed or if the size was less than or equal to 1 as could see no point in having a rail fence of 1 as would just give it as it was originally.
Function GetSizeOfRailFence(MenuOption:char) : Integer;
{function that reads a number as a string, calls a function to check
it is a valid number. If it is it then checks to make sure the rail fence size
is is greater than 1 and less than the length of the plain/cipher text depending
on the menu optio chosen}
Var
SizeOfRailFence : Integer;
tempSize:string ; //tempVariable to hold size entered as a string
lengthText: Integer; //used to hold the length of the plain/cipher text
Begin
Write('Enter the number of lines in the rail fence: ');
//read the number entered into tempSize
Readln(tempSize);
//see if it is a valid number and assign the result to SizeOfRailFence
sizeOfRailFence:=checkvalidNumber(tempSize);
//If the user is encrypting then it is about plaintext
if upcase(menuOption)='H' then
//get the length of the plaintext
lengthtext:=length(Plaintext)
//otherwise it is about ciphertext
else
//get the length of the ciphertext
lengthtext:=length(Ciphertext);
{check to make sure it is greater than 1 and less than or equal to the length of the
plain/cipher text, otherwise encryption is not valid}
if (SizeOfRailFence <=1) or (SizeOfRailFence >= lengthText) then
begin
//If it is invalid set the size to 0
SizeOfRailFence:=0;
GetSizeOfRailFence := SizeOfRailFence;
end
else
//otherwise send the valid size back to the calling function
GetSizeOfRailFence := SizeOfRailFence;
End;
This is the VB.Net solution. It is a general function that can be called anywhere you need to check a number. It returns 0 if the number is not valid. This means it returns 0 if it is not a number and 0 if it is the number 0. This is because 0 is invalid even it if is a number as all of the numbers required in the system should be greater than 0.
Answer:
Function checkValidNumber(ByVal numberToCheck As String) As Integer
Dim convertedNumber As Integer 'string number converted to an integer
'try to see if the number is an integer. If it is and is above 0 assign it to
'checkValidNumber
Try
convertednumber = NumberToCheck
If convertedNumber > 0 then
checkValidNumber = convertedNumber
Else
checkValidNumber = 0
End If
Catch ex as Exception
'if it is not set checkValidNumber to 0.
checkValidNumber = 0
End Try
End Function
An alternate form uses the TryParse procedure to avoid creating an exception
Function checkValidNumber(ByVal numberToCheck As String) As Integer
Dim convertedNumber As Integer 'string number converted to an integer
Dim code As Integer
'try to see if the number is an integer. If it is and is above 0 assign it to
'checkValidNumber
If Integer.TryParse(NumberToCheck,convertednumber) then
checkValidNumber = convertednumber
Else
checkValidNumber = 0
End If
End Function
8. Cannot see this being something the students need to do but if anyone is interested here is the code to crack diary.txt.
Answer:
Procedure crackSteg;
var
MyFile:textfile;
begin
startPosition:=1;
endPosition:=1;
n:=GetSizeOfFile; // note wrote a function to do this. If you just want to check it out try 9 which is the example given by exam board
assignFile(myFile,'steg.txt');
rewrite(myFile);
repeat
repeat
repeat
Plaintext := EveryNthCharacterSteganography(StartPosition, EndPosition, N);
if (plaintext<>'') and (length(plaintext)>10) then
begin
writeln(Myfile,'Start is ',startPosition, ' End position is ',endPosition,' N is ',n);
writeln(MyFile,'The plain text is ',Plaintext))
end;
startPosition:=startPosition+1 ;
until startPosition>=endPosition;
startPosition:=1;
n:=n+1;
until n>endposition;
endPosition:=endPosition+1;
startPosition:=1;
n:=GetSizeOfFile; // note wrote a function to do this. If you just want to check it out try 9 which is the example given by exam board
until endPosition>getsizeoffile;
closefile(MyFile);
writeln('end');
end;
9. The Caesar Cipher Key (N) could also be validated using a "Type check" (signed integer), a "Range check"(-25 to +25), and a "Presence check"
Answer:
Function GetKeyForCaesarCipher() As Integer
Dim Key As Integer
Dim validKey As Boolean
Do
validKey = False
Console.Write("Enter the amount that shifts the plaintext alphabet to the ciphertext alphabet: ")
Try 'Trycatch will pick up TYPE and PRESSENCE checks
Key = Console.ReadLine
If Key >= -25 And Key <= 25 Then 'Range Check
validKey = True
Else
Console.WriteLine("Please enter a value between -25 and 25")
End If
Catch ex As Exception
validKey = False
Console.WriteLine("Please enter a signed integer between -25 and 25")
End Try
Loop Until validKey
GetKeyForCaesarCipher = Key
End Function
This is the Pascal/Delphi solution.
Answer:
Function GetKeyForCaesarCipher : Integer;
Var
strkey: string;
Key,interrorcode : Integer;
validKey : Boolean;
Begin
Repeat
Repeat
validKey := False;
Write('Enter the amount that shifts the plaintext alphabet to the ciphertext alphabet: ');
Readln(strKey);
val(strkey, key, intErrorCode);
if intErrorCode > 0 then writeln('Error in data type entered or no data entered',intErrorcode);
until intErrorCode = 0;
If (Key >= -25) And (Key <= 25) Then {This is the range check}
begin
validKey := True;
end
Else
begin
WriteLn('Please enter a value between -25 and 25')
end;
until validKey;
GetKeyForCaesarCipher := Key;
End;
10. The current menu has some missing letters/options (c, f, i, l and m). Maybe they could ask the following ...
Answer:
11. Add a new PLAINTEXT option (c) to read the plaintext from a text file. The user should choose the filename.
Answer:
Function GetPlaintextFromFile() As String
Dim TextFromFile As String
Dim CharacterFromFile As Char
Dim PlaintextName As String
Dim FileLength As Integer
Console.WriteLine("What file do you want to get plaintext from?")
PlaintextName = Console.ReadLine()
TextFromFile = ""
FileOpen(1, PlaintextName & ".txt", OpenMode.Binary)'This finds the file name which the user enters.
FileLength = FileLen(PlaintextName & ".txt") 'This gets the length of each file so the for loop knows where to end.
For Count = 1 To FileLength - 1' Counts from beginning to end of file
FileGet(1, CharacterFromFile)
TextFromFile = TextFromFile & CharacterFromFile
Next
FileClose(1)
GetPlaintextFromFile = TextFromFile
End Function
'Add this to the DisplayMenu()
Console.WriteLine(" c. Get plaintext from file")
'Add this to the Sub(Main)
Case "c"
Plaintext = GetPlaintextFromFile() 'This makes the subroutine's value equal to plaintext so other subroutines can access it.
Pascal/Delphi answer::
function getPlaintextFromFile : string;
var
Filename, resultstring : string;
Plaintext : TextFile;
CurrentCharacter : char;
begin
//get filename from user. won't stop until a valid one is entered.
repeat
writeln('Enter file name for the plaintext file.');
Filename := GetTextFromUser;
until (FileExists(Filename));
//assign file to filename
assignfile(Plaintext, Filename);
reset(PlainText);
//read file
resultstring := '';
while not eof(PlainText) do
begin
read(Plaintext, CurrentCharacter);
resultstring := resultstring + CurrentCharacter
end;
closefile(plaintext);
//return result string
getPlaintextFromFile := resultstring;
end;
12. Add a new CIPHERTEXT option (f) to read the ciphertext from a text file. The user should choose the filename.
Answer:
Function GetCiphertextFromFile() As String
Dim TextFromFile As String
Dim CharacterFromFile As Char
Dim CiphertextName As String
Dim FileLength As Integer
Console.WriteLine("What file do you want to get ciphertext from?")
CiphertextName = Console.ReadLine() 'Asks for filename to search for
TextFromFile = ""
FileLength = FileLen("U:/" & CiphertextName & ".txt") 'This gets the length of each file so the for loop knows where to end.
FileOpen(1, "U:/" & CiphertextName & ".txt", OpenMode.Binary)'This finds the file name which the user enters.
For Count = 1 To FileLength - 1' Counts from beginning to end of file
FileGet(1, CharacterFromFile)
TextFromFile = TextFromFile & CharacterFromFile
Next
FileClose(1)
GetCiphertextFromFile = TextFromFile
End Function
'Add this line into the appropriate part in DisplayMenu()
Console.WriteLine(" f. Get ciphertext from file")
'Add this line into the appropriate part of Main()
Case "f"
Ciphertext = GetCiphertextFromFile()
13. Add a new ENCRYPT option (i) to write the ciphertext to a text file. The user should choose the filename.
Answer:
Sub WriteCiphertextAsFile(ByVal Ciphertext As String)
Dim FileName As String
Console.WriteLine("What name do you want to give the file?")
FileName = "U:\" & Console.ReadLine() & ".txt" 'Writes a file into the directory
FileOpen(1, FileName, OpenMode.Binary) 'The FileOpen function writes an empty text based file (due to ".txt" being defined before) if no file is found.
FilePut(1, Ciphertext) 'Puts the Ciphertext stored into the file location.
FileClose(1)
End Sub
'Add this to the appropriate part in DisplayMenu()
Console.WriteLine(" i. Save ciphertext as file")
'Add this to the appropriate part to the Main()
Case "i"
WriteCiphertextAsFile(Ciphertext)
procedure SaveCiphertext(Ciphertext : string);
var
CiphertextFile : TextFile;
Filename : string;
i : integer; //iterator
begin
//get file name from user
writeln('Enter in a name for the ciphertext to be saved under.');
Filename := GetTextFromUser;
//assign file
assignfile(CiphertextFile, Filename);
rewrite(CiphertextFile);
//write ciphertext into file
write(CipherTextFile, CipherText);
closefile(CipherTextFile);
end;
14. Add a new DECRYPT option (l) to write the plaintext to a text file. The user should choose the filename.
Answer:
Sub WritePlaintextAsFile(ByVal Plaintext As String)
Dim FileName As String
Console.WriteLine("What name do you want to give the file?")
FileName = "U:\" & Console.ReadLine() & ".txt" 'Writes a file into the directory
FileOpen(1, FileName, OpenMode.Binary)'The FileOpen function writes an empty text based file (due to ".txt" being defined before) if no file is found
FilePut(1, Plaintext) 'Puts the Plaintext stored into the file location.
FileClose(1)
End Sub
'Add this to the appropriate part in DisplayMenu()
Console.WriteLine(" l. Save plaintext as file")
'Add this to the appropriate part in Main()
Case "l"
WritePlaintextAsFile(Plaintext)
15. Option (m). What could this be used for?
Answer:
16. Possibly add a new cipher altogether; some of the letters may also have been omitted for the purpose of confusing students.(e.g. vignere – but this requires a lot of work to set up).
Answer:
17. the steganography function can crash when you dont put sensible data in – so I guess we need to check file sizes and stuff.
Answer:
18. Maybe the option to multiple encrypt for added security . I.e. encrypt the encrypted text or combining different algorithms?
Answer:
'The following series of functions requires little modification and can be used to apply multiple levels of encryption for
'the plaintext
Case "i"
DisplayPlaintext(Plaintext)
SizeOfRailFence = GetSizeOfRailFence()
Ciphertext = EncryptUsingRailFence(Plaintext, SizeOfRailFence)
AmountToShift = GetKeyForCaesarCipher()
Ciphertext = UseCaesarCipher(Ciphertext, AmountToShift)
DisplayCiphertext(Ciphertext)
'This is the equivalent decryption code
Case "l"
DisplayCiphertext(Ciphertext)
AmountToShift = -GetKeyForCaesarCipher()
Plaintext = UseCaesarCipher(Ciphertext, AmountToShift)
SizeOfRailFence = GetSizeOfRailFence()
Plaintext = DecryptUsingRailFence(Plaintext, SizeOfRailFence)
DisplayPlaintext(Plaintext)
19. You can improve the caesar algorithm by randomizing the transposition (instead of it jumping by the same amount. If you ‘randomize(encryption_key)’ before generating random values both sender and receiver will get the same series of random transpositions)
Answer:
20. Add a new section to the menu called 'CRACK' with the options to crack either the 'ceaser' or 'rail fence'. Get some encrypted text from a fellow student and see (without knowing the encryption key) what the message is. In the case of the ceaser cipher you need to try 52 different keys (-26 to 26). In the case of the rail fence you need to try each value up to the number of characters in the cyphertext string. Make sure you utilise the existing decryption functions!
Answer:
This Code will crack RailFence
Case "p" 'Code to Crack Railfence
Dim x As Integer
Console.WriteLine("Please enter a code to crack.")
Ciphertext = Console.ReadLine
SizeOfRailFence = Len(Ciphertext)
For x = 1 To SizeOfRailFence
Console.WriteLine("Try number " & x & ".")
Plaintext = DecryptUsingRailFence(Ciphertext, x)
Console.WriteLine(Plaintext)
Next
To edit the code to crack the ceaser cipher: (By Quoc-Hau Pham. Student of CTKSFC Lewisham)
Case "l"
DisplayCiphertext(Ciphertext)
For AmountToShift = 1 To 26
Plaintext = UseCaesarCipher(Ciphertext, -AmountToShift)
Console.WriteLine(AmountToShift & ". " & Plaintext)
Next
Console.ReadLine()
Or you can do a function to crack the Caesar cipher.:
Function CaesarCipherCrack(ByVal Ciphertext As String)
Dim DecipheredText As String
Dim AmountToShift As Integer
For AmountToShift = -1 To -26 Step -1 ' all of the possible combinations
DecipheredText = UseCaesarCipher(Ciphertext, AmountToShift) 'uses the function they gave us hue hue hue
Console.WriteLine("The key attempted is: " & AmountToShift) ' informs the user what the key is
Console.WriteLine(DecipheredText)
Next
End Function ' by Woj & Kiran
'Add the following code to the case statement in the Main() Subroutine:
Case "c", "C"
CaesarCipherCrack(Ciphertext)
'Add the follwing code to the DisplayMenu Subroutine:
Console.WriteLine(" c. Crack Caesar's cipher")
'p' is the case I used for the menu, which can be changed. Just enter an encoded rail fence and it'll run all the possible rail numbers. Remember to add the option in your menu so a user can use it. NOTE: There is currently a bug where the program has trouble working with codes that haven't been encrypted in the same session. I'm working on a fix. If you fix it yourself, feel free to overwrite this. Fixed - it was decrypting the cyphertext variable whist assigning user input into plaintext
In Python 3:
def PossibleSizeOfRailFence(Ciphertext):
LengthOfCipherText = len(Ciphertext)
factors = []
for i in range(1,LengthOfCipherText+1):
if LengthOfCipherText % i == 0:
factors.append(i)
return factors
def CrackRailFence(Ciphertext,ListOfFactors):
for i in ListOfFactors:
Plaintext = DecryptUsingRailFence(Ciphertext, i)
print(Plaintext)
For cracking the Caesar cipher:
In Python 3:
def CrackCaesarCipher(Ciphertext):
for i in range(1,26):
Plaintext = UseCaesarCipher(Ciphertext, i)
print(Plaintext)
Caesar crack in pascal/delphi:
procedure CrackCiphertext(Ciphertext : string);
var
i : integer; //iterator (used as iterator for iterating iterations)
begin
writeln('This crack will try all possible ciphers. You are about to be bombarded with 55 lines of text.');
writeln('Any key to proceed');
readln;
//use ciphertext function in iterator to display every result
for i := -26 to 26 do
begin
writeln(UseCaesarCipher(Ciphertext, i));
end;
writeln('------------------');
end;
Rail fence crack in pascal/delphi:
procedure CrackCiphertextRailFence(Ciphertext : string);
var
i : integer; //itteerraaaaytor
begin
writeln('Every possible rail fence crack will be listed below.');
writeln('Press any key to continue.');
readln;
//for loop with the length of the ciphertext given
for i := 1 to length(Ciphertext) do
begin
writeln(DecryptUsingRailFence(Ciphertext, i));
end;
writeln('------------------');
end;
21. You can give a negative starting position and it returns the first character of the file repeatedly example: MMMMMMMMMMMMMMMaia rolled her eyes
Answer:
Function EveryNthCharacterSteganography(ByVal StartPosition As Integer, ByVal EndPosition As Integer, ByVal N As Integer) As String
Dim HiddenMessage As String
Dim CurrentPosition As Integer
'If less then 0 assign 0 so that we ignore negative start positions
If StartPosition < 0 Then
CurrentPosition = 0
Else
CurrentPosition = StartPosition
End If
HiddenMessage = ""
While CurrentPosition <= EndPosition
HiddenMessage = HiddenMessage & GetTextFromFile(CurrentPosition, CurrentPosition)
CurrentPosition = CurrentPosition + N
End While
EveryNthCharacterSteganography = HiddenMessage
End Function
22. For the Caesar Cipher, the Rail Fence and the input for StartPosition, EndPosition and N, it doesn't check that it is an integer.
Answer:
Function GetValueForN() As Integer
Dim N As Integer
'Extra string is added to use as a validation check
Dim userInput As String = ""
Console.Write("Enter the value of n: ")
Do
userInput = Console.ReadLine
If IsNumeric(userInput) Then
N = userInput
Else
Console.WriteLine("Invalid value for n")
Console.Write("Enter the value of n: ")
End If
Loop Until IsNumeric(userInput)
GetValueForN = N
End Function
The "userInput" variable can be used to validate the StartPosition and EndPosition parameters in the GetPositionToUse procedure as demonstrated above.
23. The EndPosition of the steganography section can be greater than the end of the text file.
Answer:
Function GetTextFromFile(ByVal StartPosition As Integer, ByVal EndPosition As Integer) As String
Dim CharacterFromFile As Char
Dim TextFromFile As String
Dim Count As Integer
FileOpen(1, "diary.txt", OpenMode.Binary)
Try
For Count = 1 To StartPosition - 1
FileGet(1, CharacterFromFile)
Next
TextFromFile = ""
For Count = StartPosition To EndPosition
FileGet(1, CharacterFromFile)
TextFromFile = TextFromFile & CharacterFromFile
Next
Catch ex As IO.EndOfStreamException
End Try
FileClose(1)
GetTextFromFile = TextFromFile
End Function
Pascal solution
Function GetTextFromFile(StartPosition, EndPosition:integer) : String;
Var
CharacterFromFile : Char;
TextFromFile : String;
Count: Integer;
CurrentFile : TextFile;
Begin
AssignFile(CurrentFile,'diary.txt');
Reset(CurrentFile);
Count:=1;
if StartPosition > 1
Then
while (count<StartPosition) and (not eof(CurrentFile)) do
begin
Read(CurrentFile, CharacterFromFile);
inc(count);
end;
TextFromFile := '';
while (count<=EndPosition) and (not eof(currentFile)) do
Begin
Read(CurrentFile, CharacterFromFile);
TextFromFile := TextFromFile + CharacterFromFile;
Inc(count);
End;
CloseFile(CurrentFile);
GetTextFromFile := TextFromFile;
End;
24. If the number of lines in the rail text entered is greater than the number of characters in plain text then the encryption doesn't work.
Answer:
VB.NET Solution
Function GetSizeOfRailFence(ByVal OriginalText As String) As Integer
Dim SizeOfRailFence As Integer
Dim LengthCheck As Boolean = True
' the variable to check for errord
Do While LengthCheck = True
LengthCheck = False
Console.Write("Enter the number of lines in the rail fence: ")
SizeOfRailFence = Console.ReadLine
If SizeOfRailFence >= OriginalText.Length Then
'Checks if the rail fence entered is greater than the length of the plaintext
Console.WriteLine("The railfence must be smaller than " + CStr(OriginalText.Length))
'Tells the user to enter a value less than the number of characters in plaintext
LengthCheck = True
End If
Loop
'Loops untill the rail fence is less than plaintext length
GetSizeOfRailFence = SizeOfRailFence
End Function
25. Add a parameter to the GetTextFromFile function to replace the hard-coded 'diary.txt" file name. Pass the file name to the function when it is called. Ask the user for the file name when option n is chosen.
Answer:
26. Combine the functions UseCaesarCipher, GetTypeOfCharacter and ApplyShiftToASCIICodeForCharacter into one function, that can also apply the cipher to numbers. Furthermore this function should also include any modifications to allow the entry of minus numbers under -26.
Answer:
'Ash ;-P
Function NewUseCaesarCipher(ByVal OriginalText As String, ByVal AmountToShift As Integer) As String
Dim ChangedText As String
Dim ASCIICode As Integer
ChangedText = ""
AmountToShift = AmountToShift Mod 26
For Count = 0 To OriginalText.Length - 1
ASCIICode = Asc(OriginalText(Count))
If ASCIICode >= Asc("A") And ASCIICode <= Asc("Z") Then
ASCIICode = ((ASCIICode - Asc("A") + AmountToShift) Mod 26) + Asc("A")
ElseIf ASCIICode >= Asc("a") And ASCIICode <= Asc("z") Then
ASCIICode = ((ASCIICode - Asc("a") + AmountToShift) Mod 26) + Asc("a")
ElseIf ASCIICode >= Asc("0") And ASCIICode <= Asc("9") Then
ASCIICode = ((ASCIICode - Asc("0") + AmountToShift) Mod 10) + Asc("0")
End If
ChangedText = ChangedText & Chr(ASCIICode)
Next
NewUseCaesarCipher = ChangedText
End Function
Credit to Ashley Tucker
Code provided by AQA is linked hereEdit
link on gmshaw's site
The file path issue should be able to be corrected by your teacher and they can agree the change with AQA and provide code that will find the file. This happens most years in VB6 and the simple addition of App.path & "\ to the front of the filename solves the problems as long as the file is in the same location as the program - AQA will agree to this change to be made.
SolutionsEdit
Stop program from freezing with N option - by iPhoneK1LLA (Like A Sir on Student Room)
If you run the raw code in Visual Studio, select option n, type 1, enter key, 208, enter key, 9, enter key, the application will crash. The solution to this problem is to view the 'GetTextFromFile' function
Function GetTextFromFile(ByVal StartPosition As Integer, ByVal EndPosition As Integer) As String
Dim CharacterFromFile As Char
Dim TextFromFile As String
Dim Count As Integer
FileOpen(1, "diary.txt", OpenMode.Binary) 'This needs to be changed to the full path of file to make it run
For Count = 1 To StartPosition - 1
FileGet(1, CharacterFromFile)
Next
TextFromFile = ""
For Count = StartPosition To EndPosition
FileGet(1, CharacterFromFile)
TextFromFile = TextFromFile & CharacterFromFile
Next
FileClose(1)
GetTextFromFile = TextFromFile
End Function
You need to look at this line
FileOpen(1, "diary.txt", OpenMode.Binary)
If you try and run this it will freeze. This needs to be changed to the FULL file location, so, for mine it would be
FileOpen(1, "C:\Users\iPhoneK1LLA\Dropbox\COMP4\COMP1 PM June 2013\diary.txt", OpenMode.Binary)
Run the program again and you'll see that the program now gives you 'MeeT ME at the coLD room'
CommentsEdit
1. Who put this all into 1 file? I was the first one to put it onto the site and it was all split up into its different subs, then someone changed it into one big chunk of text :( - iPhoneK1LLA
- You can split it up using <syntaxhighlight lang="vbnet"> and </syntaxhighlight>
2. This wasn't a problem running under Delphi/Pascal, I've just loaded the code and entered n, 1, 208 etc and it printed the meet me in the cold room, no crash??? CB
3. iPhoneK1LLA can you absolutely confirm the crash because "N=9 Start=1 End=208" works fine in python 2.5.6 OP
4. I'll upload a video in a second running the raw code for VB.Net - iPhoneK1LLA
5. It's not really a crash - it just can't find the file. Either alter the file path as has been suggested or place the diary.txt file into the debug/bin folder and it will work fine. There have been 'problems' like this in previous years. NK
- or you can set the copy to output setting in the propertys to copy allways 31.222.208.187 (discuss)
6. In relation to above, the program only crashes if the file is not present, or the file contains no text, which isn't a problem for the exam, but if you would like to make the program more robust then you need to add validation to check if the file exists and that the file contains more than 0 characters, such as a Catch and Try statement, or the following:
7. There needs to be solutions for python.
If Not System.IO.File.Exists("diary.txt") or filelen("diary.txt") < 1 Then
Console.WriteLine("diary.txt does not exsist")
Exit Function
End If