Skip to content

Commit 24b228c

Browse files
Merged PR 11762034: Implement AES-KW(P)
Implement AES-KW and AES-KWP per SP800-38F Related work items: #43968124
1 parent 228c892 commit 24b228c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+123227
-122288
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ New changes will be listed here as they are developed. The version number is det
44
prior to the creation of a new release, based on the changes contained in that release.
55

66
- Add LMS implementation
7+
- Add AES-KW(P) implementation
78

89
# Version 103.5.1
910

doc/breaking_changes.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,12 @@ This simplifies how we define dynamic module exports in a cross-platform way.
3232
### Self-test functions and definitions will no longer be exposed/exported
3333
Various functions and definitions related to FIPS self-tests are exposed to callers in
3434
symcrypt_internal.h, and exported from the shared object libraries/DLLs. These functions are only
35-
intended to be used internally for FIPS compliance, so they will be removed from external visibility.
35+
intended to be used internally for FIPS compliance, so they will be removed from external visibility.
36+
37+
### Several type definitions in symcrypt_internal.h may be updated or removed
38+
There are several struct definitions with specifics sizes and alignments that a caller should never need
39+
to use directly in their code (rather than just handling pointers to these structs). A good example would be
40+
SYMCRYPT_ECPOINT. Exposing these definitions in symcrypt_internal.h means that we cannot change the
41+
definitions without making a breaking callers, so we will remove them in a breaking change.
42+
At the same time, we may also update the sizes and alignment of structs that callers may need to use directly;
43+
in particular we should consider removing the concept of SYMCRYPT_ASYM_ALIGN entirely.

inc/symcrypt.h

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6001,6 +6001,174 @@ VOID
60016001
SYMCRYPT_CALL
60026002
SymCryptXtsAesSelftest(void);
60036003

