SQLMentor // learn pl/sql

Code Obfuscation (WRAP)

Wrapping converts PL/SQL source into an unreadable, portable form so you can ship code without exposing its logic. The wrapped unit still compiles and runs identically — only the human-readable source is hidden. Oracle offers two ways to wrap: the command-line wrap utility for whole files, and the DBMS_DDL package for dynamic, in-database wrapping.

The Command-Line wrap Utility

wrap is an OS-level tool that reads a .sql file of CREATE OR REPLACE statements and writes an obfuscated .plb file:

wrap iname=emp_pkg_body.sql oname=emp_pkg_body.plb

You then run the .plb exactly like the original script. After it is installed, the source in the data dictionary is the wrapped (unreadable) text:

-- Install the wrapped version
@emp_pkg_body.plb

-- The stored source is now obfuscated
SELECT text
FROM   user_source
WHERE  name = 'EMP_MGR' AND type = 'PACKAGE BODY'
FETCH FIRST 3 ROWS ONLY;
-- => "PACKAGE BODY emp_mgr wrapped\n a000000\n b2\n abcd... (gibberish)"

Dynamic Wrapping with DBMS_DDL

When you generate PL/SQL at runtime, DBMS_DDL wraps it without a separate file step:

  • DBMS_DDL.WRAP(ddl) — takes a CREATE OR REPLACE string and returns the wrapped string.
  • DBMS_DDL.CREATE_WRAPPED(ddl) — wraps and executes the statement in one call.
DECLARE
    v_src  VARCHAR2(32767) :=
        'CREATE OR REPLACE FUNCTION secret_bonus(p_sal NUMBER) RETURN NUMBER IS
         BEGIN
             RETURN p_sal * 0.137;   -- proprietary formula
         END;';
BEGIN
    -- Create the function directly in wrapped form
    DBMS_DDL.CREATE_WRAPPED(v_src);
END;
/

-- secret_bonus works normally, but its body is not readable in USER_SOURCE
SELECT secret_bonus(10000) FROM dual;   -- 1370

What Can (and Cannot) Be Wrapped

Wrappable Not wrappable
Package bodies Package specifications (callers must see the interface)
Type bodies Object type specifications
Standalone procedures & functions Triggers
Anonymous blocks
Wrap only the body, never the spec. Callers need the package/type specification to compile against your code, and a readable spec documents the public interface. Wrapping the body hides the implementation while leaving the contract visible — exactly what you want when shipping to a customer.

Important Limitations

Wrapping is obfuscation, not encryption. It raises the effort required to read your logic, but publicly available "unwrapper" tools can partially reverse it, and it provides no protection for data. Treat it as a deterrent against casual inspection, not as a security control.

Wrapped code cannot be edited or un-wrapped by you either. Always keep the original, un-wrapped source in version control — the .plb is a build artifact, never your master copy. You also cannot wrap across versions blindly: wrap with the oldest Oracle release you must support, since a newer wrap format may not load on an older database.

Verifying a Unit Is Wrapped

-- The first stored source line of a wrapped unit contains the word "wrapped"
SELECT name, type
FROM   user_source
WHERE  line = 1
AND    LOWER(text) LIKE '%wrapped%';

Practical Workflow

  1. Develop and test with plain, readable source under version control.
  2. As a release step, wrap the package/type bodies you distribute (via wrap or DBMS_DDL).
  3. Ship the readable specs plus the wrapped bodies to the customer.
  4. Keep the un-wrapped master safe — it is the only editable copy.

Summary

  • Wrapping obfuscates PL/SQL source while leaving behaviour unchanged.
  • The command-line wrap iname=… oname=… utility wraps a whole .sql file into a .plb.
  • DBMS_DDL.WRAP returns wrapped text; DBMS_DDL.CREATE_WRAPPED wraps and executes dynamically.
  • Wrap bodies (package, type) and standalone subprograms; you cannot wrap specs, triggers, or anonymous blocks.
  • It is obfuscation, not encryption — unwrappers exist; never rely on it to protect secrets or data.
  • Wrapped code can't be edited — keep the original source in version control and wrap with the oldest supported release.