Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 SQL Server 2000 Forums
 Transact-SQL (2000)
 Credit Card Encryption

Author  Topic 

jemacc
Starting Member

42 Posts

Posted - 2006-10-18 : 16:37:37
Hi all,

Sorry if I posted this twice but I could not find my original post.

I am trying to encrypt and decrypted credit card information using the following script created by Greg Larsen. I have install the capicom.dll but I could not register it. I can call other com objects but I cannot with the capicom. if any off you can offer some assistance. Please let me know. Here is the script.

Declare @rc int
Declare @returnval int
DECLARE @object int
DECLARE @Encrypted_CreditCard varchar(4000)
DECLARE @Decrypted_CreditCard varchar(4000)
Declare @Method_call varchar(4000)
Declare @Secret_code varchar(1000)
declare @src varchar(255)
declare @desc varchar(255)

-- Password for Encryption
set @secret_code = 'super secret code'


set @Decrypted_CreditCard = '1234 5678 9012 3456'

-- Encrypt
EXEC @rc = sp_OACreate 'CAPICOM.EncryptedData', @object OUT
if @rc <> 0
begin
exec sp_oageterrorinfo @object, @src out, @desc out
select hr=convert(varbinary(4),@rc), source=@src, description=@desc
return
end

EXEC @rc = sp_OASetProperty @Object, 'Algorithm.Name', 3 -- 3DES
if @rc <> 0
begin
exec sp_oageterrorinfo @object, @src out, @desc out
select hr=convert(varbinary(4),@rc), source=@src, description=@desc
return
end

EXEC @rc = sp_OASetProperty @Object, 'Algorithm.KeyLength', 3 -- 128 bit key
if @rc <> 0
begin
exec sp_oageterrorinfo @object, @src out, @desc out
select hr=convert(varbinary(4),@rc), source=@src, description=@desc
return
end

set @method_call = 'SetSecret("' + @Secret_code + '")'
EXEC @rc=sp_OAMethod @Object, @method_call
if @rc <> 0
begin
exec sp_oageterrorinfo @object, @src out, @desc out
select hr=convert(varbinary(4),@rc), source=@src, description=@desc
return
end

EXEC @rc=sp_OASetProperty @Object, 'Content',@Decrypted_CreditCard
if @rc <> 0
begin
exec sp_oageterrorinfo @object, @src out, @desc out
select hr=convert(varbinary(4),@rc), source=@src, description=@desc
return
end

EXEC @rc=sp_OAMethod @Object, 'Encrypt(0)', @Encrypted_CreditCard out
if @rc <> 0
begin
exec sp_oageterrorinfo @object, @src out, @desc out
select hr=convert(varbinary(4),@rc), source=@src, description=@desc
return
end

-- Print encrypted text
print 'Encrypted Credit Card Info = ' + @Encrypted_CreditCard

-- Decrypt
EXEC @rc = sp_OACreate 'CAPICOM.EncryptedData', @object OUT
if @rc <> 0
begin
exec sp_oageterrorinfo @object, @src out, @desc out
select hr=convert(varbinary(4),@rc), source=@src, description=@desc
return
end

set @method_call = 'SetSecret("' + @Secret_code + '")'
EXEC @rc=sp_OAMethod @Object, @method_call
if @rc <> 0
begin
exec sp_oageterrorinfo @object, @src out, @desc out
select hr=convert(varbinary(4),@rc), source=@src, description=@desc
return

end

set @Decrypted_CreditCard = 'garbage'
set @method_call = 'Decrypt("' + @Encrypted_CreditCard + '")'
EXEC @rc=sp_OAMethod @Object,@method_call
if @rc <> 0
begin
exec sp_oageterrorinfo @object, @src out, @desc out
select hr=convert(varbinary(4),@rc), source=@src, description=@desc
return
end

EXEC @rc=sp_OAGetProperty @Object, 'Content',@Decrypted_CreditCard out
if @rc <> 0
begin
exec sp_oageterrorinfo @object, @src out, @desc out
select hr=convert(varbinary(4),@rc), source=@src, description=@desc
return
end

-- Print decrypted text
print ' '
print 'Decrypted Create Card Info = ' + @Decrypted_CreditCard

