суббота, 29 декабря 2007 г.

OpenPGP для C# .Net (2). Подписание строки (ЭЦП)

В данной заметке мы выдадим ЭЦП для произвольной строки. Результатом работы нашей программы будет файл, содержащий подпись в формате openPGP, оформленный по всем стандартам.



Как и в первой статье цикла («OpenPGP для C# .Net (1). Просмотр хранилища ключей») будем использовать библиотеку от «The Legion of the Bouncy Castle».


Вы уже знаете как обращаться с хранилищем секретных ключей:



// путь до хранилища секретных ключей
string path = @"secring_bak.gpg";
           
// прочитаем хранилище ключей
Stream BundleStream  =  File.OpenRead(path);
BundleStream  =  PgpUtilities.GetDecoderStream(BundleStream);
           
PgpSecretKeyRingBundle pgpSec  = new PgpSecretKeyRingBundle(BundleStream);Syhi-подсветка кода


Теперь нужно найти ключ, на котором мы будем подписывать. Напомню, что PGP-ключ состоит из 2-х половинок: секретного и открытого ключей.
Для того чтобы использовать секретную половинку нужно указать пароль доступа. Приведенный ниже код выполняет поиск PGP-ключа и указывает пароль для секретной половинки.



// отыщем ключ по уникальному идентификатору
long keyId = -7764185142489588446;
PgpSecretKey pgpSecKey = pgpSec.GetSecretKey(keyId);
           
// для доступа к секретному ключу нужно указать пароль
string pass = "1";
PgpPrivateKey pgpPrivKey =
    pgpSecKey.ExtractPrivateKey(pass.ToCharArray());Syhi-подсветка кода


Далее следует создать объект генератора подписи, предварительно выбрав алгоритм хеширования:



// для генерации подписи нужно выбрать
// функцию хеширования, в данном случае Sha1
HashAlgorithmTag digest = HashAlgorithmTag.Sha1;

// создадим объект генератора подписи
PgpSignatureGenerator sGen = new PgpSignatureGenerator(
    pgpSecKey.PublicKey.Algorithm, digest);

sGen.InitSign(PgpSignature.CanonicalTextDocument, pgpPrivKey);Syhi-подсветка кода


На этом подготовительные операции заканчиваются. Определим строку, которую хотим подписать, а также файл для хранения подписи в нужном формате. Корректность подписи из такого файла можно проверить стандартными средствами, например для windows можно использовать winPT.



// строку, которую будем подписывать,
// необходимо представить в виде массива байт
string str = "12привет";
byte[] byteStr = Encoding.UTF8.GetBytes(str);

// файл для хранения прозрачной подписи
Stream fos = File.Create("my_sign.asc");

// непосредственно подписание
sGen.Update(byteStr);

// формирование файла, нужного вида
ArmoredOutputStream aOut = new ArmoredOutputStream(fos);
aOut.BeginClearText(digest);
aOut.Write(byteStr);
aOut.Write((byte)'\r');
aOut.Write((byte)'\n');
aOut.EndClearText();
BcpgOutputStream bOut = new BcpgOutputStream(aOut);
           
sGen.Generate().Encode(bOut);Syhi-подсветка кода


Собирем весь код вместе:

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

using Org.BouncyCastle.Bcpg;
using Org.BouncyCastle.Bcpg.OpenPgp;
using System.Collections;


namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
    Console.WriteLine("**Подпишим строку**\n");

    // путь до хранилища секретных ключей
    string path = @"secring_bak.gpg";

    // прочитаем хранилище ключей
    Stream BundleStream = File.OpenRead(path);
    BundleStream =
        PgpUtilities.GetDecoderStream(BundleStream);

    PgpSecretKeyRingBundle pgpSec =
        new PgpSecretKeyRingBundle(BundleStream);

    // отыщем ключ по уникальному идентификатору
    long keyId = -7764185142489588446;
    PgpSecretKey pgpSecKey = pgpSec.GetSecretKey(keyId);

    // для доступа к секретному ключу нужно указать пароль
    string pass = "pass";
    PgpPrivateKey pgpPrivKey =
        pgpSecKey.ExtractPrivateKey(pass.ToCharArray());


    // для генерации подписи нужно выбрать
    // функцию хеширования, в данном случаи Sha1
    HashAlgorithmTag digest = HashAlgorithmTag.Sha1;
    PgpSignatureGenerator sGen = new PgpSignatureGenerator(
        pgpSecKey.PublicKey.Algorithm, digest);


    sGen.InitSign(
        PgpSignature.CanonicalTextDocument, pgpPrivKey);

    // строку, которую будем подписывать,
    // необходимо представить в виде массива байт
    string str = "12привет";
    byte[] byteStr = Encoding.UTF8.GetBytes(str);

    // файл для хранения прозрачной подписи
    Stream fos = File.Create("my_sign.asc");

    // непосредственно подписание
    sGen.Update(byteStr);

    // формирование файла, нужного вида
    ArmoredOutputStream aOut = new ArmoredOutputStream(fos);
    aOut.BeginClearText(digest);
    aOut.Write(byteStr);
    aOut.Write((byte)'\r');
    aOut.Write((byte)'\n');
    aOut.EndClearText();
    BcpgOutputStream bOut = new BcpgOutputStream(aOut);

    sGen.Generate().Encode(bOut);


    aOut.Close();
    fos.Close();

    Console.ReadLine();
}}}Syhi-подсветка кода


