Skip to content

Always Encrypted | Align reads of CekMdVersion and EkValueCount with TDS specification#4240

Merged
apoorvdeshmukh merged 4 commits into
dotnet:mainfrom
edwardneal:perf/read-ulong-keymdversion
May 20, 2026
Merged

Always Encrypted | Align reads of CekMdVersion and EkValueCount with TDS specification#4240
apoorvdeshmukh merged 4 commits into
dotnet:mainfrom
edwardneal:perf/read-ulong-keymdversion

Conversation

@edwardneal
Copy link
Copy Markdown
Contributor

Description

SqlClient contains a the structure of a table of CIPHER_INFO entries. The table is represented as a SqlTceCipherInfoTable and each entry is represented as a SqlTceCipherInfoEntry instance. This corresponds to an EK_INFO structure in the TDS specification. A table of EK_INFO entries appears in the COLMETADATA structure.

In the TDS specification, the EK_INFO structure's CekMdVersion field is defined as a ULONGLONG and the COLMETADATA structure's EkValueCount field is defined as a USHORT.

This PR aligns SqlClient with these type definitions. The cekMdVersion field on SqlTceCipherInfoTable is currently defined as an eight byte array, and is redefined as a ulong. This eliminates one allocation, so it technically improves performance (marginally.) The tableSize is currently defined a short, and is redefined as a ushort. This is a correctness improvement and a bugfix in an edge case where the same column is encrypted with an unreasonably large number of encryption keys.

One slight edge case lies in SqlCommand.Encryption.cs, where we read the CekMdVersion from a byte array as a little-endian ulong. This byte array is the result of reading the column_encryption_key_metadata_version column from the first result set of sp_describe_parameter_encryption, and this column is declared as binary(8). I've used BinaryPrimitives.ReadUInt64LittleEndian to bridge this gap between the stored procedure's result set and the TDS specification.

Issues

None.

Testing

Automated Always Encrypted tests continue to pass.

@edwardneal edwardneal requested a review from a team as a code owner April 25, 2026 14:37
@github-project-automation github-project-automation Bot moved this to To triage in SqlClient Board Apr 25, 2026
@cheenamalhotra cheenamalhotra added this to the 7.1.0-preview2 milestone May 8, 2026
@cheenamalhotra cheenamalhotra moved this from To triage to In review in SqlClient Board May 8, 2026
@cheenamalhotra
Copy link
Copy Markdown
Member

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 2 pipeline(s).

Test code uses reflection to call SqlTceCipherInfoEntry.Add
@apoorvdeshmukh apoorvdeshmukh requested a review from Copilot May 13, 2026 10:12
@apoorvdeshmukh
Copy link
Copy Markdown
Contributor

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 2 pipeline(s).

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aligns Always Encrypted metadata parsing/serialization with the MS-TDS specification by treating CekMdVersion as an 8-byte ULONGLONG (ulong) and EkValueCount/CEK table size as USHORT (ushort). This improves correctness for large key tables and removes unnecessary allocations by avoiding intermediate byte-array representations.

Changes:

  • Update CEK metadata version handling from byte[8]/byte[] to ulong across the Always Encrypted metadata flow.
  • Read CEK table size as ushort (instead of short) when processing COLMETADATA cipher info tables.
  • Adjust functional Always Encrypted tests/utilities to match the updated internal signatures and representations.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/Utility.cs Updates test reflection helper signature to pass CEK metadata version as ulong.
src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/ExceptionsAlgorithmErrors.cs Updates test calls to the helper to provide CEK metadata version as a numeric ulong value.
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParser.cs Reads CekMdVersion as 8-byte integer and reads CEK table size as ushort; updates bulk-copy serialization to write ulong.
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlCommand.Encryption.cs Converts binary(8) metadata version from sp_describe_parameter_encryption into a ulong using BinaryPrimitives.
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ColumnEncryptionKeyInfo.cs Stores/serializes key metadata version as ulong and writes it as little-endian bytes.
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/AlwaysEncryptedHelperClasses.cs Propagates ulong CEK metadata version through cipher info structures and serialized parameter wire format.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 14, 2026

Codecov Report

❌ Patch coverage is 15.38462% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.51%. Comparing base (62d96ad) to head (2f27d3d).
⚠️ Report is 36 commits behind head on main.

Files with missing lines Patch % Lines
...icrosoft/Data/SqlClient/ColumnEncryptionKeyInfo.cs 0.00% 5 Missing ⚠️
...oft/Data/SqlClient/AlwaysEncryptedHelperClasses.cs 25.00% 3 Missing ⚠️
...qlClient/src/Microsoft/Data/SqlClient/TdsParser.cs 33.33% 2 Missing ⚠️
.../Microsoft/Data/SqlClient/SqlCommand.Encryption.cs 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4240      +/-   ##
==========================================
- Coverage   66.02%   64.51%   -1.51%     
==========================================
  Files         277      270       -7     
  Lines       42989    65777   +22788     
==========================================
+ Hits        28383    42439   +14056     
- Misses      14606    23338    +8732     
Flag Coverage Δ
CI-SqlClient ?
PR-SqlClient-Project 64.51% <15.38%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Contributor

@apoorvdeshmukh apoorvdeshmukh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@apoorvdeshmukh apoorvdeshmukh enabled auto-merge (squash) May 14, 2026 10:49
@apoorvdeshmukh apoorvdeshmukh requested a review from benrr101 May 15, 2026 16:48
Copy link
Copy Markdown
Contributor

@benrr101 benrr101 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love it! I don't know how you found this issue to fix, but I'm happy to take it!

@apoorvdeshmukh apoorvdeshmukh merged commit 9c0d240 into dotnet:main May 20, 2026
307 checks passed
@github-project-automation github-project-automation Bot moved this from In review to Done in SqlClient Board May 20, 2026
@edwardneal edwardneal deleted the perf/read-ulong-keymdversion branch May 20, 2026 18:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants