在 Matlab 中使用 AES256 加密/解密图像



>我必须用AES256加密和解密图像。我正在研究下面的程序,该程序对明文进行加密。

AES 是一种具有 128 位固定长度输入的算法。它每轮分四个不同的步骤工作;AES256 有 14 轮,正如程序显示的另一种算法所示。

我希望将主程序调整为任何长度肯定大于 128 位的图像。我应该将其分成许多大小相同的块,还是您有其他建议?

function [output] = aes(s, oper, mode, input, iv, sbit)
% AES Encrypt/decrypt array of bytes by AES.
% output = aes(s, oper, mode, input, iv, sbit)
% Encrypt/decrypt array of bytes by AES-128, AES-192, AES-256.
% All NIST SP800-38A cipher modes supported (e.g. ECB, CBC, OFB, CFB, CTR).
% Usage example:    out = aesdecrypt(s, 'dec', 'ecb', data)
% s:                AES structure (generated by aesinit)
% oper:             operation:
%                   'e', 'enc', 'encrypt', 'E',... = encrypt
%                   'd', 'dec', 'decrypt', 'D',... = decrypt
% mode:             operation mode
%                   'ecb' = Electronic Codebook Mode
%                   'cbc' = Cipher Block Chaining Mode
%                   'cfb' = Cipher Feedback Mode
%                   'ofb' = Output Feedback Mode
%                   'ctr' = Counter Mode
%                   For counter mode you need external AES_GET_COUNTER()
%                   counter function.
% input:            plaintext/ciphertext byte-vector with length
%                   multiple of 16
% iv:               initialize vector - some modes need it
%                   ending initialize vector is stored in s.iv, so you
%                   can use aes() repetitively to encode/decode
%                   large vector:
%                   out = aes(s, 'enc', 'cbc', input1, iv);
%                   out = [out aes(s, 'enc', 'cbc', input1, s.iv)];
%                   ...
% sbit:             bit-width parameter for CFB mode
% output:           ciphertext/plaintext byte-vector
%
% See
% Morris Dworkin, Recommendation for Block Cipher Modes of Operation
% Methods and Techniques
% NIST Special Publication 800-38A, 2001 Edition
% for details.
error(nargchk(4, 6, nargin));
validateattributes(s, {'struct'}, {});
validateattributes(oper, {'char'}, {});
validateattributes(mode, {'char'}, {});
validateattributes(input, {'numeric'}, {'real', 'vector', '>=', 0, '<', 256});
if (nargin >= 5)
    validateattributes(iv, {'numeric'}, {'real', 'vector', '>=', 0, '<', 256});
    if (length(iv) ~= 16)
        error('Length of ''iv'' must be 16.');
    end
end
if (nargin >= 6)
    validateattributes(sbit, {'numeric'}, {'real', 'scalar', '>=', 1, '<=', 128});
end
if (mod(length(input), 16))
    error('Length of ''input'' must be multiple of 16.');
end
switch lower(oper)
    case {'encrypt', 'enc', 'e'}
        oper = 0;
    case {'decrypt', 'dec', 'd'}
        oper = 1;
    otherwise
        error('Bad ''oper'' parameter.');
