Esempio n. 1
0
        protected internal static Cipher InitCipherForBlock(Cipher cipher, int block,
                                                            IEncryptionInfoBuilder builder, ISecretKey skey, int encryptMode)
        {
            EncryptionVerifier ver      = builder.GetVerifier();
            HashAlgorithm      hashAlgo = ver.HashAlgorithm;

            byte[] blockKey = new byte[4];
            LittleEndian.PutUInt(blockKey, 0, block);
            MessageDigest hashAlg = CryptoFunctions.GetMessageDigest(hashAlgo);

            hashAlg.Update(skey.GetEncoded());
            byte[]           encKey = hashAlg.Digest(blockKey);
            EncryptionHeader header = builder.GetHeader();
            int keyBits             = header.KeySize;

            encKey = CryptoFunctions.GetBlock0(encKey, keyBits / 8);
            if (keyBits == 40)
            {
                encKey = CryptoFunctions.GetBlock0(encKey, 16);
            }
            ISecretKey key = new SecretKeySpec(encKey, skey.GetAlgorithm());

            if (cipher == null)
            {
                cipher = CryptoFunctions.GetCipher(key, header.CipherAlgorithm, null, null, encryptMode);
            }
            else
            {
                cipher.Init(encryptMode, key);
            }
            return(cipher);
        }
Esempio n. 2
0
        protected internal static Cipher InitCipherForBlock(Cipher existing, int block, bool lastChunk,
                                                            IEncryptionInfoBuilder builder, ISecretKey skey, int encryptionMode)
        {
            EncryptionHeader header = builder.GetHeader();

            if (existing == null || lastChunk)
            {
                String pAdding = (lastChunk ? "PKCS5PAdding" : "NoPAdding");
                existing = CryptoFunctions.GetCipher(skey, header.CipherAlgorithm, header.ChainingMode, header.KeySalt, encryptionMode, pAdding);
            }

            byte[] blockKey = new byte[4];
            LittleEndian.PutInt(blockKey, 0, block);
            byte[] iv = CryptoFunctions.GenerateIv(header.HashAlgorithm, header.KeySalt, blockKey, header.BlockSize);

            AlgorithmParameterSpec aps;

            if (header.CipherAlgorithm == CipherAlgorithm.rc2)
            {
                aps = new RC2ParameterSpec(skey.GetEncoded().Length * 8, iv);
            }
            else
            {
                aps = new IvParameterSpec(iv);
            }

            existing.Init(encryptionMode, skey, aps);
            return(existing);
        }
Esempio n. 3
0
            public EncryptionHeader(byte[] contents)
            {
                var eh = EncryptionHeader.FromBytes(contents);

                this.FileName = eh.FileName;
                this.FileSize = eh.FileSize;
            }
Esempio n. 4
0
            public static EncryptionHeader ReadFrom(Stream stream)
            {
                if (stream == null)
                {
                    throw new ArgumentNullException("stream");
                }

                var reader        = new BinaryReader(stream);
                var newMagicBytes = reader.ReadBytes(HeaderMagicBytes.Length); // 8 bytes

                // Validate magic bytes
                if (false == EqualArrays(HeaderMagicBytes, newMagicBytes))
                {
                    throw new StreamCryptoException(StreamCryptoError.NotEncrypted, "Header not found at the beginning of the stream.");
                }
                var result = new EncryptionHeader();

                result._version    = reader.ReadInt32();   // 4 bytes
                result._workload   = reader.ReadInt32();   // 4 bytes
                result._bCryptSalt = reader.ReadBytes(16); // 16 bytes
                result._pbkdf2Salt = reader.ReadBytes(16); // 16 bytes
                // Total: 48 bytes
                // Ensure the complete header is read
                if (result._pbkdf2Salt.Length != 16)
                {
                    // EOS reached
                    throw new ArgumentException("End of stream reached.", "stream");
                }
                return(result);
            }
Esempio n. 5
0
        private Cipher GetCipher(ISecretKey key)
        {
            EncryptionHeader em = builder.GetHeader();
            ChainingMode     cm = em.ChainingMode;

            Debug.Assert(cm == ChainingMode.ecb);

            return(CryptoFunctions.GetCipher(key, em.CipherAlgorithm, cm, null, Cipher.DECRYPT_MODE));
        }
