产生随机密码的基础是产生随机数。
首先,必须有种子。
DBMS_RANDOM.seed(l_seed)
这个种子可以是字符串。为了增加随机性,这个种子字符串可以从Timestamp来获取。
比如,l_seed := to_char(SYSTIMESTAMP,'YYYYDDMMHH24MISSFFFF');
其次,有Value函数。
DBMS_RANDOM.value(mix,max);
给出最小和最大值就可以产生指定范围的随机数。
步骤:
1. 按照函数自变量指定的各类字符(L,小写字母;U-大写字母;D-数字;S-其他符号)的长度,缺省值大家都是1,
产生一个包含LUDS的字符串,其长度是所要产生的密码的长度。
比如,要产生的密码长度为8,可以得到LUDSLUDS。
2. 然后把这个字符串洗牌,得到随机的字符串,比如SLDUDLUS。
3. 最后,按以上随机顺序,分别从各种字符的全集中随机取得各个字符,按照步骤2得到的顺序,拼凑一个密码。
比如 %b9H2aK$。
请看代码:
create or replace function key_gen(
p_len number default 12,
p_use_lcs number default 1,
p_use_ucs number default 1,
p_use_dgt number default 1,
p_use_smb number default 1,
p_use_hex char default 'N',
p_esy_rec char default 'N',
p_smb_str varchar2 default null
)
return varchar2 is
l_use_ptn varchar2(1000);
l_use_ptn_len number;
l_use_str varchar2(4000);
l_use_typ varchar2(10);
l_seed varchar2(100);
l_lcs varchar2(26):= 'abcdefghijklmnopqrstuvwxyz';
l_lcs_len number;
l_ucs varchar2(26):= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
l_ucs_len number;
l_dgt varchar2(10):= '0123456789';
l_dgt_len number;
l_smb varchar(50) := q'#!"#$%&'()=~`{+*}<>?_-^\@[;:],./\'#';
l_smb_len number;
l_hex varchar2(16):= '0123456789abcdef';
l_hex_len number;
l_key varchar2(4000);
l_p1 number;
begin
if Upper(p_esy_rec) = 'Y' then
l_lcs := 'abcdefghijkmnpqrstuvwxyz';
l_ucs := 'ABCDEFGHIJKLMNPQRSTUVWXYZ';
l_dgt := '23456789';
l_smb := q'|!#$%&=+*?-@|';
end if;
if p_smb_str is not null then
l_smb := p_smb_str;
end if;
l_lcs_len := lengthb(l_lcs);
l_ucs_len := lengthb(l_ucs);
l_dgt_len := lengthb(l_dgt);
l_smb_len := lengthb(l_smb);
l_hex_len := lengthb(l_hex);
l_use_ptn := Null;
l_use_ptn := l_use_ptn || Trim(rpad(' ',p_use_lcs+1,'L')); -- Put number of Lowercase into pattern
l_use_ptn := l_use_ptn || Trim(rpad(' ',p_use_ucs+1,'U')); -- Put number of Uppercase into pattern
l_use_ptn := l_use_ptn || Trim(rpad(' ',p_use_dgt+1,'D')); -- Put number of Digit into pattern
l_use_ptn := l_use_ptn || Trim(rpad(' ',p_use_smb+1,'S')); -- Put number of Symbol into pattern
if Upper(p_use_HEX) = 'Y' then -- If hex, excludes others
l_use_ptn := Trim(rpad(' ',p_len+1,'H'));
end if;
l_use_str := l_use_ptn; -- Compose character type sequence, LUCDSLUCDS....
if replace(l_use_ptn,'S','') is not null then
l_use_ptn := replace(l_use_ptn,'S',''); -- Replace S(=symble) if any. Since we need only specified numbers of symble
end if;
loop
l_use_str := l_use_str||l_use_ptn;
exit when lengthb(l_use_str)>=p_len;
end loop;
l_use_str := Substr(l_use_str,1,p_len);
--htp.p(l_use_str);
l_seed := to_char(SYSTIMESTAMP,'YYYYDDMMHH24MISSFFFF');
DBMS_RANDOM.seed(l_seed);
-- Randomize the LUDSLUDS sequence
for i in 1 .. p_len loop
l_p1 := ROUND(DBMS_RANDOM.value(1,p_len));
l_use_str := substr(l_use_str,1,l_p1-1)||substr(l_use_str,l_p1+1)||Substr(l_use_str,l_p1,1);
end loop;
l_key := NULL;
for i in 1 .. p_len loop
l_use_typ := substr(l_use_str,i,1);
case l_use_typ
when 'L' then
l_p1 := ROUND(DBMS_RANDOM.value(1,l_lcs_len));
l_key := l_key||substr(l_lcs,l_p1,1);
when 'U' then
l_p1 := ROUND(DBMS_RANDOM.value(1,l_ucs_len));
l_key := l_key||substr(l_ucs,l_p1,1);
when 'D' then
l_p1 := ROUND(DBMS_RANDOM.value(1,l_dgt_len));
l_key := l_key||substr(l_dgt,l_p1,1);
when 'S' then
l_p1 := ROUND(DBMS_RANDOM.value(1,l_smb_len));
l_key := l_key||substr(l_smb,l_p1,1);
when 'H' then
l_p1 := ROUND(DBMS_RANDOM.value(1,l_hex_len));
l_key := l_key||substr(l_hex,l_p1,1);
end case;
end loop;
return l_key;
end;
说明:
自变量有以下8个,每个都有各自的缺省值。如果不指定任何自变量而执行函数,就可以按照缺省值得到一个随机密码。
这可以满足大多数人的要求。
1. 密码长度,缺省值=12。 p_len number default 12,
2. 使用小写字母的最小个数,缺省值=1。0为不使用 p_use_lcs number default 1,
3. 使用大写字母的最小个数,缺省值=1。0为不使用 p_use_ucs number default 1,
4. 使用数字的最小个数,缺省值=1。0为不使用 p_use_dgt number default 1,
5. 使用符号的最小个数,缺省值=1。0为不使用 p_use_smb number default 1,
6. 是否使用16进数产生密码,缺省值=N(不使用) p_use_hex char default 'N',
此变量优先度高。如果指定为Y或y,第2-5项变量自动为0.
7. 是否产生易读的密码,缺省值=N(不使用) p_esy_rec char default 'N',
如果指定为Y或y,则不使用容易混淆的字母/数字/符号。比如0/O,1/l,以及一些不易记忆的符号。
8. 用户指定的符号字符串,缺省为Null。 p_smb_str varchar2 default null
此变量优先度高。如果指定,将取代函数中预设的符号字符串。这可以使得用户使用自己可以接受的符号,
比如只使用“#$%&”这4个符号。
使用例子:
1. 完全使用缺省值。产生一个12字符的密码。
select KEY_GEN() FROM DUAL;
KEY_GEN()
v2M02pH/EouB
2. 指定长度,产生一个8字符的密码。
select KEY_GEN(8) FROM DUAL;
KEY_GEN(8)
tNiC%5s1
3.产生一个由16进数组成的密码。长度为12(缺省)。
select KEY_GEN(p_use_hex=>'Y') FROM DUAL;
KEY_GEN(P_USE_HEX=>'Y')
2684dd8cf3ad
4.产生一个包含2个符号的密码,但是符号只包含“#$%&”长度为12(缺省)。
select KEY_GEN(p_smb_str=>'#$%&', p_use_smb=>2) password FROM DUAL;
PASSWORD
lpW1Ux1$S7v%