| RSA BSAFE Crypto-C |
Cryptographic Components for C |
| Search |
/* $Id: pbe.c,v 1.6 2004/12/03 02:08:41 sparki Exp $ */ /* * Copyright (C) 1998-2004 RSA Security Inc. * * This file shall only be used to demonstrate how to interface to an * RSA Security Inc. licensed development product. * * You have a royalty-free right to use, reproduce and distribute this * demonstration file, provided that you agree that RSA Security Inc. * has no warranty, implied or otherwise, or liability for this * demonstration file (including any modified version). This software * is provided "as is" without warranties or representations of any * kind. RSA Security disclaims all conditions and warranties, statutory * and otherwise, both express and implied, with respect to the software, * its quality and performance, including but not limited to, all * implied warranties of merchantability, fitness for a particular * purpose, title and noninfringement of third party rights. Without * limiting the foregoing, RSA Security does not warrant that the * software is error-free or that errors in the product will be * corrected. You agree that RSA Security shall not be liable for any * direct, indirect, incidental, special, consequential, punitive or * other damages whatsoever resulting from your use of this software * or any modified version. * * */ /* This is a Password-Based Encryption program. Note the use of the * algorithm identifier (B_GetAlgorithmInfo call on the encryption * algorithm object). This algorithm ID is used by the recipient and * contains all of the necessary algorithm parameters (such as the salt, * effective key bits, rounds, etc.). [This is PKCS #5 v1.5 PBE; the IV * is derived from the password and therefore not user-provided in * B_SetAlgorithmInfo, even though we are using a block cipher in CBC mode] */ #include "bsafe.h" #include "demoutil.h" /* in samples/common/include */ #include "bsfutil.h" /* in samples/common/include */ #define SALT_LEN 8 #define MAX_PW_LEN 20 #define BLOCK_SIZE 8 B_ALGORITHM_METHOD *PBE_CHOOSER[] = { &AM_MD5, &AM_RC2_CBC_ENCRYPT, &AM_RC2_CBC_DECRYPT, (B_ALGORITHM_METHOD *)NULL_PTR /* This will fix a problem that the IA64 compiler finds when * * seeing a short chooser list */ #ifdef IA64_FORCE_LARGE IA64_FORCE_LARGE #endif }; #ifdef CRYPTOC_APP #define MAIN pbeMain #else #define MAIN main #endif int MAIN(int argc, char *argv[]) { B_KEY_OBJ pbeKey = (B_KEY_OBJ)NULL_PTR; B_ALGORITHM_OBJ pbEncrypter = (B_ALGORITHM_OBJ)NULL_PTR; B_ALGORITHM_OBJ pbDecrypter = (B_ALGORITHM_OBJ)NULL_PTR; B_ALGORITHM_OBJ randomAlgorithm = (B_ALGORITHM_OBJ)NULL_PTR; B_RC2_PBE_PARAMS rc2PBEParams; unsigned char saltData[SALT_LEN]; unsigned char enteredPassword[MAX_PW_LEN]; ITEM pbeKeyItem; unsigned char dataToEncrypt[] = "Encrypt this sentence."; unsigned int dataToEncryptLen; unsigned char *encryptedData = NULL_PTR; unsigned int outputLenUpdate, outputLenFinal; unsigned int encryptedDataLen, decryptedDataLen; unsigned char *decryptedData = NULL_PTR; unsigned int decryptedLenUpdate, decryptedLenFinal; ITEM *getInfoBER = NULL; ITEM infoBER = {NULL, 0}; int status; do { /* The RSA_* demo code utilities are described in common/include/demoutil.h. This procedure simply checks the command-line arguments for input or output options. */ if ((status = RSA_SetOptions (argc, argv)) != 0) break; RSA_PrintMessage ("Password-Based algorithm: Encryption phase\n"); RSA_PrintMessage ("===========================================\n"); dataToEncryptLen = T_strlen ((char *)dataToEncrypt) + 1; RSA_PrintBuf ("Data To Encrypt", dataToEncrypt, dataToEncryptLen); /* Initialize a random algorithm object using a procedure described in samples/common/include/bsfutil.h */ if ((status = RSA_CreateRandomAlgorithmObject (&randomAlgorithm)) != 0) break; /* Create an algorithm object. */ if ((status = B_CreateAlgorithmObject (&pbEncrypter)) != 0) break; /* Set the algorithm to AI_MD5WithRC2_CBCPad. */ /* Generate the bytes to get an 8-byte random "salt" */ if ((status = B_GenerateRandomBytes (randomAlgorithm, saltData, SALT_LEN, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; rc2PBEParams.effectiveKeyBits = 80; rc2PBEParams.salt = saltData; rc2PBEParams.iterationCount = 1000; RSA_PrintBuf ("Salt", saltData, BLOCK_SIZE); if ((status = B_SetAlgorithmInfo (pbEncrypter, AI_MD5WithRC2_CBCPad, (POINTER)&rc2PBEParams)) != 0) break; /* Obtaining the BER-encoded algorithm identifier in this way is optional. This can be transmitted to the recipient in the clear, along with the ciphertext so that the recipient knows what algorithm and corresponding parameters (in this case salt, effective key bits, and rounds) to use for decryption. */ if ((status = B_GetAlgorithmInfo ((POINTER *)&getInfoBER, pbEncrypter, AI_MD5WithRC2_CBCPadBER)) != 0) break; infoBER.len = getInfoBER->len; infoBER.data = T_malloc (infoBER.len); if ((status = (infoBER.data == NULL_PTR)) != 0) { status = RSA_DEMO_E_ALLOC; break; } /* Since the memory that getInfoBER points to belongs to BSAFE, we make a copy now so that we can use it to set the decryption algorithm object. */ T_memcpy (infoBER.data, getInfoBER->data, infoBER.len); RSA_PrintBuf ("BER-encoded Algorithm Identifier", infoBER.data, infoBER.len); /* Create a key object. */ if ((status = B_CreateKeyObject (&pbeKey)) != 0) break; /* Set the key object -- The data portion of the struct is the password. An insecure method for entering the password would be the following. This is simply for illustrative purposes, not for duplication. (A real application would not allow the password to be echoed to the screen) */ if ((status = RSA_GetCommand ((char *)enteredPassword, sizeof (enteredPassword), "Enter a password for encryption")) != 0) break; pbeKeyItem.data = enteredPassword; pbeKeyItem.len = T_strlen ((char *)enteredPassword); if ((status = B_SetKeyInfo (pbeKey, KI_Item, (POINTER)&pbeKeyItem)) != 0) break; /* Zeroize the memory and free it up immediately after setting the key for security reasons. */ T_memset (enteredPassword, 0, sizeof (enteredPassword)); /* Init -- A key is needed before the algorithm object can be initialized for encryption. In PBE, the password is the key. */ if ((status = B_EncryptInit (pbEncrypter, pbeKey, PBE_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; /* Update */ encryptedDataLen = dataToEncryptLen + BLOCK_SIZE; encryptedData = T_malloc (encryptedDataLen); if (encryptedData == NULL_PTR) { status = RSA_DEMO_E_ALLOC; break; } if ((status = B_EncryptUpdate (pbEncrypter, encryptedData, &outputLenUpdate, encryptedDataLen, dataToEncrypt, dataToEncryptLen, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; /* Final */ if ((status = B_EncryptFinal (pbEncrypter, encryptedData + outputLenUpdate, &outputLenFinal, encryptedDataLen - outputLenUpdate, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; encryptedDataLen = outputLenUpdate + outputLenFinal; RSA_PrintBuf ("Encrypted Data", encryptedData, encryptedDataLen); /* Destroy the key object now, rebuild a new one for decryption. */ B_DestroyKeyObject (&pbeKey); RSA_PrintMessage ("\nPassword-Based algorithm: Decryption phase\n"); RSA_PrintMessage ("===========================================\n"); if ((status = B_CreateAlgorithmObject (&pbDecrypter)) != 0) break; /* Using the BER-encoded algorithm identifier, set the decryption object. If the OID in the algorithm ID does not match MD5WithRC2, we will get a non-zero error code. If an application does not know which PBE algorithm the sender is using, the recipient can set up a list of B_INFO_TYPEs containing the PBE (BER) AIs the recipient wishes to support, trying each one with the algorithm ID until B_SetAlgorithmInfo is successful. Of course, in this example, we could have used AI_MD2WithRC2_CBCPad with the same rc2PBEParams we used earlier to get the same results. */ if ((status = B_SetAlgorithmInfo (pbDecrypter, AI_MD5WithRC2_CBCPadBER, (POINTER)&infoBER)) != 0) break; /* Build a key from a new password. If it is the same password (and salt), the key will work */ if ((status = B_CreateKeyObject (&pbeKey)) != 0) break; if ((status = RSA_GetCommand ((char *)enteredPassword, sizeof (enteredPassword), "Enter a password for decryption")) != 0) break; pbeKeyItem.data = enteredPassword; pbeKeyItem.len = T_strlen ((char *)pbeKeyItem.data); if ((status = B_SetKeyInfo (pbeKey, KI_Item, (POINTER)&pbeKeyItem)) != 0) break; /* Zeroize the memory and free it up immediately after setting the key for security reasons. */ T_memset (enteredPassword, 0, sizeof (enteredPassword)); if ((status = B_DecryptInit (pbDecrypter, pbeKey, PBE_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; /* The size of the decrypted data can be no larger than the size of the encrypted data. */ decryptedDataLen = encryptedDataLen; decryptedData = T_malloc (decryptedDataLen); if (decryptedData == NULL_PTR) { status = RSA_DEMO_E_ALLOC; break; } if ((status = B_DecryptUpdate (pbDecrypter, decryptedData, &decryptedLenUpdate, decryptedDataLen, encryptedData, encryptedDataLen, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; if ((status = B_DecryptFinal (pbDecrypter, decryptedData + decryptedLenUpdate, &decryptedLenFinal, decryptedDataLen - decryptedLenUpdate, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; /* Now we know how long the decrypted data actually is. */ decryptedDataLen = decryptedLenUpdate + decryptedLenFinal; RSA_PrintBuf ("Decrypted Data", decryptedData, decryptedDataLen); if ((decryptedDataLen == dataToEncryptLen) && (T_memcmp (dataToEncrypt, decryptedData, decryptedDataLen)) == 0) { RSA_PrintMessage ("Success! "); RSA_PrintMessage ("The decrypted data matches the original data.\n"); } else { RSA_PrintMessage ("The decrypted data does not match the original data."); status = RSA_DEMO_E_INFO_DOES_NOT_VERIFY; } } while (0); if (status != 0) RSA_PrintError ("pbe", status); /* Done with the key and algorithm objects, so destroy them. */ B_DestroyKeyObject (&pbeKey); B_DestroyAlgorithmObject (&pbEncrypter); B_DestroyAlgorithmObject (&randomAlgorithm); B_DestroyAlgorithmObject (&pbDecrypter); /* Free up any memory allocated, save it to a file or print it out first if you need to save it. */ if (infoBER.data != NULL_PTR) { T_free (infoBER.data); infoBER.data = NULL_PTR; } if (encryptedData != NULL_PTR) { T_free (encryptedData); encryptedData = NULL_PTR; } if (decryptedData != NULL_PTR) { T_free (decryptedData); decryptedData = NULL_PTR; } return (status); } /* end main */