@@ -54,6 +54,7 @@ void CLuaFileDefs::LoadFunctions()
54
54
{" fileIsEOF" , fileIsEOF},
55
55
{" fileSetPos" , fileSetPos},
56
56
{" fileGetContents" , ArgumentParser<fileGetContents>},
57
+ {" fileGetHash" , ArgumentParser<fileGetHash>},
57
58
};
58
59
59
60
// Add functions
@@ -89,6 +90,7 @@ void CLuaFileDefs::AddClass(lua_State* luaVM)
89
90
lua_classfunction (luaVM, " getSize" , " fileGetSize" );
90
91
lua_classfunction (luaVM, " getPath" , " fileGetPath" );
91
92
lua_classfunction (luaVM, " getContents" , " fileGetContents" );
93
+ lua_classfunction (luaVM, " getHash" , " fileGetHash" );
92
94
lua_classfunction (luaVM, " isEOF" , " fileIsEOF" );
93
95
94
96
lua_classfunction (luaVM, " setPos" , " fileSetPos" );
@@ -858,6 +860,142 @@ std::optional<std::string> CLuaFileDefs::fileGetContents(lua_State* L, CScriptFi
858
860
return {};
859
861
}
860
862
863
+ template <typename , typename = std::void_t <>>
864
+ struct HasSetKeyMethod : std::false_type
865
+ {
866
+ };
867
+
868
+ template <typename T>
869
+ struct HasSetKeyMethod <T, std::void_t <decltype (std::declval<T>().SetKey(std::declval<const CryptoPP::byte*>(), std::declval<size_t >()))>> : std::true_type
870
+ {
871
+ };
872
+
873
+ template <typename HashAlgorithmT>
874
+ static std::string ComputeScriptFileHash (CScriptFile* scriptFile, std::string_view key = {})
875
+ {
876
+ HashAlgorithmT hash{};
877
+
878
+ if constexpr (HasSetKeyMethod<HashAlgorithmT>::value)
879
+ {
880
+ if (!key.empty ())
881
+ hash.SetKey (reinterpret_cast <const CryptoPP::byte*>(key.data ()), key.size ());
882
+ }
883
+
884
+ std::array<unsigned char , 4096 > buffer{};
885
+
886
+ while (!scriptFile->IsEOF ())
887
+ {
888
+ const long bytesRead = scriptFile->ReadToBuffer (buffer.data (), static_cast <unsigned long >(buffer.size ()));
889
+
890
+ if (bytesRead < 1 )
891
+ break ;
892
+
893
+ hash.Update (buffer.data (), static_cast <size_t >(bytesRead));
894
+ }
895
+
896
+ std::string digest;
897
+ digest.resize (hash.DigestSize ());
898
+ hash.Final (reinterpret_cast <CryptoPP::byte*>(digest.data ()));
899
+
900
+ SString result;
901
+ CryptoPP::StringSource source (digest, true , new CryptoPP::HexEncoder (new CryptoPP::StringSink (result)));
902
+
903
+ return result.ToLower ();
904
+ }
905
+
906
+ std::optional<std::string> CLuaFileDefs::fileGetHash (lua_State* const luaVM, CScriptFile* scriptFile, HashFunctionType hashFunction,
907
+ std::optional<std::unordered_map<std::string, std::string>> options)
908
+ {
909
+ // string|nil fileGetHash ( file theFile, string algorithm [, table options ] )
910
+
911
+ std::string result;
912
+
913
+ const long oldPosition = scriptFile->GetPointer ();
914
+ scriptFile->SetPointer (0 );
915
+
916
+ try
917
+ {
918
+ switch (hashFunction)
919
+ {
920
+ case HashFunctionType::MD5:
921
+ result = ComputeScriptFileHash<CryptoPP::MD5>(scriptFile);
922
+ break ;
923
+ case HashFunctionType::SHA1:
924
+ result = ComputeScriptFileHash<CryptoPP::SHA1>(scriptFile);
925
+ break ;
926
+ case HashFunctionType::SHA224:
927
+ result = ComputeScriptFileHash<CryptoPP::SHA224>(scriptFile);
928
+ break ;
929
+ case HashFunctionType::SHA256:
930
+ result = ComputeScriptFileHash<CryptoPP::SHA256>(scriptFile);
931
+ break ;
932
+ case HashFunctionType::SHA384:
933
+ result = ComputeScriptFileHash<CryptoPP::SHA384>(scriptFile);
934
+ break ;
935
+ case HashFunctionType::SHA512:
936
+ result = ComputeScriptFileHash<CryptoPP::SHA512>(scriptFile);
937
+ break ;
938
+ case HashFunctionType::HMAC:
939
+ {
940
+ if (!options.has_value ())
941
+ throw std::invalid_argument (" Invalid value for fields 'key' and 'algorithm'" );
942
+
943
+ std::unordered_map<std::string, std::string>& optionsMap = options.value ();
944
+
945
+ std::string& key = optionsMap[" key" ];
946
+ std::string& algorithm = optionsMap[" algorithm" ];
947
+ HmacAlgorithm hmacAlgorithm;
948
+
949
+ if (key.empty ())
950
+ throw std::invalid_argument (" Invalid value for field 'key'" );
951
+
952
+ if (algorithm.empty () || !StringToEnum (algorithm, hmacAlgorithm))
953
+ throw std::invalid_argument (" Invalid value for field 'algorithm'" );
954
+
955
+ switch (hmacAlgorithm)
956
+ {
957
+ case HmacAlgorithm::MD5:
958
+ result = ComputeScriptFileHash<CryptoPP::HMAC<CryptoPP::MD5>>(scriptFile, key);
959
+ break ;
960
+ case HmacAlgorithm::SHA1:
961
+ result = ComputeScriptFileHash<CryptoPP::HMAC<CryptoPP::SHA1>>(scriptFile, key);
962
+ break ;
963
+ case HmacAlgorithm::SHA224:
964
+ result = ComputeScriptFileHash<CryptoPP::HMAC<CryptoPP::SHA224>>(scriptFile, key);
965
+ break ;
966
+ case HmacAlgorithm::SHA256:
967
+ result = ComputeScriptFileHash<CryptoPP::HMAC<CryptoPP::SHA256>>(scriptFile, key);
968
+ break ;
969
+ case HmacAlgorithm::SHA384:
970
+ result = ComputeScriptFileHash<CryptoPP::HMAC<CryptoPP::SHA384>>(scriptFile, key);
971
+ break ;
972
+ case HmacAlgorithm::SHA512:
973
+ result = ComputeScriptFileHash<CryptoPP::HMAC<CryptoPP::SHA512>>(scriptFile, key);
974
+ break ;
975
+ default :
976
+ throw std::invalid_argument (" Invalid hmac algorithm" );
977
+ }
978
+
979
+ break ;
980
+ }
981
+ default :
982
+ throw std::invalid_argument (" Unknown hash algorithm" );
983
+ }
984
+ }
985
+ catch (std::exception& ex)
986
+ {
987
+ m_pScriptDebugging->LogWarning (luaVM, ex.what ());
988
+ result.clear ();
989
+ }
990
+
991
+ scriptFile->SetPointer (oldPosition);
992
+
993
+ if (result.empty ())
994
+ return {};
995
+
996
+ return result;
997
+ }
998
+
861
999
int CLuaFileDefs::fileGetPos (lua_State* luaVM)
862
1000
{
863
1001
// int fileGetPos ( file theFile )
0 commit comments