akemimadoka %!s(int64=7) %!d(string=hai) anos
pai
achega
9e63e3222e

+ 30 - 25
QQBot.Test/CryptographyTest.cpp

@@ -1,35 +1,40 @@
 #include "pch.h"
 #include <catch.hpp>
 
-template <typename T, typename U, bool = std::is_const_v<T>>
-struct MayAddConst
-{
-	using Type = std::add_const_t<U>;
-};
+using namespace QQBot;
 
-template <typename T, typename U>
-struct MayAddConst<T, U, false>
+TEST_CASE("Cryptography", "[Utility][Cryptography]")
 {
-	using Type = U;
-};
+	using namespace Cryptography;
 
-template <typename T, std::size_t N>
-typename MayAddConst<T, std::byte>::Type (&ToBytes(T (&arr)[N]))[sizeof(T) * N / sizeof(std::byte)]
-{
-	return reinterpret_cast<typename MayAddConst<T, std::byte>::Type(&)[sizeof(T) * N / sizeof(std::byte)]>(arr);
-}
+	SECTION("Tea")
+	{
+		using namespace Tea;
 
-TEST_CASE("Cryptography", "[Utility][Cryptography]")
-{
-	constexpr const char text[] = "123456789123456789";
-	constexpr const char key[] = "00000000000000000000000000000000";
+		constexpr const char text[] = "123456789123456789";
+		constexpr const char key[] = "00000000000000000000000000000000";
+
+		char result[CalculateOutputSize(std::size(text))]{};
+		const auto formattedKey = FormatKey(Utility::ToByteSpan(key));
+		const auto resultSize = Encrypt(Utility::ToByteSpan(text), Utility::ToByteSpan(result), formattedKey);
+		char decryptResult[std::size(result)]{};
+		const auto decryptResultSize = Decrypt(Utility::ToByteSpan(result), Utility::ToByteSpan(decryptResult), formattedKey);
+
+		REQUIRE(resultSize == Cryptography::Tea::CalculateOutputSize(std::size(text)));
+		REQUIRE(decryptResultSize == std::size(text));
+		REQUIRE(std::memcmp(decryptResult, text, std::size(text)) == 0);
+	}
+
+	SECTION("Md5")
+	{
+		using namespace Md5;
+
+		constexpr const char test[] = "test";
 
-	char result[QQBot::Cryptography::Tea::CalculateOutputSize(std::size(text))]{};
-	const auto resultSize = QQBot::Cryptography::Tea::Encrypt(ToBytes(text), ToBytes(result), ToBytes(key));
-	char decryptResult[std::size(result)]{};
-	const auto decryptResultSize = QQBot::Cryptography::Tea::Decrypt(ToBytes(result), ToBytes(decryptResult), ToBytes(key));
+		std::byte result[16];
+		Calculate(Utility::ToByteSpan(test).subspan(0, 4), result);
 
-	REQUIRE(resultSize == QQBot::Cryptography::Tea::CalculateOutputSize(std::size(text)));
-	REQUIRE(decryptResultSize == std::size(text));
-	REQUIRE(std::memcmp(decryptResult, text, std::size(text)) == 0);
+		constexpr const nByte expectedResult[] = "\x09\x8f\x6b\xcd\x46\x21\xd3\x73\xca\xde\x4e\x83\x26\x27\xb4\xf6";
+		REQUIRE(std::memcmp(result, expectedResult, std::size(result)) == 0);
+	}
 }

+ 22 - 20
QQBot/Cryptography.cpp

@@ -1,7 +1,7 @@
 #include "Cryptography.h"
 #include <random>
 #include "Utility.h"
-#include "natLinq.h"
+#include <openssl/md5.h>
 
 #undef min
 #undef max
@@ -11,18 +11,6 @@ using namespace QQBot::Cryptography;
 
 namespace
 {
-	std::array<std::uint32_t, 4> FormatKey(gsl::span<const std::byte> const& key)
-	{
-		if (key.empty())
-		{
-			nat_Throw(CryptoException, u8"key is empty."_nv);
-		}
-
-		std::array<std::uint32_t, 4> result{ 0x20202020, 0x20202020, 0x20202020, 0x20202020 };
-		std::memcpy(result.data(), key.data(), std::min<std::size_t>(key.size(), 16));
-		return result;
-	}
-
 	constexpr std::uint32_t TeaDelta = 0x9E3779B9;
 	constexpr std::size_t TeaIterationTimes = 16;
 	constexpr std::uint32_t TeaDecryptInitSum = TeaDelta << 4;
@@ -62,8 +50,20 @@ namespace
 	}
 }
 
