Skip to content

Commit df88c22

Browse files
committed
Update comment
1 parent fb8b273 commit df88c22

File tree

1 file changed

+55
-55
lines changed

1 file changed

+55
-55
lines changed
Lines changed: 55 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,30 @@
11
/************************************************************************************************
2-
Random Password Generation
3-
1. Defining keyword arguments control the length and characters
4-
used in the password.
5-
2. Building a macro variable containing all allowed characters.
6-
3. In a loop, using %SUBSTR(%SYSFUNC(RAND)) to pluck random characters...
7-
4. ...and appending them to the growing password.
8-
5. Testing our macro via a simple loop and various settings.
9-
6. Using a random password for an encryption key on a tempoarary dataset.
10-
2+
RANDOM PASSWORD GENERATION
3+
A macro program that generates a random password based on a list of allowed characters.
114
Keywords: Macro
125
SAS Versions: SAS 9, SAS Viya
136
Documentation: https://go.documentation.sas.com/doc/en/pgmsascdc/default/mcrolref/titlepage.htm
14-
15-
NOTES:
16-
1. Only tested with SAS OnDemand for Academics, as that is the only
17-
SAS version I have access to.
18-
2. Does not (currently) support unmatched single or double quote characters
19-
in the special characterw string. I have not tried mismatched left or
20-
right parentheses, either.
7+
1. Define keyword arguments control the length and characters used in the password.
8+
2. Build a macro variable containing all allowed characters.
9+
3. In a loop, use %SUBSTR(%SYSFUNC(RAND)) to select random characters...
10+
4. ...and append them to the growing password.
11+
5. Test macro via a simple loop and various settings.
12+
6. Use a random password for an encryption key on a tempoarary dataset.
13+
NOTE: Does not (currently) support unmatched single or double quote characters
14+
in the special characterw string. Mismatched left or right parentheses have not been
15+
tested either.
2116
************************************************************************************************/
2217

