예제 #1
0
        private void InitRead()
        {
            CipherInfo Cipher1 = null;
            CipherInfo Cipher2 = null;

            byte[] Key2 = null;
            byte[] IV2  = null;

            try
            {
                // File format version has been read
                var Subversion = m_sBaseStream.ReadByte(); // Subversion
                if (Subversion > SUB_VERSION)
                {
                    throw new InvalidDataException("Invalid sub version, please check for newer MultiCipher Plugin");
                }

                if (Subversion != SUB_VERSION)
                {
                    MessageService.ShowWarning("MultiCipher Plugin:", string.Format("You are opening Version 2.{0} of MultiCipher Keepass Database, a one way upgrade will be performed to version 2.2", Subversion), "Once saved, you will not be able to open the database in an older version of the plugin.");
                }


                m_Config.Algorithm1 = (SymAlgoCode)m_sBaseStream.ReadByte();
                Cipher1             = new CipherInfo(m_Config.Algorithm1);
                Cipher1.SetKey(m_1Key32, m_1IV16);

                m_Config.Algorithm2 = (SymAlgoCode)m_sBaseStream.ReadByte();
                Cipher2             = new CipherInfo(m_Config.Algorithm2);

                m_Config.KeyOption = (KeyOption)m_sBaseStream.ReadByte();

                if (m_Config.KeyOption == KeyOption.Yubikey_HMAC_SHA1)
                {
                    m_Config.YubikeySlot            = (byte)m_sBaseStream.ReadByte();
                    m_Config.YubikeyChallengeLength = (byte)m_sBaseStream.ReadByte();
                    m_Config.YubikeyChallenge       = new byte[64];
                    m_sBaseStream.Read(m_Config.YubikeyChallenge, 0, 64);
                }


                m_sBaseStream.ReadByte(); // Derivation Method ignore for now


                var MasterSeed = new byte[32];
                m_sBaseStream.Read(MasterSeed, 0, 32);

                var TransformSeed = new byte[32];
                m_sBaseStream.Read(TransformSeed, 0, 32);

                IV2 = new byte[Cipher2.IVSizeInBytes];
                m_sBaseStream.Read(IV2, 0, (int)Cipher2.IVSizeInBytes);

                byte[] NumRoundByteArray = new byte[8];
                m_sBaseStream.Read(NumRoundByteArray, 0, 8);
                ulong NumRounds = Extensions.ToLittleEndianUInt64(NumRoundByteArray);

                m_Config.Key2Transformations = NumRounds;

                byte[] PlainTextLengthBytes = new byte[4];
                m_sBaseStream.Read(PlainTextLengthBytes, 0, 4);

                var PlainTextLength = Extensions.ToLittleEndianInt32(PlainTextLengthBytes);

                int    ContentBufferLength = Get64BlockAlignSize(PlainTextLength);
                byte[] PlainTextBuffer     = new byte[ContentBufferLength];


                int read = m_sBaseStream.Read(PlainTextBuffer, 0, ContentBufferLength);
                if (read != ContentBufferLength)
                {
                    throw new InvalidDataException("Invalid Data length");
                }

                using (var Transformer = Cipher1.GetCipherTransformer())
                    Transformer.Decrypt(PlainTextBuffer, 0, ContentBufferLength);

                var PlainTextHash32 = new SHA256Managed();
                PlainTextHash32.TransformFinalBlock(PlainTextBuffer, 0, PlainTextLength);

                byte[] ContentBuffer2 = new byte[ContentBufferLength];

                read = m_sBaseStream.Read(ContentBuffer2, 0, ContentBufferLength);
                if (read != ContentBufferLength)
                {
                    throw new InvalidDataException("Invalid Data length 2");
                }

                Key2 = m_Config.Get2ndKey32(PlainTextHash32.Hash, MasterSeed, TransformSeed);
                Cipher2.SetKey(Key2, IV2);


                try
                {
                    using (var Transformer2 = Cipher2.GetCipherTransformer())
                        Transformer2.Decrypt(ContentBuffer2, 0, ContentBufferLength);

                    for (int i = 0; i < PlainTextLength; i++)
                    {
                        PlainTextBuffer[i] ^= ContentBuffer2[i];
                    }
                }
                finally
                {
                    Array.Clear(ContentBuffer2, 0, ContentBuffer2.Length);
                }

                m_sBaseStream.Read(ContentBuffer2, 0, 1);  // read past end

                m_ReadPlainTextStream = new MemoryStream(PlainTextBuffer, 0, PlainTextLength, false, true);
            }
            finally
            {
                if (Key2 != null)
                {
                    MemUtil.ZeroByteArray(Key2);
                }
                if (IV2 != null)
                {
                    MemUtil.ZeroArray(IV2);
                }

                if (Cipher1 != null)
                {
                    Cipher1.Dispose();
                }
                if (Cipher2 != null)
                {
                    Cipher2.Dispose();
                }
            }
        }
