Creating a Cryptographic Key
A cryptographic key is a secret sequence that is used in ciphers to encrypt and decrypt data. The cryptographic APIs of the Java Card platform define an exhaustive set of interfaces for creating symmetric and asymmetric keys. The buildKey method of the KeyBuilder class is used to generate the key.
public static Key buildKey
(byte keyType, short keyLength, boolean keyEncryption);
The KeyBuilder class defines a set of selection parameters that are used to set the key type and its length. For example, to create a secret key using the RSA algorithm with a length of 64 bytes (64 ґ 8 = 512 bits), you can use such a call to the buildKey method:
Key rsa_private_key;
rsa_private_key = KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PRIVATE,
KeyBuilder.LENGTH_RSA_512, false);
The buildKey method returns an object of the Key interface. The actual type of this object is a class that implements an interface for working with a key of a given type. In the example above, the key implementation class should implement the RSAPrivateKey interface. To be able to call methods of the RSAPrivateKey interface, it is necessary to cast the key object to the RSAPrivateKey type:
RSAPrivateKey rsa_private_key;
rsa_private_key = (RSAPrivateKey)KeyBuilder.buildKey
(KeyBuilder.TYPE_RSA_PRIVATE, KeyBuilder.LENGTH_RSA_512, false);
The buildKey method returns a key object of the specified type, but this object has not yet been initialized.
In the case of the RSA1 secret key, initialization of the key consists in setting its module and exponent. After that, the key is ready to work. To initialize the key, the setModulus and setExponent methods defined in the RSAPrivateKey interface are used:
public void setExponent(byte[] buffer, short offset, short length) public void setModulus(byte[] buffer, short offset, short length)
The setKey method of the interface is used to initialize the DES key
DESKey:
public void setKey(byte[] keyData, short kOff)
The key data is in the KeyData array, starting from the kOff offset. After returning from the setKey method, the applet may not save data in the KeyData array, because they are copied to the internal buffer.
For security reasons, encrypted data may be used to initialize the key. In this case, the key object must be associated with the cipher object so that decryption of the key data can be performed using internal calls. Probably, the reader has already noticed that in the buildKey method, in addition to the KeyType and keyLength parameters, there is a third parameter – Initialization of RSA public keys is performed in the same way.
keyEncryption. If the value of this parameter is set to true1, then the key implements the javacardx.crypto.KeyEncryption interface. The setKeyCipher and getKeyCipher methods are defined in the KeyEncryption interface.
The setKeyCipher method is designed to establish a connection between the key object and the cipher object. If the key object is linked to the cipher object using this method, the original key data must be transmitted in encrypted form. If the key object does not implement the KeyEncryption interface or a null value is specified as a reference to the associated cipher object, the original key data must be transmitted in plain text.
In any case, if you later want to get the key data using the appropriate method, this data will be returned in plain text. For example, the getKey method of the DESKey interface returns an unencrypted DES key.
Creation and verification of a digital signature
The digital signature mechanism is designed to authenticate the sender and confirm the integrity of the message. Using the javacard.security.Signature class, which defines a digital signature mechanism, is similar to working with the MessageDigest class. To create a digital signature object, use the getInstance method of the Signature class:
Signature signature;
signature = Signature.getInstance(Signature.ALG_DSA_SHA, false);
To specify the algorithm, you can use one of the selection parameters defined in the Signature class. The algorithm selection parameter determines the digital signature generation algorithm and the encryption algorithm. The Signature class defines an exhaustive set of valid digital signature algorithms. In the example we are considering, a SHA digest is generated and then signed/verified using the DSA algorithm. The second parameter, externalAccess, determines whether the returned Signature object will be accessible from contexts other than its own context. (See description of the externalAccess parameter of the buildKey method of the KeyBuilder class.)
In the process of generating a digital signature, a key is used, so first you need to initialize the Signature object. To do this, you need to call one of the init methods.
public void init (Key theKey, byte theMode); public void init (Key theKey, byte theMode,
byte[] bArray, short bOff, short bLen);
Asymmetric algorithms use different keys to generate and verify a digital signature. Therefore, in the second parameter, theMode
The key implementation class can include the javacardx.crypto.KeyEncryption interface even if this parameter is set to false.
it is necessary to specify the mode of using the key. Two modes are defined in the Signature class:
· MODE_SIGN – digital signature creation mode.
· MODE_VERIFY – digital signature verification mode.
The second init method provides data transmission for initializing the algorithm via the bArray parameter. An example of initialization data is the initial vector, which is used in DES algorithms, and triple DES in CBC1 mode.
In the process of calculating the digital signature, data is transmitted in chunks using the update method. To transfer the last portion of data and obtain a digital signature, the sign method is used. Let’s consider an example of code for generating a digital signature based on data stored in arrays s1 and s2.
// we transfer data from the byte array s1 signature.update(s1, (short)0, (short)(s1.length));
// we transfer the last portion of data from the array s2
// and get the generated signature in the array sig_buffer
// starting from offset 0
signature.sign(s2, (short)0, (short)(s2.length), sig_buffer, (short)0);
During the digital signature verification process, the same data is transmitted in chunks using the update method. The verify method is used to transfer the last portion of data and obtain the result of digital signature verification. During the execution of the verify method, the digital signature calculated from the source data is compared with the signature received from the sender of the message. If these signatures match, the method returns true. Consider an example in which the digital signature that was generated in the previous example is verified:
// we transmit data from the byte array s1 signature.update(s1, (short)0, (short)(s1.length));
// we transmit the last portion of data from the array s2
// and compare the signature calculated from the transmitted data
// with sig_buffer, which contains the previously generated signature
if (signature.verify(s2, (short)0, (short)(s2.length), sig_buffer, sig_offset, sig_length) != true)
{
ISOException.throwIt(SW_WRONG_SIGNATURE);
}
The CBC (block ciphertext transfer, cipher block chaining) mode provides a feedback mechanism for a block cipher (converting a block of plaintext into a block of encrypted data). In CBC mode, the encryption results of the previous block are used to encrypt the current block. The initial vector is used to encrypt the first block. The MODE_SIGN and MODE_VERIFY parameters defined in the Signature class have nothing to do with CBC mode. They are used to set the mode of using the key – for generating or verifying a digital signature.
Just as in the case of the MessageDigest class, if all the source data is in a single byte array, the update method does not need to be called. After the sign or verify method completes, the Signature object returns to the state it was in after the previous call to the init method. The sign method also provides for the possibility of writing the output data of a digital signature to the place of the input data, and the data may overlap. The Signature class also defines two methods: getAlgorithm and getLength, with which the applet can make certain requests to the Signature object.
Data encryption and decryption
Encryption is a tool that ensures data privacy. During the encryption process, data is converted from plaintext to ciphertext. In the process of decryption, the ciphertext is converted into its original form.
In the javacardx.crypto class.Cipher defines encryption and decryption services for both symmetric and asymmetric algorithms. Just like when working with the MessageDigest and Signature classes, to create a Cipher object, the factory getInstance method is called, to which two parameters are passed. The first parameter defines the encryption algorithm. The second parameter, externalAccess, determines whether the returned Cipher object will be accessible from contexts other than its own context (see the description of the KeyBuilder class).
Then the Cipher object should be initialized. To do this, you need to give him the appropriate key and specify the mode of its use – encryption or decryption. To do this, you need to call one of the init methods:
public void init (Key theKey, byte theMode); public void init (Key theKey, byte theMode,
byte[] bArray, short bOff, short bLen);
In the following code example, we will create a Cipher object to work with the DES algorithm in CBC mode. The source data will not be expanded to the specified size. Initialization of the Cipher object for DES encryption:
Cipher cipher;
cipher = Cipher.getInstance(Cipher.ALG_DES_CBC_NO_PAD, false); cipher.init(des_key, Cipher.MODE_ENCRYPT);
The Cipher object can also be initialized for decryption. To do this, you must specify the MODE_DECRYPT selection parameter. This means that the key specified in the init method will be used for decryption.
Then, to encrypt the data, the update and doFinal methods are called:
public short update(byte[] inBuf, short inOffset, short inLength, byte[] outBuff, short outOffset);
public short doFinal (byte[] inBuf, short inOffset, short inLength,
byte[] outBuff, short outOffset);
Both methods encrypt the plaintext from the input buffer and write the ciphertext to the output buffer. The update method allows you to sequentially transmit the next portions of data. To transfer the last portion of data, the doFinal method is called. The final generated ciphertext is written to the output buffer specified when calling the doFinal method. After the completion of the doFinal method, the Cipher object returns to the state in which it was after the previous call to the init method. The update and doFinal methods are also used to decrypt the data. Note that in the case of decryption, encrypted data is placed in the input buffer, and the decrypted text is written to the output buffer. As in the case of the classes discussed above, the update method uses additional resources to store intermediate results, so it should be used only when all the source data cannot be placed in a single byte array.
Random data generation
Random data is widely used in cryptography. To create a random number generator in the javacard.security class.RandomData provides the getInstance method. The required algorithm is specified as a parameter when calling this method. The following algorithm selection options are available: RandomData.ALG_PSEUDO_RANDOM allows you to create
a general-purpose pseudo-random number generator, and RandomData.ALG_SECURE_RANDOM allows you to create a high-security random number generator for cryptographic purposes.
Similar to other classes of cryptographic APIs of the Java Card platform, the javacard.security class.RandomData is an abstract base class. Therefore, in order to use it, it must be extended to an implementation class. The RandomData object, which is returned by the getInstance method, is exactly the object of such an implementation class that ensures the operation of the required algorithm.
The internal default value is used as the initial value of the sequence of pseudo-random numbers generated by the RandomData object. In the case of a highly secure algorithm, the object attempts initialization using a completely random number. You can set the initial value for the random number generator using the setSeed method.
Finally, the generateData method is called to get a random number:
RandomData random_data =
RandomData.getInstance(RandomData.ALG_SECURE_RANDOM);
// the initial value is set in the byte array seed random_data.setSeed(seed, seed_offset, seed_length);
// the generated random number is written to the byte array random_num
random_data.generateData(random_num, random_num_offset,
random_num_length);
Secure data storage and processing is one of the fundamental reasons for using smart cards. Therefore, information security requirements are of paramount importance for smart card developers. This chapter is devoted to the security issues of the Java Card platform. It consists of three sections. Security features of the Java Card platform. Various security mechanisms of the Java Card platform with which these tools are implemented.
This chapter is not an information security specification. Its task is to help the reader understand the general capabilities of the Java Card platform to ensure information security. In addition, this chapter concludes.
A comprehensive approach to security is needed – from the point of view of the system as a whole. The Java Card platform implements the top level of the smart card platform, which includes hardware, the “native” operating system and the host system with which the smart card interacts. A discussion of the security systems of smart card platforms is beyond the scope of this book. Readers who are interested in this topic can recommend the following books: Rankl and Effing “Smart Card Handbook” [1], Guthery and Jurgensen “Smart Card Developer’s Kit”, and Hendry “Smart Card Security and Applications”.
The security features of the Java Card platform include the basic security features of the Java language, as well as additional security features implemented on the Java Card platform.
Java Language Security Tools
The Java Card platform supports a subset of the Java Programming Language and Java Virtual Machine specifications required for smart card applications. Therefore, the Java Card platform inherits security features built into a supported subset of the Java language. The Java language security tools that form the basis of the Java Card platform security system are listed in the following list:
Java Card Platform Security
· Java refers to languages with strong typing. All invalid type conversions are prohibited, such as converting integers to references.
· The Java language provides for checking boundaries when accessing arrays.
· The Java language does not support address arithmetic with pointers. Therefore, modification of pointers to gain illegal access to other people’s memory areas is impossible.
· Variables must be initialized before use.
· The level of access to all classes, methods and fields is strictly controlled. For example, a private method cannot be called outside of the class in which it is defined.
Additional security tools for the Java Card platform
The world of smart cards is very sensitive to security, so card issuers need a reliable computing platform that can meet the special requirements for smart cards. Additional security features are implemented on the Java Card platform:
· Permanent and temporary object models – Java objects by default
Cards are permanent and stored in permanent memory. For security and performance reasons, the Java Card platform provides temporary data, such as session keys, which are stored in temporary objects in RAM. The validity period of such objects is determined by their type: CLEAR_ON_RESET or CLEAR_ON_DESELECT. After resetting the card or after deactivating the currently active applet, the temporary object is assigned a default value
(zero, false or null).
· Atomicity of operations and transaction mechanism – the Java Card platform provides data storage in objects that are placed in permanent memory. During the data recording process, a power failure or power outage may occur. The Java Card platform implements three security features to ensure data integrity. First, the Java Card platform guarantees that any update of a single field of a permanent object or class is an atomic operation. If an error occurs during the update process, the field will retain its previous value. Secondly, in the javacard class.framework.Util has an arrayCopy method, which guarantees the atomicity of updating several elements of the array. In this case, atomicity means that either all bytes of data will be successfully written to the array, or the previous values of its elements participating in the update will be restored. Third, the Java Card platform supports the transaction model. An applet can declare an update operation of several fields of various permanent objects as atomic. All changes included in the transaction are either performed correctly and consistently, or the previous values of all changed permanent fields are restored.
Security mechanisms of the Java Card platform
· Applet Security System, or Applet Firewall – the security and integrity of the system (JCRE) and all applets that run on a smart card are provided by the applet firewall. This is a protection mechanism designed to isolate applets. It separates the system memory area from the applet memory area. The idea of a security system, or firewall, is that,
that each applet is executed in its own context (object space). An applet cannot access objects of another applet unless these applets are defined in the same package (and thus use a single context). An alternative access method is provided by well-structured and secure object sharing mechanisms that are supported by the Java Card platform.
· Object sharing – the Java Card platform provides there are several mechanisms for sharing objects. Firstly, JCRE is a privileged user and has full rights to access the applets and objects that are created by the applets. Secondly, applets can access JCRE services and resources through JCRE entry point objects. Third, applets from different contexts can collectively use objects that are instances of a class that implements a sharing interface. Such objects are called sharing Interface objects (SIO, Shareable Interface Object). Finally, applets and JCRE can exchange data via global arrays.
· Native methods of applets – native methods are not executed by the Java Card virtual machine. Therefore, they are not protected by means of providing security considerations of the Java Card platform. For this reason, the applets that are loaded into the card after its release cannot contain native methods. Applets that are stored in ROM memory, as well as applets developed under the control of card issuers, may contain native methods. The interfaces for accessing the native code used in such applets are the property of the card manufacturers.