Skip Headers
Oracle® Database PL/SQL User's Guide and Reference
10g Release 2 (10.2)

Part Number B14261-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
PDF · Mobi · ePub

A Obfuscating 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.

This appendix contains these topics:

See Also:

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

What is Obfuscation?

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 command, that has been 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:

Tips When Obfuscating 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 Obfuscation

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 Corporation 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 calls a wrapped procedure.

  • 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.

Limitations of the 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.

Obfuscating PL/SQL Code With the 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:

wrap iname=input_file [oname=output_file]

Do not use any spaces around the equal signs.

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 oname option is optional, because the output file name defaults to that of the input file and its extension defaults to .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

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 procedures, functions, 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();

Obfuscating 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 calling 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 the DBMS_DDL create_wrapped Procedure

Example A-1 illustrates how CREATE_WRAPPED can be 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
  package_text := generate_spec('emp_actions'); -- generate package spec
  SYS.DBMS_DDL.CREATE_WRAPPED(package_text);  -- create and wrap the package spec
  package_text := generate_body('emp_actions'); -- generate package body
  SYS.DBMS_DDL.CREATE_WRAPPED(package_text); -- create and wrap the package body
END;
/

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

When you check the *_SOURCE views, 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 appears similar to:


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