+std::array<std::uint32_t, 4> Tea::FormatKey(gsl::span<const std::byte> const& key)
+{
+	if (key.empty())
+	{
+		nat_Throw(CryptoException, u8"key is empty."_nv);
+	}
+
+	std::array<std::uint32_t, 4> result{ 0x20202020, 0x20202020, 0x20202020, 0x20202020 };
+	std::memcpy(result.data(), key.data(), std::min<std::size_t>(key.size(), 16));
+	return result;
+}
+
 ///	@see https://baike.baidu.com/item/TEA%E5%8A%A0%E5%AF%86%E7%AE%97%E6%B3%95
-std::size_t Tea::Encrypt(gsl::span<const std::byte> const& input, gsl::span<std::byte> const& output, gsl::span<const std::byte> const& key)
+std::size_t Tea::Encrypt(gsl::span<const std::byte> const& input, gsl::span<std::byte> const& output, gsl::span<const std::uint32_t, 4> const& key)
 {
 	const auto totalProcessSize = CalculateOutputSize(input.size());
 	assert(totalProcessSize % TeaProcessUnitSize == 0);
@@ -74,7 +74,6 @@ std::size_t Tea::Encrypt(gsl::span<const std::byte> const& input, gsl::span<std:
 	const auto paddingSize = totalProcessSize - input.size();
 	const auto frontPaddingSize = paddingSize - 7;
 
-	const auto formattedKey = FormatKey(key);
 	std::random_device randomDevice;
 	std::default_random_engine randomEngine{ randomDevice() };
 	const std::uniform_int_distribution<nuInt> dist{ 0x00, 0xFF };
@@ -128,14 +127,14 @@ std::size_t Tea::Encrypt(gsl::span<const std::byte> const& input, gsl::span<std:
 			}
 		}
 
-		::Encrypt(inputBuffer, outputBuffer, formattedKey);
+		::Encrypt(inputBuffer, outputBuffer, key);
 		std::memcpy(&output[processedLength], outputBuffer, TeaProcessUnitSize);
 	}
 
 	return totalProcessSize;
 }
 
