6868#include < openssl/rand.h>
6969#include < openssl/sha.h>
7070#include < openssl/span.h>
71+ #include < openssl/digest.h>
7172
7273#include " ../internal.h"
7374#include " ../test/file_test.h"
@@ -127,6 +128,8 @@ static const EVP_CIPHER *GetCipher(const std::string &name) {
127128 return EVP_aes_192_ccm ();
128129 } else if (name == " AES-256-CCM" ) {
129130 return EVP_aes_256_ccm ();
131+ } else if (name == " XAES-256-GCM" ) {
132+ return EVP_xaes_256_gcm ();
130133 }
131134 return nullptr ;
132135}
@@ -1080,6 +1083,7 @@ TEST(CipherTest, GetCipher) {
10801083 test_get_cipher (NID_aes_256_ctr, " aes-256-ctr" );
10811084 test_get_cipher (NID_aes_256_ecb, " aes-256-ecb" );
10821085 test_get_cipher (NID_aes_256_gcm, " aes-256-gcm" );
1086+ test_get_cipher (NID_xaes_256_gcm, " xaes-256-gcm" );
10831087 test_get_cipher (NID_aes_256_ofb128, " aes-256-ofb" );
10841088 test_get_cipher (NID_aes_256_xts, " aes-256-xts" );
10851089 test_get_cipher (NID_chacha20_poly1305, " chacha20-poly1305" );
@@ -1102,6 +1106,7 @@ TEST(CipherTest, GetCipher) {
11021106 test_get_cipher (NID_aes_128_gcm, " id-aes128-gcm" );
11031107 test_get_cipher (NID_aes_192_gcm, " id-aes192-gcm" );
11041108 test_get_cipher (NID_aes_256_gcm, " id-aes256-gcm" );
1109+ test_get_cipher (NID_xaes_256_gcm, " id-xaes256-gcm" );
11051110
11061111 // error case
11071112 EXPECT_FALSE (EVP_get_cipherbyname (nullptr ));
@@ -1454,3 +1459,286 @@ TEST(CipherTest, Empty_EVP_CIPHER_CTX_V1187459157) {
14541459 CHECK_ERROR (EVP_DecryptUpdate (ctx.get (), out_vec.data (), &out_len, in_vec.data (), in_len), ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
14551460 CHECK_ERROR (EVP_DecryptFinal (ctx.get (), out_vec.data (), &out_len), ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
14561461}
1462+
1463+ TEST (CipherTest, XAES_256_GCM_EVP_CIPHER_INVALID_NONCE_KEY_LENGTH) {
1464+ std::vector<uint8_t > key (32 ), nonce (24 );
1465+
1466+ // XAES-256-GCM Encryption
1467+ bssl::UniquePtr<EVP_CIPHER_CTX> ctx (EVP_CIPHER_CTX_new ());
1468+ ASSERT_TRUE (ctx);
1469+ ASSERT_TRUE (EVP_CipherInit_ex (ctx.get (), EVP_xaes_256_gcm (), nullptr , nullptr , nullptr , 1 ));
1470+
1471+ // Valid nonce size: 20 bytes <= |N| <= 24 bytes
1472+ // Test invalid nonce size
1473+ ASSERT_TRUE (EVP_CIPHER_CTX_ctrl (ctx.get (), EVP_CTRL_AEAD_SET_IVLEN, 19 , nullptr ));
1474+ ASSERT_FALSE (EVP_CipherInit_ex (ctx.get (), nullptr , nullptr , key.data (), nonce.data (), -1 ));
1475+ ASSERT_TRUE (EVP_CIPHER_CTX_ctrl (ctx.get (), EVP_CTRL_AEAD_SET_IVLEN, 25 , nullptr ));
1476+ ASSERT_FALSE (EVP_CipherInit_ex (ctx.get (), nullptr , nullptr , key.data (), nonce.data (), -1 ));
1477+ ASSERT_TRUE (EVP_CIPHER_CTX_ctrl (ctx.get (), EVP_CTRL_AEAD_SET_IVLEN, 24 , nullptr ));
1478+
1479+ // Valid key length: 32 bytes
1480+ // Test invalid key length
1481+ ctx.get ()->key_len = 24 ;
1482+ ASSERT_FALSE (EVP_CipherInit_ex (ctx.get (), nullptr , nullptr , key.data (), nonce.data (), -1 ));
1483+
1484+ ctx.get ()->key_len = 32 ;
1485+ ASSERT_TRUE (EVP_CipherInit_ex (ctx.get (), nullptr , nullptr , key.data (), nonce.data (), -1 ));
1486+
1487+ // EVP_CipherUpdate is not allowed after EVP_CipherFinal_ex
1488+ std::vector<uint8_t > plaintext (1 ), ciphertext (1 );
1489+ int plaintext_len = 1 , ciphertext_len = 0 ;
1490+ ASSERT_TRUE (EVP_CipherUpdate (ctx.get (), ciphertext.data (), &ciphertext_len,
1491+ plaintext.data (), plaintext_len));
1492+ int len = 0 ;
1493+ ASSERT_TRUE (EVP_CipherFinal_ex (ctx.get (), ciphertext.data () + ciphertext_len, &len));
1494+ ASSERT_FALSE (EVP_CipherUpdate (ctx.get (), ciphertext.data (), &ciphertext_len,
1495+ plaintext.data (), plaintext_len));
1496+ }
1497+
1498+ TEST (CipherTest, XAES_256_GCM_EVP_CIPHER_DERIVING_SUBKEYS_DIFFERENT_NONCES) {
1499+ /*
1500+ * Test deriving many subkeys from a main key but with different nonces
1501+ * Source of test vectors:
1502+ * https://github.com/C2SP/C2SP/blob/main/XAES-256-GCM.md
1503+ */
1504+ std::vector<uint8_t > key;
1505+
1506+ /* ============ INITIALIZE ENCRYPTION CONTEXT ============ */
1507+ bssl::UniquePtr<EVP_CIPHER_CTX> ectx (EVP_CIPHER_CTX_new ());
1508+ ASSERT_TRUE (ectx);
1509+ ASSERT_TRUE (EVP_CipherInit_ex (ectx.get (), EVP_xaes_256_gcm (), nullptr , nullptr , nullptr , 1 ));
1510+ size_t iv_len = 24 ;
1511+ ASSERT_TRUE (EVP_CIPHER_CTX_ctrl (ectx.get (), EVP_CTRL_AEAD_SET_IVLEN, iv_len, nullptr ));
1512+
1513+ // Initialize the main key
1514+ DecodeHex (&key, " 0101010101010101010101010101010101010101010101010101010101010101" );
1515+ ASSERT_TRUE (EVP_CipherInit_ex (ectx.get (), nullptr , nullptr , key.data (), nullptr , -1 ));
1516+
1517+ /* ============ INITIALIZE DECRYPTION CONTEXT ============ */
1518+ bssl::UniquePtr<EVP_CIPHER_CTX> dctx (EVP_CIPHER_CTX_new ());
1519+ ASSERT_TRUE (dctx);
1520+ ASSERT_TRUE (EVP_DecryptInit_ex (dctx.get (), EVP_xaes_256_gcm (), nullptr , nullptr , nullptr ));
1521+ ASSERT_TRUE (EVP_CIPHER_CTX_ctrl (dctx.get (), EVP_CTRL_AEAD_SET_IVLEN, iv_len, nullptr ));
1522+
1523+ // Initialize the main key
1524+ ASSERT_TRUE (EVP_DecryptInit_ex (dctx.get (), nullptr , nullptr , key.data (), nullptr ));
1525+
1526+ // Test encryption and decryption
1527+ const auto test = [&ectx, &dctx](std::vector<uint8_t > &iv, const uint8_t *plaintext, size_t plaintext_len,
1528+ std::vector<uint8_t > &expected_ciphertext, std::vector<uint8_t > &expected_tag) {
1529+ // Encrypt
1530+ // Initiaze IV and derive a subkey
1531+ ASSERT_TRUE (EVP_CipherInit_ex (ectx.get (), nullptr , nullptr , nullptr , iv.data (), -1 ));
1532+
1533+ std::vector<uint8_t > ciphertext, tag;
1534+ ciphertext.resize (plaintext_len);
1535+ int ciphertext_len = 0 , len = 0 ;
1536+
1537+ // ASSERT_TRUE(EVP_CipherUpdate(ectx.get(), ciphertext.data(), &ciphertext_len, plaintext, plaintext_len));
1538+
1539+ for (size_t i = 0 ; i < plaintext_len; ++i) {
1540+ // Test streaming input
1541+ ASSERT_TRUE (EVP_CipherUpdate (ectx.get (), ciphertext.data () + ciphertext_len, &len,
1542+ plaintext + i, /* one byte */ 1 ));
1543+ ciphertext_len += len;
1544+ }
1545+
1546+ ASSERT_TRUE (EVP_CipherFinal_ex (ectx.get (), ciphertext.data () + ciphertext_len, &len));
1547+ ciphertext_len += len;
1548+ ASSERT_EQ (Bytes (ciphertext), Bytes (expected_ciphertext));
1549+
1550+ size_t tag_size = 16 ;
1551+ tag.resize (tag_size);
1552+ ASSERT_TRUE (EVP_CIPHER_CTX_ctrl (ectx.get (), EVP_CTRL_AEAD_GET_TAG, tag.size (), (void *)tag.data ()));
1553+ ASSERT_EQ (Bytes (tag), Bytes (expected_tag));
1554+
1555+ // Decrypt
1556+ // Initiaze IV and derive a subkey
1557+ ASSERT_TRUE (EVP_DecryptInit_ex (dctx.get (), nullptr , nullptr , nullptr , iv.data ()));
1558+
1559+ std::vector<uint8_t > decrypted;
1560+ decrypted.resize (ciphertext_len);
1561+ int decrypted_len = 0 ;
1562+
1563+ ASSERT_TRUE (EVP_CIPHER_CTX_ctrl (dctx.get (), EVP_CTRL_AEAD_SET_TAG, tag.size (), tag.data ()));
1564+
1565+ // ASSERT_TRUE(EVP_DecryptUpdate(dctx.get(), decrypted.data(), &decrypted_len, ciphertext.data(), ciphertext_len));
1566+ for (size_t i = 0 ; i < plaintext_len; ++i) {
1567+ // Test streaming input
1568+ ASSERT_TRUE (EVP_DecryptUpdate (dctx.get (), decrypted.data () + decrypted_len, &len,
1569+ ciphertext.data () + i, /* one byte */ 1 ));
1570+ decrypted_len += len;
1571+ }
1572+
1573+ ASSERT_TRUE (EVP_DecryptFinal (dctx.get (), decrypted.data () + decrypted_len, &len));
1574+ decrypted_len += len;
1575+
1576+ ASSERT_EQ ((size_t )decrypted_len, plaintext_len);
1577+ ASSERT_EQ (Bytes (decrypted), Bytes (plaintext, plaintext_len));
1578+ };
1579+
1580+ // Test with an IV
1581+ std::vector<uint8_t > iv;
1582+ DecodeHex (&iv, " 424242424242424242424242424242424242424242424242" );
1583+
1584+ // Test encryption and decryption with a plaintext
1585+ const uint8_t *plaintext = (const uint8_t *)" Hello, XAES-256-GCM!" ;
1586+ std::vector<uint8_t > ciphertext, tag;
1587+ DecodeHex (&ciphertext, " 01e5f78bc99de880bd2eeff2870d361f0eab5b2f" );
1588+ DecodeHex (&tag, " c55268f34b14045878fe3668db980319" );
1589+ test (iv, plaintext, strlen ((const char *)plaintext), ciphertext, tag);
1590+
1591+ // Test with another IV
1592+ DecodeHex (&iv, " 4142434445464748494a4b4c4d4e4f505152535455565758" );
1593+
1594+ // Test encryption and decryption again with another plaintext
1595+ plaintext = (const uint8_t *)" XAES-256-GCM" ;
1596+ DecodeHex (&ciphertext, " ce546ef63c9cc60765923609" );
1597+ DecodeHex (&tag, " b33a9a1974e96e52daf2fcf7075e2271" );
1598+ test (iv, plaintext, strlen ((const char *)plaintext), ciphertext, tag);
1599+ }
1600+
1601+ TEST (CipherTest, XAES_256_GCM_EVP_CIPHER_MULTI_LOOP_TEST) {
1602+ // Source of multi-loop tests:
1603+ // https://github.com/C2SP/C2SP/blob/main/XAES-256-GCM/go/XAES-256-GCM_test.go
1604+ const auto test = [](int n, const char *output) {
1605+ bssl::ScopedEVP_MD_CTX s;
1606+ ASSERT_TRUE (EVP_DigestInit (s.get (), EVP_shake128 ()));
1607+ bssl::ScopedEVP_MD_CTX d;
1608+ ASSERT_TRUE (EVP_DigestInit (d.get (), EVP_shake128 ()));
1609+
1610+ bssl::UniquePtr<EVP_CIPHER_CTX> ctx (EVP_CIPHER_CTX_new ());
1611+ ASSERT_TRUE (ctx);
1612+ ASSERT_TRUE (EVP_CipherInit_ex (ctx.get (), EVP_xaes_256_gcm (), nullptr , nullptr , nullptr , 1 ));
1613+ ASSERT_TRUE (EVP_CIPHER_CTX_ctrl (ctx.get (), EVP_CTRL_AEAD_SET_IVLEN, 24 , nullptr ));
1614+
1615+ bssl::UniquePtr<EVP_CIPHER_CTX> dctx (EVP_CIPHER_CTX_new ());
1616+ ASSERT_TRUE (dctx);
1617+ ASSERT_TRUE (EVP_DecryptInit_ex (dctx.get (), EVP_xaes_256_gcm (), nullptr , nullptr , nullptr ));
1618+ ASSERT_TRUE (EVP_CIPHER_CTX_ctrl (dctx.get (), EVP_CTRL_AEAD_SET_IVLEN, 24 , nullptr ));
1619+
1620+ std::vector<uint8_t > key (32 ), nonce (24 ), plaintext (256 );
1621+ std::vector<uint8_t > aad (256 ), ciphertext (256 ), tag (16 );
1622+ uint8_t plaintext_len = 0 , aad_len = 0 ;
1623+ int tag_size = 16 ;
1624+
1625+ for (int i = 0 ; i < n; ++i) {
1626+ ASSERT_TRUE (EVP_DigestSqueeze (s.get (), key.data (), 32 ));
1627+ ASSERT_TRUE (EVP_DigestSqueeze (s.get (), nonce.data (), 24 ));
1628+ ASSERT_TRUE (EVP_DigestSqueeze (s.get (), &plaintext_len, 1 ));
1629+ ASSERT_TRUE (EVP_DigestSqueeze (s.get (), plaintext.data (), plaintext_len));
1630+ ASSERT_TRUE (EVP_DigestSqueeze (s.get (), &aad_len, 1 ));
1631+ ASSERT_TRUE (EVP_DigestSqueeze (s.get (), aad.data (), aad_len));
1632+
1633+ // XAES-256-GCM Encryption
1634+ ASSERT_TRUE (EVP_CipherInit_ex (ctx.get (), nullptr , nullptr , key.data (), nonce.data (), -1 ));
1635+ ASSERT_EQ (aad_len, EVP_Cipher (ctx.get (), nullptr , aad.data (), aad_len));
1636+ int ciphertext_len = 0 ;
1637+ ASSERT_TRUE (EVP_CipherUpdate (ctx.get (), ciphertext.data (), &ciphertext_len,
1638+ plaintext.data (), plaintext_len));
1639+
1640+ int len = 0 ;
1641+ ASSERT_TRUE (EVP_CipherFinal_ex (ctx.get (), ciphertext.data () + ciphertext_len, &len));
1642+ ciphertext_len += len;
1643+ ASSERT_TRUE (EVP_DigestUpdate (d.get (), ciphertext.data (), ciphertext_len));
1644+
1645+ ASSERT_TRUE (EVP_CIPHER_CTX_ctrl (ctx.get (), EVP_CTRL_AEAD_GET_TAG, tag_size, tag.data ()));
1646+ ASSERT_TRUE (EVP_DigestUpdate (d.get (), tag.data (), tag_size));
1647+
1648+ // XAES-256-GCM Decryption
1649+ ASSERT_TRUE (EVP_DecryptInit_ex (dctx.get (), nullptr , nullptr , key.data (), nonce.data ()));
1650+ ASSERT_TRUE (EVP_CIPHER_CTX_ctrl (dctx.get (), EVP_CTRL_AEAD_SET_TAG, tag_size, tag.data ()));
1651+
1652+ std::vector<uint8_t > decrypted;
1653+ decrypted.resize (plaintext_len);
1654+ len = 0 ;
1655+ EVP_DecryptUpdate (dctx.get (), nullptr , &len, aad.data (), aad_len);
1656+ ASSERT_TRUE (EVP_DecryptUpdate (dctx.get (), decrypted.data (), &len, ciphertext.data (), ciphertext_len));
1657+ ASSERT_TRUE (EVP_DecryptFinal (dctx.get (), decrypted.data () + len, &len));
1658+
1659+ ASSERT_EQ (Bytes (decrypted), Bytes (plaintext.data (), plaintext_len));
1660+ }
1661+ std::vector<uint8_t > expected;
1662+ ASSERT_TRUE (DecodeHex (&expected, output));
1663+ uint8_t got[32 ] = {0 };
1664+ ASSERT_TRUE (EVP_DigestFinalXOF (d.get (), got, 32 ));
1665+ ASSERT_EQ (Bytes (got, 32 ), Bytes (expected));
1666+ };
1667+
1668+ test (10000 , " e6b9edf2df6cec60c8cbd864e2211b597fb69a529160cd040d56c0c210081939" );
1669+ test (1000000 , " 2163ae1445985a30b60585ee67daa55674df06901b890593e824b8a7c885ab15" );
1670+ }
1671+
1672+ TEST (CipherTest, XAES_256_GCM_EVP_CIPHER_SHORTER_NONCE) {
1673+ std::vector<uint8_t > key;
1674+
1675+ /* ============ INITIALIZE ENCRYPTION CONTEXT ============ */
1676+ bssl::UniquePtr<EVP_CIPHER_CTX> ectx (EVP_CIPHER_CTX_new ());
1677+ ASSERT_TRUE (ectx);
1678+ ASSERT_TRUE (EVP_CipherInit_ex (ectx.get (), EVP_xaes_256_gcm (), nullptr , nullptr , nullptr , 1 ));
1679+
1680+ // Initialize the main key
1681+ DecodeHex (&key, " 0101010101010101010101010101010101010101010101010101010101010101" );
1682+ ASSERT_TRUE (EVP_CipherInit_ex (ectx.get (), nullptr , nullptr , key.data (), nullptr , -1 ));
1683+
1684+ /* ============ INITIALIZE DECRYPTION CONTEXT ============ */
1685+ bssl::UniquePtr<EVP_CIPHER_CTX> dctx (EVP_CIPHER_CTX_new ());
1686+ ASSERT_TRUE (dctx);
1687+ ASSERT_TRUE (EVP_DecryptInit_ex (dctx.get (), EVP_xaes_256_gcm (), nullptr , nullptr , nullptr ));
1688+
1689+ // Initialize the main key
1690+ ASSERT_TRUE (EVP_DecryptInit_ex (dctx.get (), nullptr , nullptr , key.data (), nullptr ));
1691+
1692+ // Test encryption and decryption
1693+ const auto test = [&ectx, &dctx](std::vector<uint8_t > &iv, int iv_len, const uint8_t *plaintext, size_t plaintext_len) {
1694+ // Set IV Length
1695+ ASSERT_TRUE (EVP_CIPHER_CTX_ctrl (ectx.get (), EVP_CTRL_AEAD_SET_IVLEN, iv_len, nullptr ));
1696+ ASSERT_TRUE (EVP_CIPHER_CTX_ctrl (dctx.get (), EVP_CTRL_AEAD_SET_IVLEN, iv_len, nullptr ));
1697+
1698+ // Encrypt
1699+ // Initiaze IV and derive a subkey
1700+ ASSERT_TRUE (EVP_CipherInit_ex (ectx.get (), nullptr , nullptr , nullptr , iv.data (), -1 ));
1701+
1702+ std::vector<uint8_t > ciphertext, tag;
1703+ ciphertext.resize (plaintext_len);
1704+ int ciphertext_len = 0 ;
1705+
1706+ ASSERT_TRUE (EVP_CipherUpdate (ectx.get (), ciphertext.data (), &ciphertext_len,
1707+ plaintext, plaintext_len));
1708+ int len = 0 ;
1709+ ASSERT_TRUE (EVP_CipherFinal_ex (ectx.get (), ciphertext.data () + ciphertext_len, &len));
1710+ ciphertext_len += len;
1711+
1712+ size_t tag_size = 16 ;
1713+ tag.resize (tag_size);
1714+ ASSERT_TRUE (EVP_CIPHER_CTX_ctrl (ectx.get (), EVP_CTRL_AEAD_GET_TAG, tag.size (), (void *)tag.data ()));
1715+
1716+ // Decrypt
1717+ // Initiaze IV and derive a subkey
1718+ ASSERT_TRUE (EVP_DecryptInit_ex (dctx.get (), nullptr , nullptr , nullptr , iv.data ()));
1719+
1720+ std::vector<uint8_t > decrypted;
1721+ decrypted.resize (ciphertext_len);
1722+ int decrypted_len = 0 ;
1723+
1724+ ASSERT_TRUE (EVP_CIPHER_CTX_ctrl (dctx.get (), EVP_CTRL_AEAD_SET_TAG, tag.size (), tag.data ()));
1725+ ASSERT_TRUE (EVP_DecryptUpdate (dctx.get (), decrypted.data (), &decrypted_len, ciphertext.data (), ciphertext_len));
1726+ ASSERT_TRUE (EVP_DecryptFinal (dctx.get (), decrypted.data () + decrypted_len, &len));
1727+ decrypted_len += len;
1728+
1729+ ASSERT_EQ ((size_t )decrypted_len, plaintext_len);
1730+ ASSERT_EQ (Bytes (decrypted), Bytes (plaintext, plaintext_len));
1731+ };
1732+
1733+ // Test with a 20-byte IV
1734+ std::vector<uint8_t > iv;
1735+ DecodeHex (&iv, " 4242424242424242424242424242424242424242" );
1736+ const uint8_t *plaintext = (const uint8_t *)" Hello, XAES-256-GCM!" ;
1737+ std::vector<uint8_t > ciphertext, tag;
1738+ test (iv, iv.size (), plaintext, strlen ((const char *)plaintext));
1739+
1740+ // Test with a 23-byte IV
1741+ DecodeHex (&iv, " 4142434445464748494a4b4c4d4e4f5051525354555657" );
1742+ plaintext = (const uint8_t *)" XAES-256-GCM" ;
1743+ test (iv, iv.size (), plaintext, strlen ((const char *)plaintext));
1744+ }
0 commit comments