В итоге у нас получился файл следующего вида:



-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

12привет
-----BEGIN PGP SIGNATURE-----
Version: BCPG v1.32

iEYEARECAAYFAkd2NP0ACgkQlEASv9OK3SL0+wCeNq2PKsTZcGmJzbixpcMx8N1J
bSIAoKX9ERFgDOJaPO6FWm1OcBGbudaV
=Hw18
-----END PGP SIGNATURE-----

среда, 26 декабря 2007 г.

OpenPGP для C# .Net (1). Просмотр хранилища ключей

Данная заметка первая из планируемого цикла по использованию криптографических стандартов openPGP на платформе .Net. Предполагается, что вы знаете, что это такое и обладаете базовыми знаниями криптографии (получить эти знания на русском можно на страницах http://www.pgpru.com/).



Первым делом скачайте последнюю версию bccrypto-net, которую предлагает проект «The Legion of the Bouncy Castle» (большое им спасибо).


Для первого примера напишем консольное приложение, которое выводит id всех секретных ключей из хранилища.


Для начала это хранилище нужно создать. Для создания и хранения ключей PGP на ос Windows есть удобная программа с графическим интерфейсом – winPT. Каждый раз, после добавления нового ключа, программа предлагает сохранить копию хранилища ключей в удобном для вас месте (по умолчанию для хранилища секретных ключей предлагается название secring_bak.gpg). Именно с этой копией мы будем работать.


Не забудьте добавить к проекту консольного приложения BouncyCastle.Crypto.dll.



using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

using Org.BouncyCastle.Bcpg.OpenPgp;


namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(
                "**Прочитаем файл с секретными ключами**\n");

            // путь до хранилища секретных ключей
            string path = @"secring_bak2.gpg";

            // прочитаем хранилище ключей
            Stream BundleStream = File.OpenRead(path);
            BundleStream =
                PgpUtilities.GetDecoderStream(BundleStream);

            PgpSecretKeyRingBundle pgpSec =
                new PgpSecretKeyRingBundle(BundleStream);

            // переберем все связки секретных ключей,
            // каждая связка содержит секретный и публичный ключи
            foreach (PgpSecretKeyRing kRing in pgpSec.GetKeyRings())
            {
                // для каждого секретного ключа
                // покажем его уникальный идентификатор
                foreach (PgpSecretKey k in kRing.GetSecretKeys())
                {
                    Console.WriteLine(k.KeyId);
                }
            }

            BundleStream.Close();
            Console.ReadLine();
        }
    }
}Syhi-подсветка кода


Стоит отметить, что наше приложение выводит id ключей в десятеричной системе исчисления, а та же winPT в шестнадцатеричной. Вы можете проверить корректность вывода, скажем при помощи стандартного калькулятора windows – переведите число в нужную систему исчисления.