예제 #1
0
 internal static void CheckDestinationLength(this ISignAlgorithm a, int len)
 {
     if (len < a.SignatureByteLength)
     {
         Throw.ArgumentException($"Signature algorithm '{a.AlgorithmId}' requires {a.SignatureByteLength} destination bytes. Provided buffer has only {len} bytes.", "destination");
     }
 }
예제 #2
0
 internal Sender(LocalParty local, TrustedParty audience, ISignAlgorithm a, KeyBase?k, DateTime expires)
 {
     Debug.Assert((a.AlgorithmId == SignatureAlgorithmId.None) == (k == null));
     _algo          = a;
     _key           = k;
     _local         = local;
     Audience       = audience;
     DataExpiration = expires;
 }
예제 #3
0
        /// <summary>
        /// Writes DataPack into stream using signing if needed
        /// </summary>
        /// <param name="dataPack">DataPack object to write</param>
        /// <param name="stream">Stream, where DataPack will be serialized</param>
        /// <param name="signAlgorithm">Signing algorithm to use if needed</param>
        public static void Serialize(DataPack dataPack, Stream stream, ISignAlgorithm signAlgorithm = null)
        {
            if (dataPack == null)
            {
                throw new ArgumentNullException("dataPack");
            }
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }

            DataPackWriter.Write(dataPack, stream, signAlgorithm);
        }
예제 #4
0
        /// <summary>
        /// Checks if given <see cref="DataPack"/> stream sign is correc
        /// </summary>
        /// <param name="prefixSize">Size of prefix</param>
        /// <param name="signAlgorithm">Sign algorithm</param>
        /// <param name="stream">Stream of <see cref="DataPack"/></param>
        /// <returns></returns>
        public static bool IsSignMatch(uint prefixSize, ISignAlgorithm signAlgorithm, Stream stream)
        {
            if (signAlgorithm == null)
            {
                throw new ArgumentNullException("signAlgorithm");
            }
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }

            if (!stream.CanSeek)
            {
                throw new InvalidOperationException("Stream doesn't support seeking.");
            }
            if (!stream.CanRead)
            {
                throw new InvalidOperationException("Stream doesn't support reading.");
            }

            long position = stream.Position;

            stream.Seek(prefixSize + 1, SeekOrigin.Current);
            int isSignedByte = stream.ReadByte();

            if (isSignedByte == 0)
            {
                throw new InvalidOperationException("Stream is not signed.");
            }

            using (var wrapper = new NonClosingStreamWrapper(stream)) // To prevent stream from closing by BinaryReader
                using (var br = new BinaryReader(wrapper))
                {
                    uint protectedDataSize = br.ReadUInt32(); // Protected data size
                    uint signSize          = br.ReadUInt32(); // Sign size

                    using (var signStream = new FilteredStream(wrapper, wrapper.Position + protectedDataSize, signSize))
                    {
                        using (var dataStream = new FilteredStream(wrapper, wrapper.Position, protectedDataSize - 8))
                        {
                            var result = signAlgorithm.VerifySign(dataStream, signStream);

                            wrapper.Position = position;

                            return(result);
                        }
                    }
                }
        }
