日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

W密码解密算法

發(fā)布時(shí)間:2023/12/31 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 W密码解密算法 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

柵欄密碼

文章目錄

  • 柵欄密碼
    • 條形柵欄密碼
      • 加密算法
      • 解密算法
    • W形柵欄密碼
      • WWW加密算法設(shè)計(jì)
      • WWW解密算法推導(dǎo)
        • 確定字符對各行的分配規(guī)則cnt數(shù)組
          • 定義"周期"
          • 如果cntphasecnt_{phase}cntphase?是一個(gè)偶數(shù)
          • 如果cntphasecnt_{phase}cntphase?是一個(gè)奇數(shù)
          • 奇數(shù)和偶數(shù)時(shí)的區(qū)別
          • 總結(jié)成算法O(n)
        • 另一種更簡單的cnt數(shù)組的計(jì)算方式
        • 根據(jù)cnt數(shù)組指示,從密碼上連續(xù)截取相應(yīng)數(shù)量的字符
        • 方向指針解密
      • 完整算法

條形柵欄密碼

甚么是條形密碼?看完加密方法就有直觀的認(rèn)識了

加密算法

這里將柵欄橫著放用行l(wèi)ine表示,有0到h-1共h行對應(yīng)h個(gè)柵欄

設(shè)要加密的文本text,其字符下標(biāo)從0開始

然后text[0]分配給0號柵欄

text[1]分配給1號柵欄

text[n]分配給n號柵欄

text[h-1]分配給h-1號柵欄

text[h]分配給1號柵欄

text[h+1]分配給2號柵欄

以此類推

也就是說已知當(dāng)前行(柵欄號)為n則下一個(gè)柵欄應(yīng)該是(n+1)%h

最終text的字符被這樣輪流分配完畢,然后將各行按順序合并得到加密密碼

密碼=line[0]+line[1]+line[2]+...+line[h-1]

算法設(shè)計(jì):