-- Destroy object
exec @rc = sp_OADestroy @object
if @rc <> 0
begin
exec sp_OAGetErrorInfo @object
return
end



Thanks in Advance


Jaime E. Maccou

snSQL
Master Smack Fu Yak Hacker

1837 Posts

Posted - 2006-10-18 : 17:50:02
The script is useless if you can't register the component. Here's a good article (maybe the one you already saw)
http://www.dbazine.com/sql/sql-articles/larsen2

And this info on installing and registering the component
quote:
How to Install CAPICOM
It is a fairly easy process to install CAPICOM. CAPICOM consists of a single dll, capicom.dll, that must be placed in your system32 directory, then registered. You can download the CAPICOM dll from the Microsoft Download Center.
Once you have downloaded, and extracted the CAPICOM package, read the README.txt for an explanation of how to install CAPICOM. To call CAPICOM from TSQL, you will need to install CAPICOM on the SQL Server box that will be running the TSQL that calls CAPICOM.


If you can't register the component you probably don't have permissions to do so?
Go to Top of Page

jemacc
Starting Member

42 Posts

Posted - 2006-10-19 : 12:57:04
okay I was able to register the dll. my problem is how to I encrypt the table with the credit card using the script.

the table name is customer with the following columns

CREATE TABLE [dbo].[customer] (
[SubscriptionID] [int] IDENTITY (1, 1) NOT NULL ,
[CustomerID] [int] NOT NULL ,
[NameOnCard] [varchar] (255) NOT NULL ,
[CardType] [varchar] (50) NOT NULL ,
[ExpirationDate] [datetime] NOT NULL ,
[AuthCode] [int] NOT NULL ,
[DateCreated] [datetime] NOT NULL ,
[DateModified] [datetime] NOT NULL ,
[PaymentCardNumber] [varchar] (100)NOT NULL
) ON [PRIMARY]
GO

Go to Top of Page

snSQL
Master Smack Fu Yak Hacker

1837 Posts

Posted - 2006-10-19 : 13:38:19
Before looking at implementing this, there are a couple of things to ask/consider.

1. You said "my problem is how to I encrypt the table with the credit card using the script." - you don't really want to encrypt the whole table right, just the PaymentCardNumber column?

2. What kind of app is going to use the data? If you do the encryption/decryption on the SQL Server then you are securing the data, but given that you will need to decrypt it on the way out, the decrypted data will be available to any application that can query the database, and the decrypted data will travel from the SQL Server to the app or web server - is that OK? If not you may be better off implementing the encryption/decryption directly in the application, so that you are always sending/receiving the already encrypted data to SQL Server and only decrypting in the app.

3. The encryption is going to be based on a password or some other piece of secret data, where are you going to store that - if you put it in the stored proc or function that encrypts/decrypts data it's not very secure, otherwise your app could provide it with every query, but you'll have to ensure its secure then too.

4. SQL Server 2005 implements a very nice solution to this where you can base the encryption/decryption on certificates - is 2005 an option because if so, then you're probably better off doing that.

So, think about all these then we can look at whether you want to create functions based on CAPICOM to do the encryption and decryption.
Go to Top of Page

jemacc
Starting Member

42 Posts

Posted - 2006-10-19 : 14:08:57
1. Just the PaymentCardNumber
2. I will be encrypting on the server. The app will not be accessing that data; only when it writes to it.
3. for now it will be on proc. when I get it working it will be called from somewhere else more secure.
4. Yes, SQL 2005 took care of this but right now it is not a choice.

Thanks for your quick responce.
Go to Top of Page

snSQL
Master Smack Fu Yak Hacker

1837 Posts

Posted - 2006-10-19 : 15:21:22
OK then, here's what you need. First two functions that use the CAPICOM component to encrypt and decrypt a given varchar value using a given secret/password. Then two examples of using these functions, one just calls them with variables, the next one creates a temporary table and shows inserting encrypted data and then reading that data, either encrypted or decrypted.

For anyone else reading this, you'll need to get the Microsoft CAPICOM component and install it on your SQL Server machine before this will work. Get it here
http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=860EE43A-A843-462F-ABB5-FF88EA5896F6

