Local security provides protection for WebSphere MQ Everyplace data or MQeFields objects, including message, MQeMsg, objects. 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. The cryptor determines the cryptographic strength protecting the data confidentiality. The compressor determines the 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 or passphrase key. 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 function 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 MQeLocalSecure, the following attribute choices are available:
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 or passphrase automatically limits access to those who know this secret.
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 MQeRleCompressor performs 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 (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 (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.
/*SIMPLE PROTECT FRAGMENT */ #define BUF_LENGTH 1000 /* assuming this is big enough */ MQeDESCryptorHndl desC; MQeAttributeHndl attr; MQeKeyHndl localkey; MQeFieldsHndl myData; MQEBYTE protectedData[BUF_LENGTH]; MQEINT32 bufLength = BUF_LENGTH; MQERETURN rc; MQeExceptBlock exceptBlock; /*instantiate a DES cryptor */ rc = mqeDESCryptor_new(&exceptBlock, &desC); /*instantiate an Attribute using the DES cryptor */ rc = mqeAttribute_new(&exceptBlock, &attr, NULL, NULL, desC, NULL); /*instantiate a base Key object */ rc = mqeKey_new(&exceptBlock, &localKey); /*set the base Key object local key */ rc = mqeKey_setLocalKey(localKey, &exceptBlock, MQeString("my secret key")); /*attach the key to the attribute */ rc = mqeAttribute_setKey(attr, &exceptBlock, localkey); /*instantiate a MQeFields object */ rc = mqeFields_new(&exceptBlock, &myData); /*attach the attribute to the data object */ mqeFields_setAttribute(myData, &exceptBlock, attr); /*add some test data */ rc = mqeFields_putAscii(myData, &exceptBlock, MQeString("testdata"), MQeString("0123456789abcdef....")); /*encode the data */ rc = mqeFields_dump(myData, &exceptBlock, protectedData, &bufLength, MQE_FALSE); /* SIMPLE UNPROTECT FRAGMENT */ #define BUF_LENGTH 1000 /* assuming this is big enough */ MQeDESCryptorHndl desC2; MQeAttributeHndl attr2; MQeLocalSecureHndl ls2; MQEBYTE outBuf[BUF_LENGTH]; MQEINT32 bufLength = BUF_LENGTH; MQERETURN rc; MQeExceptBlock exceptBlock; /* instantiate a DES cryptor */ rc = mqeDESCryptor_new(&exceptBlock, &desC2); /* instantiate an attribute using the DES cryptor */ rc = mqeAttribute_new(&exceptBlock, &attr2, NULL, NULL, des2C, NULL); /* instantiate a (a helper) LocalSecure object */ rc = mqeLocalSecure_new(&exceptBlock, &ls2); /* open LocalSecure obj identifying target file and directory */ rc = mqeString_newChar8(&exceptBlock, &fileDir, ".\\"); rc = mqeLocalSecure_open(ls2, &exceptBlock, MQeString(".\\"), MQeString("TestSecureData.txt")); /* use LocalSecure read to restore from target and decode data */ rc = mqeLocalSecure_read(ls2, &exceptBlock, outBuf, &bufLength, attr2, MQeString("my secret key"));
/*SIMPLE PROTECT FRAGMENT */ #define BUF_LENGTH 1000 /* assuming this is big enough */ MQeDESCryptorHndl desC; MQeAttributeHndl attr; MQeKeyHndl localkey; MQeFieldsHndl myData; MQEBYTE protectedData[BUF_LENGTH]; MQEINT32 bufLength = BUF_LENGTH; MQERETURN rc; MQeExceptBlock exceptBlock; /*create a DES cryptor */ rc = mqeDESCryptor_new(&exceptBlock, &desC); /*create an Attribute using the DES cryptor */ rc = mqeAttribute_new(&exceptBlock,&attr, NULL, NULL, desC, NULL); /*create a base Key object */ rc = mqeKey_new(&exceptBlock, &localKey); /*set the base Key object local key */ rc = mqeKey_setLocalKey(localKey, &exceptBlock, MQeString("my secret key")); /*attach the key to the attribute */ rc = mqeAttribute_setKey(attr, &exceptBlock, localkey); /*create a MQeFields object */ rc = mqeFields_new(&exceptBlock, &myData); /*attach the attribute to the data object */ mqeFields_setAttribute(myData, &exceptBlock, attr); /*add some test data */ rc = mqeFields_putAscii(myData, &exceptBlock, MQeString("testdata"), MQeString("0123456789abcdef....")); /*encode the data */ rc = mqeFields_dump(myData, &exceptBlock, protectedData, &bufLength, MQE_FALSE); /* SIMPLE UNPROTECT FRAGMENT */ #define BUF_LENGTH 1000 /* assuming this is big enough */ MQeDESCryptorHndl desC2; MQeAttributeHndl attr2; MQeKeyHndl localKey2; MQeFieldsHndl myData2; MQEBYTE protectedData[BUF_LENGTH]; MQEINT32 bufLength = BUF_LENGTH; MQERETURN rc; MQeExceptBlock exceptBlock; /* read protected data into protectedData and set bufLength to the data length */ ... /* create a DES cryptor */ rc = mqeDESCryptor_new(&exceptBlock, &desC2); /*create an attribute using the DES cryptor */ rc = mqeAttribute_new(&exceptBlock, &attr2, NULL, NULL, des2C, NULL); /* create a (a helper) LocalSecure object */ rc = mqeKey_new(&exceptBlock, &localKey); /*set the base Key object local key */ rc = mqeKey_setLocalKey(localKey2, &exceptBlock, MQeString("my secret key")); /*attach the key to the attribute */ mqeAttribute_setKey(attr2, &exceptBlock, localkey2); /*create a new data object */ rc = mqeFields_new(&exceptBlock, &myData); /*attach the attribute to the data object */ mqeFields_setAttribute(myData2, &exceptBlock, attr2); /*decode the data */ mqeFields_restore(myData2, &exceptBlock, protectedData, bufLength, MQE_FALSE);