--- /dev/null
+/*
+ File: cryptTool.c
+
+ Description: simple encrypt/decrypt utility to demonstrate CDSA API
+ used for symmetric encryption
+
+ Author: dmitch
+
+ Copyright: Copyright (c) 2001,2003,2005-2006 Apple Computer, Inc. All Rights Reserved.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
+ Computer, Inc. ("Apple") in consideration of your agreement to
+ the following terms, and your use, installation, modification
+ or redistribution of this Apple software constitutes acceptance
+ of these terms. If you do not agree with these terms, please
+ do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following
+ terms, and subject to these terms, Apple grants you a personal,
+ non-exclusive license, under Apple's copyrights in this
+ original Apple software (the "Apple Software"), to use,
+ reproduce, modify and redistribute the Apple Software, with
+ or without modifications, in source and/or binary forms;
+ provided that if you redistribute the Apple Software in
+ its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all
+ such redistributions of the Apple Software. Neither the
+ name, trademarks, service marks or logos of Apple Computer,
+ Inc. may be used to endorse or promote products derived from the
+ Apple Software without specific prior written permission from
+ Apple. Except as expressly stated in this notice, no other
+ rights or licenses, express or implied, are granted by Apple
+ herein, including but not limited to any patent rights that
+ may be infringed by your derivative works or by other works
+ in which the Apple Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis.
+ APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT,
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
+ REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE
+ OR IN COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT,
+ INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION
+ AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
+ AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING
+ NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE
+ HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "common.h"
+#include <security_cdsa_utils/cuFileIo.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+static void usage(char **argv)
+{
+ printf("usage:\n");
+ printf(" %s op password keySize inFile outFile [a=algorithm]\n", argv[0]);
+ printf(" op:\n");
+ printf(" e encrypt\n");
+ printf(" d decrypt\n");
+ printf(" algorithm:\n");
+ printf(" 4 RC4 (default if no algorithm specified)\n");
+ printf(" c ASC/ComCryption\n");
+ printf(" d DES\n");
+ printf(" a AES\n");
+ exit(1);
+}
+
+/*
+ * Derive symmetric key.
+ */
+static CSSM_RETURN ctDeriveKey(CSSM_CSP_HANDLE cspHand,
+ uint32 keyAlg, // CSSM_ALGID_RC5, etc.
+ const char *keyLabel,
+ unsigned keyLabelLen,
+ uint32 keyUsage, // CSSM_KEYUSE_ENCRYPT, etc.
+ uint32 keySizeInBits,
+ CSSM_DATA_PTR password, // in PKCS-5 lingo
+ CSSM_DATA_PTR salt, // ditto
+ uint32 iterationCnt, // ditto
+ CSSM_KEY_PTR key)
+{
+ CSSM_RETURN crtn;
+ CSSM_CC_HANDLE ccHand;
+ uint32 keyAttr;
+ CSSM_DATA dummyLabel;
+ CSSM_PKCS5_PBKDF2_PARAMS pbeParams;
+ CSSM_DATA pbeData;
+ CSSM_ACCESS_CREDENTIALS creds;
+
+ memset(key, 0, sizeof(CSSM_KEY));
+ memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
+ crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand,
+ CSSM_ALGID_PKCS5_PBKDF2,
+ keyAlg,
+ keySizeInBits,
+ &creds,
+ NULL, // BaseKey
+ iterationCnt,
+ salt,
+ NULL, // seed
+ &ccHand);
+ if(crtn) {
+ printError("CSSM_CSP_CreateDeriveKeyContext", crtn);
+ return crtn;
+ }
+ keyAttr = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_RETURN_REF |
+ CSSM_KEYATTR_SENSITIVE;
+ dummyLabel.Length = keyLabelLen;
+ dummyLabel.Data = (uint8 *)keyLabel;
+
+ /* passing in password is pretty strange....*/
+ pbeParams.Passphrase = *password;
+ pbeParams.PseudoRandomFunction = CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1;
+ pbeData.Data = (uint8 *)&pbeParams;
+ pbeData.Length = sizeof(pbeParams);
+ crtn = CSSM_DeriveKey(ccHand,
+ &pbeData,
+ keyUsage,
+ keyAttr,
+ &dummyLabel,
+ NULL, // cred and acl
+ key);
+ if(crtn) {
+ printError("CSSM_DeriveKey", crtn);
+ return crtn;
+ }
+ crtn = CSSM_DeleteContext(ccHand);
+ if(crtn) {
+ printError("CSSM_DeleteContext", crtn);
+ }
+ return crtn;
+}
+
+
+int main(int argc, char **argv)
+{
+ int rtn;
+ uint32 keySizeInBytes; // from cmd line
+ char *password; // ASCII password from cmd line
+ char *inFileName; // from cmd line
+ unsigned char *inFile; // raw infile data
+ unsigned inFileSize; // in bytes
+ char *outFileName; // from cmd line
+ CSSM_CSP_HANDLE cspHand;
+ CSSM_RETURN crtn;
+ int doEncrypt = 0;
+ CSSM_DATA passwordData;
+ CSSM_DATA saltData = {8, (uint8 *)"someSalt"};
+ CSSM_DATA inData; // data to encrypt/decrypt, from inFile
+ CSSM_DATA outData = {0, NULL};// result data, written to outFile
+ CSSM_CC_HANDLE ccHand; // crypto context
+ CSSM_DATA remData = {0, NULL};
+ CSSM_SIZE bytesProcessed;
+ CSSM_KEY symKey;
+ char algSpec = '4';
+ CSSM_ALGORITHMS keyAlg = 0;
+ CSSM_ALGORITHMS encrAlg = 0;
+ CSSM_ENCRYPT_MODE encrMode = 0;
+ CSSM_PADDING padding = 0;
+ /* max of 16 bytes of init vector for the algs we use */
+ CSSM_DATA initVect = {16, (uint8 *)"someStrangeInitVector"};
+ CSSM_DATA_PTR initVectPtr = NULL;
+
+ if(argc < 6) {
+ usage(argv);
+ }
+
+ /* gather up cmd line args */
+ switch(argv[1][0]) {
+ case 'e':
+ doEncrypt = 1;
+ break;
+ case 'd':
+ doEncrypt = 0;
+ break;
+ default:
+ usage(argv);
+ }
+ password = argv[2];
+ passwordData.Data = (uint8 *)password;
+ passwordData.Length = strlen(password);
+ keySizeInBytes = atoi(argv[3]);
+ if(keySizeInBytes == 0) {
+ printf("keySize of 0 illegal\n");
+ exit(1);
+ }
+ inFileName = argv[4];
+ outFileName = argv[5];
+
+ /* optional algorithm specifier */
+ if(argc == 7) {
+ if(argv[6][0] != 'a') {
+ usage(argv);
+ }
+ algSpec = argv[6][2];
+ }
+
+ /* algorithm-specific parameters */
+ switch(algSpec) {
+ case '4':
+ /* RC4 stream cipher - no padding, no IV, variable key size */
+ keyAlg = CSSM_ALGID_RC4;
+ encrAlg = CSSM_ALGID_RC4;
+ encrMode = CSSM_ALGMODE_NONE;
+ padding = CSSM_PADDING_NONE;
+ break;
+ case 'c':
+ /* ComCryption stream cipher - no padding, no IV, variable key size */
+ keyAlg = CSSM_ALGID_ASC;
+ encrAlg = CSSM_ALGID_ASC;
+ encrMode = CSSM_ALGMODE_NONE;
+ padding = CSSM_PADDING_NONE;
+ break;
+ case 'd':
+ /* DES block cipher, block size = 8 bytes, fixed key size */
+ if(keySizeInBytes != 8) {
+ printf("***DES must have key size of 8 bytes\n");
+ exit(1);
+ }
+ keyAlg = CSSM_ALGID_DES;
+ encrAlg = CSSM_ALGID_DES;
+ encrMode = CSSM_ALGMODE_CBCPadIV8;
+ padding = CSSM_PADDING_PKCS7;
+ initVect.Length = 8;
+ initVectPtr = &initVect;
+ break;
+ case 'a':
+ /* AES block cipher, block size = 16 bytes, fixed key size */
+ if(keySizeInBytes != 16) {
+ printf("***AES must have key size of 8 bytes\n");
+ exit(1);
+ }
+ keyAlg = CSSM_ALGID_AES;
+ encrAlg = CSSM_ALGID_AES;
+ encrMode = CSSM_ALGMODE_CBCPadIV8;
+ padding = CSSM_PADDING_PKCS7;
+ initVect.Length = 16;
+ initVectPtr = &initVect;
+ break;
+ default:
+ usage(argv);
+ }
+
+ /* read inFile from disk */
+ rtn = readFile(inFileName, &inFile, &inFileSize);
+ if(rtn) {
+ printf("Error reading %s: %s\n", inFileName, strerror(rtn));
+ exit(1);
+ }
+ inData.Data = inFile;
+ inData.Length = inFileSize;
+
+ /* attach to CSP */
+ cspHand = cspStartup();
+ if(cspHand == 0) {
+ exit(1);
+ }
+
+ /*
+ * Derive an actual encryption/decryption key from the password ASCII text.
+ * We could use the ASCII text directly as key material but using the DeriveKey
+ * function is much more secure (besides being an industry-standard way to
+ * convert an ASCII password into binary key material).
+ */
+ crtn = ctDeriveKey(cspHand,
+ keyAlg,
+ "someLabel", // keyLabel, not important
+ 9, // keyLabelLen
+ doEncrypt ? CSSM_KEYUSE_ENCRYPT : CSSM_KEYUSE_DECRYPT,
+ keySizeInBytes * 8, // keySizeInBits,
+ &passwordData,
+ &saltData,
+ 1000, // iterCount, 1000 is the minimum
+ &symKey);
+ if(crtn) {
+ exit(1);
+ }
+
+ /*
+ * Cook up a symmetric encrypt/decrypt context using the key we just derived
+ */
+ crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
+ encrAlg, // encryption algorithm
+ encrMode, // mode
+ NULL, // access cred
+ &symKey,
+ initVectPtr, // InitVector
+ padding, // Padding
+ NULL, // Params
+ &ccHand);
+ if(crtn) {
+ printError("CSSM_CSP_CreateSymmetricContext", crtn);
+ exit(1);
+ }
+
+ /*
+ * Do the encrypt/decrypt.
+ * We do this with the init/update/final sequence only to demonstrate its
+ * usage.
+ */
+ if(doEncrypt) {
+ crtn = CSSM_EncryptDataInit(ccHand);
+ if(crtn) {
+ printError("CSSM_EncryptDataInit", crtn);
+ exit(1);
+ }
+
+ /* this step can be performed an arbitrary number of times, with
+ * the appropriate housekeeping of inData and outData */
+ crtn = CSSM_EncryptDataUpdate(ccHand,
+ &inData,
+ 1,
+ &outData,
+ 1,
+ &bytesProcessed);
+ if(crtn) {
+ printError("CSSM_EncryptDataUpdate", crtn);
+ exit(1);
+ }
+ outData.Length = bytesProcessed;
+
+ /* one call more to clean up */
+ crtn = CSSM_EncryptDataFinal(ccHand, &remData);
+ if(crtn) {
+ printError("CSSM_EncryptDataFinal", crtn);
+ exit(1);
+ }
+ if(remData.Length != 0) {
+ /* append remaining data to outData */
+ uint32 newLen = outData.Length + remData.Length;
+ outData.Data = (uint8 *)appRealloc(outData.Data,
+ newLen,
+ NULL);
+ memmove(outData.Data + outData.Length, remData.Data, remData.Length);
+ outData.Length = newLen;
+ appFree(remData.Data, NULL);
+ }
+ }
+ else {
+ crtn = CSSM_DecryptDataInit(ccHand);
+ if(crtn) {
+ printError("CSSM_DecryptDataInit", crtn);
+ exit(1);
+ }
+
+ /* this step can be performed an arbitrary number of times, with
+ * the appropriate housekeeping of inData and outData */
+ crtn = CSSM_DecryptDataUpdate(ccHand,
+ &inData,
+ 1,
+ &outData,
+ 1,
+ &bytesProcessed);
+ if(crtn) {
+ printError("CSSM_DecryptDataUpdate", crtn);
+ exit(1);
+ }
+ outData.Length = bytesProcessed;
+
+ /* one call more to clean up */
+ crtn = CSSM_DecryptDataFinal(ccHand, &remData);
+ if(crtn) {
+ printError("CSSM_DecryptDataFinal", crtn);
+ exit(1);
+ }
+ if(remData.Length != 0) {
+ /* append remaining data to outData */
+ uint32 newLen = outData.Length + remData.Length;
+ outData.Data = (uint8 *)appRealloc(outData.Data,
+ newLen,
+ NULL);
+ memmove(outData.Data + outData.Length, remData.Data, remData.Length);
+ outData.Length = newLen;
+ appFree(remData.Data, NULL);
+ }
+ }
+ if(crtn == CSSM_OK) {
+ rtn = writeFile(outFileName, outData.Data, outData.Length);
+ if(rtn) {
+ printf("Error writing %s: %s\n", outFileName, strerror(rtn));
+ exit(1);
+ }
+ else {
+ printf("SUCCESS: inFile length %u bytes, outFile length %u bytes\n",
+ inFileSize, (unsigned)outData.Length);
+ }
+ }
+ /* free resources */
+ crtn = CSSM_DeleteContext(ccHand);
+ if(crtn) {
+ printError("CSSM_DeleteContext", crtn);
+ }
+ crtn = CSSM_FreeKey(cspHand,
+ NULL, // access cred
+ &symKey,
+ CSSM_FALSE); // don't delete since it wasn't permanent
+ if(crtn) {
+ printError("CSSM_FreeKey", crtn);
+ }
+ free(inFile); // mallocd by readFile()
+
+ /* this was mallocd by CSP */
+ appFree(outData.Data, NULL);
+ CSSM_ModuleDetach(cspHand);
+ return rtn;
+}
+