Friday, October 30, 2009

Cross-Thread UI Component Calls and Invoke()



Chapter 10 -
Multithreaded Applications
Microsoft Visual Studio 2008 Programming
by Jamie Plenderleith and Steve Bunn 
McGraw-Hill/Osborne © 2009























Cross-Thread UI Component Calls and Invoke()


If you are starting a worker thread from the main UI thread after a button click or some other event, very often the worker thread will need to communicate something back to the UI. So, once you have fired off a new thread to perform some work in the background, there are two separate threads running in the application. This means that, in theory, we could do something like this:





Public Class Form1

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Dim myWorkerThread As New Thread(AddressOf WorkerMethod)
myWorkerThread.Start()
End Sub

Private Sub WorkerMethod()
For Each drive In My.Computer.FileSystem.Drives
Me.AddDrive(drive.Name)
Next
End Sub
End Class



The preceding code will cause an exception in the WorkerMethod() method when it attempts to access the ListBox1 control. But why? Because Windows Forms controls are not thread-safe, which means that a control bound to the UI’s thread cannot be directly accessed from another thread. An attempt to do so will cause the following exception to be thrown:





InvalidOperationException (Cross-thread operation not valid: Control
'ListBox1' accessed from a thread other than the thread it was created on.)



To get around this, we need to figure out whether the control we want to talk to needs to be “invoked” and, if so, invoke it and then do the work from the same thread that the control was created on. This sounds a lot more complicated than it actually is, and once this issue has bitten you a few times, you’ll breeze through it.


To fix the preceding code, we can do something like the following:





Public Class Form1

Private Delegate Sub AddDriveCallback(ByVal Name As String)


Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Dim myWorkerThread As New Thread(AddressOf WorkerMethod)
myWorkerThread.Start()
End Sub

Private Sub WorkerMethod()
For Each drive In My.Computer.FileSystem.Drives
Me.AddDrive(drive.Name)
Next
End Sub

Private Sub AddDrive(ByVal Name As String)
If ListBox1.InvokeRequired Then
Dim d As New AddDriveCallback(AddressOf AddDrive)
Me.Invoke(d, Name)
Else
Me.ListBox1.Items.Add(Name)
End If
End Sub
End Class



The simple part in the preceding code is that instead of adding the drive letter directly in the loop, we are calling a method to do it for us. This is also useful because we’ve encapsulated the functionality inside that method—and thank goodness for that, because the functionality has just gotten a lot more complicated! The issue that we need to overcome is that the code executing in the worker method and the Windows Forms control we want to talk to are on two different threads.


Controls have a method called Invoke() that executes a delegate on the thread that owns the control’s window handle. They also have an InvokeRequired property, which indicates whether the Invoke() method needs to be called to talk to a control. In plainer terms, if you have a single-threaded application, then all of the code to perform work and run the UI exist in the same thread. So, your code can communicate directly with your UI controls without having to worry about invoking them.


However, if you are in a multithreaded application and the UI exists in a separate thread from the worker thread, you need to do some extra work. When you want to execute some code, such as to add an item to a ListBox or change the contents of a TextBox, you need that code to execute on the same thread as the control is executing on. This is where delegates come in. If you’re not familiar with delegates, they’re simply pointers to a method, similar to how a variable is a pointer to a value or object. So, we cause the delegate to run on the UI’s thread, and thus cause the code that puts something into the ListBox to run on the UI’s thread. And because the code that’s adding something to the ListBox is running in the same thread that the ListBox was created in, there are no cross-thread issues to be concerned with.


This is a pattern that you should come to recognize and understand. It will catch you out the first few times you use it, and it’s a little strange at first, but eventually you won’t have any problems with it.


























Using a Plain Old String: Single-Threaded




I l@ve RuBoard









Using a Plain Old String: Single-Threaded


Say we want our program to keep track of the last error message we encountered and automatically decorate it with the time the message was generated. We might implement it using a global string value with helper functions to get and set the state:



// Example A-1: A simple error recording subsystem
//
String err;
int count = 0;

String GetError()
{
return err;
}

String SetError( const String& msg )
{
err = AsString( ++count ) + ": ";
err += msg;
err += " (" + TimeAsString() + ")";
return err;
}

As long as our program is single-threaded, we never have to worry about Get-Error() or SetError() being called at the same time on different threads, so all is well. For example, given:



String newerr = SetError( "A" );
newerr += " (set by A)";
cout << newerr << endl;

// ...later...
//
newerr = SetError( "B" );
newerr += " (set by B)";
cout << newerr << endl;

the output would be something like:



