Not possible to update value of encrypted column - sql-server

I have used Always Encrypted to encrypt values in a column. My connection string looks like this (everything is working fine and the client is able to decrypt the values):
Driver={ODBC Driver 13 for SQL Server};Server=10.10.10.1\INST2;Database=test;Trusted_Connection=yes;ColumnEncryption=Enabled;
Then I try to update one of the encrypted values using the following code:
ALTER PROCEDURE dbo.usp_SecurityUsers_GetDetails
(
#Firstname NVARCHAR(128)
)
AS
BEGIN;
UPDATE SecurityUsers
SET FirstName = #Firstname
WHERE login = 'system.export.service'
SELECT Login, FirstName, LastName
FROM SecurityUsers
END;
the SP is called like this:
Set cmd = Server.CreateObject("ADODB.Command")
Set cmd.ActiveConnection = conn
cmd.NamedParameters = True
cmd.CommandText = "[dbo].[usp_SecurityUsers_GetDetails]"
cmd.Parameters.Append cmd.CreateParameter("#Firstname", adLongVarWChar, adParamInput, 128, "system_text")
cmd.CommandType = adCmdStoredProc
Set recordSet = cmd.Execute
But I get the following error:
[Microsoft][ODBC Driver 13 for SQL Server][SQL Server]Encryption
scheme mismatch for columns/variables '#P1'. The encryption scheme for
the columns/variables is (encryption_type = 'PLAINTEXT') and the
expression near line '1' expects it to be (encryption_type =
'RANDOMIZED', encryption_algorithm_name =
'AEAD_AES_256_CBC_HMAC_SHA_256', column_encryption_key_name =
'CEK_SecurityLevelNormal', column_encryption_key_database_name =
'test') (or weaker).
It's very strange, because I am able to update the field if the code is not encapsulated in stored procedure and directly executed in the SQL Server Management Studio.
Also, calling the SP directly in the SSMS works.
EDIT:
Updating to .net 4.6.3 does not change anything. What I am seeing is, if I change the connection string ColumnEncryption=Enabled; to Column Encryption Setting=Enabled;, I am getting different error:
[Microsoft][ODBC Driver 13 for SQL Server][SQL Server]Operand type
clash: ntext is incompatible with nvarchar(128) encrypted with
(encryption_type = 'RANDOMIZED', encryption_algorithm_name =
'AEAD_AES_256_CBC_HMAC_SHA_256', column_encryption_key_name =
'CEK_SecurityLevelNormal', column_encryption_key_database_name =
'test')

I was feeling that the issue must be in the way I am trying to modify the data as I am able to read it. And it was so lame.
In my stored procedure I have nvarchar(256). In the ASP I am using adLongVarChar instead adVarWChar. The error seems more reasonable now:
Encryption scheme mismatch for columns/variables '#P1'.
The conclusion is one is able to read encrypted data and modify it using ADO and ODBC driver.

Related

SQL Server Always Encrypted with the JDBC not working

I'm working on an enterprise application and for some security reason I have to enable Always Encrypted. DBA and Production IT team did what needed from their side:
I can generate this script from using SQL server management studio under security -> always encrypted key
USE [DE_NAME]
/****** Object: ColumnMasterKey [*****] Script Date: 23/12/2022 17:30:17 ******/
CREATE COLUMN MASTER KEY [*****]
WITH
(
KEY_STORE_PROVIDER_NAME = N'AZURE_KEY_VAULT',
KEY_PATH = N'https://xxxxxxxxx.vault.azure.net/keys/******/####'
)
GO
What mean that Alaways Encrypted is configured in the DB?
Production IT team :
Create Keyvault
Create a Service Principal/application Registration in Azure AD
register Name(clientId) and secret in KeyPass
At keyvault level added role Assignement
From my side, I added the conf as descripted in Microsoft documentation:
https://learn.microsoft.com/en-us/sql/connect/jdbc/using-always-encrypted-with-the-jdbc-driver?view=sql-server-ver16
Application inf :
Spring boot
Java 8
mssql diver : 9.2.1.jre8
I added mssql-jdbc_auth-9.2.1.x64.dll and sqljdbc_auth.dll to -Djava.library.path
Test code :
try (Connection sourceConnection = DriverManager.getConnection("jdbc:sqlserver://server;DatabaseName=db_name;encrypt=true;trustServerCertificate=true;integratedSecurity=true;columnEncryptionSetting=Enabled;keyVaultProviderClientId=xxxxxxxx-xxxx-xxxx-xxxx-xx71xx1axxd3;keyVaultProviderClientKey=XXX7X~XXXMv21mXqXxX4FBi7XoXmxxxXDSZXw")) {
PreparedStatement stmt = sourceConnection.prepareStatement("INSERT INTO Table_name(id, aaa, bbb, ccc, ddd, eee) VALUES (?, ?, ?, ?, ?, ?)");
stmt.setInt(1, 999999);
stmt.setString(2, "local_test_0");
stmt.setInt(3, 989898);
stmt.setString(4, "local_test_0");
stmt.setString(5, "local_test_0");
stmt.setString(6, "local_test_0");//col encrypted
stmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
When I run this code I get the following error message :
com.microsoft.sqlserver.jdbc.SQLServerException: Operand type clash: varchar(12) encrypted with (encryption_type = 'DETERMINISTIC', encryption_algorithm_name = 'AEAD_AES_256_CBC_HMAC_SHA_256', column_encryption_key_name = 'CEK-XXXX-Shared-XX-XX', column_encryption_key_database_name = 'XXXX') collation_name = 'SQL_Latin1_General_CP1_CI_AS' is incompatible with nvarchar(132) encrypted with (encryption_type = 'DETERMINISTIC', encryption_algorithm_name = 'AEAD_AES_256_CBC_HMAC_SHA_256', column_encryption_key_name = 'CEK-XXXX-Shared-XX-XX', column_encryption_key_database_name = 'XXXX')
at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java:262)
at com.microsoft.sqlserver.jdbc.SQLServerStatement.getNextResult(SQLServerStatement.java:1632)
at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.doExecutePreparedStatement(SQLServerPreparedStatement.java:602)
at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement$PrepStmtExecCmd.doExecute(SQLServerPreparedStatement.java:524)
It's like the driver didn't encrypt data before inserting it.
Could you help please ?

