Skip Headers
Oracle® Database PL/SQL Language Reference
11g Release 1 (11.1)

Part Number B28370-01
Go to Documentation Home
Home
Go to Book List
Book List
Go to Table of Contents
Contents
Go to Index
Index
Go to Master Index
Master Index
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
View PDF

A Wrapping PL/SQL Source Code

This appendix describes how to use the standalone wrap utility and subprograms of the DBMS_DDL package to obfuscate, or wrap, PL/SQL source code. When you obfuscate (hide) PL/SQL units, you can deliver PL/SQL applications without exposing your source code and implementation details.

Topics:

See Also:

For information on the DBMS_DDL package, see Oracle Database PL/SQL Packages and Types Reference

What is Wrapping?

Obfuscation, or wrapping, of a PL/SQL unit is the process of hiding the PL/SQL source code. Wrapping can be done with the wrap utility and DBMS_DDL subprograms. The wrap utility is run from the command line and processes an input SQL file, such as a SQL*Plus installation script. The DBMS_DDL subprograms wrap a single PL/SQL unit, such as a single CREATE PROCEDURE statement, that was generated dynamically.

The advantages of obfuscating, or hiding, the source code of PL/SQL units with the wrap utility or wrap subprograms of the DBMS_DDL package are:

Topics:

Guidelines for Wrapping PL/SQL Units

When obfuscating (wrapping) PL/SQL units note the following:

  • When wrapping a package or object type, wrap only the body, not the specification. This allows other developers see the information they need to use the package or type, but they cannot see its implementation.

  • PL/SQL source inside wrapped files cannot be edited. To change wrapped PL/SQL code, edit the original source file and wrap it again. You can either hold off on wrapping your code until it is ready for shipment to end-users, or include the wrapping operation as part of your build environment.

  • To be sure that all the important parts of your source code are obfuscated, view the wrapped file in a text editor before distributing it.

Limitations of Wrapping

The following are limitations when obfuscating PL/SQL source code:

  • Although wrapping a compilation unit helps to hide the algorithm and makes reverse-engineering difficult, Oracle does not recommend it as a secure method for hiding passwords or table names. Obfuscating a PL/SQL unit prevents most users from examining the source code, but might not stop all attempts.

  • The wrapping does not obfuscate the source code for triggers. To hide the workings of a trigger, you can write a one-line trigger that invokes a wrapped subprogram.

  • Wrapping only detects tokenization errors, such as a runaway string, when obfuscating PL/SQL code. Wrapping does not detect syntax or semantic errors, such as tables or views that do not exist. Those errors are detected during PL/SQL compilation or when executing the output file in SQL*Plus.

  • Obfuscated PL/SQL program units cannot be imported into a database of a previous (lower) release. Wrapped compilation units are upward-compatible between Oracle releases, but are not downward-compatible. For example, you can load files processed by the V8.1.5 wrap utility into a V8.1.6 Oracle database, but you cannot load files processed by the V8.1.6 wrap utility into a V8.1.5 Oracle database.

Topics:

Limitations of the PL/SQL wrap Utility

  • Because the source code is parsed by the PL/SQL compiler, not by SQL*Plus, you cannot include substitution variables using the SQL*Plus DEFINE notation inside the PL/SQL code. You can use substitution variables in other SQL statements that are not obfuscated.

  • Most of the comments are removed in wrapped files. See "Input and Output Files for the PL/SQL wrap Utility".

Limitations of the DBMS_DDL wrap Function

  • If you invoke DBMS_SQL.PARSE (when using an overload where the statement formal has datatype VARCHAR2A or VARCHAR2S for text which exceeds 32767 bytes) on the output of DBMS_DDL.WRAP, then you need to set the LFFLG parameter to FALSE. Otherwise DBMS_SQL.PARSE adds newlines to the wrapped unit which corrupts the unit.

Wrapping PL/SQL Code with PL/SQL wrap Utility

The wrap utility processes an input SQL file and obfuscates only the PL/SQL units in the file, such as a package specification, package body, function, procedure, type specification, or type body. It does not obfuscate PL/SQL content in anonymous blocks or triggers or non-PL/SQL code.

To run the wrap utility, enter the wrap command at your operating system prompt using the following syntax (with no spaces around the equal signs):

wrap iname=input_file [ oname=output_file ]

input_file is the name of a file containing SQL statements, that you typically run using SQL*Plus. If you omit the file extension, an extension of .sql is assumed. For example, the following commands are equivalent:

wrap iname=/mydir/myfile
wrap iname=/mydir/myfile.sql

You can also specify a different file extension:

wrap iname=/mydir/myfile.src

output_file is the name of the obfuscated file that is created. The defaults to that of the input file and its extension default is .plb. For example, the following commands are equivalent:

wrap iname=/mydir/myfile
wrap iname=/mydir/myfile.sql oname=/mydir/myfile.plb

You can use the option oname to specify a different file name and extension:

wrap iname=/mydir/myfile oname=/yourdir/yourfile.out

Topics:

Input and Output Files for the PL/SQL wrap Utility

The input file can contain any combination of SQL statements. Most statements are passed through unchanged. CREATE statements that define subprograms, packages, or object types are obfuscated; their bodies are replaced by a scrambled form that the PL/SQL compiler understands.

The following CREATE statements are obfuscated:

