Skip to main content

  | मौसम…

411 समाचार
Public archive edition · Attributed source reporting with original dates · AI drafts are excluded

411 REFERENCE · Wikibooks

A-level Computing 2009/AQA/Problem Solving, Programming, Data Representation and Practical Exercise/Skeleton code/2013 Exam/Section D

Reference material by Wikibooks contributors. This retains its source identity and is not 411 news reporting.

Potential Questions 1. You could be asked to add an "r." function to reset the Plaintext and the Ciphertext variables. This is the VB.net Solution '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 #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: 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: 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: 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: 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: 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: 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: 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: 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 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 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 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. 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. 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. 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" 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. 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 ... 11. Add a new PLAINTEXT option (c) to read the plaintext from a text file. The user should choose the filename. 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. 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. 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. 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? 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). 17. the steganography function can crash when you dont put sensible data in – so I guess we need to check file sizes and stuff. 18. Maybe the option to multiple encrypt for added security . I.e. encrypt the encrypted text or combining different algorithms? '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) 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! 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 following 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 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. 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. 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. 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. 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. '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 here 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. Solutions 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' Comments 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> Also note that the code is probably copyrighted by the AQA and may not be allowed on wikibooks. Discussion around the code and potential questions are fine, for the moment use the link above to access it for all languages. Pluke (discuss • contribs) 08:52, 5 March 2013 (UTC) 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 than 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