Esempio n. 6
0
        /// <summary>
        /// Encrypts the specified stream.
        /// </summary>
        /// <param name="input">A method to call to write to the encrypted output stream.</param>
        /// <param name="outputStream">The output stream.</param>
        /// <param name="password">The password.</param>
        /// <param name="workload">The workload.</param>
        /// <exception cref="System.ArgumentNullException">
        /// inputStream
        /// or
        /// outputStream
        /// </exception>
        /// <exception cref="Common.Security.Cryptography.IO.StreamCryptoException"></exception>
        /// <remarks>
        /// <para>
        /// This method encrypts all content written by the <see cref="output"/> delegate to the <see cref="Stream"/>
        /// passed to the delegate.
        /// </para>
        /// <para>
        /// This method uses the following algorithms:
        /// AES-256 - encryption
        /// bcrypt  - key derivation
        /// PBKDF2 on HMACSHA1 - key derivation (deriving 256 bit key for AES from 192 bit bcrypt output)
        /// SHA-256 - integrity check
        /// </para>
        /// </remarks>
        public static void EncryptStream(Action <Stream> input, Stream outputStream, string password, int workload)
        {
            if (input == null)
            {
                throw new ArgumentNullException("input");
            }
            if (outputStream == null)
            {
                throw new ArgumentNullException("outputStream");
            }

            var header = new EncryptionHeader(CurrentVersion, workload);
            var key    = DeriveKey(header, password, AesKeySize);

            using (var aes = CreateAes(key))
            {
                using (var hash = SHA256.Create())
                {
                    using (var cryptor = aes.CreateEncryptor())
                    {
                        // Do NOT dispose to avoid closing the output stream
                        var cryptoStream = new CryptoStream(outputStream, cryptor, CryptoStreamMode.Write);
                        // Do NOT dispose to avoid closing the output stream
                        var hashStream = new CryptoStream(cryptoStream, hash, CryptoStreamMode.Write);

                        try
                        {
                            header.WriteTo(outputStream);
                            input(hashStream);

                            // "FlushFinalBlock" can be called only on the outermost stream. It is automatically called on the inner stream
                            // if it is a "CryptoStream". Calling it explicitly on an inner stream causes an exception.
                            if (false == cryptoStream.HasFlushedFinalBlock)
                            {
                                cryptoStream.FlushFinalBlock();
                            }
                            if (false == hashStream.HasFlushedFinalBlock)
                            {
                                hashStream.FlushFinalBlock();
                            }
                        }
                        catch (Exception exc)
                        {
                            throw new StreamCryptoException(StreamCryptoError.EncryptionError, exc.Message, exc);
                        }

                        // Write footer
                        outputStream.Write(FooterMagicBytes, 0, FooterMagicBytes.Length);
                        var hashBytes = hash.Hash;
                        outputStream.Write(hashBytes, 0, hashBytes.Length);
                    }
                }
            }
        }
Esempio n. 7
0
        private bool encryptionFeasible(FileModel fileModel, IImageWrapper container)
        {
            var spread            = this.getByteSpread();
            var numberOfChannels  = Enum.GetValues(typeof(LosslessFileMuxxer.ByteOrder)).GetLength(0);
            var totalBytesInImage = container.Width * container.Height * numberOfChannels;

            var bytesAvailableForData = totalBytesInImage - EncryptionHeader.GetHeaderLength();
            var bytesNeededForData    = fileModel.FileContents.Length * spread;

            return(bytesAvailableForData >= bytesNeededForData);
        }
