RIM Crypto API: Adding Encoding Schemes to the API

Encoding rules determine how cryptographic data such as keys and signatures, along with their associated parameters, are transmitted from one client to another. As the number of available algorithms increases, encoding becomes especially important to avoid confusion. Significant support for key and signature encoding is present in the Crypto API, but like anything else, the developer may need to add support for some new encoding format.

How Encoding Works in the API

Before attempting to add a new encoding algorithm to the Crypto API, it is necessary to examine how encoding is dealt with in the API. As an example, consider the following code for encoding a PKCS8 EC private key:

    // Create the crypto system and a private key
    ECCryptoSystem system = new ECCryptoSystem();
    ECKeyPair keyPair = new ECKeyPair( system );
    ECPrivateKey key = (ECPrivateKey)keyPair.getPrivateKey();

    // Now encode the key
    EncodedKey encodedKey = PrivateKeyEncoder.encode( key, "PKCS8" );
    byte[] encodedKeyData = encodedKey.getEncodedKey();

If the key is subsequently decoded, all the necessary information can be extracted from the encoded key, and the programmer need only pass in the encoded key:

    ECPrivateKey decodedKey = (ECPrivateKey)PrivateKeyDecoder.decode( encodedKeyData, "PKCS8" );

This code is representative of the encoding (and decoding) process in general. Encoding a signature or public key is virtually identical, except that SignatureEncoder.encode() or PublicKeyEncoder.encode() would be called. If the developer wanted to use an X509 encoding scheme instead of PKCS8 in the above example, he or she could have simply passed in the string "X509" with the call to encode().

The simple calls to encode() and decode() are all that are necessary to use the existing encoding schemes. However, the situation is more complex behind the scenes. The API must know which classes and methods to call based on the encoding scheme and algorithm in use.

Adding Private Key Encoding Algorithms

In the case of the above encoding example, the correct class was determined and the appropriate method was called behind the scenes, transparent to the developer. PKCS8_EC_PrivateKeyEncoder is the class that handles encoding for EC private keys under the PKCS8 encoding scheme. It has an encodeKey() method which is responsible for performing the actual encoding operation on the key data. To add a new encoding algorithm, the developer must simply extend PrivateKeyEncoder, override the appropriate methods (summarized later in this lesson), and register the encoder with the framework by calling PrivateKeyEncoder.add().

To decode the now-encoded key, the process is a bit more complex. The key decoder is simply passed a blob of data containing a private key. All that is known is the encoding scheme used; the key could be of any type supported. Therefore, a two-layer model was chosen for decoding operations. When PrivateKeyDecoder.decode() is called, it checks the encoded key to determine its specific type (through information stored with the key), and then passes the key on to the specific private key decoder, which can perform the actual decoding operation.

To add a decoder, two classes must be present for the framework: a general decoder class for the scheme (the first layer, which may already exist in the API or may be provided by the developer), and a decoder class for the specific key type (provided by the developer). So, if the scheme is one already supported by the API (ie PKCS8, X509, WTLS), the developer must simply create a class extending the existing base decoder class (such as PKCS8_PrivateKeyDeocder) that provides decoding support for the specific key type desired. Similar to the encoders, decodeKey() must be implemented, and the class must be registered with the framework with a call to add().

If the encoding scheme is not supported by the API, then the developer must create both a base class for the scheme as well as classes for the specific key types that are to be supported. These classes can be registered with the framework through the PrivateKeyDecoder.add() method.

Steps for Adding New Encoding Algorithms

The above example was for a private key encoder and decoder, but the steps for public key and signature encoders and decoders are very similar. The following tables summarize the steps involved in adding new encoding algorithms:

Encoders

Type Base Class Encoder Class Steps Required to Add
Signature encoder SignatureEncoder XXXX_SignatureEncoder

Extends: SignatureEncoder

Create a class extending SignatureEncoder.

Implement methods:

encodeSignature()
getEncodingAlgorithm()
getSignatureAlgorithm()

Call SignatureEncoder.add() to register class.

Public key encoder PublicKeyEncoder XXXX_PublicKeyEncoder

Extends: PublicKeyEncoder

Create a class extending PublicKeyEncoder.

Implement methods:

encodeKey()
getEncodingAlgorithm()
getKeyAlgorithm()

Call PublicKeyEncoder.add() to register class.

Private key encoder PrivateKeyEncoder XXXX_PrivateKeyEncoder

Extends: PrivateKeyEncoder

Create a class extending PrivateKeyEncoder.

Implement methods:

encodeKey()
getEncodingAlgorithm()
getKeyAlgorithm()

Call PrivateKeyEncoder.add() to register class.

Symmetric key encoder SymmetricKeyEncoder XXXX_SymmetricKeyEncoder

Extends: SymmetricKeyEncoder

Create a class extending SymmetricKeyEncoder.

Implement methods:

encodeKey()
getEncodingAlgorithm()
getKeyAlgorithm()

Call SymmetricKeyEncoder.add() to register class.

Decoders

Type Base Class Decoder Class Steps Required to Add
Signature decoder X509_SignatureDecoder
WTLS_SignatureDecoder

- OR -

Some class provided by the developer that extends SignatureDecoder

XXXX_SignatureDecoder

Extends: One of the base classes from the previous column

If this is an unsupported encoding scheme, create a base class extending SignatureDecoder that all specific decoders will subclass. Otherwise, use an existing base class.

Create a class extending the chosen base class.

Implement methods (in base class and subclass):

decodeSignature()
getEncodingAlgorithm()
getSignatureAlgorithm()

Call SignatureDecoder.add() to register class.

Public key decoder X509_PublicKeyDecoder
WTLS_PublicKeyDecoder

- OR -

Some class provided by the developer that extends PublicKeyDecoder

XXXX_PublicKeyDecoder

Extends: One of the base classes from the previous column

If this is an unsupported encoding scheme, create a base class extending PublicKeyDecoder that all specific decoders will subclass. Otherwise, use an existing base class.

Create a class extending the chosen base class.

Implement methods (in base class and subclass):

decodeKey()
getEncodingAlgorithm()
getKeyAlgorithm()

Call PublicKeyDecoder.add() to register class.

Private key decoder PKCS8_PrivateKeyDecoder

- OR -

Some class provided by the developer that extends PrivateKeyDecoder

XXXX_PrivateKeyDecoder

Extends: One of the base classes from the previous column

If this is an unsupported encoding scheme, create a base class extending PrivateKeyDecoder that all specific decoders will subclass. Otherwise, use an existing base class.

Create a class extending the chosen base class.

Implement methods (in base class and subclass):

decodeKey()
getEncodingAlgorithm()
getKeyAlgorithm()

Call PrivateKeyDecoder.add() to register class.

Symmetric key decoder PKCS8_SymmetricKeyDecoder

- OR -

Some class provided by the developer that extends SymmetricKeyDecoder

XXXX_SymmetricKeyDecoder

Extends: One of the base classes from the previous column

If this is an unsupported encoding scheme, create a base class extending SymmetricKeyDecoder that all specific decoders will subclass. Otherwise, use an existing base class.

Create a class extending the chosen base class.

Implement methods (in base class and subclass):

decodeKey()
getEncodingAlgorithm()
getKeyAlgorithm()

Call SymmetricKeyDecoder.add() to register class.