function VerifySignature(
    strFilename,
    strHash, 
    strStoreFilename, 
    strPassword
) {
    var enumStoreCerts;
    var enumChainCerts;
    var enumSigners;
    var strFileContent;
    var strSignature;
    var oSignedData;
    var StoreCert;
    var ChainCert;
    var bIsValid;
    var Message;
    var Signer;
    var Chain;
    var Store;
    var fso;
    var ts;
    var n;
    
    fso = WScript.CreateObject("Scripting.FileSystemObject");
    SignedData = WScript.CreateObject("CAPICOM.SignedData");
    
    // Load file
    ExecAndLog ("RHB64Encoder " + "\"" + strFilename + "\"" + " b64.txt");
    f = fso.GetFile ("b64.txt");
    ts = f.OpenAsTextStream(MSC.ForReading,MSC.TristateTrue);
    SignedData.Content = ts.ReadAll();
    ts.close();
    ExecAndLog ("cmd /c del b64.txt");

    try {
        SignedData.Verify (strHash, true, MSC.CAPICOM_VERIFY_SIGNATURE_ONLY);
  	} catch (e) {
	    LogEvent(1,strFilename + " " + e.description);
  	    return (false);
   	}
    
    Chain = WScript.CreateObject("CAPICOM.Chain");
    Store = WScript.CreateObject("CAPICOM.Store");
    Store.Open (
        MSC.CAPICOM_MEMORY_STORE, 
        MSC.CAPICOM_ROOT_STORE, 
        MSC.CAPICOM_STORE_OPEN_READ_WRITE
    );
    
    Store.Load(strStoreFilename, strPassword);

    bIsValid = false;
    
    enumSigners = new Enumerator(SignedData.Signers);
    for (; !enumSigners.atEnd(); enumSigners.moveNext()) {
        Signer = enumSigners.item();
        Chain.Build (Signer.Certificate);
    
        enumChainCerts = new Enumerator (Chain.Certificates);
        for (; !enumChainCerts.atEnd(); enumChainCerts.moveNext()) {
            ChainCert = enumChainCerts.item();
            
            if (ChainCert.IsValid()) {
                enumStoreCerts = new Enumerator (Store.Certificates);
                for (; !enumStoreCerts.atEnd(); enumStoreCerts.moveNext()) {
                    StoreCert = enumStoreCerts.item();
                    
                    if (StoreCert.Thumbprint == ChainCert.Thumbprint) {
                        bIsValid = true;
                    }
                }
            }
        }
        
        if (bIsValid) {
            return (true);
        } else {
            return (false);
        }
    }
}

function VerifyFilesExistance(strHashesFile,strRootDir) {
    var arrFilesInHash = new Array();
    var arrContent = new Array();
    
    // Get FileSystemObject Objects
    var fso = new ActiveXObject("Scripting.FileSystemObject");
    f = fso.GetFile (strHashesFile);
    
    try {
        // Retrive all signed files from hashes file
        arrFilesInHash = GetFilesFromHash(strHashesFile)

        // Retrive directory structure
        arrContent = GetDirContent(strRootDir)

        // Remove root directory string from content arrray
        arrContent = RemoveStringFromArray(arrContent, strRootDir)

        // Compare both Arrays
        if (CompareLists(arrContent, arrFilesInHash, f.Name)) {
            return (true);
        } else {
            return (false);
        }
        
  	} catch (e) {
  	    LogEvent(1, e.description);
        return (false);
    }
}

function CompareLists(arrFilesInDir, arrFilesHased, strHashesFile)
{
    var strFilesInHash = arrFilesHased.toString();
    
    // Iterate all files in array
    for (var i=0; arrFilesInDir.length > i; i++) {
	    if (arrFilesInDir[i] == strHashesFile) {continue} // Ignore hases file
            if (strFilesInHash.indexOf(arrFilesInDir[i]) == -1) {
	            return (false)
            }
        }
    
    return (true)
}

function RemoveStringFromArray(arrOriginal, strRootFolder)
{   
    // Iterate all items in array
    for (var i=0; arrOriginal.length > i; i++) {
         arrOriginal[i] = arrOriginal[i].replace(strRootFolder, "", "i") // Replace strRootFolder with ""
    }
    
    return (arrOriginal)
}

function GetDirContent(strDir)
{
    var arrDirContent = new Array();
    var arrFilesInDir = GetFilesInDir(strDir);
    var arrFoldersInDir = GetFoldersInDir(strDir);
    
    // Insert all files in current dir into array 
    arrDirContent = arrDirContent.concat(arrDirContent,arrFilesInDir);
    
    // Iterate all sub folders in current directory
    for (var i=0; arrFoldersInDir.length > i; i++) {
         arrDirContent = arrDirContent.concat(GetDirContent(arrFoldersInDir[i]));
    }
    
    return (arrDirContent)  
}

function GetFilesFromHash(strHashFile)
{
    var arrFilesHased = new Array();
    
    // Get FileSystemObject Objects
    fso = new ActiveXObject("Scripting.FileSystemObject");
    f = fso.GetFile (strHashFile);
    ts = f.OpenAsTextStream(MSC.ForReading,MSC.TristateTrue)
    
    strFileHash = "";
    while (!ts.AtEndOfStream) {
        strLine = ts.ReadLine();
        if (strLine.indexOf("!") != -1) {
            arrFileHashData = strLine.split("!");
	        arrFilesHased.push(arrFileHashData[0]);
        }
    }
    return (arrFilesHased);
}

