[.NET][C#]密碼學(Rail Fence cipher)

Rail Fence Cipher 籬笆式位移密碼,很接近劉伯溫燒餅歌內的藏頭詩的排列,來認識英文單字Rail Fence[籬笆]順便練習C#語法。

與凱撒、維吉尼亞加密法中的替代字母方式不同,Rail Fence Cipher是一種位移式密碼,從Wiki的案例秒懂:

原文:'WE ARE DISCOVERED. FLEE AT ONCE'

原文排列:   上到下,下到上~

加密後字串:

WECRL TEERD SOEEF EAOCA IVDEN


需要一個厲害的迴圈並且可以輸入列數Rails來處理:

string RailFenceEncryption(string PlainText, int RailCount)
{
    //Transposition cipher 
    //(1)依照輸入參數建立籬笆列
    List<List<string>> Rails = buildRails(RailCount);
    //(2)計算一圈路徑的長度
    int PLen = GetPathLength(RailCount);
    //(3)按照籬笆排列字母
    for (int i = 0; i < PlainText.Length; i++)
    {
        //取字元位置/路徑長度餘數大小來判讀是去程還是回程
        int j = i % PLen;  
        if (j < RailCount) //去程  
        {
            Rails[j].Add(PlainText.Substring(i, 1));
        }
        else               //回程  
        {
            Rails[PLen - j].Add(PlainText.Substring(i, 1));
        }
    }
    //(4)取出每一個籬笆排列內的字元
    StringBuilder sb = new StringBuilder();
    foreach (var Rail in Rails)
    {
        foreach (var s in Rail)
        {
            sb.Append(s);
        }
    }
    return sb.ToString();
}

會使用到的方法:

public List<List<string>> buildRails(int RailCount)
{
    List<List<string>> Rails = new List<List<string>>();
    //依照輸入參數建立籬笆列
    for (int k = 0; k < RailCount; k++)
    {
        Rails.Add(new List<string> { });
    }
    return Rails;
}

public int GetPathLength(int RailCount)
{
    //計算一圈路徑的長度(扣除出發點+結束點=2)  1->2->3->4->3->2->1 
    return (RailCount * 2) - 2;
}

 

加密測試程式:

string PlainTetx1 = "WEAREDISCOVEREDFLEEATONCE";
string CipherText1 = RailFenceEncryption(PlainTetx1, 3);
Console.WriteLine("PlainTetx:{0}", PlainTetx1);
Console.WriteLine("CipherText:{0}", CipherText1);


string PlainTetx2 = "123412341234";
string CipherText2 = RailFenceEncryption(PlainTetx2, 3);
Console.WriteLine("PlainTetx:{0}", PlainTetx2);
Console.WriteLine("CipherText:{0}", CipherText2);


string PlainTetx3 = "12345612345612345612345";
string CipherText3 = RailFenceEncryption(PlainTetx3, 4);
Console.WriteLine("PlainTetx:{0}", PlainTetx3);
Console.WriteLine("CipherText:{0}", CipherText3);


string PlainTetx4 = "12345678123456781234567812345";
string CipherText4 = RailFenceEncryption(PlainTetx4, 5);
Console.WriteLine("PlainTetx:{0}", PlainTetx4);
Console.WriteLine("CipherText:{0}", CipherText4);

加密測試結果:

這個網站真感心還有繪圖:

 

今天是新年後第一天上班,事情超多,晚上下班後頭昏昏,寫不出解密方程式,明晚再來補解密。

 

解密來了:

//(1)依照輸入參數建立籬笆列
List<List<string>> Rails = buildRails(RailCount);
//(2)計算一圈路徑的長度
int PLen = GetPathLength(RailCount);
//(3)計算商
int quotient = CipherText.Length / PLen;
//(4)計算餘數:不足一圈的單位距離
int remainder = CipherText.Length % PLen;
//(5)將字元填入每一個籬笆列
int offset = 0;
for (int i = 0; i < RailCount; i++)
{
    //籬笆排數
    int j = i + 1;
    //是否為第一排籬笆及最後一排籬笆
    bool isFirstAndLast = (j == 1 || j == RailCount);
    //第一排籬笆及最後一排籬笆(一個循環圈中,路徑只會走一次)
    int length = isFirstAndLast ? quotient : quotient * 2;
    //餘數
    if (j <= remainder)
    {
        length++;             //去程
        if (!isFirstAndLast)  //回程
        {
            //(中間點 - 出發點) * 2 = 折返距離 + 出發點 <= 餘數 
            if (((RailCount - j) * 2) + j <= remainder)
            {
                length++;
            }
        }
    }
    //依照個別籬笆長度放入字元
    for (int k = 0; k < length; k++)
    {
        Rails[i].Add(CipherText.Substring(offset, 1));
        offset++;
    }
}
StringBuilder sb = new StringBuilder();
//(6)按照籬笆排列取出字元
for (int i = 0; i < CipherText.Length; i++)
{
    //取字元位置/路徑長度餘數大小來判讀是去程還是回程
    int j = i % PLen;
    if (j < RailCount) //去程
    {
        if (Rails[j].Count > 0)
        {
            sb.Append(Rails[j][0]);
            Rails[j].RemoveAt(0);
        }
    }
    else              //回程
    {
        if (Rails[PLen - j].Count > 0)
        {
            sb.Append(Rails[PLen - j][0]);
            Rails[PLen - j].RemoveAt(0);
        }
    }
}
return sb.ToString();

解密測試方法: 分別測試3、4及5排

string CipherText1 = "WECRLTEERDSOEEFEAOCAIVDEN";
string PlainTetx1 = RailFenceDecryption(CipherText1, 3);
Console.WriteLine("CipherText:{0}", CipherText1);
Console.WriteLine("PlainTetx:{0}", PlainTetx1);

string CipherText2 = "11112626262353535354444";
string PlainTetx2 = RailFenceDecryption(CipherText2, 4);
Console.WriteLine("CipherText:{0}", CipherText2);
Console.WriteLine("PlainTetx:{0}", PlainTetx2);

string CipherText3 = "11112828282373737346464645555";
string PlainTetx3 = RailFenceDecryption(CipherText3, 5);
Console.WriteLine("CipherText:{0}", CipherText3);
Console.WriteLine("PlainTetx:{0}", PlainTetx3);

解密比較: 5 Rails。相符!

小結:

   多學會一種移位式密碼(Transposition cipher)

 

古典又經典密碼學分類:  呼....

 

Rail Fence

 

參考:

Rail fence cipher wiki

http://rumkin.com/tools/cipher/railfence.php