前言:

  這是最近看 Paper 時看到的方法,有別於以往的先壓縮再加密,這是一個同時達到加密跟壓縮的方式,且概念相當簡單,只是運用簡單的亂數產生就能達成,非常聰明且漂亮的想法,特此介紹。

亂數:

  標題有個關鍵字是 Chaos-Based,這個的意思就是使用亂數的方法來達成,大家都知道電腦中所謂的亂數其實並不是真正的亂數,而是 Pseudo Random,因為要讓電腦產生真正的亂數基本上不可能,連人自己要產生真正的亂數都不太可能了,更何況電腦,所以在電腦中實作亂數的方法就是找一些簡單的數學式子,這些式子帶出來的結果會無法預測,且跟初始條件或參數有極高的敏感性。意思就是是如果初始條件或參數差了一點點,但結果可能就會差的十萬八千里遠。電腦透過運算這樣的函數,來計算出要丟出來的亂數是多少。

  在這裡我們使用的亂數產生是 Logistic Map,以下是他的式子,可以注意到它的運算非常簡單,要算出下一項只要透過簡單的乘法即可,不過要注意的是 r 需要在 3.6 ~ 4 之間較好,他還有一個好的特性是每一項都會在零跟一之間。

  

  以下展示此函數的第100項到第110項的值,看起來很像還不夠亂的原因是還太前面了,通常都會取個1000項之後就看不太出來了。

  

演算法:

  知道怎樣得到亂數之後,直接就進入他的想法吧,它主要的想法是先把一個區間切成好幾個小塊,每一塊有對應的數字等,機率高的符號,會佔比較多塊,相對的機率低得就比較少塊。並且用 Logistic Map 去產生亂數,看看產生出來的亂數對應的區塊是不是要的,如果不是就修正並重複剛剛的動作繼續往下對應,其中再找到對應之前所花的次數就是密文。因為機率高的符號,被對應到的機率也高,所以可以用比較少的次數對應到,相對的就是比較短的 bit 長度,而機率低的就會有比較長的 bit 數,達到壓縮效果。

  相信到這裡大家還是不太明白,我們來看一個簡單的例子,假設A出現的機率是1/2,B是1/4,C跟D都是1/8,則整個區塊會被切成如下第一張圖,假設我們現在要找的是C,第一次運氣不好用 Logistic Map 產生的亂數落在A區塊,則把A改成除A之外最大機率的值,以例子來說是B,繼續下去,直到找到為止,找到之後這中間尋找的次數就是C加密過後的結果,以例子來說就是3。找完之後把整個區塊恢復原狀再繼續往下加密。

  

  這個方法還有一些先天上的好處,比方說同一個字母會對應到不一樣的密文,因為亂數是一直取下去的,即使是同一個字元要加密,也有極高的機率因為對應的順序不同導致需要尋找的次數不一樣。

  解密的方式跟加密相當類似,同樣的換法,並且執行密文的次數就能得到原始的字元,而關鍵的解密要用的金鑰就是 Logistic Map 的初始條件跟參數。

Code:

  以下的例子是加密一張影像叫 Lena,會先把它轉成一維陣列在開始用此方法。

  Encrypt

clear all;

b =  3.999999991;
x = 0.3388;

for i = 1:100
    x = b*x*(1-x);
end

lena = imread('lena_small.bmp');
lena = rgb2gray(lena);
lena = reshape(lena, size(lena,1)*size(lena,2),1);

% statistic freq
freq = zeros(256,1);
for i = 1:size(lena,1)
    freq(lena(i)+1) = freq(lena(i)+1)+1;
end

% order is the freq order
[B, order] = sort(freq, 'descend');

% copy lena to origin
origin = repmat(lena, 1);

% random permutation
for i = 1:size(lena,1)
    x = b*x*(1-x);
    index = round(x*size(lena,1));
    if(index==0)
        index = 1;
    end
    temp = origin(index);
    origin(index) = origin(i);
    origin(i) = temp;
end

% encryption and compression
result = zeros(size(lena,1),1);
for i = 1:size(lena,1)
    i
    temp_order = repmat(origin, 1);
    count = 0; % save ciphertext
    freq_index = 1;
    while(true) 
        x = b*x*(1-x);
        index = round(x*size(lena,1));
        if(index==0)
            index = 1;
        end
        count = count + 1;
        value = temp_order(index);
        if(value==lena(i))
            result(i) = count;
            break;
        end
        
        for j = 1:size(lena,1)
            if(temp_order(j)==value)
                temp_order(j) = order(freq_index)-1;
            end
        end
        freq_index = freq_index + 1;
        if(freq_index>256)
            freq_index = 1;
        end
    end
end 

  在解密這邊還是讀了 lena 的原因是需要統計他的機率跟弄出那個區塊分割,真實情況應該是這個也當作是金鑰一樣,一起存起來。

  Decrypt

clear all;

b =  3.999999991;
x = 0.3388;

% the result of encryption
result = load('result1.mat');
result = result.result;

for i = 1:100
    x = b*x*(1-x);
end

lena = imread('lena_small.bmp');
lena = rgb2gray(lena);
lena = reshape(lena, size(lena,1)*size(lena,2),1);

% statistic freq
freq = zeros(256,1);
for i = 1:size(lena,1)
    freq(lena(i)+1) = freq(lena(i)+1)+1;
end

% order is the freq order
[B, order] = sort(freq, 'descend');

% copy lena to origin
origin = repmat(lena, 1);

% random permutation
for i = 1:size(lena,1)
    x = b*x*(1-x);
    index = round(x*size(lena,1));
    if(index==0)
        index = 1;
    end
    temp = origin(index);
    origin(index) = origin(i);
    origin(i) = temp;
end

% decription
output = zeros(size(lena,1),1);
for i = 1:size(lena,1)
    i
    temp_order = repmat(origin, 1);
    count = result(i); % ciphertext means iteration
    freq_index = 1;
    for k = 1:count
        x = b*x*(1-x);
        index = round(x*size(lena,1));
        if(index==0)
            index = 1;
        end
        value = temp_order(index);
        if(k==count)
            output(i) = value;
            break;
        end
        for j = 1:size(lena,1)
            if(temp_order(j)==value)
                temp_order(j) = order(freq_index)-1;
            end
        end
        freq_index = freq_index + 1;
        if(freq_index>256)
            freq_index = 1;
        end
    end
end 

結果:

  這邊的例子是跑一張50*50大小的圖片,換句話說有2500個元素需要加密。

  

  這是擷取前23項的結果,第一行是原始的值,因為是影像,所以可以看附近的值都不會差距太大,第二行是加密過後的結果,有很多個原始值一樣但加密過後的結果不一樣的例子,如第19, 20列。

  在 core i7, 16G ram 的電腦上跑,加密跟解密的執行時間都需要5分鐘上下。

Reference:

   [1] A Modified Chaos-Based Joint Compression and Encryption Scheme, Jianyong Chen, Junwei Zhou, and Kwok-Wo Wong, Senior Member, IEEE

   [2] Embedding Compression in Chaos-Based Cryptography, Kwok-Wo Wong, Senior Member, IEEE, and Ching-Hung Yuen