All of this code provided as is, with no warranty, guarantee, or any other type of liability on my part!!

If you encrypt data and lose the password - YOU CANNOT decrypt it, so don't ask how to do that!!

--Create the crypto functions
--Thanks to Greg Larsen for the original code that these functions are based on
--see http://www.dbazine.com/sql/sql-articles/larsen2
--USE AT YOUR OWN RISK
CREATE ALTER FUNCTION dbo.CAPICOMEncrypt
(@TextToEncrypt varchar(4000), @Secret varchar(1000))
RETURNS varchar(4000)
AS
BEGIN
DECLARE @EncryptedText varchar(4000)

DECLARE @rc int
DECLARE @object int
DECLARE @Method_call varchar(4000)

-- Encrypt
EXEC @rc = sp_OACreate 'CAPICOM.EncryptedData', @object OUT
if @rc <> 0
begin
return NULL
end

EXEC @rc = sp_OASetProperty @Object, 'Algorithm.Name', 3 -- 3DES
if @rc <> 0
begin
return NULL
end

EXEC @rc = sp_OASetProperty @Object, 'Algorithm.KeyLength', 3 -- 128 bit key
if @rc <> 0
begin
return NULL
end

set @method_call = 'SetSecret("' + @Secret + '")'
EXEC @rc=sp_OAMethod @Object, @method_call
if @rc <> 0
begin
return NULL
end

EXEC @rc=sp_OASetProperty @Object, 'Content',@TextToEncrypt
if @rc <> 0
begin
return NULL
end

EXEC @rc=sp_OAMethod @Object, 'Encrypt(0)', @EncryptedText out
if @rc <> 0
begin
return NULL
end

-- Destroy object
exec @rc = sp_OADestroy @object

return @EncryptedText
END

CREATE FUNCTION dbo.CAPICOMDecrypt
(@TextToDecrypt varchar(4000), @Secret varchar(1000))
RETURNS varchar(4000)
AS
BEGIN
DECLARE @DecryptedText varchar(4000)

DECLARE @rc int
DECLARE @object int
DECLARE @Method_call varchar(4000)

-- Decrypt
EXEC @rc = sp_OACreate 'CAPICOM.EncryptedData', @object OUT
if @rc <> 0
begin
return NULL
end

set @method_call = 'SetSecret("' + @Secret + '")'
EXEC @rc=sp_OAMethod @Object, @method_call
if @rc <> 0
begin
return NULL
end

set @method_call = 'Decrypt("' + @TextToDecrypt + '")'
EXEC @rc=sp_OAMethod @Object,@method_call
if @rc <> 0
begin
return NULL
end

EXEC @rc=sp_OAGetProperty @Object, 'Content',@DecryptedText out
if @rc <> 0
begin
return NULL
end

-- Destroy object
exec @rc = sp_OADestroy @object

return @DecryptedText
END


--Example of calling the crypto functions
DECLARE @secret_code varchar(1000)
DECLARE @Decrypted_CreditCard varchar(4000)
DECLARE @Encrypted_CreditCard varchar(4000)
set @secret_code = 'li3j2 4liuj3 lighgh4 lijoil4j o43i uj43'
set @Decrypted_CreditCard = '1234 5678 9012 3456'
select @Encrypted_CreditCard = dbo.CAPICOMEncrypt(@Decrypted_CreditCard, @secret_code)
select @Decrypted_CreditCard Original
select @Encrypted_CreditCard Encrypted
select dbo.CAPICOMDecrypt(@Encrypted_CreditCard, @secret_code) Decrypted


--Example of using the crypto functions on a table column
create table #TestEncryption
(EncryptedValue varchar(4000))

insert #TestEncryption
select dbo.CAPICOMEncrypt('1234 5678 9012 3456', 'my password') union all
select dbo.CAPICOMEncrypt('1234 5678 9012 3456', 'new password') union all
select dbo.CAPICOMEncrypt('1234 5678 9012 3456', 'your password') union all
select dbo.CAPICOMEncrypt('1234 5678 9012 3456', 'my password')

select EncryptedValue from #TestEncryption