6004+
////////////////////////////////////////////////////////////////////////////////////////////
6005+
//
6006+
// AES-KW and AES-KWP
6007+
//
6008+
// These are the AES-KW and AES-KWP algorithms per SP 800-38F.
6009+
//
6010+
// These are very slow compared to most AES modes, requiring a long serial chain of AES
6011+
// block encryption/decryptions, with a best case cost comparable to ~12x AES-CBC encryption
6012+
// for a given buffer size. In practice the cost is often higher.
6013+
// These cipher modes are not recommended.
6014+
//
6015+
6016+
SYMCRYPT_ERROR
6017+
SYMCRYPT_CALL
6018+
SymCryptAesKwEncrypt(
6019+
_In_ PCSYMCRYPT_AES_EXPANDED_KEY pExpandedKey,
6020+
_In_reads_(cbSrc) PCBYTE pbSrc,
6021+
SIZE_T cbSrc,
6022+
_Out_writes_to_(cbDst, *pcbResult) PBYTE pbDst,
6023+
SIZE_T cbDst,
6024+
_Out_ SIZE_T* pcbResult );
6025+
//
6026+
// Encrypt a buffer using AES-KW mode.
6027+
//
6028+
// - pExpandedKey points to the expanded key to use.
6029+
// - pbSrc is the plaintext source buffer. The source and destination buffers may be
6030+
// identical (in-place encryption) or non-overlapping, but they may not partially overlap.
6031+
// - cbSrc. # bytes of plaintext. This must be a multiple of 8, >=16, and <2^31.
6032+
// - pbDst is the ciphertext destination buffer. The source and destination buffers may be
6033+
// identical (in-place encryption) or non-overlapping, but they may not partially overlap.
6034+
// - cbDst. # bytes in the destination buffer. This must be >= cbSrc+8.
6035+
// - pcbResult pointer to a variable which receives the length of the ciphertext written to pbDst.
6036+
//
6037+
// Returns:
6038+
// SYMCRYPT_INVALID_ARGUMENT : If cbSrc is an invalid size
6039+
// SYMCRYPT_BUFFER_TOO_SMALL : If cbDst is not large enough
6040+
// (this can always be avoided if cbDst >= cbSrc+8)
6041+
// SYMCRYPT_MEMORY_ALLOCATION_FAILURE : If there is insufficient memory for the operation
6042+
// SYMCRYPT_NO_ERROR : On success
6043+
//
6044+
// Remarks:
6045+
// The standard allows larger plaintexts but there is no requirement to support them, we only support
6046+
// plaintext up to 2^31 bytes because it avoids complexity in handling overflow of 32b buffer sizes, and
6047+
// is larger than practically necessary.
6048+
// The output parameters (pbDst and pcbResult) are only set on success.
6049+
//
6050+
6051+
SYMCRYPT_ERROR
6052+
SYMCRYPT_CALL
6053+
SymCryptAesKwDecrypt(
6054+
_In_ PCSYMCRYPT_AES_EXPANDED_KEY pExpandedKey,
6055+
_In_reads_(cbSrc) PCBYTE pbSrc,
6056+
SIZE_T cbSrc,
6057+
_Out_writes_to_(cbDst, *pcbResult) PBYTE pbDst,
6058+
SIZE_T cbDst,
6059+
_Out_ SIZE_T* pcbResult );
6060+
//
6061+
// Decrypt a buffer using AES-KW mode.
6062+
//
6063+
// - pExpandedKey points to the expanded key to use.
6064+
// - pbSrc is the ciphertext source buffer. The source and destination buffers may be
6065+
// identical (in-place decryption) or non-overlapping, but they may not partially overlap.
6066+
// - cbSrc. # bytes of ciphertext. This must be a multiple of 8, >=24, and <=2^31.
6067+
// - pbDst is the plaintext destination buffer. The source and destination buffers may be
6068+
// identical (in-place decryption) or non-overlapping, but they may not partially overlap.
6069+
// - cbDst. # bytes in the destination buffer. This must be >= cbSrc-8.
6070+
// - pcbResult pointer to a variable which receives the length of the plaintext written to pbDst.
6071+
//
6072+
// Returns:
6073+
// SYMCRYPT_INVALID_ARGUMENT : If cbSrc is an invalid size
6074+
// SYMCRYPT_BUFFER_TOO_SMALL : If cbDst is not large enough
6075+
// (this can always be avoided if cbDst >= cbSrc-8)
6076+
// SYMCRYPT_AUTHENTICATION_FAILURE : If pbSrc does not decrypt successfully
6077+
// SYMCRYPT_MEMORY_ALLOCATION_FAILURE : If there is insufficient memory for the operation
6078+
// SYMCRYPT_NO_ERROR : On success
6079+
//
6080+
// Remarks:
6081+
// The standard allows larger plaintexts but there is no requirement to support them, we only support
6082+
// plaintext up to 2^31 bytes because it avoids complexity in handling overflow of 32b buffer sizes, and
6083+
// is larger than practically necessary.
6084+
// The output parameters (pbDst and pcbResult) are only set on success.
6085+
//
6086+
6087+
SYMCRYPT_ERROR
6088+
SYMCRYPT_CALL
6089+
SymCryptAesKwpEncrypt(
6090+
_In_ PCSYMCRYPT_AES_EXPANDED_KEY pExpandedKey,
6091+
_In_reads_(cbSrc) PCBYTE pbSrc,
6092+
SIZE_T cbSrc,
6093+
_Out_writes_to_(cbDst, *pcbResult) PBYTE pbDst,
6094+
SIZE_T cbDst,
6095+
_Out_ SIZE_T* pcbResult );
6096+
//
6097+
// Encrypt a buffer using AES-KWP mode.
6098+
//
6099+
// - pExpandedKey points to the expanded key to use.
6100+
// - pbSrc is the plaintext source buffer. The source and destination buffers may be
6101+
// identical (in-place encryption) or non-overlapping, but they may not partially overlap.
6102+
// - cbSrc. # bytes of plaintext. This must be >0 and <=2^31-8.
6103+
// - pbDst is the ciphertext destination buffer. The source and destination buffers may be
6104+
// identical (in-place encryption) or non-overlapping, but they may not partially overlap.
6105+
// - cbDst. # bytes in the destination buffer. This must be >= cbSrc + 16 - (cbSrc%8) - ((cbSrc%8)==0 ? 8 : 0)
6106+
// - pcbResult pointer to a variable which receives the length of the ciphertext written to pbDst.
6107+
//
6108+
// Returns:
6109+
// SYMCRYPT_INVALID_ARGUMENT : If cbSrc is an invalid size
6110+
// SYMCRYPT_BUFFER_TOO_SMALL : If cbDst is not large enough
6111+
// (this can always be avoided if cbDst >= cbSrc+15)
6112+
// SYMCRYPT_MEMORY_ALLOCATION_FAILURE : If there is insufficient memory for the operation
6113+
// SYMCRYPT_NO_ERROR : On success
6114+
//
6115+
// Remarks:
6116+
// The standard allows larger plaintexts but there is no requirement to support them, we only support
6117+
// plaintext up to 2^31 bytes because it avoids complexity in handling overflow of 32b buffer sizes, and
6118+
// is larger than practically necessary.
6119+
// The output parameters (pbDst and pcbResult) are only set on success.
6120+
//
6121+
6122+
SYMCRYPT_ERROR
6123+
SYMCRYPT_CALL
6124+
SymCryptAesKwpDecrypt(
6125+
_In_ PCSYMCRYPT_AES_EXPANDED_KEY pExpandedKey,
6126+
_In_reads_(cbSrc) PCBYTE pbSrc,
6127+
SIZE_T cbSrc,
6128+
_Out_writes_to_(cbDst, *pcbResult) PBYTE pbDst,
6129+
SIZE_T cbDst,
6130+
_Out_ SIZE_T* pcbResult );
6131+
//
6132+
// Decrypt a buffer using AES-KWP mode.
6133+
//
6134+
// - pExpandedKey points to the expanded key to use.
6135+
// - pbSrc is the ciphertext source buffer. The source and destination buffers may be
6136+
// identical (in-place decryption) or non-overlapping, but they may not partially overlap.
6137+
// - cbSrc. # bytes of ciphertext. This must be a multiple of 8, >=16, and <=2^31.
6138+
// - pbDst is the plaintext destination buffer. The source and destination buffers may be
6139+
// identical (in-place decryption) or non-overlapping, but they may not partially overlap.
6140+
// - cbDst. # bytes in the destination buffer. This must be large enough to fit the plaintext,
6141+
// a valid plaintext length is in the range [cbSrc-15, cbSrc-8]. If cbDst >= cbSrc-8 then the
6142+
// destination buffer is guaranteed to be large enough.
6143+
// - pcbResult pointer to a variable which receives the length of the plaintext written to pbDst.
6144+
//
6145+
// Returns:
6146+
// SYMCRYPT_INVALID_ARGUMENT : If cbSrc is an invalid size
6147+
// SYMCRYPT_BUFFER_TOO_SMALL : If cbDst is not large enough
6148+
// (this can always be avoided if cbDst >= cbSrc-8)
6149+
// SYMCRYPT_AUTHENTICATION_FAILURE : If pbSrc does not decrypt successfully
6150+
// SYMCRYPT_MEMORY_ALLOCATION_FAILURE : If there is insufficient memory for the operation
6151+
// SYMCRYPT_NO_ERROR : On success
6152+
//
6153+
// Remarks:
6154+
// The standard allows larger plaintexts but there is no requirement to support them, we only support
6155+
// plaintext up to 2^31 bytes because it avoids complexity in handling overflow of 32b buffer sizes, and
6156+
// is larger than practically necessary.
6157+
// The output parameters (pbDst and pcbResult) are only set on success.
6158+
//
6159+
// If we fail to decrypt due to bad data, we return SYMCRYPT_AUTHENTICATION_FAILURE in constant time with
6160+
// respect to how the decrypted data is corrupted. While there is no known attack on AES-KWP abusing
6161+
// differential timing of different failure cases, being constant time for this is cheap, so is a reasonable
6162+
// hardening measure.
6163+
//
6164+
// On success we do not attempt to hide the plaintext length from sidechannels, as this could make it hard
6165+
// for callers with known plaintext length to use precisely sized buffers to decrypt into (i.e. caller
6166+
// knows the valid plaintext is 15 bytes but the API would require caller to provide a 16 byte pbDst). It
6167+
// is expected that in any real use case the length of the plaintext would immediately be used to import the
6168+
// unwrapped key into some other piece of code - so attempting to obscure the plaintext length would not be
6169+
// of any benefit.
6170+
//
6171+
60046172