Esempio n. 8
0
        public FilePass(IStreamReader reader, RecordType id, ushort length)
            : base(reader, id, length)
        {
            // assert that the correct record type is instantiated
            Debug.Assert(this.Id == ID);

            this.wEncryptionType = reader.ReadUInt16();

            //XOR Obfuscation
            if (wEncryptionType == 0)
            {
                xorObfuscationKey    = reader.ReadUInt16();
                xorVerificationBytes = reader.ReadUInt16();
            }
            //RC4 Encryption or RC4 CryptoAPI
            else if (wEncryptionType == 1)
            {
                vMajor = reader.ReadUInt16();
                vMinor = reader.ReadUInt16();

                //Office Binary Document RC4 Encryption
                if (vMajor == 1)
                {
                    rc4Salt = reader.ReadBytes(16);
                    rc4EncryptedVerifier     = reader.ReadBytes(16);
                    rc4EncryptedVerifierHash = reader.ReadBytes(16);
                }
                //Office Binary Document RC4 CryptoAPI Encryption
                else if (vMajor == 2 || vMajor == 3 || vMajor == 4)
                {
                    encryptionHeaderFlags = reader.ReadBytes(4);
                    encryptionHeaderSize  = reader.ReadUInt32();
                    encryptionHeader      = new EncryptionHeader(reader);
                    encryptionVerifier    = new EncryptionVerifier(reader);
                }
                else
                {
                    throw new NotImplementedException(
                              "FilePass w/ wEncryptionType == 1 and vMajor == " + vMajor + " not supported");
                }
            }
            else
            {
                throw new NotImplementedException(
                          "FilePass w/ wEncryptionType == " + wEncryptionType + " not supported");
            }

            // assert that the correct number of bytes has been read from the stream
            Debug.Assert(this.Offset + this.Length == this.Reader.BaseStream.Position);
        }
Esempio n. 9
0
        /// <summary>
        /// Derives an key from the specified password.
        /// </summary>
        /// <param name="header">A file header.</param>
        /// <param name="password">The password.</param>
        /// <param name="keySize">The size of the key to derive (bits).</param>
        /// <returns>
        /// Key.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">header</exception>
        static byte[] DeriveKey(EncryptionHeader header, string password, int keySize)
        {
            if (header == null)
            {
                throw new ArgumentNullException("header");
            }

            return(DeriveKey(
                       header.Version,
                       password,
                       header.BCryptSalt,
                       header.PBKDF2Salt,
                       header.Workload,
                       keySize
                       ));
        }
Esempio n. 10
0
        public override string Serialize()
        {
            var encryption = EncryptionHeader.Serialize();
            var content    = Data.Serialize();
            var hnvsd      = $"HNVSD:999:1+@{content.Length}@{content}";
            var footer     = Footer.Serialize();

            var list = new[] { Header.Serialize(), encryption, hnvsd, footer };

            var length = list.Select(x => x.Length + 1).Sum();

            Header.Size.Value = length;
            list[0]           = Header.Serialize();

            return(string.Join("'", list) + "'");
        }
Esempio n. 11
0
        protected internal static Cipher InitCipherForBlock(Cipher cipher, int block,
                                                            IEncryptionInfoBuilder builder, ISecretKey skey, int encryptMode)
        {
            EncryptionVerifier ver      = builder.GetVerifier();
            HashAlgorithm      hashAlgo = ver.HashAlgorithm;

            byte[] blockKey = new byte[4];
            LittleEndian.PutUInt(blockKey, 0, block);
            byte[]     encKey = CryptoFunctions.GenerateKey(skey.GetEncoded(), hashAlgo, blockKey, 16);
            ISecretKey key    = new SecretKeySpec(encKey, skey.GetAlgorithm());

            if (cipher == null)
            {
                EncryptionHeader em = builder.GetHeader();
                cipher = CryptoFunctions.GetCipher(key, em.CipherAlgorithm, null, null, encryptMode);
            }
            else
            {
                cipher.Init(encryptMode, key);
            }
            return(cipher);
        }
Esempio n. 12
0
        public static RequestHeader BuildRequestHeader(EncryptionTypes encryptionType, CompressionTypes compressionType, RequestTypes requestType)
        {
            // first create headers
            EncryptionHeader encryptionHeader = new EncryptionHeader()
            {
                EncryptionType = encryptionType
            };

            MessageHeader messageHeader = new MessageHeader()
            {
                CompressionType  = compressionType,
                EncryptionHeader = encryptionHeader
            };

            RequestHeader requestHeader = new RequestHeader()
            {
                RequestType   = requestType,
                MessageHeader = messageHeader
            };

            // send response header first
            return(requestHeader);
        }