예제 #2
0
        protected override void Dispose(bool disposing)
        {
            if (disposing && !Is_Disposed)
            {
                if (m_bWriting)
                {
                    byte[]     Key2    = null;
                    byte[]     IV2     = null;
                    CipherInfo Cipher1 = null;
                    CipherInfo Cipher2 = null;

                    try
                    {
                        if (m_sBaseStream == null)
                        {
                            throw new IOException("Stream not open");
                        }

                        // First encryption
                        Cipher1 = new CipherInfo(m_Config.Algorithm1);
                        Cipher1.SetKey(m_1Key32, m_1IV16);

                        int BufferSize = Get64BlockAlignSize(m_WriteBytesLength);

                        // Make sure we have a buffer that is 64 byte aligned
                        byte[] PlainTextBuffer = new byte[BufferSize];
                        int    Pos             = 0;

                        // Dump the collected data to this buffer
                        foreach (byte[] Bytes in m_WriteDataBytesList)
                        {
                            Array.Copy(Bytes, 0, PlainTextBuffer, Pos, Bytes.Length);
                            Array.Clear(Bytes, 0, Bytes.Length);
                            Pos += Bytes.Length;
                        }
                        m_WriteDataBytesList = null;

                        var    RndGenerator    = CryptoRandom.Instance;
                        byte[] RandomDataBytes = RndGenerator.GetRandomBytes((uint)BufferSize);

                        // XOR the plaintext with random data
                        for (int i = 0; i < BufferSize; i++)
                        {
                            PlainTextBuffer[i] ^= RandomDataBytes[i];
                        }

                        // Calculate hash of data part of XORred buffer
                        var XORedTextHash32 = new SHA256Managed();
                        XORedTextHash32.TransformFinalBlock(PlainTextBuffer, 0, m_WriteBytesLength);

                        // First encrypted buffer
                        var Encrypted1Buffer = PlainTextBuffer;
                        using (var Transformer = Cipher1.GetCipherTransformer())
                            Transformer.Encrypt(Encrypted1Buffer, 0, BufferSize);


                        // 2nd Cipher initialization information
                        Cipher2 = new CipherInfo(m_Config.Algorithm2);
                        IV2     = RndGenerator.GetRandomBytes(Cipher2.IVSizeInBytes);

                        Key2 = m_Config.Get2ndKey32(XORedTextHash32.Hash);
                        Cipher2.SetKey(Key2, IV2);

                        ///////  Start writing to base stream //////////

                        m_sBaseStream.WriteByte(2);           // File Version 2
                        m_sBaseStream.WriteByte(SUB_VERSION); // Sub Version
                        m_sBaseStream.WriteByte((byte)m_Config.Algorithm1);
                        m_sBaseStream.WriteByte((byte)m_Config.Algorithm2);
                        m_sBaseStream.WriteByte((byte)m_Config.KeyOption);
                        if (m_Config.KeyOption == KeyOption.Yubikey_HMAC_SHA1)     // Is Yubikey option?
                        {
                            m_sBaseStream.WriteByte(m_Config.YubikeySlot);         // Yubikey Slot
                            m_sBaseStream.WriteByte(m_Config.YubikeyChallengeLength);
                            m_sBaseStream.Write(m_Config.YubikeyChallenge, 0, 64); // Yubikey Challenge
                        }
                        m_sBaseStream.WriteByte((byte)m_Config.KeyDerivation);     // Key derivation method

                        m_sBaseStream.Write(m_Config.MasterSeed, 0, 32);
                        m_sBaseStream.Write(m_Config.TransformSeed, 0, 32);
                        m_sBaseStream.Write(IV2, 0, IV2.Length);
                        m_sBaseStream.Write(Extensions.GetLittleEndianBytes(m_Config.Key2Transformations), 0, 8);
                        m_sBaseStream.Write(Extensions.GetLittleEndianBytes(m_WriteBytesLength), 0, 4); // Write the length

                        m_sBaseStream.Write(Encrypted1Buffer, 0, BufferSize);

                        using (var Transformer = Cipher2.GetCipherTransformer())
                            Transformer.Encrypt(RandomDataBytes, 0, BufferSize);

                        m_sBaseStream.Write(RandomDataBytes, 0, BufferSize);
                    }
                    finally
                    {
                        if (Key2 != null)
                        {
                            MemUtil.ZeroByteArray(Key2);
                        }
                        if (IV2 != null)
                        {
                            MemUtil.ZeroArray(IV2);
                        }

                        if (Cipher1 != null)
                        {
                            Cipher1.Dispose();
                        }
                        if (Cipher2 != null)
                        {
                            Cipher2.Dispose();
                        }

                        if (m_WriteDataBytesList != null)
                        {
                            foreach (byte[] Bytes in m_WriteDataBytesList)
                            {
                                Array.Clear(Bytes, 0, Bytes.Length);
                            }
                        }
                    }
                }
                else
                {
                    if (m_ReadPlainTextStream != null)
                    {
                        // Have to clear the underlying buffer
                        byte[] buf = m_ReadPlainTextStream.GetBuffer();
                        if (buf != null)
                        {
                            MemUtil.ZeroByteArray(buf);
                        }

                        m_ReadPlainTextStream.Dispose();
                    }
                }
                Is_Disposed = true;
            }
            base.Dispose(disposing);
        }