Skip to content

Commit 9f9b715

Browse files
committed
Avoid zero IV for AES encryption in xcrypt
1 parent e104459 commit 9f9b715

File tree

11 files changed

+205
-27
lines changed

11 files changed

+205
-27
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
cmake_minimum_required(VERSION 3.5.0 FATAL_ERROR)
1+
cmake_minimum_required(VERSION 3.16)
22
project(libxutils LANGUAGES C)
33

44
if (WIN32)

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
- [Implementation of advanced file search](https://github.com/kala13x/libxutils/blob/main/src/sys/srch.h)
4646
- [System time manipulation library](https://github.com/kala13x/libxutils/blob/main/src/sys/xtime.h)
4747
- [Performance monitoring library](https://github.com/kala13x/libxutils/blob/main/src/sys/mon.h)
48-
- [File and directory operations](https://github.com/kala13x/libxutils/blob/main/src/sys/xfs.h)
4948
- [Simple and fast memory pool](https://github.com/kala13x/libxutils/blob/main/src/sys/pool.h)
5049
- [Advanced logging library](https://github.com/kala13x/libxutils/blob/main/src/sys/log.h)
5150

examples/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
cmake_minimum_required(VERSION 3.10)
1+
cmake_minimum_required(VERSION 3.16)
22
project(xutils)
33

44
set(CMAKE_C_STANDARD 11)

src/crypt/crypt.c

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,40 @@ static xbool_t XCrypt_NeedsKey(xcrypt_chipher_t eCipher)
306306
return XFALSE;
307307
}
308308

309+
static xbool_t XCrypt_NeedsIV(xcrypt_chipher_t eCipher)
310+
{
311+
switch (eCipher)
312+
{
313+
case XC_AES:
314+
return XTRUE;
315+
case XC_XOR:
316+
case XC_CASEAR:
317+
case XC_HS256:
318+
case XC_MD5_HMAC:
319+
#ifdef XCRYPT_USE_SSL
320+
case XC_RS256:
321+
case XC_RSAPR:
322+
case XC_RSA:
323+
#endif
324+
case XC_HEX:
325+
case XC_CRC32:
326+
case XC_BASE64:
327+
case XC_B64URL:
328+
case XC_MD5:
329+
case XC_SHA1:
330+
case XC_SHA256:
331+
case XC_REVERSE:
332+
case XC_MD5_SUM:
333+
case XC_SHA1_SUM:
334+
case XC_SHA256_SUM:
335+
return XFALSE;
336+
default:
337+
break;
338+
}
339+
340+
return XFALSE;
341+
}
342+
309343
void XCrypt_ErrorCallback(xcrypt_ctx_t *pCtx, const char *pStr, ...)
310344
{
311345
if (pCtx->callback == NULL) return;
@@ -324,10 +358,11 @@ xbool_t XCrypt_KeyCallback(xcrypt_ctx_t *pCtx, xcrypt_chipher_t eCipher, xcrypt_
324358
memset(pKey, 0, sizeof(xcrypt_key_t));
325359
pKey->eCipher = eCipher;
326360

327-
if (!XCrypt_NeedsKey(eCipher) ||
328-
pCtx->callback == NULL) return XTRUE;
361+
if (!XCrypt_NeedsKey(eCipher) || pCtx->callback == NULL) return XTRUE;
362+
if (!pCtx->callback(XCB_KEY, pKey, pCtx->pUserPtr)) return XFALSE;
329363

330-
return pCtx->callback(XCB_KEY, pKey, pCtx->pUserPtr);
364+
if (!XCrypt_NeedsIV(eCipher)) return XTRUE;
365+
return pCtx->callback(XCB_IV, pKey->sIV, pCtx->pUserPtr);
331366
}
332367

333368
void XCrypt_Init(xcrypt_ctx_t *pCtx, xbool_t bDecrypt, char *pCiphers, xcrypt_cb_t callback, void *pUser)
@@ -345,6 +380,7 @@ uint8_t* XCrypt_Single(xcrypt_ctx_t *pCtx, xcrypt_chipher_t eCipher, const uint8
345380
if (!XCrypt_KeyCallback(pCtx, eCipher, &encKey)) return XFALSE;
346381

347382
const uint8_t *pKey = (const uint8_t*)encKey.sKey;
383+
const uint8_t *pIV = (const uint8_t*)encKey.sIV;
348384
size_t nKeyLength = encKey.nLength;
349385

350386
uint8_t *pCrypted = NULL;
@@ -354,7 +390,7 @@ uint8_t* XCrypt_Single(xcrypt_ctx_t *pCtx, xcrypt_chipher_t eCipher, const uint8
354390
{
355391
case XC_CRC32: nCRC32 = XCRC32_Compute(pInput, *pLength); break;
356392
case XC_CRC32B: nCRC32 = XCRC32_ComputeB(pInput, *pLength); break;
357-
case XC_AES: pCrypted = XCrypt_AES(pInput, pLength, pKey, nKeyLength, NULL); break;
393+
case XC_AES: pCrypted = XCrypt_AES(pInput, pLength, pKey, nKeyLength, pIV); break;
358394
case XC_HEX: pCrypted = XCrypt_HEX(pInput, pLength, XSTR_SPACE, pCtx->nColumns, XFALSE); break;
359395
case XC_XOR: pCrypted = XCrypt_XOR(pInput, *pLength, pKey, nKeyLength); break;
360396
case XC_MD5: pCrypted = XMD5_Encrypt(pInput, *pLength); *pLength = XMD5_DIGEST_SIZE; break;
@@ -407,13 +443,14 @@ uint8_t* XDecrypt_Single(xcrypt_ctx_t *pCtx, xcrypt_chipher_t eCipher, const uin
407443
if (!XCrypt_KeyCallback(pCtx, eCipher, &decKey)) return XFALSE;
408444

409445
const uint8_t *pKey = (const uint8_t*)decKey.sKey;
446+
const uint8_t *pIV = (const uint8_t*)decKey.sIV;
410447
size_t nKeyLength = decKey.nLength;
411448
uint8_t *pDecrypted = NULL;
412449

413450
switch (eCipher)
414451
{
415452
case XC_HEX: pDecrypted = XDecrypt_HEX(pInput, pLength, XFALSE); break;
416-
case XC_AES: pDecrypted = XDecrypt_AES(pInput, pLength, pKey, nKeyLength, NULL); break;
453+
case XC_AES: pDecrypted = XDecrypt_AES(pInput, pLength, pKey, nKeyLength, pIV); break;
417454
case XC_XOR: pDecrypted = XCrypt_XOR(pInput, *pLength, pKey, nKeyLength); break;
418455
case XC_CASEAR: pDecrypted = (uint8_t*)XDecrypt_Casear((const char*)pInput, *pLength, atoi(decKey.sKey)); break;
419456
case XC_BASE64: pDecrypted = (uint8_t*)XBase64_Decrypt(pInput, pLength); break;

src/crypt/crypt.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,15 @@ typedef enum
6161
{
6262
XCB_INVALID = (uint8_t)0,
6363
XCB_ERROR,
64-
XCB_KEY
64+
XCB_KEY,
65+
XCB_IV
6566
} xcrypt_cb_type_t;
6667

6768
typedef struct XCryptKey
6869
{
6970
xcrypt_chipher_t eCipher;
7071
char sKey[XSTR_MIN];
72+
char sIV[XSTR_MICRO];
7173
size_t nLength;
7274
} xcrypt_key_t;
7375

src/data/str.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
#define XSTR_MIN 2048
6565
#define XSTR_TINY 256
6666
#define XSTR_MICRO 32
67+
#define XSTR_PICO 16
6768
#define XSTR_NPOS UINT_MAX
6869
#define XSTR_STACK XSTR_MID
6970

src/xver.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212

1313
#define XUTILS_VERSION_MAX 2
1414
#define XUTILS_VERSION_MIN 7
15-
#define XUTILS_BUILD_NUMBER 2
16-
#define XUTILS_BUILD_DATE "21Jun2025"
15+
#define XUTILS_BUILD_NUMBER 3
16+
#define XUTILS_BUILD_DATE "15Sep2025"
1717

1818
#ifdef __cplusplus
1919
extern "C" {

tools/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
cmake_minimum_required(VERSION 3.10)
1+
cmake_minimum_required(VERSION 3.16)
22
project(xutils)
33

44
set(CMAKE_C_STANDARD 11)

tools/xcrypt.c

Lines changed: 74 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
#define XCRYPT_VER_MAX 0
2626
#define XCRYPT_VER_MIN 1
27-
#define XCRYPT_BUILD_NUM 22
27+
#define XCRYPT_BUILD_NUM 23
2828

2929
#define XAES_KEY_LENGTH 256
3030
#define XHEX_COLUMNS 16
@@ -39,6 +39,7 @@ typedef struct
3939
char sText[XSTR_MID];
4040
char sPair[XSTR_MID];
4141
char sKey[XSTR_MID];
42+
char sIV[XSTR_MICRO];
4243

4344
size_t nKeySize;
4445
xbool_t bDecrypt;
@@ -104,17 +105,17 @@ static void XCrypt_DisplayUsage(const char *pName)
104105
bRSA = XTRUE;
105106
#endif
106107

107-
const char *pRSAOption = bRSA ? "[-g <pub:priv>]" : XSTR_EMPTY;
108+
const char *pRSAOption = bRSA ? " [-g <pub:priv>]" : XSTR_EMPTY;
108109
const char *pRSADesc = bRSA ? "and RSA" : XSTR_EMPTY;
109110

110-
xlog("==========================================================");
111+
xlog("============================================================");
111112
xlog(" Crypt/Decrypt file or text - v%d.%d build %d (%s)",
112113
XCRYPT_VER_MAX, XCRYPT_VER_MIN, XCRYPT_BUILD_NUM, __DATE__);
113-
xlog("==========================================================");
114+
xlog("============================================================");
114115

115-
xlog("Usage: %s [-c <ciphers>] [-i <input>] [-o <output>]", pName);
116-
xlog(" %s [-K <keyfile>] [-k <key>] %s", XCrypt_WhiteSpace(nLength), pRSAOption);
117-
xlog(" %s [-t <text>] [-d] [-f] [-p] [-s] [-h] [-v]\n", XCrypt_WhiteSpace(nLength));
116+
xlog("Usage: %s [-c <ciphers>] [-i <input>] [-o <output>] [-v]", pName);
117+
xlog(" %s [-K <keyfile>] [-k <key>]%s [-x]", XCrypt_WhiteSpace(nLength), pRSAOption);
118+
xlog(" %s [-t <text>] [-I <iv>] [-d] [-f] [-p] [-s] [-h]\n", XCrypt_WhiteSpace(nLength));
118119

119120
xlog("Options are:");
120121
xlog(" -c <ciphers> # Encryption or decryption ciphers (%s*%s)", XSTR_CLR_RED, XSTR_FMT_RESET);
@@ -126,6 +127,7 @@ static void XCrypt_DisplayUsage(const char *pName)
126127
xlog(" -K <keyfile> # File path containing the key");
127128
xlog(" -k <key> # The key to pass as an argument");
128129
xlog(" -t <text> # Input text to pass as an argument");
130+
xlog(" -I <iv> # Initialization vector for AES");
129131
xlog(" -d # Decryption mode");
130132
xlog(" -f # Force overwrite output");
131133
xlog(" -s # Key size for AES %s", pRSADesc);
@@ -296,6 +298,60 @@ static xbool_t XCrypt_GetKey(xcrypt_args_t *pArgs, xcrypt_key_t *pKey)
296298
return XCrypt_SetKey(pArgs, pKey, nLength);
297299
}
298300

301+
static xbool_t XCrypt_GetIV(xcrypt_args_t *pArgs, xcrypt_key_t *pKey)
302+
{
303+
if (xstrused(pArgs->sIV))
304+
{
305+
size_t nLength = xstrncpy(pKey->sIV, sizeof(pKey->sIV), pArgs->sIV);
306+
if (nLength < 16)
307+
{
308+
xlogw("IV is too short, will be padded with zero bytes");
309+
memset(pKey->sIV + nLength, 0, 16 - nLength);
310+
}
311+
312+
return XTRUE;
313+
}
314+
315+
char sIV[XSTR_PICO];
316+
sIV[0] = XSTR_NUL;
317+
318+
const char *pCipher = XCrypt_GetCipherStr(pKey->eCipher);
319+
printf("Enter IV for the cipher '%s': ", pCipher);
320+
321+
if (!XCLI_GetPass(NULL, pKey->sIV, sizeof(pKey->sIV)))
322+
{
323+
xloge("Failed to read IV: %d", errno);
324+
return XFALSE;
325+
}
326+
327+
if (!pArgs->bDecrypt || pArgs->bForce)
328+
{
329+
printf("Re-enter IV for the cipher '%s': ", pCipher);
330+
sIV[0] = XSTR_NUL;
331+
332+
if (!XCLI_GetPass(NULL, sIV, sizeof(sIV)))
333+
{
334+
xloge("Failed to read IV: %d", errno);
335+
return XFALSE;
336+
}
337+
338+
if (strcmp(pKey->sIV, sIV))
339+
{
340+
xloge("IV do not match");
341+
return XFALSE;
342+
}
343+
}
344+
345+
size_t nLength = strlen(pKey->sIV);
346+
if (nLength < 16)
347+
{
348+
xlogw("IV is too short, will be padded with zero bytes");
349+
memset(pKey->sIV + nLength, 0, 16 - nLength);
350+
}
351+
352+
return XTRUE;
353+
}
354+
299355
static XSTATUS XCrypt_ValidateArgs(xcrypt_args_t *pArgs)
300356
{
301357
if (xstrused(pArgs->sPair))
@@ -376,7 +432,7 @@ static xbool_t XCrypt_ParseArgs(xcrypt_args_t *pArgs, int argc, char *argv[])
376432
memset(pArgs, 0, sizeof(xcrypt_args_t));
377433
int nChar = 0;
378434

379-
while ((nChar = getopt(argc, argv, "c:i:o:g:k:K:t:s:d1:f1:h1:p1:s1:x1:v1")) != -1)
435+
while ((nChar = getopt(argc, argv, "c:i:o:g:k:K:I:t:s:d1:f1:h1:p1:s1:x1:v1")) != -1)
380436
{
381437
switch (nChar)
382438
{
@@ -400,6 +456,9 @@ static xbool_t XCrypt_ParseArgs(xcrypt_args_t *pArgs, int argc, char *argv[])
400456
case 'K':
401457
xstrncpy(pArgs->sKeyFile, sizeof(pArgs->sKeyFile), optarg);
402458
break;
459+
case 'I':
460+
xstrncpy(pArgs->sIV, sizeof(pArgs->sIV), optarg);
461+
break;
403462
case 't':
404463
xstrncpy(pArgs->sText, sizeof(pArgs->sText), optarg);
405464
break;
@@ -470,6 +529,13 @@ xbool_t XCrypt_Callback(xcrypt_cb_type_t eType, void *pData, void *pCtx)
470529
xcrypt_key_t *pKey = (xcrypt_key_t*)pData;
471530
return XCrypt_GetKey(pArgs, pKey);
472531
}
532+
else if (eType == XCB_IV)
533+
{
534+
xcrypt_args_t *pArgs = (xcrypt_args_t*)pCtx;
535+
xcrypt_key_t *pKey = (xcrypt_key_t*)pData;
536+
return XCrypt_GetIV(pArgs, pKey);
537+
}
538+
473539

474540
xloge("%s (%d)", (const char*)pData, errno);
475541
return XFALSE;

0 commit comments

Comments
 (0)