Example #1
0
        public byte[] Sign(ICryptographyPluginDataProvider dataProvider, X509Certificate2 certificate)
        {
            if (this.cryptoProviderAddress == null)
            {
                throw new CloudPluginException("Settings is wrong or corrupted");
            }

            // В примере используется аутентификация в криптопровайдере по JWT-токенам.
            var accessToken = this.GetAccessTokenAsync().Result;

            if (!TryGetPin(certificate.Thumbprint, out var pin))
            {
                // Пользователь отказался от ввода ПИН-кода.
                // Генерировать и показывать исключения в этом случае не нужно. Нужно просто выйти из подписания.
                return(null);
            }

            // Платформа sungero может дать как хеш подписываемых данных, так и поток с ними.
            if (certificate.SubjectName.Name == "Иванов Иван")
            {
                return(this.SignByStreamAsync(dataProvider, accessToken, pin).Result);
            }

            return(this.SignByHashAsync(dataProvider, accessToken, pin).Result);
        }
Example #2
0
        /// <summary>
        /// Подписать по хешу.
        /// </summary>
        /// <param name="dataProvider">Поставщик данных.</param>
        /// <param name="accessToken">Токен доступа.</param>
        /// <param name="pin">ПИН-код.</param>
        /// <returns>Подпись.</returns>
        private async Task <byte[]> SignByHashAsync(ICryptographyPluginDataProvider dataProvider, string accessToken, string pin)
        {
            // Поставщик данных может рассчитать хеш от данных по нужному алгоритму, если он реализован в этом или другом криптографическом плагине.
            var hash = dataProvider.ComputeHash("1.1.1.1.123.456");

            using (var request = new HttpRequestMessage(HttpMethod.Post, new Uri(this.cryptoProviderAddress, "/signByHash")))
            {
                request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
                request.Headers.Add("PIN", pin);
                request.Content = new StringContent(Convert.ToBase64String(hash));
                using (var response = await client.SendAsync(request))
                {
                    response.EnsureSuccessStatusCode();
                    var signatureBase64 = await response.Content.ReadAsStringAsync();

                    return(Convert.FromBase64String(signatureBase64));
                }
            }
        }
Example #3
0
        /// <summary>
        /// Подписать по потоку данных.
        /// </summary>
        /// <param name="dataProvider">Поставщик данных.</param>
        /// <param name="accessToken">Токен доступа.</param>
        /// <param name="pin">ПИН-код.</param>
        /// <returns>Подпись.</returns>
        private async Task <byte[]> SignByStreamAsync(ICryptographyPluginDataProvider dataProvider, string accessToken, string pin)
        {
            var stream = dataProvider.GetData(out var needDispose);

            try
            {
                using (var memoryStream = new MemoryStream())
                {
                    await stream.CopyToAsync(memoryStream);

                    using (var request = new HttpRequestMessage(HttpMethod.Post, new Uri(this.cryptoProviderAddress, "/signByBody")))
                    {
                        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
                        request.Headers.Add("PIN", pin);
                        request.Content = new StringContent(Convert.ToBase64String(memoryStream.ToArray()));
                        using (var response = await client.SendAsync(request))
                        {
                            response.EnsureSuccessStatusCode();
                            var signatureBase64 = await response.Content.ReadAsStringAsync();

                            return(Convert.FromBase64String(signatureBase64));
                        }
                    }
                }
            }
            finally
            {
                // Потоки и их жизненный цикл могут быть разными, в зависимости от того какие данные подписываются.
                // Поэтому платформа Sungero передает специальный флаг needDispose, определяющий,
                // нужно ли в плагине после использования потока вызвать для него Dispose() или не нужно.

                // Также нужно учитывать, что StreamContent для потоковой передачи данных всегда вызывает Dispose() у своего внутреннего потока.
                // Поэтому при использовании StreamContent полученный у поставщика данных поток необходимо скопировать в другой или защитить от освобождения как-либо иначе.
                if (needDispose)
                {
                    stream.Dispose();
                }
            }
        }