Esempio n. 13
0
            public static EncryptionHeader FromBytes(byte[] contents)
            {
                var eh = new EncryptionHeader();

                if (contents == null)
                {
                    throw new ArgumentNullException("contents");                     // dumbass.
                }

                if (contents.Length < GetHeaderLength())
                {
                    throw new Exception("Invalid header. Cannot decrypt");
                }

                var headerBytes = contents.Take(GetHeaderLength()).ToArray();

                int index = 0;

                for (var i = 0; i < 4; ++index, ++i)
                {
                    var part = headerBytes[i];
                    var size = (part << (i * 0x08));
                    eh.FileSize += size;
                }

                var corruptionTest = ASCIIEncoding.ASCII.GetString(headerBytes, 4, CORRUPTION_TEST_STRING.Length);

                if (corruptionTest != CORRUPTION_TEST_STRING)
                {
                    throw new Exception("Corrupted header, cannot decrypt");
                }

                eh.FileName = ASCIIEncoding.ASCII.GetString(headerBytes, 4 + CORRUPTION_TEST_STRING.Length, MAX_FILENAME_LENGTH).Replace("\0", string.Empty);

                return(eh);
            }
Esempio n. 14
0
        /// <summary>
        /// Decrypts the specified stream.
        /// </summary>
        /// <param name="inputStream">The input stream.</param>
        /// <param name="output">The method to call to handle the decrypted data.</param>
        /// <param name="password">The password.</param>
        /// <exception cref="System.ArgumentNullException">inputStream
        /// or
        /// outputStream</exception>
        /// <exception cref="StreamCryptoException">
        /// Integrity check failed.
        /// </exception>
        /// <exception cref="Common.Security.Cryptography.IO.StreamCryptoException">Integrity check failed.</exception>
        /// <remarks>
        /// <para>
        /// This method calls the <see cref="output"/> delegate with a stream of decrypted data.
        /// </para>
        /// <para>
        /// This method uses the following algorithms:
        /// AES-256 - encryption
        /// bcrypt  - key derivation
        /// PBKDF2 on HMACSHA1 - key derivation (deriving 256 bit key for AES from 192 bit bcrypt output)
        /// SHA-256 - integrity check
        /// </para>
        /// </remarks>
        public static void DecryptStream(Stream inputStream, Action <Stream> output, string password)
        {
            if (inputStream == null)
            {
                throw new ArgumentNullException("inputStream");
            }
            if (output == null)
            {
                throw new ArgumentNullException("output");
            }

            var header = EncryptionHeader.ReadFrom(inputStream);
            var key    = DeriveKey(header, password, AesKeySize);

            using (var aes = CreateAes(key))
            {
                using (var hash = SHA256.Create())
                {
                    using (var cryptor = aes.CreateDecryptor())
                    {
                        // Do NOT dispose to avoid closing the input stream
                        // This stream stops reading when the footer is reached
                        var decryptionStream = new DecryptionStream(inputStream);
                        // Do NOT dispose to avoid closing the input stream
                        var cryptoStream = new CryptoStream(decryptionStream, cryptor, CryptoStreamMode.Read);
                        // Do NOT dispose to avoid closing the input stream
                        var hashStream = new CryptoStream(cryptoStream, hash, CryptoStreamMode.Read);

                        try
                        {
                            output(hashStream);

                            // "FlushFinalBlock" can be called only on the outermost stream. It is automatically called on the inner stream
                            // if it is a "CryptoStream". Calling it explicitly on an inner stream causes an exception.
                            if (false == cryptoStream.HasFlushedFinalBlock)
                            {
                                cryptoStream.FlushFinalBlock();
                            }
                            if (false == hashStream.HasFlushedFinalBlock)
                            {
                                hashStream.FlushFinalBlock();
                            }
                        }
                        catch (Exception exc)
                        {
                            throw new StreamCryptoException(StreamCryptoError.DecryptionError, exc.Message, exc);
                        }

                        var hashBytes = hash.Hash;

                        // Read the hash stored after the footer's magic bytes
                        var reader          = new BinaryReader(inputStream);
                        var streamHashBytes = reader.ReadBytes(hashBytes.Length);

                        if (false == EqualArrays(streamHashBytes, hashBytes))
                        {
                            throw new StreamCryptoException(StreamCryptoError.IntegrityCheckFailed, "Integrity check failed.");
                        }
                    }
                }
            }
        }
