Playfair Cipher in Navision

As earlier mentioned I have being reading some books about Cryptology – and now its Playfairs turn to be tested in Navision :-)

Playfair Cipher (aka. Playfair square) is a symmetric encryption technique and was the first literal digraph substitution cipher. It was invented by Charles Wheatstone and popularized by Lyon Playfair.

The technique encrypts pairs of letters instead of single letters, which means it is a type of digraph cipher.

The Playfair Cipher is significantly harder to break since the frequency analysis used for simple substitution ciphers does not work with it. So its no wonder, that is was used during both the first and second world war.

Lets take a closer look. First we have to choose a key, as example we will use “JULEMANDEN”.
The Playfair cipher uses a 5 by 5 table containing a key word or phrase, where the phrase normally will be the alphabet. So the key “JULEMANDEN” will become:

I U L E M
A N D B C
F G H K O
P Q R S T
V W X Y Z

How did this key be generated? Well first we took JULEMANDEN and removed duplicated letters – after this we where left with JULEMAND.

Next we replaced J with I. J & I are represented by the same letter.

Finally we split it up into a 5 x 5 square, and filled the missing field values with letters from the alphabet.

This is how it could be done in Navision:

//convert j to i
inKey := CONVERTSTR(inKey,’j’,’i’);

//Remove duplicates
FOR i := 1 TO STRLEN(inKey) DO BEGIN
……IF STRPOS(outKey,FORMAT(Key[i])) = 0 THEN
………..outKey += FORMAT(inKey[i]);
END;

//Put in fill chars
alphabet := ‘abcdefghiiklmnopqrstuvwxyz';
aIndex := 1;
WHILE STRLEN(outKey) < 25 DO BEGIN ……IF STRPOS(outKey, FORMAT(alphabet[aIndex])) = 0 THEN
………..outKey += FORMAT(alphabet[aIndex]);
……aIndex += 1;
END;

Now that the key is in place, we will focus on the encryption.

Lets try to encrypt the text: “this is encrypted”. Before the text can be encrypt it has to prepared. The preparation will go through the following steps:

  • Remove spaces
  • Remove unsupported letters. Ex. dot, numbers and localized letters ex. æøå
  • Replace j with i
  • If two letters are the same, then add a X. Ex. “this show” would be “this xshow”
  • If text length is odd then add a X to the end

Finally break the message into digraphs (groups of 2 letters). So before starting the encryption the prepared text would look like this:

Text: this is encrypted
Prepared Text: th is is en cr yp te dx

And as an Navision example:

orgText := LOWERCASE(orgText);

//Remove not supported signs – only letters are supported!
orgText := DELCHR(orgText,’=’,’ .,0123456789æøå’);
orgText := CONVERTSTR(orgText,’j’,’i’);

//If the seond letter of a pair is the same as the first letter, then use x.
i := 1;
WHILE i <= STRLEN(orgText) DO BEGIN ……nextChar := FORMAT(orgText[i]);
……IF (i > 1) THEN
………..IF orgText[i] = orgText[i-1] THEN
…………….nextChar := ‘x’ + FORMAT(orgText[i]);

……preText += nextChar;
……i += 1;
END;

//If string length is odd then add x
IF (STRLEN(preText) MOD 2) = 1 THEN
……preText += ‘x';

Now lets do the encryption by looking on the individual groups and their placement in the key.
To encrypt a group we use the following rules:

  • Is both letters in the same Row? If yes then take the next letter in the row
  • Is both letters in the same Column? If yes then take the next letter in the column
  • If none off the above occur, the rule differs. To encrypt the first letter, look along its row until the column containing the second letter is reached – the letter at this intersection replaces the first letter. To encrypt the second letter, look along its row until the column containing the first letter is reached – the letter at this intersection replaces the second letter. Hence, ‘th’ becomes ‘ro’.

The encrypted text will therefor become:

Text: this is encrypted
Encrypted: ro ep ep ub dt vs sm hl

This is how it could be done in Navision:

i := 1;
FOR i := 1 TO STRLEN(preText) DO BEGIN

