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б). |