Esempio n. 15
0
        private Pixel[,] muxxImageAndFile(FileModel fileModel, IImageWrapper container)
        {
            // warning, this is very verbose code.
            // i could have written this in linq much more elegantly,
            // however i wrote this so that others can pick it up without needing to know c# / linq / lambdas

            if (!this.encryptionFeasible(fileModel, container))
            {
                throw new Exception("image is too small to hide this file in");
            }

            int byteSpread    = this.getByteSpread();
            int bitShiftCount = (BITS_PER_CHANNEL - BITS_USED_PER_CHANNEL);
            int maxValue      = (0x01 << BITS_PER_CHANNEL) - 0x01;
            int partMask      = maxValue >> bitShiftCount;
            int visibleMask   = (byte)(maxValue << (0x08 - bitShiftCount));

            var header = new EncryptionHeader();

            header.FileName = fileModel.FileName;
            header.FileSize = (int)fileModel.FileContents.Length;

            var headerBytesUnspread = header.ToBytes();
            var fileBytesUnspread   = new byte[fileModel.FileContents.Length];

            fileModel.FileContents.Read(fileBytesUnspread, 0, (int)fileModel.FileContents.Length);

            var unspreadBytes = new byte[headerBytesUnspread.Length + fileBytesUnspread.Length];
            var spreadBytes   = new byte[unspreadBytes.Length * byteSpread];

            int unspreadIndex = 0;

            for (var i = 0; i < headerBytesUnspread.Length; ++i)
            {
                unspreadBytes [unspreadIndex] = headerBytesUnspread [i];
                ++unspreadIndex;
            }

            for (var i = 0; i < fileBytesUnspread.Length; ++i)
            {
                unspreadBytes [unspreadIndex] = fileBytesUnspread [i];
                ++unspreadIndex;
            }

            int spreadIndex = 0;

            for (var i = 0; i < unspreadBytes.Length; ++i)
            {
                var toSpread = unspreadBytes [i];

                for (var s = 0; s < byteSpread; ++s)                 // going least significant bit to most
                {
                    var spreadShift = s * BITS_USED_PER_CHANNEL;
                    var shifted     = toSpread >> spreadShift;
                    var masked      = shifted & partMask;

                    spreadBytes [spreadIndex] = (byte)masked;
                    ++spreadIndex;
                }
            }

            // sanity check
            var maxSpreadValue = (0x01 << (BITS_USED_PER_CHANNEL)) - 1;

            for (var i = 0; i < spreadBytes.Length; ++i)
            {
                var sb = spreadBytes [i];
                if (sb > maxSpreadValue)
                {
                    throw new Exception("the author is a moron");
                }
            }

            Pixel[,] dataSet = new Pixel[container.Width, container.Height];

            var numberOfChannels = Enum.GetValues(typeof(LosslessFileMuxxer.ByteOrder)).GetLength(0);
            var channelIndex     = 0;

            spreadIndex = 0;
            var rand = new Random(Guid.NewGuid().GetHashCode());
            var randomiseNonDatasetBytes = false;

            for (var x = 0; x < container.Width; ++x)
            {
                for (var y = 0; y < container.Height; ++y)
                {
                    Pixel p = new Pixel();
                    p.R = container.GetRedAtPosition(x, y);
                    p.G = container.GetGreenAtPosition(x, y);
                    p.B = container.GetBlueAtPosition(x, y);

                    if (spreadIndex < spreadBytes.Length)
                    {
                        for (var c = 0; c < numberOfChannels; ++c)
                        {
                            if (spreadIndex < spreadBytes.Length)
                            {
                                var byteToHide   = spreadBytes [spreadIndex];
                                var whichChannel = (ByteOrder)channelIndex;
                                switch (whichChannel)
                                {
                                case ByteOrder.Red:
                                    p.R = (byte)(((int)p.R & visibleMask) + byteToHide);
                                    break;

                                case ByteOrder.Green:
                                    p.G = (byte)(((int)p.G & visibleMask) + byteToHide);
                                    break;

                                case ByteOrder.Blue:
                                    p.B = (byte)(((int)p.B & visibleMask) + byteToHide);
                                    break;
                                }

                                channelIndex = channelIndex == numberOfChannels - 1 ? 0 : channelIndex + 1;
                                ++spreadIndex;
                            }
                            else
                            {
                                if (randomiseNonDatasetBytes)
                                {
                                    // not a data pixel, give it a random value
                                    var newVal = rand.Next(0, maxSpreadValue);
                                    p.R    = (byte)(((int)p.R & visibleMask) + newVal);
                                    newVal = rand.Next(0, maxSpreadValue);
                                    p.G    = (byte)(((int)p.G & visibleMask) + newVal);
                                    newVal = rand.Next(0, maxSpreadValue);
                                    p.B    = (byte)(((int)p.B & visibleMask) + newVal);
                                }
                            }
                        }
                    }
                    else
                    {
                        if (randomiseNonDatasetBytes)
                        {
                            // not a data pixel, give it a random value
                            var newVal = rand.Next(0, maxSpreadValue);
                            p.R    = (byte)(((int)p.R & visibleMask) + newVal);
                            newVal = rand.Next(0, maxSpreadValue);
                            p.G    = (byte)(((int)p.G & visibleMask) + newVal);
                            newVal = rand.Next(0, maxSpreadValue);
                            p.B    = (byte)(((int)p.B & visibleMask) + newVal);
                        }
                    }

                    dataSet [x, y] = p;
                }
            }

            return(dataSet);
        }
