I have a table with username and password fields. Now i dont want the password to be stored exactly as a string the user inputted. I want this field to be encrypted or converted into a GUID so no one including people working on SQL can see it.
In case the user loses his password, he has to come up with a new one and it shall get updated in the table.
Any ideas how i can achieve this?
OWASP guidelines say to use a one-way hash for storing passwords.
This article shows how in ASP.NET: http://www.15seconds.com/issue/000217.htm
(You didn't mention the technology you're using to connect to the server, so I took a guess on ASP.NET.)
You can use hashbytes to do so. Like this: assuming password = admin
DECLARE #dummy nvarchar(4000);
select #dummy = CONVERT(nvarchar(4000),'admin');
SELECT HashBytes('SHA1', #dummy);
CREATE FUNCTION dbo.fnInitRc4
(
#Pwd VARCHAR(256)
)
RETURNS #Box TABLE (i TINYINT, v TINYINT)
AS
BEGIN
DECLARE #Key TABLE (i TINYINT, v TINYINT)
DECLARE #Index SMALLINT,
#PwdLen TINYINT
SELECT #Index = 0,
#PwdLen = LEN(#Pwd)
WHILE #Index <= 255
BEGIN
INSERT #Key
(
i,
v
)
VALUES (
#Index,
ASCII(SUBSTRING(#Pwd, #Index % #PwdLen + 1, 1))
)
INSERT #Box
(
i,
v
)
VALUES (
#Index,
#Index
)
SELECT #Index = #Index + 1
END
DECLARE #t TINYINT,
#b SMALLINT
SELECT #Index = 0,
#b = 0
WHILE #Index <= 255
BEGIN
SELECT #b = (#b + b.v + k.v) % 256
FROM #Box AS b
INNER JOIN #Key AS k ON k.i = b.i
WHERE b.i = #Index
SELECT #t = v
FROM #Box
WHERE i = #Index
UPDATE b1
SET b1.v = (SELECT b2.v FROM #Box b2 WHERE b2.i = #b)
FROM #Box b1
WHERE b1.i = #Index
UPDATE #Box
SET v = #t
WHERE i = #b
SELECT #Index = #Index + 1
END
RETURN
END
ANd this function does the encrypt/decrypt part
CREATE FUNCTION dbo.fnEncDecRc4
(
#Pwd VARCHAR(256),
#Text VARCHAR(8000)
)
RETURNS VARCHAR(8000)
AS
BEGIN
DECLARE #Box TABLE (i TINYINT, v TINYINT)
INSERT #Box
(
i,
v
)
SELECT i,
v
FROM dbo.fnInitRc4(#Pwd)
DECLARE #Index SMALLINT,
#i SMALLINT,
#j SMALLINT,
#t TINYINT,
#k SMALLINT,
#CipherBy TINYINT,
#Cipher VARCHAR(8000)
SELECT #Index = 1,
#i = 0,
#j = 0,
#Cipher = ''
WHILE #Index <= DATALENGTH(#Text)
BEGIN
SELECT #i = (#i + 1) % 256
SELECT #j = (#j + b.v) % 256
FROM #Box b
WHERE b.i = #i
SELECT #t = v
FROM #Box
WHERE i = #i
UPDATE b
SET b.v = (SELECT w.v FROM #Box w WHERE w.i = #j)
FROM #Box b
WHERE b.i = #i
UPDATE #Box
SET v = #t
WHERE i = #j
SELECT #k = v
FROM #Box
WHERE i = #i
SELECT #k = (#k + v) % 256
FROM #Box
WHERE i = #j
SELECT #k = v
FROM #Box
WHERE i = #k
SELECT #CipherBy = ASCII(SUBSTRING(#Text, #Index, 1)) ^ #k,
#Cipher = #Cipher + CHAR(#CipherBy)
SELECT #Index = #Index +1
END
RETURN #Cipher
END
This is implemented by Peter but it helps u................
Related
I'm using SSMS, I have a sample table and I want to take each 'num' value (1, 2, 3) multiple it by a different number e.g. 1*1, 2*2, 3*3, and store the answer (14) in a new table.
I can create individual 'unnamed' tables, and I can create a new table with just one output, but not both.
DECLARE #myTableVariable TABLE (id INT, num int)
insert into #myTableVariable values(1,'1'),(2,'2'),(3,'3')
DECLARE #Multiplier INT
DECLARE #Counter INT
SET #Multiplier = 1
SET #Counter = 1
WHILE #Counter <=3
BEGIN
SELECT (num*#Multiplier) AS WMA FROM #myTableVariable WHERE ID = #Counter;
SET #Multiplier = #Multiplier + 1
SET #Counter = #Counter + 1
END
Create a variable and store the value in that variable. Doing this you are not creating any table.
Here is the code,
DECLARE #myTableVariable TABLE (id INT, num int)
insert into #myTableVariable values(1,'1'),(2,'2'),(3,'3')
DECLARE #Multiplier INT
DECLARE #Counter INT
SET #Multiplier = 1
SET #Counter = 1
DECLARE #total INT=0
WHILE #Counter <=3
BEGIN
--SELECT (num*#Multiplier) AS WMA FROM #myTableVariable WHERE ID = #Counter;
set #total = #total+(SELECT (num*#Multiplier) AS WMA FROM #myTableVariable WHERE ID = #Counter)
SET #Multiplier = #Multiplier + 1
SET #Counter = #Counter + 1
END
select #total
Hope this is what you are looking for...
Due to performance perspective I just need to remove loop and using some joins or other solution to update the data in #Result table and get the same result which return by loop.
Scalar function:
CREATE FUNCTION [MultiplyerScl]
(#a INT, #b INT)
RETURNS INT
AS
BEGIN
DECLARE #i AS INT = 2
DECLARE #Value AS INT
IF (#b % #a = 0)
BEGIN
SET #Value = #b
END
ELSE
BEGIN
WHILE (1=1)
BEGIN
IF((#b * #i) % #a = 0)
BEGIN
SET #Value = #b * #i
BREAK;
END
ELSE
BEGIN
SET #i = #i + 1
END
END
END
RETURN #Value
END
Table design and its value.
CREATE TABLE #NUM (Groupid INT, GroupValue INT)
INSERT INTO #NUM
VALUES (1, 8), (1, 9), (1, 23), (2, 5), (2, 5), (2, 10)
Main for loop logic.
SELECT
Groupid,
GroupValue,
MaxValue = MAX(GroupValue) OVER (PARTITION BY Groupid),
MaxCount = COUNT(1) OVER(),
RID = ROW_NUMBER() OVER (ORDER BY groupid)
INTO
#Result
FROM
#NUM
DECLARE #i AS INT = 1
DECLARE #RawCnt AS INT = (SELECT MAX(MaxCount) FROM #Result)
DECLARE #iGroupid INT
DECLARE #iGroupvalue INT
DECLARE #iMaxValue INT
WHILE(#i <= #RawCnt)
BEGIN
SELECT
#iGroupid = Groupid,
#iGroupvalue = Groupvalue,
#iMaxValue = MaxValue
FROM
#Result
WHERE
RID = #i
UPDATE #Result
SET MaxValue = dbo.[MultiplyerScl](#iGroupvalue, #iMaxValue)
WHERE Groupid = #iGroupid
SET #i = #i + 1
END
SELECT * FROM #Result
Try this out
SELECT
Groupid,
GroupValue,
MaxValue = MAX(GroupValue) OVER (PARTITION BY Groupid),
MaxCount = COUNT(1) OVER(),
RID = ROW_NUMBER() OVER (ORDER BY groupid)
INTO
#Result
FROM
#NUM
;WITH Res AS
(
SELECT Groupid, e.Groupvalue, dbo.[MultiplyerScl](Groupvalue, e.MaxValue) AS
MaxValue, 1 AS i
FROM #Result e
UNION ALL
--recursive execution
SELECT e.Groupid, m.Groupvalue, dbo.[MultiplyerScl](e.Groupvalue, m.MaxValue) AS MaxValue, m.i + 1 AS i
FROM #Result e
INNER JOIN Res m ON e.Groupid = m.Groupid
WHERE dbo.[MultiplyerScl](e.Groupvalue, m.MaxValue) > m.MaxValue
)
SELECT Groupid, MAX(MaxValue) AS MaxValue
INTO #FinalResult
FROM Res
GROUP BY Groupid
UPDATE re
SET re.MaxValue = ire.MaxValue
FROM #FinalResult ire
INNER JOIN #Result re ON re.Groupid = ire.Groupid
SELECT * FROM #Result
I am working on SQL Server (2005,2008 & 2012)
I wanna extract first five numbers from varchar column via using UDF
Input:
rrr123ddd4567ddd19828www2
123hhhsss124ss18762s
qq12349wsss12376ss
Output:
19828
18762
12349
My Trail is as following:
DECLARE
#myString VARCHAR(1000),
#temp VARCHAR(100),
#position INT,
#ExecuteInsert nvarchar (500),
#FirstChar bit
SET #myString = 'rrr123ddd4567ddd19828www2'
SET #position = 1
SET #FirstChar = 1
WHILE #position <= LEN(#myString)
BEGIN
IF (ISNUMERIC(SUBSTRING(#myString,#position,1))) = 1
BEGIN
SET #temp = isnull(#temp,'') + SUBSTRING(#myString,#position,1)
SET #FirstChar = 1
END
ELSE /* The char is alphabetical */
BEGIN
if (#FirstChar= 1)
BEGIN
SET #temp = isnull(#temp,'') + ','
SET #FirstChar = 0
END
END
SET #position = #position + 1
END
IF (RIGHT(#temp,1) <> ',')
BEGIN
SET #temp = #temp + ','
END
SELECT #temp = REPLACE(','+ #temp + ',',',,','')
SELECT #temp = Replace (#temp,',','''),(''')
Select #temp = '(''' + #temp + ''')'
Create table #temp
(
col1 varchar(100)
)
SET #ExecuteInsert = 'insert into #temp values ' + #temp
Execute sp_executesql #ExecuteInsert
select top 1 col1 from #temp
where LEN(col1) = 5
drop table #temp
-- Output >> 19828
The previous query is working well with string input , but I wanna using this code within UDF to could using it with columns.
if I used the previous query within UDF, the following error is raising:
Cannot access temporary tables from within a function.
EDIT
if I used Table variable , I get the next error:
Only functions and some extended stored procedures can be executed
from within a function.
any help will be greatly appreciated.
CREATE FUNCTION udfTest
(
-- Add the parameters for the function here
)
RETURNS int
AS
BEGIN
-- Declare the return variable here
DECLARE
#Result int,
#myString VARCHAR(1000),
#temp VARCHAR(100),
#position INT,
#ExecuteInsert nvarchar (500),
#FirstChar bit
SET #myString = 'rrr123ddd4567ddd19828www2'
SET #position = 1
SET #FirstChar = 1
WHILE #position <= LEN(#myString)
BEGIN
IF (ISNUMERIC(SUBSTRING(#myString,#position,1))) = 1
BEGIN
SET #temp = isnull(#temp,'') + SUBSTRING(#myString,#position,1)
SET #FirstChar = 1
END
ELSE /* The char is alphabetical */
BEGIN
if (#FirstChar= 1)
BEGIN
SET #temp = isnull(#temp,'') + ','
SET #FirstChar = 0
END
END
SET #position = #position + 1
END
IF (RIGHT(#temp,1) <> ',')
BEGIN
SET #temp = #temp + ','
END
SELECT #temp = REPLACE(','+ #temp + ',',',,','')
SELECT #temp = Replace (#temp,',','''),(''')
Select #temp = '(''' + #temp + ''')'
Declare #tempTable TABLE
(
col1 varchar(100)
)
insert into #tempTable SELECT #temp
select top 1 #Result=col1 from #tempTable
where LEN(col1) = 5
return #Result
END
GO
Here you are my answer of my question , hope helps others.
The objective is creating UDF function for using it with columns, not only fixed values.
The approach is using SplitString instead of sp_executesql
for splitting a comma separated string and loop it's values in table.
Demo:-
Create table DummyTable
( col1 varchar (100))
go
Insert into DummyTable values ('rrr123ddd4567ddd19828www2')
Insert into DummyTable values ('123hhhsss124ss18762s')
Insert into DummyTable values ('qq12349wsss12376ss')
go
/*
SplitString via Mudassar Khan
http://www.aspsnippets.com/Articles/Split-and-convert-Comma-Separated-Delimited-String-to-Table-in-SQL-Server.aspx
*/
Create FUNCTION SplitString
(
#Input NVARCHAR(MAX),
#Character CHAR(1)
)
RETURNS #Output TABLE (
Item NVARCHAR(1000)
)
AS
BEGIN
DECLARE #StartIndex INT, #EndIndex INT
SET #StartIndex = 1
IF SUBSTRING(#Input, LEN(#Input) - 1, LEN(#Input)) <> #Character
BEGIN
SET #Input = #Input + #Character
END
WHILE CHARINDEX(#Character, #Input) > 0
BEGIN
SET #EndIndex = CHARINDEX(#Character, #Input)
INSERT INTO #Output(Item)
SELECT SUBSTRING(#Input, #StartIndex, #EndIndex - 1)
SET #Input = SUBSTRING(#Input, #EndIndex + 1, LEN(#Input))
END
RETURN
END
GO
-------------------------------------
-------------------------------------
-------------------------------------
/*
My Own Function
*/
Create FUNCTION udfGetFirstFiveNumbers
(
#myString VARCHAR(1000)
)
RETURNS varchar(100)
AS
BEGIN
DECLARE
#temp VARCHAR(100),
#result Varchar (100),
#position INT,
#ExecuteInsert nvarchar (500),
#FirstChar bit
SET #position = 1
SET #FirstChar = 1
WHILE #position <= LEN(#myString)
BEGIN
IF (ISNUMERIC(SUBSTRING(#myString,#position,1))) = 1
BEGIN
SET #temp = isnull(#temp,'') + SUBSTRING(#myString,#position,1)
SET #FirstChar = 1
END
ELSE /* The char is alphabetical */
BEGIN
if (#FirstChar= 1)
BEGIN
SET #temp = isnull(#temp,'') + ','
SET #FirstChar = 0
END
END
SET #position = #position + 1
END
IF (RIGHT(#temp,1) <> ',')
BEGIN
SET #temp = #temp + ','
END
SELECT #temp = REPLACE(','+ #temp + ',',',,','')
SELECT #result = Item
FROM dbo.SplitString(#temp, ',')
where len(Item) = 5
return #result
END
GO
-- Test
select col1, dbo.udfGetFirstFiveNumbers(col1) as result
from DummyTable
Result:-
How do I replace the characters ~!##$%^&*()_+}{][ in a nvarchar (or varchar) field with a - using TSQL?
you can create user define function for that as given below
CREATE FUNCTION udf_ReplaceSpecialChar
(
#inputString VARCHAR(1000)
)
RETURNS VARCHAR(1000)
AS
BEGIN
DECLARE #outputString VARCHAR(1000),
#LENGTH INT,
#index INT,
#char CHAR(1)
SELECT #LENGTH = LEN(#inputString),
#index = 1
WHILE(#index <= #LENGTH)
BEGIN
SET #char = SUBSTRING(#inputString, #index, 1)
IF((ASCII(#char) NOT BETWEEN 65 AND 90) AND (ASCII(#char) NOT BETWEEN 97 AND 122) AND (ASCII(#char) NOT BETWEEN 48 AND 57))
BEGIN
SELECT #inputString = REPLACE(#inputString, #char, '-')
END
SET #index = #index + 1
END
SET #outputString = #inputString
RETURN #outputString
END
SELECT dbo.udf_ReplaceSpecialChar('This()*& is%%#Sample**.>String')
or you should replace each character with '-'
Like
SELECT REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE('This()*& is%%#Sample**.>String', ' ', '-'), '*', '-'), '#', '-'), '&', '-'), '(', '-'), ')', '-'), '.', '-'), '>', '-'), '%', '-')
You can use REPLACE function. If it doesn't work in some cases, please give us examples.
May be this code is that you are searching for:
-- Author: Christian d'Heureuse, www.source-code.biz
create function dbo.RemoveSpecialChars (#s varchar(256)) returns varchar(256)
with schemabinding
begin
if #s is null
return null
declare #s2 varchar(256)
set #s2 = ''
declare #l int
set #l = len(#s)
declare #p int
set #p = 1
while #p <= #l begin
declare #c int
set #c = ascii(substring(#s, #p, 1))
if #c between 48 and 57 or #c between 65 and 90 or #c between 97 and 122
set #s2 = #s2 + char(#c)
set #p = #p + 1
end
if len(#s2) = 0
return null
return #s2
end
It removes all characters except 0-9, a-z and A-Z. This function uses ASCII codes of characters to determine this ones which must be removed.
--another one variant
----------------------------------------------------------------------------------------
--better to keep such table in server, very usefull table, especially with indexes
DECLARE #Tally TABLE ( N INT )
DECLARE #i AS INT = 1
WHILE #i != 1000
BEGIN
INSERT INTO #Tally
( N )
VALUES ( #i )
SET #i = #i + 1
END
----------------------------------------------------------------------------------------
DECLARE #String AS VARCHAR(1000) = 'This()*& is%%# **.>another one //&^&*$variant'
----------------------------------------------------------------------------------------
--using #tally - split, using like - remove not required, 'for xml ...' - combine into string
SELECT REPLACE(( SELECT LEFT(SUBSTRING(#String, n, 1000), 1)
FROM #Tally AS T
WHERE SUBSTRING(#String, n, 1000) != ''
AND LEFT(SUBSTRING(#String, n, 1000), 1) LIKE '[A-Za-z0-9 ]'
FOR
XML PATH('')
), ' ', ' ')
--another one variant
------------------------------------------------------------------------------------
--better to keep such table in server, very usefull table, especially with indexes
DECLARE #Tally TABLE ( N INT )
DECLARE #i AS INT = 1
WHILE #i != 1000
BEGIN
INSERT INTO #Tally
( N )
VALUES ( #i )
SET #i = #i + 1
END
------------------------------------------------------------------------------------
DECLARE #String VARCHAR(500) ,
#B VARCHAR(500) = ''
SET #String = 'This()*& is%%# **.>another one //&^&*$variant'
SELECT #B = #B + SUBSTRING(#String, t.N, 1)
FROM #Tally t
WHERE t.N <= DATALENGTH(#String)
AND PATINDEX('[A-Za-z0-9 ]', SUBSTRING(#String, t.N, 1)) > 0
SELECT #B
--------------------------------------------------------------------------------
if you wish use this method like a function then:
Create Tally table with one field PRIMARY KEY (1000 rows, starting from 1 with step 1)
Use code below to create function
Table Tally will be very useful for the split sting, clean string etc., currently this is
the best way to use instead fetch, xml and etc.
--------------------------------------------------------------------------------
CREATE FUNCTION [dbo].[StringClean](
#A VARCHAR(500))
RETURNS VARCHAR(500)
AS
BEGIN
DECLARE #B VARCHAR(500)
SET #B = ''
SELECT #B = #B + SUBSTRING(#A, t.N, 1)
FROM dbo.Tally t
WHERE t.N <= DATALENGTH(#A)
AND PATINDEX('[A-Za-z0-9 ]', SUBSTRING(#A, t.N, 1)) > 0
RETURN #B
END
-------------------------------------------------------------------------------
SELECT dbo.StringClean('This()*& is%%# **.>another one //&^&*$variant')
-------------------------------------------------------------------------------
DECLARE #Tally TABLE ( N INT )
DECLARE #i AS INT = 1
WHILE #i != 1000
BEGIN
INSERT INTO #Tally (N) VALUES (#i)
SET #i = #i + 1
END
--------------------------------------------------------------
DECLARE #String VARCHAR(500)
DECLARE #B VARCHAR(500) = ''
DECLARE #ReplacedChars VARCHAR(50) = '~!##$%^&*()_+}{][<>/.'
SET #String = 'This()*& is%%# **.>another one //&^&*$variant'
SELECT #B = #B + CASE WHEN CHARINDEX(SUBSTRING(#String, t.N, 1), #ReplacedChars) > 0 THEN '-'
ELSE SUBSTRING(#String, t.N, 1) END
FROM #Tally t
WHERE t.N <= DATALENGTH(#String)
SELECT #B
What is wrong with this function... The function intends to remove the specified leading characters from a given string. I know there is a patindex base solution to this which however doesn't consider spaces and all zero entries... but I want to know what is wrong with this one...
If I input "00012345" it should out put me "12345" however the output I'm getting is "0001234".. Why?
The test data is:
DECLARE #result varchar(max)
EXEC #result = TrimLeadingChar '00012345'
PRINT #result
The function code is:
CREATE FUNCTION TrimLeadingChar
(
#st AS Varchar(max),
#trimChar AS Varchar(1) = "0"
)
RETURNS Varchar(max)
AS
BEGIN
DECLARE #index int
DECLARE #temp Varchar(1)
SET #index = 0
if LEN(RTRIM(LTRIM(#st))) <= 1
return #st;
While(#index < LEN(#st))
BEGIN
set #temp = substring(#st,#index,1)
if #temp = #trimChar
SET #index = #index + 1
else
Break;
END
Return substring(#st,#index, LEN(#st))
END
GO
set #temp = substring(#st,#index+1,1)
instead of
set #temp = substring(#st,#index,1)
UPDATE:
OR you should set #index = 1 at first
DECLARE #index int
DECLARE #temp Varchar(1)
SET #index = 1
then
set #temp = substring(#st,#index,1)
Just for the sake of other users: Here is the working and complete solution function for SQL Server:
CREATE FUNCTION TrimBothEndsAndRemoveLeadingChar
(
#st AS VARCHAR(MAX),
#trimChar AS VARCHAR(1) = "0"
)
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE #index INT
DECLARE #temp VARCHAR(1)
IF #st IS NULL OR #trimChar IS NULL OR LEN(RTRIM(LTRIM(#st))) <= 0
RETURN #st
SET #st = LTRIM(RTRIM(#st))
SET #index = 1
WHILE(#index <= LEN(#st))
BEGIN
SET #temp = SUBSTRING(#st, #index, 1)
IF #temp = #trimChar
SET #index = #index + 1
ELSE
BREAK;
END
DECLARE #result VARCHAR(MAX)
IF #index = (LEN(#st) + 1)
SET #result = #st
ELSE
SET #result = SUBSTRING(#st, #index, LEN(#st) + 1)
RETURN #result
END
GO