Saturday, October 31, 2009
Introduction
Introduction
This book is about using cryptography with Java.
Depending on who you are, you may think of cryptography
as a great menace or as a very useful tool. The truth is that in some
ways it is neither, in other ways it is both. It's neither because, if
you choose, you could easily reduce it to an interesting mathematical
game, with no application. It's both because it most definitely gets
applied, not always well, and not always for purposes that everyone
agrees with. Whichever side of the fence you are on, the one thing
everyone agrees with is that the politics surrounding cryptography and
access to the technology that allows you to use it have been intense.
Java, on the other hand, is simply a programming
language. It arrived on the popular scene in 1995 and has become very
popular as a language for writing applications involving the Internet,
electronic commerce, or a combination of the two. Other than the odd,
often "religious," issue between programmers or companies, the language
itself has carried none of the political problems that have accompanied
cryptography. However, a language by itself won't allow you to develop
secure Internet applications, so it quickly became apparent that it
would be necessary to introduce into Java APIs that allowed people to
make use of cryptography. When this happened the politics arrived and,
for some, using Java suddenly got intense as well. Finally, the
politics subsided and we arrived where we are now, with a rich set of
APIs that allow developers to use cryptography effectively in
application development—providing they know how.
This brings me to why this book was written. People
will still wax lyrically about key sizes and PKI (Public Key
Infrastructure), but what does it all mean, and what does it mean when
you are using Java? The Java APIs afford you a great deal of
flexibility, and although this will allow you to implement an
application using cryptography at a fundamental level, it will also
allow you to tie yourself into some terrible knots. You can avoid this
if you understand a few principals about the way the APIs are put
together. Furthermore, by understanding the relationships between the
high-level APIs and the more fundamental ones, debugging becomes easier
and you can recognize when it is not necessary to build things from
scratch, as, in some cases, the hard work has already been done. In
short, with the right understanding, you can save yourself a lot of
work. This book has been written with the aim of providing that
understanding.
Who This Book Is For
This book is written for people who are Java
developers and are trying to make use of cryptography in their
applications and for people who simply want to understand what's going
on when cryptography is being used in Java applications. It does assume
you are familiar with the Java language, but it does not assume you
have any familiarity with any of the APIs it discusses, such as the
JCA, JCE, the Bouncy Castle APIs, and JavaMail.
If you are already very familiar with the JCE and
the JCA, you might want to skim the first four chapters quickly and
start reading thoroughly from Chapter 5
onward; otherwise, I would recommend you start at the beginning. If you
do skim the first four chapters, you should pay attention to the
development of the utilities class that is added at the start of most
chapters. The reason is that the utilities class used in Chapter 5 and onward builds on the work done in the first four chapters.
Chapter 1. Introduction to Agile Java Development
1. Introduction to Agile Java DevelopmentWHEN JAVA DEVELOPMENT KIT (JDK) v1.0 was released in January 1996, it was a fairly straightforward application programming interface (API). Over the years, Java has matured into a full-blown platform. From JDK 1.0 to JDK 1.5, we have been introduced to many new features, such as the Java Collections Framework, logging API, auto-boxing, generics, and more. Although most of these are useful, Java has also become more complex, especially after the advent of the Java Platform Enterprise Edition (JEE). JEE introduced such concepts as Enterprise JavaBeans (EJB), which sought to simplify vendor-portable, enterprise-level distributed computing, but instead, it introduced unnecessary complexities for 80% of the applications out there. Nowadays, it is not uncommon for many people to think of Java/JEE as being a big and heavy technology. Well, for starters, this couldn't be further from the truth, and second, let's see if we can change this perspective in this book. In the past few years, many open source frameworks have sprung up to solve some of the problems created by JEE. This book covers some of these open source frameworks (for example, Spring and Hibernate) as well as open source tools (such as Ant and Eclipse), which provide a comprehensive, effective, and elegant solution that can either be viewed as complementary or as a complete alternative to JEE, depending on how you apply these technologies for your specific needs. In addition, nimble software development processes such as Extreme Programming (XP) and Agile Model Driven Development (AMDD) can assist in accelerating the project delivery. Software development is about people, processes, and technology (and probably in that order of priority). The people are the stakeholders, the customer we build software for. In this book, I will cover the process and technology parts. You will learn how to leverage these tools and technologies to rapidly develop end-to-end applications using Java, from the client tier to the data tier, and more. Along the way, you should see many of the benefits resulting from using these tools and technologiesfor example, simplicity and speed of development. Before we begin, if you have not read the preface, I would recommend at least glancing through it because it provides some foundation for the goals of this book and the way it is organized, and includes some reasons why I wrote this book. |
Lab 8.1 Exercise Answers
[ Team LiB ] |
Lab 8.1 Exercise AnswersThis section gives you some suggested answers to the questions in Lab 8.1, with discussion related to how those answers resulted. The most important thing to realize is whether your answer works. You should figure out the implications of the answers here and what the effects are from any different answers you may come up with. 8.1.1 Answers
Every time the loop is run, the statements in the body of the loop are executed. In this script, the value of v_counter is incremented by 1 and displayed on the screen. The EXIT condition is evaluated for each value of v_counter. Once the value of v_counter increases to 5, the loop is terminated. For the first iteration of the loop, the value of v_counter is equal to 1, and it is displayed on the screen, and so forth. After the loop has terminated, "Done..." is displayed on the screen.
Once the value of v_counter increases to 5, the IF statement
evaluates to TRUE, and the loop is terminated. The loop counter tracks the number of times the loop is executed. You will notice that in this exercise, the maximum value of v_counter is equal to the number of times the loop is iterated.
The EXIT condition is used as a part of an IF statement. The IF statement evaluates the EXIT condition to TRUE or FALSE, based on the current value of v_counter.
Assume that the loop has iterated four times already. Then the value of v_counter is incremented by 1, so v_counter is equal to 5. Next, the IF statement evaluates the EXIT condition. The EXIT condition yields TRUE, and the loop is terminated. The DBMS_OUTPUT.PUT_LINE statement is not executed for the fifth iteration of the loop because control is passed to the next executable statement after the END LOOP statement. Thus, only four values of v_counter are displayed on the screen.
Notice that the IF statement has been replaced by the EXIT WHEN statement. The rest of the statements in the body of the loop do not need to be changed. 8.1.2 Answers
If the course number is not valid, the INSERT statement
will cause an exception to be raised. As soon as an exception is raised, control is passed out of the loop to the exception handler. Therefore, if the course number is not valid, the loop will be executed only once.
In order to add 10 sections for the given course number, the test value of v_sec_num in the EXIT condition is changed to 10. Note that before you execute this version of the script you need to delete records from the SECTION table that were added when you executed the original example. If you did not run the original script, you do not need to delete records from the SECTION table. The SECTION table has a unique constraint defined on the COURSE_NO and SECTION_NO columns. In other words, the combination of course and section numbers allows you to uniquely identify each row of the table. When the original script is executed, it creates four records in the SECTION table for course number 430, section numbers 1, 2, 3, and 4. When the new version of this script is executed, the unique constraint defined on the SECTION table is violated because there already are records corresponding to course number 430 and section numbers 1, 2, 3, and 4. Therefore, these rows must be deleted from the SECTION table as follows:
Once these records are deleted from the SECTION table, you can execute the new version of the script.
|
[ Team LiB ] |
Chapter 8: Behavioral Patterns
|
Chapter 8: Behavioral Patterns
The patterns in this chapter are used to organize, manage, and combine behavior.
Chain of Responsibility
This pattern was previously described in [GoF95].
Synopsis
The Chain of Responsibility pattern allows an object to send a command without knowing what object or objects will receive it. It accomplishes this by passing the command to a chain of objects that is typically part of a larger structure. Each object in the chain may handle the command, pass the command on to the next object in the chain, or do both.
Context
Suppose that you are writing software to monitor a security system. Physically, the security system consists of sensing devices (motion detectors, smoke detectors, etc.) that transmit status information to a computer. The computer’s job is to log all status information, maintain a display showing current status information, and transmit alarms in the event of an emergency.
One of the goals for the monitoring software is that it should be highly scalable. It should be able to work for a small retail store, an office building, a warehouse, or a multi-building complex. That goal has implications for the way that you design the monitoring software.
To keep things simple, your monitoring program should instantiate an object for every sensor it is to monitor. This provides a simple way to model each sensor’s state. To ensure scalability, an object responsible for an individual sensor should not assume anything about its environment, except that it is at the bottom level of a hierarchical organization.
The organization will include objects corresponding to real-world things such as rooms, areas, floors, and buildings. Directly modeling the real world provides a straightforward way to display the status of different parts of buildings. It also allows the interpretation of a sensor’s state to be based on its environment. For example, if the temperature of a closed room exceeds 180°F, then you may want the fire sprinklers in just that room to turn on. If the temperature in an open area of a warehouse exceeds 150°F, you may want to turn on the fire sprinklers over that area and the adjacent areas. On the other hand, if the temperature in a freezer exceeds 30°F, you may want to sound an alarm to let people know that that freezer is getting too warm.
In all these cases, the object that models a sensor does not decide what to do with the state of the sensor. Instead, it delegates that decision to an object at a higher level of the hierarchy that has more contextual knowledge. Such objects either decide what to do about a notification or pass it on to the object that is organizationally above it.
Figure 8.1 shows an example of objects organized in this hierarchical way.
Figure 8.1: Physical security object organization
For example, when a TemperatureSensor object contained in an area of a warehouse receives a notification of the current temperature from the physical sensor, it passes that notification to the Area object that contains it. Rather than decide the significance of the temperature, it passes the notification to the Warehouse object that contains the Area object. The Warehouse object determines the meaning of the temperature. If the temperature is above 150°F, the Warehouse object decides that there is a fire. It turns on the sprinklers in the area that notified it and the surrounding areas. The Warehouse object does not pass on the temperature notification.
Forces
| You want an object to be able to send a command to another object without specifying the receiver. The sending object does not care which object handles the command, only that an object will receive the command and handle it. |
| You want the receivers of a command to be able to handle the command without having to know anything about the object that sent the command. |
| More than one object may be able to receive and handle a command, so you need a way to prioritize among the receivers without the sending object knowing anything about them. |
| The objects you may want to potentially handle commands are organized into a structure that can serve to prioritize among the potential handlers of a command. |
Solution
Figure 8.2 presents a class diagram that shows the organization of the Chain of Responsibility pattern. Following are explanations of the roles these classes play in the Chain of Responsibility pattern:
Figure 8.2: Chain of Responsibility pattern.
CommandSender. Instances of a class in this role send commands to the first object in a chain of objects that may handle the command. They send a command by calling the first CommandHandlerIF object’s postCommand method.
CommandHandlerIF. All objects in a chain of objects that may handle a command must implement an interface in this role. It defines two methods.
It defines a handleCommand method to handle whatever commands an implementing class is expected to handle. The handleCommand method returns true if it handled a command or false if it did not.
2. It defines a postCommand method that calls the handleCommand method. If the handleCommand method returns false and there is a next object in the chain, it calls the object’s postCommand method. If the handleCommand method returns true, it means there is no need to pass the command on to the next object in the chain.
AbstractCommandHandler. Classes in this role are abstract classes that implement the postCommand method. The purpose of this is to provide the convenience of a common implementation of postCommand for classes in the ConcreteCommandHandler role. It is very unusual for classes to want anything other than the default logic for the postCommand method. Classes in the CommandSender role should refer to objects in a chain of responsibility only through the CommandHandlerIF interface and not as instances of the AbstractCommandHandler class. The AbstractCommandHandler class is an implementation detail. Though unusual, it is possible to have classes that implement the CommandHandlerIF interface that are not subclasses of the AbstractCommandHandler class.
ConcreteCommandHandler1, ConcreteCommandHandler2, and so on. Instances of classes in this role are objects in a chain of objects that can handle commands.
Typically, CommandHandler objects are part of a larger structure. This is the case in the example shown in Figure 8.1.
Implementation
In many cases, the objects that constitute a chain of responsibility are part of a larger structure, and the chain of responsibility is formed through some links of that larger structure. When links to form a chain of responsibility do not already exist, you must add instance variables and access methods to the classes to create links that form a chain of responsibility.
A decision to make, whenever implementing the Chain of Responsi bil ity pattern, is how you will pass commands to and through the chain of objects. There are two basic ways to do it. One way is to encapsulate each kind of command in a single object that can be passed to a single postCommand method. The other way is to have as many different types of postCommand and handleCommand methods as there are different types of information associated with commands.
Passing commands in a single object is often the better choice. It incurs the cost of object creation but minimizes the cost of passing parameters to the methods of the next object in the chain. That minimizes the cost of propagating a command through a chain of objects. Passing commands in a single object usually results in less code.
On the other hand, passing the information that constitutes a command through separate parameters saves the cost of object creation at the cost of additional parameter passing. If you know that the chain of objects will be short, passing a command as multiple parameters can be the better choice.
Consequences
| The Chain of Responsibility pattern reduces coupling between the object that sends a command and the object that handles the command. The sender of a command does not need to know what object will actually handle the command. It merely needs to be able to send the command to the object that is at the head of the chain of responsibility. |
| The Chain of Responsibility pattern allows flexibility in deciding how to handle commands. Decisions about which object will handle a command can be varied by changing which objects are in the chain of responsibility or changing the order of the objects in the chain of responsibility. |
| The Chain of Responsibility pattern does not guarantee that every command will be handled. Commands that are not handled are ignored. |
| If the number of objects in a chain becomes large, there can be efficiency concerns about the amount of time that it takes a command to propagate through the chain. A high percentage of commands that are not handled exacerbates the problem because commands that are not handled are propagated through the full length of the chain. |
Java API Usage
Version 1.0 of Java used the Chain of Command pattern to handle user- interface events. That event-handling scheme used a user interface’s container hierarchy as a chain of responsibility. When an event was posted to a button or other GUI component, it would either handle the event or post it to its container. Though it was usable, there were enough problems that the creators of Java took the drastic step of changing Java’s event model. The two most serious problems related to efficiency and flexibility are as follows:
| Some platforms generate many events that most GUIs do not handle or have any interest in. One such event is MOUSE_MOVE. It may be generated every time a mouse moves just one pixel. Some programs that were built using the original event model visibly slowed down whenever there was rapid mouse movement because they spent so much time passing MOUSE_MOVE events that were never handled through the container hierarchy. |
| The Chain of Responsibility pattern assumes that all the objects that can handle a command are instances of a common superclass or implement a common interface. This limits a program to posting commands to instances of that common superclass or interface. Java’s original event model required that every object that could handle an event was an instance of the common superclass Component. This meant that it was impossible to deliver events directly to non-GUI objects, since only GUI objects are instances of Component. |
This second problem is actually an advantage for some applications. The Chain of Responsibility pattern makes it less convenient to deliver commands to objects that are not part of the chain of handlers. For some applications, delivering a command to an object outside the chain of handlers is most likely a bug. The physical security example discussed under the Context heading is an example of such an application. For applications such as this, using the Chain of Responsibility pattern will result in fewer opportunities to introduce bugs into the application than will be using the delegation event model.
Another advantage that the Chain of Responsibility has over the delegation event model is that it allows you to explicitly control the order in which commands are delivered to handlers.
Code Example
Continuing the physical security example, Figure 8.3 shows the classes used in the physical security example.
The delegation event model involves three kinds of objects:
| Event sources are objects that are a source of information about the occurrence of some sort of event. |
| Event listeners are objects that want to be informed that some particular sort of event has occurred. |
| Events are objects that encapsulate information about the occurrence of an event. |
Event source objects pass event objects to event listener objects. Event objects are an instance of a subclass of the java.util.EventObject class.
There is a naming convention that gives structure to the delegation event model. We will illustrate the naming convention using action events.
Action events are represented using the ActionEvent class. In order for instances of a class to be able to receive action events, the class must implement the ActionListener interface. Interfaces such as ActionListener declare one or more void methods that will be passed the appropriate event type. Classes that are sources of action events define methods called addActionListener and removeActionListener. These methods allow ActionListener objects to be registered and unregistered to receive action events from an object that is a source of action events.
For more information about the delegation event model, see the JavaBeans specification, which you can find at http://java/sun.com/products/javabeans/docs/spec.html.
In Figure 8.3, the classes that extend the Sensor class call the notify method they inherit from it to report a measurement to the object that is responsible for handling its measurements. Classes that extend the AbstractSecurityZone class are responsible for handling measurements from the appropriate kind of Sensor object.
Figure 8.3: Physical security classes.
The following is some code for the classes shown in Figure 8.3. First, here is code for the TemperatureSensor class. Notice that the TemperatureSensor class does nothing with a reading from a temperature sensor but pass it on.
class TemperatureSensor extends Sensor {
private SecurityZone zone;
...
/**
* When the temperature sensor associated with this object
* observes a different temperature this method is called.
*/
void notify(int measurement) {
zone.notify(measurement, this);
} // notify(int)
} // class TemperatureSensor
All of the classes that model security zones implement that SecurityZoneIF interface:
public interface SecurityZoneIF {
/**
* This method is called to notify this security zone of a
* change in a sensor measurement.
*/
public void notify(int measurement, Sensor source) ;
/**
* This method is called by a child zone to report a fire.
*/
public void fireAlarm(SecurityZone zone) ;
} // interface SecurityZoneIF
Here is the code for the SecurityZone class, which is the superclass of all of the classes that form the chains of responsibility in this example:
abstract class SecurityZone implements SecurityZoneIF {
private SecurityZone parent;
...
/**
* Return this object's parent zone.
*/
SecurityZone getParent() {
return parent;
} // getParent()
/**
* Call this method to notify this zone of a new sensor
* measurement.
*/
public void notify(int measurement, Sensor sensor) {
if (!handleNotification(measurement, sensor)
&& parent != null) {
parent.notify(measurement, sensor);
} // if
} // notify(int, Sensor)
/**
* This method is called by the notify method so that
* this object can have a chance to handle measurements.
*/
protected
abstract boolean handleNotification(int measurement,
Sensor sensor);
/**
* This method is called by a child zone to report a fire.
* It is expected that the child zone has turned on
* sprinklers or taken other measures to control the fire
* within the child zone. The purpose of this method is to
* be overridden by subclasses so it can take any
* necessary actions outside of the child zone.
*/
public void fireAlarm(SecurityZone zone) {
// Turn on sprinklers
...
if (parent != null)
parent.fireAlarm(zone);
} // fireAlarm(SecurityZone)
} // class SecurityZone
Here are the subclasses of SecurityZone that were discussed under the Context heading:
class Area extends SecurityZone {
...
/**
* This method is called by the notify method so that this
* object can have a chance to handle measurements.
*/
boolean handleNotification(int measurement,Sensor sensor){
if (sensor instanceof TemperatureSensor) {
if (measurement > 150) {
fireAlarm(this);
return true;
} // if
} // if
...
return false;
} // handleNotification(int, Sensor)
} // class Area
class Warehouse extends SecurityZone {
...
/**
* This method is called by the notify method so this
* object can have a chance to handle measurements.
*/
protected
boolean handleNotification(int measurement,Sensor sensor){
...
return false;
} // handleNotification(int, Sensor)
public void fireAlarm(SecurityZone zone) {
if (zone instanceof Area) {
// Turn on sprinklers in surrounding areas
...
// Don't call super.fireAlarm because that will
// turn on sprinklers for the whole warehouse.
if (getParent() != null)
getParent().fireAlarm(zone);
return;
} // if
...
super.fireAlarm(zone);
} // fireAlarm(SecurityZone)
} // class Warehouse
Related Patterns
Composite. When the chain of objects used by the Chain of Responsibility pattern is part of a larger structure, the larger structure is usually built using the Composite pattern.
Command. The Chain of Responsibility pattern makes the particular object that executes a command indefinite. The Command pattern makes the object that executes a command explicit and specific.
Template Method. When the objects that make up a chain of responsibility are part of a larger organization built using the Composite pattern, the Template Method pattern is often used to organize the behavior of individual objects.
Section 21.5. Tuning DML (INSERT, UPDATE, DELETE)
21.5. Tuning DML (INSERT, UPDATE, DELETE)The first principle for optimizing UPDATE, DELETE, and INSERT statements is to optimize any WHERE clause conditions used to find the rows to be manipulated or inserted. The DELETE and UPDATE statements may contain WHERE clauses, and the INSERT statement may contain SQL that defines the data to be inserted. Ensure that these WHERE clauses are efficientperhaps by creating appropriate concatenated indexes The second principle for optimizing DML performance is to avoid creating too many indexes. Whenever a row is inserted or deleted, updates must occur to every index that exists against the table. These indexes exist to improve query performance, but bear in mind that each index also results in overhead 21.5.1. Batching InsertsThe MySQL language allows more than one row to be inserted in a single INSERT operation. For instance, the statement in Example 21-21 inserts five rows into the clickstream_log table in a single call. Example 21-21. Batch INSERT statement
Batching INSERT operations in this way can radically improve performance. Figure 21-10 shows how the time taken to insert 10,000 rows into the table decreases as we increase the number of rows included within each INSERT statement. Inserting one row at a time, it took about 384 seconds to insert the rows. When inserting 100 rows at a time, we were able to add the same number of rows in only 7 seconds. Figure 21-10. Performance improvement from multirow inserts
21.5.2. Optimizing DML by Reducing Commit FrequencyIf we are using a transactional storage enginefor instance, if our tables are using the InnoDB enginewe should make sure that we are committing changes to the database only when necessary. Excessive commits will degrade performance. By default, MySQL will issue an implicit commit after every SQL statement. When a commit occurs, a storage engine like InnoDB will write a record to its transaction log on disk to ensure that the transaction is persistent (i.e., to ensure that the transaction will not be lost if MySQL or our program crashes). These transaction log writes involve a physical I/O to the disk and therefore always add to our response time. We can prevent this automatic commit behavior by issuing the SET AUTOCOMMIT=0 statement and/or by issuing a START TRANSACTION statement before issuing our statements. We can then issue a COMMIT statement at regular intervals, reducing the number of writes to the transaction log that will be required. (Note, though, that MySQL will occasionally write to the transaction log anyway when memory buffers require flushing.) Usually, the frequency with which we commit is driven by our application logic rather than by performance. For instance, if a user clicks a Save button in our application, he is going to expect that the information will be permanently saved to the database, and so we will be required to issue a COMMIT as a result. However, in batch applications, we can often choose to commit at relatively infrequent intervals. Reducing the commit frequency can have a huge effect on DML performance. In Figure 21-11, we see how reducing the commit frequency affected the time taken to insert 10,000 rows into the database. At the default settings, it took about 850 seconds (about 14 minutes) to insert the 10,000 rows. If we commit only after every 100 rows have been inserted, the time taken is reduced to only 8 seconds. In these tests, the InnoDB transaction log was on the same disk as the InnoDB tablespace files, which magnified the degradation caused by transaction log writes. Moving the transaction log to a dedicated disk can reducealthough not eliminatethe transaction log overhead. Figure 21-11. How commit frequency affects DML performance
We looked at how you can manipulate commit frequency in stored programs in Chapter 8. 21.5.3. Triggers and DML PerformanceBecause trigger code will be invoked for every row affected by the relevant DML operation, poorly performing triggers can have a very significant effect on DML performance We provide some more advice on trigger tuning in Chapter 22. |
Recipe 10.12. Evaluating Code in an Earlier Context
Recipe 10.12. Evaluating Code in an Earlier ContextProblemYou've written a method that evaluates a string as Ruby code. But whenever anyone calls the method, the objects referenced by your string go out of scope. Your string can't be evaluated within a method. For instance, here's a method that takes a variable name and tries to print out the value of the variable.
The eval code only works when it's run in the same context as the variable definition. It doesn't work as a method, because your local variables go out of scope when you call a method.
SolutionThe eval method can execute a
DiscussionA Binding object is a bookmark of the Ruby interpreter's state. It tracks the values of any local variables you have defined, whether you are inside a class or method definition, and so on. Once you have a Binding object, you can pass it into eval to run code in the same context as when you created the Binding. All the local variables you had back then will be available. If you called Kernel#binding within a class definition, you'll also be able to define new methods of that class, and set class and instance variables. Since a Binding object contains references to all the objects that were in scope when it was created, those objects can't be garbage-collected until both they and the Binding object have gone out of scope. See Also
|
Encryption Examples
Encryption Examples
The purpose of this section is to give an overview of how encryption can be performed with different data. You’ll see a few examples of encrypting data with various algorithms. To start, a simple encryption of character data is presented. The output will be viewed both as a string and as a RAW. The decryption is done to verify that you can successfully recover the original data:
sec_mgr@KNOX10g> DECLARE
2 l_plaintext VARCHAR2 (12) := 'This is data';
3 l_key VARCHAR2 (20) := 'This is the Key';
4 l_encrypted_text VARCHAR2 (24);
5 l_encrypted_raw RAW (24);
6 l_decrypted_text VARCHAR2 (`20);
7 BEGIN
8 l_encrypted_raw := data_crypto.encrypt_char (l_plaintext, l_key);
9 l_encrypted_text := data_crypto.encrypt (l_plaintext, l_key);
10 l_decrypted_text := data_crypto.decrypt (l_encrypted_text, l_key);
11 DBMS_OUTPUT.put_line ('PlainText: ' || l_plaintext);
12 DBMS_OUTPUT.put_line ('Key: ' || l_key);
13 DBMS_OUTPUT.put_line ('Encrypted RAW: ' || l_encrypted_raw);
14 DBMS_OUTPUT.put_line ('Encrypted string: ' || l_encrypted_text);
15 DBMS_OUTPUT.put_line ('Decrypted: ' || l_decrypted_text);
16 END;
17 /
PlainText: This is data
Key: This is the Key
Encrypted RAW: A84513EC540BF7E87BCA3AF29A0CAD34
Encrypted string: e ^ ' = 8. = T^¯óRí
Decrypted: This is data
Invoking encryption is done very easily. The challenge remains as to how to store encrypted data and how to mange the encryption keys. All of these issues will be addressed after a few more preliminary points are made.
Encrypting Character, Numbers, and Dates
Three of the basic data types you may be encrypting and storing are character, number, and dates. As seen in the next example, this can be accomplished fairly easy using the DATA_CRYPTO package. A simple table is created and populated with an encrypted string, number, and date:
sec_mgr@KNOX10g> CREATE TABLE enc_val_tab
2 (charval RAW(32),
3 dateval RAW(64),
4 numval RAW(32));
Table created.
sec_mgr@KNOX10g> EXEC data_crypto.setkey('EncryptionKey');
PL/SQL procedure successfully completed.
sec_mgr@KNOX10g> INSERT INTO enc_val_tab
2 VALUES (data_crypto.encrypt_char (USER),
3 data_crypto.encrypt_date (SYSDATE),
4 data_crypto.encrypt_number (10));
1 row created.
sec_mgr@KNOX10g> COMMIT ;
You can see the data is stored encrypted and can be reconstructed through the decryption process:
sec_mgr@KNOX10g> COL "Character Data" format a20
sec_mgr@KNOX10g> COL "Number Data" format a20
sec_mgr@KNOX10g> COL "Date Data" format a20
sec_mgr@KNOX10g> -- Show stored data is encrypted. Have to convert
sec_mgr@KNOX10g> -- data from RAW to view.
sec_mgr@KNOX10g> SELECT UTL_RAW.cast_to_varchar2 (charval)
2 "Character Data",
3 UTL_RAW.cast_to_varchar2 (numval)
4 "Number Data",
5 UTL_RAW.cast_to_varchar2 (dateval)
6 "Date Data"
7 FROM enc_val_tab;
Character Data Number Data Date Data
-------------------- ----------------- ------------------
_6-?é?¤+P÷Q¥¯ ÷$ px b?¦$+êUâÿ¦ñ¦ä ¡ùµ¿ò-¦°'>+" ¦-¦
sec_mgr@KNOX10g> -- Show decrypted values
sec_mgr@KNOX10g> SELECT data_crypto.decrypt_char (charval)
2 "Character Data",
3 TO_CHAR(data_crypto.decrypt_number (numval))
4 "Number Data",
5 TO_CHAR
6 (data_crypto.decrypt_date (dateval),
7 'DD-MON-RRRR HH24:MI:SS')
8 "Date Data"
9 FROM enc_val_tab;
Character Data Number Data Date Data
----------------- ------------- -----------------
SEC_MGR 10 10-APR-2004 00:00:00
Everything in the preceding looks functional unless you wanted to preserve the time when you stored the date value.
Encrypting Dates and the NLS_DATE_FORMAT
Encrypting dates is a particularly onerous task. The date has to first be converted to a character string, then to a RAW (RAW data is the preferred way to store data). The decryption process must undergo the same steps in reverse order—RAW data is converted to character, then character is converted back to date.
To do this successfully, you have to ensure your NLS_DATE_FORMAT is set to capture all of the DATE attributes. For example, if the format is DD-MON-RR, then you will lose the time aspect of your date in the data casting operations. The DATA_CRYPTO package will perform the data casting, but you are responsible for ensuring the NLS_DATE_FORMAT is set appropriately.
This can be a bit more challenging than it might first appear. Notice that the user logged in through SQL*Plus does not get the database’s default NLS_DATE_FORMAT setting:
sec_mgr@KNOX10g> -- ** Show that current format only shows date not time **
sec_mgr@KNOX10g> COL date_format format a25
sec_mgr@KNOX10g> SELECT SYS_CONTEXT ('userenv', 'nls_date_format')
2 DATE_FORMAT,
3 SYSDATE
4 FROM DUAL;
DATE_FORMAT SYSDATE
------------- -------------
DD-MON-RR 10-APR-04
sec_mgr@KNOX10g> -- The current format was not set by the init.ora parameter
sec_mgr@KNOX10g> SHOW parameter nls_date_format
NAME TYPE VALUE
------------------- ------------------- ---------
nls_date_format string DD-MON-RRRR HH24:MI:SS
You can reset the date format by issuing an ALTER SESSION, but you will have to remember to do this every time prior to encrypting data. An alternative is to create a database logon trigger. Note that the trigger does not have to set everyone’s date format. The following trigger just alters the date format for the SEC_MGR and SCOTT users:
sec_mgr@KNOX10g> -- Create logon trigger to set date format to capture time.
sec_mgr@KNOX10g> -- Consider only setting format for specific users.
sec_mgr@KNOX10g> CREATE OR REPLACE TRIGGER nls_date_logon
2 AFTER LOGON ON DATABASE
3 BEGIN
4 IF USER IN ('SEC_MGR', 'SCOTT')
5 THEN
6 EXECUTE IMMEDIATE
7 'alter session set nls_date_format=''DD-MON-RRRR HH24:MI:SS'';
8 END IF;
9 END;
10 /
Trigger created.
sec_mgr@KNOX10g> -- Show new format
sec_mgr@KNOX10g> CONN sec_mgr/oracle10g
Connected.
sec_mgr@KNOX10g> SELECT SYS_CONTEXT ('userenv', 'nls_date_format')
2 DATE_FORMAT,
3 SYSDATE
4 FROM DUAL;
DATE_FORMAT SYSDATE
----------------- -----------------
DD-MON-RRRR HH24:MI:SS 10-APR-2004 11:20:07
sec_mgr@KNOX10g> -- NOTE the format is not set for all users
sec_mgr@KNOX10g> CONN system/manager
Connected.
system@KNOX10g> -- show new format
system@KNOX10g> SELECT SYS_CONTEXT ('userenv', 'nls_date_format')
2 DATE_FORMAT,
3 SYSDATE
4 FROM DUAL;
DATE_FORMAT SYSDATE
-------------- ------------
DD-MON-RR 10-APR-04
Once the NLS_DATE_FORMAT has been set appropriately, you’ll be able to preserve the time aspects of your date:
sec_mgr@KNOX10g> -- Remove previous records.
sec_mgr@KNOX10g> TRUNCATE TABLE enc_val_tab;
Table truncated.
sec_mgr@KNOX10g> -- Set encryption key
sec_mgr@KNOX10g> EXEC data_crypto.setkey('EncryptionKey');
PL/SQL procedure successfully completed.
sec_mgr@KNOX10g> -- Insert values. NLS_DATE_FORMAT will preserve time.
sec_mgr@KNOX10g> INSERT INTO enc_val_tab
2 VALUES (data_crypto.encrypt_char (USER),
3 data_crypto.encrypt_date (SYSDATE),
4 data_crypto.encrypt_number (10));
1 row created.
sec_mgr@KNOX10g> COMMIT ;
Commit complete.
sec_mgr@KNOX10g> -- Show decrypted values
sec_mgr@KNOX10g> COL "Character Data" format a20
sec_mgr@KNOX10g> COL "Date Data" format a20
sec_mgr@KNOX10g> SELECT data_crypto.decrypt_char (charval)
2 "Character Data",
3 TO_CHAR(data_crypto.decrypt_number (numval))
4 "Number Data",
5 TO_CHAR
6 (data_crypto.decrypt_date (dateval),
7 'DD-MON-RRRR HH24:MI:SS')
8 "Date Data"
9 FROM enc_val_tab;
Character Data Number Data Date Data
----------------- ------------- ----------
SEC_MGR 10 10-APR-2004 11:56:47
Encrypting CLOBs and BLOBs
The DBMS_CRYPTO package supports the encryption of CLOBs and BLOBs. However, this support is only manifested through the use of procedures. The DATA_CRYPTO package will convert these procedures to functions. For the CLOB data, the ciphertext is also returned as a CLOB.
In the following example, a table is created that holds CLOBs. This simulates a table that might hold large documents. A CLOB is inserted and then encrypted using a simple SQL update statement.
sec_mgr@KNOX10g> CREATE TABLE docs
2 (doc_id NUMBER(4),
3 doc CLOB)
4 /
Table created.
sec_mgr@KNOX10g> INSERT INTO docs
2 VALUES (1, 'This is CLOB data');
1 row created.
sec_mgr@KNOX10g> COMMIT ;
Commit complete.
sec_mgr@KNOX10g> EXEC data_crypto.setkey('This is the Key');
PL/SQL procedure successfully completed.
sec_mgr@KNOX10g> UPDATE docs
2 SET doc = data_crypto.encrypt (doc);
1 row updated.
sec_mgr@KNOX10g> COL Encrypted format a32
sec_mgr@KNOX10g> COL Decrypted format a32
sec_mgr@KNOX10g> SELECT doc encrypted, data_crypto.decrypt (doc) decrypted
2 FROM docs;
ENCRYPTED DECRYPTED
------------------------------ ----------------
??N??¦ôa+2IDJ°?-#?_-4o_ÉÖx+| æ{ This is CLOB data
To test the BLOB encryption, a file is loaded from the file system and stored as a BLOB in the table. The BLOB is then encrypted using a SQL update statement. To verify this process, the BLOB is converted to a CLOB and the value is printed. To begin, a file directory is created and access to the directory is granted to SEC_MGR:
system@KNOX10g> CREATE OR REPLACE DIRECTORY doc_dir AS
2 'C:\tmp\esbd';
Directory created.
system@KNOX10g> GRANT ALL ON DIRECTORY doc_dir TO sec_mgr;
Grant succeeded.
The DOCS table is modified to hold the BLOB files. The file can be loaded into the table using the DBMS_LOB package. Once loaded, the BLOB can be easily encrypted.
sec_mgr@KNOX10g> DROP TABLE docs;
Table dropped.
sec_mgr@KNOX10g> CREATE TABLE docs
2 (doc_id NUMBER(4),
3 doc BLOB)
4 /
Table created.
sec_mgr@KNOX10g>
sec_mgr@KNOX10g> DECLARE
2 l_blob BLOB;
3 l_bfile BFILE;
4 BEGIN
5 INSERT INTO docs
6 VALUES (1, EMPTY_BLOB ())
7 RETURNING doc
8 INTO l_blob;
9
10 l_bfile := BFILENAME ('DOC_DIR', 'sample.xml');
11 DBMS_LOB.fileopen (l_bfile);
12 DBMS_LOB.loadfromfile (l_blob,
13 l_bfile,
14 DBMS_LOB.getlength (l_bfile));
15 DBMS_LOB.fileclose (l_bfile);
16 END;
17 /
PL/SQL procedure successfully completed.
sec_mgr@KNOX10g> EXEC data_crypto.setkey('This is the Key');
PL/SQL procedure successfully completed.
sec_mgr@KNOX10g> UPDATE docs
2 SET doc = data_crypto.encrypt (doc);
1 row updated.
sec_mgr@KNOX10g> COMMIT ;
Commit complete.
Verifying the contents requires a BLOB to CLOB conversion. The BLOB is decrypted, then converted to a CLOB that is printed. The resulting decryption can be compared to the original by using the SQL*Plus Host command:
sec_mgr@KNOX10g> DECLARE
2 l_encrypted_blob BLOB;
3 l_decrypted_blob BLOB;
4 l_decrypted_clob CLOB;
5 l_lang NUMBER := DBMS_LOB.default_lang_ctx;
6 l_warning NUMBER;
7 l_t_offset NUMBER := 1;
8 l_src_offset NUMBER := 1;
9 BEGIN
10 SELECT doc
11 INTO l_encrypted_blob
12 FROM docs;
13
14 DBMS_LOB.createtemporary (l_decrypted_blob, TRUE);
15 DBMS_LOB.createtemporary (l_decrypted_clob, TRUE);
16 -- decrypt BLOB
17 l_decrypted_blob := data_crypto.decrypt (l_encrypted_blob);
18 -- convert to CLOB for display
19 DBMS_LOB.converttoclob (l_decrypted_clob,
20 l_decrypted_blob,
21 DBMS_LOB.lobmaxsize,
22 l_t_offset,
23 l_src_offset,
24 DBMS_LOB.default_csid,
25 l_lang,
26 l_warning
27 );
28 DBMS_OUTPUT.put_line (l_decrypted_clob);
29 END;
30 /
<?xml version="1.0"?>
<document>
<value>security rawks</value>
</document>
PL/SQL procedure successfully completed.
You can see this data corresponds with the data in your file:
sec_mgr@KNOX10g> HOST cat C:\tmp\esbd\sample.xml
<?xml version="1.0"?>
<document>
<value>security rawks</value>
</document>
This example used an XML file, which would probably be stored in a CLOB or as an XMLType. You cannot encrypt an XMLType because the database interprets and validates the XML automatically; trying to store encrypted data in this type will fail. BLOBs are ideal for storing true binary data, such as images and audio data. Encrypting this data provides added security.
Attack of the Cellular Automata
[ Team LiB ] |
Attack of the Cellular AutomataThe computer game of Life (first created by Tom Conway) spawned the whole field of study of cellular automata. Will Wright used cellular automata to build SimCity. However, I always thought that it might be fun to fight a war with cellular automata. In this game, the playfield would be a standard array of cellular automata, and the two players would occupy opposite corners. The goal of the game is simple: destroy the enemy's fortress. You do this by launching gliders in his direction. He fends off your gliders with his own. Both of you have the ability to place standard units near your fortress. Gliders are one example; glider factories are another. But you can also place defensive units such as crosses and stars that act like temporary walls. The most important units you can place are "resource factories." These are very expensive, stable units that generate "resource points." These resource points are spent every time you place a unit; if you don't have any resource points, you can't place any units. So you must build and protect your resource factories. Using standard game of Life rules, the defense would always have a large advantage over the offense, so some tweaks would be necessary to balance the system. There are plenty of ways to do this. One design solution would be to permit players to modify the rules of individual cells by hitting them with special weapons. For example, one could build a "bomber glider" set to detonate after a specified number of generations; when it explodes, all the cells within the blast radius are modified in such a way as to prevent enemy activity from taking place in those cells for a set period of time. Players could thereby build a safe channel that could be traversed by their own gliders only. Bomber gliders could affect their targets in a variety of ways. The basic rules of cellular generation could be altered to render an area dead or overproductive. A dead area blocks activity, while an overproductive region generates lots of dangerous radiation. |
[ Team LiB ] |
2.1 Windows Graphics System Components
[oR] 2.1 |
< BACK  NEXT > |