Esempio n. 16
0
        private FileModel demuxxImage(Pixel[,] source)
        {
            FileModel fileModel = null;

            var numberOfChannels = Enum.GetValues(typeof(LosslessFileMuxxer.ByteOrder)).GetLength(0);
            var sourceWidth      = source.GetLength(0);
            var sourceHeight     = source.GetLength(1);
            int byteSpread       = this.getByteSpread();
            int bitShiftCount    = (BITS_PER_CHANNEL - BITS_USED_PER_CHANNEL);
            int maxValue         = (0x01 << BITS_PER_CHANNEL) - 0x01;
            int partMask         = maxValue >> bitShiftCount;

            var spreadBytes = new byte[sourceWidth * sourceHeight * byteSpread];

            var spreadIndex  = 0;
            var channelIndex = 0;

            for (var x = 0; x < source.GetLength(0); ++x)
            {
                for (var y = 0; y < source.GetLength(1); ++y)
                {
                    Pixel p = source [x, y];
                    for (var c = 0; c < numberOfChannels; ++c)
                    {
                        var  channel = (ByteOrder)channelIndex;
                        byte valueToUse;

                        switch (channel)
                        {
                        case ByteOrder.Red:
                            valueToUse = (byte)(p.R & partMask);
                            break;

                        case ByteOrder.Green:
                            valueToUse = (byte)(p.G & partMask);
                            break;

                        case ByteOrder.Blue:
                            valueToUse = (byte)(p.B & partMask);
                            break;

                        default:
                            throw new NotImplementedException();
                        }

                        spreadBytes [spreadIndex] = valueToUse;
                        ++spreadIndex;
                        channelIndex = channelIndex == numberOfChannels - 1 ? 0 : channelIndex + 1;
                    }
                }
            }

            var unspreadBytes = new byte[sourceWidth * sourceHeight];             // don't yet know how many of these are useful yet
            var unspreadIndex = 0;

            spreadIndex = 0;

            do
            {
                byte b = 0x00;

                for (var i = 0; i < byteSpread; ++i)
                {
                    var s = spreadBytes[spreadIndex];

                    var spreadShift = i * BITS_USED_PER_CHANNEL;
                    var shifted     = s << spreadShift;

                    b += (byte)shifted;

                    ++spreadIndex;
                }

                unspreadBytes[unspreadIndex] = b;
                ++unspreadIndex;
            }while(spreadIndex < spreadBytes.Length);

            var headerBytes = new byte[EncryptionHeader.GetHeaderLength()];

            for (var i = 0; i < headerBytes.Length; ++i)
            {
                var h = unspreadBytes[i];
                headerBytes [i] = h;
            }

            var header = new EncryptionHeader(headerBytes);

            var fileBytes = unspreadBytes.Skip(headerBytes.Length).Take(header.FileSize).ToArray();

            var ms = new MemoryStream(fileBytes);

            ms.Position = 0;

            fileModel = new FileModel(ms, header.FileName);

            return(fileModel);
        }