JAVA Toolkit
| home | contact




security provider

General

iSaSiLk makes use of the JCA/JCE API for all cryptographic operations.
However, it does not use the getInstance() methods of those
API classes directly, rather it uses a SecurityProvider class which
centralizes all the various calls. Basically, there are two reasons for
that. First, there is is no portable way to perform all
required operations. For example, there is no provider indepedent way
to construct a Principal object from its DER encoding. Also, some providers do
not implement all required features defined in JCA/JCE.
The second reason is that the SecurityProvider concept allows for more flexibility
and makes it easier to use several providers at the same time.

The important class here is iaik.security.ssl.SecurityProvider .
It contains all the relevant API methods and provides a default
SecurityProvider implementation that can be customized to accommodate your needs.
Additionally it contains the static setting
of the currently active SecurityProvider. It can be set and inspected using
the methods setSecurityProvider() and getSecurityProvider() ,
respectively. Note that this is a global setting for the entire VM.

The SecurityProvider Class

The SecurityProvider class defines a number of constant strings as well
as methods.

Constant String

Constant strings are defined using the following variable names:

ALG_DIGEST_MD5 ALG_DIGEST_SHA ALG_HMAC_MD5 ALG_HMAC_SHA ALG_SIGNATURE_SHADSA ALG_SIGNATURE_RAWDSA ALG_SIGNATURE_MD5RSA ALG_KEYPAIR_RSA ALG_KEYEX_RSA ALG_KEYEX_DSA ALG_KEYEX_DSA_CLIENT ALG_KEYEX_DH ALG_KEYEX_PSK ALG_KEYEX_DHE_PSK ALG_KEYEX_RSA_PSK ALG_CIPHER_AES ALG_CIPHER_AES_PKCS5 ALG_CIPHER_RC4 ALG_CIPHER_RC2 ALG_CIPHER_DES ALG_CIPHER_3DES ALG_CIPHER_IDEA ALG_CIPHER_AES ALG_CIPHER_RSA ALG_CIPHER_RSA_SIGN ALG_CIPHER_RSA_VERIFY ALG_CIPHER_RSA_ENCRYPT ALG_CIPHER_RSA_DECRYPT ALG_CIPHER_RSA_ENCRYPT_SSL2

They are used with the respective getInstance() methods.
A special case are the ALG_CIPHER_RSA_xxx strings. They are
used to simplify differentiation between the various types of RSA
operations, which is useful particularly for Smartcards (see also
iSaSiLk and Smartcards ).
Usually the same RSA implementation is used in all cases though.

SecurityProvider Constructor

The SecurityProvider class has two constructors. A no-argument constructor,
which will create a security provider that searches all JCA installed
providers, and a constructor that takes as string argument the name of
the only provider to be searched. This is usefull when you want to avoid
that implementations from some other provider is used.

Methods

The security provider defines the following methods, all of which
have been implemented to work in a provider independent way using
only the JCA/JCE APIs. Note that does not necessarily mean that
they will work with any provider as some providers do not implement
the necessary KeyFactories, etc.

protected boolean isImplemented(String algorithm); protected DHPublicKey getDHPublicKey(BigInteger y, BigInteger p, BigInteger g) throws Exception; protected DHPrivateKey getDHPrivateKey(BigInteger x, BigInteger p, BigInteger g) throws Exception; protected RSAPublicKey getRSAPublicKey(BigInteger modulus, BigInteger publicExponent) throws Exception; protected X509Certificate getX509Certificate(byte[] array) throws Exception; protected X509Certificate getX509Certificate(InputStream is) throws Exception; protected MessageDigest getMessageDigest(String algorithm) throws Exception; protected Mac getMac(String algorithm, Key key) throws Exception; protected Signature getSignature(String algorithm, int mode, Key key, SecureRandom random) throws Exception; protected byte[] calculateRawSignature(String algorithmName, byte[] dataToBeSigned, PrivateKey key, SecureRandom random) throws Exception; protected boolean verifyRawSignature(String algorithmName, byte[] dataToBeSigned, byte[] signature, PublicKey key); protected Cipher getCipher(String algorithm, int mode, Key key, AlgorithmParameterSpec spec, SecureRandom random) throws Exception; protected KeyPairGenerator getKeyPairGenerator(String algorithm) throws Exception; protected SecureRandom getSecureRandom(); public String decodeURL(byte[] encodedCertificateURL) throws Exception; public byte[] encodeURL(String certificateURL) throws Exception; public ServerName getTLSServerName(int nameType, byte[] encodedServerName); public ServerName[] getTLSServerName(int nameType, X509Certificate serverCert); public ServerName getTLSServerName(int nameType, String name) throws Exception;

