BlackBerry_Java_SDK-Development_Guide-security_Beta-US

Page 1

BlackBerry Java SDK Security Version: 6.0 Development Guide


Published: 2011-03-17 SWD-1284837-0317035019-001


Contents 1 Security overview.............................................................................................................................................

4

2 RIM Cryptographic API...................................................................................................................................... Overview of cryptography................................................................................................................................ Overview of the RIM Cryptographic API........................................................................................................... Code sample: Implementing encryption........................................................................................................... Elements of a cryptographic implementation.................................................................................................. Cryptosystems........................................................................................................................................... Keys............................................................................................................................................................ Key stores.................................................................................................................................................. Key agreement........................................................................................................................................... Certificates................................................................................................................................................. Certificate chains....................................................................................................................................... Signatures.................................................................................................................................................. Digests....................................................................................................................................................... MACs.......................................................................................................................................................... Encrypting and decrypting data........................................................................................................................ Encrypting and decrypting data using factories........................................................................................ Block algorithms........................................................................................................................................ Encryptor engines...................................................................................................................................... Handling exceptions.................................................................................................................................. Cryptographic algorithms and cryptographic codes that the RIM Cryptographic API supports....................... Symmetric block algorithms that the RIM Cryptographic API supports.................................................... Stream encryption algorithms that the RIM Cryptographic API supports................................................. Asymmetric encryption algorithms that the RIM Cryptographic API supports......................................... Signature scheme algorithms that the RIM Cryptographic API supports.................................................. Key agreement scheme algorithms that the RIM Cryptographic API supports......................................... Key generation algorithms that the RIM Cryptographic API supports...................................................... Message authentication codes that the RIM Cryptographic API supports................................................ Message digest codes that the RIM Cryptographic API supports.............................................................. TLS and WTLS protocols that the RIM Cryptographic API supports........................................................... Cipher suites for the key establishment algorithm that the RIM Cryptographic API supports................. Symmetric algorithms that the RIM Cryptographic API supports.............................................................. Hash algorithms that the RIM Cryptographic API supports....................................................................... Limitations of RIM Cryptographic API support for cipher suites for the key establishment algorithm.....

6 6 7 8 11 12 13 14 18 22 22 23 27 28 29 29 31 37 40 42 42 42 42 42 43 43 43 43 44 44 44 45 45

3 Content protection...........................................................................................................................................

46


Compressing data with content protection...................................................................................................... Enabling content protection............................................................................................................................. Enabling content protection through IT policy rules................................................................................. Enabling content protection by a device user........................................................................................... Understanding locked and unlocked device states.......................................................................................... Cryptographic keys.................................................................................................................................... Encrypting data when the device is locked............................................................................................... Decrypting data when the device is unlocked........................................................................................... Encrypting data when the device is unlocked........................................................................................... Locking the device..................................................................................................................................... Implementing content protection.................................................................................................................... Obtaining and releasing content protection tickets.................................................................................. Subscribing to content protection............................................................................................................. Registering a PersistentContentListener................................................................................................... Encoding an object.................................................................................................................................... Decoding an object.................................................................................................................................... Handling exceptions..................................................................................................................................

46 47 47 48 48 48 49 50 50 50 51 53 54 56 58 58 59

4 API control and code signing............................................................................................................................ Running BlackBerry device applications that use protected APIs..................................................................... Register to use protected BlackBerry APIs................................................................................................ Using restricted code signatures............................................................................................................... Signing your application............................................................................................................................ Requesting a replacement registration key............................................................................................... Prevent a BlackBerry device application that runs on the BlackBerry Smartphone Simulator from accessing protected APIs........................................................................................................................... Use a code signing key to help protect packages and classes................................................................... Register to use a new code signing key..................................................................................................... Import an existing registered code signing key......................................................................................... Remove a registered code signing key...................................................................................................... View the signature status for code signature requests............................................................................. Suppress code signing warnings................................................................................................................ Suppress password prompts from the BlackBerry Signature Tool............................................................ Sign a BlackBerry application project automatically after packaging........................................................ Run the BlackBerry Signature Tool in the background.............................................................................. Turn off automatic signature when you package a BlackBerry application project.................................. Using code signing keys to restrict access to packages or classes in a BlackBerry library project............. Using code signing keys to protect data in applications................................................................................... Restrict access to persistent store data using code signing keys..............................................................

60 60 60 61 61 61 62 62 62 63 63 63 63 64 64 64 64 65 66 66


Restrict access to runtime store data using code signing keys.................................................................. IT policy support........................................................................................................................................

66 67

5 Find more information......................................................................................................................................

68

6 Glossary............................................................................................................................................................

69

7 Provide feedback..............................................................................................................................................

74

8 Document revision history................................................................................................................................

75

9 Legal notice.......................................................................................................................................................

76


Security overview

Development Guide

Security overview

1

Research In Motion速 provides several options to help you protect data in your BlackBerry速 device application.

Authentication BlackBerry device users can set a password for their BlackBerry devices. When this password is active, the user must provide the password to gain access to the device. In addition, you can implement authentication of the connection between your application and the server, internet or intranet using HTTP Basic authentication or HTTPS.

Encryption Encryption is the process of making data unreadable until it is decrypted. There are several ways that you can encrypt data in your application: Encryption method RIM速 Cryptographic API Content protection

SQLite速 encryption Media card encryption

Description This API helps you encrypt and decrypt data, manage cryptographic keys, and digitally sign and verify data. It also helps you create highly secure connections. Built on the RIM Cryptographic API, the Content Protection API provides a solution for encrypting String and byte array objects. The Content Protection API works with the Content Protection framework on the BlackBerry device. The framework must be enabled by an IT policy rule or Option setting. The Database API includes encryption functionality for SQLite databases. This functionality is based on JSR 75. It allows you to encrypt data stored on external media cards (microSD) and built-in media storage (eMMC).

Access restriction You can restrict the other applications on a BlackBerry device from having access to data in your application. How you do this depends on how your data is stored. Data storage location Files SQLite databases Persistent store Record store

4

How to restrict data access You can restrict access to files in the file system with code signing keys used in conjunction with the ControlledAccess class. The Database API provides the Protected security option, which makes the database available only to apps that are signed with the same code signing key. You can restrict access to objects in the persistent store with code signing keys used in conjunction with the ControlledAccess class. You can store data privately so that other apps on the device can't access it.


Security overview

Development Guide

Data storage location Runtime store

How to restrict data access You can restrict access to objects in the runtime store with code signing keys used in conjunction with the ControlledAccess class.

Transport protection You can protect data while in transport: API RIM Cryptographic API

Transport security The RIM Cryptographic API includes TLS, WTLS, and SSL APIs that help you create highly secure connections.

Other security mechanisms This guide does not describe every form of security in detail. The central resource for BlackBerry security is www.blackberry.com/security. For more information about security of specific data storage approaches such as SQLite databases, the persistent store, and the runtime store, see the BlackBerry Java SDK Data Storage Development Guide, available at www.blackberry.com/go/devguides. For information about developing applications for smart cards, see the BlackBerry Java SDK Smart Card Development Guide, available at www.blackberry.com/go/devguides.

5


Development Guide

RIM Cryptographic API

RIM Cryptographic API

2

The RIM® Cryptographic API is a collection of classes that help you to create security solutions for your BlackBerry® device application. Using the RIM Cryptographic API, you can encrypt and decrypt data, digitally sign and verify data, work with highly secure connections, and manage cryptographic keys. The CLDC and MIDP specifications of Java® ME do not define a cryptographic API. In creating the RIM Cryptographic API, RIM chose to not follow the Java security model because mobile devices have little room for multiple cryptographic algorithm providers. In addition, compile time checking is more appropriate for embedded development than runtime checking. The RIM Cryptographic APIs are in the net.rim.device.api.crypto package.

Overview of cryptography For electronic data transmission, cryptography is used to provide highly secure, authenticated communication between a sender and a receiver. It encompasses a wide variety of processes from complex protocols and algorithms to the simple scrambling of letters of text. While cryptography is central to the security and integrity of transmitted data, it is important to realize that no protocol is entirely secure. Protocols and algorithms are constantly being assaulted by increasingly intelligent criminals with increasingly powerful computers. Cryptographers are constantly improving routines and algorithms. For example, cryptographers increase key sizes to increase the amount of work required by the hacker. There are two main types of cryptosystem: • •

Symmetric: This cryptosystem is also known as block cipher cryptography. It uses the same key for encryption and decryption. The advantages are that encryption and decryption are relatively fast. The disadvantage is that it can be difficult to securely distribute the keys. Asymmetric: This cryptosystem is also known as public key cryptography. The sender encrypts data with a public key, and then the receiver decrypts it with a private key that they already have. The keys are easy to distribute, but the encryption and decryption is relatively slow.

Symmetric and asymmetric cryptosystems are often used together. For example, two people, user1 and user2, need to do a lot of communication that must be encrypted. They need a fast cryptosystem so that their communication is quick, but they need an easy way to create a key. User1 uses user2's public key to encrypt a symmetric key. User1 then sends the symmetric key to user2. User2 decrypts the symmetric key with her private key (that only she knows). Now user1 and user2 share a symmetric key. They can send encrypted data to each other using a fast, symmetric cryptosystem. The three main goals of cryptography are confidentiality, integrity, and authentication. Confidentiality: The most common use of cryptography in the business environment is for data encryption. Encryption is the disguising of a message in such a way that its true meaning is shielded until it is deciphered by the intended receiver. There are many different ways to accomplish this. The most common approach is through the use of ciphers. In a typical scenario, a message is encoded using a predetermined and agreed upon protocol and cipher. The resulting message, called the ciphertext, is then transmitted to the receiver. Once the message is delivered, the receiver decrypts the message using the agreed upon protocol. 6


Development Guide

Overview of the RIM Cryptographic API

Many different encryption algorithms exist. Some are more secure and more practical than others. Integrity: Data integrity is acheived in modern cryptography by using a hash function to produce a unique "digital fingerprint" of a document. In other words, a complex function is applied to a document to create a unique value. When the message is delivered, the user applies the same hash function to the message. If the resulting values match, then the message likely has not been modified. While even the best hash functions are not guaranteed to produce unique values every time, the chances that two different documents will produce the same value is very unlikely. Different hashing routines exist for use in different scenarios. A common hashing routine is the MAC. MACs combine encryption keys and hashing functions to allow users to transmit secure, key-dependent hash values. Authentication: Authentication is a way to verify who you are communicating with. One common protocol combines a digital signature along with a private key encryption routine to create a type of digital stamp. In order to decrypt the message, the receiver must decrypt the digital stamp using the sender's private key. Assuming the sender's private key has not been compromised, this method assures the authenticity of the digital signature.

Overview of the RIM Cryptographic API The RIM® Cryptographic API contains the following APIs.

Secure Messaging API The Secure Messaging API is an implementation of the CMS standard. CMS specifies standard content types for cryptography. It describes message and transmission formats for those content types. S/MIME is built on CMS. The net.rim.device.api.crypto.cms package provides classes to help you create and manage CMS content types.

Secure Connection API The Secure Connection API defines protocol functionality that you can use to establish highly secure communication. You can use SSL, TLS, or WTLS. SSL: SSL is designed to secure data that is sent over TCP/IP connections; it is used in the implementation of HTTPS. SSL is provided in the net.rim.device.api.crypto.tls.ssl30 package. TLS: TLS is a standard from the IETF that is based on SSL version 3. TLS was designed to replace SSL and has been widely adopted. TLS is provided in the following packages: • •

net.rim.device.api.crypto.tls net.rim.device.api.crypto.tls.tls10

WTLS: WTLS is a layer on top of WAP rather than TCP/IP. Securing wireless communications that use WAP involves using WTLS between the client device and the WAP gateway, and one of SSL or TLS beyond the WAP gateway. WTLS is provided in the net.rim.device.api.crypto.tls.wtls20 package.

Keystore API

7


Development Guide

Code sample: Implementing encryption

A key store is a database that stores cryptographic keys and certificates. Each BlackBerry® device has a key store that is preloaded with root certificates for all of the certificate authorities. This practice makes it possible for BlackBerry device users to trust the root certificates, which form the basis for all subsequent chains of trust. Key store classes are provided in the net.rim.device.api.crypto.keystore package.

Certificate API Certificates are electronic documents that hold keys, along with identifying information. There are several packages to help you manage cryptographic certificates: • • • • •

net.rim.device.api.crypto.certificate net.rim.device.api.crypto.certificate.status net.rim.device.api.crypto.certificate.x509 javax.microedition.pki net.rim.device.api.crypto.certificate.wtls

Encoder API Encoding is the process of converting data from one format to another. While it is often part of the encryption process, encoding is not the same as encryption and is generally not secure. Keys are encoded to provide a standard representation, not to protect their identity. Classes for encoding keys and signatures are provided in the net.rim.device.api.crypto.encoder package.

ASN1 API Most applications use certificates that are produced by a certificate authority. If you need to parse or read certificates yourself, you must use the net.rim.device.api.crypto.asn1 package.

OID API Object identifiers are managed with the net.rim.device.api.crypto.oid package.

Primitives API Cryptographic primitives are the keys, MACs, ciphers, unkeyed algorithms such as digests and PRNGs, and other functionality associated with both symmetric and public key cryptography. Cryptographic primitives are provided in the net.rim.device.api.crypto package.

Code sample: Implementing encryption The following code sample uses Triple DES, which is a symmetric key encryption algorithm. The RIM® Cryptographic API simplifies the use of Triple DES to encrypt and decrypt messages. import import import import import import import 8

java.io.*; net.rim.device.api.crypto.*; net.rim.device.api.util.*; net.rim.device.api.ui.*; net.rim.device.api.ui.component.*; net.rim.device.api.ui.container.*; net.rim.device.api.util.*;


Development Guide

Code sample: Implementing encryption

public class EncodeDecodeString extends UiApplication implements FieldChangeListener { private ButtonField _encrypt_button; private ButtonField _decrypt_button; private TripleDESKey _key; private TextField _edit_input_string; public static void main( String[] args ) { EncodeDecodeString theApp = new EncodeDecodeString(); theApp.enterEventDispatcher(); } public void fieldChanged(Field field, int context) { String strCurrentMessage = _edit_input_string.getText(); if(field == _encrypt_button) { _edit_input_string.setText(encrypt(strCurrentMessage)); } else { _edit_input_string.setText(decrypt(strCurrentMessage)); } } public EncodeDecodeString() { MainScreen screen = new MainScreen(); screen.setTitle(new LabelField("Crypto Demo", LabelField.ELLIPSIS | LabelField.USE_ALL_WIDTH)); _edit_input_string = new BasicEditField("Message:", null, 256, BasicEditField.FILTER_DEFAULT); screen.add(_edit_input_string); _encrypt_button = new ButtonField("Encrypt",ButtonField.CONSUME_CLICK); _encrypt_button.setChangeListener(this); screen.add(_encrypt_button); _decrypt_button = new ButtonField("Decrypt"); _decrypt_button.setChangeListener(this); screen.add(_decrypt_button); }

pushScreen(screen);

public String encrypt(String plaintext) { try { _key = new TripleDESKey(); TripleDESEncryptorEngine encryptionEngine = new TripleDESEncryptorEngine(_key);

9


Code sample: Implementing encryption

Development Guide

// In most cases, the data to encrypt will not fit into the block // length of a cipher. When that happens, use a padding algorithm // to pad out the last block. This uses PKCS5 to do the padding. PKCS5FormatterEngine formatterEngine = new PKCS5FormatterEngine( encryptionEngine ); // Use the byte array output stream to catch the encrypted information. ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); // Create a block encryptor to help use the triple DES engine. BlockEncryptor encryptor = new BlockEncryptor( formatterEngine, outputStream ); // Encrypt the data. encryptor.write( plaintext.getBytes() ); // Close the stream. This forces the extra bytes to be padded out if // there were not enough bytes to fill all of the blocks. encryptor.close(); // Get the encrypted data. byte[] encryptedData = outputStream.toByteArray(); String strEncrypted = new String(encryptedData); return(strEncrypted);

}

} catch( CryptoTokenException e ) { System.out.println(e.toString()); } catch (CryptoUnsupportedOperationException e) { System.out.println(e.toString()); } catch( IOException e ) { System.out.println(e.toString()); } return "error";

public String decrypt(String ciphertext) { try { // Perform the decryption. Since this is a symmetric algorithm, // use the same key as before. TripleDESDecryptorEngine decryptorEngine = new TripleDESDecryptorEngine(_key); // Create the unformatter engine to remove padding bytes. PKCS5UnformatterEngine unformatterEngine = new PKCS5UnformatterEngine( decryptorEngine ); // Set up an input stream to hand the encrypted data to the // block decryptor.

10


Elements of a cryptographic implementation

Development Guide

ByteArrayInputStream inputStream = new ByteArrayInputStream( ciphertext.getBytes() ); // Create the block decryptor passing in the unformatter engine and the // encrypted data. BlockDecryptor decryptor = new BlockDecryptor( unformatterEngine, inputStream ); // Next, read from the stream. This example reads the data 10 bytes // at a time and then adds that new data to the decryptedData array. // For efficiency in a real situation, you should use a value // larger than 10. This example uses a small value to demonstrate // several iterations through the loop. byte[] temp = new byte[10]; DataBuffer db = new DataBuffer(); for( ;; ) { int bytesRead = decryptor.read( temp ); if( bytesRead <= 0 ) { // No more information to read, so leave loop. break; } db.write(temp, 0, bytesRead); } // Make sure that the decrypted data is the same as the data // that was passed into the encryptor. byte[] decryptedData = db.toArray(); String strDecrypted = new String(decryptedData); return(strDecrypted);

}

}

} catch( CryptoTokenException e ) { System.out.println(e.toString()); } catch (CryptoUnsupportedOperationException e) { System.out.println(e.toString()); } catch( IOException e ) { System.out.println(e.toString()); } return "error";

