ReactOS 0.4.17-dev-1005-g171e1de
ScsTable.c
Go to the documentation of this file.
1//
2// ScsTable.c
3// Side-channel safe table
4//
5// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
6//
7//
8// These functions implement an table of large elements.
9// Reading an element from the table is done in a way that does not reveal the
10// element accessed through memory side channels.
11// Basically, the whole table is read by the CPU, and the required data is selected
12// using boolean operations.
13//
14
15#include "precomp.h"
16
17//
18// Items are multiple of SYMCRYPT_DIGIT_SIZE long.
19//
20// Format:
21// The memory format is parameterized for optimal implementations on several
22// different architectures.
23//
24// The following parameters define the format:
25// - group_size
26// - interleave_size
27//
28// Let nElements be the number of elements in the table.
29// If necessary, the size of each element in the table is rounded up to a multiple of interleave_size.
30// Each whole group of group_size elements is interleaved with each other.
31// The last (nElements % group_size) elements are simply stored consecutively.
32// (For now we simply require that nElements is a multiple of group_size.)
33// Within each group of group_size, the data for the elements are interleaved in natural order
34// using chunks of interleave_size bytes.
35//
36// The choice of group_size and interleave_size depends on the CPU architecture, CPU features,
37// and even the element size. (E.g. 1024-bit elements might interleave @ 64 bytes on an AVX512
38// capable CPU, but 256-bit elements would have to interleave at 16 or 32 bytes on that same CPU.)
39//
40
41// Currently these are constants as that allows easier optimizations...
42#if SYMCRYPT_CPU_AMD64 | SYMCRYPT_CPU_ARM64
43#define SYMCRYPT_SCSTABLE_USE64 1
44#define SYMCRYPT_SCSTABLE_INTERLEAVE_SIZE 32
45#define SYMCRYPT_SCSTABLE_GROUP_SIZE 4
47#else
48#define SYMCRYPT_SCSTABLE_USE64 0
49#define SYMCRYPT_SCSTABLE_INTERLEAVE_SIZE 16
50#define SYMCRYPT_SCSTABLE_GROUP_SIZE 4
52#endif
53
57 _Out_ PSYMCRYPT_SCSTABLE pScsTable,
58 UINT32 nElements,
59 UINT32 elementSize )
60{
61 UINT32 groupSize;
62 UINT32 interleaveSize;
64
65 SYMCRYPT_ASSERT( nElements > 0 );
66
67#pragma warning( suppress: 4127 ) // conditional expression is constant
68 if( SYMCRYPT_CPU_AMD64 && elementSize == 128 )
69 {
70 // Highly optimized assembler mode for 1024-bit entries for RSA-2048...
71 interleaveSize = 128;
72 groupSize = 1;
73 } else {
74 // Standard C implementation
75 interleaveSize = SYMCRYPT_SCSTABLE_INTERLEAVE_SIZE;
77 }
78
79 // Right now, we limit ourselves to element sizes that are a multiple of the interleaveSize and
80 // # elements that are a multiple of the group size.
81 // We also limit ourselves to sensible input sizes
82 SYMCRYPT_ASSERT( elementSize % interleaveSize == 0 && nElements % groupSize == 0 && (elementSize | nElements) < (1 << 16) && elementSize > 0 );
83
84 cbBuffer = elementSize * nElements; // Each factor is < 2^16, so there is no overflow in the mul
85
86 pScsTable->groupSize = groupSize;
87 pScsTable->interleaveSize = interleaveSize;
88 pScsTable->nElements = nElements;
89 pScsTable->elementSize = elementSize;
90 pScsTable->cbTableData = cbBuffer;
91 pScsTable->pbTableData = NULL;
92
93 return cbBuffer;
94}
95
96VOID
102{
103 SYMCRYPT_ASSERT(cbBuffer >= pScsTable->cbTableData);
105
106 pScsTable->pbTableData = pbBuffer;
107}
108
109
111// check that an interleave size is exactly 4 words
113
114VOID
117 _Inout_ PSYMCRYPT_SCSTABLE pScsTable,
118 UINT32 iIndex,
120 UINT32 cbData )
121{
124 UINT32 elementSize = pScsTable->elementSize;
125 UINT32 groupOffset;
126
127 SYMCRYPT_ASSERT( groupSize == pScsTable->groupSize );
128 SYMCRYPT_ASSERT( interleaveSize == pScsTable->interleaveSize );
129
130 SYMCRYPT_ASSERT( cbData == elementSize );
132
133 SYMCRYPT_ASSERT(iIndex < pScsTable->nElements);
134
135 groupOffset = iIndex % groupSize;
136
137 // dcl - document why this can't be an integer overflow
138 SYMCRYPT_SCSTABLE_TYPE * pDst = (SYMCRYPT_SCSTABLE_TYPE *) (pScsTable->pbTableData + (iIndex - groupOffset) * elementSize + groupOffset * interleaveSize);
140
141 UINT32 nInterleaves = elementSize / interleaveSize;
142
143 do
144 {
145 pDst[0] = pSrc[0];
146 pDst[1] = pSrc[1];
147 pDst[2] = pSrc[2];
148 pDst[3] = pSrc[3];
149
150 pDst += interleaveSize * groupSize / sizeof( *pDst );
151 pSrc += interleaveSize / sizeof( *pSrc );
152 nInterleaves--;
153 } while( nInterleaves > 0 );
154
155}
156
157#if SYMCRYPT_CPU_AMD64
158VOID
160SymCryptScsTableStore128Xmm(
161 _Inout_ PSYMCRYPT_SCSTABLE pScsTable,
162 UINT32 iIndex,
164 UINT32 cbData )
165{
166 __m128i * pDst = (__m128i *) (pScsTable->pbTableData + iIndex * 128);
167 __m128i * pSrc = (__m128i *) pbData;
168
169 SYMCRYPT_ASSERT( cbData == 128 && pScsTable->elementSize == 128 && iIndex < pScsTable->nElements && pScsTable->groupSize == 1 );
171
172 pDst[0] = pSrc[0];
173 pDst[1] = pSrc[1];
174 pDst[2] = pSrc[2];
175 pDst[3] = pSrc[3];
176 pDst[4] = pSrc[4];
177 pDst[5] = pSrc[5];
178 pDst[6] = pSrc[6];
179 pDst[7] = pSrc[7];
180}
181#endif // AMD64
182
183VOID
186 _In_ PSYMCRYPT_SCSTABLE pScsTable,
187 UINT32 iIndex,
189 UINT32 cbData )
190{
193 UINT32 elementSize = pScsTable->elementSize;
194
195 SYMCRYPT_SCSTABLE_TYPE mask0, mask1, mask2, mask3;
196 UINT32 i;
197 UINT32 j;
198 UINT32 nElements = pScsTable->nElements;
199
200 const SYMCRYPT_SCSTABLE_TYPE * pSrc = (SYMCRYPT_SCSTABLE_TYPE *) pScsTable->pbTableData;
203
204 UINT32 nInterleaves = elementSize / interleaveSize;
205
206
207 SYMCRYPT_ASSERT( groupSize == pScsTable->groupSize );
208 SYMCRYPT_ASSERT( interleaveSize == pScsTable->interleaveSize );
209
211 SYMCRYPT_ASSERT( cbData == pScsTable->elementSize );
213
214#if SYMCRYPT_SCSTABLE_USE64
215#define SCS_MASK_EQUAL32( _a, _b ) ( ~(UINT64) ((INT64) ((UINT64)0 - (_a ^ _b)) >> 32 ) )
216#else
217#define SCS_MASK_EQUAL32( _a, _b ) (SYMCRYPT_MASK32_EQ( _a, _b ))
218#endif
219
220 i = 0;
221
222 mask0 = SCS_MASK_EQUAL32( i+0, iIndex );
223 mask1 = SCS_MASK_EQUAL32( i+1, iIndex );
224 mask2 = SCS_MASK_EQUAL32( i+2, iIndex );
225 mask3 = SCS_MASK_EQUAL32( i+3, iIndex );
226
227 j = nInterleaves;
228 pD = pDst;
229
230 do {
231 pD[0] = (mask0 & pSrc[0]) | (mask1 & pSrc[4]) | (mask2 & pSrc[ 8]) | (mask3 & pSrc[12]);
232 pD[1] = (mask0 & pSrc[1]) | (mask1 & pSrc[5]) | (mask2 & pSrc[ 9]) | (mask3 & pSrc[13]);
233 pD[2] = (mask0 & pSrc[2]) | (mask1 & pSrc[6]) | (mask2 & pSrc[10]) | (mask3 & pSrc[14]);
234 pD[3] = (mask0 & pSrc[3]) | (mask1 & pSrc[7]) | (mask2 & pSrc[11]) | (mask3 & pSrc[15]);
235 pD += interleaveSize / sizeof( *pD );
236 pSrc += interleaveSize * groupSize / sizeof( *pSrc );
237 j--;
238 } while( j > 0 );
239
240 i += groupSize;
241
242 while (i + groupSize <= nElements)
243 {
244
245 mask0 = SCS_MASK_EQUAL32( i+0, iIndex );
246 mask1 = SCS_MASK_EQUAL32( i+1, iIndex );
247 mask2 = SCS_MASK_EQUAL32( i+2, iIndex );
248 mask3 = SCS_MASK_EQUAL32( i+3, iIndex );
249
250 j = nInterleaves;
251 pD = pDst;
252
253 do {
254 pD[0] |= (mask0 & pSrc[0]) | (mask1 & pSrc[4]) | (mask2 & pSrc[ 8]) | (mask3 & pSrc[12]);
255 pD[1] |= (mask0 & pSrc[1]) | (mask1 & pSrc[5]) | (mask2 & pSrc[ 9]) | (mask3 & pSrc[13]);
256 pD[2] |= (mask0 & pSrc[2]) | (mask1 & pSrc[6]) | (mask2 & pSrc[10]) | (mask3 & pSrc[14]);
257 pD[3] |= (mask0 & pSrc[3]) | (mask1 & pSrc[7]) | (mask2 & pSrc[11]) | (mask3 & pSrc[15]);
258 pD += interleaveSize / sizeof( *pD );
259 pSrc += interleaveSize * groupSize / sizeof( *pSrc );
260 j--;
261 } while( j > 0 );
262
263 i += groupSize;
264 }
265}
266
267#if SYMCRYPT_CPU_AMD64
268VOID
270SymCryptScsTableLoad128Xmm(
271 _In_ PSYMCRYPT_SCSTABLE pScsTable,
272 UINT32 iIndex,
274 UINT32 cbData )
275{
276 UINT32 nElements = pScsTable->nElements;
277
278 __m128i R0, R1, R2, R3, R4, R5, R6, R7;
279 __m128i T0, T1;
280
281 __m128i Count = _mm_setzero_si128();
282 __m128i Ones = _mm_set_epi32( 1, 1, 1, 1 );
283 __m128i Entry = _mm_set_epi32( iIndex, iIndex, iIndex, iIndex );
284 __m128i Mask;
285 __m128i * pSrc = (__m128i *) pScsTable->pbTableData;
286 __m128i * pDst = (__m128i *) pbData;
287
288 SYMCRYPT_ASSERT( cbData == 128 && pScsTable->elementSize == 128 && iIndex < pScsTable->nElements && pScsTable->groupSize == 1 );
290
292 Count = _mm_add_epi32( Count, Ones );
293
294 R0 = _mm_and_si128( Mask, pSrc[0] );
295 R1 = _mm_and_si128( Mask, pSrc[1] );
296 R2 = _mm_and_si128( Mask, pSrc[2] );
297 R3 = _mm_and_si128( Mask, pSrc[3] );
298 R4 = _mm_and_si128( Mask, pSrc[4] );
299 R5 = _mm_and_si128( Mask, pSrc[5] );
300 R6 = _mm_and_si128( Mask, pSrc[6] );
301 R7 = _mm_and_si128( Mask, pSrc[7] );
302
303 pSrc += 8;
304
305 while( --nElements > 0 )
306 {
308 Count = _mm_add_epi32( Count, Ones );
309
310 T0 = _mm_and_si128( Mask, pSrc[0] ); R0 = _mm_or_si128( R0, T0 );
311 T1 = _mm_and_si128( Mask, pSrc[1] ); R1 = _mm_or_si128( R1, T1 );
312 T0 = _mm_and_si128( Mask, pSrc[2] ); R2 = _mm_or_si128( R2, T0 );
313 T1 = _mm_and_si128( Mask, pSrc[3] ); R3 = _mm_or_si128( R3, T1 );
314 T0 = _mm_and_si128( Mask, pSrc[4] ); R4 = _mm_or_si128( R4, T0 );
315 T1 = _mm_and_si128( Mask, pSrc[5] ); R5 = _mm_or_si128( R5, T1 );
316 T0 = _mm_and_si128( Mask, pSrc[6] ); R6 = _mm_or_si128( R6, T0 );
317 T1 = _mm_and_si128( Mask, pSrc[7] ); R7 = _mm_or_si128( R7, T1 );
318 pSrc += 8;
319 }
320
321 pDst[0] = R0;
322 pDst[1] = R1;
323 pDst[2] = R2;
324 pDst[3] = R3;
325 pDst[4] = R4;
326 pDst[5] = R5;
327 pDst[6] = R6;
328 pDst[7] = R7;
329}
330#endif // AMD64
331
332VOID
335 _Inout_ PSYMCRYPT_SCSTABLE pScsTable,
336 UINT32 iIndex,
338 UINT32 cbData )
339{
340#if SYMCRYPT_CPU_AMD64
341
342 if( pScsTable->elementSize == 128 )
343 {
344 SymCryptScsTableStore128Xmm( pScsTable, iIndex, pbData, cbData );
345 } else {
346 SymCryptScsTableStoreC( pScsTable, iIndex, pbData, cbData );
347 }
348
349#else
350
351 SymCryptScsTableStoreC( pScsTable, iIndex, pbData, cbData );
352
353#endif
354}
355
356VOID
359 _In_ PSYMCRYPT_SCSTABLE pScsTable,
360 UINT32 iIndex,
362 UINT32 cbData )
363{
364 // This is the side-channel safe routine
365
366#if SYMCRYPT_CPU_AMD64
367
368 if( pScsTable->elementSize == 128 )
369 {
370 SymCryptScsTableLoad128Xmm( pScsTable, iIndex, pbData, cbData );
371 } else {
372 SymCryptScsTableLoadC( pScsTable, iIndex, pbData, cbData );
373 }
374
375#else
376
377 SymCryptScsTableLoadC( pScsTable, iIndex, pbData, cbData );
378
379#endif
380}
381
382VOID
385 _Inout_ PSYMCRYPT_SCSTABLE pScsTable )
386{
387 SymCryptWipe( pScsTable->pbTableData, pScsTable->cbTableData );
388}
#define SYMCRYPT_SCSTABLE_INTERLEAVE_SIZE
Definition: ScsTable.c:49
VOID SYMCRYPT_CALL SymCryptScsTableLoadC(_In_ PSYMCRYPT_SCSTABLE pScsTable, UINT32 iIndex, _Out_writes_bytes_(cbData) PBYTE pbData, UINT32 cbData)
Definition: ScsTable.c:185
UINT32 SYMCRYPT_CALL SymCryptScsTableInit(_Out_ PSYMCRYPT_SCSTABLE pScsTable, UINT32 nElements, UINT32 elementSize)
Definition: ScsTable.c:56
UINT32 SYMCRYPT_SCSTABLE_TYPE
Definition: ScsTable.c:51
VOID SYMCRYPT_CALL SymCryptScsTableSetBuffer(_Inout_ PSYMCRYPT_SCSTABLE pScsTable, _Inout_updates_bytes_(cbBuffer) PBYTE pbBuffer, UINT32 cbBuffer)
Definition: ScsTable.c:98
VOID SYMCRYPT_CALL SymCryptScsTableStore(_Inout_ PSYMCRYPT_SCSTABLE pScsTable, UINT32 iIndex, _In_reads_bytes_(cbData) PCBYTE pbData, UINT32 cbData)
Definition: ScsTable.c:334
VOID SYMCRYPT_CALL SymCryptScsTableStoreC(_Inout_ PSYMCRYPT_SCSTABLE pScsTable, UINT32 iIndex, _In_reads_bytes_(cbData) PCBYTE pbData, UINT32 cbData)
Definition: ScsTable.c:116
#define SCS_MASK_EQUAL32(_a, _b)
VOID SYMCRYPT_CALL SymCryptScsTableWipe(_Inout_ PSYMCRYPT_SCSTABLE pScsTable)
Definition: ScsTable.c:384
VOID SYMCRYPT_CALL SymCryptScsTableLoad(_In_ PSYMCRYPT_SCSTABLE pScsTable, UINT32 iIndex, _Out_writes_bytes_(cbData) PBYTE pbData, UINT32 cbData)
Definition: ScsTable.c:358
#define SYMCRYPT_SCSTABLE_GROUP_SIZE
Definition: ScsTable.c:50
COMPILER_DEPENDENT_UINT64 UINT64
Definition: actypes.h:131
#define NULL
Definition: types.h:112
__m128i _mm_set_epi32(int i3, int i2, int i1, int i0)
Definition: emmintrin.h:1598
__m128i _mm_setzero_si128(void)
Definition: emmintrin.h:1674
__m128i _mm_or_si128(__m128i a, __m128i b)
Definition: emmintrin.h:1340
__m128i _mm_cmpeq_epi32(__m128i a, __m128i b)
Definition: emmintrin.h:1460
__m128i _mm_and_si128(__m128i a, __m128i b)
Definition: emmintrin.h:1330
__m128i _mm_add_epi32(__m128i a, __m128i b)
Definition: emmintrin.h:1137
unsigned int Mask
Definition: fpcontrol.c:82
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
#define C_ASSERT(e)
Definition: intsafe.h:73
#define _In_reads_bytes_(s)
Definition: no_sal2.h:170
#define _Inout_
Definition: no_sal2.h:162
#define _Out_
Definition: no_sal2.h:160
#define _In_
Definition: no_sal2.h:158
#define _Inout_updates_bytes_(s)
Definition: no_sal2.h:184
#define _Out_writes_bytes_(s)
Definition: no_sal2.h:178
int Count
Definition: noreturn.cpp:7
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:329
BYTE * PBYTE
Definition: pedump.c:66
SIZE_T cbBuffer
Definition: sc_lib_mldsa.h:405
#define R1(v, w, x, y, z, i)
Definition: sha1.c:36
#define R2(v, w, x, y, z, i)
Definition: sha1.c:37
#define R0(v, w, x, y, z, i)
Definition: sha1.c:35
#define R3(v, w, x, y, z, i)
Definition: sha1.c:38
#define R4(v, w, x, y, z, i)
Definition: sha1.c:39
Entry
Definition: section.c:5216
#define SYMCRYPT_ASSERT(_x)
Definition: symcrypt.h:10807
VOID SYMCRYPT_CALL SymCryptWipe(_Out_writes_bytes_(cbData) PVOID pbData, SIZE_T cbData)
Definition: libmain.c:137
#define SYMCRYPT_CALL
#define SYMCRYPT_CPU_AMD64
PCBYTE PBYTE SIZE_T cbData
const BYTE * PCBYTE
PCBYTE pbData
uint32_t UINT32
Definition: typedefs.h:59