ReactOS 0.4.17-dev-1005-g171e1de
chacha20_poly1305.c
Go to the documentation of this file.
1//
2// ChaCha20_Poly1305.c
3//
4// Copyright (c) Microsoft Corporation.
5//
6
7#include "precomp.h"
8
9#define CHACHA20_POLY1305_MAX_DATA_SIZE (((1ull << 32) - 1) * 64)
10
11// Compile time BOOL statically determines if we need to check cbData > CHACHA20_POLY1305_MAX_DATA_SIZE
12// Used to suppress MSVC C4127 and clang Wtautological-constant-out-of-range-compare on 32b platforms
14
15VOID
19 _In_reads_opt_( cbAuthData ) PCBYTE pbAuthData,
24{
26 BYTE partialBlockSize;
27
29
30 // Add additional authentication data if needed.
31 if ( cbAuthData > 0 )
32 {
34
35 // Append zeros to make a complete Poly1305 block.
36 partialBlockSize = cbAuthData % SYMCRYPT_POLY1305_BLOCK_SIZE;
37 if ( partialBlockSize > 0 )
38 {
40 }
41 }
42
43 // Add ciphertext if needed.
44 if ( cbData > 0 )
45 {
47
48 // Append zeros to make a complete Poly1305 block.
49 partialBlockSize = cbData % SYMCRYPT_POLY1305_BLOCK_SIZE;
50 if ( partialBlockSize > 0 )
51 {
53 }
54 }
55
56 // Add length of additional authentication data and ciphertext.
61
63}
64
65SYMCRYPT_NOINLINE
71 _In_reads_( cbNonce ) PCBYTE pbNonce,
73 _In_reads_opt_( cbAuthData ) PCBYTE pbAuthData,
78 _Out_writes_( cbTag ) PBYTE pbTag,
80{
81 SYMCRYPT_ERROR status = SYMCRYPT_NO_ERROR;
82 SYMCRYPT_CHACHA20_STATE ChaCha20State;
83 SYMCRYPT_POLY1305_STATE Poly1305State;
85
87 {
88 status = SYMCRYPT_WRONG_DATA_SIZE;
89 goto cleanup;
90 }
91
93 {
94 status = SYMCRYPT_WRONG_TAG_SIZE;
95 goto cleanup;
96 }
97
98 status = SymCryptChaCha20Init( &ChaCha20State, pbKey, cbKey, pbNonce, cbNonce, 0 );
99 if ( status != SYMCRYPT_NO_ERROR )
100 {
101 goto cleanup;
102 }
103
104 // Generate the first 32 bytes of keystream.
105 SymCryptWipeKnownSize( key, sizeof( key ) );
106 SymCryptChaCha20Crypt( &ChaCha20State, key, key, sizeof ( key ) );
107
108 // Create the Poly1305 key using the first 32 bytes of the ChaCha20 keystream.
109 SymCryptPoly1305Init( &Poly1305State, key );
110 SymCryptWipeKnownSize( key, sizeof( key ) );
111
112 // Encrypt data if needed.
113 if ( cbData > 0 )
114 {
115 // Advance the keystream to counter 1 (offset 64) for data encryption.
116 SymCryptChaCha20SetOffset( &ChaCha20State, 64 );
117 SymCryptChaCha20Crypt( &ChaCha20State, pbSrc, pbDst, cbData );
118 }
119
120 // We read the ciphertext back, violating the general rule not to rely on I/O buffers
121 // as they can reside in a different security domain. For ChaCha20Poly1305, like GCM,
122 // this read-back of data is not a problem. An attacker with access to the buffer
123 // will get the ChaCha20 key stream plus the Poly1305 authenticator of a single value.
124 // As Poly1305 is strong even with attacker-controlled data, this is harmless.
125 SymCryptChaCha20Poly1305ComputeTag( &Poly1305State, pbAuthData, cbAuthData,
126 pbDst, cbData, pbTag );
127cleanup:
128
129 SymCryptWipeKnownSize( &ChaCha20State, sizeof( ChaCha20State ) );
130 SymCryptWipeKnownSize( &Poly1305State, sizeof( Poly1305State ) );
131
132 return status;
133}
134
135SYMCRYPT_NOINLINE
141 _In_reads_( cbNonce ) PCBYTE pbNonce,
143 _In_reads_opt_( cbAuthData ) PCBYTE pbAuthData,
148 _In_reads_( cbTag ) PCBYTE pbTag,
149 SIZE_T cbTag )
150{
151 SYMCRYPT_ERROR status = SYMCRYPT_NO_ERROR;
152 SYMCRYPT_CHACHA20_STATE ChaCha20State;
153 SYMCRYPT_POLY1305_STATE Poly1305State;
156
158 {
159 status = SYMCRYPT_WRONG_DATA_SIZE;
160 goto cleanup;
161 }
162
164 {
165 status = SYMCRYPT_WRONG_TAG_SIZE;
166 goto cleanup;
167 }
168
169 status = SymCryptChaCha20Init( &ChaCha20State, pbKey, cbKey, pbNonce, cbNonce, 0 );
170 if ( status != SYMCRYPT_NO_ERROR )
171 {
172 goto cleanup;
173 }
174
175 // Generate the first 32 bytes of keystream.
176 SymCryptWipeKnownSize( key, sizeof( key ) );
177 SymCryptChaCha20Crypt( &ChaCha20State, key, key, sizeof( key ) );
178
179 // Create the Poly1305 key using the first 32 bytes of the ChaCha20 keystream.
180 SymCryptPoly1305Init( &Poly1305State, key );
181 SymCryptWipeKnownSize( key, sizeof( key ) );
182
183 // We read the ciphertext back, violating the general rule not to rely on I/O buffers
184 // as they can reside in a different security domain. For ChaCha20Poly1305, like GCM,
185 // this read-back of data is not a problem. An attacker with access to the buffer
186 // will get the ChaCha20 key stream plus the Poly1305 authenticator of a single value.
187 // As Poly1305 is strong even with attacker-controlled data, this is harmless.
188 SymCryptChaCha20Poly1305ComputeTag( &Poly1305State, pbAuthData, cbAuthData,
189 pbSrc, cbData, buf );
190
191 // Validate tag.
192 if (!SymCryptEqual(pbTag, buf, cbTag))
193 {
194 status = SYMCRYPT_AUTHENTICATION_FAILURE;
195 goto cleanup;
196 }
197
198 // Decrypt data if needed.
199 if ( cbData > 0)
200 {
201 // Advance the keystream to counter 1 (offset 64) for data decryption.
202 SymCryptChaCha20SetOffset( &ChaCha20State, 64 );
203 SymCryptChaCha20Crypt( &ChaCha20State, pbSrc, pbDst, cbData );
204 }
205
206cleanup:
207
208 SymCryptWipeKnownSize( &ChaCha20State, sizeof( ChaCha20State ) );
209 SymCryptWipeKnownSize( &Poly1305State, sizeof( Poly1305State ) );
210
211 return status;
212}
213
214
216{
217 0x5d, 0xba, 0x7b,
218 0x80, 0x10, 0xd2, 0x05, 0x4a, 0xad, 0x53, 0x1f, 0xa2, 0xce, 0x83, 0xc1, 0x66, 0x12, 0x85, 0x21
219};
220
221VOID
224{
227
231 &SymCryptTestMsg3[0], buf, 3,
232 &buf[3], SYMCRYPT_POLY1305_RESULT_SIZE ) != SYMCRYPT_NO_ERROR )
233 {
234 SymCryptFatal( 'ccp0' );
235 }
236
237 SymCryptInjectError( buf, sizeof( buf ) );
238 if ( memcmp( buf, SymCryptChaCha20Poly1305Result, sizeof( buf ) ) != 0 )
239 {
240 SymCryptFatal( 'ccp1' );
241 }
242
243 // Inject error into the ciphertext or tag.
244 SymCryptInjectError( buf, sizeof( buf ) );
245
249 buf, buf, 3,
252
253 if ( err != SYMCRYPT_NO_ERROR || memcmp( buf, SymCryptTestMsg3, 3 ) != 0 )
254 {
255 SymCryptFatal( 'ccp2' );
256 }
257}
VOID SYMCRYPT_CALL SymCryptChaCha20Poly1305Selftest(void)
SYMCRYPT_NOINLINE SYMCRYPT_ERROR SYMCRYPT_CALL SymCryptChaCha20Poly1305Encrypt(_In_reads_(cbKey) PCBYTE pbKey, SIZE_T cbKey, _In_reads_(cbNonce) PCBYTE pbNonce, SIZE_T cbNonce, _In_reads_opt_(cbAuthData) PCBYTE pbAuthData, SIZE_T cbAuthData, _In_reads_(cbData) PCBYTE pbSrc, _Out_writes_(cbData) PBYTE pbDst, SIZE_T cbData, _Out_writes_(cbTag) PBYTE pbTag, SIZE_T cbTag)
static const BYTE SymCryptChaCha20Poly1305Result[3+SYMCRYPT_POLY1305_RESULT_SIZE]
#define CHACHA20_POLY1305_MAX_DATA_SIZE
SYMCRYPT_NOINLINE SYMCRYPT_ERROR SYMCRYPT_CALL SymCryptChaCha20Poly1305Decrypt(_In_reads_(cbKey) PCBYTE pbKey, SIZE_T cbKey, _In_reads_(cbNonce) PCBYTE pbNonce, SIZE_T cbNonce, _In_reads_opt_(cbAuthData) PCBYTE pbAuthData, SIZE_T cbAuthData, _In_reads_(cbData) PCBYTE pbSrc, _Out_writes_(cbData) PBYTE pbDst, SIZE_T cbData, _In_reads_(cbTag) PCBYTE pbTag, SIZE_T cbTag)
const BOOL fcbDataLteMaxDataSizeStatic
VOID SYMCRYPT_CALL SymCryptChaCha20Poly1305ComputeTag(_Inout_ PSYMCRYPT_POLY1305_STATE pState, _In_reads_opt_(cbAuthData) PCBYTE pbAuthData, SIZE_T cbAuthData, _In_reads_(cbData) PCBYTE pbData, SIZE_T cbData, _Out_writes_(SYMCRYPT_POLY1305_RESULT_SIZE) PBYTE pbTag)
#define SIZE_T_MAX
Definition: dhcpd.h:91
static void cleanup(void)
Definition: main.c:1335
_ACRTIMP int __cdecl memcmp(const void *, const void *, size_t)
Definition: string.c:2807
unsigned int BOOL
Definition: ntddk_ex.h:94
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
#define _In_reads_(s)
Definition: no_sal2.h:168
#define _Inout_
Definition: no_sal2.h:162
#define _Out_writes_(s)
Definition: no_sal2.h:176
#define _In_reads_opt_(s)
Definition: no_sal2.h:222
BYTE * PBYTE
Definition: pedump.c:66
#define err(...)
const BYTE SymCryptTestMsg16[16]
Definition: selftest.c:15
VOID SYMCRYPT_CALL SymCryptInjectError(PBYTE pbData, SIZE_T cbData)
const BYTE SymCryptTestKey32[32]
Definition: selftest.c:10
const BYTE SymCryptTestMsg3[3]
Definition: selftest.c:8
Definition: copy.c:22
Definition: ps.c:97
VOID SYMCRYPT_CALL SymCryptPoly1305Result(_Inout_ PSYMCRYPT_POLY1305_STATE pState, _Out_writes_(SYMCRYPT_POLY1305_RESULT_SIZE) PBYTE pbResult)
Definition: poly1305.c:109
FORCEINLINE VOID SYMCRYPT_CALL SymCryptWipeKnownSize(_Out_writes_bytes_(cbData) PVOID pbData, SIZE_T cbData)
_Analysis_noreturn_ VOID SYMCRYPT_CALL SymCryptFatal(UINT32 fatalCode)
VOID SYMCRYPT_CALL SymCryptChaCha20Crypt(_Inout_ PSYMCRYPT_CHACHA20_STATE pState, _In_reads_(cbData) PCBYTE pbSrc, _Out_writes_(cbData) PBYTE pbDst, SIZE_T cbData)
Definition: chacha20.c:69
VOID SYMCRYPT_CALL SymCryptPoly1305Init(_Out_ PSYMCRYPT_POLY1305_STATE pState, _In_reads_(SYMCRYPT_POLY1305_KEY_SIZE) PCBYTE pbKey)
Definition: poly1305.c:33
#define SYMCRYPT_POLY1305_KEY_SIZE
Definition: symcrypt.h:3858
#define SYMCRYPT_POLY1305_BLOCK_SIZE
Definition: symcrypt.h:3857
VOID SYMCRYPT_CALL SymCryptChaCha20SetOffset(_Inout_ PSYMCRYPT_CHACHA20_STATE pState, UINT64 offset)
Definition: chacha20.c:59
VOID SYMCRYPT_CALL SymCryptPoly1305Append(_Inout_ PSYMCRYPT_POLY1305_STATE pState, _In_reads_(cbData) PCBYTE pbData, SIZE_T cbData)
Definition: poly1305.c:55
#define SYMCRYPT_POLY1305_RESULT_SIZE
Definition: symcrypt.h:3856
#define SYMCRYPT_STORE_LSBFIRST64(p, v)
Definition: symcrypt.h:308
BOOLEAN SYMCRYPT_CALL SymCryptEqual(_In_reads_(cbBytes) PCBYTE pbSrc1, _In_reads_(cbBytes) PCBYTE pbSrc2, SIZE_T cbBytes)
Definition: equal.c:11
SYMCRYPT_ERROR
Definition: symcrypt.h:227
SYMCRYPT_ERROR SYMCRYPT_CALL SymCryptChaCha20Init(_Out_ PSYMCRYPT_CHACHA20_STATE pState, _In_reads_(cbKey) PCBYTE pbKey, _In_ SIZE_T cbKey, _In_reads_(cbNonce) PCBYTE pbNonce, SIZE_T cbNonce, UINT64 offset)
Definition: chacha20.c:26
SIZE_T cbTag
#define SYMCRYPT_ALIGN
PCBYTE pbSrc
#define SYMCRYPT_CALL
SYMCRYPT_MAGIC_FIELD * PSYMCRYPT_POLY1305_STATE
PCBYTE pbKey
UINT64 cbAuthData
PCBYTE SIZE_T cbKey
PCBYTE PBYTE SIZE_T cbData
PCBYTE PBYTE pbDst
SIZE_T cbNonce
SYMCRYPT_CHACHA20_STATE
PSYMCRYPT_COMMON_HASH_STATE pState
const BYTE * PCBYTE
SYMCRYPT_MAGIC_FIELD SYMCRYPT_POLY1305_STATE
PCBYTE pbData
ULONG_PTR SIZE_T
Definition: typedefs.h:80
unsigned char BYTE
Definition: xxhash.c:193