Пример #1
0
        /// ----------------------------------------------------------------------------------------
        /// <summary>
        /// Decrypt and deserialize SEB settings
        /// When forEditing = true, then the decrypting password the user entered and/or
        /// certificate reference found in the .seb file is returned
        /// </summary>
        /// ----------------------------------------------------------------------------------------
        public static DictObj DecryptSEBSettings(byte[] sebData, bool forEditing, ref string sebFilePassword, ref bool passwordIsHash, ref X509Certificate2 sebFileCertificateRef, bool suppressFileFormatError = false)
        {
            // Ungzip the .seb (according to specification >= v14) source data
            byte[] unzippedSebData = GZipByte.Decompress(sebData);

            // if unzipped data is not null, then unzipping worked, we use unzipped data
            // if unzipped data is null, then the source data may be an uncompressed .seb file, we proceed with it
            if (unzippedSebData != null)
            {
                sebData = unzippedSebData;
            }

            string prefixString;

            // save the data including the first 4 bytes for the case that it's acutally an unencrypted XML plist
            byte[] sebDataUnencrypted = sebData.Clone() as byte[];

            // Get 4-char prefix
            prefixString = GetPrefixStringFromData(ref sebData);

            //// Check prefix identifying encryption modes

            /// Check for new Multipart and Custom headers

            // Multipart Config File: The first part containts the regular SEB key/value settings
            // following parts can contain additional resources. An updated SEB version will be
            // able to read and process those parts sequentially as a stream.
            // Therefore potentially large additional resources won't have to be loaded into memory at once
            if (prefixString.CompareTo(MULTIPART_MODE) == 0)
            {
                // Skip the Multipart Config File header
                byte[] multipartConfigLengthData = GetPrefixDataFromData(ref sebData, MULTIPART_LENGTH);
                long   multipartConfigLength     = BitConverter.ToInt64(multipartConfigLengthData, 0);
                Logger.AddInformation("Multipart Config File, first part (settings) length: " + multipartConfigLength);

                try
                {
                    Logger.AddInformation("Cropping config file, as this SEB version cannot process additional parts of multipart config files.");

                    byte[] dataFirstPart = new byte[sebData.Length - multipartConfigLength];
                    Buffer.BlockCopy(sebData, 0, dataFirstPart, 0, dataFirstPart.Length);
                    sebData = dataFirstPart;
                }
                catch (Exception ex)
                {
                    Logger.AddError("Error while cropping config file", null, ex, ex.Message);
                }
            }

            // Custom Header: Containts a 32 bit value for the length of the header
            // followed by the custom header information. After the header, regular
            // SEB config file data follows
            if (prefixString.CompareTo(CUSTOM_HEADER_MODE) == 0)
            {
                // Skip the Custom Header
                byte[] customHeaderLengthData = GetPrefixDataFromData(ref sebData, CUSTOMHEADER_LENGTH);
                int    customHeaderLength     = BitConverter.ToInt32(customHeaderLengthData, 0);
                Logger.AddInformation("Custom Config File Header length: " + customHeaderLength);
                try
                {
                    Logger.AddInformation("Removing custom header from config file data. This SEB version cannot process this header type and will ignore it.");

                    byte[] customHeaderData = GetPrefixDataFromData(ref sebData, customHeaderLength);

                    Logger.AddInformation("Custom header data: " + customHeaderData);
                }
                catch (Exception ex)
                {
                    Logger.AddError("Error while removing custom header from config file data", null, ex, ex.Message);
                }
            }

            // Prefix = pksh ("Public-Symmetric Key Hash") ?

            if (prefixString.CompareTo(PUBLIC_SYMMETRIC_KEY_MODE) == 0)
            {
                // Decrypt with cryptographic identity/private and symmetric key
                sebData = DecryptDataWithPublicKeyHashPrefix(sebData, true, forEditing, ref sebFileCertificateRef);
                if (sebData == null)
                {
                    return(null);
                }

                // Get 4-char prefix again
                // and remaining data without prefix, which is either plain or still encoded with password
                prefixString = GetPrefixStringFromData(ref sebData);
            }

            // Prefix = pkhs ("Public Key Hash") ?

            if (prefixString.CompareTo(PUBLIC_KEY_HASH_MODE) == 0)
            {
                // Decrypt with cryptographic identity/private key
                sebData = DecryptDataWithPublicKeyHashPrefix(sebData, false, forEditing, ref sebFileCertificateRef);
                if (sebData == null)
                {
                    return(null);
                }

                // Get 4-char prefix again
                // and remaining data without prefix, which is either plain or still encoded with password
                prefixString = GetPrefixStringFromData(ref sebData);
            }

            // Prefix = pswd ("Password") ?

            if (prefixString.CompareTo(PASSWORD_MODE) == 0)
            {
                // Decrypt with password
                // if the user enters the right one
                byte[] sebDataDecrypted = null;
                string password;
                // Allow up to 5 attempts for entering decoding password
                string enterPasswordString = SEBUIStrings.enterPassword;
                int    i = 5;
                do
                {
                    i--;
                    // Prompt for password
                    password = SebPasswordDialogForm.ShowPasswordDialogForm(SEBUIStrings.loadingSettings, enterPasswordString);
                    if (password == null)
                    {
                        return(null);
                    }
                    //error = nil;
                    sebDataDecrypted    = SEBProtectionController.DecryptDataWithPassword(sebData, password);
                    enterPasswordString = SEBUIStrings.enterPasswordAgain;
                    // in case we get an error we allow the user to try it again
                } while ((sebDataDecrypted == null) && i > 0);
                if (sebDataDecrypted == null)
                {
                    //wrong password entered in 5th try: stop reading .seb file
                    MessageBox.Show(SEBUIStrings.decryptingSettingsFailed, SEBUIStrings.decryptingSettingsFailedReason, MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return(null);
                }
                sebData = sebDataDecrypted;
                // If these settings are being decrypted for editing, we return the decryption password
                if (forEditing)
                {
                    sebFilePassword = password;
                }
            }
            else
            {
                // Prefix = pwcc ("Password Configuring Client") ?

                if (prefixString.CompareTo(PASSWORD_CONFIGURING_CLIENT_MODE) == 0)
                {
                    // Decrypt with password and configure local client settings
                    // and quit afterwards, returning if reading the .seb file was successfull
                    DictObj sebSettings = DecryptDataWithPasswordForConfiguringClient(sebData, forEditing, ref sebFilePassword, ref passwordIsHash);
                    return(sebSettings);
                }
                else
                {
                    // Prefix = plnd ("Plain Data") ?

                    if (prefixString.CompareTo(PLAIN_DATA_MODE) != 0)
                    {
                        // No valid 4-char prefix was found in the .seb file
                        // Check if .seb file is unencrypted
                        if (prefixString.CompareTo(UNENCRYPTED_MODE) == 0)
                        {
                            // .seb file seems to be an unencrypted XML plist
                            // get the original data including the first 4 bytes
                            sebData = sebDataUnencrypted;
                        }
                        else
                        {
                            // No valid prefix and no unencrypted file with valid header
                            // cancel reading .seb file
                            if (!suppressFileFormatError)
                            {
                                MessageBox.Show(SEBUIStrings.settingsNotUsable, SEBUIStrings.settingsNotUsableReason, MessageBoxButtons.OK, MessageBoxIcon.Error);
                            }
                            return(null);
                        }
                    }
                }
            }
            // If we don't deal with an unencrypted seb file
            // ungzip the .seb (according to specification >= v14) decrypted serialized XML plist data
            if (prefixString.CompareTo(UNENCRYPTED_MODE) != 0)
            {
                sebData = GZipByte.Decompress(sebData);
            }

            // Get preferences dictionary from decrypted data
            DictObj sebPreferencesDict = GetPreferencesDictFromConfigData(sebData, forEditing);

            // If we didn't get a preferences dict back, we abort reading settings
            if (sebPreferencesDict == null)
            {
                return(null);
            }

            // We need to set the right value for the key sebConfigPurpose to know later where to store the new settings
            sebPreferencesDict[SEBSettings.KeySebConfigPurpose] = (int)SEBSettings.sebConfigPurposes.sebConfigPurposeStartingExam;

            // Reading preferences was successful!
            return(sebPreferencesDict);
        }
Пример #2
0
        /// ----------------------------------------------------------------------------------------
        /// <summary>
        /// Helper method which decrypts the byte array using an empty password,
        /// or the administrator password currently set in SEB
        /// or asks for the password used for encrypting this SEB file
        /// for configuring the client
        /// </summary>
        /// ----------------------------------------------------------------------------------------
        private static DictObj DecryptDataWithPasswordForConfiguringClient(byte[] sebData, bool forEditing, ref string sebFilePassword, ref bool passwordIsHash)
        {
            passwordIsHash = false;
            string password;
            // First try to decrypt with the current admin password
            // get admin password hash
            string hashedAdminPassword = (string)SEBSettings.valueForDictionaryKey(SEBSettings.settingsCurrent, SEBSettings.KeyHashedAdminPassword);

            if (hashedAdminPassword == null)
            {
                hashedAdminPassword = "";
            }
            // We use always uppercase letters in the base16 hashed admin password used for encrypting
            hashedAdminPassword = hashedAdminPassword.ToUpper();
            DictObj sebPreferencesDict = null;

            byte[] decryptedSebData = SEBProtectionController.DecryptDataWithPassword(sebData, hashedAdminPassword);
            if (decryptedSebData == null)
            {
                // If decryption with admin password didn't work, try it with an empty password
                decryptedSebData = SEBProtectionController.DecryptDataWithPassword(sebData, "");
                if (decryptedSebData == null)
                {
                    // If decryption with empty and admin password didn't work, ask for the password the .seb file was encrypted with
                    // Allow up to 5 attempts for entering decoding password
                    int i = 5;
                    password = null;
                    string enterPasswordString = SEBUIStrings.enterEncryptionPassword;
                    do
                    {
                        i--;
                        // Prompt for password
                        password = SebPasswordDialogForm.ShowPasswordDialogForm(SEBUIStrings.reconfiguringLocalSettings, enterPasswordString);
                        // If cancel was pressed, abort
                        if (password == null)
                        {
                            return(null);
                        }
                        string hashedPassword = SEBProtectionController.ComputePasswordHash(password);
                        // we try to decrypt with the hashed password
                        decryptedSebData = SEBProtectionController.DecryptDataWithPassword(sebData, hashedPassword);
                        // in case we get an error we allow the user to try it again
                        enterPasswordString = SEBUIStrings.enterEncryptionPasswordAgain;
                    } while (decryptedSebData == null && i > 0);
                    if (decryptedSebData == null)
                    {
                        //wrong password entered in 5th try: stop reading .seb file
                        MessageBox.Show(SEBUIStrings.reconfiguringLocalSettingsFailed, SEBUIStrings.reconfiguringLocalSettingsFailedWrongPassword, MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return(null);
                    }
                    else
                    {
                        // Decrypting with entered password worked: We save it for returning it later
                        if (forEditing)
                        {
                            sebFilePassword = password;
                        }
                    }
                }
            }
            else
            {
                //decrypting with hashedAdminPassword worked: we save it for returning as decryption password
                sebFilePassword = hashedAdminPassword;
                // identify that password as hash
                passwordIsHash = true;
            }
            /// Decryption worked

            // Ungzip the .seb (according to specification >= v14) decrypted serialized XML plist data
            decryptedSebData = GZipByte.Decompress(decryptedSebData);

            // Check if the openend reconfiguring seb file has the same admin password inside like the current one

            try
            {
                sebPreferencesDict = (DictObj)Plist.readPlist(decryptedSebData);
            }
            catch (Exception readPlistException)
            {
                // Error when deserializing the decrypted configuration data
                // We abort reading the new settings here
                MessageBox.Show(SEBUIStrings.loadingSettingsFailed, SEBUIStrings.loadingSettingsFailedReason, MessageBoxButtons.OK, MessageBoxIcon.Error);
                Console.WriteLine(readPlistException.Message);
                return(null);
            }
            // Get the admin password set in these settings
            string sebFileHashedAdminPassword = (string)SEBSettings.valueForDictionaryKey(sebPreferencesDict, SEBSettings.KeyHashedAdminPassword);

            if (sebFileHashedAdminPassword == null)
            {
                sebFileHashedAdminPassword = "";
            }
            // Has the SEB config file the same admin password inside as the current settings have?
            if (String.Compare(hashedAdminPassword, sebFileHashedAdminPassword, StringComparison.OrdinalIgnoreCase) != 0)
            {
                //No: The admin password inside the .seb file wasn't the same as the current one
                if (forEditing)
                {
                    // If the file is openend for editing (and not to reconfigure SEB)
                    // we have to ask the user for the admin password inside the file
                    if (!askForPasswordAndCompareToHashedPassword(sebFileHashedAdminPassword, forEditing))
                    {
                        // If the user didn't enter the right password we abort
                        return(null);
                    }
                }
                else
                {
                    // The file was actually opened for reconfiguring the SEB client:
                    // we have to ask for the current admin password and
                    // allow reconfiguring only if the user enters the right one
                    // We don't check this for the case the current admin password was used to encrypt the new settings
                    // In this case there can be a new admin pw defined in the new settings and users don't need to enter the old one
                    if (passwordIsHash == false && hashedAdminPassword.Length > 0)
                    {
                        // Allow up to 5 attempts for entering current admin password
                        int i = 5;
                        password = null;
                        string hashedPassword;
                        string enterPasswordString = SEBUIStrings.enterCurrentAdminPwdForReconfiguring;
                        bool   passwordsMatch;
                        do
                        {
                            i--;
                            // Prompt for password
                            password = SebPasswordDialogForm.ShowPasswordDialogForm(SEBUIStrings.reconfiguringLocalSettings, enterPasswordString);
                            // If cancel was pressed, abort
                            if (password == null)
                            {
                                return(null);
                            }
                            if (password.Length == 0)
                            {
                                hashedPassword = "";
                            }
                            else
                            {
                                hashedPassword = SEBProtectionController.ComputePasswordHash(password);
                            }
                            passwordsMatch = (String.Compare(hashedPassword, hashedAdminPassword, StringComparison.OrdinalIgnoreCase) == 0);
                            // in case we get an error we allow the user to try it again
                            enterPasswordString = SEBUIStrings.enterCurrentAdminPwdForReconfiguringAgain;
                        } while (!passwordsMatch && i > 0);
                        if (!passwordsMatch)
                        {
                            //wrong password entered in 5th try: stop reading .seb file
                            MessageBox.Show(SEBUIStrings.reconfiguringLocalSettingsFailed, SEBUIStrings.reconfiguringLocalSettingsFailedWrongCurrentAdminPwd, MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return(null);
                        }
                    }
                }
            }

            // We need to set the right value for the key sebConfigPurpose to know later where to store the new settings
            sebPreferencesDict[SEBSettings.KeySebConfigPurpose] = (int)SEBSettings.sebConfigPurposes.sebConfigPurposeConfiguringClient;

            // Reading preferences was successful!
            return(sebPreferencesDict);
        }