function GetFilesInDir(strDir)
{
    var arrFilesInDir = new Array();
    var currentDir;
    var files;
    
    // Get FileSystemObject Objects
    fso = new ActiveXObject("Scripting.FileSystemObject");
    currentDir = fso.GetFolder(strDir);
    files = new Enumerator(currentDir.Files);
    
    // Get all files in files object
    for (;!files.atEnd();files.moveNext()) {
        arrFilesInDir.push(new String(files.item()))
    }
    
    return (arrFilesInDir)
}

function GetFoldersInDir(strDir)
{
    var arrSubdirsInDir = new Array();
    var currentDir;
    var subdris;
    
    // Get FileSystemObject Objects
    fso = new ActiveXObject("Scripting.FileSystemObject");
    var currentDir = fso.GetFolder(strDir);
    var subdirs = new Enumerator(currentDir.SubFolders);
    
    // Get all subfolders in subdirs object
    for (;!subdirs.atEnd();subdirs.moveNext()) {
        arrSubdirsInDir.push(new String(subdirs.item()))
    }
    
    return (arrSubdirsInDir)
}

function VerifyHashes (
    strHashesFile, 
    strTrustStore, 
    strStorePassword,
    strRootDir
) {
    var arrFileHashData;
    var bIsExclamation;
    var strFilename;
    var strFileHash;
    var strLine;
    var fso;
    var ts;
    var f;

    // Get FileSystemObject Object
    fso = new ActiveXObject("Scripting.FileSystemObject");
    
    f = fso.GetFile (strHashesFile);
    ts = f.OpenAsTextStream(MSC.ForReading,MSC.TristateTrue);
    
    bIsExclamation = false;
    strFileHash = "";
    while (!ts.AtEndOfStream) {
        strLine = ts.ReadLine();
        if (strLine.indexOf("!") != -1) {
            if (strFileHash != "") {
            	bIsExclamation = true;
                if (!VerifySignature(strFilename,strFileHash,strTrustStore,strStorePassword)) {
                    return (false);
                }
            }
            
            arrFileHashData = strLine.split("!");
            strFilename = strRootDir + "\\" + arrFileHashData[0];
            strFileHash = arrFileHashData[1];
        } else {
            strFileHash += strLine;
        }
    }
    
    if (bIsExclamation) { 
	    return (true);
    } else {
    	return (false);
    }
}

function CreateFileSignature (
    strFilename,
    strCertSubject
) {
    var strFileContent;
    var oCertificates;
    var oSignedData;
    var oSigner;
    var oStore;
    var oShell;
    var fso;
    var ts;
    var f;

    // Get FileSystemObject Object
    fso = new ActiveXObject("Scripting.FileSystemObject");
    oStore = new ActiveXObject ("CAPICOM.Store");
    
    oStore.Open (MSC.CAPICOM_CURRENT_USER_STORE, "MY");
    
    oCertificates = oStore.Certificates;
    
    oCertificates = oCertificates.Find (MSC.CAPICOM_CERTIFICATE_FIND_KEY_USAGE, MSC.CAPICOM_DIGITAL_SIGNATURE_KEY_USAGE);
    oCertificates = oCertificates.Find (MSC.CAPICOM_CERTIFICATE_FIND_SUBJECT_NAME, strCertSubject);

    oSignedData = new ActiveXObject ("CAPICOM.SignedData");
    oSigner = new ActiveXObject ("CAPICOM.Signer");

    oSigner.Options = MSC.CAPICOM_CERTIFICATE_INCLUDE_END_ENTITY_ONLY;
    oSigner.Certificate = oCertificates(1);
    ExecAndLog ("RHB64Encoder " + "\"" + strFilename + "\"" + " b64.txt");    
    f = fso.GetFile ("b64.txt");
    ts = f.OpenAsTextStream(MSC.ForReading,MSC.TristateTrue);
    oSignedData.Content = ts.ReadAll();
    ts.close();
    ExecAndLog ("cmd /c del b64.txt");
    
    return (oSignedData.Sign(oSigner, true));
}

function CreateHashes (
    strHashesFile,
    strCertSubject,
    strRootDir
) {
    var enumFiles;
    var fcFiles;
    var fso;
    var ts;
    var f;

    // Get FileSystemObject Object
    fso = new ActiveXObject("Scripting.FileSystemObject");

    fcFiles = GetDirectoryFiles (strRootDir,true);

    enumFiles = new Enumerator(fcFiles);

    ts = fso.CreateTextFile(strHashesFile, true, MSC.TristateTrue);
    
    for (; !enumFiles.atEnd(); enumFiles.moveNext()) {
        ts.WriteLine (
        	enumFiles.item().substr(strRootDir.length + 1) + 
        	"!" + 
        	CreateFileSignature (
        		enumFiles.item(),
        		strCertSubject
        	)
        );
    }

    ts.Close();
}