select dbo.CAPICOMDecrypt(EncryptedValue, 'my password') DecryptedValue from #TestEncryption
select dbo.CAPICOMDecrypt(EncryptedValue, 'new password') DecryptedValue from #TestEncryption
select dbo.CAPICOMDecrypt(EncryptedValue, 'your password') DecryptedValue from #TestEncryption
Go to Top of Page

jemacc
Starting Member

42 Posts

Posted - 2006-10-23 : 16:37:48
I taken your function and I able to get this working. The problem I am having is: when I encrypted the card number and run the store procedure again it inserts another encryption key next to the original one. How can I prevent this with the store procedure listed below. All I want to prevent is building a history of encryption keys. I have had help with it but I cannot take further.

SET QUOTED_IDENTIFIER ON
GO
SET ANSI_NULLS ON
GO

/****** Object: Stored Procedure dbo.usp_PaymentCreditCardNumber Script Date: 10/20/2006 3:18:26 PM ******/
ALTER proc usp_PaymentCreditCardNumber
as
DECLARE @OldCipherSecret NVARCHAR(100)
DECLARE @NewCipherSecret NVARCHAR(100)
DECLARE @PlainText NVARCHAR(20)
DECLARE @CipherText NVARCHAR(1000)
DECLARE @CustomerId INT
DECLARE @CardNumber NVARCHAR(1000)

DECLARE @HResult INT
DECLARE @EncryptedData INT
DECLARE @src varchar(255), @desc varchar(255)

DECLARE @LoopIndex INT


SET @OldCipherSecret = 'OldSecret'
SET @NewCipherSecret = 'NewSecret'

DECLARE @CAPICOM_ENCRYPTION_KEY_LENGTH_MAXIMUM INT
SET @CAPICOM_ENCRYPTION_KEY_LENGTH_MAXIMUM = 0
DECLARE @CAPICOM_ENCRYPTION_ALGORITHM_3DES INT
SET @CAPICOM_ENCRYPTION_ALGORITHM_3DES = 3

EXEC @HResult = sp_OACreate 'CAPICOM.EncryptedData', @EncryptedData OUT
IF @HResult <> 0
BEGIN
EXEC sp_OAGetErrorInfo @EncryptedData, @src OUT, @desc OUT
SELECT hr = convert(varbinary(4), @HResult), Source = @src, Description = @desc
RETURN
END
ELSE
BEGIN
EXEC sp_OAMethod @EncryptedData, 'SetSecret', NULL, @OldCipherSecret
DECLARE ToBeDecrypted CURSOR
LOCAL
FORWARD_ONLY
-- The SQL will need tailoring to your own table. We only want numbers that have been encrypted, that's why the length test is there.
FOR SELECT CustomerId, CardNumber FROM stsubscriptions_test WHERE DATALENGTH(CardNumber) > 100
FOR UPDATE OF CardNumber

OPEN ToBeDecrypted

FETCH NEXT FROM ToBeDecrypted
INTO @CustomerId, @CardNumber

WHILE @@FETCH_STATUS = 0
BEGIN
EXEC sp_OAMethod @EncryptedData, 'Decrypt', NULL, @CardNumber
EXEC sp_OAGetProperty @EncryptedData, 'Content', @CardNumber OUTPUT --changed from @plaintext
PRINT CAST(@CustomerId AS NVARCHAR(10)) + ': ' + @CardNumber -- changed from @plaintext
UPDATE stsubscriptions
SET CardNumber = @CardNumber
WHERE CURRENT OF ToBeDecrypted
FETCH NEXT FROM ToBeDecrypted
INTO @CustomerId, @CardNumber
END

CLOSE ToBeDecrypted
DEALLOCATE ToBeDecrypted

EXEC sp_OASetProperty @EncryptedData, 'Algorithm.Name', @CAPICOM_ENCRYPTION_ALGORITHM_3DES
EXEC sp_OASetProperty @EncryptedData, 'Algorithm.KeyLength', @CAPICOM_ENCRYPTION_KEY_LENGTH_MAXIMUM
EXEC sp_OAMethod @EncryptedData, 'SetSecret', NULL, @NewCipherSecret

DECLARE ToBeEncrypted CURSOR
LOCAL
FORWARD_ONLY
FOR SELECT CustomerId, CardNumber FROM stsubscriptions WHERE CardNumber IS NOT NULL AND DATALENGTH(CardNumber) > 1
FOR UPDATE OF CardNumber

OPEN ToBeEncrypted

FETCH NEXT FROM ToBeEncrypted
INTO @CustomerId, @CardNumber

WHILE @@FETCH_STATUS = 0
BEGIN
EXEC sp_OASetProperty @EncryptedData, 'Content', @CardNumber
EXEC sp_OAMethod @EncryptedData, 'Encrypt', @CipherText OUTPUT
UPDATE stsubscriptions_test
SET CardNumber = @CipherText
WHERE CURRENT OF ToBeEncrypted
FETCH NEXT FROM ToBeEncrypted
INTO @CustomerId, @CardNumber
END

CLOSE ToBeEncrypted
DEALLOCATE ToBeEncrypted
EXEC sp_OADestroy @EncryptedData
END

GO

SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO



I and still using the same table structure

CREATE TABLE [dbo].[customer] (
[SubscriptionID] [int] IDENTITY (1, 1) NOT NULL ,
[CustomerID] [int] NOT NULL ,
[NameOnCard] [varchar] (255) NOT NULL ,
[CardType] [varchar] (50) NOT NULL ,
[ExpirationDate] [datetime] NOT NULL ,
[AuthCode] [int] NOT NULL ,
[DateCreated] [datetime] NOT NULL ,
[DateModified] [datetime] NOT NULL ,
[PaymentCardNumber] [varchar] (100)NOT NULL
) ON [PRIMARY]
GO

Go to Top of Page

snSQL
Master Smack Fu Yak Hacker

1837 Posts

Posted - 2006-10-23 : 16:54:34
What do you want this to do? If you want to decrypt the current encrypted values and replace them with new encrypted ones, just run an UPDATE using the functions I already gave you - there is absolutely no need for a cursor.
Go to Top of Page

jemacc
Starting Member

42 Posts

Posted - 2006-10-23 : 17:42:39
I will like to decrypt the current value and stored once.
Go to Top of Page

snSQL
Master Smack Fu Yak Hacker

1837 Posts

Posted - 2006-10-23 : 18:04:17
Sorry, but I don't understand, "store once" - store where?

Here's some guesses

--update all customers to encrypt cc numbers using 'my password'
UPDATE customer
SET PaymentCardNumber = dbo.CAPICOMEncrypt(PaymentCardNumber, 'my password')
WHERE len(PaymentCardNumber) < 20

--update all customers to decrypt cc numbers using 'my password'
UPDATE customer
SET PaymentCardNumber = dbo.CAPICOMDecrypt(PaymentCardNumber, 'my password')
WHERE len(PaymentCardNumber) < 20

--update all customers to encrypt cc numbers using 'new password', that were encrypted using 'my password'
UPDATE customer
SET PaymentCardNumber = dbo.CAPICOMEncrypt(dbo.CAPICOMDecrypt(PaymentCardNumber, 'my password'), 'new password')
WHERE len(PaymentCardNumber) < 20



Go to Top of Page

jemacc
Starting Member

42 Posts

Posted - 2006-10-23 : 18:47:45
sorry about that.

I will like to update the card number to an encryption value when the data is insert in the table. Once the update occurs I do not want touch that record again. The card number will always be stored in the database encrypted.

I will look at your recommendation.
Go to Top of Page

jemacc
Starting Member

42 Posts

Posted - 2006-10-23 : 19:05:47
Thank you so much for your recommendation. Every thing works great. I really appreciate the time you have taken to look at this.

The Only change I made was to the second update

it was

UPDATE stsubscriptions
SET PaymentCardNumber = dbo.CAPICOMDecrypt(PaymentCardNumber, 'NewSecret')
WHERE len(PaymentCardNumber) < 20

and I changed it to
UPDATE stsubscriptions
SET PaymentCardNumber = dbo.CAPICOMDecrypt(PaymentCardNumber, 'NewSecret')
WHERE len(PaymentCardNumber) > 20


Go to Top of Page
   

- Advertisement -