nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: randombit/botan
Pull request #2075 (2019-08-20 09:57:54)

Serialize the PKCS11 tests
See #2072


Patch:
diff --git a/src/lib/prov/pkcs11/p11_module.cpp b/src/lib/prov/pkcs11/p11_module.cpp
index 9399aea28..066fb676e 100644
--- a/src/lib/prov/pkcs11/p11_module.cpp
+++ b/src/lib/prov/pkcs11/p11_module.cpp
@@ -15,6 +15,8 @@ namespace PKCS11 {
 Module::Module(const std::string& file_path, C_InitializeArgs init_args)
    : m_file_path(file_path)
    {
+   if(file_path.empty())
+      throw Invalid_Argument("PKCS11 no module path specified");
    reload(init_args);
    }
 


Test patch:
diff --git a/src/tests/test_runner.cpp b/src/tests/test_runner.cpp
index d5f07e504..fdc705216 100644
--- a/src/tests/test_runner.cpp
+++ b/src/tests/test_runner.cpp
@@ -318,7 +318,16 @@ size_t Test_Runner::run_tests(const std::vector<std::string>& tests_to_run,
 
       for(auto const& test_name : tests_to_run)
          {
-         m_fut_results.push_back(pool.run(run_a_test, test_name));
+         if(test_name.substr(0, 6) == "pkcs11")
+            {
+            // Run all PKCS11 tests on the main thread because they need to
+            // be serialized with respect to each other.
+            m_fut_results.push_back(std::async(std::launch::deferred, run_a_test, test_name));
+            }
+         else
+            {
+            m_fut_results.push_back(pool.run(run_a_test, test_name));
+            }
          }
 
       for(size_t i = 0; i != m_fut_results.size(); ++i)
Repository: randombit/botan
Pull request #2090 (2019-08-31 12:48:05)

Fix PBKDF2 with zero iterations
It would go into a very long loop.

OpenSSL treats iterations==0 same as iterations==1 but this seems confusing. Instead just reject it.

Unrelated, fix a divide by zero if asked to tune with 0 byte output.

Closes GH #2088


Patch:
diff --git a/src/lib/pbkdf/pbkdf2/pbkdf2.cpp b/src/lib/pbkdf/pbkdf2/pbkdf2.cpp
index aa0081917..122d0fae3 100644
--- a/src/lib/pbkdf/pbkdf2/pbkdf2.cpp
+++ b/src/lib/pbkdf/pbkdf2/pbkdf2.cpp
@@ -60,6 +60,9 @@ size_t tune_pbkdf2(MessageAuthenticationCode& prf,
                    size_t output_length,
                    uint32_t msec)
    {
+   if(output_length == 0)
+      output_length = 1;
+
    const size_t prf_sz = prf.output_length();
    BOTAN_ASSERT_NOMSG(prf_sz > 0);
    secure_vector<uint8_t> U(prf_sz);
@@ -109,6 +112,9 @@ void pbkdf2(MessageAuthenticationCode& prf,
             size_t salt_len,
             size_t iterations)
    {
+   if(iterations == 0)
+      throw Invalid_Argument("PBKDF2: Invalid iteration count");
+
    clear_mem(out, out_len);
 
    if(out_len == 0)


Test patch:
diff --git a/src/tests/data/pbkdf/pbkdf2.vec b/src/tests/data/pbkdf/pbkdf2.vec
index d4af333b8..60d250f39 100644
--- a/src/tests/data/pbkdf/pbkdf2.vec
+++ b/src/tests/data/pbkdf/pbkdf2.vec
@@ -49,6 +49,12 @@ Iterations = 1000
 Passphrase = gwrxpqxumsdsmbmhfhmfdcvlcvngzkig
 Output = 4C9DB7BA24955225D5B845F65EF24EF1B0C6E86F2E39C8DDAA4B8ABD26082D1F350381FADEAEB560DC447AFC68A6B47E6EA1E7412F6CF7B2D82342FCCD11D3B4
 
+# Generated by OpenSSL
+Passphrase = pass
+Salt = 01020304
+Iterations = 1
+Output = D54FC7B6916F7AF26115B80BA435E66293BF935EE8CF3C0D6FB954B986E68A48
+
 [PBKDF2(HMAC(SHA-256))]
 Salt = 0001020304050607
 Iterations = 10000
Repository: randombit/botan
Pull request #2111 (2019-09-23 15:35:52)

Add base32 encoding/decoding util to the cli


Patch:
diff --git a/src/cli/codec.cpp b/src/cli/codec.cpp
index 0d3df336d..48388d1a7 100644
--- a/src/cli/codec.cpp
+++ b/src/cli/codec.cpp
@@ -10,6 +10,10 @@
    #include <botan/hex.h>
 #endif
 
+#if defined(BOTAN_HAS_BASE32_CODEC)
+   #include <botan/base32.h>
+#endif
+
 #if defined(BOTAN_HAS_BASE58_CODEC)
    #include <botan/base58.h>
 #endif
@@ -139,7 +143,67 @@ class Base58_Decode final : public Command
 
 BOTAN_REGISTER_COMMAND("base58_dec", Base58_Decode);
 
-#endif // base64
+#endif // base58
+
+#if defined(BOTAN_HAS_BASE32_CODEC)
+
+class Base32_Encode final : public Command
+   {
+   public:
+      Base32_Encode() : Command("base32_enc file") {}
+
+      std::string group() const override
+         {
+         return "codec";
+         }
+
+      std::string description() const override
+         {
+         return "Encode given file to Base32";
+         }
+
+      void go() override
+         {
+         auto onData = [&](const uint8_t b[], size_t l)
+            {
+            output() << Botan::base32_encode(b, l);
+            };
+         this->read_file(get_arg("file"), onData, 768);
+         }
+   };
+
+BOTAN_REGISTER_COMMAND("base32_enc", Base32_Encode);
+
+class Base32_Decode final : public Command
+   {
+   public:
+      Base32_Decode() : Command("base32_dec file") {}
+
+      std::string group() const override
+         {
+         return "codec";
+         }
+
+      std::string description() const override
+         {
+         return "Decode Base32 encoded file";
+         }
+
+      void go() override
+         {
+         auto write_bin = [&](const uint8_t b[], size_t l)
+            {
+            Botan::secure_vector<uint8_t> bin = Botan::base32_decode(reinterpret_cast<const char*>(b), l);
+            output().write(reinterpret_cast<const char*>(bin.data()), bin.size());
+            };
+
+         this->read_file(get_arg("file"), write_bin, 1024);
+         }
+   };
+
+BOTAN_REGISTER_COMMAND("base32_dec", Base32_Decode);
+
+#endif // base32
 
 #if defined(BOTAN_HAS_BASE64_CODEC)
 


Test patch:
diff --git a/src/scripts/test_cli.py b/src/scripts/test_cli.py
index 7d9b443cf..df5e8b9b7 100755
--- a/src/scripts/test_cli.py
+++ b/src/scripts/test_cli.py
@@ -189,6 +189,10 @@ def cli_base64_tests(_tmp_dir):
     test_cli("base64_enc", "-", "YmVlcyE=", "bees!")
     test_cli("base64_dec", "-", "bees!", "YmVlcyE=")
 
+def cli_base32_tests(_tmp_dir):
+    test_cli("base32_enc", "-", "MJSWK4ZB", "bees!")
+    test_cli("base32_dec", "-", "bees!", "MJSWK4ZB")
+
 def cli_base58_tests(_tmp_dir):
     test_cli("base58_enc", "-", "C6sRAr4", "bees!")
     test_cli("base58_dec", "-", "bees!", "C6sRAr4")
@@ -1074,6 +1078,7 @@ def main(args=None):
     test_fns = [
         cli_argon2_tests,
         cli_asn1_tests,
+        cli_base32_tests,
         cli_base58_tests,
         cli_base64_tests,
         cli_bcrypt_tests,
Repository: randombit/botan
Pull request #2112 (2019-09-23 15:35:59)

Add support for TOTP in Python wrapper


Patch:
diff --git a/src/python/botan2.py b/src/python/botan2.py
index e7e685802..7db8cd9b3 100755
--- a/src/python/botan2.py
+++ b/src/python/botan2.py
@@ -22,7 +22,7 @@ from ctypes import CDLL, POINTER, byref, create_string_buffer, \
     c_void_p, c_size_t, c_uint8, c_uint32, c_uint64, c_int, c_uint, c_char_p
 
 from sys import version_info, platform
-from time import strptime, mktime
+from time import strptime, mktime, time as system_time
 from binascii import hexlify
 from datetime import datetime
 
@@ -1588,6 +1588,29 @@ class HOTP(object):
         else:
             return (False, counter)
 
+class TOTP(object):
+    def __init__(self, key, digest="SHA-1", digits=6, timestep=30):
+        self.__obj = c_void_p(0)
+        _DLL.botan_totp_init(byref(self.__obj), key, len(key), _ctype_str(digest), digits, timestep)
+
+    def __del__(self):
+        _DLL.botan_totp_destroy(self.__obj)
+
+    def generate(self, timestamp=None):
+        if timestamp is None:
+            timestamp = int(system_time())
+        code = c_uint32(0)
+        _DLL.botan_totp_generate(self.__obj, byref(code), timestamp)
+        return code.value
+
+    def check(self, code, timestamp=None, acceptable_drift=0):
+        if timestamp is None:
+            timestamp = int(system_time())
+        rc = _DLL.botan_totp_check(self.__obj, code, timestamp, acceptable_drift)
+        if rc == 0:
+            return True
+        return False
+
 def nist_key_wrap(kek, key):
     output = create_string_buffer(len(key) + 8)
     out_len = c_size_t(len(output))


Test patch:
diff --git a/src/scripts/test_python.py b/src/scripts/test_python.py
index 04b0c949e..e860df358 100644
--- a/src/scripts/test_python.py
+++ b/src/scripts/test_python.py
@@ -596,6 +596,21 @@ ofvkP1EDmpx50fHLawIDAQAB
         self.assertEqual(hotp.check(520489, 7, 2), (True, 10))
         self.assertEqual(hotp.check(520489, 0, 9), (True, 10))
 
+    def test_totp(self):
+
+        totp = botan2.TOTP(b'12345678901234567890', digest="SHA-1", digits=8)
+
+        self.assertEqual(totp.generate(59), 94287082)
+        self.assertEqual(totp.generate(1111111109), 7081804)
+        self.assertEqual(totp.generate(1111111111), 14050471)
+        self.assertEqual(totp.generate(1234567890), 89005924)
+        self.assertEqual(totp.generate(1234567890), 89005924)
+        self.assertEqual(totp.generate(2000000000), 69279037)
+
+        self.assertTrue(totp.check(7081804, 1111111109))
+        self.assertTrue(totp.check(7081804, 1111111109 - 29))
+        self.assertFalse(totp.check(7081804, 1111111109 + 1))
+        self.assertTrue(totp.check(7081804, 1111111109 + 30, 1))
 
 if __name__ == '__main__':
     unittest.main()
Repository: randombit/botan
Pull request #2174 (2019-10-22 16:34:21)

Avoid situation where is_active and is_closed could both return true
GH #2171


Patch:
diff --git a/src/lib/tls/tls_channel.cpp b/src/lib/tls/tls_channel.cpp
index 9d3f2d30d..88b897227 100644
--- a/src/lib/tls/tls_channel.cpp
+++ b/src/lib/tls/tls_channel.cpp
@@ -278,6 +278,8 @@ void Channel::change_cipher_spec_writer(Connection_Side side)
 
 bool Channel::is_active() const
    {
+   if(is_closed())
+      return false;
    return (active_state() != nullptr);
    }
 


Test patch:
diff --git a/src/tests/unit_tls.cpp b/src/tests/unit_tls.cpp
index 1055ca885..33ca89922 100644
--- a/src/tests/unit_tls.cpp
+++ b/src/tests/unit_tls.cpp
@@ -657,7 +657,11 @@ void TLS_Handshake_Test::go()
 
          m_results.test_eq("TLS key material export", client_key.bits_of(), server_key.bits_of());
 
+         m_results.confirm("Client is active", client->is_active());
+         m_results.confirm("Client is not closed", !client->is_closed());
          client->close();
+         m_results.confirm("Client is no longer active", !client->is_active());
+         m_results.confirm("Client is closed", client->is_closed());
          }
       }
Repository: randombit/botan
Pull request #2567 (2020-12-28 20:09:22)

Fix CBC mode via Python API


Patch:
diff --git a/src/python/botan2.py b/src/python/botan2.py
index 717651d00..cd6f98b7c 100755
--- a/src/python/botan2.py
+++ b/src/python/botan2.py
@@ -719,6 +719,8 @@ class SymmetricCipher(object):
         flags = 0 if encrypt else 1
         self.__obj = c_void_p(0)
         _DLL.botan_cipher_init(byref(self.__obj), _ctype_str(algo), flags)
+        self._is_cbc = algo.find('/CBC') > 0
+        self._is_encrypt = encrypt
 
     def __del__(self):
         _DLL.botan_cipher_destroy(self.__obj)
@@ -784,7 +786,16 @@ class SymmetricCipher(object):
         inp = txt if txt else ''
         inp_sz = c_size_t(len(inp))
         inp_consumed = c_size_t(0)
-        out = create_string_buffer(inp_sz.value + (self.tag_length() if final else 0))
+        extra_bytes = 0
+        if final and self._is_encrypt:
+            tag_len = self.tag_length()
+            if tag_len > 0:
+                # AEADs don't expand beyond the tag
+                extra_bytes = tag_len
+            elif self._is_cbc:
+                # Hack: the largest block size currently supported
+                extra_bytes = 64
+        out = create_string_buffer(inp_sz.value + extra_bytes)
         out_sz = c_size_t(len(out))
         out_written = c_size_t(0)
         flags = c_uint32(1 if final else 0)


Test patch:
diff --git a/src/scripts/test_python.py b/src/scripts/test_python.py
index 868de11ab..1735f26d5 100644
--- a/src/scripts/test_python.py
+++ b/src/scripts/test_python.py
@@ -156,7 +156,7 @@ class BotanPythonTests(unittest.TestCase):
         self.assertEqual(hex_encode(sha256_2.final()), hex_encode(hash1))
 
     def test_cipher(self):
-        for mode in ['AES-128/CTR-BE', 'Serpent/GCM', 'ChaCha20Poly1305']:
+        for mode in ['AES-128/CTR-BE', 'Serpent/GCM', 'ChaCha20Poly1305', 'AES-128/CBC/PKCS7']:
             enc = botan2.SymmetricCipher(mode, encrypt=True)
 
             if mode == 'AES-128/CTR-BE':
Repository: randombit/botan
Pull request #2837 (2021-10-28 21:20:48)

Remove OS::get_cpu_total and make OS::get_cpu_available more resiliant
GH #2830


Patch:
diff --git a/src/lib/utils/os_utils.cpp b/src/lib/utils/os_utils.cpp
index e278a6d07..74894f04f 100644
--- a/src/lib/utils/os_utils.cpp
+++ b/src/lib/utils/os_utils.cpp
@@ -265,30 +265,34 @@ uint64_t OS::get_cpu_cycle_counter()
    return rtc;
    }
 
-size_t OS::get_cpu_total()
+size_t OS::get_cpu_available()
    {
-#if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(_SC_NPROCESSORS_CONF)
-   const long res = ::sysconf(_SC_NPROCESSORS_CONF);
-   if(res > 0)
-      return static_cast<size_t>(res);
+#if defined(BOTAN_TARGET_OS_HAS_POSIX1)
+
+#if defined(_SC_NPROCESSORS_ONLN)
+   const long cpu_online = ::sysconf(_SC_NPROCESSORS_ONLN);
+   if(cpu_online > 0)
+      return static_cast<size_t>(cpu_online);
 #endif
 
-#if defined(BOTAN_TARGET_OS_HAS_THREADS)
-   return static_cast<size_t>(std::thread::hardware_concurrency());
-#else
-   return 1;
+#if defined(_SC_NPROCESSORS_CONF)
+   const long cpu_conf = ::sysconf(_SC_NPROCESSORS_CONF);
+   if(cpu_conf > 0)
+      return static_cast<size_t>(cpu_conf);
 #endif
-   }
 
-size_t OS::get_cpu_available()
-   {
-#if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(_SC_NPROCESSORS_ONLN)
-   const long res = ::sysconf(_SC_NPROCESSORS_ONLN);
-   if(res > 0)
-      return static_cast<size_t>(res);
 #endif
 
-   return OS::get_cpu_total();
+#if defined(BOTAN_TARGET_OS_HAS_THREADS)
+   // hardware_concurrency is allowed to return 0 if the value is not
+   // well defined or not computable.
+   const size_t hw_concur = std::thread::hardware_concurrency();
+
+   if(hw_concur > 0)
+      return hw_concur;
+#endif
+
+   return 1;
    }
 
 uint64_t OS::get_high_resolution_clock()
diff --git a/src/lib/utils/os_utils.h b/src/lib/utils/os_utils.h
index 9cefb9b41..6fe3efe77 100644
--- a/src/lib/utils/os_utils.h
+++ b/src/lib/utils/os_utils.h
@@ -50,7 +50,6 @@ bool running_in_privileged_state();
 */
 uint64_t BOTAN_TEST_API get_cpu_cycle_counter();
 
-size_t BOTAN_TEST_API get_cpu_total();
 size_t BOTAN_TEST_API get_cpu_available();
 
 /**


Test patch:
diff --git a/src/tests/test_os_utils.cpp b/src/tests/test_os_utils.cpp
index 92386114c..ad83c95b1 100644
--- a/src/tests/test_os_utils.cpp
+++ b/src/tests/test_os_utils.cpp
@@ -112,12 +112,11 @@ class OS_Utils_Tests final : public Test
 
       Test::Result test_get_cpu_numbers()
          {
-         Test::Result result("OS::get_cpu_total/OS::get_cpu_available");
+         Test::Result result("OS::get_cpu_available");
 
-         size_t tt = Botan::OS::get_cpu_total();
-         size_t ta = Botan::OS::get_cpu_available();
+         const size_t ta = Botan::OS::get_cpu_available();
 
-         result.test_lte("get_cpu_available not greater than total", ta, tt);
+         result.test_gte("get_cpu_available is at least 1", ta, 1);
 
          return result;
          }