Monday, May 15, 2017

Hack 5.1 Encrypting SAS Macros




SAS Programming Professionals,

Did you know that you can encrypt SAS macros so that nobody can see the source code?

This can be handy if cases where you have SAS macros that you must deliver to a client but do not want to divulge the source code because it employs proprietary corporate algorithms.  The client can execute the macros, but cannot see the source code, even if MPRINT and MLOGIC are enabled!

Here is an example that you can enter into a SAS session to take for a test drive:

libname mylib "c:\temp";

options mstored sasmstore=mylib;

%macro secretmc/store secure; /* This macro is encrypted */
    data _null_;
      x=1;
      put "This data step was generated from a secure macro.";
    run;
  %mend secretmc;

options mprint mlogic symbolgen;

  %secretmc

In the example, we first allocate c:\temp as a SAS data library, and then tell SAS to store any compiled macros in a catalog in that library.  Next, we create a compiled macro named SECRETMC.  The STORE option specifies that we are to compile the macro and save it.  SAS refers to the MSTORED option and stores the macro in a catalog at the location that it specifies.  The SECURE option directs SAS to encrypt the macro as it compiles it.

Next, we try to be clever and specify several options that would normally reveal SAS macros that are executed.  Then, we invoke the SECRETMC macro to see the source code.  What we see in the log is:

1    libname mylib "c:\temp";
NOTE: Libref MYLIB was successfully assigned as follows:
      Engine:        V9
      Physical Name: c:\temp
2
3    options mstored sasmstore=mylib;
4
5    %macro secretmc/store secure; /* This macro is encrypted */
6        data _null_;
7          x=1;
8          put "This data step was generated from a secure macro.";
9        run;
10     %mend secretmc;
11
12   options mprint mlogic symbolgen;
13
14     %secretmc

This data step was generated from a secure macro.
NOTE: DATA statement used (Total process time):
      real time           0.00 seconds
      cpu time            0.00 seconds

Note that the SECRETMC macro was executed and we got the message it generates, but we were unable to surface the source code.

Being clever SAS programmers, we think of a more nefarious way to surface the macro code and run the following simple DATA step:

  filename maccat catalog 'mylib.sasmacr.secretmc.macro';

  data _null_;
    infile maccat;
    input;
    list;
  run;

This program is designed to read each line of the macro stored in the SAS macro catalog and write it to the SAS log.  However, because the macro was encrypted, all we get is this:

16     filename maccat catalog 'mylib.sasmacr.secretmc.macro';
17
18     data _null_;
19       infile maccat;
20       input;
21       list;
22     run;

NOTE: The infile MACCAT is:
      Catalog Name=MYLIB.SASMACR.SECRETMC.MACRO,
      Catalog Page Size=4096,
      Number of Catalog Pages=8,
      Created=Saturday, May 14, 2015 12:51:00 PM,
      Last Modified=Monday, June 23, 2015 06:16:19 PM,
      Filename=c:\temp\sasmacr.sas7bcat,
      Release Created=9.0202M3,
      Host Created=W32_VSPRO

RULE:     ----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+-

1   CHAR  ......SECRETMC..........................°I..9.2     ....................°... ...u.....
    ZONE  0000005445454400000000000000000000000000B4003232222200000000000000000000B0002000700000
    NUMR  100080353254D30000000000000000000000004009009E2000000000000000000000100000000000500030

      87  ..¨.......>................... 116
    ZONE  00A000100030000000000000000000
    NUMR  008000C000E0000000000000000000

2   CHAR  †xf2<  .T9OT:á€{..…¯&(¾[+NìA.ÞÕ}0±.[#×.ä=5½"X[£%.e.¹%·.¶!¡(œ.ýð.'x.é.†‘u.àŸ..ÏŽ8..rBU½
    ZONE  87633AA053453E87108A22B524E40DD73B152D1E33B255A2161B2B1B2A290FF1270E08970E911C8301745B
    NUMR  6862C00149F4A10BD65F68EBBEC1BE5D01AB37E4D5D28B3535F957E6118C7D0678C9861580FEBFE8BC225D

      87  ¹æTgŸ)=xvØO.Wá#.B..÷ÀÛB.9OC™±.5më.YÈHMS¦Gë.×f.Jža‰WøG§.¢)w.iIºS,ݬ.gÿV
    ZONE  BE5692377D425E21401FCD403449B136E05C445A4E0D6149685F4A1A27164B52DA16F5
    NUMR  9647F9D868FE71302AE70B209F391A5DB0988D367BF761AE1978772297899A3CDC77F6

3   CHAR  +r.#6O.¦!MÂR 12
    ZONE  2702340A24C5
    NUMR  B2136F661D22

4   CHAR  qÚ+.=¤.Æ.^šj.«Î–9ÌŠ.8ýXÅ%éT¬ 28
    ZONE  7D203A2C15960AC93C813F5C2E5A
    NUMR  1AB3D4E63EAA3BE69CAE8D85594C
NOTE: 4 records were read from the infile MACCAT.
      The minimum record length was 12.
      The maximum record length was 156.
NOTE: DATA statement used (Total process time):
      real time           0.00 seconds
      cpu time            0.00 seconds

…which means that the SECRETMC SAS macro is secure and all attempts to reveal the source code have been thwarted!

There is obviously a lot more about compiling, storing, and securing SAS macros than can be covered in this text.  Access the SAS online documentation at support.sas.com for further reading.


Best of luck in all your SAS endeavors!

---MMMMIIIIKKKKEEEE
(aka Michael A. Raithel)
Author of the new cult classic for computer programmers:  It Only Hurts When I Hit <ENTER>
Print edition:  http://tinyurl.com/z8bzx2e 
Kindle edition: http://tinyurl.com/zypgqa7 

The hack above is an excerpt from the book:  Did You Know That?  Essential Hacks for Clever SAS Programmers