CREATE [OR REPLACE] FUNCTION function_name
CREATE [OR REPLACE] PROCEDURE procedure_name
CREATE [OR REPLACE] PACKAGE package_name
CREATE [OR REPLACE] PACKAGE BODY package_name
CREATE [OR REPLACE] TYPE type_name AS OBJECT
CREATE [OR REPLACE] TYPE type_name UNDER type_name
CREATE [OR REPLACE] TYPE BODY type_name

The CREATE [OR REPLACE] TRIGGER statement, and [DECLARE] BEGIN-END anonymous blocks, are not obfuscated. All other SQL statements are passed unchanged to the output file.

All comment lines in the unit being wrapped are deleted, except for those in a CREATE OR REPLACE header and C-style comments (delimited by /* */).

The output file is a text file, which you can run as a script in SQL*Plus to set up your PL/SQL subprograms and packages. Run a wrapped file as follows:

SQL> @wrapped_file_name.plb;

Running the wrap Utility

For example, assume that the wrap_test.sql file contains the following:

CREATE PROCEDURE wraptest IS
  TYPE emp_tab IS TABLE OF employees%ROWTYPE INDEX BY PLS_INTEGER;
  all_emps      emp_tab;
BEGIN
  SELECT * BULK COLLECT INTO all_emps FROM employees;
  FOR i IN 1..10 LOOP
    DBMS_OUTPUT.PUT_LINE('Emp Id: ' || all_emps(i).employee_id);
  END LOOP;
END;
/

To wrap the file, run the following from the operating system prompt:

wrap iname=wrap_test.sql

The output of the wrap utility is similar to the following:

PL/SQL Wrapper: Release 10.2.0.0.0 on Tue Apr 26 16:47:39 2005
Copyright (c) 1993, 2005, Oracle.  All rights reserved.
Processing wrap_test.sql to wrap_test.plb

If you view the contents of the wrap_test.plb text file, the first line is CREATE PROCEDURE wraptest wrapped and the rest of the file contents is hidden.

You can run wrap_test.plb in SQL*Plus to execute the SQL statements in the file:

SQL> @wrap_test.plb

After the wrap_test.plb is run, you can execute the procedure that was created:

SQL> CALL wraptest();

Wrapping PL/QL Code with DBMS_DDL Subprograms

The DBMS_DDL package contains procedures for obfuscating a single PL/SQL unit, such as a package specification, package body, function, procedure, type specification, or type body. These overloaded subprograms provide a mechanism for obfuscating dynamically generated PL/SQL program units that are created in a database.

The DBMS_DDL package contains the WRAP function and the CREATE_WRAPPED procedure. The CREATE_WRAPPED both wraps the text and creates the PL/SQL unit. When invoking the wrap procedures, use the fully-qualified package name, SYS.DBMS_DDL, to avoid any naming conflicts and the possibility that someone might create a local package called DBMS_DDL or define the DBMS_DDL public synonym. The input CREATE OR REPLACE statement executes with the privileges of the user who invokes DBMS_DDL.WRAP or DBMS_DDL.CREATE_WRAPPED.

The DBMS_DDL package also provides the MALFORMED_WRAP_INPUT exception (ORA-24230) which is raised if the input to the wrap procedures is not a valid PL/SQL unit.

Using DBMS_DDL create_wrapped Procedure

In Example A-1 CREATE_WRAPPED is used to dynamically create and wrap a package specification and a package body in a database.

Example A-1 Using the create_wrapped Procedure to Wrap a Package

DECLARE
-- the package_text variable contains the text
--  to create the package spec and body
  package_text VARCHAR2(32767);
  FUNCTION generate_spec (pkgname VARCHAR2) RETURN VARCHAR2 AS
  BEGIN
     RETURN 'CREATE PACKAGE ' || pkgname || ' AS
       PROCEDURE raise_salary (emp_id NUMBER, amount NUMBER);
       PROCEDURE fire_employee (emp_id NUMBER);
       END ' || pkgname || ';';
  END generate_spec;
  FUNCTION generate_body (pkgname VARCHAR2) RETURN VARCHAR2 AS
  BEGIN
     RETURN 'CREATE PACKAGE BODY ' || pkgname || ' AS
       PROCEDURE raise_salary (emp_id NUMBER, amount NUMBER) IS
       BEGIN
         UPDATE employees
           SET salary = salary + amount WHERE employee_id = emp_id;
       END raise_salary;
       PROCEDURE fire_employee (emp_id NUMBER) IS
       BEGIN
         DELETE FROM employees WHERE employee_id = emp_id;
       END fire_employee;
       END ' || pkgname || ';';
  END generate_body;

BEGIN
  -- generate package spec
  package_text := generate_spec('emp_actions')
  -- create and wrap the package spec
  SYS.DBMS_DDL.CREATE_WRAPPED(package_text);
  -- generate package body
  package_text := generate_body('emp_actions');
  -- create and wrap the package body
  SYS.DBMS_DDL.CREATE_WRAPPED(package_text);
END;
/

-- invoke a procedure from the wrapped package
CALL emp_actions.raise_salary(120, 100);

When you check the static data dictionary views *_SOURCE, the source is wrapped, or hidden, so that others cannot view the code details. For example:

SELECT text FROM USER_SOURCE WHERE name = 'EMP_ACTIONS';

The resulting output is similar to the following:

TEXT
--------------------------------------------------------------------
PACKAGE emp_actions WRAPPED
a000000
1f
abcd
...