-std::size_t Tea::Decrypt(gsl::span<const std::byte> const& input, gsl::span<std::byte> const& output, gsl::span<const std::byte> const& key)
+std::size_t Tea::Decrypt(gsl::span<const std::byte> const& input, gsl::span<std::byte> const& output, gsl::span<const std::uint32_t, 4> const& key)
 {
 	const auto inputSize = static_cast<std::size_t>(input.size());
 	if (inputSize % TeaProcessUnitSize != 0 || inputSize < 16)
@@ -143,8 +142,6 @@ std::size_t Tea::Decrypt(gsl::span<const std::byte> const& input, gsl::span<std:
 		nat_Throw(CryptoException, u8"Invalid input data."_nv);
 	}
 
-	const auto formattedKey = FormatKey(key);
-
 	std::uint32_t inputBuffer[2];
 	std::uint32_t outputBuffer[2];
 	std::uint32_t lastInputBuffer[2];
@@ -156,7 +153,7 @@ std::size_t Tea::Decrypt(gsl::span<const std::byte> const& input, gsl::span<std:
 	{
 		std::memcpy(inputBuffer, &input[processedLength], TeaProcessUnitSize);
 
-		::Decrypt(inputBuffer, outputBuffer, formattedKey);
+		::Decrypt(inputBuffer, outputBuffer, key);
 
 		if (processedLength > 0)
 		{
@@ -212,3 +209,8 @@ std::size_t Tea::Decrypt(gsl::span<const std::byte> const& input, gsl::span<std:
 
 	return inputSize - frontPaddingSize - 7;
 }
+
+void Md5::Calculate(gsl::span<const std::byte> const& input, gsl::span<std::byte, 16> const& output)
+{
+	MD5(reinterpret_cast<const unsigned char*>(input.data()), input.size(), reinterpret_cast<unsigned char*>(output.data()));
+}

+ 9 - 2
QQBot/Cryptography.h

@@ -19,7 +19,14 @@ namespace QQBot::Cryptography
 			return Utility::AlignTo(inputSize + 10, TeaProcessUnitSize);
 		}
 
-		std::size_t Encrypt(gsl::span<const std::byte> const& input, gsl::span<std::byte> const& output, gsl::span<const std::byte> const& key);
-		std::size_t Decrypt(gsl::span<const std::byte> const& input, gsl::span<std::byte> const& output, gsl::span<const std::byte> const& key);
+		std::array<std::uint32_t, 4> FormatKey(gsl::span<const std::byte> const& key);
+
+		std::size_t Encrypt(gsl::span<const std::byte> const& input, gsl::span<std::byte> const& output, gsl::span<const std::uint32_t, 4> const& key);
+		std::size_t Decrypt(gsl::span<const std::byte> const& input, gsl::span<std::byte> const& output, gsl::span<const std::uint32_t, 4> const& key);
+	}
+
+	namespace Md5
+	{
+		void Calculate(gsl::span<const std::byte> const& input, gsl::span<std::byte, 16> const& output);
 	}
 }

+ 7 - 0
QQBot/Jce.h

@@ -0,0 +1,7 @@
+#pragma once
+#include <natBinary.h>
+
+namespace QQBot::Jce
+{
+
+}

+ 5 - 4
QQBot/QQBot.vcxproj

@@ -20,6 +20,7 @@
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Cryptography.h" />
+    <ClInclude Include="Jce.h" />
     <ClInclude Include="QQBot.h" />
     <ClInclude Include="Utility.h" />
   </ItemGroup>
@@ -108,7 +109,7 @@
       <GenerateDebugInformation>true</GenerateDebugInformation>
     </Link>
     <Lib>
-      <AdditionalDependencies>NatsuLib.lib;libcrypto64MDd.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>NatsuLib.lib;legacy_stdio_definitions.lib;libcrypto64MDd.lib;%(AdditionalDependencies)</AdditionalDependencies>
     </Lib>
     <Lib>
       <AdditionalLibraryDirectories>$(SolutionDir)Extern\NatsuLib\NatsuLib\bin\$(Platform)\$(Configuration);D:\OpenSSL-Win64\lib\VC\static;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
@@ -131,7 +132,7 @@
       <GenerateDebugInformation>true</GenerateDebugInformation>
     </Link>
     <Lib>
-      <AdditionalDependencies>NatsuLib.lib;libcrypto64MDd.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>NatsuLib.lib;legacy_stdio_definitions.lib;libcrypto64MDd.lib;%(AdditionalDependencies)</AdditionalDependencies>
     </Lib>
     <Lib>
       <AdditionalLibraryDirectories>$(SolutionDir)Extern\NatsuLib\NatsuLib\bin\$(Platform)\$(Configuration);D:\OpenSSL-Win64\lib\VC\static;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
@@ -158,7 +159,7 @@
       <GenerateDebugInformation>true</GenerateDebugInformation>
     </Link>
     <Lib>
-      <AdditionalDependencies>NatsuLib.lib;libcrypto64MD.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>NatsuLib.lib;legacy_stdio_definitions.lib;libcrypto64MD.lib;%(AdditionalDependencies)</AdditionalDependencies>
     </Lib>
     <Lib>
       <AdditionalLibraryDirectories>$(SolutionDir)Extern\NatsuLib\NatsuLib\bin\$(Platform)\$(Configuration);D:\OpenSSL-Win64\lib\VC\static;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
@@ -185,7 +186,7 @@
       <GenerateDebugInformation>true</GenerateDebugInformation>
     </Link>
     <Lib>
-      <AdditionalDependencies>NatsuLib.lib;libcrypto64MD.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>NatsuLib.lib;legacy_stdio_definitions.lib;libcrypto64MD.lib;%(AdditionalDependencies)</AdditionalDependencies>
     </Lib>
     <Lib>
       <AdditionalLibraryDirectories>$(SolutionDir)Extern\NatsuLib\NatsuLib\bin\$(Platform)\$(Configuration);D:\OpenSSL-Win64\lib\VC\static;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>

+ 3 - 0
QQBot/QQBot.vcxproj.filters

@@ -24,6 +24,9 @@
     <ClInclude Include="Utility.h">
       <Filter>头文件</Filter>
     </ClInclude>
+    <ClInclude Include="Jce.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="QQBot.cpp">

+ 26 - 0
QQBot/Utility.h

@@ -1,5 +1,7 @@
 #pragma once
 #include <cstddef>
+#include <gsl/span>
+#include <type_traits>
 
 namespace QQBot::Utility
 {
@@ -7,4 +9,28 @@ namespace QQBot::Utility
 	{
 		return num + alignment - 1 & ~(alignment - 1);
 	}
+
+	template <typename T, typename U, bool = std::is_const_v<T>>
+	struct MayAddConst
+	{
+		using Type = std::add_const_t<U>;
+	};
+
+	template <typename T, typename U>
+	struct MayAddConst<T, U, false>
+	{
+		using Type = U;
+	};
+
+	template <typename T, std::size_t N>
+	typename MayAddConst<T, std::byte>::Type(&ToByteArray(T(&arr)[N]) noexcept)[sizeof(T) * N / sizeof(std::byte)]
+	{
+		return reinterpret_cast<typename MayAddConst<T, std::byte>::Type(&)[sizeof(T) * N / sizeof(std::byte)]>(arr);
+	}
+
+	template <typename T, std::size_t N>
+	gsl::span<typename MayAddConst<T, std::byte>::Type, sizeof(T) * N / sizeof(std::byte)> ToByteSpan(T(&arr)[N]) noexcept
+	{
+		return ToByteArray(arr);
+	}
 }