%%% File: generic-API.pl %%% Author: Graham Steel %%% Created: Mon Jan 26 2009 %%% Last Update: Tue Feb 10 15:43:09 2009 %% Demonstrates the generation of appropriate API rules from a protocol. participant(alice). participant(bob). participant(server). % protocol_step/4 specifies the protocol %% this is consulted from another file %% initial handles are also in the other file %% the API commands stores as generate, decrypt, encrypt %% for sicstus prolog :- dynamic command/4. %% for Gnu prolog %dynamic(command/4). %% get a new name for a handle new_handle_name(Agent,Name,Name) :- \+ handle(h(Agent,Name,_,_)). new_handle_name(Agent,Name,Name) :- new_handle_name(Agent,prime(Name),prime(Name)). %%% the algorithm go(Protocol) :- consult(Protocol), go, print_commands. go :- findall(_,( protocol_step(Played_by,LHS,MID,RHS), treat_step(Played_by,LHS,MID,RHS)),_). print_commands :- findall(_,( command(Played_by,Commands1,Commands2,Commands3), format("~n~n Command for ~w ~n~n Generate ~w ~n~n Decrypt ~w ~n~n Encrypt ~w ~n~n",[Played_by,Commands1,Commands2,Commands3])),_). treat_step(Played_by,LHS,MID,RHS) :- generate_rules(Played_by,MID,Commands1), decrypt_rules(Played_by,LHS,Commands2), % tests included here encrypt_rules(Played_by,RHS,Commands3), assert(command(Played_by,Commands1,Commands2,Commands3)),!. generate_rules(_,[],[]). generate_rules(Agent,[nonce(Agent,Name,Level,Set)|Rest],[gen(h(Agent,Name,Level,Set))|OtherCommands]) :- assert(handle(h(Agent,Name,Level,Set))), generate_rules(Agent,Rest,OtherCommands). generate_rules(Agent,[key(Agent,Name,Level,Set)|Rest],[gen(h(Agent,Name,Level,Set))|OtherCommands]) :- assert(handle(h(Agent,Name,Level,Set))), generate_rules(Agent,Rest,OtherCommands). decrypt_rules(_,[],[]). decrypt_rules(Agent,[enc(List,Key)|Rest],[decrypt([enc(List,Key),h(Agent,Key,Level,Set),Test],RHS)|Commands]) :- handle(h(Agent,Key,Level,Set)), treat_encrypted_terms(Agent,List,RHS), derive_tests(Agent,List,Test), decrypt_rules(Agent,Rest,Commands). decrypt_rules(Agent,[_|Rest],Commands) :- decrypt_rules(Agent,Rest,Commands). treat_encrypted_terms(_,[],[]) :- !. treat_encrypted_terms(Agent,[agent(Name)|Rest],[agent(Name)|RHS]) :- treat_encrypted_terms(Agent,Rest,RHS). %forwarding of encrypted packets. treat_encrypted_terms(Agent,[packet|Rest],[packet|RHS]) :- treat_encrypted_terms(Agent,Rest,RHS). %% nonce level 0 returned treat_encrypted_terms(Agent,[nonce(Agent2,Name,0,S)|Rest],[nonce(Agent2,Name,0,S)|LHS]) :- treat_encrypted_terms(Agent,Rest,LHS). %%%% nonce level 1 - get a new handle for it even if I generated it treat_encrypted_terms(Agent,[nonce(_Agent2,Name,1,Set)|Rest],[h(Agent,Name2,1,Set)|LHS]) :- new_handle_name(Agent,Name,Name2), assert(handle(h(Agent,Name2,1,Set))), treat_encrypted_terms(Agent,Rest,LHS). %%%% key level 2 - get a new handle for it even if I generated it treat_encrypted_terms(Agent,[key(_Agent2,Name,2,Set)|Rest],[h(Agent,Name2,2,Set)|LHS]) :- new_handle_name(Agent,Name,Name2), assert(handle(h(Agent,Name2,2,Set))), treat_encrypted_terms(Agent,Rest,LHS). %%%%%% encrypt_rules(_Agent,[],[]). %% only an enc term is of interest encrypt_rules(Agent,[enc(List,Key)|Rest],[encrypt([h(Agent,Key,L,Set),Terms],[enc(List,Key)])|Rules1]) :- handle(h(Agent,Key,L,Set)), % check for nested encryptions encrypt_rules(Agent,List,Rules2), treat_plaintexts(Agent,List,Terms), encrypt_rules(Agent,Rest,Rules3), append(Rules3,Rules2,Rules1). %% other stuff (this can also triggered if the encryption is with a key we don't have, %% i.e. we forward a secret packet (assuming a sensible protocol..) encrypt_rules(A,[_|Rest],RHS) :- encrypt_rules(A,Rest,RHS). %%%%%% treat_plaintexts(_Agent,[],[]). % agent name treat_plaintexts(Agent,[agent(Name)|Rest],[agent(Name)|RHS]) :- treat_plaintexts(Agent,Rest,RHS). % a nested encryption (it will have its own rule) treat_plaintexts(Agent,[enc(_,_)|Rest],[nested_encryption|RHS]) :- treat_plaintexts(Agent,Rest,RHS). % one of my nonces, 0 or 1 treat_plaintexts(Agent,[nonce(Agent,Name,L,Set)|Rest],[h(Agent,Name,L,Set)|RHS]) :- handle(h(Agent,Name,L,Set)), treat_plaintexts(Agent,Rest,RHS). %% someone elses nonce level 0 (i.e. public term) treat_plaintexts(Agent,[nonce(Agent2,Name,0,Set)|Rest],[nonce(Agent2,Name,0,Set)|RHS]) :- Agent2 \== Agent, treat_plaintexts(Agent,Rest,RHS). % key treat_plaintexts(Agent,[key(Agent,Name,L,Set)|Rest],[h(Agent,Name,L,Set)|RHS]) :- handle(h(Agent,Name,L,Set)), treat_plaintexts(Agent,Rest,RHS). %% derive tests if necessary - return the empty list of tests if not necc %% if we find something of level 2, we require %% a test on something we generated of level 1, but that's it for the moment. derive_tests(Agent,List,Tests) :- derive_tests(Agent,List,Tests,List). derive_tests(_,[],[],_). derive_tests(Agent,[key(_Agent2,_Name,2,_Set)|_Rest],[test(Handle)],List) :- find_test_nonce(Agent,Handle,List). derive_tests(Agent,[_|Rest],Test,List) :- derive_tests(Agent,Rest,Test,List). find_test_nonce(_,warning(missing_test),[]). find_test_nonce(Agent,h(Agent,Name,L,Set),[nonce(Agent,Name,L,Set)|_]). find_test_nonce(Agent,Handle,[_|List]) :- find_test_nonce(Agent,Handle,List).