Last modified on 26 May 2014, at 13:07

A-level Computing/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 :

'Add this to the end of the case select in sub Main
                Case "r"
                    Ciphertext = ""
                    Plaintext = ""
                    'If option R is selected then it will reset the
'Then Add this to the DisplayMenu Sub
        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 ceaser 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 encryted 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>
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 (discusscontribs) 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 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