Repository: godotengine/godot (language: cpp)

Issue:
Mbed TLS error when exporting with PCK encryption (musl libc)
### Tested versions

- Reproducible in: 4.4-beta1 and later
- Not reproducible in: 4.3-stable

### System information

Alpine Linux - musl libc - gcc - Godot 4.4.rc2 - AMD GPU

### Issue description

I have compiled both the editor and the export templates in my system (Alpine Linux with musl libc and GCC) as usual, with my encryption key exported.
When I try to export the game with the PCK encryption enabled, fails at 20% with the following errors:

```
ERROR:  failed
  ! mbedtls_ctr_drbg_seed returned an error -52.
   at: init (core/crypto/crypto_core.cpp:73)
ERROR: Failed to initialize random number generator.
   at: open_and_parse (core/io/file_access_encrypted.cpp:52)
ERROR: Condition "err != OK" is true. Returning: ERR_SKIP
   at: _save_pack_file (editor/export/editor_export_platform.cpp:304)
ERROR: Save PCK: Failed to export project files.
   at: add_message (editor/export/editor_export_platform.h:243)
```

It works OK if I use the same compiled templates in the official 4.4-rc2 release running on my steam deck (GLIBC), so I think that the issue is in my compiled editor, not in the templates.

### Steps to reproduce

I've compiled the editor and templates with the following commands under Alpine Linux (musl libc) using GCC:

```
# Editor
scons platform=linuxbsd arch=x86_64 production=yes lto=none

# Templates (export the encryption key here)
scons platform=windows target=template_debug arch=x86_64 production=yes lto=none
scons platform=windows target=template_release arch=x86_64 production=yes lto=none
```

### Minimal reproduction project (MRP)

none


Discussion / hints:
**UPDATE**

I've just tried to compile the editor without builtin_mbedtls and installed mbedtls-dev on my system:

```
scons platform=linuxbsd arch=x86_64 production=yes lto=none builtin_mbedtls=no
```

The editor builds successfully, but trying to export returns the same error as using the builtin library.
This might be an incompatibility between musl libc or other Alpine components and mbedTLS' default entropy function.

Do you get similar errors when using the Asset Library? I expect it might fail to initialize a TLS context too and not be able to download icons of assets.
> Do you get similar errors when using the Asset Library? I expect it might fail to initialize a TLS context too and not be able to download icons of assets.

It works ok with the asset library. I can see all the icons and just downloaded an addon without errors.
Is it working with a new project? It might be system entropy pool size issue, Asset Library likely initialize RNG once, and PCK encryption do it for every file (~probably more in 4.4 than in 4.3, due to IV generation changes~ should actually use it less, but only is `seed` is set). What's `cat /proc/sys/kernel/random/poolsize` command output on your system?
> It might be system entropy pool size issue

Also, try setting `seed` in the PCK encryption tab to a non-zero value.
Error `-52` is `MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED`, so it is likely related to entropy pool.
> What's `cat /proc/sys/kernel/random/poolsize` command output on your system?

It's 256

I will try with a new project, and also setting `seed` in the PCK tab.
@bruvzg I can confirm that it's working well with a smaller project by default, and with the biggest project setting the `seed` value to a non-zero value.

Fix patch:
diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp
index f2749157b3d0..f3d89a66971f 100644
--- a/core/io/file_access_encrypted.cpp
+++ b/core/io/file_access_encrypted.cpp
@@ -30,9 +30,17 @@
 
 #include "file_access_encrypted.h"
 
-#include "core/crypto/crypto_core.h"
 #include "core/variant/variant.h"
 
+CryptoCore::RandomGenerator *FileAccessEncrypted::_fae_static_rng = nullptr;
+
+void FileAccessEncrypted::deinitialize() {
+	if (_fae_static_rng) {
+		memdelete(_fae_static_rng);
+		_fae_static_rng = nullptr;
+	}
+}
+
 Error FileAccessEncrypted::open_and_parse(Ref<FileAccess> p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic, const Vector<uint8_t> &p_iv) {
 	ERR_FAIL_COND_V_MSG(file.is_valid(), ERR_ALREADY_IN_USE, vformat("Can't open file while another file from path '%s' is open.", file->get_path_absolute()));
 	ERR_FAIL_COND_V(p_key.size() != 32, ERR_INVALID_PARAMETER);
@@ -48,9 +56,15 @@ Error FileAccessEncrypted::open_and_parse(Ref<FileAccess> p_base, const Vector<u
 		key = p_key;
 		if (p_iv.is_empty()) {
 			iv.resize(16);
-			CryptoCore::RandomGenerator rng;
-			ERR_FAIL_COND_V_MSG(rng.init(), FAILED, "Failed to initialize random number generator.");
-			Error err = rng.get_random_bytes(iv.ptrw(), 16);
+			if (unlikely(!_fae_static_rng)) {
+				_fae_static_rng = memnew(CryptoCore::RandomGenerator);
+				if (_fae_static_rng->init() != OK) {
+					memdelete(_fae_static_rng);
+					_fae_static_rng = nullptr;
+					ERR_FAIL_V_MSG(FAILED, "Failed to initialize random number generator.");
+				}
+			}
+			Error err = _fae_static_rng->get_random_bytes(iv.ptrw(), 16);
 			ERR_FAIL_COND_V(err != OK, err);
 		} else {
 			ERR_FAIL_COND_V(p_iv.size() != 16, ERR_INVALID_PARAMETER);
diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h
index 570955b78352..a1bc0f09dcf6 100644
--- a/core/io/file_access_encrypted.h
+++ b/core/io/file_access_encrypted.h
@@ -31,6 +31,7 @@
 #ifndef FILE_ACCESS_ENCRYPTED_H
 #define FILE_ACCESS_ENCRYPTED_H
 
+#include "core/crypto/crypto_core.h"
 #include "core/io/file_access.h"
 
 #define ENCRYPTED_HEADER_MAGIC 0x43454447
@@ -57,6 +58,8 @@ class FileAccessEncrypted : public FileAccess {
 
 	void _close();
 
+	static CryptoCore::RandomGenerator *_fae_static_rng;
+
 public:
 	Error open_and_parse(Ref<FileAccess> p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic = true, const Vector<uint8_t> &p_iv = Vector<uint8_t>());
 	Error open_and_parse_password(Ref<FileAccess> p_base, const String &p_key, Mode p_mode);
@@ -97,6 +100,8 @@ class FileAccessEncrypted : public FileAccess {
 
 	virtual void close() override;
 
+	static void deinitialize();
+
 	FileAccessEncrypted() {}
 	~FileAccessEncrypted();
 };
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index 568694bdf4d0..d58097920d91 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -45,6 +45,7 @@
 #include "core/io/config_file.h"
 #include "core/io/dir_access.h"
 #include "core/io/dtls_server.h"
+#include "core/io/file_access_encrypted.h"
 #include "core/io/http_client.h"
 #include "core/io/image_loader.h"
 #include "core/io/json.h"
@@ -455,5 +456,7 @@ void unregister_core_types() {
 	CoreStringNames::free();
 	StringName::cleanup();
 
+	FileAccessEncrypted::deinitialize();
+
 	OS::get_singleton()->benchmark_end_measure("Core", "Unregister Types");
 }


Test patch: