Beispiel #1
0
 private void ReadHeaderV1(BinaryReader br)
 {
     header        = new HeaderV1();
     header.magic  = new string(br.ReadChars(4));
     header.type   = br.ReadUInt32();
     header.width  = br.ReadUInt32();
     header.height = br.ReadUInt32();
     header.unk1   = br.ReadUInt32();
     header.unk2   = br.ReadUInt32();
     header.mips   = br.ReadUInt32();
     header.format = br.ReadUInt32();
 }
        protected internal Header GenerateHeader(
            ISymmetricEncryptionProviderOptions options,
            ReadOnlySpan <byte> symmetricKey = default,
            ReadOnlySpan <byte> privateKey   = default,
            ReadOnlySpan <byte> metadata     = default,
            IEncryptionProvider symmetricKeyEncryptionProvider = null)
        {
            Check.NotNull(nameof(options), options);
            privateKey = !privateKey.IsEmpty ? privateKey : options.Key.Memory.Span;

            ReadOnlySpan <byte> signingKey = default;

            if (options.SigningKey != null)
            {
                signingKey = options.SigningKey.Memory.Span;
            }

            // header values
            // 1. version
            // 2. metadataSize
            // 3. iterations
            // 4. symmetricSaltSize
            // 5. signingSaltSize
            // 6. ivSize
            // 7. symmetricKeySize
            // 8. hashSize

            // header values
            // 1. metadata (optional)
            // 2. symmetricSalt (optional)
            // 3. signingSalt (optional)
            // 4. iv
            // 5. symmetricKey (optional)
            // 6. hash
            var header = new HeaderV1();

            header.MetaDataSize = metadata.Length;

            bool privateKeyEmpty   = privateKey == null || privateKey.IsEmpty;
            bool symmetricKeyEmpty = symmetricKey == null || symmetricKey.IsEmpty;

            if (privateKeyEmpty && symmetricKeyEmpty)
            {
                throw new ArgumentNullException(nameof(privateKey), "privateKey or symmetricKey must have a value");
            }

            if (!options.SkipSigning && privateKeyEmpty && signingKey.IsEmpty)
            {
                throw new ArgumentNullException(nameof(privateKey),
                                                "privateKey must have a value or options.SigningKey must have a value or options.SkipSigning must be true");
            }

            if (!privateKeyEmpty)
            {
                header.SymmetricSaltSize = (short)(options.SaltSize / 8);

                if (!options.SkipSigning && (signingKey == null || signingKey.IsEmpty))
                {
                    header.SigningSaltSize = (short)(options.SaltSize / 8);
                    this.signingAlgorithm  = this.signingAlgorithm ?? CreateSigningAlgorithm(options);
                }
            }

            if (!symmetricKeyEmpty)
            {
                header.SymmetricKeySize = (short)(options.KeySize / 8);
            }

            this.algorithm = this.algorithm ?? CreateSymmetricAlgorithm(options);
            this.algorithm.GenerateIV();
            var iv = this.algorithm.IV;

            header.IvSize = (short)iv.Length;
            {
                var buffer = MemoryPool <byte> .Shared.Rent(iv.Length);

                iv.CopyTo(buffer.Memory.Span);
                header.IV = buffer;
            }

            header.HashSize   = (short)(this.signingAlgorithm.HashSize / 8);
            header.Iterations = options.Iterations;
            using (var ms = new MemoryStream(new byte[header.HeaderSize]))
                using (var bw = new BinaryWriter(ms, Utf8.NoBom, false))
                {
                    if (!symmetricKey.IsEmpty && symmetricKeyEncryptionProvider != null)
                    {
                        symmetricKey            = symmetricKeyEncryptionProvider.Encrypt(symmetricKey);
                        header.SymmetricKeySize = (short)symmetricKey.Length;
                    }

                    header.SymmetricAlgorithmType = options.SymmetricAlgorithm;
                    header.KeyedHashAlgorithmType = options.KeyedHashedAlgorithm;

                    bw.Write(header.Version);
                    bw.Write((short)header.SymmetricAlgorithmType);
                    bw.Write((short)header.KeyedHashAlgorithmType);
                    bw.Write(header.MetaDataSize);
                    bw.Write(header.Iterations);
                    bw.Write(header.SymmetricSaltSize);
                    bw.Write(header.SigningSaltSize);
                    bw.Write(header.IvSize);
                    bw.Write(header.SymmetricKeySize);
                    bw.Write(header.HashSize);

                    if (privateKey != null)
                    {
                        ReadOnlySpan <byte> symmetricSalt = GenerateSalt(header.SymmetricSaltSize);
                        if (symmetricSalt.Length != header.SymmetricSaltSize)
                        {
                            throw new Exception("bad length");
                        }

                        using (var generator = new Rfc2898DeriveBytes(privateKey, symmetricSalt, options.Iterations, HashAlgorithmName.SHA256))
                        {
                            //symmetricSalt = generator.Salt;
                            ReadOnlySpan <byte> bytes = generator.GetBytes(options.KeySize / 8);
                            var buffer = MemoryPool <byte> .Shared.Rent(bytes.Length);

                            bytes.CopyTo(buffer.Memory.Span);
                            header.SymmetricKey = buffer;

                            bw.Write(symmetricSalt);
                        }

                        if (!options.SkipSigning || !signingKey.IsEmpty)
                        {
                            var signingSalt = GenerateSalt(header.SigningSaltSize);

                            using (var generator = new Rfc2898DeriveBytes(
                                       privateKey, signingSalt, options.Iterations, HashAlgorithmName.SHA256))
                            {
                                signingKey = generator.GetBytes(options.KeySize / 8);
                                var buffer = MemoryPool <byte> .Shared.Rent(signingKey.Length);

                                signingKey.CopyTo(buffer.Memory.Span);
                                header.SigningKey = buffer;
                                bw.Write(signingSalt);
                            }

                            signingSalt.Clear();
                        }
                    }

                    bw.Write(iv);
                    if (!symmetricKeyEmpty)
                    {
                        bw.Write(symmetricKey);
                    }

                    bw.Flush();
                    ms.Flush();
                    header.Position = ms.Position;

                    ReadOnlySpan <byte> data = ms.ToArray();
                    header.Bytes = MemoryPool <byte> .Shared.Rent(header.HeaderSize);

                    data.CopyTo(header.Bytes.Memory.Span);
                }

            return(header);
        }
        protected internal Header ReadHeader(
            Stream reader,
            ISymmetricEncryptionProviderOptions options,
            ReadOnlySpan <byte> privateKey = default,
            IEncryptionProvider symmetricKeyEncryptionProvider = null)
        {
            Check.NotNull(nameof(reader), reader);
            Check.NotNull(nameof(options), options);

            ReadOnlySpan <byte> signingKey = default;

            if (options.SigningKey != null)
            {
                signingKey = options.SigningKey.Memory.Span;
            }

            using (var ms = new MemoryStream())
                using (var bw = new BinaryWriter(ms, Utf8.NoBom, true))
                    using (var br = new BinaryReader(reader, Utf8.NoBom, true))
                    {
                        var version = br.ReadInt16();
                        bw.Write(version);
                        Header header = null;
                        switch (version)
                        {
                        case 1:
                        default:
                            header = new HeaderV1();
                            break;
                        }

                        // header shorts/ints
                        // 1. version
                        // 2. algo
                        // 3. signing,
                        // 4. metadataSize
                        // 5  iterations
                        // 6. symmetricSaltSize
                        // 7. signingSaltSize
                        // 8. ivSize
                        // 9. symmetricKeySize
                        // 10. hashSize

                        // header values
                        // 1. metadata
                        // 2. symmetricSalt
                        // 3. signingSalt
                        // 4. iv
                        // 5. symmetricKey
                        // 6. hash
                        header.SymmetricAlgorithmType = (SymmetricAlgorithmType)br.ReadInt16();
                        header.KeyedHashAlgorithmType = (KeyedHashAlgorithmType)br.ReadInt16();
                        header.MetaDataSize           = br.ReadInt32();
                        header.Iterations             = br.ReadInt32();
                        header.SymmetricSaltSize      = br.ReadInt16();
                        header.SigningSaltSize        = br.ReadInt16();
                        header.IvSize           = br.ReadInt16();
                        header.SymmetricKeySize = br.ReadInt16();
                        header.HashSize         = br.ReadInt16();

                        bw.Write((short)header.SymmetricAlgorithmType);
                        bw.Write((short)header.KeyedHashAlgorithmType);
                        bw.Write(header.MetaDataSize);
                        bw.Write(header.Iterations);
                        bw.Write(header.SymmetricSaltSize);
                        bw.Write(header.SigningSaltSize);
                        bw.Write(header.IvSize);
                        bw.Write(header.SymmetricKeySize);
                        bw.Write(header.HashSize);

                        if (options.SymmetricAlgorithm != header.SymmetricAlgorithmType)
                        {
                            options.SymmetricAlgorithm = header.SymmetricAlgorithmType;
                            this.algorithm             = null;
                        }

                        if (options.KeyedHashedAlgorithm != header.KeyedHashAlgorithmType)
                        {
                            options.KeyedHashedAlgorithm = header.KeyedHashAlgorithmType;
                            this.signingAlgorithm        = null;
                        }

                        byte[] metadata                 = null;
                        byte[] symmetricSalt            = null;
                        ReadOnlySpan <byte> signingSalt = default;
                        byte[] iv = null;
                        ReadOnlySpan <byte> symmetricKey = default;
                        byte[] hash = null;

                        if (header.MetaDataSize > 0)
                        {
                            metadata = br.ReadBytes(header.MetaDataSize);
                            bw.Write(metadata);
                        }

                        if (header.SymmetricSaltSize > 0)
                        {
                            symmetricSalt = br.ReadBytes(header.SymmetricSaltSize);
                            bw.Write(symmetricSalt);
                        }

                        if (header.SigningSaltSize > 0)
                        {
                            signingSalt = br.ReadBytes(header.SigningSaltSize);
                            bw.Write(signingSalt);
                        }

                        if (header.IvSize > 0)
                        {
                            iv = br.ReadBytes(header.IvSize);
                            bw.Write(iv);
                        }

                        if (header.SymmetricKeySize > 0)
                        {
                            symmetricKey = br.ReadBytes(header.SymmetricKeySize);
                            bw.Write(symmetricKey);
                        }

                        if (header.HashSize > 0)
                        {
                            hash = br.ReadBytes(header.HashSize);
                            bw.Write(hash);
                        }

                        bw.Flush();
                        ms.Flush();
                        {
                            var bytes  = ms.ToArray();
                            var buffer = MemoryPool <byte> .Shared.Rent(bytes.Length);

                            bytes.CopyTo(buffer.Memory.Span);
                            header.Bytes = buffer;
                        }

                        header.Position = reader.Position;

                        if (symmetricKeyEncryptionProvider != null)
                        {
                            symmetricKey = symmetricKeyEncryptionProvider.Decrypt(symmetricKey);
                        }

                        if (symmetricKey == null && privateKey.IsEmpty)
                        {
                            throw new ArgumentNullException(nameof(privateKey),
                                                            "privateKey or symmetricKey must have a value");
                        }

                        if (!options.SkipSigning && privateKey == null && signingKey.IsEmpty)
                        {
                            throw new ArgumentNullException(nameof(privateKey),
                                                            "privateKey must have a value or options.SigningKey must have a value or options.SkipSigning must be true");
                        }

                        if (symmetricKey == null)
                        {
                            if (symmetricSalt == null)
                            {
                                throw new InvalidOperationException("symmetricSalt for the privateKey could not be retrieved");
                            }

                            using (var generator = new Rfc2898DeriveBytes(privateKey, symmetricSalt, header.Iterations, HashAlgorithmName.SHA256))
                            {
                                var buffer = MemoryPool <byte> .Shared.Rent(options.KeySize / 8);

                                ReadOnlySpan <byte> bytes = generator.GetBytes(options.KeySize / 8);
                                bytes.CopyTo(buffer.Memory.Span);
                                header.SymmetricKey = buffer;
                            }
                        }

                        if (!options.SkipSigning && (signingKey == null || signingKey.IsEmpty))
                        {
                            if (signingSalt == null)
                            {
                                throw new InvalidOperationException("symmetricSalt for the privateKey could not be retrieved");
                            }

                            var key = !symmetricKey.IsEmpty ? symmetricKey : privateKey;
                            using (var generator = new Rfc2898DeriveBytes(key, signingSalt, header.Iterations, HashAlgorithmName.SHA256))
                            {
                                generator.IterationCount = header.Iterations;
                                var buffer = MemoryPool <byte> .Shared.Rent(options.KeySize / 8);

                                ReadOnlySpan <byte> bytes = generator.GetBytes(options.KeySize / 8);
                                bytes.CopyTo(buffer.Memory.Span);
                                header.SigningKey = buffer;
                            }
                        }

                        {
                            IMemoryOwner <byte> buffer = null;

                            if (header.SymmetricKeySize > 0)
                            {
                                buffer = MemoryPool <byte> .Shared.Rent(header.SymmetricKeySize);

                                symmetricKey.CopyTo(buffer.Memory.Span);
                                header.SymmetricKey = buffer;
                            }

                            buffer = MemoryPool <byte> .Shared.Rent(iv.Length);

                            iv.CopyTo(buffer.Memory.Span);
                            header.IV = buffer;

                            buffer = MemoryPool <byte> .Shared.Rent(header.HashSize);

                            hash.CopyTo(buffer.Memory.Span);
                            header.Hash = buffer;
                        }

                        return(header);
                    }
        }
Beispiel #4
0
        public void ReadHeaderV1()
        {
            log.Debug("Reading ABF Header (v1)");
            headerV1 = new HeaderV1();
            headerV1.fFileSignature         = FileReadString(0, 4);         //4s;
            headerV1.fFileVersionNumber     = FileReadFloat(4, 1);          //f;
            headerV1.nOperationMode         = FileReadShort(8, 1);          //h;
            headerV1.lActualAcqLength       = FileReadInt(10, 1);           //i;
            headerV1.nNumPointsIgnored      = FileReadShort(14, 1);         //h;
            headerV1.lActualEpisodes        = FileReadInt(16, 1);           //i;
            headerV1.lFileStartTime         = FileReadInt(24, 1);           //i;
            headerV1.lDataSectionPtr        = FileReadInt(40, 1);           //i;
            headerV1.lTagSectionPtr         = FileReadInt(44, 1);           //i;
            headerV1.lNumTagEntries         = FileReadInt(48, 1);           //i;
            headerV1.lSynchArrayPtr         = FileReadInt(92, 1);           //i;
            headerV1.lSynchArraySize        = FileReadInt(96, 1);           //i;
            headerV1.nDataFormat            = FileReadShort(100, 1);        //h;
            headerV1.nADCNumChannels        = FileReadShort(120, 1);        //h;
            headerV1.fADCSampleInterval     = FileReadFloat(122, 1);        //f;
            headerV1.fSynchTimeUnit         = FileReadFloat(130, 1);        //f;
            headerV1.lNumSamplesPerEpisode  = FileReadInt(138, 1);          //i;
            headerV1.lPreTriggerSamples     = FileReadInt(142, 1);          //i;
            headerV1.lEpisodesPerRun        = FileReadInt(146, 1);          //i;
            headerV1.fADCRange              = FileReadFloat(244, 1);        //f;
            headerV1.lADCResolution         = FileReadInt(252, 1);          //i;
            headerV1.nFileStartMillisecs    = FileReadShort(366, 1);        //h;
            headerV1.nADCPtoLChannelMap     = FileReadShorts(378, 16);      //16h;
            headerV1.nADCSamplingSeq        = FileReadShorts(410, 16);      //16h;
            headerV1.sADCChannelName        = FileReadStrings(442, 10, 16); //10s;
            headerV1.sADCUnits              = FileReadStrings(602, 8, 16);  //8s;
            headerV1.fADCProgrammableGain   = FileReadFloats(730, 16);      //16f;
            headerV1.fInstrumentScaleFactor = FileReadFloats(922, 16);      //16f;
            headerV1.fInstrumentOffset      = FileReadFloats(986, 16);      //16f;
            headerV1.fSignalGain            = FileReadFloats(1050, 16);     //16f;
            headerV1.fSignalOffset          = FileReadFloats(1114, 16);     //16f;
            headerV1.nDigitalEnable         = FileReadShort(1436, 1);       //h;
            headerV1.nActiveDACChannel      = FileReadShort(1440, 1);       //h;
            headerV1.nDigitalHolding        = FileReadShort(1584, 1);       //h;
            headerV1.nDigitalInterEpisode   = FileReadShort(1586, 1);       //h;
            headerV1.nDigitalValue          = FileReadShorts(2588, 10);     //10h;
            headerV1.lDACFilePtr            = FileReadInts(2048, 2);        //2i;
            headerV1.lDACFileNumEpisodes    = FileReadInts(2056, 2);        //2i;
            headerV1.fDACCalibrationFactor  = FileReadFloats(2074, 4);      //4f;
            headerV1.fDACCalibrationOffset  = FileReadFloats(2090, 4);      //4f;
            headerV1.nWaveformEnable        = FileReadShorts(2296, 2);      //2h;
            headerV1.nWaveformSource        = FileReadShorts(2300, 2);      //2h;
            headerV1.nInterEpisodeLevel     = FileReadShorts(2304, 2);      //2h;
            headerV1.nEpochType             = FileReadShorts(2308, 20);     //20h;
            headerV1.fEpochInitLevel        = FileReadFloats(2348, 20);     //20f;
            headerV1.fEpochLevelInc         = FileReadFloats(2428, 20);     //20f;
            headerV1.lEpochInitDuration     = FileReadInts(2508, 20);       //20i;
            headerV1.lEpochDurationInc      = FileReadInts(2588, 20);       //20i;
            headerV1.nTelegraphEnable       = FileReadShorts(4512, 16);     //16h;
            headerV1.fTelegraphAdditGain    = FileReadFloats(4576, 16);     //16f;
            headerV1.sProtocolPath          = FileReadString(4898, 384);    //384s;

            // clean up adc and dac units
            for (int i = 0; i < headerV1.sADCUnits.Length; i++)
            {
                headerV1.sADCUnits[i] = headerV1.sADCUnits[i].Trim();
            }
            for (int i = 0; i < headerV1.sADCChannelName.Length; i++)
            {
                headerV1.sADCChannelName[i] = headerV1.sADCChannelName[i].Trim();
            }
        }