Example #1
0
        internal static bool   Decrypt(
            DecMPEFileInfo decMpeFileInfo,
            string[] passwords,
            string outputDir,
            IProgress <string> progress = null)
        {
            int nQuestions         = decMpeFileInfo._nQuestions;
            int nRequiredPasswords = decMpeFileInfo._nRequiredPasswords;

            int nDecryptedQuestionKeys = 0;                                                      // Number of QuestionKeys that could be decoded. (J)複号できたQuestionKeyの数

            int[]  questionKeyIndexes = new int[nRequiredPasswords];                             // Index of QuestionKeys that could be decoded. (J)複号できたQuestionKeyのIndex
            byte[] questionKeys       = new byte[nRequiredPasswords * Crypto.AES_KEY_SIZE_BYTE]; // Combined Question Key (for decrypt dataKey)

            // check password
            for (int i = 0; i < nQuestions && nDecryptedQuestionKeys < nRequiredPasswords; ++i)
            {
                var passwordTxt = passwords[i];
                if (passwordTxt == "")
                {
                    continue;
                }
                var question = decMpeFileInfo._decQuestions[i];

                byte[] password = Encoding.UTF8.GetBytes(passwordTxt);
                for (int j = 0; j < question.nPasswords; ++j)
                {
                    var result = Crypto.decryptByte(question.encryptedQuestionKeys, j * Crypto.AES_KEY_SIZE_BYTE_WITH_PADDING, Crypto.AES_KEY_SIZE_BYTE_WITH_PADDING, password, Crypto.createSalt(i, j));
                    if (result != null)
                    {
                        if (result.Length != Crypto.AES_KEY_SIZE_BYTE)
                        {   // assertion
                            throw new Exception("broken file");
                        }

                        // store question key
                        Buffer.BlockCopy(result, 0, questionKeys, nDecryptedQuestionKeys * Crypto.AES_KEY_SIZE_BYTE, Crypto.AES_KEY_SIZE_BYTE);
                        questionKeyIndexes[nDecryptedQuestionKeys] = i;
                        nDecryptedQuestionKeys += 1;
                        break;
                    }
                }
            }

            if (nDecryptedQuestionKeys < nRequiredPasswords)
            {
                return(false);   // fail. number of passwords is not enough.
            }


            // decrypt data
            byte[]  dataKey      = null;
            int[][] combinaitons = Combination.enumerateCombination(nQuestions, nRequiredPasswords);
            for (int i = 0; i < combinaitons.Length; ++i)
            {
                if (combinaitons[i].SequenceEqual(questionKeyIndexes))
                {
                    dataKey = Crypto.decryptByte(decMpeFileInfo._encryptedDataKeys, i * Crypto.AES_KEY_SIZE_BYTE_WITH_PADDING, Crypto.AES_KEY_SIZE_BYTE_WITH_PADDING, questionKeys);
                    break;
                }
            }

            if (dataKey == null)
            {
                throw new Exception("broken file");
            }

            progress?.Report("(1/3) decripting archive.");
            // OK
            var tmpFileCompress = System.IO.Path.GetRandomFileName();

            try
            {
                using (FileStream zipFS = new FileStream(tmpFileCompress, FileMode.Create))
                {
                    decMpeFileInfo._encryptedFS.Position = decMpeFileInfo._dataStartPosition;
                    Crypto.decryptStream(decMpeFileInfo._encryptedFS, zipFS, dataKey);
                }

                // ZipFile.ExtractToDirectory can not read files unless Close() is done on zipFS
                //(J) zipFS を Close() しないと ZipFile.ExtractToDirectory はファイルを読み込めない
                try
                {
                    progress?.Report("(2/3) creating output file(s).");
                    System.IO.Compression.ZipFile.ExtractToDirectory(tmpFileCompress, outputDir);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
            finally
            {
                File.Delete(tmpFileCompress);
            }
            progress?.Report("(3/3) finished.");

            return(true);    // succeed
        }
Example #2
0
        /**
         * encryption
         */
        internal static void Encrypt_2(
            FileStream encryptedFS,
            string[] hintList,
            List <string>[] passwordList,
            int nRequiredPasswords,
            AppConst.MPE_Flag flag,
            RNGCryptoServiceProvider r,
            byte[] dataKey,
            FileStream outputFS,
            IProgress <string> progress = null)
        {
            // generate questionKeys, encryptedQuestionKeys
            int nQuestions = hintList.Length;

            byte[][]   questionKeys          = new byte[nQuestions][];
            byte[][][] encryptedQuestionKeys = new byte[nQuestions][][];
            for (int i = 0; i < nQuestions; ++i)
            {
                questionKeys[i] = new byte[Crypto.AES_KEY_SIZE_BYTE];   // Encryption key for dataKey
                r.GetBytes(questionKeys[i]);

                // encrypt questionKey
                // Based on the number of passwords, assign the location of the password to encrypt questionKeys. In order to hide the number of passwords, dummy indexes are also included.
                // For example, when three passwords are set in the Question being processed, the following values ​​are randomly set in passwordEncryptIndexes.
                // passwordEncryptIndexes = {1, -1, 0, 2, -1}
                // In this case, encryptedQuestionKeys is [question 0] encrypted questionKey with password 1, [1]: dummy, [2]: questionKey encrypted with password 0, [3]: questionKey encrypted with password 2 , [4]: ​​Dummy is stored.
                //(J) パスワードの個数をもとに、questionKeysを暗号化するパスワードの位置を割り当てる。パスワード個数を隠蔽するため、ダミーのインデクスも含まれる。
                //(J) たとえば、処理中の Question にパスワードが3つ設定されている場合に、passwordEncryptIndexes には以下のような値をランダムに設定する。
                //(J) passwordEncryptIndexes = {1, -1, 0, 2, -1}
                //(J) この場合はencryptedQuestionKeys は、[0]:パスワード1で暗号化されたquestionKey, [1]:ダミー, [2]:パスワード0で暗号化されたquestionKey, [3]:パスワード2で暗号化されたquestionKey, [4]:ダミー が格納される。
                int[] passwordEncryptIndexes = alllocPasswordEncryptIndexes(passwordList[i].Count);
                encryptedQuestionKeys[i] = new byte[passwordEncryptIndexes.Length][];
                for (int j = 0; j < passwordEncryptIndexes.Length; ++j)
                {
                    if (passwordEncryptIndexes[j] >= 0)
                    {   // real password
                        String password      = passwordList[i][passwordEncryptIndexes[j]];
                        byte[] passwordBytes = Encoding.UTF8.GetBytes(password);

                        encryptedQuestionKeys[i][j] = Crypto.encryptByte(questionKeys[i], passwordBytes, Crypto.createSalt(i, j));
                        if (encryptedQuestionKeys[i][j].Length != Crypto.AES_KEY_SIZE_BYTE_WITH_PADDING)
                        {                                        // assertion
                            throw new Exception("system error"); //!
                        }
                    }
                    else
                    {   // dummy key
                        byte[] dummyKey = new byte[Crypto.AES_KEY_SIZE_BYTE_WITH_PADDING];
                        r.GetBytes(dummyKey);
                        encryptedQuestionKeys[i][j] = dummyKey;
                    }
                }
            }

            // generate encryptedDataKey
            int[][]  combinaiton         = Combination.enumerateCombination(nQuestions, nRequiredPasswords);
            byte[]   combinedQuestionKey = new byte[nRequiredPasswords * Crypto.AES_KEY_SIZE_BYTE];
            byte[][] encryptedDataKey    = new byte[combinaiton.Length][];
            for (int i = 0; i < combinaiton.Length; ++i)
            {
                // Create a password for dataKey from multiple question keys.
                //(J) 複数のquestion key から dataKey 用のパスワードを作成する
                for (int j = 0; j < combinaiton[i].Length; ++j)
                {
                    int qkIdx = combinaiton[i][j];
                    Buffer.BlockCopy(questionKeys[qkIdx], 0, combinedQuestionKey, j * Crypto.AES_KEY_SIZE_BYTE, Crypto.AES_KEY_SIZE_BYTE);
                }

                encryptedDataKey[i] = Crypto.encryptByte(dataKey, combinedQuestionKey);
                if (encryptedDataKey[i].Length != Crypto.AES_KEY_SIZE_BYTE_WITH_PADDING)
                {                                        // assertion
                    throw new Exception("system error"); //!
                }
            }

            progress?.Report("(3/4) creating output file.");
            // create question Header (for MPE File)
            using (var questionHeaderMS = new MemoryStream())
            {
                byte[] bytes;
                //	flag				1
                questionHeaderMS.WriteByte((byte)flag);
                //	nQuestions			4
                bytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(nQuestions));
                questionHeaderMS.Write(bytes, 0, bytes.Length);
                //	nRequiredPasswords		4
                bytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(nRequiredPasswords));
                questionHeaderMS.Write(bytes, 0, bytes.Length);
                //	nPasswordCombinations	4
                bytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(encryptedDataKey.Length));
                questionHeaderMS.Write(bytes, 0, bytes.Length);
                //	encryptedDataKeys	n  * 48
                for (int i = 0; i < encryptedDataKey.Length; ++i)
                {
                    questionHeaderMS.Write(encryptedDataKey[i], 0, encryptedDataKey[i].Length);
                }

                //	Question			n
                for (int i = 0; i < nQuestions; ++i)
                {
                    // hint string len      4
                    byte[] hintStrBytes = Encoding.UTF8.GetBytes(hintList[i]);
                    bytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(hintStrBytes.Length));
                    questionHeaderMS.Write(bytes, 0, bytes.Length);
                    // hint string          n
                    questionHeaderMS.Write(hintStrBytes, 0, hintStrBytes.Length);
                    // nPasswords            4
                    bytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(encryptedQuestionKeys[i].Length));
                    questionHeaderMS.Write(bytes, 0, bytes.Length);
                    // encryptedQuestionKeys n * 48
                    for (int j = 0; j < encryptedQuestionKeys[i].Length; ++j)
                    {
                        questionHeaderMS.Write(encryptedQuestionKeys[i][j], 0, encryptedQuestionKeys[i][j].Length);
                    }
                }

                Encrypt_3(questionHeaderMS, encryptedFS, outputFS);
            }
        }