예제 #5
0
        public async ValueTask <ISender> CreateSenderAsync(IActivityMonitor monitor,
                                                           TrustedParty audience,
                                                           ISignAlgorithm algorithm,
                                                           TimeSpan validity,
                                                           bool encrypt     = false,
                                                           uint maxUseCount = 0)
        {
            Throw.CheckNotNullArgument(monitor);
            Throw.CheckNotNullArgument(audience);
            Throw.CheckNotNullArgument(algorithm);
            Throw.CheckArgument(validity >= Configuration.MinSignatureLifetime && validity <= Configuration.MaxSignatureLifetime);
            var bestBefore = _appClock.Clock.UtcNow + validity;
            var key        = algorithm.KeyRequirement != null
                        ? await ResolveOutgoingKeyAsync(monitor, audience, algorithm.KeyRequirement, bestBefore, maxUseCount)
                        : null;

            return(new Sender(this, audience, algorithm, key, bestBefore));
        }
        /// <summary>
        /// Initializes a new <see cref="TrustedPartyConfiguration"/>.
        /// </summary>
        /// <param name="outgoingSignatureAlgorithmId">See <see cref="OutgoingSignatureAlgorithm"/>.</param>
        /// <param name="allowedIncomingSignatureAlgorithms">See <see cref="AllowedIncomingSignatureAlgorithms"/>.</param>
        /// <param name="minSignatureLifetime">See <see cref="MinSignatureLifetime"/>.</param>
        /// <param name="maxSignatureLifetime"><see cref="MaxSignatureLifetime"/>.</param>
        /// <param name="alwaysRequireIncomingExpirationTime">See <see cref="AlwaysRequireIncomingExpirationTime"/>.</param>
        /// <param name="rsaKeySizeForSignature">See <see cref="RSAKeyBitLengthForSignature"/>.</param>
        public TrustedPartyConfiguration(SignatureAlgorithmId outgoingSignatureAlgorithmId,
                                         IEnumerable <SignatureAlgorithmId>?allowedIncomingSignatureAlgorithms,
                                         TimeSpan minSignatureLifetime,
                                         TimeSpan maxSignatureLifetime,
                                         bool alwaysRequireIncomingExpirationTime,
                                         int rsaKeySizeForSignature = 2048)
        {
            Throw.CheckArgument(Enum.IsDefined(typeof(SignatureAlgorithmId), outgoingSignatureAlgorithmId));
            Throw.CheckArgument(rsaKeySizeForSignature is 2048 or 3072 or 7680 or 15360);
            Throw.CheckArgument(minSignatureLifetime >= TimeSpan.FromSeconds(1));
            Throw.CheckArgument(maxSignatureLifetime <= TimeSpan.FromDays(1095));
            Throw.CheckArgument(minSignatureLifetime <= maxSignatureLifetime);

            _rsaKaySize           = rsaKeySizeForSignature;
            _minSignatureLifetime = minSignatureLifetime;
            _maxSignatureLifetime = maxSignatureLifetime;
            _alwaysRequireIncomingExpirationTime = alwaysRequireIncomingExpirationTime;
            _algCache        = new ISignAlgorithm[14];
            _outgoingSignAlg = CreateAndCacheSignAlgorithm(outgoingSignatureAlgorithmId);
            if (allowedIncomingSignatureAlgorithms != null)
            {
                foreach (var s in allowedIncomingSignatureAlgorithms)
                {
                    _allowedIncomingSignAlgorithms |= 1 << (int)s;
                    CreateAndCacheSignAlgorithm(s);
                }
            }
            else
            {
                _allowedIncomingSignAlgorithms = 1 << (int)outgoingSignatureAlgorithmId;
            }

            ISignAlgorithm CreateAndCacheSignAlgorithm(SignatureAlgorithmId id)
            {
                var a = _algCache[(int)id];

                if (a == null)
                {
                    a = id.GetAlgorithm(_rsaKaySize);
                    _algCache[(int)id] = a;
                }
                return(a);
            }
        }
        /// <summary>
        /// Writes <see cref="DataPack"/> to stream
        /// </summary>
        /// <param name="dataPack">Data</param>
        /// <param name="stream">Stream where <see cref="DataPack"/> is written to</param>
        /// <param name="signAlgorithm">Sign algorithm if needed</param>
        public void Write(DataPack dataPack, Stream stream, ISignAlgorithm signAlgorithm = null)
        {
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }
            if (dataPack == null)
            {
                throw new ArgumentNullException("dataPack");
            }

            if (!stream.CanSeek)
            {
                throw new InvalidOperationException("Stream doesn't support seeking.");
            }
            if (!stream.CanWrite)
            {
                throw new InvalidOperationException("Stream doesn't support writing.");
            }

            using (var wrapper = new NonClosingStreamWrapper(stream)) // To prevent source stream from closing by BinaryWriter
                using (var bw = new BinaryWriter(wrapper))
                {
                    // Size of prefix
                    bw.Write(dataPack.PrefixSize);

                    // Prefix of data
                    bw.Write(dataPack.GetPrefix(), 0, dataPack.PrefixSize);

                    uint signInfoAddress = 0;
                    uint dataSizeAddress = 0;
                    if (signAlgorithm == null)
                    {
                        // Stream not signed
                        bw.Write((byte)0);
                    }
                    else
                    {
                        // Stream is signed
                        bw.Write((byte)1);
                        signInfoAddress = GetAddress(bw);
                        bw.Write(0); // Protected data size
                        bw.Write(0); // Sign size
                        dataSizeAddress = GetAddress(bw) - 8;
                    }

                    // Create implicit properties
                    var implicitProperties = new Properties();
                    if (dataPack.DateCreate != null)
                    {
                        implicitProperties["DateCreate"] = dataPack.DateCreate.Value.ToString(Consts.DateTimeFormat, CultureInfo.InvariantCulture);
                    }
                    if (dataPack.FileId != null)
                    {
                        implicitProperties["FileId"] = dataPack.FileId != null
                        ? dataPack.FileId.Value.ToString()
                        : null;
                    }
                    if (dataPack.Description != null)
                    {
                        implicitProperties["Description"] = dataPack.Description;
                    }

                    // Info section implicit properties
                    var properties = implicitProperties.GetPropertiesList();
                    bw.Write(InfoSection);
                    uint address = GetAddress(bw);
                    bw.Write(0u);
                    ushort cnt = (ushort)properties.Count;
                    bw.Write(cnt);

                    for (ushort i = 0; i < cnt; i++)
                    {
                        Serializer.SerializeWithLengthPrefix(wrapper, properties[i], PrefixStyle.Base128);
                    }

                    WriteSize(bw, address, address + 4);

                    // Info section with data headers info
                    bw.Write(InfoSection);
                    address = GetAddress(bw);
                    bw.Write(0u);
                    cnt = (ushort)dataPack.Headers.Count;
                    bw.Write(cnt);

                    for (ushort i = 0; i < cnt; i++)
                    {
                        Serializer.SerializeWithLengthPrefix(wrapper, dataPack.Headers[i], PrefixStyle.Base128);
                    }

                    WriteSize(bw, address, address + 4);

                    // Header section with data properties info
                    properties = dataPack.Properties.GetPropertiesList();
                    bw.Write(InfoSection);
                    address = GetAddress(bw);
                    bw.Write(0u);
                    cnt = (ushort)properties.Count;
                    bw.Write(cnt);

                    for (ushort i = 0; i < cnt; i++)
                    {
                        Serializer.SerializeWithLengthPrefix(wrapper, properties[i], PrefixStyle.Base128);
                    }

                    WriteSize(bw, address, address + 4);

                    // Header section with data dataPart's info
                    bw.Write(InfoSection);
                    var dataPartAddress = GetAddress(bw);
                    bw.Write(0u);
                    cnt = (ushort)dataPack.DataParts.Count;
                    bw.Write(cnt);

                    for (ushort i = 0; i < cnt; i++)
                    {
                        bw.Write(0u);
                        bw.Write((ushort)0);
                        bw.Write(0u);
                        bw.Write(0u);
                        bw.Write((ushort)0);
                        bw.Write(0u);
                        bw.Write(0u);
                        bw.Write(0u);
                    }

                    WriteSize(bw, dataPartAddress, dataPartAddress + 4);

                    bw.Write(DataSection);
                    address = GetAddress(bw);
                    bw.Write(0u);

                    for (ushort i = 0; i < cnt; i++)
                    {
                        WriteDataPart(bw, dataPartAddress + 6, i, dataPack);
                    }

                    WriteSize(bw, address, address + 4);

                    bw.Seek(0, SeekOrigin.End);
                    bw.Flush();

                    if (signAlgorithm != null)
                    {
                        uint protectedDataSize = GetAddress(bw) - dataSizeAddress;

                        wrapper.Position = dataSizeAddress;
                        bw.Write(protectedDataSize);
                        bw.Flush();

                        byte[] sign;
                        using (var filter = new FilteredStream(wrapper, dataSizeAddress, protectedDataSize))
                        {
                            sign = signAlgorithm.GetSign(filter);
                        }

                        wrapper.Seek(0, SeekOrigin.End);

                        bw.Write(sign, 0, sign.Length);
                        bw.Flush();

                        wrapper.Position = signInfoAddress;
                        bw.Write((uint)sign.Length);
                        bw.Flush();

                        wrapper.Seek(0, SeekOrigin.End);
                    }
                }
        }
예제 #8
0
        /// <summary>
        /// Sign source <see cref="DataPack"/> stream using given sign algorithm and outputs result to destinationStream
        /// </summary>
        /// <param name="prefixSize">Size of file prefix</param>
        /// <param name="signAlgorithm">Sign algorithm</param>
        /// <param name="sourceStream">Source stream</param>
        /// <param name="destinationStream">Destination stream</param>
        public static void Sign(uint prefixSize, ISignAlgorithm signAlgorithm, Stream sourceStream, Stream destinationStream)
        {
            if (signAlgorithm == null)
            {
                throw new ArgumentNullException("signAlgorithm");
            }
            if (sourceStream == null)
            {
                throw new ArgumentNullException("sourceStream");
            }
            if (destinationStream == null)
            {
                throw new ArgumentNullException("destinationStream");
            }

            var position = sourceStream.Position;

            if (!sourceStream.CanSeek)
            {
                throw new InvalidOperationException("Source stream doesn't support seeking.");
            }
            if (!sourceStream.CanRead)
            {
                throw new InvalidOperationException("Source stream doesn't support reading.");
            }
            if (!destinationStream.CanSeek)
            {
                throw new InvalidOperationException("Destination stream doesn't support seeking.");
            }
            if (!destinationStream.CanRead)
            {
                throw new InvalidOperationException("Destination stream doesn't support reading.");
            }
            if (!destinationStream.CanWrite)
            {
                throw new InvalidOperationException("Destination stream doesn't support writing.");
            }

            sourceStream.Seek(prefixSize + 1, SeekOrigin.Current);
            int isSignedByte = sourceStream.ReadByte();

            if (isSignedByte == 1)
            {
                throw new InvalidOperationException("Source stream already signed.");
            }

            sourceStream.Position = position;

            var buffer = BufferProvider.Current.TakeBuffer();

            try
            {
                int  byteCount;
                uint prefixBytesLeft = prefixSize + 1;
                while ((byteCount = sourceStream.Read(buffer, 0, (int)Math.Min(buffer.Length, prefixBytesLeft))) > 0)
                {
                    destinationStream.Write(buffer, 0, byteCount);
                    prefixBytesLeft -= (uint)byteCount;
                    if (prefixBytesLeft == 0)
                    {
                        break;
                    }
                }

                using (var wrapper = new NonClosingStreamWrapper(destinationStream)) // To prevent stream from closing by BinaryWriter
                    using (var bw = new BinaryWriter(wrapper))
                    {
                        bw.Write((byte)1);

                        uint signInfoAddress = GetAddress(bw);
                        bw.Write(0); // Protected data size
                        bw.Write(0); // Sign size

                        uint dataSizeAddress = GetAddress(bw) - 8;

                        while ((byteCount = sourceStream.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            wrapper.Write(buffer, 0, byteCount);
                        }

                        wrapper.Flush();
                        uint protectedDataSize = GetAddress(bw) - dataSizeAddress;

                        wrapper.Position = dataSizeAddress;
                        bw.Write(protectedDataSize);
                        bw.Flush();

                        byte[] sign;
                        using (var filter = new FilteredStream(wrapper, dataSizeAddress, protectedDataSize))
                        {
                            sign = signAlgorithm.GetSign(filter);
                        }

                        wrapper.Seek(0, SeekOrigin.End);

                        bw.Write(sign, 0, sign.Length);
                        bw.Flush();

                        wrapper.Position = signInfoAddress;
                        bw.Write((uint)sign.Length);
                        bw.Flush();

                        wrapper.Seek(0, SeekOrigin.End);
                    }
            }
            finally
            {
                BufferProvider.Current.ReturnBuffer(buffer);
            }
        }