Elements of a cryptographic implementation To create an application that uses the RIM速 Cryptographic API, you work with cryptographic elements such as keys, key stores, and certificates.

11


Elements of a cryptographic implementation

Development Guide

Cryptosystems A cryptosystem is a set of algorithms that implements encryption, decryption, and key generation. Cryptosystems are used by all the public key cryptographic algorithms to hold public information that is common to all users within a cryptographic community or system. Typically the cryptosystem holds some mathematical numbers that each user's computer must have for the cryptographic calculations to succeed. The RIM速 Cryptographic API supports the following cryptosystems: Diffie-Hellman, DSA, Elliptic Curve, Key Exchange Algorithm, and RSA. To create a cryptosystem, you implement a class in the net.rim.device.api.crypto.CryptoSystem interface. The CryptoSystem interface simplifies the creation and management of keys, and lets you specify all possible parameters for keys.

RSA cryptosystem RSA is a public key cryptosystem. The RSA cryptosystem is generally considered to be the easiest of the supported cryptosystems to use because you only need to set the size of the modulus. To create an RSA cryptosystem, use the RSACryptoSystem class. Code sample The following code sample uses the RSACryptoSystem class to create an RSA cryptosystem. It specifies the modulusBitLength parameter as 1024. RSACryptoSystem rsaCryptoSystem = new RSACryptoSystem(1024);

DSA cryptosystem DSA is a United States federal government standard defined in FIPS 186. To create a DSA cryptosystem, use the DSACryptoSystem class. There are multiple constructors that you can use to create a DSA cryptosystem. This is the simplest way to create a DSA cryptosystem: DSACryptoSystem system = new DSACryptoSystem();

Alternatively, you can specify parameters. In the following example, the constructor is called with values for p, q, and g. /* 1024 bit key parameters */ private static final byte[] p = new (byte)0xfd, (byte)0x7f, (byte)0x53, (byte)0x12, (byte)0x29, (byte)0x52, (byte)0x2e, (byte)0xec, (byte)0xe4, (byte)0xb7, (byte)0x52, (byte)0x3c, (byte)0xc3, (byte)0x1e, (byte)0x3f, (byte)0x26, (byte)0x69, (byte)0x45, (byte)0x51, (byte)0xfb, (byte)0x59, (byte)0xfa, (byte)0xbf, (byte)0xc5, 12

byte[] { (byte)0x81, (byte)0xdf, (byte)0xe7, (byte)0xef, (byte)0x80, (byte)0x5d, (byte)0x3d, (byte)0xf5,

(byte)0x1d, (byte)0x4a, (byte)0xf6, (byte)0x44, (byte)0xb6, (byte)0x40, (byte)0x8d, (byte)0xba,

(byte)0x75, (byte)0x9c, (byte)0x11, (byte)0x00, (byte)0x51, (byte)0x22, (byte)0x58, (byte)0x30,


Development Guide

Elements of a cryptographic implementation

(byte)0xf6, (byte)0xcb, (byte)0x9b, (byte)0x55, (byte)0x6c, (byte)0x81, (byte)0x3b, (byte)0x80, (byte)0x1d, (byte)0x34, (byte)0xf2, (byte)0x66, (byte)0x60, (byte)0xb7, (byte)0x6b, (byte)0x50, (byte)0xa5, (byte)0xa4, (byte)0x9f, (byte)0x9f, (byte)0x04, (byte)0x7b, (byte)0x10, (byte)0x22, (byte)0xc2, (byte)0xbb, (byte)0xa9, (byte)0xd7, (byte)0xfe, (byte)0xb7, (byte)0x1b, (byte)0xf8, (byte)0x3b, (byte)0x57, (byte)0xe7, (byte)0xa8, (byte)0xa6, (byte)0x15, (byte)0x0f, (byte)0x04, (byte)0x83, (byte)0xf6, (byte)0xd3, (byte)0xc5, (byte)0x1e, (byte)0x02, (byte)0x35, (byte)0x54, (byte)0x13, (byte)0x5a, (byte)0x91, (byte)0x32, (byte)0xf6, (byte)0x75, (byte)0xf3, (byte)0x2b, (byte)0x61, (byte)0xd7, (byte)0x2a, (byte)0xef, (byte)0x22, (byte)0x03, (byte)0x19, (byte)0x9d, (byte)0xd1, (byte)0x01, (byte)0xc7 }; private static final byte[] q = new byte[] { (byte)0x97, (byte)0x60, (byte)0x50, (byte)0x8f, (byte)0x15, (byte)0x0b, (byte)0xcc, (byte)0xb2, (byte)0x92, (byte)0xb9, (byte)0xa2, (byte)0xeb, (byte)0x84, (byte)0x0b, (byte)0xf0, (byte)0x1c, (byte)0xf5 }; private static final byte[] g = new byte[] { (byte)0xf7, (byte)0xe1, (byte)0xa0, (byte)0x85, (byte)0xd6, (byte)0x3d, (byte)0xde, (byte)0xcb, (byte)0xbc, (byte)0xab, (byte)0x36, (byte)0xb8, (byte)0x57, (byte)0xb9, (byte)0x79, (byte)0xaf, (byte)0xbb, (byte)0xfa, (byte)0x3a, (byte)0xea, (byte)0xf9, (byte)0x57, (byte)0x4c, (byte)0x0b, (byte)0x3d, (byte)0x82, (byte)0x67, (byte)0x51, (byte)0x59, (byte)0x57, (byte)0xba, (byte)0xd4, (byte)0x59, (byte)0x4f, (byte)0xe6, (byte)0x07, (byte)0x10, (byte)0x81, (byte)0x80, (byte)0xb4, (byte)0x16, (byte)0x71, (byte)0x23, (byte)0xe8, (byte)0x4c, (byte)0x16, (byte)0x13, (byte)0xb7, (byte)0xcf, (byte)0x09, (byte)0x8c, (byte)0xc8, (byte)0xa6, (byte)0xe1, (byte)0x3c, (byte)0x7a, (byte)0x8b, (byte)0x54, (byte)0x7c, (byte)0x8d, (byte)0xe0, (byte)0xa3, (byte)0xae, (byte)0x1e, (byte)0x2b, (byte)0xa6, (byte)0x75, (byte)0x91, (byte)0x6e, (byte)0xa3, (byte)0x0b, (byte)0xfa, (byte)0x21, (byte)0x35, (byte)0x62, (byte)0xfb, (byte)0x62, (byte)0x7a, (byte)0x01, (byte)0x24, (byte)0xcc, (byte)0xa4, (byte)0xf1, (byte)0xbe, (byte)0xa8, (byte)0x90, (byte)0x89, (byte)0xa8, (byte)0x83, (byte)0xdf, (byte)0x5a, (byte)0xe5, (byte)0x9f, (byte)0x06, (byte)0x92, (byte)0x66, (byte)0x5e, (byte)0x80, (byte)0x7b, (byte)0x55, (byte)0x64, (byte)0x01, (byte)0x4c, (byte)0x3b, (byte)0xfe, (byte)0x49, (byte)0x2a }; DSACryptoSystem system = new DSACryptoSystem( p, q, g );

(byte)0xd7, (byte)0x6f, (byte)0x99, (byte)0xe8, (byte)0x4f, (byte)0xc6, (byte)0xc6, (byte)0xfb, (byte)0xc3, (byte)0x16, (byte)0xae, (byte)0xf2, (byte)0x48,

(byte)0x23, (byte)0x82, (byte)0x58,

(byte)0x9b, (byte)0x5c, (byte)0x94, (byte)0x82, (byte)0x07, (byte)0x8e, (byte)0x71, (byte)0x49, (byte)0x28, (byte)0x32, (byte)0x16, (byte)0x28, (byte)0xb3, (byte)0x7f, (byte)0xf1, (byte)0x3b, (byte)0x51, (byte)0xe1, (byte)0x8b, (byte)0x25, (byte)0xcf,

Keys Asymmetric key cryptography uses two keys, a public key to encrypt and verify input, and a private key to decrypt data. Symmetric key cryptography uses a single key for both encryption and decryption. In the RIM速 Cryptographic API, you create keys using subinterfaces of the net.rim.device.api.crypto.Key interface. Following are some of the subinterfaces of the Key interface:

13


Development Guide

• • •

Elements of a cryptographic implementation

PublicKey: Public keys are used in asymmetric key cryptography. The public key is typically used in operations

such as encryption and verification. You can divulge the contents of this key to anyone. PrivateKey: Private keys are used in asymmetric key cryptography. The private key is typically used in operations such as decryption and signing. You must protect the contents of this key. SymmetricKey: Symmetric keys are used in symmetric key cryptography. The symmetric key is used for both encryption and decryption. You must protect the contents of this key.

Code sample: Creating a symmetric key The following code sample shows how to create a symmetric DES key object containing a randomly generated DES key. The DESKey class is in the SymmetricKey interface. DESKey unknownKey = new DESKey();

Code sample: Creating a public key and private key The following code sample creates a pair of keys: a public key and private key. It uses the default value for the public exponent, e. The value chosen for e is a compromise between efficiency and security. // Create an RSA key pair. RSAKeyPair rsaKeyPair = new RSAKeyPair( rsaCryptoSystem ); // Get the private and public keys that were just created. RSAPublicKey rsaPublicKey = rsaKeyPair.getRSAPublicKey(); RSAPrivateKey rsaPrivateKey = rsaKeyPair.getRSAPrivateKey();

The following example creates assymetric keys, but you can specify the values for e and n. // Create an RSA key pair with a modulus 1024 bits in length and values e and n. RSACryptoSystem rsaCryptoSystem = new RSACryptoSystem(1024); RSAPublicKey rsaPublicKey = new RSAPublicKey( rsaCryptoSystem, e, n );

Key stores A key store is a collection of KeyStoreData records. A KeyStoreData record contains data such as public keys, private keys, symmetric keys, certificates, an identifier for the KeyStoreData record, and other items. Each BlackBerry® device has a key store that is preloaded with root certificates for various certificate authorities. These trusted root certificates form the basis for all subsequent chains of trust. BlackBerry device users can customize their key store. For example, they can decide to be prompted for their password every time the key store is accessed. The functionality for creating and managing key stores, including some predefined key stores, is provided in the net.rim.device.api.crypto.keystore.KeyStore package. The KeyStore package provides a key store model that allows you to manage the distribution and access of keys both on the desktop and on the device. The KeyStore package contains the following classes:

14


Development Guide

• • •

Elements of a cryptographic implementation

The RIMKeyStore class is provided as a default implementation. It stores keys only until the device is restarted, so it cannot be used to store permanent keys. An example of its use is to store smartcard keys: in that case, keys are always stored on the smartcard so the key store does not need to be persisted. The following key stores are variants of this class: • The PersistableRIMKeyStore class is useful for keys that need to persist across device restarts. • The SyncableRIMKeyStore class is useful for keys that need to persist across restarts, and also allows the device user to synchronize the keys with the Synchronize Certificates tool in the BlackBerry Desktop Manager (for BlackBerry® Desktop Manager 5 and earlier). The TrustedKeyStore class provides highly secure storage for certificates and keys that have a high security level. Only signed applications can add keys to the TrustedKeyStore. The DeviceKeyStore provides functionality to synchronize with desktop software. The CombinedKeyStore allows you to combine several key stores into what looks like one key store.

Code sample: Creating a key store The following code sample creates a new key store called "My Keystore" and a key pair called keyPair. An associatedData object is created to help with later retrieval from the key store. RIMKeyStore keyStore = new RIMKeyStore("My Keystore"); DSAKeyPair keyPair = new DSAKeyPair( new DSACryptoSystem() ); AssociatedData associatedData = new AssociatedData( AssociatedData.EMAIL, "user01@example.com".getBytes() );

The next code sample adds keyPair to the key store. The set method adds a KeyStoreData object that contains information that will be associated with the array of aliases contained inside the class. The keyStore.set method is called with eight parameters: • • • • • • • •

The AssociatedData object (an associated Data array containing the aliases to index this record in the key store). A label ("Crypto Signing Key") that identifies the key. The private key. The private key encoding algorithm. In this case it is set to null and so the default format, PKCS8, is used. A low security level for the key, which means that when someone tries to access the private key, they will not be prompted for a password. The public key. The KeyUsage settings (in this case, these specify that the public key is for email protection and key agreement). The ticket, which in this case is null.

A try/catch block is used to capture any exceptions that might be thrown. try {

}

keyStore.set( new AssociatedData[] {associatedData}, "Crypto Signing Key", keyPair.getDSAPrivateKey(), null, KeyStore.SECURITY_LEVEL_LOW, keyPair.getDSAPublicKey(), KeyUsage.EMAIL_PROTECTION | KeyUsage.KEY_AGREEMENT, null );

15


Development Guide

Elements of a cryptographic implementation

catch( NoSuchAlgorithmException e ) { } catch( KeyStoreCancelException e ) { return; } catch( InvalidKeyEncodingException e ) { } catch( CryptoTokenException e ) { } catch( InvalidKeyException e ) { } catch( CryptoUnsupportedOperationException e ) { }

The following code sample retrieves the key called keyPair from the key store. First, the code creates an index. You only add an index to a key store once. Earlier in this example, an AssociatedData object was associated with the email address user01@example.com, so the new index is of type AssociatedDataKeyStoreIndex. The index is added to the key store. Next, the KeyStore.elements method is used to retrieve the key. The elements method uses the index (index.getID) and the bytes associated with the AssociatedData object ("user01@example.com".getBytes). The elements method returns an enumeration of all KeyStoreData objects that match the search criteria. A while loop is used to loop through the enumeration, looking for the label "Crypto Signing Key". (In a real world application, two keys might have the same AssociatedData information and the same label, so you should prompt the user to determine which key should be retrieved.) The getPrivateKey method is called to retrieve the key. The parameter null is used because there is no ticket. AssociatedDataKeyStoreIndex index = new AssociatedDataKeyStoreIndex( AssociatedData.EMAIL ); keyStore.addIndex( index ); Enumeration enum = keyStore.elements( index.getID(), "user01@example.com".getBytes() ); KeyStoreData data = null; PrivateKey privateKey = null; while( enum.hasMoreElements() ) { data = (KeyStoreData)enum.nextElement(); if( "Crypto Signing Key".equals( data.getLabel() ) ) { try { privateKey = data.getPrivateKey( null ); 16


Elements of a cryptographic implementation

Development Guide

}

}

} catch( { } catch( { } catch( { } catch( { } catch( { } catch( { }

NoSuchAlgorithmException e ) KeyStoreCancelException e ) InvalidKeyEncodingException e ) CryptoTokenException e ) CryptoUnsupportedOperationException e ) KeyStoreDecodeException e )

