Архитектура криптографии Java (JCA) — это расширяемая среда, которая позволяет использовать криптографические операции. JCA также способствует независимости реализации (программа не должна заботиться о том, кто предоставляет криптографический сервис) и функциональной совместимости реализации (программа не должна быть привязана к конкретному поставщику конкретной криптографической службы).
JCA позволяет многочисленным криптографическим службам, например, шифрам, генераторам ключей, дайджестам сообщений, объединяться в класс java.security.Provider и регистрироваться декларативно в специальном файле (java.security) или программно через класс java.security.Security (метод ‘addProvider’).
Хотя JCA является стандартом, разные JDK реализуют JCA по-разному. Между JDK Sun / Oracle и IBM JDK IBM более «упорядочен», чем Oracle. Например, поставщик услуг IBM (com.ibm.crypto.provider.IBMJCE) реализует следующие форматы хранилищ ключей: JCEKS, PKCS12KS (PKCS12), JKS. Oracle JDK «распространяет» реализации формата хранилища ключей на следующих поставщиков:
- sun.security.provider.Sun — JKS
- com.sun.crypto.provider.SunJCE — JCEKS
- com.sun.net.ssl.internal.ssl.Provider — PKCS12
Несмотря на популярную рекомендацию писать приложения, которые не указывают на определенный класс Provider, есть некоторые варианты использования, которые требуют, чтобы приложение / программа точно знали, какие услуги предлагает класс Provider. Это требование становится более распространенным при поддержке нескольких серверов приложений, которые могут быть тесно связаны с конкретным JDK, например, WebSphere в комплекте с IBM JDK. Я обычно использую Tomcat + Oracle JDK для разработки (более легкий, быстрый), но мои настройки тестирования / производства — WebSphere + IBM JDK. Чтобы еще больше усложнить ситуацию, моему проекту необходимо использовать аппаратный модуль безопасности (HSM), который использует JCA API через класс провайдера com.ncipher.provider.km.nCipherKM. Поэтому, когда я дома (без доступа к HSM), я хотел бы продолжить писать код, но, по крайней мере, протестировать коды на провайдере JDK. Затем я могу переключиться на использование поставщика nCipherKM для следующего раунда модульного тестирования, прежде чем передать код в систему контроля версий.
Обычно предполагается, что одного класса провайдера достаточно, например, IBMJCE для IBM JDK, SunJCE для Oracle JDK. Таким образом, обычное решение состоит в том, чтобы реализовать класс, который определяет одного поставщика, используя отражение, чтобы избежать ошибок компиляции из-за ‘Class Not Found’:
01
02
03
04
05
06
07
08
09
10
11
|
//For nShield HSM Class c = Class.forName( 'com.ncipher.provider.km.nCipherKM' ); Provider provider = (Provider)c.newInstance(); //For Oracle JDK Class c = Class.forName( 'com.sun.crypto.provider.SunJCE' ); Provider provider = (Provider)c.newInstance(); //For IBM JDK Class c = Class.forName( 'com.ibm.crypto.provider.IBMJCE' ); Provider provider = (Provider)c.newInstance(); |
Этот дизайн был в порядке, пока я не столкнулся с ошибкой NoSuchAlgorithmException при выполнении некоторых тестовых случаев в Oracle JDK. И алгоритм, который я использовал, это RSA, общий алгоритм! Как это может быть, в документации сказано, что RSA поддерживается! Те же тесты отлично работали на IBM JDK.
После дальнейшего расследования я понял, что, к моему ужасу, у поставщика SunJCE нет реализации службы KeyPairGenerator для RSA. Однако реализация реализована в классе поставщика sun.security.rsa.SunRsaSign. Таким образом, предположение о том, что «один провайдер предоставит им все», нарушено. Но благодаря открытому API JCA объект Provider может быть передан при запросе экземпляра Service, например
1
|
KeyGenerator kgen = KeyGenerator.getInstance( 'AES' , provider); |
Чтобы помочь мне с осмотром различных объектов Provider, я предоставил тест JUnit для распечатки различных сервисов каждого зарегистрированного экземпляра Provider в JDK.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
package org.gizmo.jca; import java.security.Provider; import java.security.Provider.Service; import java.security.Security; import java.util.Comparator; import java.util.SortedSet; import java.util.TreeSet; import javax.crypto.KeyGenerator; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.junit.Test; public class CryptoTests { @Test public void testBouncyCastleProvider() throws Exception { Provider p = new BouncyCastleProvider(); String info = p.getInfo(); System.out.println(p.getClass() + ' - ' + info); printServices(p); } @Test public void testProviders() throws Exception { Provider[] providers = Security.getProviders(); for (Provider p : providers) { String info = p.getInfo(); System.out.println(p.getClass() + ' - ' + info); printServices(p); } } private void printServices(Provider p) { SortedSet services = new TreeSet ( new ProviderServiceComparator()); services.addAll(p.getServices()); for (Service service : services) { String algo = service.getAlgorithm(); System.out.println( '==> Service: ' + service.getType() + ' - ' + algo); } } /** * This is to sort the various Services to make it easier on the eyes... */ private class ProviderServiceComparator implements Comparator { @Override public int compare(Service object1, Service object2) { String s1 = object1.getType() + object1.getAlgorithm(); String s2 = object2.getType() + object2.getAlgorithm();; return s1.compareTo(s2); } } } |
В любом случае, если используемые вами алгоритмы являются общими и достаточно сильными для ваших нужд, можно использовать поставщика BouncyCastle. Он хорошо работает в JDK (протестирован с IBM и Oracle). BouncyCastle не поддерживает форматы хранилища ключей JKS или JCEKS, но если вы не суетливы, формат хранилища ключей BC работает просто отлично. BouncyCastle также имеет открытый исходный код и может быть свободно включен в ваши приложения.
Совет : хранилища ключей JKS не могут хранить SecretKeys. Вы можете попробовать это как домашнее задание
Надеюсь, что этот пост поможет вам глубже изучить JCA или, по крайней мере, осознать ловушки «блаженного невежества» при работе с JCA.
Ссылка: Криптография с использованием JCA — Services In Providers от нашего партнера JCG Аллена Джулии в блоге YK’s Workshop .