bool isSpace(const char &c) {//忽略所有空格回車換行if (c == ' ' || c == '\n' || c == '\r')return true;return false; }//柵欄密碼算法 string fence_encrypt(const string &text, const int &cnt_fence) {//這里cnt_fence柵欄數(shù)就是前文的hstring fences[cnt_fence];int length = text.length();int now = 0;for (auto c : text) {if (isSpace(c))continue;fences[now] += c;//c放入當(dāng)前柵欄now = (now + 1) % cnt_fence;//now指向下一個(gè)柵欄的位置}string encrypted;for (int i = 0; i < cnt_fence; i++) {encrypted += fences[i];}return encrypted; }

解密算法

那拿來的放回哪里去,實(shí)際上解密算法和加密算法是完全相同的

string fence_decrypt(const string &encrypted, const int &cnt_fence) {string fences[cnt_fence];int length = encrypted.length();int now = 0;for (auto c : encrypted) {fences[now] += c;now = (now + 1) % cnt_fence;}string text;for (int i = 0; i < cnt_fence; i++) {text += fences[i];}return text; }

W形柵欄密碼

啥叫WWW加密呢?

區(qū)別于條形柵欄加密

條形柵欄加密:

將123456789A進(jìn)行深度為3(柵欄數(shù)為3)的條形柵欄加密得到

line[0]= 1 4 7 A line[1]= 2 5 8 line[2]= 3 6 9

密文為第0行+第1行+第2行=147A258369

注意實(shí)際編程的時(shí)候下標(biāo)從0開始

考慮用W形將明文123456789A加密,深度為3

line[0]= --1---5---9-- line[1]= ---2-4-6-8-A- line[2]= ----3---7----

密文為第0行+第1行+第2行=1592468A37

也就是說,方向是這樣的:

是個(gè)W形狀,因此叫做WWW加密算法

WWW加密算法設(shè)計(jì)

我們需要加密的明文為text,text[0]表示明文的第0個(gè)字符

當(dāng)深度為3的時(shí)候,

text[0]放在第0行

text[1]放在第1行

text[2]放在第2行

text[3]放在第1行

即text的字符會依次放在第0,1,2,1,0,1,2,1,0…行

規(guī)定一個(gè)方向指示director,下(+1),上(-1),表示下一個(gè)字符應(yīng)該放在當(dāng)前字符歸屬行的上一行還是下一行

這個(gè)方向只能在達(dá)到最高處(第0行)或者達(dá)到最低處(第h-1行)轉(zhuǎn)向,在中間的行(1到h-2行)只能遵守規(guī)定號的方向跳轉(zhuǎn),

這個(gè)過程神似穿針引線,從左上縫補(bǔ)到右下,然后到右上然后右下…

具體算法如下:

int now=0;//當(dāng)前行指針int director;//方向標(biāo)識for (auto c : text) {if (now == 0)director = 1;//如果當(dāng)前位置now在最高行則規(guī)定方向=1表示下一行應(yīng)往低處(0->h-1方向)跳轉(zhuǎn)else if (now == h - 1)director = -1;//如果當(dāng)前位置now在最低行則規(guī)定方向=-1表示下一行應(yīng)往高處(h-1->0)方向跳轉(zhuǎn)//注意這里沒有[2,h-2]這些行的條件判斷,意味著這些行不會修改director方向,只會遵守方向lines[now] += c;//字符c加入當(dāng)前行now = now + director;//根據(jù)director指示跳轉(zhuǎn)到下一行}

完整代碼:

string WWW_encrypt(const string &text, const int &h) {string lines[h];int length = text.length();int now = 0;int director;for (auto c : text) {if (now == 0)director = 1;else if (now == h - 1)director = -1;lines[now] += c;now = now + director;}string encrypted;for (int i = 0; i < h; i++) {//按照從0到h-1的順序?qū)⒏餍衅唇悠饋?/span>encrypted += lines[i];}return encrypted; }

WWW解密算法推導(dǎo)

還是觀察明文123456789A加密,深度為3的例子

line[0]= --1---5---9-- line[1]= ---2-4-6-8-A- line[2]= ----3---7----

密文為第0行+第1行+第2行=1592468A37

發(fā)現(xiàn)我們只需要還原出這三行的內(nèi)容來然后借用剛才加密的思想,使用方向指示就可以還原出未加密的文本

關(guān)鍵在于怎么確定這幾行每行的內(nèi)容是啥

密文的前三個(gè)159歸屬第0行

然后2468A五個(gè)歸屬于第1行,

然后37兩個(gè)歸屬于第2行,

貌似沒有規(guī)律,不能確定哪幾個(gè)歸屬于哪一行

但是可以確定的是,歸屬于同一行的字符一定挨著,并且最開始一定是歸屬于第一行的,然后是歸屬于第二行的,以此類推

確定字符對各行的分配規(guī)則cnt數(shù)組

定義"周期"

我們把紅框稱為"上周期",其中不含最低行(第h-1行)的字符
我們把黑框稱為"下周期",其中不含最高行(第0行)的字符

兩種周期的共同點(diǎn)是,每個(gè)周期里有h-1個(gè)字符,我們把"周期"作為"上周期"和"下周期"的籠統(tǒng)稱呼

兩種周期的差異點(diǎn)是上周期優(yōu)先填充(或者說分配)高處行,方向是高到低(0→h?10\rightarrow h-10h?1),下周期有限填充低處行,方向是(h?1→0h-1\rightarrow 0h?10)

現(xiàn)在給定密文長度為n,已知采用深度為h的加密方法

那么完整的"周期"數(shù)為cntphase=?nh?1?cnt_{phase}=\lfloor \frac{n}{h-1}\rfloorcntphase?=?h?1n??

如果cntphasecnt_{phase}cntphase?是一個(gè)偶數(shù)

則上下周期各占一半,cntupperphase=cntlowerphase=12cntphase=12?nh?1?cnt_{upperphase}=cnt_{lowerphase}=\frac{1}{2}cnt_{phase}=\frac{1}{2}\lfloor \frac{n}{h-1}\rfloorcntupperphase?=cntlowerphase?=21?cntphase?=21??h?1n??

到此,各行分到的字符數(shù)為

cnt[0]=cnt_upperphase; //最高行只在所有上周期中每個(gè)上周期獲得一個(gè)字符 cnt[1~h-2]=cnt_upperphase+cnt_lowerphase; //中間行在所有上下周期中都可以每個(gè)周期獲得一個(gè)字符 cnt[h-1]=cnt_lowerphase; //最低行只在所有下周期中每個(gè)下周期獲得一個(gè)字符

此時(shí)剩余沒有分配的字符數(shù)量為remain=n?cntphase×charactersperphase=n?cntphase×(h?1)=n??nh?1?×(h?1)remain=n-cnt_{phase}\times characters\ per\ phase=n-cnt_{phase}\times (h-1)=n-\lfloor \frac{n}{h-1}\rfloor\times (h-1)remain=n?cntphase?×characters?per?phase=n?cntphase?×(h?1)=n??h?1n??×(h?1)

如果remain=0說明所有字符恰好被完整個(gè)周期分配完畢,否則remain>0說明有剩余字符

這些剩余字符屬于一個(gè)新的上周期,因此第0到remain-1行各自拿走一個(gè)

到此,各行分到的字符數(shù)為

cnt[0]=cnt_upperphase+1; //最高行再獲取一個(gè) cnt[1~remain-1]=cnt_upperphase+cnt_lowerphase+1; //前remain行都各自再獲取一個(gè) cnt[remain~h-1]=cnt_upperphase+cnt_lowerphase; //此后各行保持不變 cnt[h-1]=cnt_lowerphase;

分配完畢

如果cntphasecnt_{phase}cntphase?是一個(gè)奇數(shù)

如果cntphasecnt_{phase}cntphase?是一個(gè)奇數(shù),則上周期比下周期多一個(gè)

cntlowerphase=?12cntphase?cnt_{lowerphase}=\lfloor\frac{1}{2}cnt_{phase}\rfloorcntlowerphase?=?21?cntphase??

cntupperphase=?12cntphase?=cntphase?cntlowerphasecnt_{upperphase}=\lceil\frac{1}{2}cnt_{phase}\rceil=cnt_{phase}-cnt_{lowerphase}cntupperphase?=?21?cntphase??=cntphase??cntlowerphase?,用計(jì)算機(jī)取上整數(shù)比較麻煩

顯然cntphasecnt_{phase}cntphase?是一個(gè)奇數(shù)時(shí)的計(jì)算方法同樣適用于偶數(shù)
{cntphase=?nh?1?cntlowerphase=?12cntphase?cntupperphase=?12cntphase?=cntphase?cntlowerphase\begin{cases} cnt_{phase}=\lfloor \frac{n}{h-1}\rfloor\\ cnt_{lowerphase}=\lfloor\frac{1}{2}cnt_{phase}\rfloor\\ cnt_{upperphase}=\lceil\frac{1}{2}cnt_{phase}\rceil=cnt_{phase}-cnt_{lowerphase}\end{cases} ??????cntphase?=?h?1n??cntlowerphase?=?21?cntphase??cntupperphase?=?21?cntphase??=cntphase??cntlowerphase??
到此,各行分到的字符數(shù)為

cnt[0]=cnt_upperphase; //最高行只在所有上周期中每個(gè)上周期獲得一個(gè)字符 cnt[1~h-2]=cnt_upperphase+cnt_lowerphase; //中間行在所有上下周期中都可以每個(gè)周期獲得一個(gè)字符 cnt[h-1]=cnt_lowerphase; //最低行只在所有下周期中每個(gè)下周期獲得一個(gè)字符

此時(shí)剩余沒有分配的字符數(shù)量為remain=n?cntphase×charactersperphase=n?cntphase×(h?1)=n??nh?1?×(h?1)remain=n-cnt_{phase}\times characters\ per\ phase=n-cnt_{phase}\times (h-1)=n-\lfloor \frac{n}{h-1}\rfloor\times (h-1)remain=n?cntphase?×characters?per?phase=n?cntphase?×(h?1)=n??h?1n??×(h?1)

如果remain=0說明所有字符恰好被完整個(gè)周期分配完畢,否則remain>0說明有剩余字符

這些剩余字符屬于一個(gè)新的下周期,因此第h-1到h-2+remain行各自拿走一個(gè)

到此各行分到的字符數(shù)為

cnt[0]=cnt_upperphase; cnt[1~h-remain-1]=cnt_upperphase+cnt_lowerphase //h-remain-1往上的行不變 cnt[h-remain~h-1]=cnt_upperphase+cnt_lowerphase+1; //[h-1,h-remain]行均從新的下周期中獲得一個(gè)字符 cnt[h-1]=cnt_lowerphase+1; //最低行在新的下周期中獲得一個(gè)字符
奇數(shù)和偶數(shù)時(shí)的區(qū)別

由于奇數(shù)時(shí)計(jì)算周期的公式同樣適用于偶數(shù)
{cntphase=?nh?1?cntlowerphase=?12cntphase?cntupperphase=?12cntphase?=cntphase?cntlowerphase\begin{cases} cnt_{phase}=\lfloor \frac{n}{h-1}\rfloor\\ cnt_{lowerphase}=\lfloor\frac{1}{2}cnt_{phase}\rfloor\\ cnt_{upperphase}=\lceil\frac{1}{2}cnt_{phase}\rceil=cnt_{phase}-cnt_{lowerphase}\end{cases} ??????cntphase?=?h?1n??cntlowerphase?=?21?cntphase??cntupperphase?=?21?cntphase??=cntphase??cntlowerphase??
因此在兩種情況,只有在處理最后剩下的不完整的新周期時(shí),才有不同,

不同的原因是上下周期分配字符的方向和起點(diǎn)不同

總結(jié)成算法O(n)
vector<int> allocate(const int &n, const int &h) { //n個(gè)字符,加密深度為hvector<int> cnt(h);int cnt_phase = n / (h - 1);int cnt_lowerphase = cnt_phase / 2;int cnt_upperphase = cnt_phase - cnt_lowerphase;cnt[0] = cnt_upperphase;cnt[h - 1] = cnt_lowerphase;for (int i = 1; i <= h - 2; i++) {cnt[i] = cnt_phase;}int remain = n - cnt_phase * (h - 1);if (remain == 0)return cnt;if (cnt_phase % 2 == 0) {for (int i = 0; i <= remain - 1; ++i)++cnt[i];} else {for (int i = h - 1; i >= h - remain; --i)++cnt[i];}return cnt; }

以1592468A37為例驗(yàn)證:

#include <iostream> #include <vector> #include <algorithm> using namespace std; vector<int> allocate(const int &n, const int &h);//詳見上文 int main() {string text = "1592468A37";vector<int> cnt = allocate(text.length(), 3);for (auto i : cnt)cout << i << " ";return 0; }

結(jié)果

3 5 2

是正確的

另一種更簡單的cnt數(shù)組的計(jì)算方式

注意到

vector<int> allocate(const int &n, const int &h);

這個(gè)函數(shù)并沒有獲取密碼的具體字符信息,而是只給定了密碼長度和加密深度,就可以求出一個(gè)cnt數(shù)組

也就是說,cnt數(shù)組和密碼是什么字符沒有關(guān)系

那么我們豈不是可以正著來,直接用加密算法求得cnt數(shù)組?

給加密算法encrypt函數(shù)傳入一個(gè)n位長的任意字符串可以求得各行分配到的字符,自然也就求得了各行應(yīng)該分配的字符個(gè)數(shù)

也就是說,不管是對123456789還是987654321加密,其排列出的W的形狀是相同的

我們現(xiàn)有的加密算法:

string WWW_encrypt(const string &text, const int &h) {string lines[h];int length = text.length();int now = 0;int director;//方向指示標(biāo)記for (auto c : text) {if (now == 0)director = 1;else if (now == h - 1)director = -1;lines[now] += c;now = now + director;}string encrypted;for (int i = 0; i < h; i++) {encrypted += lines[i];}return encrypted; }

只需要對其進(jìn)行一些改造

vector<int> allocate(const int &n, const int &h) {vector<int> cnt(h);int director;//方向指示標(biāo)記int now = 0;for (int i = 1; i <= n; i++) {if (now == 0)director = 1;else if (now == h - 1)director = -1;++cnt[now];now = now + director;}return cnt; }

于是同樣用O(n)O(n)O(n)甚至更實(shí)際更優(yōu)于前一種的方法出現(xiàn)了

根據(jù)cnt數(shù)組指示,從密碼上連續(xù)截取相應(yīng)數(shù)量的字符

根據(jù)剛才我們推測得到的算法,

第0行應(yīng)當(dāng)截取密碼的從0開始,長度為cnt[0]這一段字串encrypted.substr(0,cnt[0]);

第1行應(yīng)從第0行截取剩下的開始截取,長度為cnt[1]這一字串encrypted.substr(cnt[0],cnt[1])

以此類推,第n行應(yīng)該截取encrypted.substr(cnt[0]+cnt[1]+....+cnt[n-1],cnt[n])

line[0]=encrypted.substr(0,cnt[0]); line[n]=encrypted.substr(length,cnt[n]); length=sum(cnt[0],cnt[1],...,cnt[n-1]);

總結(jié)算法:

vector<string> getLines(const string &encrypted, const int &h) {vector<string> line(h);vector<int> cnt = allocate(encrypted.length(), h);line[0] = encrypted.substr(0, cnt[0]);int length = 0;//累加前面的字串長度for (int i = 1; i <= h - 1; i++) {length += cnt[i - 1];//累加line[i] = encrypted.substr(length, cnt[i]);}return line; }

方向指針解密

現(xiàn)在各行都已經(jīng)求出來了,得到了我們想象中的這樣的結(jié)構(gòu):

line[0]= --1---5---9-- line[1]= ---2-4-6-8-A- line[2]= ----3---7----

實(shí)際上是這樣的:

line[0]=1,5,9 line[1]=2,4,6,8,A line[2]=3,7

現(xiàn)在又到了穿針引線的時(shí)間,director指示跳轉(zhuǎn)的方向,每行還需要維護(hù)一個(gè)標(biāo)記,記錄當(dāng)前行應(yīng)該取哪個(gè)字符了,方便下一次取

什么意思呢?具體來說

注意下標(biāo),排名都是從0開始

初始時(shí)各行的標(biāo)記mark[i]=0都是0,意思是,如果要取,肯定從首個(gè)(第0個(gè))字符開始

從第0行開始取direction置1,取第0個(gè)元素1,++mark[0],意思是第一行的首個(gè)元素已經(jīng)取出,如果下次跳轉(zhuǎn)到第一行取數(shù)時(shí)應(yīng)該取下一個(gè)元素

按照direction=1下跳到第2行,取第0個(gè)元素2,++mark[1],意思時(shí)第二行的首個(gè)元素已經(jīng)取出,如果下次跳轉(zhuǎn)到第二行取數(shù)時(shí)應(yīng)該取下一元素

按照direction=1下跳到第2行,置direction=-1,取第0個(gè)元素3,++mark[2],意思時(shí)第二行的首個(gè)元素已經(jīng)取出,如果下次跳轉(zhuǎn)到第二行取數(shù)時(shí)應(yīng)該取下一元素

按照direction=-1上跳到第1行,取第1個(gè)元素4,++mark[1],意思是第二行的第二個(gè)元素已經(jīng)取出,如果下次跳轉(zhuǎn)到第二行取數(shù)時(shí)應(yīng)該取下一元素

string decrypt(const string &encrypted, const int &h) {vector<string>line = getLines(encrypted, h);int length = encrypted.length();int director = 0;int now = 0;int mark[h];for (int i = 0; i < h; i++) {mark[i] = 0;//mark數(shù)組置0}string decrypted;for (int i = 0; i < length; i++) {if (now == 0)director = 1;else if (now == h - 1)director = -1;decrypted += line[now][mark[now]];++mark[now];//當(dāng)前行標(biāo)記后移now += director;//now按照director指示跳轉(zhuǎn)}return decrypted; }

完整算法

#include <iostream> #include <vector> #include <algorithm> using namespace std;vector<int> allocate(const int &n, const int &h) { //n個(gè)字符,加密深度為hvector<int> cnt(h);int cnt_phase = n / (h - 1);int cnt_lowerphase = cnt_phase / 2;int cnt_upperphase = cnt_phase - cnt_lowerphase;cnt[0] = cnt_upperphase;cnt[h - 1] = cnt_lowerphase;for (int i = 1; i <= h - 2; i++) {cnt[i] = cnt_phase;}int remain = n - cnt_phase * (h - 1);if (remain == 0)return cnt;if (cnt_phase % 2 == 0) {for (int i = 0; i <= remain - 1; ++i)++cnt[i];} else {for (int i = h - 1; i >= h - remain; --i)++cnt[i];}return cnt;}vector<string> getLines(const string &encrypted, const int &h) {vector<string> line(h);vector<int> cnt = allocate(encrypted.length(), h);line[0] = encrypted.substr(0, cnt[0]);int length = 0;for (int i = 1; i <= h - 1; i++) {length += cnt[i - 1];line[i] = encrypted.substr(length, cnt[i]);}return line; }string decrypt(const string &encrypted, const int &h) {vector<string>line = getLines(encrypted, h);int length = encrypted.length();int director = 0;int now = 0;int mark[h];for (int i = 0; i < h; i++) {mark[i] = 0;}string decrypted;for (int i = 0; i < length; i++) {if (now == 0)director = 1;else if (now == h - 1)director = -1;decrypted += line[now][mark[now]];++mark[now];now += director;}return decrypted; }int main() {string text = "1592468A37";cout << decrypt(text, 3);return 0; }

總結(jié)

以上是生活随笔為你收集整理的W密码解密算法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。