@@ -512,14 +512,21 @@ static bool _fle2_placeholder_aes_aead_encrypt(_mongocrypt_key_broker_t *kb,
512
512
// ECCDerivedFromDataTokenAndContentionFactor)
513
513
// FLE V2: p := EncryptCTR(ECOCToken, ESCDerivedFromDataTokenAndContentionFactor)
514
514
// Range V2: p := EncryptCTR(ECOCToken, ESCDerivedFromDataTokenAndContentionFactor || isLeaf)
515
+ // Text search: p := EncryptCTR(ECOCToken, ESCDerivedFromDataTokenAndContentionFactor || msize)
516
+ struct encrypted_token_metadata {
517
+ mc_optional_bool_t is_leaf ; // isLeaf for Range V2, none for all other cases
518
+ mc_optional_uint32_t msize ; // msize for text search, none for all other cases
519
+ };
520
+
515
521
static bool _fle2_derive_encrypted_token (_mongocrypt_crypto_t * crypto ,
516
522
_mongocrypt_buffer_t * out ,
517
- bool concatentate_leaf ,
518
523
const mc_CollectionsLevel1Token_t * collectionsLevel1Token ,
519
524
const _mongocrypt_buffer_t * escDerivedToken ,
520
525
const _mongocrypt_buffer_t * eccDerivedToken ,
521
- mc_optional_bool_t is_leaf ,
526
+ struct encrypted_token_metadata token_metadata ,
522
527
mongocrypt_status_t * status ) {
528
+ // isLeaf and msize should never both be set.
529
+ BSON_ASSERT (!token_metadata .is_leaf .set || !token_metadata .msize .set );
523
530
mc_ECOCToken_t * ecocToken = mc_ECOCToken_new (crypto , collectionsLevel1Token , status );
524
531
if (!ecocToken ) {
525
532
return false;
@@ -531,10 +538,10 @@ static bool _fle2_derive_encrypted_token(_mongocrypt_crypto_t *crypto,
531
538
const _mongocrypt_buffer_t * p = & tmp ;
532
539
if (!eccDerivedToken ) {
533
540
// FLE2v2
534
- if (concatentate_leaf && is_leaf .set ) {
541
+ if (token_metadata . is_leaf .set ) {
535
542
// Range V2; concat isLeaf
536
543
_mongocrypt_buffer_t isLeafBuf ;
537
- if (!_mongocrypt_buffer_copy_from_data_and_size (& isLeafBuf , (uint8_t []){is_leaf .value }, 1 )) {
544
+ if (!_mongocrypt_buffer_copy_from_data_and_size (& isLeafBuf , (uint8_t []){token_metadata . is_leaf .value }, 1 )) {
538
545
CLIENT_ERR ("failed to create is_leaf buffer" );
539
546
goto fail ;
540
547
}
@@ -544,6 +551,21 @@ static bool _fle2_derive_encrypted_token(_mongocrypt_crypto_t *crypto,
544
551
goto fail ;
545
552
}
546
553
_mongocrypt_buffer_cleanup (& isLeafBuf );
554
+ } else if (token_metadata .msize .set ) {
555
+ // Text search; concat msize
556
+ _mongocrypt_buffer_t msizeBuf ;
557
+ // msize is a 3-byte value, so copy the 3 least significant bytes into the buffer in little-endian order.
558
+ uint32_t le_msize = BSON_UINT32_TO_LE (token_metadata .msize .value );
559
+ if (!_mongocrypt_buffer_copy_from_data_and_size (& msizeBuf , (uint8_t * )& le_msize , 3 )) {
560
+ CLIENT_ERR ("failed to create msize buffer" );
561
+ goto fail ;
562
+ }
563
+ if (!_mongocrypt_buffer_concat (& tmp , (_mongocrypt_buffer_t []){* escDerivedToken , msizeBuf }, 2 )) {
564
+ CLIENT_ERR ("failed to allocate buffer" );
565
+ _mongocrypt_buffer_cleanup (& msizeBuf );
566
+ goto fail ;
567
+ }
568
+ _mongocrypt_buffer_cleanup (& msizeBuf );
547
569
} else {
548
570
p = escDerivedToken ;
549
571
}
@@ -753,16 +775,23 @@ static bool _mongocrypt_fle2_placeholder_to_insert_update_common(_mongocrypt_key
753
775
754
776
// p := EncryptCTR(ECOCToken, ESCDerivedFromDataTokenAndContentionFactor)
755
777
// Or in Range V2, when using range: p := EncryptCTR(ECOCToken, ESCDerivedFromDataTokenAndContentionFactor || 0x00)
756
- if (!_fle2_derive_encrypted_token (
757
- crypto ,
758
- & out -> encryptedTokens ,
759
- true,
760
- common -> collectionsLevel1Token ,
761
- & out -> escDerivedToken ,
762
- NULL , // unused in v2
763
- // If this is a range insert, we append isLeaf to the encryptedTokens. Otherwise, we don't.
764
- placeholder -> algorithm == MONGOCRYPT_FLE2_ALGORITHM_RANGE ? OPT_BOOL (false) : (mc_optional_bool_t ){0 },
765
- status )) {
778
+ // Or in Text Search, when using msize: p := EncryptCTR(ECOCToken, ESCDerivedFromDataTokenAndContentionFactor ||
779
+ // 0x000000)
780
+ struct encrypted_token_metadata et_meta = {{0 }};
781
+ if (placeholder -> algorithm == MONGOCRYPT_FLE2_ALGORITHM_RANGE ) {
782
+ // For range, we append isLeaf to the encryptedTokens.
783
+ et_meta .is_leaf = OPT_BOOL (false);
784
+ } else if (placeholder -> algorithm == MONGOCRYPT_FLE2_ALGORITHM_TEXT_SEARCH ) {
785
+ // For text search, we append msize to the encryptedTokens.
786
+ et_meta .msize = OPT_U32 (0 );
787
+ }
788
+ if (!_fle2_derive_encrypted_token (crypto ,
789
+ & out -> encryptedTokens ,
790
+ common -> collectionsLevel1Token ,
791
+ & out -> escDerivedToken ,
792
+ NULL , // unused in v2
793
+ et_meta ,
794
+ status )) {
766
795
goto fail ;
767
796
}
768
797
@@ -1021,11 +1050,10 @@ static bool _mongocrypt_fle2_placeholder_to_insert_update_ciphertextForRange(_mo
1021
1050
// Or in Range V2: p := EncryptCTR(ECOCToken, ESCDerivedFromDataTokenAndContentionFactor || isLeaf)
1022
1051
if (!_fle2_derive_encrypted_token (kb -> crypt -> crypto ,
1023
1052
& etc .encryptedTokens ,
1024
- true,
1025
1053
edge_tokens .collectionsLevel1Token ,
1026
1054
& etc .escDerivedToken ,
1027
1055
NULL , // ecc unsed in FLE2v2
1028
- OPT_BOOL (is_leaf ),
1056
+ ( struct encrypted_token_metadata ){. is_leaf = OPT_BOOL (is_leaf )} ,
1029
1057
status )) {
1030
1058
goto fail_loop ;
1031
1059
}
@@ -1087,6 +1115,7 @@ static bool _mongocrypt_fle2_placeholder_to_insert_update_ciphertextForRange(_mo
1087
1115
mc_Text##Type##TokenSet_t *out, \
1088
1116
const _mongocrypt_buffer_t *value, \
1089
1117
int64_t contentionFactor, \
1118
+ uint32_t msize, \
1090
1119
const mc_CollectionsLevel1Token_t *collLevel1Token, \
1091
1120
const mc_ServerTokenDerivationLevel1Token_t *serverLevel1Token, \
1092
1121
mongocrypt_status_t *status) { \
@@ -1124,11 +1153,10 @@ static bool _mongocrypt_fle2_placeholder_to_insert_update_ciphertextForRange(_mo
1124
1153
} \
1125
1154
if (!_fle2_derive_encrypted_token(kb->crypt->crypto, \
1126
1155
&out->encryptedTokens, \
1127
- false, \
1128
1156
collLevel1Token, \
1129
1157
&out->escDerivedToken, \
1130
1158
NULL, \
1131
- (mc_optional_bool_t){0}, \
1159
+ (struct encrypted_token_metadata){.msize = OPT_U32(msize)}, \
1132
1160
status)) { \
1133
1161
return false; \
1134
1162
} \
@@ -1230,6 +1258,8 @@ static bool _fle2_generate_TextSearchTokenSets(_mongocrypt_key_broker_t *kb,
1230
1258
& tsts -> exact ,
1231
1259
& asBsonValue ,
1232
1260
contentionFactor ,
1261
+ // For the exact token, report total msize of the token set.
1262
+ encodeSets -> msize ,
1233
1263
common .collectionsLevel1Token ,
1234
1264
common .serverTokenDerivationLevel1Token ,
1235
1265
status )) {
@@ -1258,10 +1288,12 @@ static bool _fle2_generate_TextSearchTokenSets(_mongocrypt_key_broker_t *kb,
1258
1288
_mongocrypt_buffer_init (& asBsonValue );
1259
1289
_mongocrypt_buffer_copy_from_string_as_bson_value (& asBsonValue , substring , (int )bytelen );
1260
1290
1291
+ // For substring, prefix, and suffix tokens, report 0 as the msize.
1261
1292
if (!_fle2_generate_TextSubstringTokenSet (kb ,
1262
1293
& tset ,
1263
1294
& asBsonValue ,
1264
1295
contentionFactor ,
1296
+ 0 /* msize */ ,
1265
1297
common .collectionsLevel1Token ,
1266
1298
common .serverTokenDerivationLevel1Token ,
1267
1299
status )) {
@@ -1302,6 +1334,7 @@ static bool _fle2_generate_TextSearchTokenSets(_mongocrypt_key_broker_t *kb,
1302
1334
& tset ,
1303
1335
& asBsonValue ,
1304
1336
contentionFactor ,
1337
+ 0 /* msize */ ,
1305
1338
common .collectionsLevel1Token ,
1306
1339
common .serverTokenDerivationLevel1Token ,
1307
1340
status )) {
@@ -1342,6 +1375,7 @@ static bool _fle2_generate_TextSearchTokenSets(_mongocrypt_key_broker_t *kb,
1342
1375
& tset ,
1343
1376
& asBsonValue ,
1344
1377
contentionFactor ,
1378
+ 0 /* msize */ ,
1345
1379
common .collectionsLevel1Token ,
1346
1380
common .serverTokenDerivationLevel1Token ,
1347
1381
status )) {
@@ -1543,16 +1577,15 @@ static bool _mongocrypt_fle2_placeholder_to_insert_update_ciphertextForTextSearc
1543
1577
_mongocrypt_buffer_copy_to (& payload .edcDerivedToken , & payload .escDerivedToken );
1544
1578
_mongocrypt_buffer_copy_to (& payload .edcDerivedToken , & payload .serverDerivedFromDataToken );
1545
1579
1546
- // p := EncryptCTR(ECOCToken, ESCDerivedFromDataTokenAndContentionFactor)
1580
+ // p := EncryptCTR(ECOCToken, ESCDerivedFromDataTokenAndContentionFactor | 0x000000 )
1547
1581
// Since p is never used for text search, this just sets p to a bogus ciphertext of
1548
1582
// the correct length.
1549
1583
if (!_fle2_derive_encrypted_token (kb -> crypt -> crypto ,
1550
1584
& payload .encryptedTokens ,
1551
- false,
1552
1585
common .collectionsLevel1Token ,
1553
1586
& payload .escDerivedToken , // bogus
1554
1587
NULL , // unused in FLE2v2
1555
- (mc_optional_bool_t ){ 0 },
1588
+ (struct encrypted_token_metadata ){. msize = OPT_U32 ( 0 ) },
1556
1589
status )) {
1557
1590
goto fail ;
1558
1591
}
0 commit comments