суббота, 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-----

1 комментарий:

Артур Тагиров комментирует...

Вы случайно не знаете, а как с помощью этой библиотеки получить "непрозрачную подпись" (text-armored)?