The next code sample adds a certificate to the key store and then verifies that the certificate exists. This code sample assumes that you have a WTLS certificate. The first parameter for the keyStore.set method is an array containing the aliases needed to index this record in the key store. When you provide this information you are able to query the certificate with the alias that you specify, as shown in the previous example. However in this example the parameter is set to null, the certificate is put in the key store, and then keyStore.isMember() is called to check the membership. The isMember method creates an index for the certificate. byte[] certData = { /* Certificate data as a byte array */ }; try { //Assuming that you have a WTLS certificate, create a WTLS certificate. WTLSCertificate cert = WTLSCertificate( certData ); keyStore.set(null, "my certificate", cert, new CertificateStatus(), null); ... } catch ( CertificateParsingException e ) { } catch ( NoSuchAlgorithmException e ) { } catch ( InvalidKeyEncodingException e ) { } catch ( InvalidKeyException e ) { } catch ( CryptoTokenException e ) { }

17


Development Guide

Elements of a cryptographic implementation

catch ( CryptoUnsupportedOperationException e ) { } catch ( KeyStorePasswordException e ) { } //Verify that the certificate is in the key store. WTLSCertificate myNewCert = WTLSCertificate( certData ); if ( keyStore.isMember(myNewCert) ) { System.out.println("Certificate provided is in the key store"); } else { System.out.println("Certificate provided is not in the key store"); }

Key agreement Key agreement provides a way for two independent parties to establish a highly secure channel over an insecure network. Key agreement protocols generally use both parties' public and private keys, along with any algorithmspecific parameters, to create a secret piece of data. The secret data is created independently by both parties through the use of the publicly shared information and then is used as a session key for highly secure communication. The secret key is derived from public data but is not sent out over the network. The RIM® Cryptographic API supports the following key agreement schemes: • • • •

DHKeyAgreement: Diffie-Hellman Key Agreement ECDHKeyAgreement: Elliptic Curve Diffie-Hellman Key Agreement ECMQVKeyAgreement: Elliptic Curve Menezes, Qu, and Vanstone Key Agreement KEAKeyAgreement: Key Exchange Algorithm

ECDHKeyAgreement is a common key agreement scheme. It requires the use of a public key and a private key. Each party in a highly secure communication uses their own private key and the public key of the other party. When each party uses the key agreement algorithm, the same secret data is created. Code sample: Implementing ECDHKeyAgreement The following code sample illustrates ECDHKeyAgreement. It assumes that sendPublicKey() and receivePublicKey() exist and enable the exchange of keys between the two clients. When a message is sent by one client, it is received by the other. Operations occur locally, and the details of the key exchange are not displayed. In your application, the public keys are exchanged over the network, and the private keys must be protected by each party. Identical shared secrets are created by each client (here called client1Secret and client2Secret). This example generates the local secret on the local client. It creates a local shared secret that is identical to the local client's secret. It generates the secret key. It creates a local shared secret that is identical to the secret just generated.

18


Development Guide

Elements of a cryptographic implementation

//Generate the local secret on the local client. public void generateLocalSecret() { // Create an EC crypto system for key creation ECCryptoSystem cryptoSystem = new ECCryptoSystem(); // Create the first party's public and private keys ECKeyPair client1KeyPair = new ECKeyPair( cryptoSystem ); // Create a local shared secret that is identical to the local client's secret. // Send the local client public key (client1) to the remote user (client2). sendPublicKey( client1KeyPair.getECPublicKey() ); ECPublicKey client2PublicKey = receivePublicKey(); // Generate the shared secret for this client. byte[] client1Secret = ECDHKeyAgreement.generateSharedSecret( client1KeyPair.getECPrivateKey(), client2PublicKey ); // Create a shared secret key based on the shared secret DESKey secretKey = new DESKey( client1Secret ); } // Generate the secret key, a shared key for communication between clients. public void generateRemoteSecret() { // Create an EC crypto system for key creation ECCryptoSystem cryptoSystem = new ECCryptoSystem(); // Create the remote public and private keys ECKeyPair client2KeyPair = new ECKeyPair( cryptoSystem ); // Create a local shared secret. It is identical to the secret just generated. // Send and receive the keys. sendPublicKey( client2KeyPair.getECPublicKey() ); ECPublicKey client1PublicKey = receivePublicKey(); // Generate the secret data based on the client1 public // key and client2 private key. byte[] client2Secret = ECDHKeyAgreement.generateSharedSecret( client2KeyPair.getECPrivateKey(), client1PublicKey );

}

// Create a shared secret key based on this secret data. DESKey secretKey = new DESKey( client2Secret );

Code sample: Implementing ECMQVKeyAgreement The following code sample illustrates ECMQVKeyAgreement. The code is similar to the ECDHKeyAgreement example, but this scheme makes use of an additional set of ephemeral (temporary) keys for added security. Ephemeral keys are keys that are stored and used for only a limited amount of time. This way, if a key is compromised, a new key is created periodically and the compromised key is no longer used. The example assumes that sendPublicKey() and receivePublicKey() are invoked and enable the exchange of keys between the two clients. If something is sent by one client, it is received by the other. 19


Development Guide

Elements of a cryptographic implementation

This example uses five keys: the local public ephemeral key, the local private ephemeral key, the local private static key, the remote public static key, and the remote public ephemeral key. // Create a static (regular) key pair and an ephemeral key pair. public void generateLocalSecret() { // Create an EC crypto system for key creation. ECCryptoSystem cryptoSystem = new ECCryptoSystem(); // Create the first client's static and ephemeral key pairs. ECKeyPair client1StaticPair = new ECKeyPair( cryptoSystem ); ECKeyPair client1EphemeralPair = new ECKeyPair( cryptoSystem ); // Send and receive the newly created public and public ephemeral key pair // using a predetermined key exchange protocol. // Send and receive public keys. sendPublicKey( client1StaticPair.getECPublicKey() ); sendPublicKey( client1EphemeralPair.getECPublicKey() ); ECPublicKey client2StaticKey = receivePublicKey(); ECPublicKey client2EphemeralKey = receivePublicKey(); // Generate the shared secret for this client. This // is identical to that generated by client2. byte[] client1Secret = ECMQVKeyAgreement.generateSharedSecret( client1StaticPair.getECPrivateKey(), client1EphemeralPair, client2StaticKey, client2EphemeralKey ); // Create a shared secret key based on this secret data. DESKey secretKey = new DESKey( client1Secret ); } // Create a shared secret and use it to create a shared secret key. public void generateRemoteSecret() { // Create an EC crypto system for key creation. ECCryptoSystem cryptoSystem = new ECCryptoSystem(); // Create the second client's static and ephemeral key pairs. ECKeyPair client2StaticPair = new ECKeyPair( cryptoSystem ); ECKeyPair client2EphemeralPair = new ECKeyPair( cryptoSystem ); // Send and receive the keys. sendPublicKey( client2StaticPair.getECPublicKey() ); sendPublicKey( client2EphemeralPair.getECPublicKey() ); ECPublicKey client1StaticKey = receivePublicKey(); ECPublicKey client1EphemeralKey = receivePublicKey(); // Generate the shared secret for this client. byte[] client2Secret = ECMQVKeyAgreement.generateSharedSecret( client2StaticPair.getECPrivateKey(), client2EphemeralPair, client1StaticKey, client1EphemeralKey );

}

20

// Create a shared secret key based on this secret data. DESKey secretKey = new DESKey( client2Secret );


Development Guide

Elements of a cryptographic implementation

Key encoders and decoders Encoded keys can be transmitted as a complete package (including any required system parameters) so that it is clear to the recipient how to decode the message. Encoding and decoding of keys is done with the net.rim.device.api.crypto.encoder package. Code sample: Encoding and decoding RSA private keys The following code sample demonstrates how to encode and decode RSA private keys using PKCS8, which is a common private key encoding scheme. It starts by creating a new RSACryptoSystem object for key generation. It creates the key pair to hold the RSA keys. It encodes the key using the PrivateKeyEncoder class. // Create a new RSA cryptosystem for key generation. RSACryptoSystem cryptoSystem = new RSACryptoSystem(); // The key pair can hold the RSA keys. RSAKeyPair keyPair = new RSAKeyPair( cryptoSystem); RSAPrivateKey privateKey = keyPair.getRSAPrivateKey(); // Encode the key using the PrivateKeyEncoder class. EncodedKey encodedKey = PrivateKeyEncoder.encode( privateKey, "PKCS8" ); byte[] encodedKeyData = encodedKey.getEncodedKey();

The following example shows how to decode the encoded key. RSAPrivateKey decodedKey = ( RSAPrivateKey ) PrivateKeyDecoder.decode( encodedKeyData, "PKCS8" );

Code sample: Encoding and decoding elliptic curve public keys The following example shows how to encode an elliptic curve public key with X.509. // Create a new EC cryptosystem for key generation. ECCryptoSystem cryptoSystem = new ECCryptoSystem(); // The key pair can hold the EC keys. ECKeyPair keyPair = new ECKeyPair( cryptoSystem); ECPublicKey publicKey = keyPair.getECPublicKey(); // Encode the key using the PublicKeyEncoder class. EncodedKey encodedKey = PublicKeyEncoder.encode( publicKey, "X509" ); byte[] encodedKeyData = encodedKey.getEncodedKey();

The following example shows how to decode an elliptic curve public key with X.509. ECPublicKey decodedKey = ( ECPublicKey ) PublicKeyDecoder.decode( encodedKeyData, "X509" );

21


Development Guide

Elements of a cryptographic implementation

Certificates A certificate is an electronic document that is used to identify an individual, company, or other entity, and to associate that entity with a public key. A certificate uses a digital signature to bind the public key to an identity. When an entity wants to use a certificate, it can verify the signature to ensure that the key it provides is legitimate. Certificate authorities are organizations that issue certificates and validate identities. Certificates can be self-signed, but they are usually signed by a certificate authority. You can manage certificates with the net.rim.device.api.crypto.certificate package. Each certificate on a BlackBerry速 device has a certificate status. The certificate status indicates if the certificate is good, revoked, or unknown. Status values are managed by the net.rim.device.api.crypto.keystore.CertificateStatusManager class.

Code sample: Creating a certificate If you have the encoding for a certificate, you can use code such as the following to create an X.509 certificate. Replace the text <encoding> with an appropriate value: byte[] encoding = encoding; X509Certificate certificate = new X509Certificate( <encoding> );

You can also use a certificate factory to create a certificate from its encoding. The certificate factory can read X.509 and WTLS certificates. For example: InputStream encoding = encoding; Certificate certificate = CertificateFactory.getInstance( "X509",encoding );

To create a new X.509 certificate, invoke X509Certificate.createCertificate(). The following code sample creates a root certificate (a certificate for which the issuer and subject are the same). RSAKeyPair keyPair = new RSAKeyPair( new RSACryptoSystem() ); X509DistinguishedName name = new X509DistinguishedName( "O=Research In Motion,C=Canada" ); long keyUsage = KeyUsage.KEY_CERT_SIGN; byte[] serialNumber = new byte[] { (byte)0x01 }; long validNotBefore = System.currentTimeMillis(); // Add a year of milliseconds. long validNotAfter = validNotBefore + 1000*60*60*24*365; X509Certificate root = X509Certificate.createX509Certificate( keyPair, name, keyUsage, serialNumber, null, validNotBefore, validNotAfter );

Certificate chains The Certificate interface also supports certificate chains. A certificate chain is a set of certificates that can provide greater security than a single certificate. There are several ways to create a certificate chain. If all the certificates are individual objects, then you can put them in an array. 22


Development Guide

Elements of a cryptographic implementation

Certificate endEntity = ... Certificate firstCA = ... Certificate rootCA = ... Certificate[] chain = new Certificate[] { endEntity, firstCA, rootCA };

Alternatively, you can use the buildCertificateChain method, which is found in the CertificateUtilities class. The following example assumes that one of the certificate authorities is in an array of certificates, and that the other certificate authority is in a key store. Certificate endEntity = ... Certificate[] pool = ... ( contains firstCA ) KeyStore keyStore = ... ( contains rootCA ) Certificate[] chain = CertificateUtilities.buildCertChain( endEntity, pool, keyStore );

You can use the following code to determine if the chain is trusted. KeyStore trustedKeyStore = TrustedKeyStore.getInstance(); boolean trusted = CertificateUtilities.isCertificateChainTrusted( chain, trustedKeyStore )

Alternatively, you can attempt to create a trusted certificate chain directly. For example: Certificate endEntity = ... Certificate[] pool = ... ( contains firstCA ) KeyStore keyStore = ... ( contains rootCA ) KeyStore trustedKeyStore = TrustedKeyStore.getInstance(); Certificate[] trustedChain = CertificateUtilities.buildTrustedCertChain( endEntity, pool,keyStore, trustedKeyStore );

Signatures Signatures are typically used only with public/private key schemes. Signatures provide a way for verifying data origin authentication and identity authentication. If we can assume that an entity is the only one that knows the private key, then the private key can be used to prove to others that only that entity could have signed the information. A signature can include one or more mathematical values, depending on the signing algorithm used, and so requires an encoding scheme. The RIM速 Cryptographic API uses the net.rim.device.api.crypto.SignatureSigner interface for all signing functions. A SignatureSigner combines the message to be signed and the signer's private key to yield the mathematical values that make up a signature. A SignatureEncoder then encodes these mathematical values into a byte array for transmission or storage.

RSA signature signers RSA signature signing uses the PKCS1SignatureSigner class, the PSSSignatureSigner class, or the X931SignatureSigner class. For RSA signatures, messages must be encoded by a formatter. Formatters are used in a similar way to the classes that implement the SignatureSigner interface.

23


Development Guide

Elements of a cryptographic implementation

Code sample The following code sample creates the message to be signed. It creates the RSA key pair, the digest, and the salt value. (The salt value is random data that is appended to the key to make the key more difficult to break.) The code sample creates an RSASignatureSigner and passes in a digest algorithm and PSS signature formatter. The example could pass the signature signer into a stream, but instead it uses the signature signer directly. Finally, it encodes the signature using X.509. // Create the message to be signed. String message = "Hello World."; // Create the necessary RSA key pair for signing and verifying. RSACryptoSystem cryptoSystem = new RSACryptoSystem(); RSAKeyPair keyPair = new RSAKeyPair( cryptoSystem ); // Create the digest and the salt value. SHA1Digest digest = new SHA1Digest(); byte[] salt = RandomSource.getBytes( digest.getDigestLength() ); // Create the RSASignatureSigner passing in a digest algorithm // and PSS signature formatter. PSSSignatureSigner signer = new PSSSignatureSigner( keyPair.getRSAPrivateKey(), digest, salt ); // For this example, simply use the signature signer directly, // even though you could pass it into a stream as before. signer.update( message.getBytes() ); // Encode the signature using X509. EncodedSignature encSignature = SignatureEncoder.encode( signer, "X509" );

The following example shows how to decode and verify the signature (assuming the encoded signature and RSA key pair exist). It starts by decoding the encoded signature. It gives the verifier the message string. It checks that the signature verifies, and then prints it. // Decode the encoded signature. DecodedSignature decodedSignature = SignatureDecoder.decode( encSignature.getEncodedSignature(), "X509" ); SignatureVerifier verifier = decodedSignature.getVerifier( keyPair.getPublicKey() ); // Give the verifier the message string. verifier.update( message.getBytes() ); // Check that the signature verifies, and then print it. if( verifier.verify() == true ) { System.out.println( "Signature verifies." ); } else { System.out.println( "Signature does not verify." ); }

24


Development Guide

Elements of a cryptographic implementation

Implement signatures The following procedure shows you how to use signatures with the DSA algorithm. 1.

Create and use a signature signer, and create a key pair. DSACryptoSystem cryptoSystem = new DSACryptoSystem(); DSAKeyPair keyPair = new DSAKeyPair( cryptoSystem ); DSAPrivateKey privateKey = keyPair.getDSAPrivateKey();

2.

Specify the message to be signed. String message = new String("Jeans are on sale");

3.

Create the signer. SignatureSigner signer = new DSASignatureSigner( privateKey ); signer.update( message.getBytes() );

4.

Create an X.509 signature. EncodedSignature signature = SignatureEncoder.encode( signer, "X509" );

5.

Get the data of the signature. byte[] signatureData = signature.getEncodedSignature(); // bytes String encodingAlgorithm = signature.getEncodingAlgorithm(); // "X509"

6.

Verify the signature. a. Retrieve the public key. DSAPublicKey publicKey = keyPair.getDSAPublicKey();

b.

Decode the signature. DecodedSignature decodedSignature = SignatureDecoder.decode( signatureData, "X509" );

c.

Get the signature verifier. SignatureVerifier verifier = decodedSignature.getVerifier(publicKey);

d.

Enter the message to be verified. verifier.update( message.getBytes() );

e.

Verify the signature. boolean verified = verifier.verify();

f.

Print out the result. System.out.println("Signature was verified " + verified + ".");

25


Development Guide

Elements of a cryptographic implementation

Signature streams You can use the SignatureSigner class and SignatureVerifier class with a signature stream. The signature stream ( net.rim.device.api.crypto.SignatureSignerOutputStream ) allows you to write data to the stream. When you close the stream, the signature is appended to the stream. Code sample The following example shows how to use the signature stream. It generates a key pair, and then gets the private key. It creates the signature signer. It creates the output streams and then it writes out the data to be signed and signs it. It creates byte arrays for the signature. Finally, it closes the output streams and gets the stream contents. // Generate a key pair that can be used for signing (and // eventually for verifying). ECKeyPair keyPair = new ECKeyPair( new ECCryptoSystem() ); // Get the private key for use with the signature signer. ECPrivateKey privateKey = keyPair.getECPrivateKey(); // Create the signature signer. This example uses ECDSA. ECDSASignatureSigner signer = new ECDSASignatureSigner( privateKey, new MD5Digest() ); // Create the output stream for use as the underlying stream. // This example uses a byte array output stream. ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); // Create the SignatureSignerOutputStream SignatureSignerOutputStream signerStream = new SignatureSignerOutputStream( signer, outputStream ); // Write out the data to be signed. String info = new String("Hello World"); // Sign this information. signerStream.write( info.getBytes() ); // Declare the byte arrays for r and s, which represent the signature. byte[] r = new byte[signer.getRLength()]; byte[] s = new byte[signer.getSLength()]; signer.sign( r, 0, s, 0 ); // Close the output stream (upper layer). signerStream.close(); // Get the stream contents for later. byte[] contents = outputStream.toByteArray(); // Close the underlying output stream. outputStream.close();

26


Development Guide

Elements of a cryptographic implementation

You can use the SignatureVerifierInputStream class to verify the signature that you sent to output in the previous section. The following code sample shows how to verify the signature that was generated using a signature output stream. It gets the public key from the last example. It sets up the signature verifier and the input stream. It reads the data from the stream and checks to see that the signature is correct. Finally, it prints the result. // Get the public key from the key pair in the last example. ECPublicKey publicKey = keyPair.getECPublicKey(); // Set up the ECDSASignatureVerifier. ECDSASignatureVerifier verifier = new ECDSASignatureVerifier( publicKey, new MD5Digest(), r, 0, s, 0 ); // Set up the input stream (using contents from above). ByteArrayInputStream inputStream = new ByteArrayInputStream( contents ); // Use this to set up the SignatureVerifierInputStream SignatureVerifierInputStream verifierStream = new SignatureVerifierInputStream( verifier, inputStream ); // Read the data from the stream. byte[] data = new byte[verifierStream.available()]; verifierStream.read( data ); // Use the verifier to check if the signature is correct. boolean result = verifier.verify(); // Print out the result. System.out.println("Signature verification was " + result + ".");

