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 theDBMS_DDL package, see Oracle Database PL/SQL Packages and Types Reference |
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:
It is difficult for other developers to misuse your application, or business competitors to see your algorithms.
Your source code is not visible through the USER_SOURCE
, ALL_SOURCE
, or DBA_SOURCE
data dictionary views.
SQL*Plus can process the obfuscated source files.
The Import and Export utilities accept wrapped files. You can back up or move wrapped procedures.
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.
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.
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".
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.
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
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_nameCREATE [OR REPLACE] PROCEDURE
procedure_nameCREATE [OR REPLACE] PACKAGE
package_nameCREATE [OR REPLACE] PACKAGE BODY
package_nameCREATE [OR REPLACE] TYPE
type_name AS OBJECT
CREATE [OR REPLACE] TYPE
type_name UNDER
type_nameCREATE [OR REPLACE] TYPE BODY
type_nameThe 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;
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();
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.
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