|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
Note: This is an unedited contribution. If this article is inappropriate,
needs attention or copies someone else's work without reference then please
Report This Article
IntroductionA software developer may find it necessary to "sell" some of his/her valuable mental skills and labor directly or indirectly to someone in order to make a physical and resulting mental living. The difference is in the "someone", be it his/her boss, a movement/cause or middle/end customers. The term "selling" used here does not necessary result in a cash return, it is used in a more general sense. For example, in open source community, a developer "sell" his/her contribution and get the benefit of resulting joy of mental achievement and a sense of belonging, the spirit of sharing with and help others, the right to improve or use others contribution, and some other technical advantages of such a mode of development. There is nothing in this article that is explicitly or implicitly against it, it is view in an orthogonal perspective. The technology developed at CryptoGateway that is capable of making the "selling" (in the above sense) to "someone" more manageable by right owners, e.g. the service providing sector of a open source community that owns a public license, and the "someone". This article is on an access control technology for .Net (and possibly Java) assemblies and the supporting framework. It is an architectural overview, so it does not contain a complete program that can be used immediately. The framework proposed is general. It does not depend on the access control technology that requires it. Since the author is not familiar with Java programming, the rest of the article will use the .Net term for a particular concept. An assembly in frameworks like .Net contain extensive self-reflective meta information about the type hierarchy contained in the assembly, which can be queried using the .Net framework itself. These information are a great language feature for designing, developing, manipulating (e.g. turning an operation into data of the meta system) and maintaining codes. It is not a welcome feature when the inner details of at least some assemblies in a software system are not indented to be exposed or publicized. Public or authorized sharing of code normally happen at the source code level, assemblies are not usually used to that end. This is because tools exist (or can be developed at low cost) that can be used to reverse-engineer the assemblies given the complete information. It is true that the current trend of software industry is shifting towards more of a service oriented type with the service provider holding most of the important assemblies on their servers. There is still a need to ship some of the assemblies to end users which are likely to contain assemblies that
One way of trying to achieve assembly protection is the use of code obfuscation. The other one, among others, is assembly encryption (with a digital signature as an additional option). The pros and cons of these methods will not be discussed here. If needed, these two techniques can be combined, especially when a non-intrusive encryption method, like the p2p data access control technology of us (see, e.g., 1, 2, 3, and the media player briefly discussed in this article), is employed to realize layered defense. The FrameworkA. The HostThe framework that is considered to be good in general and is flexible enough to support the code protection technology and the resulting development culture should have, or is capable of been evolved into one that have, the following properties:
There are many plug-in frameworks belonging to a variety of design patterns for .Net, this article is not going to discuss or compare any of them due partly to the length limit of the article. The way how the host realize the asynchronized message passing between its child components is also not to be covered here. A schematic UML diagram for how the child components are connected to host and each other that can satisfy the above requirements is shown in Fig. 1. There is a one to many relationship between the interface and the sockets and the components. A component is part of a socket. Each socket can allow a sequence of one to any components forming an ordered processing pipeline, to be plugged in. It is explained in more details in the following. B. The ConnectionThis frame work is interface based. The top level development "flow chart " is shown in the followingStep 1: Interface specificationThe first step in the attempt to connect a component to a host that is previously unknown to the host is to provide an interface that declares the properties and methods that are open to the host and a set of sockets (see the following). Interfaces are introduced at least in two ways:
Step 2: The Component Socket
After the step one is done in a particular iteration or if the component implements a existing interface and either it is the first attempt to be plugged into the host or it is to be plugged in to a new kind of socket, then the socket has to be designed and implemented. A socket acts as a dispatcher for call requests from the host to the component (sequence) derived from the same interface. It is also responsible for loading and unloading assemblies that contains the implement. It is initialized from a XML configuration "script" either in a execution branch reached prior to or just before one of the components handled by it is needed. The socket should be created in a separated When the need to use one of the components arises, an instance of the socket that hold it is created first and then the corresponding set of assemblies are loaded by it. The load process, opaque to the host, is represented by call stack 9->10->11->12 in Fig. 2, which is discussed in the following The Secured Assembly loader is itself a socket holding the client of a process server inside crypto-gateway server where the authentication and decryption is performed. After the corresponding assembly is loaded, the set of instances of the types that is configured to be attached to the socket is created, which is represented by the call stack 13->14 in Fig. 2. After the socket is created, all the objects that is configured to attach to it are also created. The type of these objects and the objects themselves are used to access their members via reflection. More details is provided in the following. The method call and property access can now be delegated to the component object (objects pipeline, if so configured) by the socket, which can also be configured to perform logging, exception trap and handling, etc.. The interface can also define a set of events for the components to call back to the host, which could 1) handling it; 2) delegate the call to other child components; 3) propagate it upward in the host hierarchy. The synchronized version of it is illustrated in Fig. 2 by 20->...->27. For asynchronized version, which is suggested above, call 20 returns (26->27) immediately after 21, leaving the host to handle the message. A typical socket call handler looks like namespace Media
{
public class Mp3PlayerSocket : IStreamClient
{
.....................
public void LoadPlayList(System.Collections.ArrayList list)
{
try
{
if (!pipeline)
{
if (miLoadPlayList==null)
miLoadPlayList = otype.GetMethod("LoadPlayList",
new Type [] {typeof(System.Collections.ArrayList)});
miLoadPlayList.Invoke(o,new object [] {list});
}
else
{
foreach (string key in ttable)
{
otype = atable[key] as Type;
ArrayList item_list = new ArrayList();
miLoadPlayList = otype.GetMethod("LoadPlayList",
new Type [] {typeof(System.Collections.ArrayList)});
o = ol[key];
miLoadPlayList.Invoke(o,new object [] {item_list});
list.AddRange(item_list);
}
}
}
catch (Exception ex)
{
LogError(ex);
}
finally
{
................
}
}
private static MethodInfo miLoadPlayList = null;
..........
}
}
where <?xml version="1.0" encoding="utf-8"?>
<config>
<sactserver ip="127.0.0.1" port="1221" path="/" channelexpires="120" channelpersists="false" />
<holder>
<!--Auto generated nodes, edit with caution!-->
<assembly secured="true"
default="true" feature-index="0"
atoken="/MediaPlayer/MediaClients_0.ctk"
id="e6f511d2-f9f9-4ad6-b700-2505b92c64dc"
depend_id=""
name="MediaClients, Version=0.2.2059.28511, Culture=neutral, PublicKeyToken=null"
display="Media Clients">
<description />
<server ip="127.0.0.1" port="1221" />
<gui type="Media.Mp3Player,Mp3Player" show-background="images\Img12345.jpg" />
<interface type="Media.IStreamClient" wrapper="Media.Mp3ClientSocket" >
<type name="Media.Mp3Client" activate="true" ext=".mp3" descr="MP3 Audio"/>
<type name="Media.Equlizer" activate="false" ext=".mp3" descr="MP3 Filter"/>
</interface>
</assembly>
</holder>
</config>
Step 3: The implementationThe implementation is then performed. During the process a need may arises to go to a previous step. Step 4: The Test ProcessThen the test is carried out. During the process a need may arises to go to a previous step. Step 5: Done?If not, go to a previous steps, otherwise exit the process. C. The RealizationMost of design goals discussed above are realized and tested in various .Net programs of CryptoGateway that are in private use, under evaluation, or for public download. Although not a single one contains a realization of all of them, their combination does not have foreseeable obstacles. Assembly Protection and Distribution
An IntroductionThe data access control technology of CryptoGateway is based on a declarative identity management and access right distribution system using cryptographic (RSA and AES) means. It can be applied to any digital data. Access right is distributed using soft tokens containing authentication information about the producer and the user through conventional communication channels like e-mail. The soft access token is secured using the same access control method. The production and distribution process is schematically shown in Fig. 3. For more details, interested read should read articles following the links given above. .Net AssembliesThey are not special in terms of crypo-images production, access token distribution and user access. More details on how this is accomplished is given here. What is special is the client, called "Secured Assembly Loader" in Fig. 1, of the process server hosted by the crypto-gateway server. It is specifically designed to communicate to the said server to load .Net assemblies, to connect to the authentication user interface, etc.. The one for the media player is written in C#. The process server do the actual job of authenticating the user. It also make sure that the data is indeed signed by the producer in the background. Valid data will be loaded only after both the user is authenticated and the producer's digital signature is verified. After the data is load by the above mentioned loader, it will try to generate an assembly by calling Assemb assembly = Assembly.Load(data);
Type type = assembly.GetType("...type name ...");
ConstructorInfo cinfo = type.GetConstructor(....);
object obj = cinfo.Invoke(args);
....
MethodInfo minfo = type.GetMethod(...);
minfo.Invoke(...);
....
PropertyInfo pinfo = type.GetProperty(...);
pinffo.GetValue(obj,...);
pinfo.SetValue(obj,...);
......
FieldInfo finfo = type.GetField(...);
finfo.GetValue(obj);
finfo.SetValue(obj,...);
......
where "data" is a byte array containing the serialized assembly data recovered by the process server. After the assembly is successfully constructed, reflection can be used to create instances and access their members. Unloading of these assembly is also possible by calling the In the design stage, various functional units used by the system should be partitioned into to a set of assemblies taking into account of the fact that .Net assemblies are not a The factorization should also be geared towards logical separation of responsibilities. The host, as an upper layer, should treat various components in as little different ways as possible, which can be achieved by making the components as self-sustaining and self-describing as possible. This is called the principle of "maxium symmetry" in this article. A reader might encounter similar principle in studies on information/statistics related subjects under the name "maximum entropy" with its roots in statistic physics (try to search this site, a reader can find a few). "Symmetry", which is related to certain kind of invariance, is used because something is known is going to be put in a proper order. It is a better term for engineering. "Entropy", on the other hand, is related to things that are unknown that are going to be known or learnt. In fact better learning strategy also involves putting what's needed to be known next in a proper order, better engineering should also admit that there are unknowns. On artistic side the principle could result in greater simplicity in code. On practical side it leads to increased code reusability (invariance!), reduced maintenance cost and opened possibility for future expansion. The practice following this principle is also expected to result in a increase of code performance because passing messages (call request) through socket->host->sockets layers and Admittedly, the above formalization process generates a significant number of higher-level assemblies and classes (interfaces, sockets, configuration files, etc..) from classes where the real job is done. The synchronization between these classes in the iterative code development process is tedious and could be error prone. This pre-processing job can in fact be automated by taking advantage of the reflection capability of .Net and other frameworks. The use of software tools, like the x-script generator, can greatly simplify the tasks and reduce the possibility of code inconsistency. The post-processing, including compiling, signing of digital signature, encryption, initial access token distribution, registration, packing, uploading, etc., can also be streamlined using these tools too. Points of InterestIt can be expected that the application of the same idea to Java assembly (bytecode) is straightforward since these two frameworks share a lot of similarities in the aspects that are relevant to code protection and the plug-in (-out) framework introduced here. As a reader already know, this article is written in a as general as possible form, it provides an ideal or background reference that hopefully will result in designs and structures that allow later transition to a more flexible system with less effort for those who use it. For simple applications, it is an overkill. In actual implementations, depending on the scale, flexibility, and future expansion requirements, a lot of the socket layers, interfaces definitions and code protection steps can be skipped or short circuited, at least in the early rounds/versions of the system, only taking into account of the possibility of expand it is required during the factorization process. To DoContinue expansion of the "etc.", etc..
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||