ASP parameters to call a stored procedure in SQL Server

I try call this stored procedure in SQL Server that inserts data.
I have this:
CREATE PROCEDURE [dbo].[AddUser]
#user_id bigint,
#user_name varchar(20)
AS
BEGIN
INSERT INTO [users] ([id], [name])
VALUES (#user_id, #user_name)
END
and I have this ASP code:
<%
Const adCmdStoredProc = 4
Const adBigInt = 20
Const adParamInput = 1
Const adVarChar = 200
Set conn = Server.CreateObject("ADODB.Connection")
connectionstring = "Provider=SQLOLEDB.1;Password=***********;Persist Security Info=True;User ID=sa;Initial Catalog=Test;Data Source=AREAWEB2-PC"
conn.Open connectionstring
Set cmd = Server.CreateObject("ADODB.Command")
Set cmd.ActiveConnection = conn
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "{call AddUser (?,?)}"
frm_id = 1
frm_name = "Carlos"
Set prmUserId = cmd.CreateParameter("#user_id", adBigInt, adParamInput, 0, frm_id)
Set prmUserName = cmd.CreateParameter("#user_name", adVarChar, adParamInput, 20, frm_name)
Cmd.Parameters.Append prmUserId
Cmd.Parameters.Append prmUserName
Set rs = cmd.Execute
%>
But I get this error message:
Microsoft OLE DB Provider for SQL Server error '80040e10'
What is wrong ?
If you Google the error code 80040e10 it becomes apparent quickly that the issue is one of the following to do with your parameter definitions;
From Why do I get 80040E10 errors?
Microsoft OLE DB Provider for SQL Server error '80040e10'
Procedure '' expects parameter '', which was not supplied.
Your issue is likely due to passing a 0 size in your #user_id parameter, as all parameters have to pass a maximum size either using .CreateParameter() or before appending a parameter to the collection using .Size property.
Update:
As the OP has pointed out the issue is actually due to the wrong CommandType property value being set.
Thought it would be worth expanding the answer to explain why. The reason is the CommandType in the OP's example is set to adCmdStoredProc but the .CommandText property is not set to a Stored Procedure name, the easiest way to correct this (instead of removing the .CommandType) is to change the .CommandText as follows;
cmd.CommandText = "AddUser"
The other option is to change the .CommandType to adCmdText which will accept the format {call AddUser (?,?)}.
cmd.CommandType = adCmdText
Internally ADO uses adCmdText for the adCmdStoredProc CommandTypeEnum as the .CommmandText will get changed to the format {call AddUser (?,?)}, the difference is you cannot use this form yourself unless you specify .CommandType = adCmdText. There is no additional benefits to using either one, but in my opinion adCmdStoredProc just simplifies the calls and hides the nuts and bolts from you.
The code fails because I have these incorrect:
cmd.CommandType = adCmdStoredProc
Removing it, works.

[Microsoft][ODBC SQL Server Driver][SQL Server]Changed database context to 'dbname'

I have a form with a textarea field that has about 250k of html in it. I'm posting it to an ASP page that is calling a stored procedure and inserting the text into a table. The field type and stored procedure parameter are both varchar(max). This page works fine when I post smaller html sets but give me the error.
[Microsoft][ODBC SQL Server Driver][SQL Server]Changed database context to 'dbname'
when I use large HTML data sets. Any ideas what the problem is?
ASP
Dim addRS, addCMD
Set addCMD = Server.CreateObject("ADODB.Command")
addCMD.ActiveConnection = objconn
ddCMD.CommandType = adCmdStoredProc
addCMD.CommandText = "insert_emailjob"
addCMD.Parameters.Append(addCMD.CreateParameter("emailbody",adlongVarchar,adParamInput,10000000,emailbody))
set addRS = server.createobject("ADODB.Recordset")
addRS.CursorLocation = adUseClient
addRS.open addCMD
PROC
ALTER PROCEDURE [dbo].[insert_emailjob]
#emailbody as varchar(max)
AS
BEGIN
INSERT INTO emails (emailbody) VALUES (#emailbody)
END
there is a default iis limit of uploading more than 100k in one form field
http://technet.microsoft.com/en-us/library/aa996475(v=exchg.80)

Microsoft OLE DB Provider for SQL Server error '80040e14'

Stored procedure, and using ADO to connect, i'm having problems with the quotes however..
x = "text'"
If instr(x,"'") then x=replace(x,"'","''")
'x = "text''" at this point
Set Rs = Server.Createobject("adodb.recordset")
Rs.Open "Select_SP #name='" & x & "'"
I thought i was doing this right.. But I guess not, because i'm getting this error:
Microsoft OLE DB Provider for SQL Server error '80040e14'
SELECT ID from Table where Name='text''
Shouldn't it be
Name = 'text'''
Why isn't SQL recognizing the double quotes using ADO?
The Select_SP Uses something like this:
SET #sql = 'SELECT ID from Table where Name='''+#name+''''
Exec(#sql)
Do I have this SP written correctly?
The short answer is, don't call procedures the way you're doing it. Use a Command instead. This is from memory, since I don't have a Windows system in front of me at the moment, but it should work:
Dim cmd
Set cmd = Server.CreateObject("ADODB.Command")
Set Cmd.ActiveConnection = myConnectionVariableHere
cmd.CommandType = adCmdStoredProc
cmd.CommandText = "Select_SP"
'Note: if the above two lines don't work, replace them with the following
'cmd.CommandType = adCmdText
'cmd.CommandText = "Select_CP #name=?"
cmd.Parameters.Append cmd.CreateParameter("name", adVarChar, adParamInput, len(x), x)
Rs.Open cmd
Now, all that said, I can't tell you why your procedure is giving that particular output since you're not showing us the code for it. But I'm fairly certain ADO isn't going to convert a pair of single quotes into a double quote - not sure why you'd expect it to.
Edit after seeing the OP's edit. Don't execute SQL that way unless you absolutely have to. You will only give yourself grief. I don't know what database you're using and that procedure syntax doesn't look familiar, but in Oracle you could write something like:
PROCEDURE sql_test(MyName IN VARCHAR2, MyCursor OUT SYS_REFCURSOR) IS
BEGIN
OPEN MyCursor FOR SELECT id FROM some_table WHERE name = MyName;
END;

Issue with parameters assignment in ADODB Command

We use an ADODB command to perform queries (call stored procedures) on our SQL Server 2000 database, using SQLOLEDB driver.
On one of our server we have issues when we assign parameter values. Here's how it goes :
Set conn = Server.CreateObject("ADODB.Connection")
conn.CommandTimeout = 0
conn.ConnectionTimeout = 15
conn.Mode = 1 ' adModeRead
conn.ConnectionString = connectionString ' SQLOLEDB
conn.CursorLocation = 3 ' adUseClient
conn.Open
Set cmd = Server.CreateObject("ADODB.Command")
cmd.ActiveConnection = conn ' previously created connection
cmd.CommandType = 4 ' adCmdStoredProc
cmd.CommandText = "dbo.StoredProcedureName"
cmd.CommandTimeout = 0
cmd.Parameters.Refresh ' Get the parameters info from the database
' Pseudo code here :
Foreach cmd.parameters
cmd.parameters(index).value = somevalue
Next
This code actually works on our production server, but for some odd reasons it does not work on our dev server and generates this error : Application uses a value of the wrong type for the current operation when we assign a value (which contain a decimal part, let's say a string like "12.75") to a datatype money parameter.
The code is exactly the same on dev and on prod. Do this could have something to do with regional settings, language of ADODB, language of thr OS or some other Windows component ? Because it is classic ASP code we already looked at Session.LCID but they are the same on both servers, so we are clueless right now.
Have any idea ?
Is it possible the dev server is set up with a different base language or other regional settings? Just for kicks try assigning the value 12,75 instead of 12.75.
From the MS KB
Parameters.refresh will fail in some situations or return
information that is not entirely correct. Parameters.refresh is
particularly vulnerable when used on ASP pages.
There is a known issue regarding parameter direction when using Parameters.refresh from Classic ASP. MS guidance is to manually generate the parameters.
http://support.microsoft.com/kb/183008
http://support.microsoft.com/kb/174223

Resources