classdef Blake_256 % Blake_256 % File: Blake_256.m % Description: Defines a class which implements the BLAKE-256 % cryptographic hash function. % Notes: % % Change History % Date | Contributor | Description % ------------+----------------------+----------------------------------- % 16/03/2011 | Zeke Steer | Authored % | Loughborough Uni, UK | % ------------+----------------------+----------------------------------- properties ( Constant ) nRounds_32 = 14; % number of rounds % array of permutations of {0,...,15}, sigma o = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15; 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3; 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4; 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8; 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13; 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9; 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11; 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10; 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5; 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 ]; % array of constants, c c = { '243F6A88', '85A308D3', '13198A2E', '03707344', ... 'A4093822', '299F31D0', '082EFA98', 'EC4E6C89', ... '452821E6', '38D01377', 'BE5466CF', '34E90C6C', ... 'C0AC29B7', 'C97C50DD', '3F84D5B5', 'B5470917' ... }; % array of initial values, iv iv = { '6A09E667', 'BB67AE85', '3C6EF372', 'A54FF53A', ... '510E527F', '9B05688C', '1F83D9AB', '5BE0CD19' ... }; end properties ( GetAccess = private ) c_32, iv_256 % fi objects f % fimath object state % hash structure end methods ( Static = true ) function [ out ] = ToUInt_32( in ) % ToUint_32 % Converts a 32-element array of Boolean values into a 32-bit % unsigned integer. % Inputs: in % 32-element array of Boolean values % Outputs: out % 32-bit unsigned integer out = 0; % loop through array for i = 1:32 % sum decimal value of each bit if in( i ) == 1 out = out + 2^( i - 1 ); end end end end methods ( Access = private ) function [ v ] = G( obj, v, i, r ) % G % Transforms a 4-element array of 32-bit values in accordance with % the BLAKE specification, pp. 9 - 10. % Inputs: obj % Blake_256 object % v % Input vector % i % Index % r % Round % Outputs: v % Output vector % generate indices into state.m_32 and c j = obj.o( mod( r - 1, 10 ) + 1, 2 * i - 1 ) + 1; k = obj.o( mod( r - 1, 10 ) + 1, 2 * i ) + 1; % perform 1st sequence of transformations v( 1 ) = v( 1 ) + v( 2 ) + ... bitxor( obj.state.m_32( j ), obj.c_32( k ) ); v( 4 ) = bitror( bitxor( v( 4 ), v( 1 ) ), 16 ); v( 3 ) = v( 3 ) + v( 4 ); v( 2 ) = bitror( bitxor( v( 2 ), v( 3 ) ), 12 ); % perform 2nd sequence of transformations v( 1 ) = v( 1 ) + v( 2 ) + ... bitxor( obj.state.m_32( k ), obj.c_32( j ) ); v( 4 ) = bitror( bitxor( v( 4 ), v( 1 ) ), 8 ); v( 3 ) = v( 3 ) + v( 4 ); v( 2 ) = bitror( bitxor( v( 2 ), v( 3 ) ), 7 ); end function [ obj ] = Compress( obj ) % Compress % Compresses a 512-bit message block in accordance with the BLAKE % specification, pp. 9 - 12. % Inputs: obj % Blake_256 object % Outputs: obj % Blake_256 object % populate 4x4 matrix, v with initial chain values v = [ obj.state.h_32( 1 ), obj.state.h_32( 2 ), ... obj.state.h_32( 3 ), obj.state.h_32( 4 ); ... obj.state.h_32( 5 ), obj.state.h_32( 6 ), ... obj.state.h_32( 7 ), obj.state.h_32( 8 ); ... bitxor( obj.state.s_32( 1 ), obj.c_32( 1 ) ), ... bitxor( obj.state.s_32( 2 ), obj.c_32( 2 ) ), ... bitxor( obj.state.s_32( 3 ), obj.c_32( 3 ) ), ... bitxor( obj.state.s_32( 4 ), obj.c_32( 4 ) ); ... bitxor( obj.state.t_32( 1 ), obj.c_32( 5 ) ), ... bitxor( obj.state.t_32( 1 ), obj.c_32( 6 ) ), ... bitxor( obj.state.t_32( 2 ), obj.c_32( 7 ) ), ... bitxor( obj.state.t_32( 2 ), obj.c_32( 8 ) ) ... ]; % do rounds for r = 1 : obj.nRounds_32 % do column steps v( [ 1, 2, 3, 4 ] ) = obj.G( v( [ 1, 2, 3, 4 ] ), ... 1, r ); v( [ 5, 6, 7, 8 ] ) = obj.G( v( [ 5, 6, 7, 8 ] ), ... 2, r ); v( [ 9, 10, 11, 12 ] ) = obj.G( v( [ 9, 10, 11, 12 ] ), ... 3, r ); v( [ 13, 14, 15, 16 ] ) = obj.G( v( [ 13, 14, 15, 16 ] ), ... 4, r ); % do diagonal steps v( [ 1, 6, 11, 16 ] ) = obj.G( v( [ 1, 6, 11, 16 ] ), ... 5, r ); v( [ 5, 10, 15, 4 ] ) = obj.G( v( [ 5, 10, 15, 4 ] ), ... 6, r ); v( [ 9, 14, 3, 8 ] ) = obj.G( v( [ 9, 14, 3, 8 ] ), ... 7, r ); v( [ 13, 2, 7, 12 ] ) = obj.G( v( [ 13, 2, 7, 12 ] ), ... 8, r ); end % generate next chain values obj.state.h_32( 1 ) = bitxor( obj.state.h_32( 1 ), ... bitxor( obj.state.s_32( 1 ), ... bitxor( v( 1, 1 ), v( 3, 1 ) ) ) ); obj.state.h_32( 2 ) = bitxor( obj.state.h_32( 2 ), ... bitxor( obj.state.s_32( 2 ), ... bitxor( v( 1, 2 ), v( 3, 2 ) ) ) ); obj.state.h_32( 3 ) = bitxor( obj.state.h_32( 3 ), ... bitxor( obj.state.s_32( 3 ), ... bitxor( v( 1, 3 ), v( 3, 3 ) ) ) ); obj.state.h_32( 4 ) = bitxor( obj.state.h_32( 4 ), ... bitxor( obj.state.s_32( 4 ), ... bitxor( v( 1, 4 ), v( 3, 4 ) ) ) ); obj.state.h_32( 5 ) = bitxor( obj.state.h_32( 5 ), ... bitxor( obj.state.s_32( 1 ), ... bitxor( v( 2, 1 ), v( 4, 1 ) ) ) ); obj.state.h_32( 6 ) = bitxor( obj.state.h_32( 6 ), ... bitxor( obj.state.s_32( 2 ), ... bitxor( v( 2, 2 ), v( 4, 2 ) ) ) ); obj.state.h_32( 7 ) = bitxor( obj.state.h_32( 7 ), ... bitxor( obj.state.s_32( 3 ), ... bitxor( v( 2, 3 ), v( 4, 3 ) ) ) ); obj.state.h_32( 8 ) = bitxor( obj.state.h_32( 8 ), ... bitxor( obj.state.s_32( 4 ), ... bitxor( v( 2, 4 ), v( 4, 4 ) ) ) ); end end methods function [ obj ] = Blake_256( ) % Blake_256 % Blake_256 constructor. % Inputs: - % Outputs: obj % Blake_256 object % set fimath properties obj.f = fimath( 'CastBeforeSum', 1, ... 'MaxProductWordLength', 128, ... 'MaxSumWordLength', 128, ... 'OverflowMode', 'wrap', ... 'ProductBias', 0, ... 'ProductMode', 'KeepLSB', ... 'ProductWordLength', 32, ... 'RoundMode', 'ceil', ... 'SumBias', 0, ... 'SumMode', 'KeepLSB', ... 'SumWordLength', 32 ... ); % convert c in hex to fi representation obj.c_32 = fi( [ ], 0, 32, 0, obj.f ); obj.c_32.hex = char( obj.c ); % convert iv in hex to fi representation obj.iv_256 = fi( [ ], 0, 32, 0, obj.f ); obj.iv_256.hex = char( obj.iv ); % initialise hash structure obj.state = struct( 'h_32', fi( [ ], 0, 32, 0, obj.f ), ... 's_32', fi( zeros( 1, 4 ), 0, 32, 0, obj.f ), ... 't_32', fi( [ ], 0, 32, 0, obj.f ), ... 'm_32', fi( [ ], 0, 32, 0, obj.f ) ... ); end function [ obj ] = Salt( obj, salt ) % Salt % Sets a salt. % Inputs: obj % Blake_256 object % salt % 128-bit salt % Outputs: obj % Blake_256 object % convert salt to 128-bit fi representation salt = fi( salt, 0, 128, 0, obj.f ); % generate 4-element array of 32-bit values for i = 1 : 4 obj.state.s_32( i ) = Blake_256.ToUInt_32( ... salt.bitget( i * 32 - 31 : i * 32 ) ); end end function [ obj, hash ] = Hash( obj, data, length ) % Hash % Generates a 256-bit cryptographic hash value for an arbitrary % block of data. % Inputs: obj % Blake_256 object % data % Arbitrary block of data % length % Data length in bits % re-initialise hash structure obj.state.h_32 = obj.iv_256; obj.state.t_32 = fi( zeros( 1, 2 ), 0, 32, 0, obj.f ); obj.state.m_32 = fi( zeros( 1, 16), 0, 32, 0, obj.f ); % convert data to fi representation data = fi( data, 0, length, 0, obj.f ); % calculate pad bits so message length is multiple of 512 bits pad = 512 - mod( length + 66, 512 ); % pad message data = data.bitconcat( fi( 1, 0, 1, 0, obj.f ), ... fi( 0, 0, pad, 0, obj.f ), ... fi( 1, 0, 1, 0, obj.f ), ... fi( length, 0, 64, 0, obj.f ) ... ); % generate initial data index i = length + pad + 66 + 1; % loop through 512-bit message blocks while length >= 512 % increment counter LS 32 bits by 512 obj.state.t_32( 1 ) = obj.state.t_32( 1 ) + ... fi( 512, 0, 32, 0, obj.f ); % increment counter MS 32 bits on overflow if obj.state.t_32( 1 ) == 0 obj.state.t_32( 2 ) = obj.state.t_32( 2 ) + ... fi( 1, 0, 32, 0, obj.f ); end % split 512-bit message block into 16 32-bit values for j = 1 : 16 obj.state.m_32( j ) = Blake_256.ToUInt_32( data.bitget( ... i - j * 32 : i - ( j - 1 ) * 32 - 1 ) ); end % compress message block obj = obj.Compress( ); % decrement length and data index length = length - 512; i = i - 512; end % increment counter LS 32 bits by remaining data bits obj.state.t_32( 1 ) = obj.state.t_32( 1 ) + ... fi( length, 0, 32, 0, obj.f ); % split 512-bit message block into 16 32-bit values for j = 1 : 16 obj.state.m_32( j ) = Blake_256.ToUInt_32( data.bitget( ... i - j * 32 : i - ( j - 1 ) * 32 - 1 ) ); end % compress message block obj = obj.Compress( ); % decrement data index i = i - 512; % check for special case, 0 data bits in last message block if length > 446 % 0 data bits so counter = 0 obj.state.t_32(1) = 0; obj.state.t_32(2) = 0; % split 512-bit message block into 16 32-bit values for j = 1 : 16 obj.state.m_32( j ) = Blake_256.ToUInt_32( data.bitget( ... i - j * 32 : i - ( j - 1 ) * 32 - 1 ) ); end % compress message block obj = obj.Compress( ); end % convert hash value to hex and return hash = obj.state.h_32.hex; end end end