print Print
Logo: Stiftung Secure Information and Communication Technologies SIC Stiftung Secure Information and Communication Technologies SIC

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_DIGEST_SHA256
  ALG_DIGEST_SHA384
  ALG_HMAC_MD5
  ALG_HMAC_SHA
  ALG_HMAC_SHA256
  ALG_HMAC_SHA384
  ALG_SIGNATURE_SHADSA
  ALG_SIGNATURE_SHAECDSA
  ALG_SIGNATURE_SHA224ECDSA
  ALG_SIGNATURE_SHA256ECDSA
  ALG_SIGNATURE_SHA384ECDSA
  ALG_SIGNATURE_SHA412ECDSA
  ALG_SIGNATURE_RAWDSA
  ALG_SIGNATURE_MD5RSA
  ALG_SIGNATURE_SHA1RSA
  ALG_SIGNATURE_SHA224RSA
  ALG_SIGNATURE_SHA256RSA
  ALG_SIGNATURE_SHA384RSA
  ALG_SIGNATURE_SHA512RSA
  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_GCM
  ALG_CIPHER_AES_PKCS5
  ALG_CIPHER_CAMELLIA
  ALG_CIPHER_CAMELLIA_GCM
  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 Print