Note that the getCipher() , getSignature() , and
getMac() must initialize the respective
object before returning it if requested (i.e. mode is not SIGNATURE_NONE,
CIPHER_NONE, key is not null, respectively). This structure was chosen to
allow you to convert keys if your provider can only handle its own keys objects, etc.
For example, for symmetric keys the SecretKeySpec class is used,
which may not be supported by all providers.

The following two methods could not be implemented in a provider independent way and only
return null when called. For this particular case the library has been
designed to work without them as well, but note that this disables the more
precise client authentication certificate selection. Therefore, it is recommended
to provide concrete implementations for your provider if possible.

protected Principal getPrincipal(byte[] array) throws Exception; protected byte[] getEncodedPrincipal(Principal principal);

The following method could not be implemented in a provider independent way and only
return null when called. For this particular case the library has been
designed to work without them as well, but note that this disables the more
precise server name verification. Therefore, it is recommended
to provide concrete implementations for your provider if possible.

protected String[] getTLSServerName(X509Certificate serverCert);

The following methods could not be implemented in a provider independent way.
They are required when using iSaSiLk with TLS extensions:

protected String[] getTLSServerName(X509Certificate serverCert); public byte[] createCertStatusRequest(int statusType) throws Exception; public byte[] createPkiPath(X509Certificate[] certificates) throws Exception; public SecretKey deriveKey(String algorithm, char[] password, byte[] salt, int iterationCount, int keyLen, String keyName, SecureRandom random) throws Exception; public byte[] calculateTrustedAuthorityIdentifier(int type, X509Certificate certificate) throws Exception;

The SecurityProvider Default Implementation

Below we provide the source code for the SecurityProvider class.
It is the code from iSaSiLk slightly modified
(comments and constant strings removed, etc.).

public class SecurityProvider {

protected String providerName;

public SecurityProvider() { this(null); }

public SecurityProvider(String providerName) { this.providerName = providerName; }

protected DHPublicKey getDHPublicKey(BigInteger y, BigInteger p, BigInteger g) throws Exception { DHPublicKeySpec spec = new DHPublicKeySpec(y, p, g); KeyFactory factory = (providerName == null) ? KeyFactory.getInstance("DH") : KeyFactory.getInstance("DH", providerName); DHPublicKey key = (DHPublicKey)factory.generatePublic(spec); return key; }

protected DHPrivateKey getDHPrivateKey(BigInteger x, BigInteger p, BigInteger g) throws Exception { DHPrivateKeySpec spec = new DHPrivateKeySpec(x, p, g); KeyFactory factory = (providerName == null) ? KeyFactory.getInstance("DH") : KeyFactory.getInstance("DH", providerName); DHPrivateKey key = (DHPrivateKey)factory.generatePrivate(spec); return key; }

protected RSAPublicKey getRSAPublicKey(BigInteger modulus, BigInteger publicExponent) throws Exception { RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, publicExponent); KeyFactory factory = (providerName == null) ? KeyFactory.getInstance("RSA") : KeyFactory.getInstance("RSA", providerName); RSAPublicKey key = (RSAPublicKey)factory.generatePublic(spec); return key; }

protected X509Certificate getX509Certificate(byte[] array) throws Exception { CertificateFactory factory = (providerName == null) ? CertificateFactory.getInstance("X.509") : CertificateFactory.getInstance("X.509", providerName); InputStream in = new ByteArrayInputStream(array); X509Certificate cert = (X509Certificate)factory.generateCertificate(in); return cert; }

protected Principal getPrincipal(byte[] array) throws Exception { return null; }

protected byte[] getEncodedPrincipal(Principal principal) { return null; }

protected MessageDigest getMessageDigest(String algorithm) throws Exception { return (providerName == null) ? MessageDigest.getInstance(algorithm) : MessageDigest.getInstance(algorithm, providerName); }

protected Mac getMac(String algorithm, Key key) throws Exception { Mac mac = (providerName == null) ? Mac.getInstance(algorithm) : Mac.getInstance(algorithm, providerName); if( key != null ) { mac.init(key); } return mac; }