Digests Digests are hash functions that are used to convert input data to a fixed-size hash. A digest can be used as a secure hash function to reduce a large amount of data into a small, unique identifier. The functionality for working with digests is provided in the net.rim.device.api.crypto.Digest interface. The RIM® Cryptographic API supports the following hash algorithms: • • • • • •

MD2 Digest MD4 Digest MD5 Digest SHA-1 Digest SHA-224 Digest, SHA-256 Digest, SHA-384 Digest, SHA-512 Digest RIPEMD-128 Digest, RIPEMD-160 Digest

In North America, the most commonly used hash functions are SHA-1 and SHA-2. The digest length of SHA-1 is 160 bits. SHA-2 has variable digest bit lengths of 256 bits, 384 bits, and 512 bits. These lengths match the security level of the AES candidate. The RIM Cryptographic API supports SHA-1 (in the class SHA1Digest) and SHA-2 (in the classes SHA224Digest, SHA256Digest, SHA384Digest, and SHA512Digest).

27


Development Guide

Elements of a cryptographic implementation

Code sample: Using digests The following code sample illustrates the use of SHA-1 and SHA-2, but all the algorithms are used in the same way. This example shows how to instantiate the different types of SHA. It uses the SHA-1 algorithm to show how the functions work. It updates the contents of the hash function. Finally, it gets the hash value. // Instantiate any of the different types of SHA. SHA1Digest digest160 = new SHA1Digest(); SHA256Digest digest256 = new SHA256Digest(); SHA384Digest digest384 = new SHA384Digest(); SHA512Digest digest512 = new SHA512Digest(); // Use the SHA-1 algorithm. byte[] data = new byte[128]; RandomSource.getBytes( data ); // Update the contents of the hash function. (This is the data that gets hashed.) digest160.update( data ); digest160.update( data, 10, 15 ); // Get the hash value. byte[] digestValue = digest160.getDigest();

You can retrieve the hash value using the following code. byte[] hashValue = new byte[digest160.getDigestLength()]; digest160.getDigest( hashValue, 0 );

The following code sample shows how to create an instance of a DigestOutputStream and then pass an instance of a digest algorithm to the constructor. You can use the same method for DigestInputStream, except that the data read from the input stream (passed to DigestInputStream) is passed through the digest algorithm. This example creates a SHA digest of the default length. It then creates a new DigestOutputStream object. The example passes in a null value for the OutputStream parameter so that this stream does not pass the data written to it into another output stream. The example then invokes the write() method and finally gets the hash value. // Create a SHA digest with the default length (160-bit). SHA1Digest digest = new SHA1Digest(); // Create a new DigestOutputStream. DigestOutputStream out = new DigestOutputStream( digest, null ); // Invoke write to update the digest (assuming data exists and contains the message). out.write( data ); // Get the hash value. byte[] digestValue = digest.getDigest();

MACs A MAC is used to verify that the information passed through the MAC has not been changed or modified. It is essentially a keyed hash function. A key is required for the creation and verification of the hash value. 28


Development Guide

Encrypting and decrypting data

MAC functionality is based on the Digest interface and is provided in the net.rim.device.api.crypto.MAC interface. A MAC can be used with a digest to ensure that data is not modified without permission. The RIM® Cryptographic API supports the following MACs: • • •

CBC MAC HMAC Null MAC

The HMAC class implements the MAC interface and allows for easy use of keyed hash functions. The code required to use an HMAC is similar to that for digests, except that you require a key to generate the hash. Code sample The following example creates an HMAC key, which can be an array of data of any length. In most cases, a length equal to the bit size of the digest is recommended. Random data is used in this example. byte[] keyData = new byte[ 20 ]; RandomSource.getBytes( keyData ); // Create the key. HMACKey key = new HMACKey( keyData ); // Create the SHA digest. SHA1Digest digest = new SHA1Digest(); // Create the HMAC, passing in the key and the SHA digest. // Any instance of a digest can be used here. HMAC hMac = new HMAC( key, digest ); // The HMAC can be updated much like a digest. hMac.update( data ); hMac.update( data, 10, 15 ); // Now get the MAC value. byte[] macValue = hMac.getMAC();

Encrypting and decrypting data Factory classes are the standard way to encrypt and decrypt data. The factory classes are net.rim.device.api.crypto.EncryptorFactory and net.rim.device.api.crypto.DecryptorFactory . Engine classes are available in case you need to directly access algorithms. All the engine classes derive from the net.rim.device.api.crypto.BlockEncryptorEngine interface.

Encrypting and decrypting data using factories In most cases, encryption and decryption is done using factories. The two factory classes are EncryptorFactory and DecryptorFactory .

29


Development Guide

Encrypting and decrypting data

Code sample: Encrypting data using a factory The first two inputs of the EncryptorFactory class are the output stream used to collect the ciphertext and the key used to encrypt the data. The key, in this case a DES key, is created as shown in the following code sample. DESKey key = new DESKey();

Note: The details of the generation and distribution of keys are not specified in this example. In this example, the same instance of the key is used to encrypt and decrypt the message. In a real world scenario, the protocol would first be agreed upon, and then the keys would be created and distributed. In the following code sample, EncryptorFactory.getEncryptorOutputStream() is invoked and the resulting output stream is stored in the encryptor variable. The encryptor variable is created in a try clause to catch and display any exceptions that might occur. try { //Create the EncryptorFactory. EncryptorOutputStream encryptor = EncryptorFactory.getEncryptorOutputStream( key.getData(), stream, encryptionType, IV ); encryptor.write( message.getBytes() ); encryptor.close(); cipherText = stream.toByteArray();

}

//Output the messages to the console. System.out.println("Original Message: " + message); System.out.println("Ciphertext: " + cipherText);

Code sample: Decrypting data using a factory The decryption process is similar to the encryption process. In the following code sample, the input stream is created to hold the ciphertext from the encryption process. Like the key, the ciphertext was previously transmitted to the receiver by the sender. The getDecryptorInputStream method of the DecryptorFactory class is called and the resulting object is created and stored in a variable of type DecryptorInputStream called decryptor. Because the data may contain extra padding, a for loop is used to extract the data from the output stream. The following example uses a loop that reads from the input stream and exits when it reads the first empty block of data. The decryption routine occurs within a try block. The arrays are compared to determine that the decryption was successful, and a message is displayed in the console. If the decryption fails, exception error messages appear in the console. ByteArrayInputStream input = new ByteArrayInputStream( stream.toByteArray() ) DecryptorInputStream decryptor = DecryptorFactory.getDecryptorInputStream(symmetricKey,input); byte[] decrypted = new byte[0]; byte[] temp = new byte[10]; for( ;; ) { 30


Encrypting and decrypting data

Development Guide

int read = decryptor.read( temp, 0, 10 ); if( read < 0 ) { // We are at the end of the stream. break; } // Copy. net.rim.vm.Array.resize( decrypted, read + decrypted.length ); System.arraycopy( temp, 0, decrypted, decrypted.length - read, read ); } if( Arrays.equals( message.getBytes(), decrypted ) ) { System.out.println("Encryption/Decryption Passed."); } else { System.out.println("Encryption/Decryption Failed."); } }

Block algorithms A block algorithm operates on fixed-length groups of bits called blocks, and applies the same transformation to each one. The block of ciphertext that a block algorithm produces is the same length as the plaintext it encrypts. An initialization vector is a string of random information that is used with some block cipher modes to ensure that a unique ciphertext message appears each time a plaintext message is encrypted.

Block ciphers A block cipher is a symmetric key cipher that operates on fixed-length groups of bits called blocks. A mode of operation describes the process of encypting a block cipher under a single key. The RIM® Cryptographic API supports the following modes of operation for block encryption: • • • • •

ECB (default for all engine classes) CBC CFB OFB CTR

You can use CFB, OFB, or CTR modes to convert a block algorithm to a stream algorithm. All encryption engines operate in ECB mode, which means that they take in one block at a time and return one block at a time. There is no chaining or dependence on other blocks for the encryption of the ciphertext. ECB is not the most highly secure mode for encryption. If you require higher security, consider using CBC or one of the other supported modes.

Block formatters and unformatters Block formatting is done by padding and encoding blocks of data. To help you format and unformat blocks, the RIM® Cryptographic API provides the net.rim.device.api.crypto.BlockFormatterEngine interface and the net.rim.device.api.crypto.BlockUnformatterEngine interface. These interfaces include the algorithms PKCS5, OAEP, and PKCS1. PKCS5 provides padding, and OAEP and PKCS1 provide block encoding. 31


Encrypting and decrypting data

Development Guide

A BlockFormatterEngine uses a BlockEncryptorEngine to encrypt the data after the appropriate encoding or padding has been performed. BlockEncryptor uses both a BlockEncryptorEngine and a BlockFormatterEngine, so that you can use either of them with the stream-based approach. The following code samples demonstrate two approaches to using block formatters. Code sample: Using block formatters The following code sample uses the PKCS5FormatterEngine. It specifies input and output, and then creates a random new DES key. It creates the engine and the block encoder engine. It encodes and encrypts the data using PKCS5. The last Boolean argument indicates whether or not this is the last block. // Input (less than 8 bytes). byte[] input = { 0x00, 0x00, 0x00, 0x00, 0x00 }; // Output. byte[] output = new byte[ 8 ]; // Create a random new DES key. DESKey key = new DESKey(); // Create the engine. DESEncryptorEngine desEngine = new DESEncryptorEngine( key ); // Create the block encoder engine. PKCS5FormatterEngine formatter = new PKCS5FormatterEngine( desEngine ); // Encode and encrypt the information using PKCS5. // The last boolean argument indicates whether this is the last block. formatter.formatAndEncrypt( input, 0, input.length, output, 0, true ); System.out.println("Ciphertext = " + new String( output ) + ".")

Code sample: Using a formatter to encrypt a stream of data The following code sample uses the formatter to encrypt a stream of data. This example uses DES in CBC mode with PKCS5 padding. The code sample specifies input and then creates a new DES key with the given data. It creates the DES engine, CBC engine, and PKCS5 Encoder engine. Using the input byte array, it creates an output stream. Using the CBCEncryptorEngine, it creates the encryptor. It writes the data to encrypt. Finally, it closes the output stream and grabs the bytes. Note: It is important to call close() with padding encoders, as it ensures that the last block is encoded properly. // Input. byte[] input

= { (byte)'H', (byte)'e', (byte)'l', (byte)'l', (byte)'o', (byte)',', (byte)' ', (byte)'w',(byte)'o', (byte)'r', (byte)'l', (byte)'d', byte)'!', (byte)'!' };

// Initialization vector. byte[] iv = { (byte)0xFF, (byte)0xFE, (byte)0xFD, (byte)0xFC,(byte)0xFB, (byte)0xFA, (byte)0xF9, (byte)0xF8 }; 32


Development Guide

Encrypting and decrypting data

// Key data. byte[] keyData = { (byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67,(byte)0x89, (byte)0x01, (byte)0x23, (byte)0x45 }; // Create a new DES key with the given data. DESKey key = new DESKey( keyData ); // Create the DES engine. DESEncryptorEngine desEngine = new DESEncryptorEngine( key ); // Create the CBC engine. CBCEncryptorEngine cbcEngine = new CBCEncryptorEngine( desEngine, new InitializationVector( iv ) ); // Create the PKCS5 Encoder engine. PKCS5FormatterEngine formatter = new PKCS5FormatterEngine( cbcEngine ); // Create a stream from the input byte array. ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); // Create the Encryptor using the CBCEncryptorEngine. BlockEncryptor encryptor = new BlockEncryptor( formatter, outputStream ); // Write the data to encrypt. encryptor.write( input, 0, input.length ); // Close the output stream and obtain the bytes. encryptor.close(); byte[] output = outputStream.toByteArray(); System.out.println( "Ciphertext = " + new String( output ) + "." );

Code sample: Using an unformatter To use an unformatter, extend the methods for encrypting and decrypting data. The following code sample demonstrates the unformatter. It specifies the output of the previous example, and specifies input. It creates a new DES key with the given data. It creates the DES engine, CBC engine, and PKCS5 Decoder engine. It creates a stream from the input byte array. Using the CBCDecryptorEngine, it creates the encryptor. It reads in the decrypted data, and then it closes the decryptor and the input stream. // Output from previous example. byte[] output = { (byte)0x58, (byte)0x95, (byte)0xBC, (byte)0xF4, (byte)0x3F, (byte)0xD8, (byte)0xD8, (byte)0xAD, (byte)0x80, (byte)0x9A, (byte)0x95, (byte)0x34, (byte)0xB4, (byte)0xCC, (byte)0x76, (byte)0x79 }; // Input. byte[] input = new byte[14]; byte[] iv = { (byte)0xFF, (byte)0xFE, (byte)0xFD, (byte)0xFC, (byte)0xFB, (byte)0xFA, (byte)0xF9, (byte)0xF8 }; byte[] keyData = { (byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67, (byte)0x89, (byte)0x01, (byte)0x23, (byte)0x45 };

33


Development Guide

Encrypting and decrypting data

// Create a new DES key with the given data. DESKey key = new DESKey( keyData ); // Create the DES engine. DESDecryptorEngine desEngine = new DESDecryptorEngine( key ); // Create the CBC engine. CBCDecryptorEngine cbcEngine = new CBCDecryptorEngine( desEngine, new InitializationVector( iv ) ); // Create the PKCS5 Decoder engine. PKCS5UnformatterEngine unformatter = new PKCS5UnformatterEngine( cbcEngine ); // Create a stream from the input byte array. ByteArrayInputStream inputStream = new ByteArrayInputStream( output ); // Create the Decryptor using the CBCDecryptorEngine. BlockDecryptor decryptor = new BlockDecryptor( unformatter, inputStream ); // Read in the decrypted data. decryptor.read( input, 0, input.length ); // Close the decryptor and the input stream. decryptor.close(); inputStream.close(); System.out.println("Ciphertext = " + new String( output ) + "."); System.out.println("Plaintext = " + new String( input ) + ".");

Stream ciphers A stream cipher, also called a stream algorithm, combines plaintext bits with a keystream. A keystream is a pseudorandom algorithm bit stream. Plaintext digits are encrypted one at a time. The stream cipher part of the RIM速 Cryptographic API is based on the common stream interface in Java速, and uses similar read and write function calls to interact with the stream. After a stream cipher is established, you don't need to write code for what it does: all activity is automatically performed by the class on the underlying stream. A pseudorandom source is a bit stream generator that is initialized with a seed. It supplies an arbitrarily long stream of difficult-to-predict and non-repeating bits. The PseudoRandomSource interface represents a PRNG. A PRNG expands a finite length seed into an arbitrarily long stream of pseudo-random bytes. The PseudoRandomSource classes provide methods for retrieving bytes from the PRNG and resetting the state of the PRNG. Most stream ciphers create the ciphertext by applying an exclusive-or to the plaintext with a keystream. The keystream is generated from a PRNG. To use the ARC4 algorithm, an instance of the ARC4PseudoRandomSource class is required. Instead of using the ARC4PseudoRandomSource class directly to encrypt data, you might find it more flexible and reliable to use the PRNGEncryptor class, which implements the StreamEncryptor class. Code sample: Stream encryption using the ARC4 algorithm

34


Development Guide

Encrypting and decrypting data

The following code sample illustrates encryption using a stream cipher. It specifies the input byte array. It uses the RandomSource to acquire input bytes. It prints out plaintext. It sets up the ARC4Key with length 256 bytes. It creates the ARC4PseudoRandomSource. It creates the output stream to store the encrypted data. It creates the PRNGEncryptor stream encryptor, which uses the ARC4PseudoRandomSource and an output stream. To encrypt, it calls write() with the plaintext. Finally, it prints the ciphertext. // Input byte array. byte[] plaintext = new byte[128]; // Use the Random source to get input bytes. RandomSource.getBytes( plaintext ); // Print out the plaintext. System.out.println("Plaintext = " + new String( plaintext ) + "."); // Set up the ARC4Key of length 256 bytes. ARC4Key key = new ARC4Key( 256 ); // Create the ARC4PseudoRandomSource. ARC4PseudoRandomSource source = new ARC4PseudoRandomSource( key ); // Create the output stream to store the encrypted data. ByteArrayOutputStream out = new ByteArrayOutputStream(); // Create the PRNGEncryptor stream encryptor, which uses // the ARC4PseudoRandomSource and an output stream. PRNGEncryptor encryptStream = new PRNGEncryptor( source, out ); // To encrypt, invoke write with the plaintext. encryptStream.write( plaintext, 0, plaintext.length ); encryptStream.close(); byte[] ciphertext = out.toByteArray(); // Print out the ciphertext. System.out.println( "Ciphertext = " + new String(ciphertext) + "." );

The following code sample shows you how to decrypt the data. It reloads the key to decrypt the plaintext. It creates an input stream with ciphertext as the basis. It creates an instance of a PRNGDecryptor to decrypt the data. It decrypts by reading from the stream and storing the decrypted data in plaintext. It prints the plaintext. // Reload the key to get the ciphertext back to plaintext (decrypt). source = new ARC4PseudoRandomSource( key ); // Create an input stream with ciphertext as the basis. ByteArrayInputStream in = new ByteArrayInputStream( ciphertext ); // Create an instance of a PRNGDecryptor to decrypt the data. PRNGDecryptor decryptStream = new PRNGDecryptor( source, in ); // Decrypt by reading from the stream and storing the decrypted data in plaintext. decryptStream.read( plaintext, 0, ciphertext.length ); decryptStream.close();

35


Development Guide

Encrypting and decrypting data

// Print out the plaintext. System.out.println( "Plaintext = " + new String( plaintext ) + "." );

Converting a block cipher to a stream cipher CFB mode is commonly used to convert a block cipher to a stream cipher. OFB mode can also be used to convert a block cipher to a stream cipher. The CFBEncryptor class (or any class that extends the StreamEncryptor class) accepts data using calls to write(), encrypts the data, and then writes that encrypted data to the output stream passed into the constructor. The encrypted data can be passed into any output stream. Code sample The following code sample shows how to encrypt and decrypt data using CFB mode. It uses DES, which is a common symmetric key algorithm. The first code sample sets up the input as random bytes. It sets up the DESKey, encryptor engine, initialization vector, output stream, and encryptor. It writes out the data to be encrypted and then closes the encryptor stream. Next, it gets the data from the data stream, and then prints the input and output. // Set up the input as random bytes. byte[] input = new byte[128]; RandomSource.getBytes( input ); // Set up the DESKEy. DESKey key = new DESKey(); // Set up the encyptor engine. DESEncryptorEngine engine1 = new DESEncryptorEngine( key ); // Set up the initialization vector. byte[] iv1 = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; // Set up the output stream. ByteArrayOutputStream outStream = new ByteArrayOutputStream(); // Set up the encryptor. CFBEncryptor encryptor = new CFBEncryptor( engine1, new InitializationVector( iv1 ), outStream, true ); // Write out the data to be encrypted. encryptor.write( input, 0, input.length ); // Close the encryptor stream. encryptor.close(); // Get the data from the underlying data stream. byte[] output = outStream.toByteArray(); outStream.close();

36


Development Guide

Encrypting and decrypting data

// Print out the input and the output. System.out.println("Plaintext = " + new String( input ) + "."); System.out.println("Ciphertext = " + new String( output ) + ".");

To decrypt data that was encrypted using CFB, a similar process is followed. The following example uses the same input and output byte array as the previous example, as well as the same key. This example sets up the encryptor engine, initialization vector, output stream, and decryptor. It reads in the data to be decrypted. It closes the decryptor stream and prints the input and output. // Set up the DESEngine. DESEncryptorEngine engine2 = new DESEncryptorEngine( key ); // Set up the initialization vector. byte[] iv2 = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; // Set up the output stream. ByteArrayInputStream inStream = new ByteArrayInputStream( output ); // Set up the decryptor. CFBDecryptor decryptor = new CFBDecryptor( engine2, new InitializationVector( iv2 ), inStream, true ); // Read in the data to be decrypted. decryptor.read( input, 0, input.length ); // Close the encryptor stream. decryptor.close(); inStream.close(); // Print out the input and the output. System.out.println("Plaintext = " + new String( input ) + ".");

Encryptor engines Encryptor engines are an alternative to encryptor factories (the EncryptorFactory class). The EncryptorFactory class is built on engines. Both engines and factories produce identical results. Engines allow you to access the lowest level of abstraction and directly access algorithms. For example, you could use the DESEncryptorEngine class to directly access the DES algorithm by passing in a plaintext byte array and receiving an encrypted byte array. All the engine classes derive from the net.rim.device.api.crypto.BlockEncryptorEngine interface. The code samples below demonstrate the two main approaches to using encryptor engines: a block-based approach that uses an encryptor engine to encrypt blocks of data; and a stream-based approach that uses a block encryptor to encrypt a stream of data. Code sample: Encrypting blocks of data with an encryptor engine

37


Development Guide

Encrypting and decrypting data

In ECB mode, the engine takes one block at a time and returns one block at a time. There is no chaining or dependence on other blocks for the encryption of the ciphertext. This is not the most secure mode for encryption, but it is the more straightforward approach. The following sample code uses the DESEncryptorEngine class. It shows how to encrypt data using DES and a block algorithm in ECB mode. First input is defined, and then output is defined. Next, the code creates a new DES key with the given data and creates the engine. Finally, it encrypts the input with an offset of zero. Note: This example assumes that the characters are low enough in the Unicode character set to have a code point less than 256 (requiring a single byte value) so that the byte array length is the same as the number of characters. This may not always be the case with character sets such as Arabic, Cyrillic, and Chinese. // Input. byte[] input = { 'T','e','s','t','i','n','g','!' }; // Output. byte[] output = new byte[ 8 ]; byte[] keyData = { (byte)0x01, (byte)0x23, (byte)0x45,(byte)0x67, (byte)0x89, (byte)0x01, (byte)0x23, (byte)0x45 }; // Create a new DES key with the given data. DESKey key = new DESKey( keyData ); // Create engine. DESEncryptorEngine engine = new DESEncryptorEngine( key ); // Encrypt the input with offset of zero. engine.encrypt( input, 0, output, 0); System.out.println("Ciphertext = " + new String( output ) + ".");

The following sample code shows how to decrypt data using a block algorithm. This sample uses the DESDecryptorEngine class to perform decryption. // Input. byte[] input = { (byte)0x77, (byte)0xFB, (byte)0xF4, byte)0x94,(byte)0xE9, (byte)0x70, (byte)0xDD, (byte)0x0B }; // Output. byte[] output = new byte[ 8 ]; // Key data from encryption. byte[] keyData = { (byte)0x01,(byte)0x23, byte)0x45, byte)0x67, (byte)0x89, (byte)0x01, (byte)0x23, (byte)0x45 }; // Create a new DES key with the given data. DESKey key = new DESKey( keyData ); // Create engine. DESDecryptorEngine engine = new DESDecryptorEngine( key ); // Decrypt the input with offset of zero. engine.decrypt( input, 0, output, 0); System.out.println("Plaintext = " + new String( output ) + ".");

38


Encrypting and decrypting data

Development Guide

Code sample: Encrypting streams of data with an encryptor engine The following code sample uses CBC mode. This approach is more verbose and time-consuming to write than the previous example, but it yields clearer and more reliable results. This approach uses an initialization vector. The initialization vector is a byte array of random data that is used to further randomize generated data. Initialization vectors can be used with some block cipher modes, such as CBC, to ensure that when the same plaintext message is encrypted twice, it will not result in the same ciphertext message both times. This approach to encryption uses a BlockEncryptor to encrypt a stream of data with DES. The actual encryption is performed with the call to write(). The rest of the code is for setting up or tearing down the encryptors and engines. //Input. byte[] input = { (byte)'T', (byte)' ', (byte)'a', (byte)'s',

(byte)'h', (byte)'i', (byte)' ', (byte)'t',

(byte)'i', (byte)'s', (byte)'t', (byte)'!',

(byte)'s', (byte)' ', (byte)'e', (byte)'!' };

