Статус: Активный участник
Группы: Участники
Зарегистрирован: 24.12.2007(UTC) Сообщений: 390 Откуда: КриптоПро Поблагодарили: 2 раз в 2 постах
|
Пример, котрый вы привели в тексте сообщения демонстрирует один из вариантов установки нескольких подписей на документ - Countersigner и это скорее всего не то что Вам требуется (в этом примере подписанный документ содержит как сам документ так и его подпись). Открепленная подпись создается почти так же как и совмещенная с сообщением, за исключение создания класса SignedCms. В кострукторе необходимо указать, что создается открепленная подпись: Код:SignedCms signedCms = new SignedCms(contentInfo, true);
Проверка подписи так же аналогична, за исключением того, что при создании объекта SignedCms необходимо передать как сообщения так и флаг detached подписи, например, так Код:ContentInfo contentInfo = new ContentInfo(msg);
SignedCms signedCms = new SignedCms(contentInfo, true);
Пример кода для получения открепленной подписи: Код:class DetachedSignature
{
const String signerName = "TestGost";
[STAThread]
static void Main(string[] args)
{
// Исходное сообщение.
const String msg = "Это сообщение, которое будет подписано.";
Console.WriteLine("\nИсходное сообщение (длина {0}): {1} ",
msg.Length, msg);
// Переводим исходное сообщение в массив байтов.
Encoding unicode = Encoding.Unicode;
byte[] msgBytes = unicode.GetBytes(msg);
Console.WriteLine("\n\n------------------------------");
Console.WriteLine(" Поиск сертификата ");
Console.WriteLine("------------------------------\n");
X509Certificate2 signerCert = GetSignerCert();
Console.WriteLine("\n\n----------------------");
Console.WriteLine("На стороне отправителя");
Console.WriteLine("----------------------\n");
byte[] encodedSignature = SignMsg(msgBytes, signerCert);
Console.WriteLine("\n\n------------------------");
Console.WriteLine(" На стороне получателя ");
Console.WriteLine("------------------------\n");
// При проверка detached подписи передаем и само сообщение
if (VerifyMsg(msgBytes, encodedSignature))
{
Console.WriteLine("\nСообщение проверено.");
}
else
{
Console.WriteLine("\nОшибка при проверке сообщения.");
}
}
// Открываем хранилище 'My' и ищем сертификат
// для подписи сообщения. Сертификат должен
// иметь поля Субъект (subject name) "TestGost".
static public X509Certificate2 GetSignerCert()
{
// Открываем хранилище My.
X509Store storeMy = new X509Store(StoreName.My,
StoreLocation.CurrentUser);
storeMy.Open(OpenFlags.ReadOnly);
// Отображаем сертификаты для удобства работы
// с примером.
Console.WriteLine("Найдены сертификаты следующих субъектов " +
"в хранилище {0}:", storeMy.Name);
foreach (X509Certificate2 cert in storeMy.Certificates)
{
Console.WriteLine("\t{0}", cert.SubjectName.Name);
}
// Ищем сертификат для подписи.
X509Certificate2Collection certColl =
storeMy.Certificates.Find(X509FindType.FindBySubjectName,
signerName, false);
Console.WriteLine(
"Найдено {0} сертификат(ов) в хранилище {1} для субъекта {2}",
certColl.Count, storeMy.Name, signerName);
// Проверяем, что нашли требуемый сертификат
if (certColl.Count == 0)
{
Console.WriteLine(
"Сертификат для данного примера не найден " +
"в хранилище. Выберите другой сертификат для подписи. ");
}
storeMy.Close();
// Если найдено более одного сертификата,
// возвращаем первый попавщийся.
return certColl[0];
}
// Подписываем сообщение секретным ключем.
static public byte[] SignMsg(
Byte[] msg,
X509Certificate2 signerCert)
{
// Создаем объект ContentInfo по сообщению.
// Это необходимо для создания объекта SignedCms.
ContentInfo contentInfo = new ContentInfo(msg);
// Создаем объект SignedCms по только что созданному
// объекту ContentInfo.
// SubjectIdentifierType установлен по умолчанию в
// IssuerAndSerialNumber.
// Свойство Detached устанавливаем явно в true, таким
// образом сообщение будет отделено от подписи.
SignedCms signedCms = new SignedCms(contentInfo, true);
// Определяем подписывающего, объектом CmsSigner.
CmsSigner cmsSigner = new CmsSigner(signerCert);
// Подписываем CMS/PKCS #7 сообение.
Console.Write("Вычисляем подпись сообщения для субъекта " +
"{0} ... ", signerCert.SubjectName.Name);
signedCms.ComputeSignature(cmsSigner);
Console.WriteLine("Успешно.");
// Кодируем CMS/PKCS #7 подпись сообщения.
return signedCms.Encode();
}
// Проверяем SignedCms сообщение и возвращаем Boolean
// значение определяющее результат проверки.
static public bool VerifyMsg(Byte[] msg,
byte[] encodedSignature)
{
// Создаем объект ContentInfo по сообщению.
// Это необходимо для создания объекта SignedCms.
ContentInfo contentInfo = new ContentInfo(msg);
// Создаем SignedCms для декодирования и проверки.
SignedCms signedCms = new SignedCms(contentInfo, true);
// Декодируем подпись
signedCms.Decode(encodedSignature);
// Перехватываем криптографические исключения, для
// возврата о false значения при некорректности подписи.
try
{
// Проверяем подпись. В данном примере не
// проверяется корректность сертификата подписавшего.
// В рабочем коде, скорее всего потребуется построение
// и проверка корректности цепочки сертификата.
Console.Write("Проверка подписи сообщения ... ");
signedCms.CheckSignature(true);
Console.WriteLine("Успешно.");
}
catch (System.Security.Cryptography.CryptographicException e)
{
Console.WriteLine("Функция VerifyMsg возбудила исключение: {0}",
e.Message);
Console.WriteLine("Проверка PKCS #7 сообщения завершилась " +
"неудачно. Возможно сообщене, подпись, или " +
"соподписи модифицированы в процессе передачи или хранения. " +
"Подписавший или соподписавшие возможно не те " +
"за кого себя выдают. Достоверность и/или целостность " +
"сообщения не гарантируется. ");
return false;
}
return true;
}
}
Проверять совместимость лучше навтречу с тем продуктом, с которым предполагается встречная работа, т.к. кроме банальных ошибок, возможно множество всяких ньюансов. Например стандарт CMS/PKCS7 поддерживает, различные способы кодирования отправителя, которые конкретное ПО может не поддерживать. Для проверки корректности кодирования сообщения можно использовать "Приложение командной строки dumpasn1 Питера Гутмана (Peter Gutmann) для просмотра файлов формата ASN.1 BER/DER: dumpasn1.rar (Windows, x86)." доступно на нашем сайте в разделе "Загрузка файлов". Для проверки корректности вычисления подписи и выяснения проблем совместимости с CAPI/CSP можно использовать csptest (опции cmslowsign, cmssfsign,...) входящий в состав csp версий выше 3.0 |