| RSA BSAFE Crypto-C |
Cryptographic Components for C |
| Search |
/* $Id: setoaep.c,v 1.6 2004/12/03 02:08:38 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 program will generate a RSA keypair, encrypt with the public key, * then decrypt with the private key -- i.e. Digital Envelope. * * Modified to use the SET OAEP encryption. */ #include "bsafe.h" #include "demoutil.h" /* in samples/common/include */ #include "bsfutil.h" /* in samples/common/include */ #include "rsautil.h" /* in samples/pkalg/rsa */ /* Set an arbitrary value for the number of bytes to encrypt */ #define DATA_TO_ENCRYPT_LEN 8 /* RSA_MODULUS_BITS must be evenly divisible by 8 for these AI's */ #define RSA_MODULUS_BITS 1024 #define BLOCK_SIZE ((RSA_MODULUS_BITS + 7) / 8) /* For SET OAEP, the padding scheme needs exactly 25 bytes to work with. In contrast, PKCS #1 v1.5 padding needs a minimum of 11 bytes. */ #define BLOCK_OVERHEAD 25 /* This indicates the number of actual bytes which are available to hold the data to encrypt. In the SET v1.0 spec book 3, this would correspond to the ADB, actual data block, on p. 17. The extra '- 1' is because Crypto-C expects the first byte to indicate the block contents, BC, as specified on p. 16 in book 3 of the SET 1.0 spec. However, there is no specific requirement imposed by Crypto-C to adhere to the recommendation in the SET spec. Therefore, AI_SET_OAEP_RSAPublic/Private can also be used like raw RSA, except that the size of the data to encrypt must be a multiple of (BLOCK_SIZE - 25). However for the purposes of this example, as shown in RSA_Encrypt/Decrypt below, we use BC = 0. */ #define BLOCK_PAYLOAD (BLOCK_SIZE - BLOCK_OVERHEAD - 1) #define NUM_BLOCKS ((DATA_TO_ENCRYPT_LEN + BLOCK_PAYLOAD - 1) / BLOCK_PAYLOAD) /* Supports RSA public-key encryption using OAEP. * dataToEncrypt.data must point to a block of memory large enough to * hold the encrypted data (a multiple of the modulus size) */ int RSAEncrypt (B_ALGORITHM_OBJ randomAlgorithm, B_KEY_OBJ publicKey, ITEM *dataToEncrypt, ITEM *encryptedData); /* Supports RSA private-key decryption using OAEP. * decryptedData.data must point to a block of memory large enough * to hold the decrypted data. */ int RSADecrypt (B_KEY_OBJ privateKey, ITEM *encryptedData, ITEM *decryptedData); #ifdef CRYPTOC_APP #define MAIN setoaepMain #else #define MAIN main #endif int MAIN(int argc, char *argv[]) { B_ALGORITHM_OBJ randomAlgorithm = (B_ALGORITHM_OBJ)NULL_PTR; B_KEY_OBJ publicKey = (B_KEY_OBJ)NULL_PTR; B_KEY_OBJ privateKey = (B_KEY_OBJ)NULL_PTR; ITEM dataToEncrypt, encryptedData = {NULL, 0}, decryptedData = {NULL, 0}; unsigned char dataToEncryptWithRSA[DATA_TO_ENCRYPT_LEN]; 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 ("RSA With SET OAEP Algorithm\n"); RSA_PrintMessage ("===========================\n"); if ((status = RSA_CreateRandomAlgorithmObject (&randomAlgorithm)) != 0) break; if ((status = B_GenerateRandomBytes (randomAlgorithm, dataToEncryptWithRSA, DATA_TO_ENCRYPT_LEN, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; dataToEncrypt.data = dataToEncryptWithRSA; dataToEncrypt.len = DATA_TO_ENCRYPT_LEN; RSA_PrintBuf ("Data To Encrypt", dataToEncrypt.data, dataToEncrypt.len); /* The following function is in samples/pkalg/rsa/rsautil.c */ if ((status = RSA_CreateRSAKeypair (&publicKey, &privateKey, RSA_MODULUS_BITS, randomAlgorithm)) != 0) break; encryptedData.len = BLOCK_SIZE * NUM_BLOCKS; encryptedData.data = T_malloc (encryptedData.len); if (encryptedData.data == NULL_PTR) { status = RSA_DEMO_E_ALLOC; break; } if ((status = RSAEncrypt (randomAlgorithm, publicKey, &dataToEncrypt, &encryptedData)) != 0) break; decryptedData.data = T_malloc (BLOCK_PAYLOAD * NUM_BLOCKS); if (decryptedData.data == NULL_PTR) { status = RSA_DEMO_E_ALLOC; break; } if ((status = RSADecrypt (privateKey, &encryptedData, &decryptedData)) != 0) break; if ((decryptedData.len == dataToEncrypt.len) && (T_memcmp (dataToEncrypt.data, decryptedData.data, decryptedData.len)) == 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 ("setoaep", status); /* Destroy objects and free memory */ B_DestroyAlgorithmObject (&randomAlgorithm); B_DestroyKeyObject (&privateKey); B_DestroyKeyObject (&publicKey); T_free (encryptedData.data); T_free (decryptedData.data); return (status); } /* end main */ /* Supports RSA public-key encryption using OAEP. * dataToEncrypt.data must point to a block of memory large enough to * hold the encrypted data (a multiple of the modulus size) */ int RSAEncrypt(B_ALGORITHM_OBJ randomAlgorithm, B_KEY_OBJ publicKey, ITEM *dataToEncrypt, ITEM *encryptedData) { int status; B_ALGORITHM_METHOD *ENCRYPTION_CHOOSER[] = { &AM_RSA_ENCRYPT, (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 }; B_ALGORITHM_OBJ rsaEncryptor = (B_ALGORITHM_OBJ)NULL_PTR; unsigned int inputDataLeft; unsigned char inputBlock[BLOCK_PAYLOAD + 1]; /* + 1 for BC */ unsigned int inputBlockIndex, encryptedDataIndex; unsigned int outputLenUpdate, outputLenFinal; do { RSA_PrintMessage ("\nEncrypting with the RSA Public Key...\n"); /* Create an Algorithm Object */ if ((status = B_CreateAlgorithmObject (&rsaEncryptor)) != 0) break; /* Set the algorithm object to AI_SET_OAEP_RSAPublic */ if ((status = B_SetAlgorithmInfo (rsaEncryptor, AI_SET_OAEP_RSAPublic, NULL_PTR)) != 0) break; /* Init -- encrypt with the recipient's public key */ if ((status = B_EncryptInit (rsaEncryptor, publicKey, ENCRYPTION_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; /* Update */ /* inputBlockIndex is used to tell how far into the dataToEncrypt->data buffer we've gone */ inputBlockIndex = 0; /* encryptedDataIndex tells us where to begin writing to encryptedData->data */ encryptedDataIndex = 0; /* number of bytes remaining in dataToEncrypt->data */ inputDataLeft = dataToEncrypt->len; while (inputDataLeft > 0) { /* zeroize the inputBlock array and write data to encrypt beginning at inputBlock[1], so that the first byte will be zero and any unused space at the end of inputData will be zero. SET v1.0 book 3, pp.16-17 where BC=0. */ T_memset (inputBlock, 0, BLOCK_PAYLOAD + 1); /* Write as many bytes as possible from dataToEncrypt->data to inputBlock. */ if (inputDataLeft < BLOCK_PAYLOAD) { T_memcpy (inputBlock + 1, dataToEncrypt->data + inputBlockIndex, inputDataLeft); inputDataLeft = 0; } else { T_memcpy (inputBlock + 1, dataToEncrypt->data + inputBlockIndex, BLOCK_PAYLOAD); inputDataLeft -= BLOCK_PAYLOAD; inputBlockIndex += BLOCK_PAYLOAD; } if ((status = B_EncryptUpdate (rsaEncryptor, encryptedData->data + encryptedDataIndex, &outputLenUpdate, BLOCK_SIZE, (unsigned char *)inputBlock, BLOCK_PAYLOAD + 1, randomAlgorithm, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; /* Final */ if ((status = B_EncryptFinal (rsaEncryptor, encryptedData->data + encryptedDataIndex + outputLenUpdate, &outputLenFinal, BLOCK_SIZE - outputLenUpdate, randomAlgorithm, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; encryptedDataIndex += outputLenUpdate + outputLenFinal; } if (status != 0) break; RSA_PrintBuf ("Encrypted Data", encryptedData->data, encryptedData->len); } while (0); if (status != 0) RSA_PrintError ("RSAEncrypt", status); B_DestroyAlgorithmObject (&rsaEncryptor); return (status); } /* end RSAEncrypt */ /* Supports RSA private-key decryption using OAEP. * decryptedData.data must point to a block of memory large enough * to hold the decrypted data. */ int RSADecrypt(B_KEY_OBJ privateKey, ITEM *encryptedData, ITEM *decryptedData) { int status; B_ALGORITHM_METHOD *DECRYPTION_CHOOSER[] = { &AM_RSA_CRT_DECRYPT_BLIND, (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 }; B_ALGORITHM_OBJ rsaDecryptor = (B_ALGORITHM_OBJ)NULL_PTR; unsigned char outputBuffer[BLOCK_SIZE]; unsigned int encryptedDataLeft; unsigned int decryptedBlockLen, decryptedPayloadLen; unsigned int encryptedDataIndex; unsigned int outputLenUpdate, outputLenFinal, padBytes; do { RSA_PrintMessage ("\nDecrypting with the RSA Private Key...\n"); /* Create an Algorithm Object */ if ((status = B_CreateAlgorithmObject (&rsaDecryptor)) != 0) break; /* Set the algorithm object to AI_SET_OAEP_RSAPrivate */ if ((status = B_SetAlgorithmInfo (rsaDecryptor, AI_SET_OAEP_RSAPrivate, NULL_PTR)) != 0) break; /* Init -- Use the private key associated with the public key used to encrypt */ if ((status = B_DecryptInit (rsaDecryptor, privateKey, DECRYPTION_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; /* Update */ /* The encrypted data length should be a multiple of the block size. */ encryptedDataIndex = 0; decryptedPayloadLen = 0; encryptedDataLeft = encryptedData->len; decryptedData->len = 0; /* Decrypt each block of encrypted data */ while (encryptedDataLeft > 0) { if ((status = B_DecryptUpdate (rsaDecryptor, outputBuffer, &outputLenUpdate, BLOCK_SIZE, encryptedData->data + encryptedDataIndex, BLOCK_SIZE, NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; /* Final */ if ((status = B_DecryptFinal (rsaDecryptor, outputBuffer + outputLenUpdate, &outputLenFinal, BLOCK_SIZE - outputLenUpdate, NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; decryptedPayloadLen = outputLenUpdate + outputLenFinal; encryptedDataLeft -= BLOCK_SIZE; encryptedDataIndex += BLOCK_SIZE; /* Copy the decrypted data from outputBuffer to decryptedData->data. The BC byte is not part of the payload; when encrypting we used BC=0. Strip any trailing zeros, which were pad bytes. */ if (outputBuffer[0] != 0) { status = BE_INPUT_DATA; break; } for (padBytes = 0, decryptedBlockLen = decryptedPayloadLen - 1; (decryptedBlockLen > 0) && (outputBuffer[decryptedBlockLen] == 0); ++padBytes, --decryptedBlockLen); /* The amount of 'real' data in the decrypted data is decryptedBlockLen bytes */ T_memcpy (decryptedData->data + decryptedData->len, outputBuffer + 1, decryptedBlockLen); decryptedData->len += decryptedBlockLen; } if (status != 0) break; RSA_PrintBuf ("Decrypted Data", decryptedData->data, decryptedData->len); } while (0); if (status != 0) RSA_PrintError ("RSADecrypt", status); B_DestroyAlgorithmObject (&rsaDecryptor); return (status); } /* end RSADecrypt */