From df21719faf4fbd4580640dfc7dfdee3fe8a1680c Mon Sep 17 00:00:00 2001
From: taynpg <taynpg@163.com>
Date: Wed, 28 Feb 2024 17:02:36 +0800
Subject: [PATCH] =?UTF-8?q?RSA=E5=8A=A0=E5=AF=86=E8=A7=A3=E5=AF=86?=
 =?UTF-8?q?=E5=BA=93=E8=B0=83=E8=AF=95=E9=80=9A=E8=BF=87?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 CMakeLists.txt                |  3 ++-
 cryp/CMakeLists.txt           |  3 ++-
 cryp/box_rsa.cpp              | 35 ++++++++++++++++++--------
 cryp/box_rsa.h                | 17 +++++++------
 test/CMakeLists.txt           |  5 ++++
 test/cryp_test/CMakeLists.txt |  6 +++++
 test/cryp_test/main.cpp       | 47 +++++++++++++++++++++++++++++++++++
 7 files changed, 97 insertions(+), 19 deletions(-)
 create mode 100644 test/CMakeLists.txt
 create mode 100644 test/cryp_test/CMakeLists.txt
 create mode 100644 test/cryp_test/main.cpp

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 579f2aa..a2efd7d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -11,4 +11,5 @@ if (MSVC)
     add_compile_options(-D_CRT_SECURE_NO_WARNINGS)
 endif()
 
-add_subdirectory(cryp)
\ No newline at end of file
+add_subdirectory(cryp)
+add_subdirectory(test)
\ No newline at end of file
diff --git a/cryp/CMakeLists.txt b/cryp/CMakeLists.txt
index 9d29e51..9eb443f 100644
--- a/cryp/CMakeLists.txt
+++ b/cryp/CMakeLists.txt
@@ -4,4 +4,5 @@ set(CMAKE_CXX_STANDARD 11)
 
 find_package(OpenSSL REQUIRED)
 add_library(box_cryp STATIC "box_rsa.h" "box_rsa.cpp")
-target_link_libraries(box_cryp PRIVATE OpenSSL::SSL OpenSSL::Crypto)
\ No newline at end of file
+target_link_libraries(box_cryp PRIVATE OpenSSL::SSL OpenSSL::Crypto)
+target_include_directories(box_cryp PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
\ No newline at end of file
diff --git a/cryp/box_rsa.cpp b/cryp/box_rsa.cpp
index 7c28f47..c44bf9f 100644
--- a/cryp/box_rsa.cpp
+++ b/cryp/box_rsa.cpp
@@ -7,7 +7,6 @@
 #include <openssl/rsa.h>
 #include <string>
 
-
 constexpr size_t g_buffsize = 2048;
 
 namespace cppbox {
@@ -17,8 +16,8 @@ class CRSAOperatorImp
 public:
     CRSAOperatorImp()
     {
-        err_ = new char[g_buffsize];
-        ioerr_ = BIO_new_mem_buf(err_, g_buffsize);
+        err_ = new char[g_buffsize + 1];
+        ioerr_ = BIO_new(BIO_s_mem());
     }
     ~CRSAOperatorImp()
     {
@@ -32,7 +31,7 @@ public:
         mem_ = BIO_new_mem_buf((void*)public_pem.data, public_pem.len);
         key_ = PEM_read_bio_PUBKEY(mem_, nullptr, nullptr, nullptr);
         if (key_ == nullptr) {
-            std::snprintf(err_, g_buffsize, "Read From Public Key Mem Data Failed.");
+            ERR_print_errors(ioerr_);
             clear();
             return false;
         }
@@ -47,6 +46,7 @@ public:
         if (EVP_PKEY_encrypt(ctx_, result.data, &result.len, data.data, data.len) <= 0) {
             free_data(result);
             clear();
+            ERR_print_errors(ioerr_);
             return false;
         }
         clear();
@@ -58,7 +58,7 @@ public:
         mem_ = BIO_new_mem_buf((void*)private_pem.data, private_pem.len);
         key_ = PEM_read_bio_PrivateKey(mem_, nullptr, nullptr, nullptr);
         if (key_ == nullptr) {
-            std::snprintf(err_, g_buffsize, "Read From Private Key Mem Data Failed.");
+            ERR_print_errors(ioerr_);
             clear();
             return false;
         }
@@ -76,6 +76,7 @@ public:
             ERR_print_errors(ioerr_);
             return false;
         }
+        result.data[result.len] = '\0';
         clear();
         return true;
     }
@@ -93,13 +94,14 @@ public:
         file_data.len = ftell(fp);
         fseek(fp, 0, SEEK_SET);
 
-        file_data.data = (unsigned char*)malloc(file_data.len);
+        alloc_data(file_data);
         if (file_data.data == NULL) {
             fclose(fp);
             std::snprintf(err_, g_buffsize, "Alloc Mem Failed: %zd", file_data.len);
             return false;
         }
         file_data.len = fread(file_data.data, 1, file_data.len, fp);
+        fclose(fp);
         bool ret = encrypt_pub(file_data, data, result);
         free(file_data.data);
         return ret;
@@ -118,13 +120,14 @@ public:
         file_data.len = ftell(fp);
         fseek(fp, 0, SEEK_SET);
 
-        file_data.data = (unsigned char*)malloc(file_data.len);
+        alloc_data(file_data);
         if (file_data.data == NULL) {
             fclose(fp);
             std::snprintf(err_, g_buffsize, "Alloc Mem Failed: %zd", file_data.len);
             return false;
         }
         file_data.len = fread(file_data.data, 1, file_data.len, fp);
+        fclose(fp);
         bool ret = decrypt_pri(file_data, data, result);
         free(file_data.data);
         return ret;
@@ -145,12 +148,16 @@ public:
         }
         key_ = EVP_RSA_gen(g_buffsize / 2);
         if (key_ == nullptr) {
-            ERR_print_errors_fp(stderr);
+            ERR_print_errors(ioerr_);
             return false;
         }
         PEM_write_PUBKEY(fp_pub, key_);
         PEM_write_PrivateKey(fp_pri, key_, nullptr, nullptr, 0, nullptr, nullptr);
         clear();
