Pārlūkot izejas kodu

Merge pull request #57887 from Faless/crypto/4.x_os_get_entropy

Rémi Verschelde 3 gadi atpakaļ
vecāks
revīzija
6e73aa0497

+ 2 - 0
core/crypto/SCsub

@@ -31,6 +31,8 @@ if not has_module:
         "aes.c",
         "base64.c",
         "constant_time.c",
+        "ctr_drbg.c",
+        "entropy.c",
         "md5.c",
         "sha1.c",
         "sha256.c",

+ 43 - 0
core/crypto/crypto_core.cpp

@@ -30,12 +30,55 @@
 
 #include "crypto_core.h"
 
+#include "core/os/os.h"
+
 #include <mbedtls/aes.h>
 #include <mbedtls/base64.h>
+#include <mbedtls/ctr_drbg.h>
+#include <mbedtls/entropy.h>
 #include <mbedtls/md5.h>
 #include <mbedtls/sha1.h>
 #include <mbedtls/sha256.h>
 
+// RandomGenerator
+CryptoCore::RandomGenerator::RandomGenerator() {
+	entropy = memalloc(sizeof(mbedtls_entropy_context));
+	mbedtls_entropy_init((mbedtls_entropy_context *)entropy);
+	mbedtls_entropy_add_source((mbedtls_entropy_context *)entropy, &CryptoCore::RandomGenerator::_entropy_poll, nullptr, 256, MBEDTLS_ENTROPY_SOURCE_STRONG);
+	ctx = memalloc(sizeof(mbedtls_ctr_drbg_context));
+	mbedtls_ctr_drbg_init((mbedtls_ctr_drbg_context *)ctx);
+}
+
+CryptoCore::RandomGenerator::~RandomGenerator() {
+	mbedtls_ctr_drbg_free((mbedtls_ctr_drbg_context *)ctx);
+	memfree(ctx);
+	mbedtls_entropy_free((mbedtls_entropy_context *)entropy);
+	memfree(entropy);
+}
+
+int CryptoCore::RandomGenerator::_entropy_poll(void *p_data, unsigned char *r_buffer, size_t p_len, size_t *r_len) {
+	*r_len = 0;
+	Error err = OS::get_singleton()->get_entropy(r_buffer, p_len);
+	ERR_FAIL_COND_V(err, MBEDTLS_ERR_ENTROPY_SOURCE_FAILED);
+	*r_len = p_len;
+	return 0;
+}
+
+Error CryptoCore::RandomGenerator::init() {
+	int ret = mbedtls_ctr_drbg_seed((mbedtls_ctr_drbg_context *)ctx, mbedtls_entropy_func, (mbedtls_entropy_context *)entropy, nullptr, 0);
+	if (ret) {
+		ERR_FAIL_COND_V_MSG(ret, FAILED, " failed\n  ! mbedtls_ctr_drbg_seed returned an error" + itos(ret));
+	}
+	return OK;
+}
+
+Error CryptoCore::RandomGenerator::get_random_bytes(uint8_t *r_buffer, size_t p_bytes) {
+	ERR_FAIL_COND_V(!ctx, ERR_UNCONFIGURED);
+	int ret = mbedtls_ctr_drbg_random((mbedtls_ctr_drbg_context *)ctx, r_buffer, p_bytes);
+	ERR_FAIL_COND_V_MSG(ret, FAILED, " failed\n  ! mbedtls_ctr_drbg_seed returned an error" + itos(ret));
+	return OK;
+}
+
 // MD5
 CryptoCore::MD5Context::MD5Context() {
 	ctx = memalloc(sizeof(mbedtls_md5_context));

+ 19 - 4
core/crypto/crypto_core.h

@@ -35,9 +35,24 @@
 
 class CryptoCore {
 public:
+	class RandomGenerator {
+	private:
+		void *entropy = nullptr;
+		void *ctx = nullptr;
+
+		static int _entropy_poll(void *p_data, unsigned char *r_buffer, size_t p_len, size_t *r_len);
+
+	public:
+		RandomGenerator();
+		~RandomGenerator();
+
+		Error init();
+		Error get_random_bytes(uint8_t *r_buffer, size_t p_bytes);
+	};
+
 	class MD5Context {
 	private:
-		void *ctx = nullptr; // To include, or not to include...
+		void *ctx = nullptr;
 
 	public:
 		MD5Context();
@@ -50,7 +65,7 @@ public:
 
 	class SHA1Context {
 	private:
-		void *ctx = nullptr; // To include, or not to include...
+		void *ctx = nullptr;
 
 	public:
 		SHA1Context();
@@ -63,7 +78,7 @@ public:
 
 	class SHA256Context {
 	private:
-		void *ctx = nullptr; // To include, or not to include...
+		void *ctx = nullptr;
 
 	public:
 		SHA256Context();
@@ -76,7 +91,7 @@ public:
 
 	class AESContext {
 	private:
-		void *ctx = nullptr; // To include, or not to include...
+		void *ctx = nullptr;
 
 	public:
 		AESContext();

+ 10 - 13
core/io/resource_uid.cpp

@@ -31,7 +31,7 @@
 #include "resource_uid.h"
 
 #include "core/config/project_settings.h"
-#include "core/crypto/crypto.h"
+#include "core/crypto/crypto_core.h"
 #include "core/io/dir_access.h"
 #include "core/io/file_access.h"
 
@@ -82,20 +82,14 @@ ResourceUID::ID ResourceUID::text_to_id(const String &p_text) const {
 	return ID(uid & 0x7FFFFFFFFFFFFFFF);
 }
 
-ResourceUID::ID ResourceUID::create_id() const {
-	mutex.lock();
-	if (crypto.is_null()) {
-		crypto = Ref<Crypto>(Crypto::create());
-	}
-	mutex.unlock();
+ResourceUID::ID ResourceUID::create_id() {
 	while (true) {
-		PackedByteArray bytes = crypto->generate_random_bytes(8);
-		ERR_FAIL_COND_V(bytes.size() != 8, INVALID_ID);
-		const uint64_t *ptr64 = (const uint64_t *)bytes.ptr();
-		ID id = int64_t((*ptr64) & 0x7FFFFFFFFFFFFFFF);
-		mutex.lock();
+		ID id = INVALID_ID;
+		MutexLock lock(mutex);
+		Error err = ((CryptoCore::RandomGenerator *)crypto)->get_random_bytes((uint8_t *)&id, sizeof(id));
+		ERR_FAIL_COND_V(err != OK, INVALID_ID);
+		id &= 0x7FFFFFFFFFFFFFFF;
 		bool exists = unique_ids.has(id);
-		mutex.unlock();
 		if (!exists) {
 			return id;
 		}
@@ -261,6 +255,9 @@ ResourceUID *ResourceUID::singleton = nullptr;
 ResourceUID::ResourceUID() {
 	ERR_FAIL_COND(singleton != nullptr);
 	singleton = this;
+	crypto = memnew(CryptoCore::RandomGenerator);
+	((CryptoCore::RandomGenerator *)crypto)->init();
 }
 ResourceUID::~ResourceUID() {
+	memdelete((CryptoCore::RandomGenerator *)crypto);
 }

+ 2 - 3
core/io/resource_uid.h

@@ -35,7 +35,6 @@
 #include "core/string/string_name.h"
 #include "core/templates/ordered_hash_map.h"
 
-class Crypto;
 class ResourceUID : public Object {
 	GDCLASS(ResourceUID, Object)
 public:
@@ -47,7 +46,7 @@ public:
 	static String get_cache_file();
 
 private:
-	mutable Ref<Crypto> crypto;
+	void *crypto; // CryptoCore::RandomGenerator (avoid including crypto_core.h)
 	Mutex mutex;
 	struct Cache {
 		CharString cs;
@@ -67,7 +66,7 @@ public:
 	String id_to_text(ID p_id) const;
 	ID text_to_id(const String &p_text) const;
 
-	ID create_id() const;
+	ID create_id();
 	bool has_id(ID p_id) const;
 	void add_id(ID p_id, const String &p_path);
 	void set_id(ID p_id, const String &p_path);

+ 2 - 0
core/os/os.h

@@ -132,6 +132,8 @@ public:
 
 	virtual String get_stdin_string(bool p_block = true) = 0;
 
+	virtual Error get_entropy(uint8_t *r_buffer, int p_bytes) = 0; // Should return cryptographically-safe random bytes.
+
 	virtual PackedStringArray get_connected_midi_inputs();
 	virtual void open_midi_inputs();
 	virtual void close_midi_inputs();

+ 1 - 1
doc/classes/ResourceUID.xml

@@ -14,7 +14,7 @@
 			<description>
 			</description>
 		</method>
-		<method name="create_id" qualifiers="const">
+		<method name="create_id">
 			<return type="int" />
 			<description>
 			</description>

+ 40 - 0
drivers/unix/os_unix.cpp

@@ -65,6 +65,21 @@
 #include <time.h>
 #include <unistd.h>
 
+#if defined(OSX_ENABLED) || (defined(__ANDROID_API__) && __ANDROID_API__ >= 28)
+// Random location for getentropy. Fitting.
+#include <sys/random.h>
+#define UNIX_GET_ENTROPY
+#elif defined(__FreeBSD__) || defined(__OpenBSD__) || (defined(__GLIBC_MINOR__) && (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 26))
+// In <unistd.h>.
+// One day... (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 700)
+// https://publications.opengroup.org/standards/unix/c211
+#define UNIX_GET_ENTROPY
+#endif
+
+#if !defined(UNIX_GET_ENTROPY) && !defined(NO_URANDOM)
+#include <fcntl.h>
+#endif
+
 /// Clock Setup function (used by get_ticks_usec)
 static uint64_t _clock_start = 0;
 #if defined(__APPLE__)
@@ -150,6 +165,31 @@ String OS_Unix::get_stdin_string(bool p_block) {
 	return "";
 }
 
+Error OS_Unix::get_entropy(uint8_t *r_buffer, int p_bytes) {
+#if defined(UNIX_GET_ENTROPY)
+	int left = p_bytes;
+	int ofs = 0;
+	do {
+		int chunk = MIN(left, 256);
+		ERR_FAIL_COND_V(getentropy(r_buffer + ofs, chunk), FAILED);
+		left -= chunk;
+		ofs += chunk;
+	} while (left > 0);
+#elif !defined(NO_URANDOM)
+	int r = open("/dev/urandom", O_RDONLY);
+	ERR_FAIL_COND_V(r < 0, FAILED);
+	int left = p_bytes;
+	do {
+		ssize_t ret = read(r, r_buffer, p_bytes);
+		ERR_FAIL_COND_V(ret <= 0, FAILED);
+		left -= ret;
+	} while (left > 0);
+#else
+	return ERR_UNAVAILABLE;
+#endif
+	return OK;
+}
+
 String OS_Unix::get_name() const {
 	return "Unix";
 }

+ 1 - 10
drivers/unix/os_unix.h

@@ -43,7 +43,6 @@ protected:
 
 	virtual void initialize_core();
 	virtual int unix_initialize_audio(int p_audio_driver);
-	//virtual Error initialize(int p_video_driver,int p_audio_driver);
 
 	virtual void finalize_core() override;
 
@@ -54,15 +53,7 @@ public:
 
 	virtual String get_stdin_string(bool p_block) override;
 
-	//virtual void set_mouse_show(bool p_show);
-	//virtual void set_mouse_grab(bool p_grab);
-	//virtual bool is_mouse_grab_enabled() const = 0;
-	//virtual void get_mouse_position(int &x, int &y) const;
-	//virtual void set_window_title(const String& p_title);
-
-	//virtual void set_video_mode(const VideoMode& p_video_mode);
-	//virtual VideoMode get_video_mode() const;
-	//virtual void get_fullscreen_mode_list(List<VideoMode> *p_list) const;
+	virtual Error get_entropy(uint8_t *r_buffer, int p_bytes) override; // Should return cryptographycally-safe random bytes.
 
 	virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false) override;
 	virtual Error close_dynamic_library(void *p_library_handle) override;

+ 6 - 3
platform/osx/export/codesign.cpp

@@ -1359,9 +1359,12 @@ Error CodeSign::_codesign_file(bool p_use_hardened_runtime, bool p_force, const
 
 	// Generate common signature structures.
 	if (id.is_empty()) {
-		Ref<Crypto> crypto = Ref<Crypto>(Crypto::create());
-		PackedByteArray uuid = crypto->generate_random_bytes(16);
-		id = (String("a-55554944") /*a-UUID*/ + String::hex_encode_buffer(uuid.ptr(), 16));
+		CryptoCore::RandomGenerator rng;
+		ERR_FAIL_COND_V_MSG(rng.init(), FAILED, "Failed to initialize random number generator.");
+		uint8_t uuid[16];
+		Error err = rng.get_random_bytes(uuid, 16);
+		ERR_FAIL_COND_V_MSG(err, err, "Failed to generate UUID.");
+		id = (String("a-55554944") /*a-UUID*/ + String::hex_encode_buffer(uuid, 16));
 	}
 	CharString uuid_str = id.utf8();
 	print_verbose(vformat("CodeSign: Used bundle ID: %s", id));

+ 0 - 1
platform/osx/export/codesign.h

@@ -41,7 +41,6 @@
 #ifndef CODESIGN_H
 #define CODESIGN_H
 
-#include "core/crypto/crypto.h"
 #include "core/crypto/crypto_core.h"
 #include "core/io/dir_access.h"
 #include "core/io/file_access.h"

+ 7 - 0
platform/windows/os_windows.cpp

@@ -46,6 +46,7 @@
 #include "windows_terminal_logger.h"
 
 #include <avrt.h>
+#include <bcrypt.h>
 #include <direct.h>
 #include <knownfolders.h>
 #include <process.h>
@@ -192,6 +193,12 @@ void OS_Windows::finalize_core() {
 	NetSocketPosix::cleanup();
 }
 
+Error OS_Windows::get_entropy(uint8_t *r_buffer, int p_bytes) {
+	NTSTATUS status = BCryptGenRandom(nullptr, r_buffer, p_bytes, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
+	ERR_FAIL_COND_V(status, FAILED);
+	return OK;
+}
+
 Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) {
 	String path = p_path.replace("/", "\\");
 

+ 2 - 0
platform/windows/os_windows.h

@@ -106,6 +106,8 @@ protected:
 public:
 	virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override;
 
+	virtual Error get_entropy(uint8_t *r_buffer, int p_bytes) override;
+
 	virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false) override;
 	virtual Error close_dynamic_library(void *p_library_handle) override;
 	virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false) override;

+ 5 - 0
thirdparty/mbedtls/include/godot_core_mbedtls_config.h

@@ -7,7 +7,12 @@
 
 #define MBEDTLS_AES_C
 #define MBEDTLS_BASE64_C
+#define MBEDTLS_CTR_DRBG_C
+#define MBEDTLS_ENTROPY_C
 #define MBEDTLS_MD5_C
 #define MBEDTLS_SHA1_C
 #define MBEDTLS_SHA256_C
 #define MBEDTLS_PLATFORM_ZEROIZE_ALT
+#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES
+
+#include <limits.h>