Subject: Credit Card Encryption
Posted By: jemacc Post Date: 10/18/2006 6:45:58 PM
Hi all 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


Jaime E. Maccou
Reply By: SQLScott Reply Date: 10/18/2006 7:29:02 PM
Jamie,

How did you try and register the dll?  What error did you get when attempting to register it?

Scott Klein
Author - Professional SQL Server 2005 XML
http://www.wrox.com/WileyCDA/WroxTitle/productCd-0764597922.html
Reply By: jemacc Reply Date: 10/18/2006 8:25:31 PM
I was finally able to register it but. I still get and error " Invalid String"

Jaime E. Maccou
Reply By: jemacc Reply Date: 10/18/2006 8:55:23 PM
Hi All,

I was able to figure it out.  I made a mistake in registering the .dll Here is the site with all instructions.
http://www.dbazine.com/sql/sql-articles/larsen2


Thanks to Greg Larsen; it works like a charm!

Jaime E. Maccou
Reply By: joefawcett Reply Date: 10/19/2006 2:46:14 AM
Be careful of the following scenario which might hit you...
If you encrypt the data and then have to change the CAPICOM secret you have two main options, either keep a history of old secrets and when trying to decrypt use all in order until one finally gives a legitimate credit card number, or decrypt and re-encrypt all the numbers as you make the change so that there is only one secret in play at any one time.
I wrote the following routine to do that and it may help in future:

DECLARE @OldCipherSecret NVARCHAR(100)
DECLARE @NewCipherSecret NVARCHAR(100)
DECLARE @PlainText NVARCHAR(20)
DECLARE @CipherText NVARCHAR(1000)
DECLARE @CustomerId INT
DECLARE @PaymentCardNumber 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, PaymentCardNumber FROM tblCustomer WHERE DATALENGTH(PaymentCardNumber) > 100 
  FOR UPDATE OF PaymentCardNumber

  OPEN ToBeDecrypted

  FETCH NEXT FROM ToBeDecrypted 
  INTO @CustomerId, @PaymentCardNumber

  WHILE @@FETCH_STATUS = 0
  BEGIN
    EXEC sp_OAMethod @EncryptedData, 'Decrypt', NULL, @PaymentCardNumber
    EXEC sp_OAGetProperty @EncryptedData, 'Content', @PlainText OUTPUT 
    PRINT CAST(@CustomerId AS NVARCHAR(10)) + ': ' + @PlainText
    UPDATE tblCustomer
    SET PaymentCardNumber = @PlainText
    WHERE CURRENT OF ToBeDecrypted
    FETCH NEXT FROM ToBeDecrypted 
    INTO @CustomerId, @PaymentCardNumber
  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, PaymentCardNumber FROM tblCustomer WHERE PaymentCardNumber IS NOT NULL AND DATALENGTH(PaymentCardNumber) > 1
  FOR UPDATE OF PaymentCardNumber
  
  OPEN ToBeEncrypted

  FETCH NEXT FROM ToBeEncrypted 
  INTO @CustomerId, @PaymentCardNumber

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

  CLOSE ToBeEncrypted
  DEALLOCATE ToBeEncrypted
  EXEC sp_OADestroy @EncryptedData
END

This would be easier in SQL 2005 where you could make the decrypt/encrypt user defined functions written in .NET.


--

Joe (Microsoft MVP - XML)
Reply By: jemacc Reply Date: 10/19/2006 11:02:18 AM
using the script I have what would be your best advice for encrypting a table with columns. CustomerID, PaymentCardNumber.

Yours deletes the credit card number. I will like to encrypt the number stored and then decrypt when needed.


Jaime E. Maccou
Reply By: joefawcett Reply Date: 10/19/2006 11:55:50 AM
quote:
Originally posted by jemacc

using the script I have what would be your best advice for encrypting a table with columns. CustomerID, PaymentCardNumber.

Yours deletes the credit card number. I will like to encrypt the number stored and then decrypt when needed.


Jaime E. Maccou



If you mean my script then on my server it decrypts and then encrypts using the new secret.

--

Joe (Microsoft MVP - XML)
Reply By: jemacc Reply Date: 10/19/2006 12:34:33 PM
Yes your scripts.  I have changed the column and table name.  What I see it does is sets the credit card number to NULL.  Here is my table structure