//Initialization vector. byte[] iv = { (byte)0xFF, (byte)0xFE, (byte)0xFD, (byte)0xFC, (byte)0xFB, (byte)0xFA, (byte)0xF9, (byte)0xF8 }; //Key data. byte[] keyData = { (byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67, (byte)0x89, (byte)0x01, (byte)0x23, (byte)0x45 }; // Create a new DES key with the given data. DESKey key = new DESKey( keyData ); // Create the DES Engine. DESEncryptorEngine desEngine = new DESEncryptorEngine( key ); // Create the CBC engine. CBCEncryptorEngine cbcEngine = new CBCEncryptorEngine(desEngine, new InitializationVector(iv)); // Create a stream to hold the encrypted data. ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); // Create the Encryptor using the CBCEncryptorEngine and the output stream. BlockEncryptor encryptor = new BlockEncryptor( cbcEngine, outputStream ); // Write out the data to encrypt. encryptor.write( input, 0, input.length ); // Close the encryptor and grab the bytes. encryptor.close(); byte[] output = outputStream.toByteArray(); System.out.println("Ciphertext = " + new String( output ) + ".");

39


Encrypting and decrypting data

Development Guide

The following code uses BlockDecryptor to decrypt a stream of data with DES. This example demonstrates DES decryption in CBC mode. //Input byte[] input = { (byte)0x58, (byte)0x9F, (byte)0x31, (byte)0x56,

(byte)0x47, (byte)0xEF, (byte)0x4E, (byte)0xAC,

(byte)0x50, (byte)0x0D, (byte)0xB7, (byte)0x3C,

(byte)0x34, (byte)0x77, (byte)0x73, (byte)0xD6 };

//Initialization vector. byte[] iv = { (byte)0xFF, (byte)0xFE, (byte)0xFD, (byte)0xFC, (byte)0xFB, (byte)0xFA, (byte)0xF9, (byte)0xF8 }; //Output. byte[] output = new byte[ 16 ]; //Key data. byte[] keyData = { (byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67, (byte)0x89, (byte)0x01, (byte)0x23, (byte)0x45 }; // Create a new DES key with the given data. DESKey key = new DESKey( keyData ); // Create the DES Engine. DESDecryptorEngine desEngine = new DESDecryptorEngine( key ); // Create the CBC engine. CBCDecryptorEngine cbcEngine = new CBCDecryptorEngine(desEngine, new InitializationVector(iv)); // Create a stream from the input byte array. ByteArrayInputStream inputStream = new ByteArrayInputStream( input ); // Create the Decryptor using the CBCDecryptorEngine. BlockDecryptor decryptor = new BlockDecryptor( cbcEngine, inputStream ); // Read in the decrypted data. int ret = decryptor.read( output, 0, output.length ); // Close the encryptor and grab the bytes. decryptor.close(); inputStream.close(); System.out.println("Plaintext = " + new String( output ) + ".");

Handling exceptions The RIM速 Cryptographic API has two exceptions:

40


Encrypting and decrypting data

Development Guide

Exception

Description

javacard.security.CryptoExcept ion

CryptoException is the most commonly thrown exception. Where

CryptoIOException

possible, a subclass exception is thrown that indicates what caused the error. Examples of CryptoException subclasses are InvalidKeyPairException, InvalidKeyFormatException, and InvalidSignatureFormatException. If none of the subclasses suit the error, CryptoException is thrown. CryptoIOException is an IOException that contains a CryptoException. Some stream-related classes such as EncryptorOutputStream can only throw an IOException. CryptoIOException is thrown only when an IOException has

occurred within a crypto member. For example, if an error occurs and an IOException is thrown within an EncryptorOutputStream, a CryptoIOException is thrown instead of the IOException. To make it easier for you to debug your application, the CryptoIOException is handled separately from the IOException.

