ReactOS 0.4.17-dev-1005-g171e1de
scsTools.c
Go to the documentation of this file.
1//
2// scsTools.c Support tools for writing side-channel safe code
3//
4// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
5//
6
7#include "precomp.h"
8
9//
10// This code needs to process data in words, and we'd like to use 32-bit words on 32-bit
11// architectures and 64-bit words on 64-bit architectures. So we use NATIVE_UINT & friends.
12//
13
14// Buffer limits for SymCryptScsRotateBuffer
15#define MIN_BUFFER_SIZE (32)
16
17//
18// Masking functions
19// Masking functions can be more efficient if the inputs are restricted to values that can
20// be represented in the signed data types.
21// This is why we have some functions that take 31-bit inputs.
22//
23
24// 31-bit inputs
25
29{
30 SYMCRYPT_ASSERT( v < (1UL<<31) );
31 return (-(INT32) v) >> 31;
32}
33
37{
38 return ~SymCryptMask32IsNonzeroU31( v );
39}
40
44{
45 SYMCRYPT_ASSERT( a < (1UL<<31) );
46 SYMCRYPT_ASSERT( b < (1UL<<31) );
47
48 return SymCryptMask32IsNonzeroU31( a ^ b );
49}
50
54{
55 SYMCRYPT_ASSERT( a < (1UL<<31) );
56 SYMCRYPT_ASSERT( b < (1UL<<31) );
57
58 // Casting to INT32 is defined as a and b are < 2^31
59 return ((INT32) a - (INT32) b) >> 31;
60}
61
62
63// 32-bit inputs
64
68{
69 return ~(UINT32) ( (-(INT64)(a^b)) >> 32);
70}
71
72
73// Other helper functions
77{
78 SIZE_T res;
79
80 SYMCRYPT_ASSERT( v <= (SIZE_T_MAX / 2) + 1);
81 // If v is very large, then the result res might overflow.
82 // As SIZE_T is an unsigned type, the overflow is defined to
83 // be modulo 2^n for some n, and therefore we'll get res==0
84 // which will terminate the loop.
85
86 res = 1;
87 while( res < v )
88 {
89 res += res;
90
91 // Catch any overflows; should never happen but break to avoid infinite loop
92 if( res == 0 )
93 {
94 break;
95 }
96 }
97
98 return res;
99}
100
101
102//
103// Copy data
104//
105
106VOID
109 _In_reads_( cbDst ) PCBYTE pbSrc,
110 SIZE_T cbSrc,
111 _Out_writes_( cbDst ) PBYTE pbDst,
112 SIZE_T cbDst )
113// Copy cbSrc bytes of pbSrc into pbDst without revealing cbSrc
114// through side channels.
115// - pbSrc/cbSrc: buffer to copy data from
116// - pbDst/cbDst: buffer that receives the data
117// Equivalent to:
118// n = min( cbSrc, cbDst )
119// pbDst[ 0.. n-1 ] = pbSrc[ 0 .. n - 1 ]
120// cbSrc is protected from side-channels; cbDst is public.
121// Note that pbSrc must be cbDst bytes long, not cbSrc bytes.
122{
123 UINT32 i;
124
125 SYMCRYPT_ASSERT( cbSrc <= (1UL << 31) && cbDst <= (1UL << 31) );
126
127 // Loop over the destination buffer and update each byte with the source data (if appropriate)
128 // We round-robin loop over the source buffer
129 for( i = 0; i < cbDst; i++ )
130 {
131 pbDst[ i ] ^= (pbSrc[ i ] ^ pbDst[ i ]) & SymCryptMask32LtU31( i, (UINT32) cbSrc );
132 }
133}
134
135
136//
137// Buffer rotation
138// To recover a message from an encoding with variable data position we have to do a copy from a
139// variable memory location. But our memory access pattern cannot depend on the secret location.
140// This code rotates a given buffer by a variable # bytes without revealing the shift amount.
141//
142// For efficiency we do this using NATIVE_UINT values so that we get the best performance on each platform.
143//
144// The first step is to rotate the array between 0 and NATIVE_BYTES-1 bytes to get the proper word alignment.
145// After that we only have to rotate the words.
146// We do this using a sequence of swaps.
147// Notation:
148// W[i] array of words, 0 <= i < n where n is the # words, a power of 2.
149// s Rotation amount (to the left). The value in W[s] at the start should appear in W[0] at the end.
150//
151// We use masked swaps as they seem to be more efficient then masked multiplexers.
152// We can split this problem down recursively
153//
154// Function Rotate( W, n, s)
155// - Rotate W[0..n/2-1] by s mod n/2
156// - Rotate W[n/2..n-1] by s mod n/2
157// for i in 0..n/2-1:
158// swap W[i] and W[i+n/2] if (i+s) % n >= n/2
159//
160// After the two half-sized rotates, each word is in the right position modulo n/2, so all that needs to be
161// done in possibly swap (W[i],W[i+n/2]) pairs.
162// Let W' be the array after the half-sized rotates. We have
163// W'[i] = W[ (i + s) % (n/2) ] for i in 0..n/2
164// In the final array W'' we should have W''[i] = W[ (i+s)%n ]
165// So W''[i] = W'[i] when (i+s) % n = (i+s) % n/2 which is equivalent to (i+s)%n < n/2.
166//
167// We turn this into a non-recursive algorithm.
168// First we do rotations on 2 words,
169// then the fixups to make it 4-word rotations,
170// then on to 8-words, etc.
171// At each level we compute the masks for the swaps once, and re-use them for each copy
172// As a further optimization, we merge the 1st and 2nd pass into one to reduce the # read/writes
173//
174// We avoid using / and % throughout to avoid any time-dependent instructions.
175//
176
177VOID
180 _Inout_updates_( cbBuffer ) PBYTE pbBuffer,
182 SIZE_T lshift )
183{
184 NATIVE_UINT * pBuf;
185 UINT32 n;
186 UINT32 a;
187 UINT32 b;
188 UINT32 i;
189 UINT32 j;
190 UINT32 blockSize;
191 UINT32 blockSizeLog;
192 UINT32 blockSizeLimit;
193
201 NATIVE_UINT M0;
202 NATIVE_UINT M1;
203
204 NATIVE_UINT Mask[ 16 ]; // Size must be a power of 2
205
207 SYMCRYPT_ASSERT( lshift < cbBuffer );
208
209 pBuf = (NATIVE_UINT *) pbBuffer;
211
212 // First a rotate left by lshift % NATIVE_BYTES
213 // This is more complex because shifting by NATIVE_BITS is not a defined operation, and behavior is different
214 // on different CPUs.
215
216 // Compute the shift amounts & mask
217 // M = 0 if lshift % NATIVE_BYTES == 0, -1 otherwise
218 a = 8 * (lshift & (NATIVE_BYTES-1)); // Core shift
219 M = (-(NATIVE_INT)a) >> (NATIVE_BITS - 1); // mask
220 b = (NATIVE_BITS - a) & (UINT32) M; // complementary shift, or 0 if it would be equal to NATIVE_BITS
221
222 i = n;
223 V = pBuf[0];
224 do{
225 // Loop invariant: i > 0 && v = pBuf[i] from before any changes;
226 i--;
227 T = pBuf[i];
228 pBuf[i] = T >> a | ((V << b) & M);
229 V = T;
230 } while( i > 0 );
231
232 // Now that the rotation is word-aligned, we can start our word rotation
233 lshift >>= NATIVE_BYTES_LOG2; // convert to # words to rotate.
234
235 // We know we have at least 4 words, so we start with a pass do do 4-word rotations
236 SYMCRYPT_ASSERT( n >= 4 );
237
238 M = -(NATIVE_INT)(lshift & 1);
239 M0 = -(NATIVE_INT)( ((lshift + 0) >> 1) & 1 ); // s + 0 mod 4 >= 2
240 M1 = -(NATIVE_INT)( ((lshift + 1) >> 1) & 1 ); // s + 1 mod 4 >= 2
241
242 for( i=0; i<n; i+=4 )
243 {
244 A = pBuf[i];
245 B = pBuf[i+1];
246 C = pBuf[i+2];
247 D = pBuf[i+3];
248
249 T = (A ^ B) & M;
250 A ^= T;
251 B ^= T;
252
253 T = (C ^ D) & M;
254 C ^= T;
255 D ^= T;
256
257 T = (A ^ C) & M0;
258 A ^= T;
259 C ^= T;
260
261 T = (B ^ D) & M1;
262 B ^= T;
263 D ^= T;
264
265 pBuf[i ] = A;
266 pBuf[i+1] = B;
267 pBuf[i+2] = C;
268 pBuf[i+3] = D;
269 }
270
271 // Do the swaps using the mask array
272 blockSize = 4; // size of rotated blocks
273 blockSizeLog = 2;
274
275 //
276 // Using the mask array is beneficial as long as the array is used twice or more
277 // Each swap loop processes 2 * blockSize of data, so the block size should never
278 // be larger than n/4
279 blockSizeLimit = SYMCRYPT_MIN( SYMCRYPT_ARRAY_SIZE( Mask ), n/4 );
280 while( blockSize <= blockSizeLimit )
281 {
282 // Compute the masks for this level
283 for( i=0; i<blockSize; i++ )
284 {
285 Mask[i] =-(NATIVE_INT)( ((i + lshift) >> blockSizeLog) & 1);
286 }
287
288 // Now swap the elements of pairs of blocks according to the masks
289 for( i=0; i < n; i += 2 * blockSize )
290 {
291 for( j=0; j < blockSize; j++ )
292 {
293 A = pBuf[ i + j ];
294 B = pBuf[ i + j + blockSize ];
295 T = (A ^ B) & Mask[j];
296 A ^= T;
297 B ^= T;
298 pBuf[ i + j ] = A;
299 pBuf[ i + j + blockSize ] = B;
300 }
301 }
302 blockSize *= 2;
303 blockSizeLog += 1;
304 }
305
306 // Do the rest without using a mask array, either because we are only
307 // going to use each mask value once, or because we don't have a large-enough
308 // array
309 while( blockSize < n )
310 {
311 // Now swap the elements of pairs of blocks according to the masks
312 for( i=0; i < n; i += 2 * blockSize )
313 {
314 for( j=0; j < blockSize; j++ )
315 {
316 M = -(NATIVE_INT)( ((j + lshift) >> blockSizeLog) & 1);
317 A = pBuf[ i + j ];
318 B = pBuf[ i + j + blockSize ];
319 T = (A ^ B) & M;
320 A ^= T;
321 B ^= T;
322 pBuf[ i + j ] = A;
323 pBuf[ i + j + blockSize ] = B;
324 }
325 }
326 blockSize *= 2;
327 blockSizeLog += 1;
328 }
329
330}
331
332
333//
334// Map values in a side-channel safe way, typically used for mapping error codes.
335//
336// (pcMap, nMap) point to an array of nMap entries of type SYMCRYPT_UINT32_MAP;
337// each entry specifies a single mapping. If u32Input matches the
338// 'from' field, the return value will be the 'to' field value.
339// If u32Input is not equal to any 'from' field values, the return value is u32Default.
340// Both u32Input and the return value are treated as secrets w.r.t. side channels.
341//
342// If multiple map entries have the same 'from' field value, then the return value
343// is one of the several 'to' field values; which one is not defined.
344//
345// This function is particularly useful when mapping error codes in situations where
346// the actual error cannot be revealed through side channels.
347//
348
349UINT32
352 UINT32 u32Input,
353 UINT32 u32Default,
355 SIZE_T nMap)
356{
357 UINT32 mask;
358 UINT32 u32Output = u32Default;
359
360 for (SIZE_T i = 0; i < nMap; ++i)
361 {
362 mask = SymCryptMask32EqU32(u32Input, pcMap[i].from);
363 u32Output ^= (u32Output ^ pcMap[i].to) & mask;
364 }
365
366 return u32Output;
367}
COMPILER_DEPENDENT_INT64 INT64
Definition: actypes.h:132
#define D(d)
Definition: builtin.c:4557
#define C(c)
Definition: builtin.c:4556
Definition: ehthrow.cxx:93
Definition: ehthrow.cxx:54
Definition: terminate.cpp:24
#define SIZE_T_MAX
Definition: dhcpd.h:91
#define A(row, col)
#define B(row, col)
#define M(row, col)
unsigned int Mask
Definition: fpcontrol.c:82
const GLdouble * v
Definition: gl.h:2040
GLdouble n
Definition: glext.h:7729
GLuint res
Definition: glext.h:9613
GLenum GLint GLuint mask
Definition: glext.h:6028
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
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 V(i, a, b, c, d)
Definition: jaricom.c:29
#define a
Definition: ke_i.h:78
#define b
Definition: ke_i.h:79
#define _In_reads_(s)
Definition: no_sal2.h:168
#define _Inout_updates_(s)
Definition: no_sal2.h:182
#define _Out_writes_(s)
Definition: no_sal2.h:176
BYTE * PBYTE
Definition: pedump.c:66
#define T(num)
Definition: thunks.c:311
INT32 NATIVE_INT
Definition: sc_lib.h:76
UINT32 NATIVE_UINT
Definition: sc_lib.h:77
#define NATIVE_BYTES_LOG2
Definition: sc_lib.h:80
#define NATIVE_BYTES
Definition: sc_lib.h:79
#define NATIVE_BITS
Definition: sc_lib.h:78
#define SYMCRYPT_ARRAY_SIZE(_x)
Definition: sc_lib.h:342
SIZE_T cbBuffer
Definition: sc_lib_mldsa.h:405
#define MIN_BUFFER_SIZE
Definition: scsTools.c:15
VOID SYMCRYPT_CALL SymCryptScsRotateBuffer(_Inout_updates_(cbBuffer) PBYTE pbBuffer, SIZE_T cbBuffer, SIZE_T lshift)
Definition: scsTools.c:179
UINT32 SYMCRYPT_CALL SymCryptMask32IsNonzeroU31(UINT32 v)
Definition: scsTools.c:28
UINT32 SYMCRYPT_CALL SymCryptMask32EqU32(UINT32 a, UINT32 b)
Definition: scsTools.c:67
UINT32 SYMCRYPT_CALL SymCryptMask32IsZeroU31(UINT32 v)
Definition: scsTools.c:36
UINT32 SYMCRYPT_CALL SymCryptMapUint32(UINT32 u32Input, UINT32 u32Default, _In_reads_(nMap) PCSYMCRYPT_UINT32_MAP pcMap, SIZE_T nMap)
Definition: scsTools.c:351
UINT32 SYMCRYPT_CALL SymCryptMask32NeqU31(UINT32 a, UINT32 b)
Definition: scsTools.c:43
SIZE_T SYMCRYPT_CALL SymCryptRoundUpPow2Sizet(SIZE_T v)
Definition: scsTools.c:76
UINT32 SYMCRYPT_CALL SymCryptMask32LtU31(UINT32 a, UINT32 b)
Definition: scsTools.c:53
VOID SYMCRYPT_CALL SymCryptScsCopy(_In_reads_(cbDst) PCBYTE pbSrc, SIZE_T cbSrc, _Out_writes_(cbDst) PBYTE pbDst, SIZE_T cbDst)
Definition: scsTools.c:108
CardRegion * from
Definition: spigame.cpp:19
#define SYMCRYPT_ASSERT(_x)
Definition: symcrypt.h:10807
PCBYTE pbSrc
#define SYMCRYPT_CALL
#define SYMCRYPT_MIN(_a, _b)
PCBYTE PBYTE pbDst
const BYTE * PCBYTE
int32_t INT32
Definition: typedefs.h:58
ULONG_PTR SIZE_T
Definition: typedefs.h:80
uint32_t UINT32
Definition: typedefs.h:59