Monday, March 1, 2021

A Second Script For Generating Randomized Oracle Passwords

 A couple of posts back I published a password-generation script I wrote enforcing password complexity constraints (e.g., at least 2 each of lower-case and upper-case characters, special characters, digits) This was a general, easily customizable script; Oracle. of course, has nuanced password policies, depending on the product (e.g., middleware in running OEM cloud control); it might have restrictions, say, on the first character of the password  or restrict the use of special characters. 

You don't have to use a script, of course. For example, there are password generators for most password manager software (e.g., KeePass)) or online (e.g., my SQL Server colleague uses Norton). Why use a script? Well, for instance, I've worked in environments which restricted URL's and it's easier to integrate with related scripts. For example, when I worked as a NASA contractor, I used OPR via Source Forge with the idea of program/password independence (avoiding cleartext passwords in scripts). I've seen other ways of storing passwords, such as password-protected pdf files or spreadsheets (see, e.g., here).

There are other things that come into place into general password policies. For example, my Solaris administrator used a dictionary check to qualify OS passwords, and I found my original script didn't work for my Unix account. Another colleague, not using my script, ran into a similar problem, somehow triggering the dictionary check. I basically suggested that she try overwriting password vowels with consonants. So, for instance, from a script perspective, you might adjust the source character strings and random operator arguments to the lengths of the modified character strings.

Note that the use of special characters in complex passwords can be parsed by Oracle; usually you'll want to use double-quotes around complex passwords. One specific notable example is "@"; the familiar Oracle user knows that Oracle uses @ for Oracle networking connections, so if you don't use quotes, it might read the rest of your password as a net service name in tnsnames.ots. So chances are,  if you run into connection issues, you might have forgotten to use double-quotes in entering your password

A number of government agencies, for example, will require Oracle STIG compliance. The STIGs might require regular password rotations, e.g., every 2 months or sooner, a minimum length (say, 15 characters or more), complexity rules (a mix of character types), restrictions on password reusability, etc.

So what motivated a second password script? Even though the first script worked in Linux and Cygwin, it didn't work in the Solaris version of bash.  The key issue involved a way to scramble a string using all characters in the string. A command I used to do that in the first script wasn't available in Solaris, at least the version I'm using. So basically say I have a string of 16 characters, so the subscripts range from 1 to 16  (or equivalently 0 to 15). So I want a string of 1 to 16 in some random order, without repeating an integer and including every integer. Now I can easily generate one random integer in that range and run that process 16 times. But there's a good chance I'll run into duplicates: e;g.,

~ [Cygwin home]
$ for ((i=1;i<=100;i++)); do echo $(($RANDOM%16)); done
11
2
4
7
1
6
10
5
14
10
0
1
2
5
15
4
3
11
7
9
13
7
4
12
4
11
15
7
2
6
4
10
3
6
0
7
5
6
13
13
7
3
2
5
1
4
11
14
15
6
5
10
3
5
10
1
12
0
5
13
7
3
8
9
12
9
12
7
3
9
9
12
12
2
0
4
5
11
6
14
11
0
2
14
13
2
7
14
15
6
8
9
13
1
15
9
3
2
5
11

So the general idea is to generate a long enough string so each subscript (0-15) appears at least once and then in order of their first appearance in the string: using the above example, 11,2,4,7,1,6,10,5,14,0,15,3,9,13,12,8. I arbitrarily set the length of the string to 1000 characters. 

In this variation of the script I generate q 16-character password, include 4 characters each of 4 types (upper case, lower, digit and special) The password is first displayed to demonstrate complexity policy compliance by character type. I then reshuffle the characters by subscript as described above and display the password in final sequence.

#!/bin/bash
ls=abcdefghijklmnopqrstuvwxyz
us=ABCDEFGHIJKLMNOPQRSTUVWXYZ
ds=0123456789
cs=\#\$\_\@\!
ts=$ls$us$ds$cs
myctr=0
pw=''
npw=''
for (( c=1; c<=4; c++ ))
do
   p=$(($RANDOM % 26 ))-1
   pw=$pw${ls:$p:1}
done
for (( c=1; c<=4; c++ ))
do
   p=$(($RANDOM % 26 ))-1
   pw=$pw${us:$p:1}
done
for (( c=1; c<=4; c++ ))
do
   p=$(($RANDOM % 10 ))-1
   pw=$pw${ds:$p:1}
done
for (( c=1; c<=4; c++ ))
do
   p=$(($RANDOM % 5 ))-1
   pw=$pw${cs:$p:1}
done
echo $pw
for ((i=1; i<=1000; i++)); do echo $(($RANDOM % 16)); done | cat -n | sort -uk2 | sort -nk1 | cut -f2- > tmpsrt
cat tmpsrt | while read mysubs
do
npw=$npw${pw:$mysubs:1}
myctr=$myctr+1
if [[ $myctr -eq 16 ]]; then echo $npw; fi;
done

$ ./genpwd2
bbtuARCC9465@_$_
6_tC54C@Rubb$_9A