……Index1 := STRPOS(KeyIndex,FORMAT(preText[i]));
……row1 := ROUND(Index1 / 5,1,’>’);
……col1 := Index1 MOD 5;
……IF col1 = 0 THEN col1 := 5;

……Index2 := STRPOS(KeyIndex,FORMAT(preText[i+1]));
……row2 := ROUND(Index2 / 5,1,’>’);
……col2 := Index2 MOD 5;
……IF col2 = 0 THEN col2 := 5;

……i += 1;

……//The letters are in the same Row
……IF row1 = row2 THEN BEGIN
………..colpos := NextPos(col1);
………..Index1 := ((row1 – 1) * 5) + colpos;

………..colpos := NextPos(col2);
………..Index2 := ((row2 – 1) * 5) + colpos;

………..crypText += (FORMAT(KeyIndex[Index1]) + FORMAT(KeyIndex[Index2]));

……//The Letters are in the same Column
……END ELSE IF col1 = col2 THEN BEGIN
………..rowpos := NextPos(row1);
………..Index1 := ((rowpos – 1) * 5) + col1;

………..rowpos := NextPos(row2);
………..Index2 := ((rowpos – 1) * 5) + col2;

………..crypText += (FORMAT(KeyIndex[Index1]) + FORMAT(KeyIndex[Index2]));

……//Letters are in a square
……END ELSE BEGIN
………..rowpos := NextPos(row1 – 1);
………..Index1 := ((rowpos – 1) * 5) + col2;

………..rowpos := NextPos(row2 – 1);
………..Index2 := ((rowpos – 1) * 5) + col1;

………..crypText += (FORMAT(KeyIndex[Index1]) + FORMAT(KeyIndex[Index2]));
……END;

END;

Where NextPos is calculated in this way:

NewPos := (Pos + 1) MOD 5;
IF NewPos = 0 THEN
……NewPos := 5;

To decrypt – just do the inverse ;-)

Now you are able to encrypt with Playfair in Navision.

You can leave a response, or trackback from your own site.

