-
Notifications
You must be signed in to change notification settings - Fork 0
/
dbo.genpassword.sql
139 lines (117 loc) · 5.05 KB
/
dbo.genpassword.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/*
genpassword.sql v2.1
Generates random passwords - MS SQL Server 2016
Public domain. No warranties.
Parameters:
@size Total number of characters required
@lc Minimum number of lower-case letters required (zero means no lower-case)
@uc Minimum number of upper-case letters required (zero means no upper-case)
@num Minimum number of numeric digits required (zero means no numbers)
@sym Minimum number of symbol characters required (zero means no symbols)
@pwd Output parameter for generated password
@symset Set of (non-alpha, non-numeric) symbols
@leetsafe Excludes l,O,0
@patt Specifies a pattern of characters which the password must match
If len(@patt) is shorter than the password then any characters are permitted after that length
The following characters are valid in the pattern
0 = digit
L = letter
A = letter or digit
& = any character
Example: @patt = 'LL' means the password must begin with two letters
*/
CREATE OR ALTER PROCEDURE dbo.genpassword
(
@size INT = NULL,
@lc TINYINT = NULL,
@uc TINYINT = NULL,
@num TINYINT = NULL,
@sym TINYINT = NULL,
@pwd NVARCHAR(256) = NULL OUT,
@symset NVARCHAR(256) = NULL,
@leetsafe BIT = 1,
@patt NVARCHAR(256) = N''
)
AS
BEGIN;
DECLARE @charset NVARCHAR(128),
@lcchar NVARCHAR(128),
@ucchar NVARCHAR(128),
@numchar NVARCHAR(128),
@symchar NVARCHAR(128),
@sympat NVARCHAR(256),
@try SMALLINT,
@randbin VARBINARY(256),
@charsetlength TINYINT,
@charsetoffset TINYINT,
@seed VARBINARY(256);
SELECT @size = CASE WHEN @size > 256 THEN 256 WHEN @size > 0 THEN @size ELSE 8 END,
@lc = COALESCE(@lc,0),
@uc = COALESCE(@uc,0),
@num = COALESCE(@num,0),
@sym = COALESCE(@sym,0),
@sympat = N'',
@patt = REPLACE(REPLACE(REPLACE(REPLACE(COALESCE(@patt,N''),N'0',N'[0-9]'),N'A',N'[A-Z0-9]'),N'L',N'[A-Z]'),N'&',N'_')+N'%',
/* If no complexity requirements specified then default to lower-case only */
@lc = CASE WHEN @lc + @uc + @num + @sym = 0 THEN 1 ELSE @lc END;
/* Set the upper-case, lower-case, numeric and symbol character sets */
IF @leetsafe = 1 OR @leetsafe IS NULL
BEGIN;
SELECT
@ucchar = N'ABCDEFGHIJKLMNPQRSTUVWXYZ', /* excludes O to avoid confusion with zero */
@lcchar = N'abcdefghijkmnopqrstuvwxyz', /* excludes l to avoid confusion with one */
@numchar = N'123456789', /* excludes zero */
@symchar = CASE WHEN @symset>N'' THEN @symset ELSE N'-,;+%&!.' END;
END;
IF @leetsafe = 0
BEGIN;
SELECT
@ucchar = N'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
@lcchar = N'abcdefghijklmnopqrstuvwxyz',
@numchar = N'0123456789',
@symchar = CASE WHEN @symset>N'' THEN @symset ELSE N'-,;+%&!.' END;
END;
/* Add escape characters to the symbol pattern*/
WHILE LEN(@sympat)<LEN(@symchar)*2
SET @sympat = @sympat+N'x'+SUBSTRING(@symchar,(LEN(@sympat)/2)+1,1)
/* Now define the composite character set we are actually going to use */
SELECT @charset =
CASE WHEN @lc > 0 THEN @lcchar ELSE N'' END
+ CASE WHEN @uc > 0 THEN @ucchar ELSE N'' END
+ CASE WHEN @num > 0 THEN @numchar ELSE N'' END
+ CASE WHEN @sym > 0 THEN @symchar ELSE N'' END,
@charsetlength = LEN(@charset),
@pwd = '',
@try = 0;
WHILE @pwd = '' AND @try < 900 /* Loop: try upto 900 times to get a good password */
BEGIN;
SET @try = @try + 1;
SET @seed =
CAST(HASHBYTES('SHA2_512',CAST(NEWID() AS VARBINARY(16))) AS VARBINARY(64))
+CAST(HASHBYTES('SHA2_512',CAST(NEWID() AS VARBINARY(16))) AS VARBINARY(64))
+CAST(HASHBYTES('SHA2_512',CAST(NEWID() AS VARBINARY(16))) AS VARBINARY(64))
+CAST(HASHBYTES('SHA2_512',CAST(NEWID() AS VARBINARY(16))) AS VARBINARY(64));
/* Generate random binary */
SET @randbin = CRYPT_GEN_RANDOM(@size,@seed);
/* Convert the binary to a password based on the required character set */
WHILE @charsetlength > 0 AND LEN(@pwd) < @size /* repeat until we reach the required size */
SET @pwd = @pwd
+ SUBSTRING(@charset
, CAST(SUBSTRING(@randbin,LEN(@pwd)+1,1) % @charsetlength + 1 AS INT),1);
/* Check if the password meets complexity requirements. If not then set to '' so we can try again */
IF NOT (@pwd LIKE @patt COLLATE Latin1_General_CI_AS)
OR
NOT ( @pwd LIKE REPLICATE(N'%['+@lcchar+N']',@lc)+N'%' COLLATE Latin1_General_CS_AS
AND @pwd LIKE REPLICATE(N'%['+@ucchar+N']',@uc)+N'%' COLLATE Latin1_General_CS_AS
AND @pwd LIKE REPLICATE(N'%['+@numchar+N']',@num)+N'%' COLLATE Latin1_General_CS_AS
AND @pwd LIKE REPLICATE(N'%['+@sympat+']',@sym)+N'%' COLLATE Latin1_General_CS_AS
ESCAPE N'x' COLLATE Latin1_General_CS_AS)
SET @pwd = N'';
END;
PRINT @pwd;
END;
GO
/* Generate some passwords */
DECLARE @pass VARCHAR(MAX);
EXEC GenPassword @size=10, @lc=1, @uc=1, @num=1, @sym=1, @leetsafe = 1, @patt ='L';
GO 100