Local security protects WebSphere MQ Everyplace message or MQeFields data locally. This is achieved by creating an attribute with an appropriate symmetric cryptor and compressor, creating and setting up an appropriate key, by providing a password. The key is explicitly attached to the attribute, and the attribute is attached to the WebSphere MQ Everyplace message. WebSphere MQ Everyplace provides the MQeLocalSecure Java class and C API to assist with the setup of local security, but in all cases it is the responsibility of the local security user (WebSphere MQ Everyplace internally or a WebSphere MQ Everyplace application) to set up an appropriate attribute and manage the password key.
Local security provides protection for WebSphere MQ Everyplace data, MQeFields objects, including Java message objects, for example MQeMsgObject. The protected data is returned in a byte array. To apply local security to a data object you must:
The authenticator determines how access to the data is controlled. It is invoked every time a piece of data is acessed. The cryptor determines the cryptographic strength protecting the data confidentiality. The compressor determines the amount of storage required by the message.
WebSphere MQ Everyplace provides the MQeLocalSecure class to assist with the use of local security. However, it is the responsibility of the local security user to setup an appropriate attribute and provide the password. MQeLocalSecure provides the function to protect the data and to save and restore it from backing storage. If an application chooses to attach an attribute to a message without using MQeLocalSecure, it also needs to save the data after using dump and must retrieve the data before using restore.
Consider a scenario where mobile agents working on many different customer sites want to ensure that the confidential data of one customer is not accidentally shared with another. Local security features, using different keys, and possibly different cryptographic strengths, provide a simple method for protecting different customer data held on a single machine .
A simple extension of this scenario could be that the protected local data is accessed using a key that is pulled from a secure queue on an WebSphere MQ Everyplace server node. The agents client has to authenticate itself to access the server queue and pull the local key data, but never knows the actual key.
One of the advantages of taking this approach is that an audit trail is easily accumulated for all access to customer specific data.
When using local security, WebSphere MQ Everyplace provides attribute choices for authentication, encryption, and compression. The algorithms supported by WebSphere MQ Everyplace for authentication, encryption, and compression are listed in Table 4.
Function | Algorithm |
---|---|
Authentication | WTLS mini-certificate (NTAuthenticator or UserIdAuthenticator, Java only) |
Validation Windows NT, Windows 2000, AIX, or Solaris identity | |
WinCEAuthenticator (C only) | |
Compression | LZW (Java only) |
RLE (Java and C) | |
GZIP (Java only) | |
Encryption | Triple DES (Java only) |
DES (Java only) | |
MARS (Java only) | |
RC4 (Java and C) | |
RC6 (Java only) | |
XOR (Java only) |
You can use your own implementations of authenticators, provided that your cryptor is symmetric.
You should use an authenticator if you need to provide additional controls to prevent access to the local data by unauthorized users. In some ways using an authenticator is unnecessary since providing the key password automatically limits access to those who know this secret.
Queue-based security, uses mini-certificate based mutual authentication, and message-level protection.
The choice of cryptor is driven by the strength of protection required. The stronger the encryption, the more difficulty an attacker would face when trying to get illegal access to the data. Data protected with symmetric ciphers that use 128 bit keys is acknowledged as more difficult to attack than data protected using ciphers that use shorter keys. However, in addition to cryptographic strength, the selection of a cryptor may also be driven by many other factors. An example is that some financial solutions require the use of triple DES in order to get audit approval.
You should use a compressor if you need to optimize the size of the protected data. However, the effectiveness of the compressor depends on the content of the data. The Java MQeRleCompressor and the C MQE_RLE_COMPRESSOR perform run length encoding. This means that the compressor routines compress or expand repeated bytes. Hence it is effective in compressing and decompressing data with many repeated bytes. MQeLZWCompressor uses the LZW scheme. The simplest form of the LZW algorithm uses a dictionary data structure in which various words, or data patterns, are stored against different codes. This compressor is likely to be most effective where the data has a significant number of repeating words, or data patterns. The MQeGZIPCompressor uses the same compression algorithm as the gzip command on UNIX. This searches for repeating patterns in the data and replaces subsequent occurrences of a pattern with a reference back to the first occurrence of the pattern.
try { .../* SIMPLE UNPROTECT FRAGMENT */ .../* instantiate a DES cryptor */ MQeDESCryptor desC = new MQeDESCryptor( ); .../* instantiate an attribute using the DES cryptor */ MQeAttribute desA = new MQeAttribute( null, desC, null); .../* instantiate a (a helper) LocalSecure object */ MQeLocalSecure ls = new MQeLocalSecure( ); .../* open LocalSecure obj identifying target file and directory */ ls.open( ".\\", "TestSecureData.txt" ); /*instantiate a MQeFields object */ MQeFields myData =new MQeFields(); /*add some test data */ myData.putAscii("testdata","0123456789abcdef...."); .../* use LocalSecure write to protect data*/ ls.write( myData.dump(), desA, "It_is_a_secret" ) ); ... } catch ( Exception e ) { e.printStackTrace(); /* show exception */ } try { .../* SIMPLE UNPROTECT FRAGMENT */ .../* instantiate a DES cryptor */ MQeDESCryptor des2C = new MQeDESCryptor( ); .../* instantiate an attribute using the DES cryptor */ MQeAttribute des2A = new MQeAttribute( null, des2C, null); .../* instantiate a (a helper) LocalSecure object */ MQeLocalSecure ls2 = new MQeLocalSecure( ); .../* open LocalSecure obj identifying target file and directory */ ls2.open( ".\\", "TestSecureData.txt" ); .../* use LocalSecure read to restore from target and decode data*/ String outData = MQe.byteToAscii( ls2.read( desA2, "It_is_a_secret")); .../* show results.... */ trace ( "i: test data out = " + outData); ... } catch ( Exception e ) { e.printStackTrace(); /* show exception */ }
try { .../*SIMPLE PROTECT FRAGMENT */ .../*instantiate a DES cryptor */ MQeDESCryptor desC = new MQeDESCryptor(); .../*instantiate an Attribute using the DES cryptor */ MQeAttribute attr = new MQeAttribute(null,desC,null); .../*instantiate a base Key object */ MQeKey localkey = new MQeKey(); .../*set the base Key object local key */ localkey.setLocalKey("my secret key"); .../*attach the key to the attribute */ attr.setKey(localkey); /*instantiate an MQeFields object */ MQeFields myData = new MQeFields(); /*attach the attribute to the data object */ myData.setAttribute(attr); /*add some test data */ myData.putAscii("testdata", "0123456789abcdef...."); trace ("i:test data in = " + myData.getAscii("testdata")); /*encode the data */ byte [] protectedData = myData.dump(); trace ("i:protected test data = " + MQe.byteToAscii(protectedData)); } catch (Exception e ) { e.printStackTrace(); /*show exception */ } try { .../*SIMPLE UNPROTECT FRAGMENT */ .../*instantiate a DES cryptor */ MQeDESCryptor desC2 = new MQeDESCryptor(); .../*instantiate an Attribute using the DES cryptor */ MQeAttribute attr2 = new MQeAttribute(null,desC2,null); .../*instantiate a base Key object */ MQeKey localkey2 = new MQeKey(); .../*set the base Key object local key */ localkey2.setLocalKey("my secret key"); .../*attach the key to the attribute */ attr2.setKey(localkey2 ); /*instantiate a new data object */ MQeFields myData2 = new MQeFields(); /*attach the attribute to the data object */ myData2.setAttribute(attr2 ); /*decode the data */ myData2.restore(protectedData ); /*show the unprotected test data */ trace ("i:test data out = " + myData2.getAscii("testdata")); } catch (Exception e ) { e.printStackTrace(); /*show exception */ }
/* write to a file */ MQeFieldsAttrHndl hAttr = NULL; MQeStringHndl hKeySeed = NULL, hDir = NULL, hFile = NULL; MQeStringHndl hFieldName = NULL, hFieldData = NULL; MQeExceptBlock exceptBlock; MQeLocalSecureHndl hLocalSecure = NULL; MQeFieldsHndl hData = NULL; MQEBYTE outBuf[128]; MQEINT32 bufLen = 128; MQERETURN rc; /* create a key seed string */ rc = mqeString_newChar8(&exceptBlock, &hKeySeed, "my secret key"); /* create a new attribute with a RC4 cryptor */ rc = mqeFieldsAttr_new(&exceptBlock, hAttr, NULL, MQE_RC4_CRYPTOR_CLASS_NAME, NULL, hKeySeed); /* create a dir string */ rc = mqeString_newChar8( &exceptBlock, &hDir, ".\\"); /* create a file name string */ rc = mqeString_newChar8( &exceptBlock, &hFile, "localSecureFile.txt"); /* create an MQeLocalSecure */ rc = mqeLocalSecure_new( &exceptBlock, &hLocalSecure); /* open file */ rc = mqeLocalSecure_open(hLocalSecure, &exceptBlock, hDir, hFile); /* create a data Fields */ rc = mqeFields_new(&exceptBlock, &hData); /* add some test data */ rc = mqeString_newChar8(&exceptBlock, &hFieldName, "testdata"); rc = mqeString_newChar8(&exceptBlock, &hFieldData, "0123456789abcdef...."); rc = mqeFields_putAscii(hData, &exceptBlock, hFieldName, hFieldData); /* dump (protect) data Fields */ rc = mqeFields_dump(hData, &exceptBlock, outBuf, &buflen); /* write to .\\ocalSecureFile.txt */ rc = mqeLocalSecure_write(hLocalSecure, &exceptBlock, outBuf, bufLen, hAttr, NULL); /* read from a file */ MQeFieldsAttrHndl hAttr = NULL; MQeStringHndl hKeySeed = NULL, hDir = NULL, hFile = NULL; MQeStringHndl hFieldName = NULL, hFieldData = NULL; MQeExceptBlock exceptBlock; MQeLocalSecureHndl hLocalSecure = NULL; MQERETURN rc; MQEBYTE outBuf[128]; MQEINT32 bufLen = 128; /* create a key seed string */ rc = mqeString_newChar8(&exceptBlock, &hKeySeed, "my secret key"); /* create a new attribute with a RC4 cryptor */ rc = mqeFieldsAttr_new(&exceptBlock, &hAttr, NULL, MQE_RC4_CRYPTOR_CLASS_NAME, NULL, hKeySeed); /* create a dir string */ rc = mqeString_newChar8( &exceptBlock, &hDir, ".\\"); /* create a file name string */ rc = mqeString_newChar8( &exceptBlock, &hFile, "localSecureFile.txt"); /* create an MQeLocalSecure */ rc = mqeLocalSecure_new( &exceptBlock, &hLocalSecure); /* open file */ rc = mqeLocalSecure_open(hLocalSecure, &exceptBlock, hDir, hFile); /* read from .\\ocalSecureFile.txt */ rc = mqeLocalSecure_read(hLocalSecure, &exceptBlock, outBuf, &Buflen, hAttr, NULL); /* create a data Fields */ rc = mqeFields_new(&exceptBlock, &hData); /* restore data Fields */ rc = mqeFields_restore(hData, &exceptBlock, outBuf, bufLen); /* read test data */ rc = mqeString_newChar8(&exceptBlock, &hFieldName, "testdata"); rc = mqeFields_getAscii(hData, &exceptBlock, &hFieldData, hFieldName);
/* dump to a buffer */ MQeFieldsAttrHndl hAttr = NULL; MQeStringHndl hKeySeed = NULL, hFieldName = NULL, hFieldData = NULL; MQeExceptBlock exceptBlock; MQeFieldsHndl hData = NULL; MQEBYTE outBuf[128]; MQEINT32 bufLen = 128; MQERETURN rc; /* create a key seed string */ rc = mqeString_newChar8(&exceptBlock, &hKeySeed, "my secret key"); /* create a new attribute with a RC4 cryptor */ rc = mqeFieldsAttr_new(&exceptBlock, &hAttr, NULL, MQE_RC4_CRYPTOR_CLASS_NAME, NULL, hKeySeed); /* create a data Fields */ rc = mqeFields_new(&exceptBlock, &hData); /* set the attribute to the data Fields */ rc = mqeFields_setAttribute(hData, &exceptBlock, hAttr); /* add some test data */ rc = mqeString_newChar8(&exceptBlock, &hFieldName, "testdata"); rc = mqeString_newChar8(&exceptBlock, &hFieldData, "0123456789abcdef...."); rc = mqeFields_putAscii(hData, &exceptBlock, hFieldName, hFieldData); /* dump (protect) data Fields */ rc = mqeFields_dump(hData, &exceptBlock, outBuf, &bufLen); /* restor from a buffer */ MQeFieldsAttrHndl hAttr = NULL; MQeStringHndl hKeySeed = NULL, hFieldName = NULL, hFieldData = NULL; MQeExceptBlock exceptBlock; MQERETURN rc; MQEBYTE outBuf[128]; MQEINT32 bufLen = 128; ... /* assume protected data is in inBuf and its length is in bufLen */ /* create a key seed string */ rc = mqeString_newChar8(&exceptBlock, &hKeySeed, "my secret key"); /* create a new attribute with a RC4 cryptor */ rc = mqeFieldsAttr_new(&exceptBlock, &hAttr, NULL, MQE_RC4_CRYPTOR_CLASS_NAME, NULL, hKeySeed); /* create a data Fields */ rc = mqeFields_new(&exceptBlock, &hData); /* set the attribute to the data Fields */ rc = mqeFields_setAttribute(hData, &exceptBlock, hAttr); /* restore data Fields */ rc = mqeFields_restore(hData, &exceptBlock, inBuf, bufLen); /* read test data */ rc = mqeString_newChar8(&exceptBlock, &hFieldName, "testdata"); rc = mqeFields_getAscii(hData, &exceptBlock, &hFieldData, hFieldName);