5 Responses to “Playfair Cipher in Navision”

  1. Gonzalio says:

    An еxcеllеnt sitе! And not badly madе. The main thing that thе information on it useful, I will go into free timе … Good luck to you all!

  2. guidorobben says:

    Hi,

    Could I be possible to add the types of the variables? Or maybe a working example?

  3. iby says:

    Hi,

    I had to do some digging… but finally I found my sample code…
    So here you are:

    
    
    OBJECT Codeunit 50300 Playfair Cipher
    
    {
    
      OBJECT-PROPERTIES
    
      {
    
        Date=16-11-08;
    
        Time=19:49:42;
    
        Modified=Yes;
    
        Version List=;
    
      }
    
      PROPERTIES
    
      {
    
        OnRun=BEGIN
    
     
                Key := 'julemanden';
    
                KeyIndex := GenerateKeyIndex(Key);
    
     
                OrigText := 'This text should be encrypted';
    
                prepText := PrepareText(OrigText);
    
                EncryptText := Encrypt(prepText);
    
                DecryptText := Decrypt(EncryptText);
    
                MESSAGE('origtext: ' + OrigText + '\Prep: ' + prepText + '\Encrypted: ' + EncryptText + '\Decrypt: ' + DecryptText);
    
              END;
    
     
      }
    
      CODE
    
      {
    
        VAR
    
          KeyIndex@1112800000 : Text[25];
    
          Key@1112800001 : Text[30];
    
          OrigText@1112800002 : Text[250];
    
          EncryptText@1112800003 : Text[250];
    
          prepText@1112800004 : Text[250];
    
          DecryptText@1112800005 : Text[250];
    
     
        PROCEDURE GenerateKeyIndex@1112800001(inKey@1112800000 : Text[25]) outKey : Text[25];
    
        VAR
    
          i@1112800001 : Integer;
    
          aIndex@1112800003 : Integer;
    
          alphabet@1112800002 : Text[30];
    
        BEGIN
    
          inKey := CONVERTSTR(inKey,'j','i');
    
     
          //Remove duplicates
    
          FOR i := 1 TO STRLEN(inKey) DO BEGIN
    
            IF STRPOS(outKey,FORMAT(Key[i])) = 0 THEN
    
              outKey += FORMAT(inKey[i]);
    
          END;
    
     
          //Put in fill chars
    
          alphabet := 'abcdefghiiklmnopqrstuvwxyz';
    
          aIndex := 1;
    
          WHILE STRLEN(outKey) < 25 DO BEGIN
    
            IF STRPOS(outKey, FORMAT(alphabet[aIndex])) = 0 THEN
    
              outKey += FORMAT(alphabet[aIndex]);
    
            aIndex += 1;
    
          END;
    
        END;
    
     
        PROCEDURE PrepareText@1112800000(orgText@1112800000 : Text[250]) preText : Text[250];
    
        VAR
    
          i@1112800001 : Integer;
    
          nextChar@1112800002 : Text[2];
    
        BEGIN
    
     
          orgText := LOWERCASE(orgText);
    
     
          //Remove not supported signs - only letters are supported!
    
          orgText := DELCHR(orgText,'=',' .,0123456789‘›†');
    
          orgText := CONVERTSTR(orgText,'j','i');
    
     
          //If the seond letter of a pair is the same as the first letter, then use x.
    
          i := 1;
    
          WHILE i <= STRLEN(orgText) DO BEGIN
    
     
            nextChar := FORMAT(orgText[i]);
    
            IF (i > 1) THEN
    
              IF orgText[i] = orgText[i-1] THEN
    
                nextChar := 'x' + FORMAT(orgText[i]);
    
     
            preText += nextChar;
    
            i += 1;
    
          END;
    
     
          //If string length is odd then add x
    
          IF (STRLEN(preText) MOD 2) = 1 THEN
    
            preText += 'x';
    
        END;
    
     
        PROCEDURE Encrypt@1112800002(VAR preText@1112800002 : Text[250]) crypText : Text[250];
    
        VAR
    
          i@1112800001 : Integer;
    
          row1@1112800003 : Integer;
    
          row2@1112800000 : Integer;
    
          col1@1112800004 : Integer;
    
          col2@1112800005 : Integer;
    
          Index1@1112800008 : Integer;
    
          Index2@1112800009 : Integer;
    
          colpos@1112800012 : Integer;
    
          rowpos@1112800013 : Integer;
    
        BEGIN
    
     
          i := 1;
    
          FOR i := 1 TO STRLEN(preText) DO BEGIN
    
     
            Index1 := STRPOS(KeyIndex,FORMAT(preText[i]));
    
            row1 := ROUND(Index1 / 5,1,'>');
    
            col1 := Index1 MOD 5;
    
            IF col1 = 0 THEN col1 := 5;
    
     
            Index2 := STRPOS(KeyIndex,FORMAT(preText[i+1]));
    
            row2 := ROUND(Index2 / 5,1,'>');
    
            col2 := Index2 MOD 5;
    
            IF col2 = 0 THEN col2 := 5;
    
     
            i += 1;
    
     
            //The letters are in the same Row
    
            IF row1 = row2 THEN BEGIN
    
              colpos := NextPos(col1);
    
              Index1 := ((row1 - 1) * 5) + colpos;
    
     
              colpos := NextPos(col2);
    
              Index2 := ((row2 - 1) * 5) + colpos;
    
     
              crypText += (FORMAT(KeyIndex[Index1]) + FORMAT(KeyIndex[Index2]));
    
     
            //The Letters are in the same Column
    
            END ELSE IF col1 = col2 THEN BEGIN
    
              rowpos := NextPos(row1);
    
              Index1 := ((rowpos - 1) * 5) + col1;
    
     
              rowpos := NextPos(row2);
    
              Index2 := ((rowpos - 1) * 5) + col2;
    
     
              crypText += (FORMAT(KeyIndex[Index1]) + FORMAT(KeyIndex[Index2]));
    
     
            //Letters are in a square
    
            END ELSE BEGIN
    
              rowpos := NextPos(row1 - 1);
    
              Index1 := ((rowpos - 1) * 5) + col2;
    
     
              rowpos := NextPos(row2 - 1);
    
              Index2 := ((rowpos - 1) * 5) + col1;
    
     
              crypText += (FORMAT(KeyIndex[Index1]) + FORMAT(KeyIndex[Index2]));
    
            END;
    
     
          END;
    
        END;
    
     
        PROCEDURE Decrypt@1112800003(VAR preText@1112800002 : Text[250]) crypText : Text[250];
    
        VAR
    
          i@1112800001 : Integer;
    
          row1@1112800003 : Integer;
    
          row2@1112800000 : Integer;
    
          col1@1112800004 : Integer;
    
          col2@1112800005 : Integer;
    
          Index1@1112800008 : Integer;
    
          Index2@1112800009 : Integer;
    
          colpos@1112800012 : Integer;
    
          rowpos@1112800013 : Integer;
    
        BEGIN
    
     
          i := 1;
    
          FOR i := 1 TO STRLEN(preText) DO BEGIN
    
     
            Index1 := STRPOS(KeyIndex,FORMAT(preText[i]));
    
            row1 := ROUND(Index1 / 5,1,'>');
    
            col1 := Index1 MOD 5;
    
            IF col1 = 0 THEN col1 := 5;
    
     
            Index2 := STRPOS(KeyIndex,FORMAT(preText[i+1]));
    
            row2 := ROUND(Index2 / 5,1,'>');
    
            col2 := Index2 MOD 5;
    
            IF col2 = 0 THEN col2 := 5;
    
     
            i += 1;
    
     
            //The letters are in the same Row
    
            IF row1 = row2 THEN BEGIN
    
              colpos := NextPos2(col1);
    
              Index1 := ((row1 - 1) * 5) + colpos;
    
     
              colpos := NextPos2(col2);
    
              Index2 := ((row2 - 1) * 5) + colpos;
    
     
              crypText += (FORMAT(KeyIndex[Index1]) + FORMAT(KeyIndex[Index2]));
    
     
            //The Letters are in the same Column
    
            END ELSE IF col1 = col2 THEN BEGIN
    
              rowpos := NextPos(row1);
    
              Index1 := (rowpos * 5) + col1;
    
     
              rowpos := NextPos(row2);
    
              Index2 := (rowpos * 5) + col2;
    
     
              crypText += (FORMAT(KeyIndex[Index1]) + FORMAT(KeyIndex[Index2]));
    
     
            //Letters are in a square
    
            END ELSE BEGIN
    
              rowpos := NextPos(row2 - 1);
    
              Index2 := ((rowpos - 1) * 5) + col1;
    
     
              rowpos := NextPos(row1 - 1);
    
              Index1 := ((rowpos - 1) * 5) + col2;
    
     
              crypText += (FORMAT(KeyIndex[Index1]) + FORMAT(KeyIndex[Index2]));
    
            END;
    
     
          END;
    
        END;
    
     
        PROCEDURE "**** Help functions *****"@1112800004();
    
        BEGIN
    
        END;
    
     
        PROCEDURE NextPos@1112800005(Pos@1112800000 : Integer) NewPos : Integer;
    
        BEGIN
    
     
          NewPos := (Pos + 1) MOD 5;
    
     
          IF NewPos = 0 THEN
    
            NewPos := 5;
    
        END;
    
     
        PROCEDURE NextPos2@1112800006(Pos@1112800000 : Integer) NewPos : Integer;
    
        BEGIN
    
     
          NewPos := (Pos - 1) MOD 5;
    
     
          IF NewPos = 0 THEN
    
            NewPos := 5;
    
        END;
    
     
        BEGIN
    
        END.
    
      }
    
    }
    
     
    
    

  4. antivirusqzwzd says:

    Very informative post. Thanks for taking the time to share your view with us.

  5. aspinnaTeapse says:

    Just looked through the thread! Awesome work.

Leave a Reply


+ 6 = twelve