Code sample In the following code sample, a try/catch block is used to allow each exception to be caught by the exception handler. The string associated with the exception is output to the console so that you can check the log to determine if an exception was thrown. try {

//*cryptographic code } catch( IOException e ) { System.out.println(e.toString()); } catch( CryptoTokenException e ) { System.out.println(e.toString()); }

41


Development Guide

Cryptographic algorithms and cryptographic codes that the RIM Cryptographic API supports

Cryptographic algorithms and cryptographic codes that the RIM Cryptographic API supports Symmetric block algorithms that the RIM Cryptographic API supports Symmetric block algorithms use PKCS #5 for padding. The RIM® Cryptographic API supports the CBC, CFB, ECB, OFB, and X modes for all algorithms. The RIM Cryptographic API implements the modes separately from the symmetric block algorithms. Algorithm AES CAST5 DES RC2 RC5® Skipjack Triple DES

Key length (bits) 128, 192, and 256 128 56 8 to 1024 0 to 2040 80 112 and 168

Stream encryption algorithms that the RIM Cryptographic API supports The RIM® Cryptographic API supports the ARC4 algorithm, with an unlimited key length, as the symmetric stream encryption algorithm. The RIM Cryptographic API supports the ECIES algorithm, with an unlimited key length (160 bits to 571 bits for seeding), as the asymmetric stream encryption algorithm.

Asymmetric encryption algorithms that the RIM Cryptographic API supports Algorithm ElGamal RSA® raw RSA with OAEP formatting RSA with PKCS #1 formatting (versions 1.5 and 2.0)

Key length (bits) 512 to 4096 512 to 4096 512 to 4096 512 to 4096

Type discrete logarithm integer factorization integer factorization integer factorization

Signature scheme algorithms that the RIM Cryptographic API supports If the signature scheme algorithm that a developer wants to use is the RSA® algorithm using ANSI® X9.31, ANSI X9.31 uses one of the following algorithms for the required message digest code: SHA-1, SHA-2, or RIPEMD-160. 42


Development Guide

Cryptographic algorithms and cryptographic codes that the RIM Cryptographic API supports

Algorithm Key length (bits) DSA 512 to 1024 ECDSA 160 to 571 ECNR 160 to 571 RSA速 using ANSI X9.31 512 to 4096 RSA using PKCS #1 (versions 1.5 and 512 to 4096 2.0) RSA using PSS 512 to 4096

Type discrete logarithm (Elliptic Curve) discrete logarithm (Elliptic Curve) discrete logarithm integer factorization integer factorization integer factorization

Key agreement scheme algorithms that the RIM Cryptographic API supports Algorithm Diffie-Hellman ECDH ECMQV KEA

Key length (bits) 512 to 4096 160 to 571 160 to 571 1024

Type discrete logarithm (Elliptic Curve) discrete logarithm (Elliptic Curve) discrete logarithm discrete logarithm

Key generation algorithms that the RIM Cryptographic API supports Algorithm Diffie-Hellman DSA Elliptic Curve RSA速

Key length (bits) 512 to 4096 512 to 1024 160 to 571 512 to 2048

Type discrete logarithm discrete logarithm (Elliptic Curve) discrete logarithm integer factorization

Message authentication codes that the RIM Cryptographic API supports Code CBC-MAC HMAC

Key length (bits) variable (block cipher key length) variable

Message digest codes that the RIM Cryptographic API supports Code MD2

Digest length (bits) 128 43


Development Guide

Code MD4 MD5 RIPEMD SHA

Cryptographic algorithms and cryptographic codes that the RIM Cryptographic API supports

Digest length (bits) 128 128 128, 160 160, 224, 256, 384, 512

TLS and WTLS protocols that the RIM Cryptographic API supports The RIM速 Cryptographic API supports the cipher suite components for the TLS protocol and WTLS protocol that apply only to direct mode SSL/TLS and WTLS.

Cipher suites for the key establishment algorithm that the RIM Cryptographic API supports Direct mode SSL DH_anon

Direct mode TLS DH_anon

DH_anon_EXPORT DHE_DSS DHE_DSS_EXPORT RSA RSA_EXPORT

DH_anon_EXPORT DHE_DSS DHE_DSS_EXPORT RSA RSA_EXPORT

WTLS RSA速 _768, DH_anon, DH_anon_512, DH_anon_768 RSA_anon_512 RSA_512 RSA_anon_768 RSA RSA_anon

Symmetric algorithms that the RIM Cryptographic API supports Direct mode SSL DES DES-40 ARC4-128 ARC4-128 ARC4-128 ARC4-128 ARC4-40 Triple DES

44

Direct mode TLS ARC4-128 DES Triple DES AES-128 AES-256 ARC4-40 DES-40

WTLS RC5速 -64 RC5-56 RC5-128 DES-40 DES Triple DES RC5-40 RC5


Development Guide

Cryptographic algorithms and cryptographic codes that the RIM Cryptographic API supports

Hash algorithms that the RIM Cryptographic API supports Direct mode SSL MD5 SHA-1

Direct mode TLS MD5 SHA-1

WTLS SHA SHA-40, SHA-80, MD5, MD5-40, MD5-80

Limitations of RIM Cryptographic API support for cipher suites for the key establishment algorithm The RIM速 Cryptographic API implementation of the TLS protocol and WTLS protocol supports the use of the RSA速 public key algorithm, DSA public key algorithm, and Diffie-Hellman key exchange algorithm, with the following limitations. Cipher suite type export non-export

Typical component limitation RSA and Diffie-Hellman: 1024 bytes or less non elliptic curve operations: 4096 bytes

Limitations to non-export cipher suite types are due to the computational constraints of a BlackBerry速 device.

45


Development Guide

Content protection

Content protection

3

Content protection is a security framework that you can use to protect application data on a BlackBerry® device. Content protection addresses the problem of someone stealing a device and copying its data, which may be possible even when data is encrypted and the mobile device is locked. Content protection encrypts data in such a way that the encryption key is inaccessible when the device is locked. There are three parts to a content protection implementation: • • •

There is content protection functionality on every BlackBerry device. To use it, the device must have a device password, and content protection must be enabled by the device user or by an IT policy rule. To protect data in an application, the application must subscribe to the content protection framework by registering a listener. Content protection functionality is triggered by the user locking and unlocking the device.

Content protection can be used to encrypt data in String objects or byte arrays. Content protection can apply to data that is not persisted, but the Content Protection API contains specific functionality for the persistent store. Whenever an application attempts to encrypt an object, the unencrypted version of the object is marked with a special bit called a plaintext bit. Any object marked with a plaintext bit is presumed to contain unencrypted, sensitive data. An application specifies which data it considers to be sensitive by encrypting and decrypting objects, marking these objects with plaintext bits. Until an attempt has been made to encrypt data, the device assumes that that data is not sensitive. When the device is locked, the content protection framework uses these plaintext bits to ensure that as many plaintext objects as possible are erased from device memory. Here are the basic steps for implementing content protection for your application: •

Subscribe to content protection. • Implement the PersistentContentListener interface. • Register the listener using PersistentContent.addListener() or PersistentContent.addWeakListener(). • Encode and decode your objects, as required, using PersistentContent.encode() and PersistentContent.decode(). Note: In the context of content protection, encoding means to encrypt and/or compress objects.

Compressing data with content protection In addition to encrypting data, content protection can be used to compress data. Compression and encryption are enabled separately. As with encryption, applications can compress data by passing data objects to the content protection framework and then storing the altered versions that the framework returns. Applications can only compress data if the BlackBerry® device user has enabled compression on the BlackBerry device. The content protection framework does not compress all data that is passed to it. For example, anything smaller than 32 bytes is not compressed because the overhead associated with the compression process would result in compressed data that is larger than the original, uncompressed data. 46


Development Guide

Enabling content protection

Enabling content protection For content protection to be in effect, the following conditions must be met: • • •

The BlackBerry® device must have a password set. Content protection must be enabled on the device, either through an IT policy rule or by the BlackBerry device user. (Content protection is not enabled by default.) The application must subscribe to the content protection framework.

When content protection is first enabled on a device, the device must be locked and remain locked long enough (a few minutes) for the device to fully enable content protection and remove all unencrypted, sensitive data. Each time a device transitions from having content protection turned off to having it turned on, the following occurs: 1. 2. 3.

4.

The content protection framework notifies all registered apps to re-encode their data. During this process, data may be encrypted. The device waits two minutes before it attempts to fully enable content protection. This waiting period is designed to guard against the possibility that the user only wanted to lock the device temporarily. The device displays a dialog box reading, "Content Protection is being enabled. This operation may take a few minutes to complete." Content protection is only considered to be fully enabled after all registered applications have finished encoding their data, the content protection framework has cleaned all the plaintext objects it can from memory, the encryption keys are no longer available, and the device is securely locked. This process may take some time to complete, depending on the amount of data that needs to be encoded. The content protection framework enforces additional safeguards, such as having garbage collection zero out deleted data that was previously encrypted.

Enabling content protection through IT policy rules In a BlackBerry® Enterprise Server environment, administrators can use IT policy rules to turn content protection on and off on the BlackBerry® devices they administrate. There are several IT policy settings that pertain to content protection: •

• • • •

Content Protection Usage IT policy rule: Determines whether BlackBerry device users can enable content protection on their devices. When this rule is set to disallowed, users cannot turn on content protection. When this rule is set to allowed, users can choose whether or not to use content protection. The Content Protection Usage IT policy rule cannot be used to force users to use content protection; that is handled by the Content Protection Strength IT policy rule. Content Protection Strength IT policy rule: Specifies the strength of the key used to encrypt data when the device is locked. If the Content Protection Strength IT policy is set, content protection cannot be turned off. Content Protection of Contact List IT policy rule: Includes or excludes contacts from content protection. Two Factor Content Protection Usage IT policy rule: Specifies whether the device uses an installed smart card reader and certificate for certain content protection operations. This option is only present if a supported smart card driver is installed. Force Content Protection Of Master Keys IT policy rule: Enables or disables content protection for device transport keys. 47


Development Guide

Understanding locked and unlocked device states

IT policy rules for content protection only specify a minimum level of security. Provided that content protection has not been forbidden by an IT policy, device users can increase the strength of encryption used on their devices. For more information about the IT policy rules that affect content protection, see the BlackBerry Enterprise Solution Security Technical Overview, available at http://docs.blackberry.com/en/admin.

Enabling content protection by a device user The following content protection options allow BlackBerry® device users to specify the strength and extent of content protection on their BlackBerry devices: • • •

Encrypt: Enables or disables content protection and media encryption. Strength: Dictates the strength of the key used to encrypt data when the device is locked. Include Contacts: Includes or excludes certain contact fields from content protection. When content protection for contacts is turned on, the caller's name does not appear on the screen if the user receives a call from a contact when the device is locked. If contacts are excluded from content protection, the user is presented with the caller's name and user picture, as usual. Include Media Files: Specifies whether media files stored on the internal media card (eMMC) should be encrypted. Although it is grouped with the content protection options, this option actually has nothing to do with content protection. Content protection is not used to encrypt media files and generally only applies to data that is ultimately written to the device's internal flash memory. Two-factor Protection: Specifies whether the device uses an installed smart card reader and certificate for certain content protection operations. This option is only present if a supported smart card driver is installed.

Understanding locked and unlocked device states The content protection framework encrypts data differently when the BlackBerry® device is locked and when it is unlocked. When the device is unlocked, it is generally considered appropriate for security requirements to be relatively lax. Therefore, all the cryptographic keys necessary to decrypt data are readily available. Applications that subscribe to the content protection framework can encrypt, decrypt, compress, or decompress data at any time. The content protection framework does not dictate which data should be considered sensitive or when that data should be encrypted or compressed; it is up to each individual application to implement the available content protection APIs in a way that makes the most sense for that application. When the device is locked, it is generally considered appropriate for security requirements to be much stricter. Therefore, the content protection framework only allows applications to encrypt data, not decrypt it, and it ensures that garbage collection removes any unencrypted, potentially sensitive data as promptly as possible. When an application receives potentially sensitive data while the device is locked, the application should encrypt the data immediately.

Cryptographic keys The content protection framework uses one cryptographic key to encrypt data when the BlackBerry® device is unlocked and a different set of keys to encrypt data when the device is locked. 48


Development Guide

Understanding locked and unlocked device states

When the device is unlocked, the content protection framework encrypts all data passed to it using a symmetric cryptographic key known as the content protection key or bulk key. The bulk key is a 256 bit AES key. It can encrypt and decrypt data quickly, making it ideal for transcoding data when the device is unlocked and the user is unlikely to tolerate long delays or reduced performance that might result from using a slower and more cumbersome system of keys. The bulk key can't be used when the device is locked because it can decrypt data that it previously encrypted. When the device is locked, the bulk key must be hidden from potential attackers by encrypting it using the device password. When the device is locked, the content protection framework uses a more complicated system of paired private and public ECC keys to encrypt data. The content protection framework can encrypt in any one of three different encryption strengths when a device is locked, each of which corresponds to a different key size: • • •

Strong keys: 160 bit ECC keys (equivalent to an 80 bit symmetric key) Stronger keys: 238 bit ECC keys (equivalent to a 128 bit symmetric key) Strongest keys: 571 bit ECC keys (equivalent to a 256 bit symmetric key)

The content protection framework decides which set of keys to use based on the device's Encryption Strength setting, as configured through either the Options application or an IT policy. If the setting is Stronger or Strongest, then when content protection is turned on for the first time, the BlackBerry device user is asked to generate random data by pressing random keys or scrolling around the screen. This random data is incorporated into the Stronger and Strongest keys, making them more random and thus more secure. Each pair of ECC keys consists of a public key and a private key. When the device is locked, only the public ECC key is available; the private ECC key, like the bulk key, is hidden and encrypted with the device password. This makes it possible to encrypt data so that it can only be decrypted when the device is unlocked and the private ECC key once again becomes available. The paired ECC keys are also known as the long-term public key and the long-term private key. They are used in combination with a pair of cryptographic keys that are only used once, the one-time public key and the one-time private key. The long-term public key is involved in encrypting every piece of new data that arrives on the device when it is locked, while the long-term private key remains encrypted (and so hidden and inaccessible) for as long as the device is locked. The long-term private key is only used after the device is unlocked, to aid in decrypting those data objects that were previously encrypted using the long-term public key. Every time new data arrives on the device and an application makes it into a data object and passes that object to the content protection framework, a new pair of one-time keys is created, which are only used to encrypt that one data object.

Encrypting data when the device is locked To encrypt a new data object when a BlackBerry® device is locked, the content protection framework starts by combining the long-term public key with the one-time private key to produce a symmetric key. This symmetric key is similar to the symmetric AES bulk key that is used to encrypt data when the device is unlocked. This symmetric key is used to encrypt the new data.

49


Development Guide

Understanding locked and unlocked device states

Once the data has been successfully encrypted, the one-time private key and the symmetric key it helped create are deleted and wiped from the device. The one-time public key is embedded within the encoding that represents the encrypted data. This leaves just the long-term public key and the one-time public key available. With only those two keys, there is no way to decrypt the encrypted object.

Decrypting data when the device is unlocked When a BlackBerry速 device is unlocked, the AES bulk key and long-term private ECC key are decrypted and once again made available for the content protection framework to use. At this point, any data encrypted by the content protection framework can be decrypted. The content protection framework automatically determines when the bulk key can be used to decrypt data or if the corresponding one-time symmetric key needs to be recomputed. When the device is unlocked and the long-term private key is available, the long-term public key and the one-time private key can be combined so that that they create a single symmetric key. This key is identical to the key that is produced when the long-term private key and the one-time public key are combined. To decrypt an object that was encrypted when the device was locked, the content protection framework combines the long-term private key with the one-time public key. This is relatively easy because when an object is encrypted using a combination of public and private keys, the relevant one-time public key is stored with it. Data that was originally encrypted when the device was unlocked can be decrypted using the AES bulk key, since that is the same key that the content protection framework used to encrypt the data. The content protection framework tracks the number of times it has been asked to decode data that was encrypted when the device was locked. Once it reaches the threshold number of 2053 data objects, the content protection framework sends out a notification requesting that all applications verify the integrity of their data and re-encode any data that does not conform to the current content protection settings or that was not encoded using the bulk key. By re-encoding data when it receives such a notification, an application can improve its performance, since an object encrypted using the bulk key is much quicker to decrypt than one encrypted using the two-key ECC scheme.

Encrypting data when the device is unlocked When a BlackBerry速 device is unlocked, the content protection framework encrypts data using the AES bulk key. Applications that subscribe to the content protection framework can encrypt and decrypt data at any time, as long as the device is unlocked.

Locking the device When a BlackBerry速 device locks, the content protection framework sends out a "state changed" notification to all registered listeners. Applications that subscribe to the content protection framework can use this notification as a trigger to encrypt any of their data that has not already been encrypted. As soon as all the registered listeners indicate that they no longer need the bulk key, the framework hides the bulk key and private ECC keys. Once these keys are hidden, only the long-term public ECC keys are available.

50


Development Guide

Implementing content protection

The framework initiates garbage collection of any plaintext object that is not in use. (A plaintext object is an object marked with a plaintext bit. It is presumed to contain unencrypted, sensitive data. It is by encrypting and decrypting objects, and thereby marking them with plaintext bits, that an application specifies which data it considers to be sensitive.) It may not be possible to remove some plaintext objects because, for example, they are referenced by applications that do not use content protection or that do not use it well. In an effort to eliminate the possibility of confidential information being held by an application when the device is locked, the content protection framework attempts to close all open screens. For each screen that is open, it does the equivalent of pressing the Escape key. This is a best effort approach, and when a key press is not able to close a screen the device stops trying to close that screen.

Implementing content protection The following classes and interfaces are used to implement content protection: • • •

net.rim.device.api.system.PersistentContent: This class contains utility methods for encoding and

decoding data, registering listeners, and performing other tasks related to content protection. net.rim.device.api.system.PersistentContentListener: This listener interface lets your application receive notifications when there are changes to the BlackBerry® device's content protection state or content protection settings. net.rim.device.api.system.PersistentContentException: This exception is thrown when an error occurs with content protection.

Code sample: Registering a listener The following code sample shows one way to register a listener. First, the sample code synchronizes the PersistentObject so that no other object can acquire the lock before the commit operation is finished, and then it initializes the PersistentObject, if necessary. It registers a PersistentContentListener when the

application starts. public static void main(String[] args) { if ( args != null && args.length > 0 && args[0].equals("startup") ) { PersistentObject store = PersistentStore.getPersistentObject( PERSISTENT_STORE_DEMO_ID); // Synchronize the PersistentObject. synchronized(store) { // If the PersistentObject is empty, initialize it. if(store.getContents() == null) { store.setContents(new Vector()); PersistentObject.commit(store); } } // Register a PersistentContentListener upon device start-up.

51


Implementing content protection

Development Guide

}

PersistentContent.addListener(new PersistentStoreListener()); } else { // Launch the GUI version of the application. PersistentStoreDemo theApp = new PersistentStoreDemo(); theApp.enterEventDispatcher(); }

Code sample: Implementing the listener The following code sample implements the listener. The listener listens for changes to the device content protection and compression settings as well as persistent content state changes, and it encodes data accordingly. In this example, changes to the device's state are ignored. (In this example it is assumed that data is always encoded inside objects, so there is no need to encode or decode them during locking and unlocking.) The generation parameter is used to determine if the content protection settings on the device have changed since the listener was notified. final class PersistentStoreListener implements PersistentContentListener { public void persistentContentStateChanged(int state) { // There is nothing to do. It is assumed that data is encoded properly // when it is placed in the Vector written to the persistent store. } // Called when the device's Content Protection/Compression security settings // are changed. Re-encodes the data accordingly. public void persistentContentModeChanged(int generation) { PersistentObject persist = PersistentStore.getPersistentObject( PersistentStoreDemo.PERSISTENT_STORE_DEMO_ID); if (persist != null) { synchronized(persist.getContents()) { Vector meetings = (Vector) persist.getContents(); if (meetings == null) { // Contents empty; nothing to re-encode. return; } // Get a ticket in case data must be decrypted as // part of re-encoding data. Object ticket = PersistentContent.getTicket(); if (ticket == null ) { // No ticket is available. Stop trying // to re-encode to avoid possible failures. return; } for (int i = 0; i < meetings.size(); ++i) 52


Implementing content protection

Development Guide

{

}

Meeting meeting = (Meeting)meetings.elementAt( i ); // meeting.reEncode(); // meeting object contains a _fields Vector. for (int i = 0; i < meeting.NUM_FIELDS; ++i) { Object encoding = meeting._fields.elementAt(i); if(!PersistentContent.checkEncoding(encoding)) { encoding = PersistentContent.reEncode(encoding); meeting._fields.setElementAt(encoding, i); } } if ( generation != PersistentContent.getModeGeneration() ) { // Device's content protection or compression // settings have changed again since the listener was // last notified. Abort this re-encoding because it // will have to be done again anyway according to the // new content protection or compression settings. break; }

// Release the ticket. ticket = null;

}

}

}

}

// Commit the updated data to the persistent store. persist.commit();

Obtaining and releasing content protection tickets Content protection tickets are used to ensure that the BlackBerry速 device does not hide the cryptographic keys necessary for decryption until all decryption operations are complete. When your application decrypts an object, it should begin by requesting a content protection ticket. If the device is unlocked, the content protection framework should immediately grant you a ticket. If the device is securely locked, no tickets are available. There are two different methods you can use to request a content protection ticket:

PersistentContent.getTicket() and PersistentContent.waitForTicket(). The getTicket() method is non-blocking; it will either return a ticket right away or it will return null. The waitForTicket() method blocks

the caller until a ticket can be obtained.

Note: Never call waitForTicket() from the event thread. Doing so may cause your application to shut down.

53


Development Guide

Implementing content protection

When your application has finished decrypting your data, you must immediately release your content protection ticket. This is essential because the framework cannot hide the cryptographic keys, and so make the device highly secure, until all content protection tickets have been released. As long as a strong reference to a ticket exists, the device is not securely locked.

Subscribing to content protection To have your application notified of changes to the content protection state or content protection settings, you must implement the PersistentContentListener interface and register your listener with the content protection framework. Your implementation of PersistentContentListener determines how your application reacts to changes in the BlackBerry® device's content protection state, such as when it transitions from locked to unlocked; and how your application reacts to changes to the device's content protection settings, such as when content protection is turned on or off. The PersistentContentListener interface requires that you implement two methods: • •

persistentContentModeChanged(), which is triggered when the device's content protection settings

change.

persistentContentStateChanged(), which is triggered when the device transitions between locked and

unlocked states.

Capturing mode changes When the content protection settings on a BlackBerry® device change, the content protection framework calls the listener's persistentContentModeChanged() method. For example, the method is called if encryption is turned off or on, if compression is turned off or on, or if the encryption strength of content protection is changed. When your listener is notified of a change in content protection settings, it should review all the data it has stored and ensure that the encoded data meets the requirements imposed by the new content protection settings. The first thing persistentContentModeChanged should do is obtain a content protection ticket. You need to obtain a ticket to ensure that the cryptographic keys, which you may need to re-encode your data, remain available for as long as you need them. If you do not obtain a ticket, the framework could make the decryption keys unavailable when you are decrypting data without you knowing, making it impossible to complete the process. When you attempt to obtain a ticket you should always check to make sure that your attempt was successful—that the ticket returned is not null. If it is null then you probably do not want to try to re-encode, because if you find you need to decrypt, exceptions will occur. If the ticket is not null, then your application can start checking and, if necessary, re-encoding your data. If you are checking and re-encoding a lot of data, you will likely want to pause intermittently to check whether the generation value has changed. The generation value is an integer counter that is incremented every time modifications to the content protection settings are made (or, more generally, every time a mode changed event occurs). You can check the generation value using PersistentContent.getGeneration(). If the generation value that was provided as part of the call to persistentContentModeChanged() is different from the value returned by getGeneration(), you know that the device's content protection settings have been changed. If you're