1: A (12:01:09.65) (set by A)
2: B (12:01:09.125) (set by B)







    I l@ve RuBoard



    Introduction



    [ Team LiB ]






    Introduction



    An
    important web application configuration
    task is to create the
    path
    by which your servlet is requested by web users. This is what the
    user types into the address field of his browser in order to make a
    request to the servlet. While this is sometimes the full name of the
    servlet, that convention often results in an awkward URI. For
    example, a web site might have a servlet that dynamically assembles a
    "Resources" page, instead of a
    static resources.html page. Using the full
    servlet name, the request URL might be http://www.myorganization.com/servlet/com.organization.servlets.resources.ResourceServlet.
    This is quite a path to type in; it makes much more sense to map this
    to a servlet path, which is an alias for the
    servlet. Using the servlet path, the (new) address for the dynamic
    page might be
    http://www.myorganization.com/resources. The
    servlet path, in this case, is /resources.



    This servlet path is also the identifier used by other servlets or
    JSPs that forward requests to this particular servlet, as well as the
    address that an HTML form tag uses in its action
    attribute to launch parameter names and values toward the servlet.
    The servlet specification offers an intuitive and flexible way to map
    HTTP requests to servlets in the web.xml
    deployment descriptor.



    This chapter describes how you can use the
    web.xml deployment descriptor to create one or
    more aliases (servlet paths) to your servlet. It also discusses how
    to invoke the servlet with other types of URLs, such as one that
    looks like a JSP page request (e.g., info.jsp)
    or one that looks like an HTML page request
    (info.html). Recipe 3.5
    also describes how to access a servlet without a
    mapping in web.xml, for example, for the
    developer who wants to debug her servlet without modifying the
    web.xml file.



    Finally, Recipe 3.7, Recipe 3.9, and Recipe 3.10 show how to
    map all requests to one
    "controller" servlet (Recipe 3.7), restrict the requests for certain servlets
    to authenticated users (Recipe 3.9), and block all
    requests to certain servlets except those forwarded from the
    controller (Recipe 3.10).







      [ Team LiB ]



      Ruby Cookbook








      Ruby Cookbook
      By
      Lucas Carlson, Leonard Richardson
      ...............................................
      Publisher: O'Reilly
      Pub Date: July 2006
      Print ISBN-10: 0-596-52369-6
      Print ISBN-13: 978-0-59-652369-5

      Pages: 906
       

      Table of Contents
       | Index



      Do you want to push Ruby to its limits? The Ruby
      Cookbook


      is the most comprehensive problem-solving guide to today's
      hottest

      programming

      language. It gives you hundreds of solutions to real-world
      problems,

      with clear explanations and thousands of lines of code you
      can use in

      your own projects.





      From data structures and algorithms, to integration
      with

      cutting-edge technologies, the Ruby
      Cookbook
      has

      something for every programmer. Beginners and advanced
      Rubyists

      alike will learn how to program with:



      • Strings and
        numbers

      • Arrays and hashes

      • Classes, modules, and
        namespaces

      • Reflection and
        metaprogramming

      • XML and HTML
        processing

      • Ruby on Rails (including Ajax
        integration)

      • Databases

      • Graphics

      • Internet services like email, SSH, and
        BitTorrent

      • Web services

      • Multitasking

      • Graphical and terminal
        interfaces





      If you need to write a web application, this book
      shows you

      how to get started with Rails. If you're a system
      administrator who

      needs to

      rename thousands of files, you'll see how to use Ruby for
      this and

      other everyday tasks. You'll learn how to read and write
      Excel

      spreadsheets, classify text with Bayesian filters, and
      create PDF

      files. We've even included a few silly tricks that were too
      cool to

      leave out, like how to blink the lights on your
      keyboard.





      The Ruby Cookbook is the most useful
      book yet

      written about Ruby. When you need to solve a problem, don't
      reinvent

      the wheel: look it up in

      the Cookbook.








      Recipe 16.9 Setting Request Attributes in Servlets



      [ Team LiB ]






      Recipe 16.9 Setting Request Attributes in Servlets




      Problem



      You want to use a servlet to store an attribute in a request.





      Solution



      Use the javax.servlet.ServletRequest.setAttribute(
      )
      method.





      Discussion



      The ServletRequest.setAttribute( ) method is often
      used in code that dynamically forwards requests or includes content
      with a javax.servlet.RequestDispatcher.



      Web applications that use RequestDispatchers to
      share requests between web components can communicate between these
      components using request attributes. Both the recipient of the
      RequestDispatcher.forward( ) method and the
      included file or page involved with the
      RequestDispatcher.include( ) method have access to
      the original or enclosing request. Therefore, these web components
      can also access any object attributes that are stored in those
      requests.



      The servlet in Example 16-10 creates an instance of a
      ContextObject, stores some information in the
      object by calling its put( ) method, and then
      places the object in the HttpServletRequest under
      the name
      "com.jspservletcookbook.ContextObject."
      The servlet then uses a RequestDispatcher to
      forward the request (including the attribute) and response to the
      servlet path /displayAttr. The web component
      mapped to that servlet path now has access to the previously created
      request attribute.




      Example 16-10. Binding an object to a request

      package com.jspservletcookbook;           

      import javax.servlet.*;
      import javax.servlet.http.*;

      public class RequestBinder extends HttpServlet {

      public void doGet(HttpServletRequest request,
      HttpServletResponse response) throws ServletException,
      java.io.IOException {

      //bind an object to the request
      ContextObject contextObj = new ContextObject( );

      contextObj.put( request.getRemoteAddr( ), ""+new java.util.Date( ));

      request.setAttribute(
      "com.jspservletcookbook.ContextObject",contextObj );

      //use RequestDispatcher to forward request to another servlet
      // mapped to the servlet path '/displayAttr'
      RequestDispatcher dispatcher = request.getRequestDispatcher(
      "/displayAttr");

      dispatcher.forward(request,response);


      } //doGet

      }



      Example 16-11 shows the servlet that receives the
      forwarded request. The RequestDisplay servlet is
      mapped in web.xml to the
      /displayAttr servlet path. This servlet gets the
      request attribute from the HttpServletRequest
      object by calling getAttribute( ) with the
      attribute name:
      com.jspservletcookbook.ContextObject. Since the
      return value of getAttribute( ) is typed to
      Object, the code must cast the result to
      ContextObject.




      Example 16-11. The target of RequestDispatcher.forward has access to the request attribute

      package com.jspservletcookbook;           

      import javax.servlet.*;
      import javax.servlet.http.*;

      public class RequestDisplay extends HttpServlet {

      public void doGet(HttpServletRequest request, HttpServletResponse response) throws
      ServletException, java.io.IOException {

      ContextObject obj = (ContextObject) request.getAttribute(
      "com.jspservletcookbook.RequestObject");


      response.setContentType("text/html");
      java.io.PrintWriter out = response.getWriter( );
      out.println(
      "<html><head><title>Request Attribute</title></head><body>");
      out.println("<h2>Request attribute values</h2>");

      //display the keys of the java.util.Map stored in the request object
      //attribute
      if (obj != null)
      out.println( obj.getValues( ) );


      out.println("</body></html>");

      } //end doGet

      }



      Make sure to check whether the ServletRequest.getAttribute(
      )
      return value is null before calling
      any of the object attribute's methods. The
      getAttribute( ) method returns
      null if the request does not contain an attribute
      of the specified name.





      See Also



      Recipe 16.1-Recipe 16.4 on handling
      ServletContext attributes in servlets and JSPs;
      Recipe 16.5-Recipe 16.8 on handling session
      attributes in servlets and JSPs; Recipe 16.10
      on setting request attributes in JSPs; Recipe 16.11 and Recipe 16.12 on accessing or removing request attributes in
      servlets and JSPs; the Javadoc for javax.servlet.
      ServletRequestAttributeListener
      :
      http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/ServletRequestAttributeListener.html.








        [ Team LiB ]



        Section 25.187. JSObject.getSlot( ): read an array element of a JavaScript object










        25.187. JSObject.getSlot( ): read an array element of a JavaScript object


        Java method in Java plug-in



        25.187.1. Synopsis



        public Object getSlot(int index)




        25.187.1.1. Arguments



        index


        The index of the array element to be read.





        25.187.1.2. Returns

        The value of the array element at the specified index of a JavaScript object.





        25.187.2. Description


        The getSlot( ) method of the Java JSObject class reads and returns to Java the value of an array element at the specified index of a JavaScript object. The return value may be another JSObject object or a Double, Boolean, or String object, but it is returned as a generic Object, which you must cast as necessary.













        Section 6.7. Conclusion










        6.7. Conclusion


        In this chapter we examined the MySQL error handlers that allow you to catch error conditions and take appropriate corrective actions. Without error handlers, your stored programs will abort whenever they encounter SQL errors, returning control to the calling program. While this might be acceptable for some simple stored programs, it is more likely that you will want to trap and handle errors within the stored program environment, especially if you plan to call one stored program from another. In addition, you need to declare handlers for cursor loops so that an error is not thrown when the last row is retrieved from the cursor.


        Handlers can be constructed to catch all errors, although this is currently not best practice in MySQL, since you do not have access to an error code variable that would allow you to differentiate between possible error conditions or to report an appropriate diagnostic to the calling program. Instead, you should declare individual handlers for error conditions that can reasonably be anticipated. When an unexpected error occurs, it is best to let the stored program abort so that the calling program has access to the error codes and messages.


        Handlers can be constructed that catch either ANSI-standard SQLSTATE codes or MySQL-specific error codes. Using the SQLSTATE codes leads to more portable code, but because specific SQLSTATE codes are not available for all MySQL error conditions, you should feel free to construct handlers against MySQL-specific error conditions.


        To improve the readability of your code, you will normally want to declare named conditions against the error codes you are handling, so that the intention of your handlers is clear. It is far easier to understand a handler that traps DUPLICATE_KEY_VALUE than one that checks for MySQL error code 1062.


        At the time of writing, some critical SQL:2003 error-handling functionality has yet to be implemented in MySQL, most notably the ability to directly access the SQLSTATE or SQLSTATE variables, as well as the ability to raise an error condition using the SIGNAL statement. In the absence of a SQLSTATE or SQLCODE variable, it is good practice for you to define handlers against all error conditions that can reasonably be anticipated that populate a SQLCODE-like variable that you can use within your program code to detect errors and take appropriate action. We expect MySQL to add these "missing" features in version 5.2you should check to see if they have been implemented in the time since this book was written (see the book's web site for details). Note also that it is currently possible to provide a workaround (though a somewhat awkward one) for the missing SIGNAL statement if you find that it is absolutely necessary in your programs.












        Lab 20.2 Exercises



        [ Team LiB ]





        Lab 20.2 Exercises


        20.2.1 Use OPEN-FOR, FETCH, and CLOSE Statements


        Create the following PL/SQL script:





        -- ch20_2a.sql, version 1.0
        SET SERVEROUTPUT ON
        DECLARE
        TYPE zip_cur_type IS REF CURSOR;
        zip_cur zip_cur_type;

        sql_stmt VARCHAR2(500);
        v_zip VARCHAR2(5);
        v_total NUMBER;
        v_count NUMBER;
        BEGIN
        sql_stmt := 'SELECT zip, COUNT(*) total'||
        ' FROM student ' ||
        'GROUP BY zip';

        v_count := 0;
        OPEN zip_cur FOR sql_stmt;
        LOOP
        FETCH zip_cur INTO v_zip, v_total;
        EXIT WHEN zip_cur%NOTFOUND;

        -- Limit the number of lines printed on the
        -- screen to 10
        v_count := v_count + 1;
        IF v_count <= 10 THEN
        DBMS_OUTPUT.PUT_LINE ('Zip code: '||v_zip||
        ' Total: '||v_total);
        END IF;
        END LOOP;
        CLOSE zip_cur;

        EXCEPTION
        WHEN OTHERS THEN
        IF zip_cur%ISOPEN THEN
        CLOSE zip_cur;
        END IF;

        DBMS_OUTPUT.PUT_LINE ('ERROR: '||
        SUBSTR(SQLERRM, 1, 200));
        END;

        Consider the use of spaces in the SQL statements generated dynamically. In the script above, the string that holds the dynamic SQL statement consists of three strings concatenated together where each string is written on a separate line.





        sql_stmt := 'SELECT zip, COUNT(*) total'||
        ' FROM student ' ||
        'GROUP BY zip';

        This format of the dynamic SELECT statement is very similar to the format of any static SELECT statement that you have seen throughout this book. However, there is a settled difference. In one instance, extra spaces have been added for formatting reasons. For example, the FROM keyword is prefixed by two spaces so that it is aligned with the SELECT keyword. Yet, in another instance, a space has been added to separate out a reserved phrase. In this case, a space has been added after the STUDENT table to separate out GROUP BY clause. This step is necessary because once the strings are concatenated the resulting SELECT statement looks as follows:





        SELECT zip, COUNT(*) total FROM student GROUP BY zip

        If no space is added after the STUDENT table, the resulting SELECT statement





        SELECT zip, COUNT(*) total FROM studentGROUP BY zip

        causes error shown below





        ERROR: ORA-00933: SQL command not properly ended

        PL/SQL procedure successfully completed.

        Execute the script, then complete the following exercises:


        a)

        Explain the script ch20_2a.sql shown above.

        b)

        Modify the script created in the previous exercise (ch20_2a.sql) so that the SELECT statement can be run against either STUDENT or INSTRUCTOR table. In other words, a user can specify table name used in the SELECT statement at the run time.






          [ Team LiB ]



          Chapter 13. Using MySQL Stored Programs with PHP










          Chapter 13. Using MySQL Stored Programs with PHP





          The combination of PHP and MySQL is one of the most popular and powerful partnerships in open source web development and is a key component of the LAMP (Linux-Apache-MySQL-PHP/Perl/Python) stack. There are reportedly more than 18 million web sites based on PHP technology (according to http://www.netcraft.com), and the majority of these are using MySQL as the underlying database.


          PHP started off as a simple CGI-based processor for amateur web development in the mid-1990s. It borrowed heavily from the Perl language (at the time, the most popular approach for CGI-based dynamic web development), but was more tightly integrated with HTML andunlike Perlwas designed specifically for web development.


          PHP takes a similar approach to dynamic web content as Microsoft's ASP (Active Server Pages) and J2EE's JSP (Java 2 Enterprise Edition Java Server Pages). All of these technologies involve embedding tags into HTML pages (renamed appropriately as PHP, ASP, or JSP pages, of course) that control the dynamic content of the page. In the case of PHP, the tags contain PHP code. The PHP code is executed by the PHP engine, which is usually deployed within the web server (Apache, IIS, etc.) and typically interacts with a database to provide dynamic, data-driven content.


          As a language, PHP delivers much of the flexibility and power of the popular Perl open source scripting language and has a wide variety of interfaces to back-end databases. It is probably fair to characterize PHP as having a shallower learning curve than the ASP.NET or J2EE alternatives. Also, since PHP is open source, software licensing costs are, of course, minimal (although many larger enterprises seek support from Zend Corporation or another commercial entity).


          In this chapter we will review the use of PHP with MySQL and show how stored programs can be used within PHP-based applications.




















































          Prev don't be afraid of buying books Next






























          "NO COMMENT"




          There are valid reasons to write comments.
          We'll talk about these later. However, as we discussed in Chapter 2,
          most comments are not written for valid reasons. Fowler's Refactoring[16] calls
          comments "deodorant". . . they are there to try to hide the bad
          smell of the code. The code is unclear, the code is poorly written,
          names are badly chosen, the logic is obtuse, etc. Comments were
          added to try to explain what the code does. The code should have
          been, and should be, refactored to make the comments
          unnecessary.



          Don't get me wrong. I'm not saying "Don't write
          documentation." Nobody really doing XP will say that. Sometimes it
          is important to the customer to have specific documentation
          written. Also, I'm not saying "Never write comments." What I am
          saying is "Never write unnecessary comments." Most comments are
          unnecessary if the code is written so that the intent is clear. If
          and when we do write comments, we need to make sure they
          communicate why and not how.





          Valid Comments



          As I mentioned above, there are several valid
          reasons for us to write comments.






          Incomplete
          code
          This type of comment serves as a note to what we were
          in the midst of working on, or how we see the code evolving. There
          generally is not much need for this type of comment, since tasks
          should be no larger than what can be accomplished in a single day.
          If you find that you do need to make such a note, choose a standard
          tag for it so you can quickly search for loose ends. And stay away
          from generic not done yet comments. I'd suggest something
          like:




          // TODO: The tree should be balanced after doing the insertion.






          A valid use for this type of comment might be to
          note code that could benefit from being refactored. Maybe we saw
          the need to refactor but didn't have time to do it. Make a note so
          that someone will spot it and do the refactoring when there is
          time. It might be prudent to use standard wording for these
          "refactoring To Do" comments so that a global search can be
          performed as a rough code-debt metric. I suggest something similar
          to the following:




          // CODE DEBT: the looping structure is a bit convoluted, could use
          // some method extraction.













          Refactoring doesn't
          make it clear enough
          This isn't really a valid comment,
          rather it is more like the previous type. . . it's an IOU. If
          refactoring doesn't clean up the code, either someone else should
          try their hand at it, or (more likely) the code in question should
          be scrapped and rewritten.




          // NEEDS WORK: I tried extract method, but it's still awkward.
          // Maybe refactoring to a Strategy would clean it up?













          Use of an unusual
          algorithm
          If we use an uncommon algorithm for some reason,
          we should make a note of it with a comment. Point the reader to
          where they can learn more. Don't try to document
          the algorithm in a huge comment. Just note what algorithm it is,
          why it was used, and where to find more information.




          // I used an AVL Tree algorithm here to keep the tree balanced.













          Use of a published
          algorithm
          If we use an algorithm that is published
          somewhere, we should add a comment saying where and giving credit
          to the author. This type of comment is often used with the previous
          type.




          // This AVL alorithm was based on Brad Appleton's implementation at
          // http://www.enteract.com/~bradapp/ftp/src/libs/C++/AvlTrees.html













          Performance
          tuning
          This is important. If we tune for performance, we
          should add a comment explaining it. At the very least we need to
          add a note saying that the method in question has been tuned. If we
          tune without adding such a note we may find that someone later
          refactors to make the code clearer, undoing the optimization in the
          process. Keep in mind that we generally shouldn't be performance
          tuning until late in the project, once performance has been
          measured and actual bottlenecks have been found.




          // A circular queue is used here for performance reasons: to avoid
          // having to move elements around.













          Class comment
          This is the one case that is often useful, in spite of the general
          disapproval of comments. Not much is required. A simple note at the
          beginning of the class briefly explaining why the class exists and
          what it is used for will suffice. Avoid writing a how to use this class tutorial. That's
          one of the things the tests are for.




          /**
          * This class represents a single movie title. It is responsible for
          * maintaining its own ratings, reviews, etc.
          */














          A final note related to comments. Programmers
          often sign their work by including a comment in the file header
          noting who wrote it. That's fine; credit where credit is due and
          all that, except:











          1. If we are practicing XP, specifically collective
            code ownership, everyone will likely work on that code. It is owned
            by the team.












          2. A record of who worked on each file will be
            maintained by the source code control system (SCCS). It is
            redundant to include the information in the file itself as well.
            Another comment on this: Please don't include an expandable change
            log in the file (e.g., $Log$ in CVS). This clutters the
            code, makes the files larger, and duplicates information that is
            easy to extract from the SCCS.























































          Amazon






          Snapshots and Situational Awareness




















          Snapshots and Situational Awareness



          A phrase often used in military circles, situational awareness refers to the ability to understand what is happening at any time, all the time. It’s a comprehensive understanding of where the good guys are, where the bad guys are, who is doing what, and why they are doing it.


          The same concept proves valuable within the IT community. You should know all the interrelationships among your networks, servers, applications, and databases. Furthermore, within the database, you should know what schemas, applications, and users exist and what privileges they each should and should not have. Also important is understanding what applications are being accessed by what community of users for what data.


          A simple snapshot of the baseline configuration combined with ongoing and vigilant monitoring is practice you will find very valuable. The resulting snapshot should be documented. The document does not have to be fancy; SQL output may prove sufficient. This snapshot will allow you to more easily identify anomalies and react to them. Often, a security compromise will occur over long periods of time. How can they go on for so long without anyone noticing? It’s because there was no awareness of what was going on when it was going on. For example, if someone were robbing you one penny at a time, you might never realize it was even happening if you never balanced your checkbooks.


          Another benefit of snapshots is that they help you understand what damage has occurred if something does happen. If a schema is compromised, ask yourself simple questions like, “What privileges did the schema have? What data was there? What procedures were in place? What data did those procedures act on?” You can extend this concept into one of threat assessments (actually part of risk analysis) to predict the results of bad things that might happen.


          This overall awareness of the system is important to understanding how to design a secure system and how to respond logically, quickly, and accurately to security incidents.




          Cover All the Areas


          The concept of security transcends database security, and even computer security. Overall, an organization is concerned with all facets of security. There is, in a sense, a security ecosystem. One area of security complements and relates to other areas. A challenge to implementing computer security is in understanding the complex inter-relationships. Here is a list of some of the other security areas that should be considered when addressing security:





          • Physical security Protect the assets from physical abuse, including theft. As mentioned previously, theft of a server is not only theft of the hardware but also theft of the data. Booting a server to a “startup” level, changing the super-user password, and exploiting the rest of the system is easy to do if the physical access to the server is compromised.





          • Personnel security Ensure people are honest and ethical. This one may be the hardest, because you have to trust people. Generally, you should marry the access a person is given with the amount of trust you have for that person. For people who actually run the systems, some background checks may be necessary and desirable. Keep track of personnel status. A disgruntled employee can cause an enormous amount of IT damage.





          • Training Teach people the good behavior required to provide a secure environment. A simple course or document that explains the company policies and describes good security behavior is invaluable to an organization. Include instructions such as




            • Lock the door to your office




            • Don’t leave confidential material laying around




            • Use “strong” passwords




            • Lock unattended computers







          • Contingency plans Plan for power failures, security compromises, and disasters. If you don’t have a plan, make one. It will provide a framework for you and guidance to those who are involved in the disaster. Your plan may indicate that there is no contingency for a certain event, but that is okay. It shows you have thought about it and decided to do nothing. It can be a “placeholder” for when you do have a strategy.





          • Information access management Access to IT systems should be diligently governed in accordance with the least-privilege principle. This means that application owners, DBAs, and security officers should agree on who has access to what kind of data. This agreement should be documented and audited for compliance.





          • Information security Provide confidentiality, privacy, and integrity of your data. Information may take various forms; digital is only one. Digital security will not prevent someone from stealing a confidential printout from an unsecured printer or overhearing a phone conversation about confidential information. Note that theft of a printout is not the same as physical security, which could be used to prevent a person from getting access to the printer altogether. Instructing employees on proper behaviors is critical to ensuring the security ecosystem is functioning well.




          To implement security effectively, you need a heterogeneous collection of mandatory controls that cannot be bypassed, such as encryption for confidentiality. You also need discretionary controls that you must hope are not misused by users. All of the areas are equally important to providing a secure ecosystem.




















          Chapter 35. Where to Find More Information










           < Free Open Study > 







          Chapter 35. Where to Find More Information



          cc2e.com/3560



          Contents



          • Information About Software Construction page 856

          • Topics Beyond Construction page 857

          • Periodicals page 859

          • A Software Developer's Reading Plan page 860

          • Joining a Professional Organization page 862



          Related Topics



          • Web resources: http://www.cc2e.com



          If you've read this far, you already know that a lot has been written about effective software-development practices. Much more information is available than most people realize. People have already made all the mistakes that you're making now, and unless you're a glutton for punishment, you'll prefer reading their books and avoiding their mistakes to inventing new versions of old problems.



          Because this book describes hundreds of other books and articles that contain information on software development, it's hard to know what to read first. A software-development library is made up of several kinds of information. A core of programming books explains fundamental concepts of effective programming. Related books explain the larger technical, management, and intellectual contexts within which programming goes on. And detailed references on languages, operating systems, environments, and hardware contain information that's useful for specific projects.



          cc2e.com/3581



          Books in the last category generally have a life span of about one project; they're more or less temporary and aren't discussed here. Of the other kinds of books, it's useful to have a core set that discusses each of the major software-development activities in depth: books on requirements, design, construction, management, testing, and so on. The following sections describe construction resources in depth and then provide an overview of materials available in other software knowledge areas. Section 35.4 wraps these resources into a neat package by defining a software developer's reading program.














             < Free Open Study > 



            Section 9.2. Building a Timing Diagram from a Sequence Diagram










            9.2. Building a Timing Diagram from a Sequence Diagram


            Let's assemble a timing diagram from scratch. We're going to work from the same example used in the communication and sequence diagram chapters, the Create a new Regular Blog Account interaction, shown in Figure 9-3.



            Figure 9-3. A sequence diagram contains very little, if any, information about timing, and its main focus is the order of events within an interaction




            9.2.1. Timing Constraints in System Requirements




            The interaction shown in Figure 9-3 was originally the result of a requirement such as the one described in Requirement A.2.



            Requirement A.2


            The content management system shall allow an administrator to create a new regular blog account, provided the personal details of the author are verified using the Author Credentials Database.




            Now, let's extend the original requirement with some timing considerations so that we've got something to add by modeling the interaction in a timing diagram.



            Requirement A.2 (Updated)


            The content management system shall allow an administrator to create a new regular blog account within five seconds of the information being entered, provided the personal details of the author are verified using the Author Credentials Database.




            Requirement A.2 has been modified to include a timing constraint that dictates how long it should take for the system to accept, verify, and create a new account. Now that there is more information about the timing of Requirement A.2, there is enough justification to model the interaction that implements the requirement using a timing diagram.













            Wrapper Classes








            Wrapper Classes


            The student system must store student charges in a collection to be totaled later. Each charge is an int that represents the number of cents a student spent on an item.



            Remember that primitive types are not objectsthey do not inherit from the class java.lang.Object. The java.util.List interface only supplies an add method that takes a reference type as a argument. It does not supply overloaded add methods for each of the primitive types.


            In order to store the int charge in a collection, then, you must convert it to an object. You accomplish this by storing the int in a wrapper object.


            For each primitive type, java.lang defines a corresponding wrapper class.[8]

            [8] The table lists all available primitive types and corresponding wrappers. You will learn more about the unfamiliar types in Lesson 10.


            Type

            Wrapper Class

            char

            Character

            byte

            Byte

            short

            Short

            int

            Integer

            long

            Long

            float

            Float

            double

            Double

            boolean

            Boolean



            Each wrapper class provides a constructor that takes a primitive of the appropriate type as argument. The wrapper stores this primitive and allows for extracting it using a corresponding getter method. In the case of the Integer wrapper, you extract the original int by sending the message intValue to the wrapper.


            A test (in StudentTest) for the example:



            public void testCharges() {
            Student student = new Student("a");
            student.addCharge(500);
            student.addCharge(200);
            student.addCharge(399);
            assertEquals(1099, student.totalCharges());
            }


            If you had to write the implementation using pre-J2SE 5.0 code, it would look something like this:



            public class Student implements Comparable {
            ...
            private List charges = new ArrayList();
            ...
            public void addCharge(int charge) {
            charges.add(new Integer(charge));
            }

            public int totalCharges() {
            int total = 0;
            Iterator it = charges.iterator();
            while (it.hasNext()) {
            Integer charge = (Integer)it.next();
            total += charge.intValue();
            }
            return total;
            }
            ...


            The addCharge method shows how you would wrap the int in an instance of the Integer wrapper class in order to pass it to the add method of the charges collection. When iterating through the collection (in totalCharges), you would have to cast each retrieved Object to the Integer wrapper class. Only then would you be able to extract the original int value through use of the intValue method.


            J2SE 5.0 simplifies the code through the use of parameterized types and the for-each loop.



            public class Student implements Comparable<Student> {
            ...
            private List<Integer> charges = new ArrayList<Integer>();
            ...
            public void addCharge(int charge) {
            charges.add(new Integer(charge));
            }

            public int totalCharges() {
            int total = 0;
            for (Integer charge: charges)
            total += charge.intValue();
            return total;
            }
            ...


            In addition to allowing you to wrap a primitive, the wrapper classes provide many class methods that operate on primitives. Without the wrapper classes, these methods would have nowhere to go. You have already used the Character class method isWhitespace.


            A further simplification of the code comes about from one of the new J2SE 5.0 features, autoboxing.


            Autoboxing and Autounboxing


            Autoboxing is the compiler's ability to automatically wrap, or "box" a primitive type in its corresponding wrapper class. Autoboxing only occurs when Java can find no method with a matching signature. A signature match occurs when the name and arguments of a message send match a method defined on the class of the object to which the message is being sent. An argument is considered to match if the types match exactly or if the type of the argument is a subtype of the argument type as declared in the method.


            As an example, if Box declares a method as:



            void add(List list) {... }


            then any of the following message sends will resolve to this add method:



            Box b = new Box();
            b.add(new List());
            b.add(new ArrayList());


            The second add message send works because ArrayList is a subclass of List.


            If Java finds no direct signature match, it attempts to find a signature match based on wrapping. Any method with an Object argument in the appropriate place is a match.


            In the addCharge method, the explicit wrapping of the int into an Integer is no longer necessary:



            public void addCharge(int charge) {
            charges.add(charge);
            }


            It is important for you to understand that the wrapping does occur behind the scenes. Java creates a new Integer instance for each primitive value you wrap.


            Autoboxing only occurs on arguments. It would be nice if autoboxing occurred anywhere you attempted to send a message to a primitive. This is not yet a capability, but it would allow expressions like:



            6.toString() // this does not work


            Autounboxing occurs when you attempt to use a wrapped primitive anywhere a primitive is expected. This is demonstrated in the following two tests:



            public void testUnboxing() {
            int x = new Integer(5);
            assertEquals(5, x);
            }

            public void testUnboxingMath() {
            assertEquals(10, new Integer(2) * new Integer(5));
            }


            The more useful application of autounboxing is when you extract elements from a collection bound to a primitive wrapper type. With both autoboxing and autounboxing, the charge code in Student becomes:



            public void addCharge(int charge) {
            charges.add(charge);
            }

            public int totalCharges() {
            int total = 0;
            for (int charge: charges)
            total += charge;
            return total;
            }


            You will learn about addition capabilities of wrapper classes in Lesson 10 on mathematics.








              Section 22.5.&nbsp; Project Indexing










              22.5. Project Indexing


              As mentioned in Section 18.1.2, Xcode will devote a background thread to identifying and indexing all the symbols in your project and the frameworks it uses. On recent machines, with a moderately sized project and a reasonably paced typist, you will see no effect, other than having an index, from the indexing thread. In some cases, however, indexing may slow your machine down.


              The drastic thing you can do about this is to turn indexing off. In the Code Sense pane of the Preferences window, clear the checkbox labeled Indexing: Enable for all projects. No indexing threads will then be started; nor will you be able to use the Class Browser, the Class Model, the Project Symbols smart group, Code Sense, or command-double-clicking to find symbol definitions.


              The less drastic step is to reduce the amount of indexing that has to be done. In all but the very largest project, the lion's share of indexing is done in frameworks, and it makes sense to do that part of the indexing once, in advance, and have individual projects use these master indexes as bases for project indexes. The facility is formally known as index templates, and you have to build and enable them to make use of them.


              You will find the necessary makings in /Developer/Extras/Xcode Index Templates/. There is a way to build and enable templates piecemeal and to control where they are stored, but for most purposes, it's good enough to build them all, store them in the /Library domain, and enable Xcode's use of them. Do this in the Terminal application by focusing on the templates directory and executing the command install_templates found there:


                 $ cd "/Developer/Extras/Xcode Index Templates"
              $ sudo ./install_templates
              Password:
              $


              More information about index templates, including details on manual installation, can be found in the read-me file in the Xcode Index Templates directory.


              It sometimes happens that features that depend on indexing stop working or work unreliably. Code Sense, for instance, might not be delivering all the completions you think it ought to, given the context. It is possible that the project index has been corrupted. If you think that this may have happened, select Edit Project Settings in the Project menu (or double-click the Project icon at the top of the Groups & Files list), and click Rebuild Code Sense Index at the bottom of the Info window that results.


              If a problem persists and you are using index templates, see whether turning index templates off and rebuilding the project index cures the problem. If so, rebuild the index templates before using them again.












              DBMS_CRYPTO




















              DBMS_CRYPTO


              The DBMS_CRYPTO package is new to Oracle Database 10g. This package replaces the DBMS_ OBFUSCATION_TOOLKIT which, while still available, has been deprecated. DBMS_CRYPTO adds several new encryption algorithms, hashing algorithms, and a key-hashed capability. It shouldn’t be overlooked that the package name is both easier to type and easier to pronounce.


              There are two additional places to find information on the new package. Chapter 22 of the PL/SQL Packages and Type Reference 10 g Release 1 is a good starting resource that explains the organization of the package. As a reference source, however, it lacks code examples. In addition to the code in this chapter, actual code examples can be found in Chapter 16 of Developing Applications Using Data Encryption of the Oracle Database Security Guide 10 g Release 1.


              The default privileges on DBMS_CRYPTO are secure. That is, the package has no explicit grants given to the DBA group or to PUBLIC. Before you can begin, you have to grant execute privileges on the package to your security manager. The Oracle Database Security Guide 10 g also strongly recommends that you revoke the PUBLIC execute privileges from the DBMS_ OBFUSCATION_TOOLKIT. If an attacker can’t execute the program to decrypt the data, then recovering the original text becomes even more difficult.


              The DBMS_CRYPTO package is very robust. The application developer can choose from a potpourri of encryption algorithms, padding techniques, initialization vectors, and block cipher modifiers. Padding techniques are the methods used to ensure the data sizes are congruent with the algorithm being used. Many of the encryption algorithms require the data to be padded to an 8-byte boundary. An initialization vector (IV) is random data that is prepended to the actual data you want to encrypt. It adds security for data values that are of low cardinality (that is, they don’t have many differences) because the resulting ciphertext for two identical values that use different IVs will be different. This makes breaking the encryption more difficult. Block cipher modifiers allow you to specify how a block cipher algorithm is implemented. There are four block cipher modifiers: Electronic Code Book (ECB) will encrypt each block of data independently of the previous and subsequent blocks; Cipher Block Chaining (CBC) uses an exclusive-OR (XOR) of the previous data block with the current block before it is encrypted; Cipher Feedback (CFB) allows the data to be smaller than the block size (no padding is required); and Output Feedback (OFB) uses data from the previous block to fill the rightmost slots of the current block.


              Don’t worry if you don’t understand the differences in algorithms, padding, or modifiers. You can strongly and securely encrypt the data using the recommended settings you see in the examples. For those die-hard cryptographers who understand the differences and have specific preferences, the DBMS_CRYPTO package will allow you to exploit the different padding, initialization vectors, and cipher modifiers.




              Encryption Routines


              DBMS_CRYPTO provides one encryption function and two encryption procedures. The function is based on the RAW data type. It accepts a key, data, and optional IV parameter of type RAW, and it also returns a RAW data type. The two encryption procedures are LOB oriented. One procedure accepts a BLOB as the data parameter; the other procedure accepts a CLOB as the data parameter. Both procedures expect a key and an optional IV of type RAW, and both procedures write the encrypted data to a BLOB data type.


              At first, there seems to be something missing. What happened to support for VARCHAR2? It’s not an oversight. The VARCHAR2 data type is not directly supported. The encryption function can be easily used by translating the VARCHAR2 data types using the UTL_RAW package. The VARCHAR2 encrypted data can be corrupted if updated by two users or databases that are using different character sets—this is discussed in more detail in the “Storing Encrypted Data” section, later in the chapter. To encrypt any data type that is not a RAW, CLOB, or BLOB, you’ll have to perform data type translation.


              DBMS_CRYPTO solves many of the challenges that existed with its predecessor. The encryption procedures are designed to handle all large objects. LOB support was missing from the DBMS_OBFUSCATION_TOOLKIT. In addition, DBMS_CRYPTO automatically pads all data when using the block encryption algorithms (or block ciphers). The block ciphers operate on 8-byte boundaries and require that the data fall evenly on the byte boundaries. For the data that does not fall on the boundary, padding has to be used to increase the data size. For example, the character string “123456789” has to be padded with an additional 7 characters to make its total length 16 characters, which is evenly divisible by 8. Prior to DBMS_CRYPTO, the developer had to manually pad the data.





              DBMS_CRYPTO Simple Example



              This first example illustrates how to invoke the encryption function for the DBMS_CRYPTO package:



              sec_mgr@KNOX10g> -- DBMS_CRYPTO simple example 
              sec_mgr@KNOX10g> DECLARE
              2 -- Variable for the encryption algorithm that will be used.
              3 -- Using AES with 128-bit key size on a CBC modifier
              4 -- and padded using the PKCS#5 padding standard
              5 l_algorithm PLS_INTEGER
              6 := dbms_crypto.encrypt_aes128
              7 + dbms_crypto.chain_cbc
              8 + dbms_crypto.pad_pkcs5;
              9 -- Variable for the data that will be encrypted.
              10 l_data VARCHAR2 (4) := 'DATA';
              11 -- Variable for the key that will be used for the encryption.
              12 -- Key has to be 16 bytes for AES128 algorithm
              13 l_key VARCHAR2 (16) := 'TheEncryptionKey';
              14 -- Initialization vector. Vector has to be
              15 -- 16 bytes for AES128 algorithm.
              16 l_iv VARCHAR2 (16) := '0123456789012345';
              17 BEGIN
              18 DBMS_OUTPUT.put_line
              19 ( 'Encrypted DATA: '
              20 || UTL_RAW.cast_to_varchar2
              21 (dbms_crypto.encrypt
              22 (UTL_RAW.cast_to_raw (l_data),
              23 l_algorithm,
              24 UTL_RAW.cast_to_raw (l_key),
              25 UTL_RAW.cast_to_raw (l_iv))));
              26 END;
              27 /
              Encrypted DATA: e ^ ' = 8. = T^¯óRí

              PL/SQL procedure successfully completed.


              The output from the encryption function was converted back to a string to illustrate that ‘DATA’ no longer looks like a valid string—it’s encrypted.


              The encryption algorithm was set by defining a local variable that is the resulting summation of the algorithm, the block modifier, and the padding. This is discussed in more detail in the “Encryption Algorithms” section, later in the chapter.


              The DBMS_CRYPTO package is complete in the sense that you can use it to encrypt practically all of the standard data types after you convert them to a RAW, CLOB, or BLOB.


              While working with the procedures and functions, you may find that you have to repetitively perform data type conversions. You’ll notice in the preceding example that the data, the key, and the IV have to be converted to the RAW data type. This may or may not be a problem with your data. I find that it is easier to produce examples when the data, keys, and IVs are strings.


              The encryption key size and the IV size can be 8, 16, 24, or 32 bytes and are dependent on the encryption algorithm that will be used. This example artificially creates the exact size key and IV. A key that is too short or too long will cause an error. An IV that is too short will cause an error, and only the first 8, 16, 24, or 32 bytes of the IV will be used based on the algorithm. Depending on how you generate your IV and key, you may have to truncate or pad those values in addition to converting them.





              DATA_CRYPTO Package


              For many of your practical uses, you may find it easier to create a package that can be used to cast your data types for you. To help illustrate how encryption can be used, the DATA_CRYPTO package presented here will act as a wrapper for the database’s DBMS_CRYPTO. The DATA_ CRYPTO package will make data encryption easier when performing SQL-based updates, and it will also simplify the example code. The complete package specifications and the implementation of the package body are given in Appendix B.


              Based on the complexity of the example just shown, encryption and decryption functions for the character, date, and number data types will be provided. The DATA_CRYPTO functions will perform the data type casting. All functions accept the key as a character string. The package will ensure the key is the appropriate size for the given algorithm.


              The functions are named ENCRYPT_<data type> and DECRYPT_<data type>; for example, ENCRYPT_CHAR is used for encrypting character data. The returning values for the encryption function and the input data type for the decryption function are RAW data types. You will see later in the “Storing Encrypted Data” section that storing encrypted data as a RAW is important for ensuring that you will be able to decrypt it later. There is an additional ENCRYPT and DECRYPT function that accepts character data and returns encrypted character data. These two complementary functions are used for illustrative purposes.


              As mentioned, DBMS_CRYPTO provides encryption and decryption procedures for BLOBs and CLOBs. However, both procedures return BLOBs, and both are procedures as opposed to functions. The DATA_CRYPTO package will provide BLOB functions. There is also a function to return encrypted CLOB data, which is helpful in illustrating examples.


              The IV isn’t used in efforts to help simplify the code examples. You’ll be able to understand how the encryption works without their use. You should note that IVs can make encrypting data with repeating values, which use repeating keys, more secure.




              Encryption Algorithms


              The DBMS_CRYPTO supports DES, triple-DES with two keys, triple-DES with three keys, AES with three different key sizes, and the RC4 algorithms. DBMS_CRYPTO determines the proper algorithm by its numeric value as opposed to a string value. The algorithm parameter is therefore a numeric data type. The base algorithm (for example, DES, 3DES, and AES) has a numeric value that is added to the numeric value for the block modifier (for example, CBC, CFB, ECB, and OFB) and the padding algorithms (for example, PKCS5, Zeros, ORCL, or None). The DATA_CRYPTO package will support the various algorithms but will be defaulted to the Oracle-recommended CBC block modifier and the Oracle-recommended PKCS5 data padding. The DATA_CRYPTO package uses global package variables and stores the computed numerical value for the algorithms:


              -- Strongest AES at 256-bit key length (32-bytes) 
              g_aes256 CONSTANT PLS_INTEGER
              := dbms_crypto.encrypt_aes256
              + dbms_crypto.chain_cbc
              + dbms_crypto.pad_pkcs5;

              These algorithms can be easily modified to accommodate a different block chaining algorithm or different padding algorithms by modifying this definition. To make it easy to pass these algorithms to procedures, a DATA_CRYPTO function is provided for each algorithm that returns the algorithms numeric value:


              FUNCTION aes256  
              RETURN PLS_INTEGER
              AS
              BEGIN
              RETURN g_aes256;
              END;

              This allows you to easily pass the algorithm as a parameter to the DATA_CRYPTO.ENCRYPT functions from SQL statements:



              sec_mgr@KNOX10g> COL Encrypted format a32 
              sec_mgr@KNOX10g> SELECT
              2 data_crypto.encrypt ('Data', 'Key', data_crypto.aes256) encrypted
              3 FROM DUAL;

              ENCRYPTED
              -----------------------
              ¦lé+=&n-ç0?Ç+f±ß





              GET and SET functions


              The DATA_CRYPTO package allows the user to set and modify the default encryption algorithm by calling getter and setter procedures. Recall the DBMS_CRYPTO package resolves the encryption algorithm by evaluating its numerical value. This user-friendly version translates the number to text, making testing and debugging easier:



              -- Set encryption algorithm 
              -- Stores value in global package variable
              PROCEDURE set_algorithm (p_enc_algorithm IN PLS_INTEGER);

              -- return character representation of currently set algorithm
              FUNCTION get_algorithm
              RETURN VARCHAR2;


              Similarly, if you want to set the encryption key to be used in successive encryption and decryption operations, a set key procedure is provided. The key is stored in a package variable:


              -- Stores key as a RAW in a global package variable 
              -- Key is sized based on algorithm passed or the globally
              -- defined algorithm
              PROCEDURE setkey (
              p_key IN VARCHAR2,
              p_enc_algorithm IN PLS_INTEGER DEFAULT NULL
              );




              Key Sizing


              The DBMS_CRYPTO function and its procedures accept RAW keys. The keys have to be the correct size for the algorithm being used. The key size varies from 8 bytes for DES to 32 bytes for AES256. The RC4 algorithm will take a key of any size. As you will soon see, one popular approach to key management is not storing the keys but rather (securely) computing the encryption keys. Therefore, it’s desirable to have a routine that ensures the key size is appropriate for the algorithm being used.


              The examples used in this chapter will use string-based keys for the encryption and decryption parameter. The DBMS_CRYPTO requires the key to be a RAW, so a function is provided to convert the key to a RAW and adjust it to the appropriate size:


              -- Return RAW key of appropriate size based on algorithm   
              -- If algorithm is null, the global algorithm will be used.
              FUNCTION getkey (
              p_key IN VARCHAR2 DEFAULT NULL,
              p_enc_algorithm IN PLS_INTEGER DEFAULT NULL )
              RETURN RAW;

              This function will also provide utility if you want to directly invoke the DBMS_CRYPTO and ensure the key is sized appropriately as shown here:



              sec_mgr@KNOX10g> SELECT dbms_crypto.encrypt   
              2 (UTL_RAW.cast_to_raw ('data'),
              3 data_crypto.aes,
              4 data_crypto.getkey ( 'my encryption key'
              5 || ' of some random length',
              6 data_crypto.aes
              7 )
              8 ) encrypted
              9 FROM DUAL;

              ENCRYPTED
              ------------------------------
              CF7723ECBFCFF059B2A62BC2DB9BA56F


              The DATA_CRYPTO.GETKEY function will use the left-most bytes of the key passed. Keys that are too large for the algorithm will be truncated. Keys that are too small will be right padded with binary zeros.






              Note 


              Two identical values encrypted with the same key result in the same ciphertext; therefore, careful attention to the encryption keys and their lengths is important to ensuring the data encryption is effectively implemented.



              Keys that are too small or too large can result in a less secure implementation. (This is probably why Oracle does not automatically size the keys for you.) You’ll see an example of this in the “Weak Keys” section.





              Weak Keys


              The DBMS_CRYPTO package does not truncate or pad encryption keys in any way. This leaves the responsibility for creating the appropriately sized keys to the developer. There are a few important things to consider.


              The DATA_CRYPTO.GETKEY is a convenience function. It pads or truncates keys for the relevant encryption algorithm. It uses the left-most bits for the truncation. It is therefore possible to provide two different keys that get truncated to the same encryption key. That is, if the key is too long for the algorithm, then its truncation may remove the uniqueness:



              sec_mgr@KNOX10g> COL encrypted1 format a16 
              sec_mgr@KNOX10g> COL encrypted2 format a16
              sec_mgr@KNOX10g> EXEC data_crypto.set_Algorithm(data_crypto.DES);

              PL/SQL procedure successfully completed.

              sec_mgr@KNOX10g> SELECT data_crypto.encrypt_char ('Data',
              2 'ThisKeyIsOver8bytes')
              3 encrypted1,
              4 data_crypto.encrypt_char ('Data',
              5 'ThisKeyIsAlsoOver8bytes')
              6 encrypted2
              7 FROM DUAL;

              ENCRYPTED1 ENCRYPTED2
              ------------------- ---------------------
              0DCA01D7A8E26AAF 0DCA01D7A8E26AAF


              The DES algorithm requires an 8-byte key. The DATA_CRYPTO.GETKEY function truncates the key to the first 8 bytes. The two preceding keys result in the same key, which subsequently produces the same ciphertext.


              The DATA_CRYPTO.GETKEY will also pad the encryption key to make it the appropriate length. The overall strength of the algorithm is influenced by the uniqueness and variations in all elements of the key. If you elect to use AES256, the key size is 32 bytes. If you use a key with one character (a key size of 1 byte), then the remaining key bytes (characters) will be the same—you will have 1 byte that you provided and 31 bytes of binary zeros. This could make it much easier for an attacker to guess your encryption key.


              The DATA_CRYPTO.GETKEY is provided for convenience and as a reference. Understanding the implications of key size and thus overall strength is important to ensuring the encryption process will be effective.