410013796724260
• Webmoney
R335386147728
Z369087728698
Цифровые подписи, SignatureСогласно общепринятой терминологии электронная подпись представляет реквизит электронного документа, который позволяет проверить целостность электронного документа и принадлежность подписи. Электронная подпись никак не связана с конфиденциальностью информации, т.е. подписанный документ может быть свободным для прочтения. Для работы с цифровой подписью используются асимметричные ключи — автор шифрует сообщение своим закрытым ключом (PrivateKey), а пользователи, имеющие открытые ключи (PublicKey) могут расшифровать и прочитать сообщение. Поскольку закрытый ключ имеет только автор, следовательно зашифровать сообщение мог только он. Этим подтверждается авторство сообщения. Зашифровать сообщение можно и симметричным ключом. Но такой ключ будет одноразовым и для следующего сообщения придется генерировать другой ключ. В некоторых случаях в качестве цифровой подписи используется дайджест сообщения, зашифрованный с помощью закрытого ключа. Адресат может получить дайджест сообщения, используя открытый ключ, и сравнить его с дайджестом самого сообщения и убедиться в подлинности сообщения, т.е. в его целостности и принадлежности автору. Цифровая подпись SignatureСначала рассмотрим процесс формирования и проверки цифровой подписи сообщения в виде дайджеста. Для этого последовательно пройдем 3 этапа :
На 2-ом этапе цифровую подпись сообщения в виде дайджеста сохраним в файл, а при проверке цифровой подписи на третьем этапе будем читать этот дайджест из файла и сравнивать его c цифровой подписью, получаемой открытым ключом.
Примечание : 1-ый этап. Генерирование ключей, KeyPairGenerator, KeyPairНе вникая в алгоритмы и особенности их реализациии, можно использовать уже готовые библиотеки и методы криптографии. Они предоставляются определенными так называемыми провайдерами (Provider). По умолчанию встроенные средства Java поставляет провайдер «SUN». Таким образом, единственное, что необходимо сделать для генерирования ключей, это указать алгоритм и провайдера. Для генерирования пары ключей PrivateKey и PublicKey используются классы KeyPairGenerator и KeyPair пакета java.security. В связи с тем, что большинство криптографических алгоритмов являются вероятностными, необходимо использовать вероятностный источник класса java.security.SecureRandom. При этом существует возможность использовать разные методы, например, SHA1PRNG (PRNG - pseudo random number generation algorithm). Ниже приводится код генерирования ключей privateKey, publicKey.
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("DSA", "SUN");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
keyPairGen.initialize(1024, random);
KeyPair keyPair = keyPairGen.genKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
Для получения объекта keyPairGen необходимо вызвать static factory метод getInstance(). В качестве аргументов передаются строки с указанием алгоритма DSA (Digital Signature Algorithm) и провайдера «SUN». Провайдера можно было бы и не указывать. При инициализации объекта KeyPair был определен размер в битах 1024 и источник случайных чисел random. Также можно было бы обойтись и без SecureRandom. На завершающем этапе выполнялась генерация пары ключей generateKeyPair() и определялись значения двух отдельных ключей - методы getPrivate() и getPublic() класса KeyPair. Для сохранения ключей в файл и чтения из файла предлагаются к использованию простенькие процедуры saveKey(path, key) и readKey(path) :
void saveKey(final String filePath, final Object key)
throws FileNotFoundException, IOException
{
if (key != null){
FileOutputStream fos = new FileOutputStream(filePath);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(key);
oos.close();
fos.close();
}
}
private Object readKey(final String filePath)
throws FileNotFoundException,
IOException, ClassNotFoundException
{
FileInputStream fis = new FileInputStream(filePath);
ObjectInputStream ois = new ObjectInputStream(fis);
Object object = ois.readObject();
return object;
}
2-ой этап.Формирование цифровой подписи, SignatureДля создания цифровой подписи используется класс Signature и его статический метод getInstance(), которому передается в качестве параметров алгоритм DSA с SHA1 (хэш-функция) и наименование провайдера. После этого signature инициализируется закрытым ключом.
final String MESSAGE = "Пусть всегда будет солнце";
final String FILE_sign = "data.sign";
// Создание подписи
Signature signature = Signature.getInstance("SHA1withDSA", "SUN");
// Инициализация подписи закрытым ключом
signature.initSign(privateKey);
// Формирование цифровой подпись сообщения с закрытым ключом
signature.update(MESSAGE.getBytes());
// Байтовый массив цифровой подписи
byte[] realSignature = signature.sign();
// Сохранение цифровой подписи сообщения в файл
FileOutputStream fos = new FileOutputStream(FILE_sign);
fos.write(realSignature);
fos.close();
После токо, как объект signature подготовлен, формируется цифровая подпись с использованием метода update(), и дайджест цифровой подписи в виде байтового массива сохраняется в файл. 3-ий этап. Проверка цифровой подписи, Signature.verify()На этом этапе формируется цифровая подпись сообщения с использованием открытого ключа. После этого из файла извлекается цифровая подпись, созданная закрытым ключом, и выполняется проверка методом verify().
// Инициализация цифровой подписи открытым ключом
signature.initVerify(publicKey);
// Формирование цифровой подпись сообщения с открытым ключом
signature.update(MESSAGE.getBytes());
// Открытие и чтение цифровой подписи сообщения
FileInputStream fis = new FileInputStream(FILE_sign);
BufferedInputStream bis = new BufferedInputStream(fis);
byte[] bytesSignature = new byte[bis.available()];
bis.read(bytesSignature);
fis.close();
// Проверка цифровой подписи
boolean verified = signature.verify(bytesSignature);
assertTrue("Проверка цифровой подписи", verified);
Цифровая подпись объекта, SignedObjectРассмотрим пример SigningExample, в котором объект «цифровой подписи» SignedObject будет использован для шифрации текста закрытым ключом, а уже открытым ключом будет извлекаться исходное сообщение. Для этого создадим функцию формирования подписанного объекта createSignedObject и функцию проверки цифрового SignedObject объекта verifySignedObject.
private SignedObject createSignedObject(final String msg, PrivateKey key)
throws InvalidKeyException, SignatureException,
IOException, NoSuchAlgorithmException
{
Signature signature = Signature.getInstance(key.getAlgorithm());
return new SignedObject(msg, key, signature);
}
private boolean verifySignedObject(final SignedObject obj, PublicKey key)
throws InvalidKeyException, SignatureException,
NoSuchAlgorithmException
{
// Verify the signed object
Signature signature = Signature.getInstance(key.getAlgorithm());
return obj.verify(key, signature);
}
В следующем листинге приводится код примера, в котором выполняются следующие действия :
private PrivateKey privateKey = null;
private PublicKey publicKey = null;
private final String MESSAGE = "Пусть всегда будет солнце";
private final String FILE_private = "private.key";
private final String FILE_public = "public.key" ;
public SigningExample()
{
try {
createKeys();
saveKey(FILE_private, privateKey);
saveKey(FILE_public , publicKey );
privateKey = (PrivateKey) readKey(FILE_private);
publicKey = (PublicKey ) readKey(FILE_public );
SignedObject signedObject = createSignedObject(MESSAGE, privateKey);
// Проверка подписанного объекта
boolean verified = verifySignedObject(signedObject, publicKey);
System.out.println("Проверка подписи объекта : " + verified);
// Извлечение подписанного объекта
String unsignedObject = (String) signedObject.getObject();
System.out.println("Исходный текст объекта : " + unsignedObject);
} catch (ClassNotFoundException e) {
} catch (IOException e) {
System.err.println("Exception thrown during test: " + e.toString());
} catch (InvalidKeyException e) {
System.err.println(e.getMessage());
} catch (SignatureException e) {
System.err.println(e.getMessage());
} catch (NoSuchAlgorithmException e) {
System.err.println(e.getMessage());
} catch (NoSuchProviderException e) {
System.err.println(e.getMessage());
}
}
Примечание : в примерах для формирования цифровой подписи была использована строка «Пусть всегда будет солнце». Однако подписывать можно не только строку, но и объект. При использовании объекта для подписи необходимо выполнять главное условие - объект должен быть сериализован. Более подробная информация о подписывании объекта вместе с примерами представлена на странице Сериализация объектов. Скачать пример создания ЭЦПИсходный код рассмотренного примера в виде проекта Eclipse можно скачать здесь (10.8 Kб). |