54


Development Guide

Implementing content protection

in the middle of processing your application's data to bring it in line with a given generation and, when checking the generation value, you discover that the generation value has changed since you started processing, you will want to restart the checking/re-encoding process with the new generation value. This is a way to optimize your implementation of this method if you are dealing with a large amount of data at once. After all data has been checked and, if necessary, re-encoded, you must release the content protection ticket. It is very important that you release the ticket, either explicitly, by setting the ticket to null, or implicitly, by ensuring that the method in which the ticket is requested ends as soon as the operation for which it is needed ends. If you do not release the ticket, the framework will not know when it's safe to hide the decryption keys. The persistentContentModeChanged() method is also called in the following cases: • • •

The content protection framework has decrypted objects 2053 times that were encrypted while the device was locked. The content protection framework detects data that is not encoded, but should be according to the content protection settings on the device. The content protection framework detects data that is not encrypted, but should be according to the compression and encryption settings of an application.

Code sample The following code sample is a simple implementation of persistentContentModeChanged. The example checks and, if necessary, re-encodes the individual elements of an Object array called data. This array is a member field of the enclosing class. Each element of the data array is passed into the checkEncoding() method to determine whether it is currently encoded in accord with the current content protection settings. If it is not, the reEncode() method is called, to encode the data according to the new standards. public void persistentContentModeChanged(int generation) { Object ticket = PersistentContent.getTicket(); if( ticket != null ) { for( int i = 0; i < data.length; i++ ) { if( ! PersistentContent.checkEncoding( data[ i ] ) { data[ i ] = PersistentContent.reEncode( data[ i ] ); } } } ticket = null; }

Capturing state changes Content protection listeners are notified of changes to the content protection state of the BlackBerry® device. This means that your application can tell when the device transitions between being locked and unlocked. Content protection state changes can also be used to determine when the device switches between being insecurely locked

55


Development Guide

Implementing content protection

and securely locked, although it is unlikely that you will want to do anything in response to that transition. In all probability, you will only ever be interested in differentiating between two broad categories of states: the unlocked states and the locking or locked states. The content protection framework calls PersistentContentListener.persistentContentStateChanged() only when a device transitions from the unlocked state to the locked state. There are four different state values that can be used to identify the device's current content protection state: • • • •

Unlocked: Indicates that the device is currently unlocked. Locking: Indicates that the device is in the process of locking. Securely Locked: Indicates that data on the device is secured. The device is locked and all data that should be encoded is encoded. Insecurely Locked: Indicates that data on the device is not secured. The device is locked but some data on the device may be in plaintext format. This occurs if data is received when the device is locked.

When the device transitions from a locked state to the unlocked state, applications can obtain content protection tickets and decode data as required. When a device is locked, it transitions first from unlocked to locking and then from locking to one of the locked states. When the device is in the intermediate locking state, your application should ensure that all of its sensitive data has been encrypted correctly, such as by using the checkEncoding() method. The device state does not transition from the locking state to a locked state until all content protection tickets have been released.

Registering a PersistentContentListener In most cases, to register a listener with content protection you should call

PersistentContent.addListener(). The addListener() method registers a persistent content listener using

a strong reference to the provided listener so that it will not be garbage collected.

If you want to register only a weak reference to the content protection listener, you can instead register your listener with the content protection framework using PersistentContent.addWeakListener(). If the device running your application resets, then your application will have to call addWeakListener() again. Code sample In some cases you might want to register your PersistentContentlistener when your application first starts. In the following code sample, the application registers a PersistentContentListener when the BlackBerry® device starts if no arguments are passed to the application or if the startup argument is specified. The listener listens for changes to the device content protection and compression settings as well as persistent content state changes. The code sample launches the GUI portion of the application if the arguments are specified and startup is not listed as the first argument. final class PersistentStoreListener implements PersistentContentListener { public void persistentContentStateChanged(int state) { // There is nothing to do. It is assumed that data is encoded properly

56


Implementing content protection

Development Guide

}

// when it is placed in the Vector written to the persistent store.

// Called when the device's Content Protection/Compression security settings // are changed. Re-encodes the data accordingly. public void persistentContentModeChanged(int generation) { PersistentObject persist = PersistentStore.getPersistentObject( PersistentStoreDemo.PERSISTENT_STORE_DEMO_ID); if (persist != null) { synchronized(persist.getContents()) { Vector meetings = (Vector) persist.getContents(); if (meetings == null) { // Contents empty; nothing to re-encode. return; } // Get a ticket in case we need to decrypt data as // part of re-encoding data. Object ticket = PersistentContent.getTicket(); if (ticket == null ) { // No ticket is available. We need to stop trying // to re-encode to avoid possible failures. return; } for (int i = 0; i < meetings.size(); ++i) { Meeting meeting = (Meeting)meetings.elementAt( i ); // meeting.reEncode(); // meeting object contains a _fields Vector. for (int i = 0; i < meeting.NUM_FIELDS; ++i) { Object encoding = meeting._fields.elementAt(i); if(!PersistentContent.checkEncoding(encoding)) { encoding = PersistentContent.reEncode(encoding); meeting._fields.setElementAt(encoding, i); } }

}

if ( generation != PersistentContent.getModeGeneration() ) { // Device's content protection or compression // settings have changed again since the listener was // last notified. Abort this re-encoding because it // will have to be done again anyway according to the // new content protection or compression settings. break; }

57


Implementing content protection

Development Guide

// Release the ticket. ticket = null;

}

}

}

}

// Commit the updated data to the persistent store. persist.commit();

Encoding an object The PersistentContent.encode() method encrypts and/or compresses a String or byte array into an encoded object according to the security settings that enabled content protection (on the BlackBerry速 device or in the IT policy rules). If the data you want to encode is not a String or byte array, you must convert it into a String or byte array before you encode it. Encoding can be performed at any time, regardless of whether the device is locked or unlocked. If encryption or compression is enabled, the encode() method encodes the data passed to it. If neither is enabled, the encode() method passes back an unencoded, unaltered version of the data object. To encode an object, you must pass the object to the PersistentContent.encode() method, as shown in following example: String data = "This is a secret."; // Encrypt and/or compress the data. Object encoding = PersistentContent.encode( data ); ... // Optionally, persist the encoding.

Decoding an object The decode() method decrypts and/or decompresses an encoded object back to its original form. Before decoding data, you should request a content protection ticket. Always release content protection tickets as soon as you finish using them. Decoding can only be performed when the BlackBerry速 device is unlocked. This can pose a problem if the device locks while an application is performing a lengthy operation that requires the ability to decode encrypted data, such as sorting encrypted records. In this case, the application can obtain a ticket. As long as a strong reference to a ticket exists, decoding encrypted data is allowed. Thus, applications should release tickets as soon as possible to allow the device to reach a locked and secure state.

Code sample Object ticket = PersistentContent.getTicket(); if( ticket != null ){ return( PersistentContent.decodeString( encodedString )); }

58


Development Guide

Implementing content protection

Handling exceptions The PersistentContentException can be thrown when objects protected with content protection are stored in the persistent store. This exception is thrown when an attempt is made to write unencrypted data that was previously encrypted by the content protection framework. To debug a PersistentContentException, obtain a Java速 state dump and an event log. You can use the event log to identify the object that caused the exception. Using that information, you can look in the Java state dump in the IDE, using the Objects window, and identify which object threw the exception, how it's being referenced, and what data it contains. This should make it possible for you to identify whether it's your application that is causing problems, or whether the cause is something else on the BlackBerry速 device.

59


Development Guide

API control and code signing

API control and code signing

4

When you develop a Java® application for BlackBerry® devices, you can use only the public APIs. The BlackBerry® Java® Virtual Machine on the BlackBerry device is designed to protect the underlying data and operating system, so applications cannot call undocumented or unsupported APIs or access data that is not explicitly exposed through the APIs. If you try to use APIs that are not publicly exposed, your application receives an error message at runtime. Public APIs are either open or signed. Signed APIs expose the methods to access BlackBerry device user data or other information on the device that is considered sensitive. You can use signed APIs, but you must request access to a set of code signing keys from Research In Motion®. You must then digitally sign your application before you install it on a device. Code signing does not certify or approve an application, but it allows RIM to identify the author of an application that uses sensitive APIs, if the application is malicious. In addition to API control, code signing can be used with the persistent store or runtime store to restrict access to data by other applications on a device.

Running BlackBerry device applications that use protected APIs To use protected Research In Motion® APIs in your BlackBerry® device application, you must first get code signing keys from RIM. For more information about code signing and to register with RIM to use protected APIs, visit www.blackberry.com/eng/developers/javaappdev/codekeys.jsp. If a BlackBerry device application tries to access protected RIM APIs, the BlackBerry® Java® Plug-in might display warning messages in the Java® editor window or in the Problems view. The warning messages appear next to the lines of application code that reference a protected API. You can suppress these warnings if you test your application on a non-secure device.

Register to use protected BlackBerry APIs 1. 2.

3. 4. 5. 6.

60

Visit www.blackberry.com/JDEKeys and complete the registration form. Save the .csi file that Research In Motion sends to you. The .csi file contains a list of signatures and your registration information. If the BlackBerry® Signing Authority Tool administrator does not provide you with the .csi file or the Registration PIN and you are an ISV partner, contact your ISV Technical Partnership Manager. If you are not an ISV partner, send an email message to jde@rim.com. Double-click the .csi file to start the BlackBerry Signing Authority Tool. If a dialog box appears that states that a private key cannot be found, follow the instructions to create a new key pair file. In the Registration PIN field, type the PIN that RIM provided. In the Private Key Password field, type a password of at least eight characters. The private key password protects your private key. If you lose this password, you must register again with RIM. If this password is stolen, contact RIM immediately.


Running BlackBerry device applications that use protected APIs

Development Guide

7. 8.

Click Register. Click Exit.

Using restricted code signatures The BlackBerry® Signing Authority Tool administrator might place restrictions on your .csi file to limit your access to code signatures. To request changes to these restrictions, contact your administrator. .csi file restriction # of Requests

Expiry Date

Description This restriction specifies the maximum number of requests that you can make by using this .csi file. When you reach the maximum number of requests, the .csi file is no longer valid. To make new code signature requests, you must apply for a new .csi file. Although administrators can permit an infinite number of requests, they often specify a maximum number of requests for security reasons. This restriction specifies the expiry date for your .csi file. After the expiry date, you can no longer make code signature requests with this .csi file. To make new signature requests, you must apply for a new .csi file.

Signing your application Before you begin: To perform this task, you must already have a .csi file that Research In Motion provides. For more information about requesting a .csi file from RIM , visit www.blackberry.com/eng/developers/javaappdev/ codekeys.jsp 1. 2. 3. 4. 5.

In Eclipse®, in the Package Explorer view, right-click a BlackBerry® application project. Click BlackBerry > Sign with Signature Tool. In the Signature Tool dialog box, click Request. Type your private key password. Click OK.

Requesting a replacement registration key Your registration key and .csk file are stored together. If you lose the registration key or the .csk file, you cannot request code signatures. • •

If you are an ISV partner and lose the .csk file, contact your ISV Technical Partnership Manager. If you are not an ISV partner and lose the .cskf file, send an email message to jde@rim.com.

61


Development Guide

Running BlackBerry device applications that use protected APIs

Prevent a BlackBerry device application that runs on the BlackBerry Smartphone Simulator from accessing protected APIs To prevent an application that runs on the BlackBerry速 Smartphone Simulator from accessing protected APIs, you must turn on device security in the BlackBerry Smartphone Simulator. 1. 2. 3. 4. 5. 6. 7.

On the Run menu, click Debug Configurations or Run Configurations. Expand the BlackBerry Simulator item. Select an existing launch configuration for a BlackBerry Smartphone Simulator, or create a new one. Click the Simulator tab. Click the General tab. Select Enable device security. Click Run.

Use a code signing key to help protect packages and classes Before you begin: You must have the internal code signing key, the external code signing key, or both code signing keys that Research In Motion provides. For more information about requesting code signing keys from RIM, visit www.blackberry.com/eng/developers/javaappdev/codekeys.jsp. 1. 2. 3. 4. 5. 6. 7. 8. 9.

Open Eclipse速. Open the project that contains the packages or classes that you want to control access to. In the Navigator view, double-click a .key file. To specify that the .key file is used to protect all public classes, select Use as default for public classes. To specify that the .key file is used to protect all non-public classes, select Use as default for non-public classes. Locate the name of the package that contains the packages and classes that the .key file protects. Expand the package contents. Select each element that requires access control. Click Ok.

Register to use a new code signing key 1. 2. 3. 4. 5.

On the menu, click Preferences. Expand the BlackBerry速 Java速 Plug-in item. Click Signature Tool. Click Install New Keys. Navigate to the location of the signature (.csi) file that you want to add the key to and click the file.

6. 7.

Click Open. Click OK.

62


Development Guide

Running BlackBerry device applications that use protected APIs

Import an existing registered code signing key 1. 2. 3. 4. 5. 6. 7.

On the menu, click Preferences. Expand the BlackBerry® Java® Plug-in item. Click Signature Tool. Click Import Existing Keys. Navigate to the location of the BlackBerry® development environment that you want to import the key from. Select the folder that you want to import the key from. Click OK.

Remove a registered code signing key 1. 2. 3. 4. 5.

On the menu, click Preferences. Expand the BlackBerry® Java® Plug-in item. Click Signature Tool. Click Remove Keys. Click Yes.

6.

Click OK.

View the signature status for code signature requests For files that the Web Signer application has signed, the status is Signed. For files that the Web Signer application did not sign, the status is Failed. The Web Signer application might have rejected the .cod file because the private key password was typed incorrectly. 1. 2. 3. 4.

Open Eclipse®. On the Project menu, click BlackBerry > Sign with Signature Tool. Select a .cod file. View the Status column.

Suppress code signing warnings 1. 2. 3. 4. 5.

On the menu, click Preferences. Expand the BlackBerry Java Plug-in item. Click Warnings. Select the keys for the protected APIs that you do not want to see warnings for. Click OK.

63


Development Guide

Running BlackBerry device applications that use protected APIs

Suppress password prompts from the BlackBerry Signature Tool When you package a BlackBerry® application project, the BlackBerry® Signature Tool prompts you for your signing password. You can save your signing password for the Eclipse® session. 1. 2.

When you are prompted, in the Signing Password dialog box, select Remember password. Click OK.

Sign a BlackBerry application project automatically after packaging 1. 2. 3. 4. 5.

On the menu, click Preferences. Expand the BlackBerry Java Plug-in item. Click Signature Tool. Select Automatically sign the .cod files after packaging. Click OK.

Run the BlackBerry Signature Tool in the background You can run the BlackBerry® Signature Tool automatically after you package your BlackBerry application project. 1. 2. 3. 4. 5.

On the menu, click Preferences. Expand the BlackBerry Java Plug-in item. Click the Signature Tool. Select the Run Signature Tool in background check box. Click OK.

Turn off automatic signature when you package a BlackBerry application project By default, when you package a BlackBerry® application project, the BlackBerry® Signature Tool runs automatically to sign .cod files that access protected APIs. To turn off this feature and run the BlackBerry Signature Tool manually, complete the following tasks: 1. 2. 3. 4. 5.

64

On the menu, click Preferences. Expand the BlackBerry Java Plug-in item. Click the Signature Tool item. Clear the Automatically sign the .cod files after packaging option. Click OK.


Running BlackBerry device applications that use protected APIs

Development Guide

Using code signing keys to restrict access to packages or classes in a BlackBerry library project You can help protect the packages and the classes in your BlackBerry速 library project by using your own code signing key. For more information about the code signing process visit www.blackberry.com/go/devguides to see the BlackBerry Signing Authority Tool Version 1.0 - Password Based Administrator Guide. Note: You can help protect a package or a class with only one private key at a time. Before you begin: You must have a key pair (public key and private key). You can get a key pair by using the BlackBerry速 Signing Authority Tool. To download the BlackBerry Signing Authority Tool visit www.blackberry.com/developers/ downloads. 1.

Complete one of the following tasks: Task Copy a public key (.key) into your BlackBerry library project.

Steps a.

In the Package Explorer view, copy and paste the private key into the /src folder of your BlackBerry library project.

b.

Double-click the private key to open the key editor.

Import a public key (.key) into your a. BlackBerry library prloject. b.

Link a public key (.key) to your BlackBerry library project.

On the File menu, click Import. Expand General and click File System.

c.

Click Next.

d.

In the From directory dialog box, click Browse. Navigate to the location of the private key and click OK.

e.

In the right-hand pane, select the private key.

f.

In the Into folder dialog box, click Browse and navigate to the location of the /src folder of your BlackBerry library project.

g.

Click the src folder and click OK.

h.

Click Finish.

i.

Double-click the private key to open the key editor.

a.

In the Package Explorer view, right-click the /src folder of your BlackBerry library project.

b.

Click New > File.

c.

Click Advanced.

d.

Select the Link to file in the file system option.

e.

Click Browse to navigate to the location of the private key and click Open.

f.

Click Finish.