+
+        fclose(fp_pub);
+        fclose(fp_pri);
+
         return true;
     }
 
@@ -199,12 +206,14 @@ public:
             data.data = nullptr;
             return;
         }
-        data.data = static_cast<unsigned char*>(malloc(data.len));
+        data.data = static_cast<unsigned char*>(malloc(data.len + 1));
     }
 
     void get_last_error(char* buf, int len)
     {
-        std::snprintf(buf, len, err_, strlen(err_));
+        int read_len = BIO_read(ioerr_, err_, g_buffsize);
+        std::snprintf(buf, len, err_, read_len);
+        buf[read_len] = '\0';
     }
 
 private:
@@ -275,4 +284,10 @@ const char* CRSAOperator::get_last_error() const
     return err_;
 }
 
+void CRSAOperator::free_hdata(HData& data)
+{
+    assert(imp_);
+    imp_->free_data(data);
+}
+
 }   // namespace cppbox
\ No newline at end of file
diff --git a/cryp/box_rsa.h b/cryp/box_rsa.h
index 627c165..69f205a 100644
--- a/cryp/box_rsa.h
+++ b/cryp/box_rsa.h
@@ -5,7 +5,7 @@ namespace cppbox {
 
 struct HData {
     unsigned char* data;
-    size_t    len;
+    size_t         len;
 };
 
 class CRSAOperatorImp;
@@ -14,16 +14,19 @@ class CRSAOperator
 private:
     CRSAOperatorImp* imp_{};
     char*            err_{};
+
 public:
     CRSAOperator();
     ~CRSAOperator();
+
 public:
-    bool encrypt_pub(const HData& public_pem, const HData& data, HData& result);
-    bool encrypt_pub(const char* pub_path, const HData& data, HData& result);
-    bool decrypt_pri(const HData& private_pem, const HData& data, HData& result);
-    bool decrypt_pri(const char* pri_path, const HData& data, HData& result);
-    bool generate_keypair(const char* pub_path, const char* pri_path);
-    bool generate_keypair(HData& pub, HData& pri);
+    bool        encrypt_pub(const HData& public_pem, const HData& data, HData& result);
+    bool        encrypt_pub(const char* pub_path, const HData& data, HData& result);
+    bool        decrypt_pri(const HData& private_pem, const HData& data, HData& result);
+    bool        decrypt_pri(const char* pri_path, const HData& data, HData& result);
+    bool        generate_keypair(const char* pub_path, const char* pri_path);
+    bool        generate_keypair(HData& pub, HData& pri);
+    void        free_hdata(HData& data);
     const char* get_last_error() const;
 };
 
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644
index 0000000..869ee40
--- /dev/null
+++ b/test/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required (VERSION 3.8)
+project (auxiliarytool_test)
+set(CMAKE_CXX_STANDARD 11)
+
+add_subdirectory(cryp_test)
\ No newline at end of file
diff --git a/test/cryp_test/CMakeLists.txt b/test/cryp_test/CMakeLists.txt
new file mode 100644
index 0000000..272ba31
--- /dev/null
+++ b/test/cryp_test/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required (VERSION 3.8)
+project (cryp_test)
+set(CMAKE_CXX_STANDARD 11)
+
+add_executable(cryp_test "main.cpp")
+target_link_libraries(cryp_test PRIVATE box_cryp)
\ No newline at end of file
diff --git a/test/cryp_test/main.cpp b/test/cryp_test/main.cpp
new file mode 100644
index 0000000..f95fbee
--- /dev/null
+++ b/test/cryp_test/main.cpp
@@ -0,0 +1,47 @@
+#include <iostream>
+#include <box_rsa.h>
+#include <cassert>
+
+using namespace cppbox;
+
+CRSAOperator opr;
+
+void file_test()
+{
+    if (!opr.generate_keypair("public.pem", "private.pem")) {
+        std::cout << opr.get_last_error() << std::endl;
+    }
+    
+    const char* pub = "public.pem";
+    const char* pri = "private.pem";
+
+    HData source_data;
+    int size = 512;
+    source_data.data = (unsigned char*)malloc(size);
+    source_data.len = size;
+    source_data.len = std::snprintf((char *)source_data.data, source_data.len, "This is a cryp test!");
+
+    HData en_result_data;
+    HData de_result_data;
+    if (!opr.encrypt_pub(pub, source_data, en_result_data)) {
+        std::cout << opr.get_last_error() << std::endl;
+    }
+    if (!opr.decrypt_pri(pri, en_result_data, de_result_data)) {
+        std::cout << opr.get_last_error() << std::endl;
+    }
+    assert(strcmp((const char *)de_result_data.data, (const char *)source_data.data) == 0);
+
+    opr.free_hdata(en_result_data);
+    opr.free_hdata(de_result_data);
+    remove(pub);
+    remove(pri);
+
+    std::cout << "cryp_test success!" << std::endl;
+}
+
+int main()
+{
+    file_test();
+
+    return 0;
+}
\ No newline at end of file