protected Signature getSignature(String algorithm, int mode, Key key, SecureRandom random) throws Exception { Signature sig = (providerName == null) ? Signature.getInstance(algorithm) : Signature.getInstance(algorithm, providerName); if( mode == SIGNATURE_SIGN ) { sig.initSign((PrivateKey)key); } else if( mode == SIGNATURE_VERIFY ) { sig.initVerify((PublicKey)key); } // do nothing for SIGNATURE_NONE return sig; }

protected byte[] calculateRawSignature(String algorithmName, byte[] dataToBeSigned, PrivateKey key, SecureRandom random) throws Exception { Cipher cipher = getCipher(algorithmName, CIPHER_ENCRYPT, key, null, random); byte[] signature = cipher.doFinal(dataToBeSigned); return signature ; }

protected boolean verifyRawSignature(String algorithmName, byte[] dataToBeSigned, byte[] signature, PublicKey key) throws Exception { Cipher cipher = getCipher(algorithmName, CIPHER_DECRYPT, key, null, null); byte[] received_hash = cipher.doFinal(signature); return Utils.equalsBlock(dataToBeSigned, received_hash); }

protected Cipher getCipher(String algorithm, int mode, Key key, AlgorithmParameterSpec spec, SecureRandom random) throws Exception { if( algorithm.startsWith(ALG_CIPHER_RSA) ) { algorithm = ALG_CIPHER_RSA; } Cipher cipher = (providerName == null) ? Cipher.getInstance(algorithm) : Cipher.getInstance(algorithm, providerName); if( mode != CIPHER_NONE ) { int cmode = (mode == CIPHER_ENCRYPT) ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE; cipher.init(cmode, key, spec, random); } return cipher; }

protected KeyPairGenerator getKeyPairGenerator(String algorithm) throws Exception { return (providerName == null) ? KeyPairGenerator.getInstance(algorithm) : KeyPairGenerator.getInstance(algorithm, providerName); }

protected SecureRandom getSecureRandom() { return new SecureRandom(); }

protected String[] getTLSServerName(X509Certificate serverCert) { return null; }

}

Writing Your Own SecurityProvider

Step One: Writing the Provider

Basically there are two scenarios:

  1. You want to mainly use the IAIK JCE as a provider and use another
    provider just for a few algorithms. For instance, you might want to use
    the IAIK PCKS#11 provider for doing RSA based cipher operations only.
  2. You do not want to use the IAIK JCE at all and use only some other
    provider.

In the first case the easiest thing to do is to subclass the
IaikProvider class. For example,

package demo;

public class MySecurityProvider extends IaikProvider {

protected Cipher getCipher(String algorithm, int mode, Key key, AlgorithmParameterSpec param, SecureRandom random) throws Exception { if (key instanceof IAIKPKCS11Key) { if (algorithm.startsWith(ALG_CIPHER_RSA)) { algorithm = ALG_CIPHER_RSA; } cipherEngine = Cipher.getInstance(algorithm, ((IAIKPKCS11Key) key).getTokenManager().getProvider().getName()); if (mode != CIPHER_NONE) { int cmode = (mode == CIPHER_ENCRYPT) ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE; cipherEngine.init(cmode, key, param, random); } } else { cipherEngine = super.getCipher(algorithm, mode, key, param, random); }

} }

In the second case, i.e. you want to use a different provider altogether
and not use the IAIK JCE at all (for whatever reason ;-) it will be easiest
to start with the SecurityProvider class and override those
methods where you cannot use the default implementation. It might we
wise to have the IAIK JCE in your CLASSPATH at first so that
you can use its implementations for those parts you have not changed
to use your provider yet.

Step Two: Using it in Your Program

To use your own SecurityProvider in your application you only have
to make sure you have all required classes in your CLASSPATH
and that you activate it at the beginning of your program. This
can be done using, for example:

SecurityProvider.setSecurityProvider(new demo.MySecurityProvider());

Alternatively you may set your security provider via property file. iSaSiLk
first looks if there is a property file with name "SecurityProvider.properties"
located in package iaik.security.ssl. You may set the value of the only "class"
entry to the full name of your provider, e.g.:

class = demo.MySecurityProvider

Of course you also have to make sure your provider is initialized
in whatever way(s) it requires, e.g. add it as a JCE security provider.

 

 
print    tip a friend
back to previous page back  |  top to the top of the page