The key editor opens automatically. 65


Development Guide

2. 3. 4.

Using code signing keys to protect data in applications

In the key editor, select the package or class that you want to restrict access to. Close the key editor and click Save. Package your BlackBerry library project. Access to the .cod file that is created is restricted at runtime.

After you finish: When a BlackBerry device application accesses a package or a class that is protected in the BlackBerry library project, the application's .cod file must be signed with the same private key as the package or class. You can sign the .cod file with the private key by using the File Signer tool in the BlackBerry Signing Authority Tool.

Using code signing keys to protect data in applications Code signing keys can be used to restrict access to data in the persistent store and runtime store. This is a way to control access from other apps on a BlackBerry速 device.

Restrict access to persistent store data using code signing keys Code signing keys can be used to control access to the persistent store. This is a way to restrict or share access with other apps on a BlackBerry速 device. 1.

Import the required classes and interfaces. import java.util.Hashtable; import net.rim.device.api.system.PersistentObject;

2.

Create a hash ID for the object you want to store in a persistent object. long MY_DATA_ID = 0x33abf322367f9018L; Hashtable myHashtable = new Hashtable();

3.

Store the object in the persistent object and protect the object with the CodeSigningKey object. For example, after a BlackBerry device application runs the following line of code, only .cod files that are signed with the RSAE .key file can read or overwrite the object in the persistent object. persistentObject.setContents( new ControlledAccess( myHashtable, key ) );

4.

Make sure that the object is protected, and invoke getContents using the CodeSigningKey object as a parameter. Hashtable myHashtable = (Hashtable) persistentObject.getContents( key );

Restrict access to runtime store data using code signing keys Code signing keys can be used to control access to the runtime store. This is a way to restrict or share access with other apps on a BlackBerry速 device. 1.

66

Import the required classes and interfaces.


Development Guide

Using code signing keys to protect data in applications

import java.util.Hashtable; import net.rim.device.api.system.RuntimeStore;

2.

Create a hash ID for the object you want to store in the runtime store. long MY_DATA_ID = 0x33abf322367f9018L; Hashtable myHashtable = new Hashtable();

3.

Store the object in the runtime store and protect the object with the CodeSigningKey object. Only applications signed with the key can read or change the object. RuntimeStore.put( MY_DATA_ID, new ControlledAccess( myHashtable, key ) );

4.

Make sure that the object is protected with a particular code signing key, and invoke RuntimeStore.get, providing as parameters the hash ID for the object and the CodeSigningKey object.

IT policy support You can use the APIs in the net.rim.device.api.itpolicy package to access the IT policy information on the BlackBerry速 device and change the behavior or functionality of a BlackBerry device application. Each IT policy item consists of a name, a description, and a value. The value can be a string, integer, or Boolean value. BlackBerry device IT policy settings are automatically synchronized and updated over the wireless network with BlackBerry速 Device Software 3.6 or later. With earlier versions of the BlackBerry Device Software, IT policy settings are updated when the device user synchronizes the BlackBerry device with the computer. For more information about IT policies, see the BlackBerry Enterprise Server Policy Reference Guide.

Application control The BlackBerry速 Enterprise Server application control policy rules are designed to allow or prevent the installation of specific applications on the BlackBerry device and to limit the permissions of applications on the device. For example, administrators can use the application control policy to make sure that a game application on the device cannot access the phone application. The administrator can apply application control policies only when the device is associated with a BlackBerry Enterprise Server. If the administrator or a device user denies the application access to one of the protected areas, the application throws a ControlledAccessException.

67


Development Guide

Find more information • • • • •

68

Find more information

5

www.blackberry.com/go/apiref: View the latest version of the API reference for the BlackBerry® Java® SDK. www.blackberry.com/go/devguides: Find development guides, release notes, and sample application overviews for the BlackBerry Java SDK. www.blackberry.com/developers: Visit the BlackBerry® Developer Zone for resources on developing BlackBerry device applications. www.blackberry.com/go/developerkb: View knowledge base articles on the BlackBerry Development Knowledge Base. www.blackberry.com/developers/downloads: Find the latest development tools and downloads for developing BlackBerry device applications.


Development Guide

Glossary

Glossary

6

AES Advanced Encryption Standard ARC4 Alleged Rivest's Cipher 4 BlackBerry transport layer encryption BlackBerry transport layer encryption (formerly known as standard BlackBerry encryption) uses a symmetric key encryption algorithm to help protect data that is in transit between a BlackBerry device and the BlackBerry速 Enterprise Server when the data is outside an organization's firewall. BlackBerry Enterprise Server environment A BlackBerry速 Enterprise Server environment consists of one or more BlackBerry Domain instances, a messaging server, and any third-party software and hardware that the BlackBerry Enterprise Server components interact with. CAST Carlisle Adams Stafford Tavares CBC cipher block chaining certificate A certificate is a digital document that binds the identity and public key of a certificate subject. Each certificate has an corresponding private key that is stored separately. A certificate authority signs the certificate to indicate that it is authentic and can be trusted. CFB cipher feedback CLDC Connected Limited Device Configuration code-signing keys Code-signing keys are the keys that are stored on media cards that sign files so that a user can install and run the files on a BlackBerry device. content protection Content protection helps protect user data on a locked BlackBerry device by encrypting the user data using the content protection key and ECC private key. content protection key 69


Development Guide

Glossary

The content protection key encrypts user data on a BlackBerry device when the device is locked. CTR click-through rate DES Data Encryption Standard device transport key The device transport key (formerly known as the master encryption key) is unique to a BlackBerry device. The BlackBerry device and BlackBerry速 Enterprise Server use the device transport key to encrypt the message keys. DH Diffie-Hellman DHE Diffie-Hellman Ephemeral DSA Digital Signature Algorithm ECB electronic code book ECC Elliptic Curve Cryptography ECDH Elliptic Curve Diffie-Hellman ECDSA Elliptic Curve Digital Signature Algorithm ECIES Elliptic Curve Integrated Encryption Standard ECMQV Elliptic Curve Menezes-Qu-Vanstone ECNR Elliptic Curve Nyberg Rueppel ephemeral key The ephemeral key encrypts the ECC public key, ECC private key, and content protection key.

70


Development Guide

Glossary

FIPS Federal Information Processing Standards flash memory The flash memory is an internal file system on a BlackBerry device that stores application data and user data. HMAC keyed-hash message authentication code HTTPS Hypertext Transfer Protocol over Secure Sockets Layer IT policy An IT policy consists of various IT policy rules that control the security features and behavior of BlackBerry devices, BlackBerry enabled devices, the BlackBerry® Desktop Software, and the BlackBerry® Web Desktop Manager. IT policy rule An IT policy rule permits you to customize and control the actions that BlackBerry devices, BlackBerry enabled devices, the BlackBerry® Desktop Software, and the BlackBerry® Web Desktop Manager can perform. JDK Java® Development Kit JVM Java® Virtual Machine Java ME Java® Platform, Micro Edition KEA Key Exchange Algorithm MAC message authentication code MIDP Mobile Information Device Profile OAEP Optimal Asymmetric Encryption Padding OFB output feedback

71


Development Guide

Glossary

PIN personal identification number PKCS Public-Key Cryptography Standards principal encryption key The principal encryption key encrypts the device transport key when a BlackBerry device is locked if content protection is turned on. PRNG pseudorandom number generator PSS Probabilistic Signature Scheme RACE Research and Development in Advanced Communications Technologies in Europe RC Rivest's Cipher RIM signing authority system The RIM速 signing authority system is a collection of servers that sign the boot ROM code for a BlackBerry device during the manufacturing process. RIPEMD RACE Integrity Primitives Evaluation Message Digest root certificate A root certificate is a self-signed certificate and usually belongs to a certificate authority. SHA Secure Hash Algorithm S/MIME Secure Multipurpose Internet Mail Extensions TCP/IP Transmission Control Protocol/Internet Protocol (TCP/IP) is a set of communication protocols that is used to transmit data over networks, such as the Internet. Triple DES Triple Data Encryption Standard 72


Development Guide

Glossary

WAP Wireless Application Protocol WTLS Wireless Transport Layer Security

73


Development Guide

Provide feedback To provide feedback on this deliverable, visit www.blackberry.com/docsfeedback.

74

Provide feedback

7


Document revision history

Development Guide

Document revision history Date 14 March 2011

8

Description Initial version.

75


Development Guide

Legal notice

Legal notice

9

息2011 Research In Motion Limited. All rights reserved. BlackBerry速, RIM速, Research In Motion速, and related trademarks, names, and logos are the property of Research In Motion Limited and are registered and/or used in the U.S. and countries around the world. ANSI is a trademark of the American National Standards Institute. Java is a trademark of Oracle America, Inc. Eclipse is a trademark of Eclipse Foundation, Inc. RSA is a trademark of RSA Security. SQLite is a trademark of Hipp, Wyrick & Company, Inc. All other trademarks are the property of their respective owners. This documentation including all documentation incorporated by reference herein such as documentation provided or made available at www.blackberry.com/go/docs is provided or made accessible "AS IS" and "AS AVAILABLE" and without condition, endorsement, guarantee, representation, or warranty of any kind by Research In Motion Limited and its affiliated companies ("RIM") and RIM assumes no responsibility for any typographical, technical, or other inaccuracies, errors, or omissions in this documentation. In order to protect RIM proprietary and confidential information and/or trade secrets, this documentation may describe some aspects of RIM technology in generalized terms. RIM reserves the right to periodically change information that is contained in this documentation; however, RIM makes no commitment to provide any such changes, updates, enhancements, or other additions to this documentation to you in a timely manner or at all. This documentation might contain references to third-party sources of information, hardware or software, products or services including components and content such as content protected by copyright and/or third-party web sites (collectively the "Third Party Products and Services"). RIM does not control, and is not responsible for, any Third Party Products and Services including, without limitation the content, accuracy, copyright compliance, compatibility, performance, trustworthiness, legality, decency, links, or any other aspect of Third Party Products and Services. The inclusion of a reference to Third Party Products and Services in this documentation does not imply endorsement by RIM of the Third Party Products and Services or the third party in any way. EXCEPT TO THE EXTENT SPECIFICALLY PROHIBITED BY APPLICABLE LAW IN YOUR JURISDICTION, ALL CONDITIONS, ENDORSEMENTS, GUARANTEES, REPRESENTATIONS, OR WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY CONDITIONS, ENDORSEMENTS, GUARANTEES, REPRESENTATIONS OR WARRANTIES OF DURABILITY, FITNESS FOR A PARTICULAR PURPOSE OR USE, MERCHANTABILITY, MERCHANTABLE QUALITY, NON-INFRINGEMENT, SATISFACTORY QUALITY, OR TITLE, OR ARISING FROM A STATUTE OR CUSTOM OR A COURSE OF DEALING OR USAGE OF TRADE, OR RELATED TO THE DOCUMENTATION OR ITS USE, OR PERFORMANCE OR NON-PERFORMANCE OF ANY SOFTWARE, HARDWARE, SERVICE, OR ANY THIRD PARTY PRODUCTS AND SERVICES REFERENCED HEREIN, ARE HEREBY EXCLUDED. YOU MAY ALSO HAVE OTHER RIGHTS THAT VARY BY STATE OR PROVINCE. SOME JURISDICTIONS MAY NOT ALLOW THE EXCLUSION OR LIMITATION OF IMPLIED WARRANTIES AND CONDITIONS. TO THE EXTENT PERMITTED BY LAW, ANY IMPLIED WARRANTIES OR CONDITIONS RELATING TO THE DOCUMENTATION TO THE EXTENT THEY CANNOT BE EXCLUDED AS SET OUT ABOVE, BUT CAN BE LIMITED, ARE HEREBY LIMITED TO NINETY (90) DAYS FROM THE DATE YOU FIRST ACQUIRED THE DOCUMENTATION OR THE ITEM THAT IS THE SUBJECT OF THE CLAIM. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW IN YOUR JURISDICTION, IN NO EVENT SHALL RIM BE LIABLE FOR ANY TYPE OF DAMAGES RELATED TO THIS DOCUMENTATION OR ITS USE, OR PERFORMANCE OR NONPERFORMANCE OF ANY SOFTWARE, HARDWARE, SERVICE, OR ANY THIRD PARTY PRODUCTS AND SERVICES REFERENCED HEREIN INCLUDING WITHOUT LIMITATION ANY OF THE FOLLOWING DAMAGES: DIRECT, 76


Development Guide

Legal notice

CONSEQUENTIAL, EXEMPLARY, INCIDENTAL, INDIRECT, SPECIAL, PUNITIVE, OR AGGRAVATED DAMAGES, DAMAGES FOR LOSS OF PROFITS OR REVENUES, FAILURE TO REALIZE ANY EXPECTED SAVINGS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, LOSS OF BUSINESS OPPORTUNITY, OR CORRUPTION OR LOSS OF DATA, FAILURES TO TRANSMIT OR RECEIVE ANY DATA, PROBLEMS ASSOCIATED WITH ANY APPLICATIONS USED IN CONJUNCTION WITH RIM PRODUCTS OR SERVICES, DOWNTIME COSTS, LOSS OF THE USE OF RIM PRODUCTS OR SERVICES OR ANY PORTION THEREOF OR OF ANY AIRTIME SERVICES, COST OF SUBSTITUTE GOODS, COSTS OF COVER, FACILITIES OR SERVICES, COST OF CAPITAL, OR OTHER SIMILAR PECUNIARY LOSSES, WHETHER OR NOT SUCH DAMAGES WERE FORESEEN OR UNFORESEEN, AND EVEN IF RIM HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW IN YOUR JURISDICTION, RIM SHALL HAVE NO OTHER OBLIGATION, DUTY, OR LIABILITY WHATSOEVER IN CONTRACT, TORT, OR OTHERWISE TO YOU INCLUDING ANY LIABILITY FOR NEGLIGENCE OR STRICT LIABILITY. THE LIMITATIONS, EXCLUSIONS, AND DISCLAIMERS HEREIN SHALL APPLY: (A) IRRESPECTIVE OF THE NATURE OF THE CAUSE OF ACTION, DEMAND, OR ACTION BY YOU INCLUDING BUT NOT LIMITED TO BREACH OF CONTRACT, NEGLIGENCE, TORT, STRICT LIABILITY OR ANY OTHER LEGAL THEORY AND SHALL SURVIVE A FUNDAMENTAL BREACH OR BREACHES OR THE FAILURE OF THE ESSENTIAL PURPOSE OF THIS AGREEMENT OR OF ANY REMEDY CONTAINED HEREIN; AND (B) TO RIM AND ITS AFFILIATED COMPANIES, THEIR SUCCESSORS, ASSIGNS, AGENTS, SUPPLIERS (INCLUDING AIRTIME SERVICE PROVIDERS), AUTHORIZED RIM DISTRIBUTORS (ALSO INCLUDING AIRTIME SERVICE PROVIDERS) AND THEIR RESPECTIVE DIRECTORS, EMPLOYEES, AND INDEPENDENT CONTRACTORS. IN ADDITION TO THE LIMITATIONS AND EXCLUSIONS SET OUT ABOVE, IN NO EVENT SHALL ANY DIRECTOR, EMPLOYEE, AGENT, DISTRIBUTOR, SUPPLIER, INDEPENDENT CONTRACTOR OF RIM OR ANY AFFILIATES OF RIM HAVE ANY LIABILITY ARISING FROM OR RELATED TO THE DOCUMENTATION. Prior to subscribing for, installing, or using any Third Party Products and Services, it is your responsibility to ensure that your airtime service provider has agreed to support all of their features. Some airtime service providers might not offer Internet browsing functionality with a subscription to the BlackBerry速 Internet Service. Check with your service provider for availability, roaming arrangements, service plans and features. Installation or use of Third Party Products and Services with RIM's products and services may require one or more patent, trademark, copyright, or other licenses in order to avoid infringement or violation of third party rights. You are solely responsible for determining whether to use Third Party Products and Services and if any third party licenses are required to do so. If required you are responsible for acquiring them. You should not install or use Third Party Products and Services until all necessary licenses have been acquired. Any Third Party Products and Services that are provided with RIM's products and services are provided as a convenience to you and are provided "AS IS" with no express or implied conditions, endorsements, guarantees, representations, or warranties of any kind by RIM and RIM assumes no liability whatsoever, in relation thereto. Your use of Third Party Products and Services shall be governed by and subject to you agreeing to the terms of separate licenses and other agreements applicable thereto with third parties, except to the extent expressly covered by a license or other agreement with RIM. Certain features outlined in this documentation require a minimum version of BlackBerry速 Enterprise Server, BlackBerry速 Desktop Software, and/or BlackBerry速 Device Software.

77


Development Guide

Legal notice

The terms of use of any RIM product or service are set out in a separate license or other agreement with RIM applicable thereto. NOTHING IN THIS DOCUMENTATION IS INTENDED TO SUPERSEDE ANY EXPRESS WRITTEN AGREEMENTS OR WARRANTIES PROVIDED BY RIM FOR PORTIONS OF ANY RIM PRODUCT OR SERVICE OTHER THAN THIS DOCUMENTATION.

Research In Motion Limited 295 Phillip Street Waterloo, ON N2L 3W8 Canada Research In Motion UK Limited Centrum House 36 Station Road Egham, Surrey TW20 9LF United Kingdom Published in Canada

78


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.