60056173
////////////////////////////////////////////////////////////////////////////////////////////
60066174
//

inc/symcrypt_internal.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -292,17 +292,15 @@ C_ASSERT( (SYMCRYPT_ALIGN_VALUE & (SYMCRYPT_ALIGN_VALUE - 1 )) == 0 );
292292

293293
#if SYMCRYPT_MS_VC
294294
#define SYMCRYPT_ALIGN_AT(alignment) __declspec(align(alignment))
295-
#define SYMCRYPT_ALIGN_TYPE_AT(typename, alignment) typename SYMCRYPT_ALIGN_AT(alignment)
296295
#define SYMCRYPT_WEAK_SYMBOL
297296
#elif SYMCRYPT_GNUC
298297
#define SYMCRYPT_ALIGN_AT(alignment) __attribute__((aligned(alignment)))
299-
#define SYMCRYPT_ALIGN_TYPE_AT(typename, alignment) typename SYMCRYPT_ALIGN_AT(alignment)
300298
#define SYMCRYPT_WEAK_SYMBOL __attribute__((weak))
301299
#else
302300
#define SYMCRYPT_ALIGN_AT(alignment)
303-
#define SYMCRYPT_ALIGN_TYPE_AT(typename, alignment) typename
304301
#define SYMCRYPT_WEAK_SYMBOL
305302
#endif
303+
#define SYMCRYPT_ALIGN_TYPE_AT(typename, alignment) typename SYMCRYPT_ALIGN_AT(alignment)
306304
#define SYMCRYPT_ALIGN SYMCRYPT_ALIGN_AT(SYMCRYPT_ALIGN_VALUE)
307305
#define SYMCRYPT_ALIGN_STRUCT SYMCRYPT_ALIGN_TYPE_AT(struct, SYMCRYPT_ALIGN_VALUE)
308306
#define SYMCRYPT_ALIGN_UNION SYMCRYPT_ALIGN_TYPE_AT(union, SYMCRYPT_ALIGN_VALUE)
@@ -2050,11 +2048,10 @@ typedef const SYMCRYPT_SSKDF_MAC_EXPANDED_SALT *PCSYMCRYPT_SSKDF_MAC_EXPANDED_SA
20502048
//
20512049
// These objects are all aligned to SYMCRYPT_ASYM_ALIGN
20522050
//
2051+
#define SYMCRYPT_ASYM_ALIGN SYMCRYPT_ALIGN_AT(SYMCRYPT_ASYM_ALIGN_VALUE)
20532052
#if SYMCRYPT_MS_VC
2054-
#define SYMCRYPT_ASYM_ALIGN __declspec(align(SYMCRYPT_ASYM_ALIGN_VALUE))
20552053
#define SYMCRYPT_ASYM_ALIGN_STRUCT SYMCRYPT_ASYM_ALIGN struct
20562054
#elif SYMCRYPT_GNUC
2057-
#define SYMCRYPT_ASYM_ALIGN __attribute__((aligned(SYMCRYPT_ASYM_ALIGN_VALUE)))
20582055
#define SYMCRYPT_ASYM_ALIGN_STRUCT struct SYMCRYPT_ASYM_ALIGN
20592056
#else
20602057
#error Unknown compiler

lib/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ set(SOURCES_COMMON
1212
aes-ymm.c
1313
aescmac.c
1414
aesCtrDrbg.c
15+
aeskw.c
1516
AesTables.c
1617
blockciphermodes.c
1718
ccm.c

0 commit comments

Comments
 (0)