2318
/************************************************************************************************
24-
1. Defining keyword arguments control the length and characters
19+
1. Define keyword arguments control the length and characters
2520
used in the password.
2621
a. len= is the desired length of the password, defaulting to 24
2722
b. digits= is a Boolean flag, defaulting to TRUE. When TRUE (non-zero),
2823
digits 0-9 are available for use in the password.
2924
c. special= is a set of special characters to also use in passwords. Defaults
3025
to those shown in the %NRSTR(). Use special= to not have any specials.
3126
************************************************************************************************/
27+
3228
%MACRO RANDPASS(len=24,digits=1,special=%NRSTR(@%&#!?.-_+*,/;:));
3329
%LOCAL pass;
3430
%LOCAL chars;
@@ -37,13 +33,14 @@
3733
%LOCAL i;
3834

3935
/************************************************************************************************
40-
2. Building a macro variable containing all allowed characters.
36+
2. Build a macro variable containing all allowed characters.
4137
a. Add the lowercase letters.
4238
b. Add uppercase characters via %UPCASE().
4339
c. Add digits, if requested.
4440
d. Add special characters. Note the use of %SUPERQ() to avoid issues
4541
with &s and %s that may be present in the string.
4642
************************************************************************************************/
43+
4744
%LET chars=abcdefghijklmnopqrstuvwxyz;
4845
%LET chars=&chars%UPCASE(&chars);
4946
%IF &digits %THEN
@@ -53,31 +50,34 @@
5350
%LET numchars=%length(&chars);
5451

5552
%DO i=1 %TO &len;
56-
/************************************************************************************************
57-
3. In a loop, using %SUBSTR(%SYSFUNC(RAND)) to pluck random characters...
58-
a. RAND('INTEGER', n) produces a random intger between 1 and n, inclusive
59-
which is exactly what we need.
60-
b. %SYSFUNC() invokes it from Macro.
61-
c. %SUBSTR(string, N, 1) plucks the Nth character from the string.
62-
************************************************************************************************/
63-
%LET pick=%SUBSTR(&chars,%SYSFUNC(RAND(INTEGER,&numchars)),1);
64-
65-
/************************************************************************************************
66-
4. ...and appending them to the growing password.
67-
a. Note in particular the shenanigans here.
68-
b. Simply coding "%LET pass=%SUPERQ(pass)&pick" _does_not_work_. Hidden
69-
macro quoting characters end up in &pass, in a nested fashion, and
70-
this produces nested Macro function WARNINGs when the password length
71-
grows to about 12 characters, which is unacceptable.
72-
c. The %QSUBSTR() manages to avoid this problem, and also avoids attempts
73-
to resolve any &foo that might appear in the growing password.
74-
d. However, %QSUBSTR() can't work on an empty string, so we have to avoid
75-
it first time though, hence the %IF.
76-
************************************************************************************************/
77-
%IF &i = 1 %THEN
78-
%LET pass=&pick;
79-
%ELSE
80-
%LET pass=%QSUBSTR(%SUPERQ(pass),1)&pick;
53+
54+
/************************************************************************************************
55+
3. In a loop, use %SUBSTR(%SYSFUNC(RAND)) to select random characters...
56+
a. RAND('INTEGER', n) produces a random intger between 1 and n, inclusive
57+
which is exactly what we need.
58+
b. %SYSFUNC() invokes it from Macro.
59+
c. %SUBSTR(string, N, 1) plucks the Nth character from the string.
60+
************************************************************************************************/
61+
62+
%LET pick=%SUBSTR(&chars,%SYSFUNC(RAND(INTEGER,&numchars)),1);
63+
64+
/************************************************************************************************
65+
4. ...and append them to the growing password.
66+
a. Note in particular the shenanigans here.
67+
b. Simply coding "%LET pass=%SUPERQ(pass)&pick" _does_not_work_. Hidden
68+
macro quoting characters end up in &pass, in a nested fashion, and
69+
this produces nested Macro function WARNINGs when the password length
70+
grows to about 12 characters, which is unacceptable.
71+
c. The %QSUBSTR() manages to avoid this problem, and also avoids attempts
72+
to resolve any &foo that might appear in the growing password.
73+
d. However, %QSUBSTR() can't work on an empty string, so we have to avoid
74+
it first time though, hence the %IF.
75+
************************************************************************************************/
76+
77+
%IF &i = 1 %THEN
78+
%LET pass=&pick;
79+
%ELSE
80+
%LET pass=%QSUBSTR(%SUPERQ(pass),1)&pick;
8181
%END;
8282

8383
%* The result of the macro is this generated password;
@@ -86,45 +86,45 @@
8686
%MEND;
8787

8888
/************************************************************************************************
89-
5. Testing our macro via a simple loop, and various settings.
89+
5. Test macro via a simple loop and various settings.
9090
a. We need to define a macro for this. Macro now allows %IF statements in
9191
"open code", but not loops.
9292
b. Just two cases here. All-defaults, plus longer-no-digits-no-specials.
9393
c. The "test" just prints them to the log, for eyeballing.
9494
d. Then we run the loop 3 times to get an idea as to what it's doing.
9595
************************************************************************************************/
96+
9697
%MACRO TEST(n);
97-
%DO i=1 %TO &n;
98-
%PUT pw1=%RANDPASS();
99-
%PUT pw2=%RANDPASS(len=30,digits=0,special=);
98+
%DO i=1 %TO &n;
99+
%PUT pw1=%RANDPASS();
100+
%PUT pw2=%RANDPASS(len=30,digits=0,special=);
100101
%END;
101102
%MEND;
102103

103104
%TEST(3);
104105

105-
106-
107106
/************************************************************************************************
108-
6. Using a random password for an encryption key on a tempoarary dataset.
107+
6. Use a random password for an encryption key on a tempoarary dataset.
109108
a. Generate a longish (60 characters) password, safe from prying eyes.
110-
b. We import a list of NSA recruits from a secret location no one has
109+
b. Import a list of NSA recruits from a secret location no one has
111110
ever heard of, and protect it with AES encryption with our generated
112111
password.
113-
c. Now we can run analytics on it safely. Here, we run PROC MEANS, and
112+
c. Now we can run analytics on it safely. Run PROC MEANS, and
114113
then ponder why the recruits are all teenagers.
115-
d. Now we can drop the table (I used PROC SQL), knowing that even if the
114+
d. Drop the table (I used PROC SQL), knowing that even if the
116115
data was recovered from the disk, the encryption renders it unreadable.
117116
************************************************************************************************/
117+
118118
%LET pw=%randpass(len=60);
119119
%*PUT pw=&pw <== to see it, but its supposed to be a secret;
120120

121121
DATA nsaclass(ENCRYPT=aes ENCRYPTKEY="&pw");
122-
SET sashelp.class;
122+
SET sashelp.class;
123123
RUN;
124124

125125
PROC MEANS DATA=nsaclass(ENCRYPTKEY="&pw");
126126
RUN;
127127

128128
PROC SQL;
129-
DROP TABLE nsaclass;
129+
DROP TABLE nsaclass;
130130
QUIT;

0 commit comments

Comments
 (0)