end
blocks = length(input)/16;
input = input(:);
switch lower(mode)
    case {'ecb'}
        % Electronic Codebook Mode
        % ------------------------
        output = zeros(1,length(input));
        idx = 1:16;
        for i = 1:blocks
            if (oper)
                % decrypt
                output(idx) = aesdecrypt(s,input(idx));
            else
                % encrypt
                output(idx) = aesencrypt(s,input(idx));
            end
            idx = idx + 16;
        end
    case {'cbc'}
        % Cipher Block Chaining Mode
        % --------------------------
        if (nargin < 5)
            error('Missing initialization vector ''iv''.');
        end
        output = zeros(1,length(input));
        ob = iv;
        idx = 1:16;
        for i = 1:blocks
            if (oper)
                % decrypt
                in = input(idx);
                output(idx) = bitxor(ob(:), aesdecrypt(s,in)');
                ob = in;
            else
                % encrypt
                ob = bitxor(ob(:), input(idx));
                ob = aesencrypt(s, ob);
                output(idx) = ob;
            end
            idx = idx + 16;
        end
        % store iv for block passing
        s.iv = ob;
    case {'cfb'}
        % Cipher Feedback Mode
        % --------------------
        % Special mode with bit manipulations
        % sbit = 1..128
        if (nargin < 6)
            error('Missing ''sbit'' parameter.');
        end
        % get number of bits
        bitlen = 8*length(input);
        % loop counter
        rounds = round(bitlen/sbit);
        % check 
        if (rem(bitlen, sbit))
            error('Message length in bits is not multiple of ''sbit''.');
        end
        % convert input to bitstream
        inputb = reshape(de2bi(input,8,2,'left-msb')',1,bitlen);
        % preset init. vector
        ib = iv;
        ibb = reshape(de2bi(ib,8,2,'left-msb')',1,128);
        % preset output binary stream
        outputb = zeros(size(inputb));
        for i = 1:rounds
            iba = aesencrypt(s, ib);
            % convert to bit, MSB first
            ibab = reshape(de2bi(iba,8,2,'left-msb')',1,128);
            % strip only sbit MSB bits
            % this goes to xor
            ibab = ibab(1:sbit);
            % strip bits from input
            inpb = inputb((i - 1)*sbit + (1:sbit));
            % make xor
            outb = bitxor(ibab, inpb);
            % write to output
            outputb((i - 1)*sbit + (1:sbit)) = outb;
            if (oper)
                % decrypt
                % prepare new iv - bit shift
                ibb = [ibb((1 + sbit):end) inpb];
            else
                % encrypt
                % prepare new iv - bit shift
                ibb = [ibb((1 + sbit):end) outb];
            end
            % back to byte ary
            ib = bi2de(vec2mat(ibb,8),'left-msb');
            % loop
        end
        output = bi2de(vec2mat(outputb,8),'left-msb');
        % store iv for block passing
        s.iv = ib;
    case {'ofb'}
        % Output Feedback Mode
        % --------------------
        if (nargin < 5)
            error('Missing initialization vector ''iv''.');
        end
        output = zeros(1,length(input));
        ib = iv;
        idx = 1:16;
        for i = 1:blocks
            % encrypt, decrypt
            ib = aesencrypt(s, ib);
            output(idx) = bitxor(ib(:), input(idx));
            idx = idx + 16;
        end
        % store iv for block passing
        s.iv = ib;
    case {'ctr'}
        % Counter Mode
        % ------------
        if (nargin < 5)
            iv = 1;
        end
        output = zeros(1,length(input));
        idx = 1:16;
        for i = (iv):(iv + blocks - 1)
            ib = AES_GET_COUNTER(i);
            ib = aesencrypt(s, ib);
            output(idx) = bitxor(ib(:), input(idx));
            idx = idx + 16;
        end
        s.iv = iv + blocks;
    otherwise
        error('Bad ''oper'' parameter.');
end

AES加密功能:

function [out] = aesencrypt(s, in)
% AESENCRYPT  Encrypt 16-bytes vector.
% Usage:            out = aesencrypt(s, in)
% s:                AES structure
% in:               input 16-bytes vector (plaintext)
% out:              output 16-bytes vector (ciphertext)
if (nargin ~= 2)
    error('Bad number of input arguments.');
end
validateattributes(s, {'struct'}, {});
validateattributes(in, {'numeric'}, {'real','uint8'});
% copy input to local
% 16 -> 4 x 4
state = reshape(in, 4, 4);
% Initial round
% AddRoundKey keyexp(1:4)
state = bitxor(state, (s.keyexp(1:4, :))');
% Loop over (s.rounds - 1) rounds
for i = 1:(s.rounds - 1)
    % SubBytes - lookup table
    state = s.s_box(state + 1);
    % ShiftRows
    state = shift_rows(state, 0);
    % MixColumns
    state = mix_columns(state, s);
    % AddRoundKey keyexp(i*4 + (1:4))
    state = bitxor(state, (s.keyexp((1:4) + 4*i, :))');
end
% Final round
% SubBytes - lookup table
state = s.s_box(state + 1);
% ShiftRows
state = shift_rows(state, 0);
% AddRoundKey keyexp(4*s.rounds + (1:4))
state = bitxor(state, (s.keyexp(4*s.rounds + (1:4), :))');
% copy local to output
% 4 x 4 -> 16
out = reshape(state, 1, 16);

函数 埃西尼特:

function s = aesinit(key)
% AESINIT Generate structure with s-boxes, expanded key, etc.
% Usage:            s = aesinit([23 34 168 ... 39])
% key:              16 (AES-128), 24 (AES-192), and 32 (AES-256)
%                   items array with bytes of key
% s:                AES structure for AES parameters and tables
% Stepan Matejka, 2011, matejka[at]feld.cvut.cz
% $Revision: 1.1.0 $  $Date: 2011/10/12 $
validateattributes(key,...
    {'numeric'},...
    {'real', 'vector', '>=', 0, '<=', 255});
key = key(:);
lengthkey = length(key);
switch (lengthkey)
    case 16
        rounds = 10;
    case 24
        rounds = 12;
    case 32
        rounds = 14;
    otherwise
        error('Only AES-128, AES-192, and AES-256 are supported.');
end
% fill s structure
s = {};
s.key = key;
s.bytes = lengthkey;
s.length = lengthkey * 8;
s.rounds = rounds;
% irreducible polynomial for multiplication in a finite field 0x11b
% bin2dec('100011011');
s.mod_pol = 283;
% s-box method 1 (slow)
% ---------------------
%     % multiplicative inverse table
%     % first is zero, calculate rest
%     inverse = zeros(1,256);
%     for i = 2:256
%         inverse(i) = find_inverse(i - 1, s.mod_pol);
%     end
%     
%     % generate s-box
%     s_box = zeros(1,256);
%     for i = 1:256
%         % affine transformation
%         s_box(i) = aff_trans(inverse(i));
%     end
%     s.s_box = s_box;
%     
%     % generate inverse s-box
%     inv_s_box(s_box(1:256) + 1) = (1:256) - 1;
%     s.inv_s_box = inv_s_box;
% s-box method 2 (faster)
% -----------------------
% first build logarithm lookup table and it's inverse
aes_logt = zeros(1,256);
aes_ilogt = zeros(1,256);
gen = 1;
for i = 0:255
    aes_logt(gen + 1) = i;
    aes_ilogt(i + 1) = gen;
    gen = poly_mult(gen, 3, s.mod_pol);
end
% store log tables
s.aes_logt = aes_logt;
s.aes_ilogt = aes_ilogt;
% build s-box and it's inverse
s_box = zeros(1,256);
loctable = [1 2 4 8 16 32 64 128 1 2 4 8 16 32 64 128];
for i = 0:255
    if (i == 0)
        inv = 0;
    else
        inv = aes_ilogt(255 - aes_logt(i + 1) + 1);
    end
    temp = 0;
    for bi = 0:7
        temp2 = sign(bitand(inv, loctable(bi + 1)));
        temp2 = temp2 + sign(bitand(inv, loctable(bi + 4 + 1)));
        temp2 = temp2 + sign(bitand(inv, loctable(bi + 5 + 1)));
        temp2 = temp2 + sign(bitand(inv, loctable(bi + 6 + 1)));
        temp2 = temp2 + sign(bitand(inv, loctable(bi + 7 + 1)));
        temp2 = temp2 + sign(bitand(99, loctable(bi + 1)));
        if (rem(temp2,2))
            temp = bitor(temp, loctable(bi + 1));
        end
    end
    s_box(i + 1) = temp;
end
inv_s_box(s_box(1:256) + 1) = (0:255);
% table correction (must be)
s_box(1 + 1) = 124;
inv_s_box(124 + 1) = 1;
inv_s_box(99 + 1) = 0;
s.s_box = s_box;
s.inv_s_box = inv_s_box;
% tables for fast MixColumns
mix_col2 = zeros(1,256);
mix_col3 = mix_col2;
mix_col9 = mix_col2;
mix_col11 = mix_col2;
mix_col13 = mix_col2;
mix_col14 = mix_col2;
for i = 1:256
    mix_col2(i) = poly_mult(2, i - 1, s.mod_pol);
    mix_col3(i) = poly_mult(3, i - 1, s.mod_pol);
    mix_col9(i) = poly_mult(9, i - 1, s.mod_pol);
    mix_col11(i) = poly_mult(11, i - 1, s.mod_pol);
    mix_col13(i) = poly_mult(13, i - 1, s.mod_pol);
    mix_col14(i) = poly_mult(14, i - 1, s.mod_pol);
end
s.mix_col2 = mix_col2;
s.mix_col3 = mix_col3;
s.mix_col9 = mix_col9;
s.mix_col11 = mix_col11;
s.mix_col13 = mix_col13;
s.mix_col14 = mix_col14;
% expanded key
s.keyexp = key_expansion(s.key, s.s_box, s.rounds, s.mod_pol, s.aes_logt, s.aes_ilogt);
% poly & invpoly
s.poly_mat = [...
    2 3 1 1;...
    1 2 3 1;...
    1 1 2 3;...
    3 1 1 2];
s.inv_poly_mat =[...
    14 11 13  9;...
    9  14 11 13;...
    13  9 14 11;...
    11 13  9 14];
% end of aesinit.m
% ------------------------------------------------------------------------
function p = poly_mult(a, b, mod_pol)
% Multiplication in a finite field
% For loop multiplication - slower than log/ilog tables
% but must be used for log/ilog tables generation
p = 0;
for counter = 1 : 8
    if (rem(b, 2))
        p = bitxor(p, a);
        b = (b - 1)/2;
    else
        b = b/2;
    end
    a = 2*a;
    if (a > 255)
        a = bitxor(a, mod_pol);
    end
end
% ------------------------------------------------------------------------
function inv = find_inverse(in, mod_pol)
% Multiplicative inverse for an element a of a finite field
% very bad calculate & test method
% Not used in faster version
% loop over all possible bytes
for inv = 1 : 255
    % calculate polynomial multiplication and test to be 1
    if (1 == poly_mult(in, inv, mod_pol))
        % we find it
        break
    end
end
inv = 0;
% ------------------------------------------------------------------------
function out = aff_trans(in)
% Affine transformation over GF(2^8)
% Not used for faster s-box generation
% modulo polynomial for multiplication in a finite field
% bin2dec('100000001');
mod_pol = 257;
% multiplication polynomial
% bin2dec('00011111');
mult_pol = 31;
% addition polynomial
% bin2dec('01100011');
add_pol = 99;
% polynomial multiplication
temp = poly_mult(in, mult_pol, mod_pol);
% xor with addition polynomial
out = bitxor(temp, add_pol);
% ------------------------------------------------------------------------
function expkey = key_expansion(key, s_box, rounds, mod_pol, aes_logt, aes_ilogt)
% Expansion of key
% This is old version for AES-128 (192?, 256? not tested):
% rcon = ones(1,rounds);
% for i = 2:rounds
%     rcon(i) = poly_mult(rcon(i - 1), 2, mod_pol);
% end
% % fill bytes 2, 3, and 4 by 0
% rcon = [rcon(:), zeros(rounds, 3)];
% 
% kcol = length(key)/4;
% expkey = (reshape(key, kcol, 4))';
% for i = (kcol + 1):(4*rounds + 4)
%     % copy the previous row of the expanded key into a buffer
%     temp = expkey(i - 1, :);
%     % each fourth row
%     if (mod(i, 4) == 1)
%         % shift temp
%         temp = temp([2 3 4 1]);
%         % s-box transform
%         temp = s_box(temp + 1);
%         % compute the current round constant
%         r = rcon((i - 1)/4, :);
%         % xor
%         temp = bitxor(temp, r);
%     else
%         if ((kcol > 6) && (mod(i, kcol) == 0))
%             temp = s_box(temp);
%         end
%     end
%     % generate new row of the expanded key
%     expkey(i, :) = bitxor(expkey(i - 4, :), temp);
% end
% This is new faster version for all AES:
rcon = 1;
kcol = length(key)/4;
expkey = (reshape(key,4,kcol))';
% traverse for all rounds
for i = kcol:(4*(rounds + 1) - 1)
    % copy the previous row of the expanded key into a buffer
    temp = expkey(i, :);
    % each kcol row
    if (mod(i, kcol) == 0)
        % rotate word
        temp = temp([2 3 4 1]);
        % s-box transform
        temp = s_box(temp + 1);
        % xor
        temp(1) = bitxor(temp(1), rcon);
        % new rcon
        % 1. classic poly_mult
        % rcon = poly_mult(rcon, 2, mod_pol);
        % 2. or faster version with log/ilog tables
        % note rcon is never zero here
        % rcon = aes_ilogt(mod((aes_logt(rcon + 1) + aes_logt(2 + 1)), 255) + 1);
        rcon = aes_ilogt(mod((aes_logt(rcon + 1) + 25), 255) + 1);
    else
        if ((kcol > 6) && (mod(i, kcol) == 4))
            temp = s_box(temp + 1);
        end
    end
    % generate new row of the expanded key
    expkey(i + 1, :) = bitxor(expkey(i - kcol + 1, :), temp);
end

您被限制为 128 位,因为您尝试使用 aesencrypt 进行加密,这是在 4x4 块上工作的低级函数之一。如果您改用aes函数,则可以对任何"长度倍数为 16 的字节向量"进行编码。它将反复为您调用aesenrypt,直到处理完所有 4x4 块。

最新更新