function [] = pass_protect(fname,newfname,pswrd,savemfile)
%pass_protect(fname,newfname,pswrd,savemfile) password protected pcode.
% This function will create a password protected pcode version of a
% function M-file. The arguments are as follows:
%
% fname: The name of the function M-file to encode and protect (a string).
% newfname: The name of the password protected pcode file (a string).
% pswrd: The password needed to run the pcode the first time (a string).
% savemfile: Allows the user to save the intermediate M-file ({0} or 1).
%
% This program works by creating a copy of the supplied function, fname,
% with a password prompt inserted after the help. Then the copy is
% converted into pcode for secure distribution. The user has the option
% of saving the intermediate M-file, or letting it be deleted after pcode
% generation. The default is for the intermediate M-file to be deleted.
% The original M-file will not be altered.
%
% Example:
% Say you have a function M-file named myfun.m in the current directory.
% To create a password protected pcode version of myfun.m named pr_myfun.p
% use the following:
%
% pass_protect('myfun','pr_myfun','Master&Servant',1)
%
% The intermediate M-file, pr_myfun.m, is saved in this example. In order
% to use pr_myfun.p, the user will need to enter the password after the
% function is called the first time. The user will not have to enter the
% password for subsequent function calls until a 'clear all' is issued.
% Also note that there is no need to include the file extention for
% either of the first two arguments.
%
% Calling pass_protect with no arguments runs a documented example using
% the Matlab function M-file logm.m. Again, logm.m will not be altered.
%
% This function only works on function M-files that do not use nested
% functions. It is easily modified to work with such functions, perhaps if
% this is often needed I would make another copy of this for that purpose.
% If you are unsure as to how to do this, email me and I will tell you.
% Hint: you need to add 5 'end's and a -1 to this code.
% Will not work for scripts either. Works on itself, but with warnings!
%
% See also: pcode
% Created by Matt Fig
% Email: popkenai@yahoo.com
% Built with 2006a on 10-29-2007
if nargin==0 % User wants an example.
fprintf('\n\t\t%s\n',...
'Running: pass_protect(''logm'',''pr_logm'',''pass'',1)')
fprintf('\t\t%s\n','File to be password protected: logm.m')
fprintf('\t\t%s\n','Protected version of logm: pr_logm.p')
fprintf('\t\t%s\n','Password for use of pr_logm: pass')
fprintf('\t\t%s\n','Intermediate M-file saved: yes')
fname = 'logm';
newfname = 'pr_logm';
pswrd = 'pass';
savemfile = 1; % Save the intermediate M-file.
fprintf('\t\t%s\n\n',...
'Now enter this at the command line: pr_logm([3,4;5,60])')
elseif nargin <3
error('Three or zero inputs are required, see help. Aborting.');
elseif nargin <4
savemfile = 0; % Default to delete the intermediate M-file.
end
if ~ischar(fname) || ~ischar(newfname) || ~ischar(pswrd) % Ignored help?
error('The first three arguments must by strings. See help.')
end
insstr{1} = 'persistent pswrdcmp;'; % These lines prompt for password.
insstr{2} = 'if ~ischar(pswrdcmp)';
insstr{3} = 'pswrdcmp = passprompt;'; % Prompt user for password.
insstr{4} = 'end';
insstr{5} = ['pswrd = ',char(39),pswrd,char(39),';']; % Make a string?
insstr{6} = 'if strcmp(pswrd,pswrdcmp)'; % Check with stored password.
insstr{7} = 'else';
insstr{8} = 'clear pswrdcmp;'; % Let them try again!
insstr{9} = 'error(''Access denied, incorrect password entered.'')';
insstr{10} = 'end';
insstr{11} = 'clear global rEaLlY_wEiRd_NaMe_PASSword;'; % Get rid of this!
if strfind(fname,'.m'),else fname = [fname, '.m'];end % Check for file ext.
[idxfile,txtfile] = reader(fname,0); % Get the indexes for writing.
if strfind(newfname,'.m'),else newfname = [newfname, '.m'];end %
fl = fopen(newfname,'w+t'); % Open the new file for writting.
for ii = 1:idxfile
fwrite(fl,sprintf('%s',txtfile{ii})); % Copy file through the help.
end
fwrite(fl,sprintf('\n%s',' ')); % Write in a buffer blank line.
for ii = 1:11
fwrite(fl,sprintf('\n%s',insstr{ii})); % Write in the prompt lines.
end
for ii = idxfile+1:length(txtfile)
fwrite(fl,sprintf('%s',txtfile{ii})); % Copy the rest of the file.
end
[idxself,txtself] = reader('pass_protect.m',1); % Find the password gui.
fwrite(fl,sprintf('\n%s',' ')); % Write in a buffer blank line.
for ii = idxself:length(txtself)
fwrite(fl,sprintf('%s',txtself{ii})); % Write in the password gui.
end
fclose(fl); % Close the new M-file.
pcode(newfname); % Turn it into pcode.
if savemfile~=1
delete(newfname); % Delete the new M-file unless user entered 1.
end
%------------------------------------------------------------------------
%------------------------------------------------------------------------
function [idx,C] = reader(fname,flag)
% reads an M-file and decides where to put the password prompts. The
% password prompt will be put after the help in the original file, even
% though the help will be unavailable in the pcode. This simply serves to
% preserve the standard in case the user wants to keep and inspect the
% M-file.
A = fopen(fname); % Open the file to be read/copied.
B = fscanf(A,'%c'); % Read the contents into a character array.
fclose(A); % Close the file.
B = int8(B); % Look at the ascii map.
B(B==10)=[]; % Look for linefeeds, delete them.
idx = find(B==13); % Find returns, used to create a cell array.
idx = [1, idx];
lngth = length(idx);
C = cell(1,lngth); % Preallocation.
for ii = 1:lngth-1
C{ii} = char(B(idx(ii):idx(ii+1)-1)); % Put each line into a cell.
end
C{lngth} = char(B(idx(lngth):end)); % Put the last line in a cell.
idxfunc = 1; idxhlp = 1;
if flag==0
try % The file may not have help, so skip this.
hlp = sscanf(help(fname),'%c');
hlp = int8(hlp);
idx = find(hlp==10);% Here we need to use the linefeeds as index.
idx = [1, idx];
lngth = length(idx);
hlpcell = cell(1,lngth-1);
for ii = 1:lngth-1
hlpcell{ii} = char(hlp(idx(ii):idx(ii+1)-1)); % As above.
end
idxhlp = find(~cellfun(@isempty,strfind(C,hlpcell{end}(3:end))),...
1,'first'); % The last line of the help.
% Or the line right after the func declaration:
idxfunc = find(~cellfun(@isempty,strfind(C,'function')),1,'first');
catch
idxfunc = find(~cellfun(@isempty,strfind(C,'function')),1,'first');
end
if idxhlp <= idxfunc % Either insert after help or func decl.
idx = idxfunc;
else
idx = idxhlp;
end
else % Here we are looking at THIS file.
idx = find(~cellfun(@isempty,strfind(C,'function [rEaLlY')),2);
idx = idx(2); % Find the line number of passprompt func below.
end
%-------------------------------------------------------------------------
%-------------------------------------------------------------------------
function [rEaLlY_wEiRd_NaMe_PASSword] = passprompt() %#ok
% This function will be written into the the new M-file to prompt the user
% for a password. The global variable is only active until the user closes
% the password prompt dialog, then it is deleted: See line 81 above.
global rEaLlY_wEiRd_NaMe_PASSword %#ok Password temporarily stored here.
h_fig = figure('units','pixels','position',[450 450 300 60],...
'menubar','none','name','Verify Password.'...
,'resize','off','NumberTitle','off');
txt1 = uicontrol(h_fig,'style','text','position',[5 20 80 20],...
'string','Password:','fontweight','bold',...
'HorizontalAlign','left','FontSize',11); %#ok
edt1 = uicontrol(h_fig,'style','edit','position',[90 20 200 20],...
'backgroundcolor','w','callback',...
@closeit,'tooltipstring',[' Enter your password '...
'here.'],'HorizontalAlign','left','KeyPressFcn',...
@keypress);
uicontrol(edt1) % Put a blinking cursor in edit box.
uiwait % Suspend other exection until return is pressed.
function [] = closeit(hand,eventdata) %#ok
% Closes the dialog when user presses return.
global rEaLlY_wEiRd_NaMe_PASSword % Pick a name unlikely to be in use.
rEaLlY_wEiRd_NaMe_PASSword = get(gcf,'UserData'); % Retrieve password.
close(gcf) %
function [] = keypress(hand,eventdata) %#ok
% Deals with user input.
str1 = get(gcf,'CurrentCharacter'); % The character user entered.
num = int8(str1);
if num == 13 % This is a carriage return.
return
end
prnt = get(hand,'parent'); % Handle to gui.
str2 = get(hand,'string'); % the string of the edit box.
if num == 8 % Backspace pressed, update password and screen.
set(hand,'string',str2(1:end-1));
str3 = get(prnt,'UserData');
set(prnt,'UserData',str3(1:end-1));
elseif ~isempty(num)
set(hand,'string',[str2,'*']) ; % Print out an asterik in gui.
set(prnt,'UserData',[get(prnt,'UserData'),str1]); % Update password.
end