CREATE TABLE [dbo].[customer_test] (
    [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 ,
    [CardNumber] [varchar] (50) NULL
) ON [PRIMARY]
GO


I will like to store the paymentcardnumber encrypted, then decrypted if necessary at another time.

Thanks




Jaime E. Maccou
Reply By: joefawcett Reply Date: 10/19/2006 1:57:44 PM
Sorry a mistake, I've edited the script, change @PlainText to @PaymentCardNumber in the encrypt section. But my script is designed to overcome the "secret" changing problem. There was already a script to encrypt in isolation.

--

Joe (Microsoft MVP - XML)
Reply By: jemacc Reply Date: 10/20/2006 5:50:31 AM
Thank you joefawcett, as you have been so help in this.

The encryption process has work and I have tried to decrypt using the cursor but was unsuccessful, can you walk me through this process.  Once again you have being great.



Jaime E. Maccou
Reply By: jemacc Reply Date: 10/20/2006 4:35:43 PM
How can I remove the history from your script. Once the number is inserted and encrypted I can decrypted using

select dbo.ufn_paymentCreditCardDecrypt(CardNumber, 'NewSecret')PmtCrdCardNumberDecrypted  from customer
I only want to encrypt the new inserted records.

your help will be greatly appreciated.

Jaime E. Maccou
Reply By: joefawcett Reply Date: 10/21/2006 3:22:44 AM
Do you want to encrypt one record as it is inserted or a batch in one go?

--

Joe (Microsoft MVP - XML)
Reply By: jemacc Reply Date: 10/21/2006 2:05:35 PM
I will like to insert each record when inserted.

Jaime E. Maccou
Reply By: jemacc Reply Date: 10/23/2006 8:45:07 PM
Hi All,

Here are my final results; try it and see if it works for you.


/*Download this file from here.  You will need it: http://www.microsoft.com/downloads/details.aspx?FamilyID=860ee43a-a843-462f-abb5-ff88ea5896f6&displaylang=en&Hash=nukHU0e%2bqo6NIplVN69Kvuc2%2fU8U4g5dSo5gNjFs7DPU%2fib6Ae3W9CcQrEwhZWPpHpvYi%2bP2slgP%2fvVc8ee5Fg%3d%3d

 

In addition, here is the site where I got it from: http://www.dbazine.com/sql/sql-articles/larsen2 the instruction is here as well.*/


USE [Northwind]
GO
/****** Object:  Table [dbo].[customers]    Script Date: 10/23/2006 20:27:52 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
    CREATE TABLE [dbo].[customers](
        [SubscriptionID] [int] IDENTITY(1,1) NOT NULL,
        [CustomerID] [int] NOT NULL,
        [NameOnCard] [varchar](255) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
        [CardType] [varchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
        [ExpirationDate] [datetime] NOT NULL,
        [AuthCode] [int] NOT NULL,
        [DateCreated] [datetime] NOT NULL CONSTRAINT [DF_customers_DateCreated]  DEFAULT (getdate()),
        [DateModified] [datetime] NOT NULL CONSTRAINT [DF_customers_DateModified]  DEFAULT (getdate()),
        [CardNumber] [varchar](250) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
        CONSTRAINT [PK_customers] PRIMARY KEY CLUSTERED
    (
        [SubscriptionID] ASC
    )WITH (PAD_INDEX  = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
    ) ON [PRIMARY]

    GO
    SET ANSI_PADDING OFF


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

--update all customer to decrypt CardNumber numbers using 'password'
    UPDATE customers
    SET CardNumber = dbo.CAPICOMDecrypt(CardNumber, 'password')
    WHERE len(CardNumber) > 20

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


    CREATE  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

    --Step 1

    --A.Create the encrypt function to call the com application CAPICOM

    CREATE  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

    --B. Create the Decrypt function to call the com application CAPICOM


    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

     

    --Step2
    --Create store procedure to update and encrypt credit card number
     
        Create procedure usp_EncryptCardNumber
        as
        UPDATE customers
        SET CardNumber = dbo.CAPICOMDecrypt(CardNumber, 'password')—Here we will decide best password to use
        WHERE len(CardNumber) < 20


    --Create store procedure to update and decrypt credit card number
     
        Create procedure usp_DecryptCardNumber
        as
        UPDATE customers
        SET CardNumber = dbo.CAPICOMDecrypt(CardNumber, 'password')—Must be the same as encrypted password
        WHERE len(CardNumber) > 20



thanks to all
Greg Larsen
joefawcett
snSQL



Jaime E. Maccou

Go to topic 51349

Return to index page 141
Return to index page 140
Return to index page 139
Return to index page 138
Return to index page 137
Return to index page 136
Return to index page 135
Return to index page 134
Return to index page 133
Return to index page 132