RSA BSAFE® Crypto-C Cryptographic Components for C Developer’s Guide Version 5.2.
RSA Security Inc. 20 Crosby Drive Bedford, MA 01730 USA Tel (US) 1 877 RSA 4900, +1 781 301 5000 Fax +1 781 301 5170 www.rsasecurity.com RSA Security Ireland Limited Bay 127, Shannon Free Zone Shannon, County Clare, Ireland Tel +353 61 72 5100 Fax +353 61 72 5110 www.rsasecurity.ie See our Web Site for regional Customer Service telephone and fax numbers.
Contents Preface xv What’s New in Version 5.2.2? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xvi Improved performance. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .xvi Hardware support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .xvi MultiPrime RSA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Cryptographic Standards and Crypto-C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 PKCS Standards and Crypto-C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . NIST Standards and Crypto-C. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . PKCS Compared with NIST. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ANSI X9 Standards and Crypto-C . . . .
Optimal Asymmetric Encryption Padding (OAEP) . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 Authentication and Digital Signatures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 Digital Signature Algorithm (DSA) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 Digital Certificates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 Diffie-Hellman Public Key Agreement . . . . . . . . . . . . .
Elliptic Curve Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 Interoperability. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90 Elliptic Curve Standards. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 Security Considerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Memory-Management Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 Memory-Management Routines and Standard C Libraries . . . . . . . . . . . . . . . . . . 122 Memory Allocation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123 Binary Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123 BER/DER Encoding. . . . . . . . . . . . . . . . . . . . .
Chapter 6 Symmetric-Key Operations 177 Block Ciphers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178 DES with CBC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Decrypting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . The RC2 Cipher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Performing Diffie-Hellman Key Agreement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249 Generating Diffie-Hellman Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249 Distributing Diffie-Hellman Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253 Crypto-C Format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253 BER Format . . . . . . . . . . . . . . . . . . . .
Appendix A Command-Line Demos 327 Overview of the Demos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327 Command-Line Demo User’s Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328 BDEMO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Starting BDEMO. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
List of Figures Figure 3-1 Symmetric-Key Encryption and Decryption . . . . . . . . . . . . . . . . . . . . 36 Figure 3-2 Triple DES Encryption as Implemented in Crypto-C. . . . . . . . . . . . . . 38 Figure 3-3 Electronic Codebook (ECB) Mode . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 Figure 3-4 Cipher-Block Chaining (CBC) Mode . . . . . . . . . . . . . . . . . . . . . . . . . . 43 Figure 3-5 Cipher Feedback (CFB) Mode. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
xii R S A B S A F E C r y p t o - C D e v e l o p e r ’s G u i d e
List of Tables Table 3-1 Calculation of 827 mod 55. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 Table 3-2 Elliptic Curve Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 Table 3-3 DES Weak and Semi-Weak Keys . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 Table 3-4 Summary of Recommended Key Sizes . . . . . . . . . . . . . . . . . . . . . . . 98 Table 4-1 Message Digests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
xiv R S A B S A F E C r y p t o - C D e v e l o p e r ’s G u i d e
Preface Dear Crypto-C Developer: Congratulations on your purchase of RSA BSAFE® Crypto-C (Crypto-C), the state-ofthe-art in cryptographic software toolkits. Crypto-C provides developers with the most important privacy, authentication, and data integrity routines. Crypto-C contains a full palette of popular cryptographic algorithms. This software development kit enables you to develop applications for a wide range of purposes, including electronic commerce, home banking, Webcasting, and enterprise security.
What’s New in Version 5.2.2? What’s New in Version 5.2.2? Following is a list of RSA BSAFE Crypto-C features that are new in version 5.2.2: Improved performance With the new performance improvements, you’ll be able to use RSA BSAFE CryptoC’s algorithms at unprecedented levels of speed and throughput across a wide range of hardware platforms.
Organization of This Manual V5.2. Use this AI to save the internal state of an RC4 encryption or decryption object, or to create a new object from the saved state of a previous RC4 object. Advanced Encryption Standard (AES) Crypto-C includes basic AES support for the cutting edge in processor technology: Intel Itanium and Pentium 4. Organization of This Manual This manual is organized as follows: • Chapter 1, “Introduction,” introduces the Crypto-C toolkit.
Conventions Used in This Manual Conventions Used in This Manual The following typographical conventions are used in this manual.
Terms and Abbreviations Terms and Abbreviations The following table lists terms and abbreviations used in this document. Refer to the Glossary for a list of security and cryptographic terms and abbreviations, along with their definitions, that are used throughout the RSA BSAFE Crypto-C documentation set. Term or Abbreviation Definition Crypto-C RSA BSAFE Crypto-C: Cryptographic software development kit developers use to develop secure applications. .doc (file) Word for Windows, version 6.
Related Documents Related Documents Following is a list of documents referenced in this book and suggested material for further reading. 1. The Public-Key Cryptography Standards (PKCS), RSA Laboratories. (http://www.rsasecurity.com/rsalabs/PKCS/) 2. Frequently Asked Questions (FAQ) About Today’s Cryptography, RSA Laboratories. (http://www.rsasecurity.com/rsalabs/faq/) 3. The following Internet Standard documents: • RFCs 1421, 1422, 1423, 1424 on Privacy Enhancement for Internet Electronic Mail. 4.
Related Documents 12. • Results from the RSA Factoring Challenge • Recommendations on Elliptic Curve Cryptosystems • Recent Results for MD2, MD4, and MD5 The following OAEP specifications: • SET Secure Electronic Transaction Specification. Book 3: Formal Protocol Definition, version 1.0. SETCo, 1997. (http://www.setco.org/) • 13. 14. PKCS#1: RSA Cryptography Specifications. Version 2.0. RSA Security, 1998. (http://www.rsasecurity.
How to Contact RSA Security How to Contact RSA Security RSA Security Web Site You can visit the RSA Security Web site at http://www.rsasecurity.com. It contains the latest RSA Security news, security bulletins, and information about coming events. RSA BSAFE product information is available at http://www.rsasecurity.com/ products/bsafe. RSA Laboratories’ Cryptography FAQ can also be found at http://www.rsasecurity.com/rsalabs/faq.
Chapter 1 Introduction This chapter introduces the Crypto-C toolkit. It lists the algorithms, cryptographic standards, NIST standards, and ANSI X9 standards used in Crypto-C.
The Crypto-C Toolkit The Crypto-C Toolkit Crypto-C provides developers with a state-of-the-art implementation of the most important privacy, authentication, and data integrity routines.
The Crypto-C Toolkit Public-Key Algorithms • • RSA Public Key Cryptosystem Diffie-Hellman Key Agreement Digital Signatures • • DSA RSA Digital Signatures Elliptic Curve Public-Key Algorithms • • • Elliptic Curve Digital Signature Algorithm (ECDSA) Elliptic Curve Diffie-Hellman Key Agreement Elliptic Curve Authenticated Encryption Scheme (ECAES) Secret Sharing • Bloom-Shamir Secret Sharing Hardware Support In addition to the cryptographic algorithms listed here, Crypto-C offers a hardware interface
Cryptographic Standards and Crypto-C Cryptographic Standards and Crypto-C PKCS Standards and Crypto-C Crypto-C is a general-purpose programming tool that developers can use to write a wide variety of applications. Crypto-C was built to help developers implement the Public-Key Cryptography Standards (PKCS), a series of documents that specify a standard way of performing basic cryptographic operations.
Cryptographic Standards and Crypto-C • Secure Hash Algorithm (SHA1), as specified in FIPS PUB 180-1, Secure Hash Standard (SHS) • • RSA Digital Signatures (rDSA), as specified in FIPS PUB 186-2 • • Data Encryption Standard (DES), as specified in FIPS PUB 46-2 Digital Signature Algorithm (DSA), as specified in FIPS PUB 186, Digital Signature Standard (DSS) DES Modes of Operation, as specified in FIPS PUB 81 NIST Approval and Windows NT Platforms If you require NIST approval for your Windows NT applic
Cryptographic Standards and Crypto-C ANSI X9 Standards and Crypto-C Crypto-C also complies with a number of standards established by the X9 Financial Services Industry committee of the American National Standards Institute (ANSI). If you are writing a financial or government application that must comply with one of the X9 standards, you may benefit by using Crypto-C. This release is fully compliant with the following ANSI X9 standards: • The ANSI X9.
Chapter 2 Quick Start This chapter provides an introduction to using Crypto-C. You are first presented with the Crypto-C model and then you are presented an introductory example.
The Six-Step Sequence The Six-Step Sequence The Crypto-C model generally follows a six-step sequence: 1. Create 2. Set 3. Init 4. Update 5. Final 6. Destroy In addition, for every application, you must include the necessary header files; we will call this Step 0. The six-step sequence makes it easier to maintain your code. For example, if you have implemented a message digest routine using MD2 and wish to use SHA1 instead, you simply need to make changes in Steps 2 and 3, Set and Init.
Introductory Example Introductory Example The CD containing the Crypto-C library distribution also includes sample source code to accompany this Developer’s Guide. One of the files on that CD, introex.c, is an example of converting the Introductory Example into a program. Later in this manual are instructions on writing code for many Crypto-C operations. There are sample programs on the CD to accompany all the topics covered.
Introductory Example specify the type of algorithm that is being used, supply any special information or parameters that the algorithm requires, and generate or supply a key for algorithms that need one. In Step 1, we simply create the object. We do this by declaring a variable to be an algorithm object and calling B_CreateAlgorithmObject.
Introductory Example int status; do { if ((status = B_CreateAlgorithmObject (&rc4Encrypter)) != 0) break; . . . } while (0); Standard RSA Security coding practices use the above do-while construct to make it easy to break out of a sequence when encountering an error. If a Crypto-C function returns a non-zero value, break will exit the do-while, and further code dependent on the offending call will not be executed.
Introductory Example there is a single stream cipher, the RC4 cipher, and a number of AIs that can be used to implement it. For this example we will use AI_RC4; we pass this as the second argument to B_SetAlgorithmInfo. The third argument is information that is specific to the AI we chose.
Introductory Example See the description and prototype in Chapter 4 of the Reference Manual for B_EncryptInit: int B_EncryptInit ( B_ALGORITHM_OBJ algorithmObject, B_KEY_OBJ keyObject, B_ALGORITHM_CHOOSER algorithmChooser, A_SURRENDER_CTX *surrenderContext ); /* algorithm object /* key object /* algorithm chooser /* surrender context */ */ */ */ As in Step 2, the first argument is the algorithm object; once again, we use rc4Encrypter. The next three arguments are new.
Introductory Example object as an RC4 key, we need to use B_SetKeyInfo. See Chapter 4 of the Reference Manual for this function’s description and prototype: int B_SetKeyInfo ( B_KEY_OBJ keyObject, B_INFO_TYPE infoType, POINTER info ); /* key object */ /* type of key information */ /* key information */ This function is similar to B_SetAlgorithmInfo. The first argument is the key object just created, rc4Key.
Introductory Example static unsigned char rc4KeyData[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10 }; ITEM rc4KeyItem; rc4KeyItem.data = rc4KeyData; rc4KeyItem.len = sizeof(rc4keyData); Now we can complete the call to B_SetKeyInfo: if ((status = B_SetKeyInfo (rc4Key, KI_Item, (POINTER)&rc4KeyItem)) != 0) break; As with algorithm objects, once you have set a key object, you should not set it again. If you need another key object, you should create a new one.
Introductory Example instructions on writing an algorithm chooser. For the purposes of our example, we see that the Reference Manual entry for AI_RC4 states that we should use AM_RC4_ENCRYPT in our chooser.
Introductory Example information that it needs to perform RC4 encryption. In Step 4, we can enter the data to encrypt with the B_EncryptUpdate function.
Introductory Example For now, we declare: unsigned char *encryptedData = NULL_PTR; For a stream cipher, the length of the encrypted (output) data is equal to the length of the input data. So we allocate dataToEncryptLen bytes with T_malloc: encryptedData = T_malloc (dataToEncryptLen); if ((status = (encryptedData == NULL_PTR)) != 0) break; The previous code sample uses the Crypto-C routine T_malloc.
Introductory Example function must know the size of the buffer. The Update function will not attempt to place data into unallocated memory; instead, it returns an error if it needs to place more bytes into the buffer than are allocated. In our example, we will use dataToEncryptLen as our output data size. The seventh argument is a random algorithm. Recall that in Chapter 2 of the Reference Manual, the description of AI_RC4 states: You may pass (B_ALGORITHM_OBJ)NULL_PTR for all randomAlgorithm arguments.
Introductory Example int B_EncryptFinal ( B_ALGORITHM_OBJ algorithmObject, unsigned char *partOut, unsigned int *partOutLen, unsigned int maxPartOutLen, B_ALGORITHM_OBJ randomAlgorithm, A_SURRENDER_CTX *surrenderContext ); /* algorithm object /* output data buffer /* length of output data /* size of output data buffer /* random byte source /* surrender context */ */ */ */ */ */ For our example, the first argument is rc4Encrypter.
Introductory Example function calls after the do-while construct. That way, even if there is an error somewhere and the program breaks out of the do-while before executing all the calls within the do-while, the Destroy functions will execute. In case the error occurs before an object has been created, it is a good idea to initialize objects to NULL_PTR. If an object is NULL_PTR, the Destroy function does nothing.
Introductory Example For this example, call T_free as follows: T_free (encryptedData); Note: Using T_free means you can no longer access the data at that address. Do not free a buffer until you no longer need the data it contains. If you will need the data later, you might want to save it to a file first. You may want to zeroize any sensitive data before you free it. To do this, duplicate the following sequence after the do-while.
Introductory Example static char dataToEncrypt[] = "Encrypt this sentence."; unsigned char *encryptedData = NULL_PTR; unsigned int dataToEncryptLen, encryptedDataLen; unsigned int outputLenUpdate, outputLenFinal; int status; do { dataToEncryptLen = strlen (dataToEncrypt) + 1; /* Step 1: Create an algorithm object. */ if ((status = B_CreateAlgorithmObject (&rc4Encrypter)) != 0) break; /* Step 2: Set the algorithm to a type that does rc4 encryption. AI_RC4 will do.
Introductory Example /* Step 4: Update */ encryptedData = T_malloc (dataToEncryptLen); if ((status = (encryptedData == NULL_PTR)) != 0) break; if ((status = B_EncryptUpdate (rc4Encrypter, encryptedData, &outputLenUpdate, dataToEncryptLen, (unsigned char *)dataToEncrypt, dataToEncryptLen, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; /* Step 5: Final */ if ((status = B_EncryptFinal (rc4Encrypter, encryptedData + outputLenUpdate, &outputLenFinal, dataToEncryptLen - outputLenUpdate, (B
Introductory Example if (encryptedData != NULL_PTR){ T_memset (encryptedData, 0, dataToEncryptLen); T_free (encryptedData); encryptedData = NULL_PTR; } } /* end main */ You may find it a useful exercise to compile and link this program. Also, it could also be instructive to add some print statements.
Decrypting the Introductory Example Decrypting the Introductory Example Decrypting data is similar to encrypting. The RC4 cipher uses symmetric-key encryption, which means the key that was used to encrypt will be the key needed for decryption. The example in this section corresponds to the file dintroex.c. Step 1: Creating an Algorithm Object First create the algorithm object.
Decrypting the Introductory Example Step 3b: Setting the Key Object We need to fill our key with the same 10 bytes of data we used for encryption. We must make sure that we use the same key as we used to encrypt.
Decrypting the Introductory Example Step 5: Final if ((status = B_DecryptFinal (rc4Decrypter, decryptedData + decryptedLenUpdate, &decryptedLenFinal, encryptedDataLen - decryptedLenUpdate, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; In the “Introductory Example” on page 9, the plaintext was a string. Therefore, we can compute the sum of decryptedLenUpdate and decryptedLenFinal to determine how many characters make up the decryption.
Multiple Updates Multiple Updates An application can do multiple updates before the Final call. For example, suppose you have data from three different files that you want to encrypt into a single buffer. You could do this in three steps: read the contents of the first file into a buffer; read the next file, appending the contents to the end of the existing buffer; then append the contents of the third. But that would be clumsy if the contents of the three files are already in three buffers.
Multiple Updates places them into the given buffer, and sets a flag indicating whether the bytes returned are the last ones in the file or not. Assume also that the subroutine AppendDataToFile appends output data to a file.
Multiple Updates /* If there was an error in the above while loop, break out of the do-while construct. */ if (status != 0) break; /* Call B_EncryptFinal once after all Updates. */ if ((status = B_EncryptFinal (encryptionObject, blockOfEncryptedData, &outputLenFinal, UPDATE_OUTPUT_SIZE, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; /* Save the encrypted data.
Summary of the Six Steps Summary of the Six Steps A typical implementation uses the six steps as follows: Step 0: Include Include the necessary header files. In addition, make sure that: • • • Your compiler can locate the Crypto-C header files. Your compiler can locate and link in the Crypto-C library. You compile and link in the file containing the definitions for the T_ functions; an example is provided in tstdlib.c.
Summary of the Six Steps • For some algorithms, such as generating a public/private key pair, there is no Update step. Step 5: Final Finalize the action initiated in Step 4. Again, the finalization depends on the algorithm; for some algorithms, Final is replaced by Generate. For example: • For an encryption or decryption algorithm, the Final step encrypts or decrypts the final portion of the data.
34
Chapter 3 Cryptography This chapter contains a brief outline of the basic cryptographic principles and terminology used throughout this manual and documentation set. Refer to Terms and Abbreviations on page xix of the Preface for a list of terms and abbreviations used in this documentation set. The publications listed in “Related Documents” on page xx provide more comprehensive discussions of cryptographic functions and operations.
Cryptography Overview Cryptography Overview Symmetric-Key Cryptography In symmetric-key cryptography, as Figure 3-1 shows, the encrypting key is the same as the decrypting key. Using any other key to decrypt will produce incorrect results. Symmetric-key cryptography is also sometimes called secret-key cryptography, because the key used to both encrypt and decrypt must be kept secret. Ciphers There are two categories of symmetric encryption algorithms, block ciphers and stream ciphers.
Cryptography Overview Block Ciphers Block ciphers encrypt data block-by-block. They can encrypt each block separately as in ECB mode, or they can use other modes to make the cipher less vulnerable to attacks based on regular patterns. A mode of operation usually combines the underlying cipher with feedback and other simple operations. The security remains a function of the cipher and not of the mode. See “Modes of Operation” on page 41 for more information.
Cryptography Overview Triple DES Triple DES executes DES three times, which triples the number of bits in an encryption key. A number of different methods achieve this function. The technique that Crypto-C uses is depicted in Figure 3-2 on page 38. This technique is known as EDE, or “Encrypt-Decrypt-Encrypt.” The decryption process in the middle stage of Triple DES encryption provides compatibility with DES. If the three keys are the same, the Triple DES operation is equivalent to a single DES encryption.
Cryptography Overview it is proprietary to RSA Security. The RC2 cipher has an eight-byte block size. Therefore, the input must be a multiple of eight bytes, or be padded to be a multiple of eight bytes, for the RC2 cipher to operate properly in CBC or ECB modes. The RC2 input key can be of any length from 1 to 128 bytes. The algorithm uses the input key to generate an effective key that is actually used for encryption purposes.
Cryptography Overview for 12-round RC5-32, recent cryptanalytic work suggests 16 rounds is now a more conservative choice. For the RC5 cipher with a 64-bit word size, RSA Security recommends at least 20 rounds. The key size can be as little as 0 (zero) and as many as 255 bytes. The RC5 cipher uses the secret key bytes to generate an expanded key table during the Init phase. The key table is then used during encryption or decryption. Therefore, key length will have no appreciable effect on algorithm speed.
Cryptography Overview would slow down the encryption and decryption operations. In addition, if the 20-round version of RC6 is accepted as submitted to the AES, a round count other than 20 rounds might not be AES. AES The National Institute of Standards and Technology (NIST) selected an alogorithm (Rijndael) as the replacement for the Data Encryption Standard (DES) in its Advanced Encryption Standard project. Crypto-C includes basic AES support.
Cryptography Overview Electronic Codebook (ECB) Mode ECB is not a feedback mode; it encrypts each block of input independently of all other blocks. Plaintext patterns are not concealed; instead each identical block of plaintext yields an identical block of ciphertext. This could help an eavesdropper break the code. In addition, the plaintext can be easily manipulated by removing, repeating, or interchanging blocks. The speed of each encryption operation is identical to that of the block cipher.
Cryptography Overview Cipher Block Chaining (CBC) Mode With CBC mode, each plaintext block is XORed with the previous ciphertext block, then encrypted. CBC mode is as secure as the underlying block cipher against standard attacks. In addition, any patterns in the plaintext are concealed by the XORing of the previous ciphertext block with the plaintext block. The decryptor follows the same sequence of steps to decrypt, using the same (secret) key and initialization vector (IV).
Cryptography Overview 1st message block P 1 Initialization Vector (IV) Block Cipher B1 XOR 1st cipher block C1 Key (K) 2nd message block P2 Block Cipher B2 XOR 2nd cipher block C 2 Key (K) Figure 3-5 Cipher Feedback (CFB) Mode To encrypt plaintext using CFB mode: 1. Generate your key and your IV. 2. Encrypt the IV with the key to get a block of output, B1. 3. XOR B1 with the first block of your plaintext, P1, to get the first block of ciphertext, C1. 4.
Cryptography Overview Output Feedback (OFB) Mode Output feedback mode is similar to CFB mode, except that the quantity XORed with each plaintext block is generated independently of both the plaintext and the ciphertext. To encrypt a plaintext using OFB, first generate the “output” used for encryption. This is intermediate data that is used in the encryption process. In OFB, the output depends only on the key and the initialization vector. 1. Generate your key and your IV. 2.
Cryptography Overview 1st message block Initialization Vector (IV) Block Cipher XOR 1st cipher block Key (K) 2nd message block Block Cipher XOR 2nd cipher block Key (K) Figure 3-6 Output Feedback Mode (OFB) Stream Ciphers A stream cipher processes the input data one unit at a time. A unit of data is generally a byte, or sometimes even a bit. In this way, encryption or decryption can execute on a variable length of input.
Cryptography Overview guess), an attacker would be able to determine some of the original message bytes by XORing two sets of cipher bytes. Key Key Mixing Pseudorandom bytes Nth message byte Figure 3-7 XOR Nth cipher byte RC4 Encryption or Decryption The RC4 algorithm with MAC The RC4-with-MAC algorithm is an extension of the RC4 cipher. It provides data integrity by using a Message Authentication Code (MAC) with the RC4 encryption algorithm.
Cryptography Overview • It is computationally infeasible to produce data that has a specific digest. In other words, given a particular block of the proper size, it will be virtually impossible to determine a unit of data that will digest to that particular block. • It is computationally infeasible to produce two different units of data that produce the same digest. In other words, given some data, it is virtually impossible to create different data that will digest to the same block as the first.
Cryptography Overview Hash-Based Message Authentication Codes (HMAC) A hash-based message authentication code (HMAC) combines a secret key with a message digest to create a message authentication code. This method of creating a MAC makes it possible to update the underlying message digest if a new attack makes the original message digest unsecure. Crypto-C provides an HMAC implementation based on SHA1.
Cryptography Overview Normally, the mixing is a message digest. This makes the task of getting from password to key very time-consuming for an attacker. Digesting a password with a salt helps thwart dictionary attacks. An attacker could put together a “dictionary” of keys generated from likely passwords, and try out each key on encrypted data. This would greatly reduce the amount of work necessary to find the key and may make it feasible to recover encrypted material.
Cryptography Overview her message using that public key. Unlike symmetric-key cryptography, the key used for encryption will not decrypt the message. That is, knowledge of Bob’s public key will not help an attacker. To decrypt a message, Bob uses his private key. If Bob wants to respond to Alice, he can encrypt his message using her public key. To understand this idea, think of taking a number to a power. For instance, given values x and y, compute z = xy.
Cryptography Overview authentication that MIT professors Ronald L. Rivest, Adi Shamir, and Leonard M. Adleman invented in 1977. It is actually similar to the example in the previous section that takes numbers to a power, except that it works in modular math. Modular Math Modular math uses a positive integer as a modulus; the only numbers under consideration are the integers from 0 to one less than the modulus.
Cryptography Overview below. To compute ciphertext c from a plaintext message m, find c = me mod n. To decrypt, determine the private key d, the inverse of e, and compute m = cd mod n. The relationship between e and d ensures that the algorithm correctly recovers the original message m, because cd = (me)d = med ≡ m1 = m mod n. Only the entity that knows d can decrypt.
Cryptography Overview The calculation is shown in Table 3-1: Calculation of 827 mod 55 Table 3-1 80 1 mod 55 81 8 mod 55 8 2 81 · 81 = 8 · 8 = 64 64 – 55 = 9 9 mod 55 8 4 82 · 82 = 9 · 9 = 81 81 – 55 = 26 26 mod 55 8 8 84 · 84 = 26 · 26 = 676 676 – (12 · 55) = 16 16 mod 55 16 88 · 88 = 16 · 16 = 256 256 – (4 · 55) = 36 36 mod 55 8 · 9 = 72 72 – 55 = 17 17 · 16 = 272 272 – (4 · 55) = 52 52 mod 55 52 · 36 = 1872 1872 – (34 · 55) = 2 2 mod 55 8 81 · 82 (8 · 8 ) · 8 1 2 8 (
Cryptography Overview However, for very large numbers, factoring is very difficult. The RSA Laboratories publication, Frequently Asked Questions About Today’s Cryptography (the FAQ), describes the state of the art in factoring. Factoring numbers takes a certain number of steps, and the number of steps increases exponentially as the size of the number increases. Even on supercomputers, the time to execute all the steps is so great that for large numbers it could take years to compute.
Cryptography Overview to reveal the contents of a digital envelope. The main features of OAEP are redundancy and randomization. The redundancy feature makes it difficult for an attacker to create a new derived message from an existing ciphertext message. The recipient of a derived message checks the redundancy after decrypting the message and rejects redundant messages. The PKCS #1 format has only about 16 bits of redundancy, whereas OAEP formats have 64 to 160 bits of redundancy.
Cryptography Overview Authentication and Digital Signatures Suppose Alice and Bob are disputing a contract. Alice says that Bob must uphold certain obligations because he agreed to them in a contract. Bob says that this is not the contract he signed. He offers as evidence his copy of the contract and sure enough, it differs from Alice’s.
Cryptography Overview 1. Alice and Bob compose a contract in digital format. The file can be in any form, such as a word processing file or an ASCII file. 2. Each party digests the file and encrypts the digest with their private key. 3. That encrypted digest is their digital signature. 4. The contract now consists of the file and the two copies of the encrypted digest, one using Alice’s private key, the other using Bob’s private key. Everyone gets copies of this contract.
Cryptography Overview 4. Digest the message file. 5. If the digest matches the 16 bytes you obtained from decrypting the original 96byte block, the message is verified. That is, you can assume the 96-byte block is the file’s digest encrypted with the RSA private key associated with the public key you used. It would have been computationally infeasible to produce that 96byte block any other way. There are other uses for a digital signature.
Cryptography Overview Digital Signature Algorithm (DSA) The Digital Signature Algorithm (DSA) is part of the Digital Signature Standard (DSS), published by the National Institute of Standards and Technology (NIST), a division of the US Department of Commerce. It is the digital authentication standard of the US government. The DSS specifies the Secure Hash Algorithm (SHA1) as the message digest to use with DSA when generating a digital signature. To generate a DSA key pair: 1.
Cryptography Overview a = gu1 mod p b = yu2 mod p v = (a · b mod p) mod q 3. If v = r, the signature is verified. If v ≠ r, the signature is invalid. The Math To see that this is indeed the signature, consider the following.
Cryptography Overview A certificate connects an entity to a public key. For instance, it can list an individual’s name, address, and public key. When people want to use a person’s public key, they look up the certificate associated with that person’s name and address. A certificate can contain a wide variety of information on its owner, such as the person’s organization or job title. This helps differentiate between people who have the same name.
Cryptography Overview • • Phase 1 Phase 2 Parameters Phase 1 Alice Bob Private value Private value Public value Public value Alice Bob Phase 2 Agreed upon key Figure 3-12 = Agreed upon key The Diffie-Hellman Key Agreement Protocol Parameter Generation A central authority selects a prime number p of length k bytes, and an integer g greater than 0 but less than p, called the base.
Cryptography Overview 3. The two parties exchange the public values. These private and public values correspond to the private and public key components of a key pair. The public value is generated in such a way that computing the private value from the public number is computationally infeasible. Phase 2 Each participant computes the agreed-upon secret key, z, using the other participant’s public value, y', their own private value, x, and the prime, p.
Cryptography Overview Security The security of Diffie-Hellman key agreement relies on the difficulty of computing nth roots modulo a prime number. It takes very little time to exponentiate a number modulo a prime, but it takes a great deal of time to compute its roots. This problem in modular arithmetic is called the discrete logarithm problem. (Recall that, in the real numbers, if you can compute the logarithm of a number, you can easily compute all of its roots.
Cryptography Overview • • • Elliptic Curve Signature Schemes (ECDSA) Elliptic Curve Authenticated Encryption Scheme (ECAES) Elliptic Curve Diffie-Hellman key agreement (ECDH) Crypto-C also allows you to generate precomputed acceleration tables to speed up certain elliptic curve operations. For more information, see the example “Generating a Public-Key Acceleration Table” on page 277. Elliptic Curve Parameters A number of parameters are necessary for elliptic curve cryptosystems.
Cryptography Overview • • An odd prime field, Fp, where p is an odd prime. A field of even characteristic, F2m. For more information about finite fields, see the book by A. Menezes, I. Blake, X. Gao, R. Mullin, S. Vanstone, and T. Yaghoobian, Applications of Finite Fields [18] and also Chapter 2 of Alfred J. Menezes, Paul C. van Oorschot, and Scott A. Vanstone’ s book, Handbook of Applied Cryptography [17]. Odd Prime Fields The odd prime field Fp is simply Zp, the integers mod p.
Cryptography Overview 0 = 0·I ≡ (2·2m–1)·I mod2m = 2·(2m–1·I) ≡ 2·1 mod 2m =2 Instead, we create the field F2m in a completely abstract manner. We start by letting the elements of the finite field F2m be the bit strings of bit-length m. Mathematicians have shown that it is possible to create an addition and a multiplication that make these strings, called m-tuples, into a field. Addition is easy to define: to add two strings, just XOR them. This is the same as adding them bit by bit, with no carry.
Cryptography Overview elliptic curve parameters. Coefficients Over a Field of Even Characteristic An elliptic curve E over a field of even characteristic F2m is all the pairs of points (x,y) that satisfy the equation: y2 + xy = x3 + ax2 +b In this equation, x and y are elements of F2m, and so are a and b. The whole equation is evaluated over F2m. For computational reasons, there is also a “point at infinity”, Ο, that is included as well.
Cryptography Overview is written E(Fq). The Order of an Elliptic Curve The addition system that makes the points on the elliptic curve into what is called a group has a number of properties. First, there can only be a finite number of points on the curve. If every possible pair (x,y) were on the curve, there would be only p2 or (2m)2 = 22m possibilities of pairs. The total number of points, including the point Ο, is called the order of the elliptic curve. The order is written as #E(Fq).
Cryptography Overview • The order n of P P is sometimes called the base point. The Cofactor We mentioned previously that the prime number n that is the order of P must evenly divide the order of the elliptic curve. That is, we know that the number h = #E(Fq)/n is an integer. We call h the cofactor, and set it as our last parameter: • The cofactor h = #E(Fq)/n Summary of Elliptic Curve Terminology Table 3-2 lists the elliptic curve parameters and gives a short description of each parameter.
Cryptography Overview Representing Fields of Even Characteristic For fields of even characteristic (fields of the form F2m), Crypto-C allows you to choose how you want the field to be represented. The representation you choose is internal to Crypto-C and affects how field arithmetic is performed. The choice of representation is also one of the formal elliptic curve parameters that must be transmitted along with the public key.
Cryptography Overview Creating the Key Pair To compute a public/private key pair: 1. Generate a random value, d, between 1 and n–1. 2. Compute the elliptic curve point dP, that is, P added to itself d times. Call this point Q; it is a pair of field elements (xQ,yQ). The key pair is (Q,d): Q is the public key, d is the private key. As previously mentioned, even if you know P and Q, you cannot easily calculate d.
Cryptography Overview x 1 , you will be using regular arithmetic. This is so different from arithmetic in F2m that, for example, x 1 + x 2 ≠ x 1 + x 2 . However, if you convert two field elements and perform operations on them that show they are equal after conversion, then they were equal before conversion. 5. Compute s = k–1(e+dr) mod n. Again, you must check that s is nonzero. The signature for this message is the pair r and s.
Cryptography Overview The following calculations are really just a series of substitutions that can be made by looking back at the definition. You may find it more convincing to go through the substitution steps yourself, by glancing back at the preceding sections Creating the Key Pair, Signing a Message, and Verifying a Signature. If the message has been signed correctly, then s = s’.
Cryptography Overview Encrypting a Message Using the Public Key Anyone who wishes to send Bob an encrypted message can do so using the elliptic curve parameters and Q. To encrypt a message M, where the length (in bytes) of the message is f, another party follows these steps: 1. Compute a random value, k1, between 1 and n – 1. 2. Compute the elliptic curve point Q1 = k1P. This will be transmitted along with the encrypted message. 3. Compute the elliptic curve point S1 = k1Q. S1 is a pair (x1,y1).
Cryptography Overview 6. Compute an authentication tag, tag = SHA1 (x1 || M’). That is, tag is the SHA1 hash of concatenation of the x-coordinate of the secret point k1Q and the message M’. Since tag is an SHA1 hash, tag is 20 bytes long. 7. Transmit the ciphertext c = (Q1,M’,tag). The total length of c in bytes is: 21+2 · (the length of a field element in bytes) + f.
Cryptography Overview Phase 1 The first party randomly generates a private value, a number k1, greater than 0 but less than n. Similarly, the second party generates a random private value, k2. Each party then computes a public value. To do this, they each compute Ri = kiP. For each party, this is an elliptic curve point. The two parties exchange their public values. These private and public values correspond to the private and public key components of a key pair.
Cryptography Overview Parameters Phase 1 Alice Bob Private value Private value Public value Public value Alice Bob Phase 2 Agreed upon key Figure 3-13 = Agreed upon key Elliptic Curve Diffie-Hellman Key Agreement The Math Even though the two parties involved are making computations using different private values, they will both end up with the same secret key, as illustrated by the following.
Cryptography Overview R2: 2nd party’s public value xS: secret key In phase 1, each party computes a private value, ki, and then a public value, Ri: R1 = k1P R2 = k2P In phase 2, the parties trade public values and compute the same elliptic curve point S: S = k1R2 = k1k2P S = k2R1 = k2k1P The first coordinate of S, xS, is their agreed-upon secret key.
Cryptography Overview Share #1 Secret Splitting A Secret Value . . . N Shares Share # N Figure 3-14 Any K out of the N shares Figure 3-15 Secret Sharing — Key Share Assignment . . . Secret Reconstruction The Original Secret Secret Sharing — Full Key Generation From Shares Working with Keys Key Generation The techniques for generating public/private key pairs and symmetric keys are quite different.
Cryptography Overview Key Management The term key management refers to the collection of processes and methods for assigning the right keys to communication sessions, providing the right keys to the right persons, and making sure unauthorized personnel cannot gain access to keys. Key management is the most difficult security problem.
Applications of Cryptography ASCII Encoding and Decoding ASCII encoding and decoding is required when you need to send encrypted or signed data using communication protocols that allow transmission of printable characters only. In this case, the application must convert the encrypted 8-bit values to a string of printable characters. Crypto-C uses the Internet RFC1113 method for implementing ASCII-encoding. The Internet Draft RFC1113 is a publication that describes this system.
Applications of Cryptography • Ensure file integrity and protect against tampering. Cryptographic techniques can be used to guarantee that only authorized personnel can modify or install certain files. • • Archive important data so that it can be accessed only by authorized personnel. Protect intellectual property. Point-to-Point Applications Applications that require establishing a secure link between two nodes are very common and may have different topologies.
Applications of Cryptography 4. Perform the encryption and decryption using the RC4 cipher with the established key. If the application requires multiple session keys, use a message digest on the agreed-upon secret value and a counter to generate a new key. There is an attack against this kind of protocol known as “man-in-the-middle.” Someone could intercept all messages between the two parties and pose as each individual’s other participant.
Applications of Cryptography public key is communicated to the server and an entry is made in the table maintained by the server for the public keys. As an alternative, the server can certify the public keys of the client nodes by generating a digital certificate to be signed by the server’s private key. In this case, the server only trusts messages from previously-certified keys.
Choosing Algorithms Choosing Algorithms In some cases, an application’s constraints determine the algorithm. In other cases, the developer can choose among a number of algorithm options and still produce a viable PKI solution. This section presents suggestions to help you determine the best choice. Public-Key vs. Symmetric-Key Cryptography Because symmetric-key encryption algorithms are much faster than public-key algorithms, they are most suited for bulk data encryption.
Choosing Algorithms Block Symmetric-Key Algorithms The following considerations may help when choosing between DES, DESX, Triple DES, and the RC2, RC5, and RC6 algorithms. DES is a standard algorithm in use by many applications. Using DES ensures widespread connectivity. However, DES is limited to an effective key size of 56 bits. The cryptography community expects that, because of the continued increase in computing power, within a few years, DES will not be strong enough to withstand attacks.
Choosing Algorithms Digital envelopes are more convenient when the contact between nodes is not interactive, such as email. One node can send a message to another without waiting for the other node to respond. To thwart man-in-the-middle attacks, authentication by digital signatures should be built into any communication system. Secret Sharing and Key Escrow Also known as emergency access, secret sharing and key escrow both allow for recovery of keys by parties other than the owner.
Choosing Algorithms limited. In typical applications of cryptography, public-key operations are employed in combination with other techniques. In particular, public-key operations often represent only a minor overhead in the total processing, whether in storage or in computation time. A “faster” or “smaller” public-key technique thus may have little overall impact in many applications. Elliptic curve cryptosystems have, at this point, relatively fewer cryptanalytic results than established systems.
Security Considerations already in place, or where a hardware developer wants to be able to provide a platform that supports both RSA and elliptic curve encryption. For the even characteristic finite field, F2m, there is also a choice of representation. For these fields, elements can be represented using a polynomial basis, a normal basis, or some other basis. For some values of m, elements can also be represented in an optimal normal basis, which is generally more efficient than an ordinary normal basis.
Security Considerations that ensure allocation of core memory, and not of virtual memory. It is a good idea to generate new public/private key pairs every so often to thwart long-term factoring attacks. Material encrypted using the old key pair should be reencrypted with the new. However, an application may not have access to all material protected by an old key pair, so it may be necessary to retain old key pairs in a secure environment.
Security Considerations attacker can predict two or three of the bits in each seed byte. Bit 7, for instance, will always be 0. Furthermore, many of the keystrokes can be predicted: they will probably be lowercase letters that alternate between the left and right hand. Analysis of this issue has determined that there is only one bit of entropy from each keystroke (think of the term “entropy” as “unrepeatability”). When using keystrokes, use at least one for each bit of key size.
Security Considerations Initialization Vectors and Salts Although IVs and salts are not secret information, it is still a good idea to use random values. If a salt is not random, an attacker will have much fewer precomputations to make in generating keys from possible password/salt combinations. An IV should also be used for only one message. Using the same IV with the same key on two separate messages may provide an attacker with useful information.
Security Considerations Stream Ciphers A stream cipher (such as the RC4 cipher) will create a stream of pseudo-random bytes based on the secret key; this is known as the key stream. To encrypt, you XOR the plaintext with the key stream, byte by byte. The XOR operation has the property that the ciphertext XORed with the same key stream decrypts, restoring the plaintext. This also means that an XOR operation between the plaintext and the ciphertext will reproduce the key stream.
Security Considerations parameters, then in theory, an attacker with access to accurate timings can determine unknown values. This is the case for RSA, Diffie-Hellman, and DSA operations. For instance, in an RSA signing operation, purportedly an attacker who knows the message being signed and exactly how long it takes to create the digital signature can determine the signer’s RSA private key. Currently, there is no known successful implementation of such a procedure.
Security Considerations = (r-1)(r)(md) = (1)(md) mod n Crypto-C offers both blinding and non-blinding RSA private operations through separate algorithm methods. It currently offers no blinding technique in DiffieHellman or DSA operations. Crypto-C uses MD5 random number generation to produce the random value r.
Security Considerations Table 3-4 gives a summary of the recommended key sizes for the algorithms supported in Crypto-C. These recommendations were current at the time this manual went to press. Please note, however, that such recommendations are always provisional and can be affected by changes in the cryptographic state of the art.
Security Considerations progress in factoring algorithms and improvements in computing power. Diffie-Hellman Parameters and DSA Keys The security of the Diffie-Hellman algorithm and DSA are both dependent on the complexity of computing logarithms modulo a prime number. Generally, this is equivalent to the complexity of the factoring problem, because modern factoring algorithms generally apply to the discrete logarithm problem.
Security Considerations Elliptic Curve Keys For prototyping and evaluation, RSA Security recommends setting the order of the base point to be between 160 and 170 bits. Currently, RSA Security does not recommend using elliptic curve cryptography for long-term applications.
Chapter 4 Using Crypto-C Algorithms in Crypto-C Whatever algorithm Crypto-C performs, it does so from an algorithm object. An algorithm object is used to hold information about an algorithm’s parameters and to keep a context during cryptographic operations. To build an algorithm object, create an empty object with B_CreateAlgorithmObject. Then, use B_SetAlgorithmInfo to fill the object with the information necessary to distinguish it as an object performing the desired operation.
Algorithms in Crypto-C Information Formats Provided by Crypto-C There are four types of AIs in Crypto-C. These AIs differ in the format in which they provide information: • • Basic algorithm info types provide information in Crypto-C’s internal format. • PEM-based algorithm info types provide information in a format that complies with the Privacy Enhanced Mail draft standard. • BSAFE1 algorithm info types provide information in a format that is backwardcompatible with BSAFE 1.x.
Algorithms in Crypto-C PEM-Based Algorithm Info Types The Privacy Enhanced Mail (PEM) draft standard is a product of the Internet Activities Board, Network Working Group (see RFC 1421-1424). It defines the proper formatting of information passed between entities in electronic mail. Formatting information to follow this standard is fairly simple. BSAFE1 Algorithm Info Types The fourth kind of AI ends with BSAFE1.
Algorithms in Crypto-C Note: Not all message digests are recommended. See “Message Digests” on page 47 for details. Table 4-2 Message Authentication Algorithm Info Type Description AI_MAC BSAFE 1.x message authentication code; supplied for backward compatibility with BSAFE 1.
Algorithms in Crypto-C Table 4-5 Symmetric Stream Ciphers Some stream ciphers include message authentication codes to detect tampering with the data stream.
Algorithms in Crypto-C Table 4-6 Symmetric Block Ciphers (Continued) Algorithm Info Type Description Padding AI_DESX_CBCPadBER DESX-CBC, 8-byte IV, BER-encoded algorithm identifier PKCS #5 AI_DESX_CBC_BSAFE1 DESX-CBC, 8-byte IV, padding optional; backward compatibility with BSAFE 1.
Algorithms in Crypto-C Table 4-6 Symmetric Block Ciphers (Continued) Algorithm Info Type Description Padding AI_MD2WithRC2_CBCPadBER MD2 digest followed by RC2-CBC, BER-encoded algorithm identifier PKCS #5 AI_MD5WithDES_CBCPad MD5 digest followed by DES-CBC PKCS #5 AI_MD5WithDES_CBCPadBER MD5 digest followed by DES-CBC, BER-encoded algorithm identifier PKCS #5 AI_MD5WithRC2_CBCPad MD5 digest followed by RC2-CBC PKCS #5 AI_MD5WithRC2_CBCPadBER MD5 digest followed by RC2-CBC, BER-encoded al
Algorithms in Crypto-C Table 4-7 RSA Public-Key Cryptography (Continued) Algorithm Info Type Description Pad AI_PKCS_OAEP_RSAPrivateBER RSA private-key encryption/decryption with OAEP in accordance with PKCS #1, BER-encoded algorithm identifier PKCS #1 v2 OAEP AI_PKCS_OAEP_RSAPublic RSA public-key encryption/decryption with PKCS #1 OAEP in accordance with PKCS #1 v2 OAEP AI_PKCS_OAEP_RSAPublicBER RSA public-key encryption/decryption with PKCS #1 OAEP in accordance with PKCS #1, v2 OAEP BER-encod
Algorithms in Crypto-C Table 4-7 RSA Public-Key Cryptography (Continued) Algorithm Info Type Description Pad BER PEM Digital Signatures Composite operations for signing data: digest the data, then encrypt the BER encoding of the digest with RSA. BER-encoded digest is 34 bytes for 16-bit digests (MD2, MD5); min. RSA modulus is 45 bytes long. BER-encoded digest is 35 bytes for 20-byte digests (SHA1); min. RSA modulus is 46 bytes long.
Algorithms in Crypto-C Table 4-9 Diffie-Hellman Key Agreement Algorithm Info Type Description BER Parameter Generation AI_DHParamGen Diffie-Hellman parameter generation Key Agreement AI_DHKeyAgree Diffie-Hellman key agreement AI_DHKeyAgreeBER Diffie-Hellman key agreement, BER-encoded algorithm identifier Table 4-10 a Elliptic Curve Public-Key Cryptography Algorithm Info Type Description Parameter Generation AI_ECParamGen EC parameter generation AI_ECParameters EC parameter use and access
Algorithms in Crypto-C Table 4-10 Elliptic Curve Public-Key Cryptography (Continued) Algorithm Info Type Description Elliptic Curve DSA AI_EC_DSA Raw ECDSA signature/verification AI_EC_DSAWithDigest SHA1 digest followed by ECDSA signature/verification Elliptic Curve Authenticated Encryption System AI_EC_ES Table 4-11 EC Authenticated Encryption System Bloom-Shamir Secret Sharing Algorithm Info Type Description AI_BSSecretSharing Bloom-Shamir secret sharing Table 4-12 Hardware Interface Fo
Algorithms in Crypto-C Table 4-13 Advanced Encryption Standard (AES) Algorithm Info Type Description AI_AES_CBC AES encryption or decryption in CBC mode. No padding. AI_AES128_CBC AES encryption or decryption in CBC mode. No padding. AI_AES192_CBC AES encryption or decryption in CBC mode. No padding. AI_AES256_CBC AES encryption or decryption in CBC mode. No padding. AI_AES_CBCPad AES encryption or decryption in CBC mode. PKCS #5 padding.
Keys In Crypto-C Keys In Crypto-C The key object is used to hold any key-related information and to supply this information to functions that require it. To build a key, create an empty key object with B_CreateKeyObject. Then, use B_SetKeyInfo to fill it with the information necessary to distinguish it as the desired key. That information for B_SetKeyInfo is made up of two items, a Key Info Type (KI) and its specific accompanying info.
Keys In Crypto-C Table 4-15 Block Cipher Keys Key Information Type Description KI_RC2_BSAFE1 RC2 key in BSAFE 1.x format KI_RC2WithBSAFE1Params RC2 key with additional parameters in BSAFE 1.
Keys In Crypto-C Table 4-18 Elliptic Curve Keys Key Information Type Description KI_ECPrivate EC private key and underlying EC parameters KI_ECPrivateBER BER-encoded EC private key and underlying EC parameters KI_ECPrivateComponent Private component of an EC private key KI_ECPrivateComponentBER Private component of a BER-encoded EC private key KI_ECPublic EC public key and underlying EC parameters KI_ECPublicBER BER-encoded EC public key and underlying EC parameters KI_ECPublicComponent Pu
System Considerations In Crypto-C System Considerations In Crypto-C Algorithm Choosers When you use an AI, it in turn calls one or more algorithm methods. An algorithm method (or AM) is the underlying code that will actually perform the cryptography. Because many AIs can perform more than one cryptographic function (for instance, both encryption and decryption, as with AI_FeedbackCipher), an application will often have a choice of which underlying cryptographic code to link in.
System Considerations In Crypto-C RC5, or RSA encryption. So we could have built an algorithm chooser that included only one AM, the one we used for RC4 encryption. To find the AM we need, look at the Reference Manual, Chapter 2, for the entry on the AI in use. We used AI_RC4. The Reference Manual states that for this AI, the possible AMs are AM_RC4_ENCRYPT for encrypting and AM_RC4_DECRYPT for decrypting.
System Considerations In Crypto-C description of AI_X962Random_V0 instead of AI_SHA1Random: B_ALGORITHM_METHOD *RSA_SAMPLE_CHOOSER[] = { &AM_SHA_RANDOM, &AM_RSA_KEY_GEN, &AM_RSA_ENCRYPT, &AM_RSA_CRT_DECRYPT, (B_ALGORITHM_METHOD *)NULL_PTR }; Note: The previous algorithm chooser lists AM_RSA_CRT_DECRYPT. This AM will not perform blinding (see “Timing Attacks and Blinding” on page 95). If you want your application to perform blinding, use AM_RSA_CRT_ENCRYPT_BLIND or AM_RSA_CRT_DECRYPT_BLIND.
System Considerations In Crypto-C typedef struct { int (*Surrender) (POINTER); POINTER handle; POINTER reserved; } A_SURRENDER_CTX; /* surrender function callback */ /* application-specific information */ /* reserved for future use */ Chapter 1 also gives the form that a surrender function must have: int (*Surrender) ( POINTER handle ); /* application-specific information */ If you define a surrender function within the surrender context, Crypto-C functions will call it at regular intervals during exec
System Considerations In Crypto-C if ((int)*handle == 0) { printf (“\nSurrender function ...\n”); *handle = 1; time (¤tTime); } else { time (&getTime); if (currentTime != getTime) { printf “ ."); currentTime = getTime; } } return (0); } A routine that calls Crypto-C functions would use the above surrender function as follows: A_SURRENDER_CTX generalSurrenderContext; int generalFlag; generalSurrenderContext.Surrender = GeneralSurrenderFunction; generalSurrenderContext.
System Considerations In Crypto-C object. When you call B_GetAlgorithmState, you receive a buffer that contains all of the data necessary to reconstruct the object, using the call B_SetAlgorithmState, to the state it was in at the time of calling the Get routine (B_GetAlogorithmState). This is useful in SSL, for example.
System Considerations In Crypto-C information it is looking for. This information, though, belongs to Crypto-C; subsequent Crypto-C calls can alter or erase it. If an application needs to save the information, it should copy it into its own buffer or allocated space. See “Distributing Diffie-Hellman Parameters” on page 253 for an example. Note: Crypto-C will sometimes call for an unsigned int argument and other times an unsigned int *.
System Considerations In Crypto-C Some applications may need to be completely autonomous; that is, they should have no need to link in any external libraries. As far as possible, the Crypto-C library is autonomous, but Crypto-C does need the functionality of certain standard C library routines, such as malloc. For Crypto-C to remain autonomous, the user must supply these routines. The routines in tstdlib.c do call the standard C library routines, so to use tstdlib.
System Considerations In Crypto-C more individuals. For example, users may need to transmit a public key, elliptic curve parameters, or an algorithm name. Not everyone uses Crypto-C, and how information is processed in Crypto-C may be different from another company’s package. There needs to be a standard for describing certain information. BER/DER is such a standard. Open Systems Interconnection (OSI, described in ANSI’s X.
System Considerations In Crypto-C Crypto-C returns a pointer to the location where we can find the info, not the info itself. When we destroy the object, that info will disappear. If we want to save it, we have to copy it over into our own buffer, the memory for which we must allocate. ITEM *getInfoBER; ITEM infoBER; infoBER.data = NULL_PTR; if ((status = B_GetAlgorithmInfo ((POINTER *)&getInfoBER, encryptionObject, AI_RC4_BER)) != 0) break; infoBER.len = getInfoBER–>len; infoBER.data = T_malloc (infoBER.
System Considerations In Crypto-C Input and Output Some of the AI entries in the Reference Manual include the categories “Input Constraints” and “Output Considerations”: • Input constraints generally describe the input requirements of the algorithm specified by the AI. • Output considerations warn you that there may be more (or fewer) output bytes than input bytes. Two algorithm types that typically have input constraints or output considerations are symmetric block algorithms and the RSA algorithm.
System Considerations In Crypto-C Crypto-C offers padding for the symmetric block-encryption algorithms, which have no restrictions on the total input length. Padding means that the total length of the encrypted data can be as many as eight bytes more than the total length of the input. For algorithm info types that supply padding, Crypto-C will pad even if the input is a multiple of the block size. This way, when decrypting, Crypto-C knows that the last byte is guaranteed to be a pad byte.
System Considerations In Crypto-C This applies to PKCS #1 v1.5 block 02 padding. Set OAEP or PKCS #12 OAEP have different requirements. Refer to the RSA BSAFE Crypto-C Reference Manual for the corresponding algorithm information type (AI) to obtain more information. • For raw RSA encryption and decryption, the application must divide the encryption or decryption input into blocks.
System Considerations In Crypto-C Key Size In cryptography, security is measured in key size: the bigger the key, the greater the security. Key size, in turn, is measured in bits. However, a bit number does not necessarily describe the entire key. DES Keys A DES key is 56 bits. However, that size refers to its cryptographic size, not its physical size. To build a DES key, you need 64 bits, but because eight of those bits are “parity bits,” which are known, you really only get 56 secret bits.
System Considerations In Crypto-C ends and the public exponent begins. It would be a good idea to put identifying marks on the data to make it easier to parse. BER/DER encoding standardizes such identifying marks as an industry standard so that people using different software packages can still trade information. Hence, with Crypto-C, the user has the option of storing a 768-bit public key simply as a modulus and public exponent (99 bytes), or in its DER-encoded format, which requires 126 bytes.
System Considerations In Crypto-C • Total: 484 bytes In addition, when the most significant bit of the most significant byte of a value is set, DER calls for a prepended 0 byte, so that it is not interpreted as a negative 2’s complement number. For example, converting the decimal number 3,260,571,825 into hex yields 0xC25860B1. As a byte string, it would be: C2 58 60 B1 which is four bytes long.
Using Cryptographic Hardware Using Cryptographic Hardware Crypto-C lets you enhance the security and speed of cryptographic operations by exploiting cryptographic hardware that supplies an interface to CryptoC via the BSAFE Hardware Application Programming Interface (BHAPI). Capabilities include a hardware algorithm method for random number generation and key token types that encapsulate RSA, DSA, and symmetric keys inside of hardware.
Using Cryptographic Hardware the application has been compiled. If more than one hardware method is present for the same AM — for example, if the application includes hardware methods implementing RSA encryption from two different manufacturers — B_CreateSessionChooser includes all available hardware methods. When an object’s methods are instantiated at initialization, Crypto-C loads the object with the first compatible method from the session chooser.
Using Cryptographic Hardware PKCS #11 Support PKCS #11 support has been added to Crypto-C v5.1. The routine will allow you to create a new algorithm chooser from an existing chooser. It uses the hwInfoType to determine which of the AM's in the currentChooser are to be supplemented with hardware functionality. Then it uses this information to create a new AM. The routine then creates a new chooser that contains all the AM's in currentChooser plus any new AM's created.
Using Cryptographic Hardware Using a PKCS #11 Device with Crypto-C If you want to have Crypto-C use a PKCS #11 device to perform the crypto, you must first build a hardware chooser. To do that, call, B_CreateHardwareChooser.
Using Cryptographic Hardware In this example, we passed 0 for sessionHandle and NULL_PTR for cryptokiFunctions. This means we want Crypto-C to load up the library (whose shared library name, p11DLLName, is given in the libraryName field), do the necessary initializations, find the appropriate token (if installed) using the given tokenLabel, then log on using the given passPhrase and create a session. After the call to B_CreateHardwareChooser, if we examined p11Session.
Using Cryptographic Hardware surrender context (private key operations are more susceptible to a timing attack when you use a surrender context, for instance), you must pass in NULL_PTR. If you want one operation to use a surrender context and another not to, you must create two choosers. When, later on, you call the Crypto-C function that will actually call down to the token (such as B_GenerateKeypair or B_SignFinal), Crypto-C will ignore any surrenderContext argument you pass at that time.
Using Cryptographic Hardware want to create a hardware chooser only, and if you want to do the task in hardware, or if you can't you don't want to do it at all, then pass in a (B_ALGORITHM_CHOOSER)NULL_PTR as the swReplacement argument. Note that often a software backup is not necessarily possible. A token may possess the signing key and does not allow it to leave the device. If you can not do the task in hardware, you can not do it in software, since you do not have the key.
Using Cryptographic Hardware B_KEYPAIR_GEN_PARAMS keypairGenParams; keypairGenParams.privateKeyAttributes.keyUsage = CF_DIGITAL_SIGNATURE; keypairGenParams.privateKeyAttributes.tokenFlag = TF_PRIVATE; keypairGenParams.privateKeyAttributes.start = 0; keypairGenParams.privateKeyAttributes.end = 0; keypairGenParams.publicKeyAttributes.keyUsage = CF_DIGITAL_SIGNATURE; keypairGenParams.publicKeyAttributes.tokenFlag = TF_RESIDE_ON_TOKEN; keypairGenParams.publicKeyAttributes.start = 0; keypairGenParams.
Using Cryptographic Hardware may need to set the attributes manually for the token to work. You can use this AI for any key pair generation, not just RSA. If you use this AI for software key pair generation, the attributes will be ignored. After setting the algorithm object to generate a key pair, initialize.
Using Cryptographic Hardware info types if it is a key that resides on the token and is not private. KI_TOKEN_INFO *priKeyToken = (KI_TOKEN_INFO *)NULL_PTR; ITEM *pubKeyInfo = (ITEM *)NULL_PTR; if ((status = B_GetKeyInfo ((POINTER *)&priKeyToken, priKey, KI_Token)) != 0) break; if ((status = B_GetKeyInfo ((POINTER *)&pubKeyInfo, pubKey, KI_RSAPublicBER)) != 0) break; Now you can send the public key to whomever you want. You can also save the private key token info.
Using Cryptographic Hardware This code looks just like regular code. Whether you are signing with software or hardware, it looks the same. See the sample files in the sample\pkcs11 directory. We are using the hardware chooser we created. To perform RSA signatures (with MD5) we need to include AM_MD5 in our chooser. Our original chooser contained AM_MD5 and AM_PKCS11_RSA_PRIVATE_SIGN.
Using Cryptographic Hardware CK_RV rv; CK_SESSION_HANDLE sessionHandle; HINSTANCE libHandle; GetFunctionList GetList; CK_FUNCTION_LIST_PTR fnctList; /* Load the library if possible. */ libHandle = LoadLibrary (p11Info->session.libraryName); if (libHandle == (HINSTANCE)NULL_PTR) return (BE_HARDWARE); /* Get the PKCS 11 function C_GetFunctionList. With this function, we can get the function list (pointers to all PKCS 11 functions) with one call.
Using Cryptographic Hardware PKCS #11 Support for DSA Key Pair Generation This section describes how to generate a DSA key pair using a PKCS #11 device. You will need some DSA parameters, since PKCS #11 does not specify a way to generate parameters. If you do not already have them, use Crypto-C to generate some DSA parameters.
Using Cryptographic Hardware B_ALGORITHM_METHOD *DSA_KEY_GEN_CHOOSER[] = { &AM_DSA_KEY_GEN, (B_ALGORITHM_METHOD *)NULL_PTR; }; B_ALGORITHM_OBJ dsaKeyGen = (B_ALGORITHM_OBJ)NULL_PTR; B_KEY_OBJ pubKey = (B_KEY_OBJ)NULL_PTR; B_KEY_OBJ priKey = (B_KEY_OBJ)NULL_PTR; if ((status = B_CreateAlgorithmObject (&dsaKeyGen)) != 0) break; if ((status = B_CreateKeyObject (&pubKey)) != 0) break; if ((status = B_CreateKeyObject (&priKey)) != 0) break; if ((status = B_GenerateParameters (dsaParamGen, dsaKeyGen, randomObject
Using Cryptographic Hardware destroying, or copy it into your own buffer. Since you generated the key pair only to be able to extract the parameters, you will almost certainly want to simply throw away the generated keys. Once you have the parameters, you can generate a key pair using PKCS #11. This will look just like RSA key pair generation, except instead of using AM_PKCS11_RSA_KEY_GEN, you will use AM_PKCS11_DSA_KEY_GEN.
Using Cryptographic Hardware Advanced PKCS #11 This chapter earlier described internalKey as the collection of three items: CKA_CLASS, CKA_TYPE and the digest of the modulus. A more rigorous description would be CKA_CLASS, CKA_TYPE and CKA_ID. When Crypto-C generates a key pair, it uses the SHA-1 digest of the modulus as the CKA_ID. CKA_CLASS CKA_TYPE CKA_ID For an RSA private key, it would be this. CKO_PRIVATE_KEY 00 00 00 03 00 00 00 00 CKK_RSA 66 a9 47 2d 80 5a. . .
Using Cryptographic Hardware In real life, you may never have to use this feature. Mostly you will retrieve the internalKey from your database, use it, close out the session and be done. But if there is some odd case where you have the key handle and want to pass it to Crypto-C, this is the way to do it. Random Numbers In our sample, we say the random object you create will not be used. If random numbers are needed, the token will use its own random number generator.
Using Cryptographic Hardware To implement this, the hardware accelerator might require you to call its keywrapping routines to build a digital envelope. When you request the key in order to store it for later use, the hardware could return a handle to the key. But if you give that data to another cryptographic package, the key will mean nothing. So, once you build a key (symmetric or private) on a hardware device, it is possible that only that hardware device will be able to use that key.
150
Chapter 5 Non-Cryptographic Operations Crypto-C supplies a number of non-cryptographic algorithms that are necessary for cryptographic applications.
Message Digests Message Digests A message digest is a fixed-length, statistically-unique identifier that corresponds to a set of data. That is, each unit of data — such as a file, string, or buffer — maps to a particular byte sequence (usually 16 or 20 bytes long). A digest is not random: digesting the same unit of data with the same message-digest algorithm will always produce the same byte sequence. Digests are used in random-number generation, password-based encryption, and digital signatures.
Message Digests if ((status = B_SetAlgorithmInfo (digester, AI_SHA1, NULL_PTR)) != 0) break; Step 3: Init To initialize a message digest, call B_DigestInit. The Reference Manual Chapter 4 entry on B_DigestInit shows that it requires four arguments. The first argument is the algorithm object. The second is a key object. All Crypto-C message digest AIs call for a properly cast NULL_PTR as the key object; Crypto-C provides this argument for algorithms, like HMAC, that require keys.
Message Digests Your call will be the following: /* The variable dataToDigest should already point to allocated memory and contain the data, dataToDigestLen should already be set to the number of bytes to digest. */ unsigned char *dataToDigest; unsigned int dataToDigestLen; if ((status = B_DigestUpdate (digester, dataToDigest, dataToDigestLen, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; Step 5: Final An MD2 or MD5 digest is always 16 bytes; an SHA1 digest is always 20 bytes.
Message Digests Step 6: Destroy Remember to destroy all objects when you are done with them: B_DestroyAlgorithmObject (&digester); BER-Encoding the Digest If you want to send your digest to someone, you should BER-encode the algorithm identifier and the digest. The Crypto-C function B_EncodeDigestInfo offers a way to put together a string containing your information in BER format. The example in this section corresponds to the file mdber.c.
Message Digests The following example BER-encodes the preceeding sample digest: #define DIGEST_LEN 20 #define ALG_ID_LEN DIGEST_LEN + 18 ITEM *sha1AlgInfoBER; unsigned char digestInfoBER[ALG_ID_LEN]; unsigned int digestInfoBERLen; if ((status = B_GetAlgorithmInfo ((POINTER *)&sha1AlgInfoBER, digester, AI_SHA1_BER)) != 0) break; if ((status = B_EncodeDigestInfo (digestInfoBER, &digestInfoBERLen, ALG_ID_LEN, sha1AlgInfoBER, digestedData, digestedDataLen)) != 0) break; To decode BER-encoded information, call
Message Digests B_DigestUpdate before calling B_DigestFinal(). This is useful when an application is called upon to digest large amounts of data. It will feed "bite-sized" pieces of data to the algorithm object instead of having to fit the entire input data into memory at one time. The DigestDataMultipleUpdates helper function in mdigsv.c shows this scenario.
Message Digests state of the algorithm object following the call to B_DigestUpdate. The digestAI argument is simply the AI_* that we used in the original B_SetAlgorithmInfo call. This is required because each AI_* has a routine associated with it internally, which it uses to interpret the data in the given state info. The dataToDigest argument contains the block to digest.
Message Digests Table 5-1 Code Sample: DigestDataSavedState() int DigestDataSavedState (ITEM *stateInfo, B_INFO_TYPE digestAI, ITEM *dataToDigest) { int status = 0; B_ALGORITHM_OBJ digestObj = NULL; ITEM newStateInfo = {NULL, 0}, bsfStateInfo = {NULL, 0}; do { if ((status = B_CreateAlgorithmObject (&digestObj)) != 0) break; if ((status = B_SetAlgorithmState (digestObj, digestAI, stateInfo, DIGEST_CHOOSER)) != 0) break; if ((status = B_DigestUpdate (digestObj, dataToDigest->data, dataToDigest->len, NULL)
Message Digests T_memcpy (newStateInfo.data, bsfStateInfo.data, newStateInfo.len); } while (0); if (status != 0) RSA_PrintError ("DigestDataSavedState", status); else { /* update stateInfo so the caller can have an updated algorithm object */ T_memset (stateInfo->data, 0, stateInfo->len); T_free (stateInfo->data); stateInfo->data = newStateInfo.data; stateInfo->len = newStateInfo.
Hash-Based Message Authentication Code Hash-Based Message Authentication Code (HMAC) A hash-based message authentication code (HMAC) combines a secret key with a message digest to create a message authentication code. See “Hash-Based Message Authentication Codes (HMAC)” on page 49 for a description of the algorithm. Crypto-C provides an HMAC implementation based on SHA1. Recall that SHA1 produces a 20-byte digest and takes input in 64-byte blocks. The example in this section corresponds to the file hmac.c.
Hash-Based Message Authentication Code (HMAC) B_DIGEST_SPECIFIER hmacInfo; hmacInfo.digestInfoType = AI_SHA1; hmacInfo.digestInfoParams = NULL_PTR; if ((status = B_SetAlgorithmInfo (HMACDigester, AI_HMAC, (POINTER)&hmacInfo)) != 0) break; Step 3: Init For hash-based message authentication, you need a key before you can initialize the object.
Hash-Based Message Authentication Code /* Complete Steps 1-4 of Generating Random Numbers */ /* Generate KEY_SIZE bytes of random data for the key. */ if ((status = B_GenerateRandomBytes (randomAlgorithm, keyData, KEY_SIZE, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; keyDataItem.data = keyData; keyDataItem.len = key_Size; /* Set the key object */ if ((status = B_SetKeyInfo (HMACKey, KI_Item, (pointer) & keyDataItem)) != 0) break; Once you have properly initialized the key object, you can call B_DigestInit.
Hash-Based Message Authentication Code (HMAC) Step 5: Final After the data to digest has been processed by calls to B_DigestUpdate, call B_DigestFinal. You need to pass a pointer to the location where B_DigestFinal can store the output. In the case of AI_HMAC using SHA1, you need 20 bytes to store the result.
Generating Random Numbers Generating Random Numbers In the “Introductory Example” on page 9, we hard-coded the DES key. In an actual application, you would use randomly-generated values. Crypto-C allows you to generate a pseudo-random sequence of bytes using a pseudo-random number generator (PRNG). These PRNGs are based on the message digests MD2, MD5, and SHA1. This section shows how to use AI_X962Random_V0, a SHA1-based pseudorandom number generator.
Generating Random Numbers Step 2: Setting The Algorithm Object You need to supply an appropriate algorithm info type (AI) and the proper associated info to B_SetAlgorithmInfo. For random-number generation, you have a choice between AI_MD2Random, AI_MD5Random, AI_X962Random_V0 (also known as AI_SHA1Random), and AI_X931Random, based on the message digest algorithms MD2, MD5, and SHA1 described earlier. For this example, choose AI_X962Random_V0.
Generating Random Numbers B_ALGORITHM_METHOD *RANDOM_CHOOSER[] = { &AM_SHA_RANDOM, (B_ALGORITHM_METHOD *)NULL_PTR }; if ((status = B_RandomInit (randomAlgorithm, RANDOM_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; Refer to “Saving State” on page 120 for a discussion of how to save the state of the algorithm object for future use. Step 4: Update The B_RandomUpdate function mixes in a random seed to the algorithm object.
Generating Random Numbers predict or reproduce. Once you have seeded the random algorithm, the algorithm can produce a sequence of random bytes; these bytes are “more random” and are generated more quickly than the seed. See “Pseudo-Random Numbers and Seed Generation” on page 92 for more information. Before you get your seed, you need to set aside memory to hold it.
Generating Random Numbers Now that you have a random seed, you can call B_RandomUpdate. The length argument tells Crypto-C how many bytes from the random seed buffer to use. See “Pseudo-Random Numbers and Seed Generation” on page 92 for a discussion on how many seed bytes to use. In this example, you will use all 256 bytes from the buffer, even though you probably entered fewer than 256 characters at the keyboard.
Generating Random Numbers Step 6: Destroy Remember to destroy all objects when done with them. You must also call T_free once for each call to T_malloc.
Generating Random Numbers For this example, you will specify six streams of randomness, and provide a seed stored in an ITEM structure, randomSeed. The amount of seed data passed in the A_X931_RANDOM_PARAMS structure must greater than or equal to 20 * (number of streams) bytes and less than or equal to 64 * (number of streams) bytes. With six streams, this means the seed size must be between 120 bytes and 384 bytes.
Converting Data Between Binary and ASCII Converting Data Between Binary and ASCII If you have data in binary format, yet need it in ASCII, or vice versa, Crypto-C offers functions to encode and decode according to the RFC1113 standard. The example in this section corresponds to the file encdec.c. Encoding Binary Data To ASCII Step 1: Creating An Algorithm Object Declare a variable to be B_ALGORITHM_OBJ.
Converting Data Between Binary and ASCII if ((status = B_EncodeInit (asciiEncoder)) != 0) break; Step 4: Update Enter the data to encode through B_EncodeUpdate. The application is responsible for allocating the space for the output of this routine. When encoding, for each three bytes of input there are four bytes of output. So when allocating space, multiply the input size by 4/3 and round up. If memory is not an issue, you can make the output buffer twice the size of the input length.
Converting Data Between Binary and ASCII Step 5: Final Finalize the encoding process, writing out any remaining bytes: unsigned int asciiEncodingLenFinal; if ((status = B_EncodeFinal (asciiEncoder, asciiEncoding + asciiEncodingLenUpdate, &asciiEncodingLenFinal, (binaryDataLen * 2) - asciiEncodingLenUpdate)) != 0) break; Step 6: Destroy Remember to destroy all objects and free up any memory allocated when done: B_DestroyAlgorithmObject (&asciiEncoder); T_free (asciiEncoding); Decoding ASCII-Encoded Data S
Converting Data Between Binary and ASCII if ((status = B_SetAlgorithmInfo (asciiDecoder, AI_RFC1113Recode, NULL_PTR)) != 0) break; Step 3: Init To initialize decoding, call B_DecodeInit. This function takes only one argument, the algorithm object: if ((status = B_DecodeInit (asciiDecoder)) != 0) break; Step 4: Update Enter the data to decode through B_DecodeUpdate. The application is responsible for allocating the space for the output of this routine.
Converting Data Between Binary and ASCII if ((status = B_DecodeUpdate (asciiDecoder, binaryDecoding, &binaryDecodingLenUpdate, asciiEncodingLenTotal, asciiEncoding, asciiEncodingLenTotal)) != 0) break; Step 5: Final Finalize the decoding process, writing out any bytes remaining: unsigned int binaryDecodingLenFinal; if ((status = B_DecodeFinal (asciiDecoder, binaryDecoding + binaryDecodingLenUpdate, &binaryDecodingLenFinal, asciiEncodingLenTotal - binaryDecodingLenUpdate)) != 0) break; Step 6: Destroy Whe
Chapter 6 Symmetric-Key Operations Recall that the RC4 algorithm of the “Introductory Example” on page 9 is called symmetric-key encryption because the encryption key used is the same the decryption key. Crypto-C offers two types of symmetric-key encryption operations: stream ciphers and block ciphers. The RC4 cipher, the only stream cipher in Crypto-C, was used in the “Introductory Example” on page 9. This chapter gives examples of the RC2, RC5, RC6 and DES block ciphers.
Block Ciphers Block Ciphers DES with CBC The example in this section corresponds to the file descbc.c. Step 1: Creating an Algorithm Object Declare a variable to be a B_ALGORITHM_OBJ.
Block Ciphers typedef struct { unsigned char *encryptionMethodName; /* examples include “des”, “rc5” POINTER encryptionParams; /* e.g.
Block Ciphers /* Complete steps 1 - 4 of Generating Random Numbers, then */ /* call B_GenerateRandomBytes. */ if ((status = B_GenerateRandomBytes (randomAlgorithm, ivBytes, 8, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; ivItem.data = ivBytes; ivItem.len = 8; You must also indicate that you want to use the standard CBC padding which is defined in PKCS#5; do this by setting fbParams.paddingMethodName to "pad". You do not need to pass in any padding parameters for this padding scheme.
Block Ciphers Step 3b: Setting the Key Object You want to use a KI compatible with DES encryption, so return to the entry for AI_FeedbackCipher in Chapter 2 of the Reference Manual: Key info types for keyObject in B_EncryptInit or B_DecryptInit: Depends on cipher type, as follows: Cipher KIs DES KI_Item, KI_DES8, KI_DES8Strong, KI_8Byte See “Summary of KIs” on page 113 of this manual for a discussion of the KIs. For this example, you will use KI_DES8Strong.
Block Ciphers Now that you have a key, you need an algorithm chooser and a surrender context.
Block Ciphers if ((status = B_EncryptUpdate (encryptionObject, encryptedData, &outputLenUpdate, encryptedDataLen, (unsigned char *)dataToEncrypt, dataToEncryptLen, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; Step 5: Final if ((status = B_EncryptFinal (encryptionObject, encryptedData + outputLenUpdate, &outputLenFinal, encryptedDataLen - outputLenUpdate, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; Step 6: Destroy Remember to destroy all objects that you
Block Ciphers The RC2 Cipher The RC2 cipher is a variable-key-size block cipher. Whereas a DES key requires eight bytes — no more, no less — an RC2 key can be anywhere between one and 128 bytes. The larger the key, the greater the security. The RC2 cipher is called a block cipher because it encrypts 8-byte blocks. Recall that DES also is a block cipher that encrypts 8-byte blocks. That means the RC2 cipher can serve as a drop-in replacement for DES.
Block Ciphers Once again, encryptionMethodName is the block cipher that you will use; in this example, use “rc2”. All the other parameters are the same as for DES, except encryptionParams. For the RC2 cipher, the Reference Manual indicates that you need to supply an A_RC2_PARAMS structure for the RC2 encryption algorithm: typedef struct { unsigned int effectiveKeyBits; } A_RC2_PARAMS; /* effective key size in bits */ There is a distinction between key size and effective key bits.
Block Ciphers rc2Params.effectiveKeyBits = 80; ivItem.data = initVector; ivItem.len = BLOCK_SIZE; fbParams.encryptionMethodName = (unsigned char *)"rc2"; fbParams.encryptionParams = NULL_PTR; fbParams.feedbackMethodName = (unsigned char *)"cbc"; fbParams.feedbackParams = (POINTER)&ivItem; fbParams.paddingMethodName = (unsigned char *)"pad"; fbParams.
Block Ciphers typedef struct { unsigned char *data; unsigned int len; } ITEM; Use a random number generator to come up with 24 bytes. ITEM rc2KeyItem; rc2KeyItem.len = 24; rc2KeyItem.data = T_malloc (rc2KeyItem.len); if ((status = (rc2KeyItem.data == NULL_PTR)) != 0) break; /* Complete steps 1 - 4 of Generating Random Numbers, then call B_GenerateRandomBytes. */ if ((status = B_GenerateRandomBytes (randomAlgorithm, rc2KeyItem.data, rc2KeyItem.
Block Ciphers You need an algorithm chooser and a surrender context. This is a speedy function, so it is reasonable to use a properly cast NULL_PTR for the surrender context. However, you do want to build a chooser: B_ALGORITHM_METHOD *RC2_CHOOSER[] = { &AM_CBC_ENCRYPT, &AM_RC2_ENCRYPT, &AM_SHA_RANDOM, (B_ALGORITHM_METHOD *)NULL_PTR }; if ((status = B_EncryptInit (rc2Encrypter, rc2Key, RC2_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; Step 4: Update Enter the data to encrypt through B_EncryptUpdate.
Block Ciphers if ((status = (encryptedData == NULL_PTR)) != 0) break; if ((status = B_EncryptUpdate (rc2Encrypter, encryptedData, &outputLenUpdate, encryptedDataLen, dataToEncrypt, dataToEncryptLen, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; Step 5: Final unsigned int outputLenFinal; if ((status = B_EncryptFinal (rc2Encrypter, encryptedData + outputLenUpdate, &outputLenFinal, encryptedDataLen - outputLenUpdate, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break
Block Ciphers Decrypting As with the “Introductory Example” on page 9, decrypting is similar to encrypting. Use the same AI, IV, and key. Use the proper decrypting AM and call B_DecryptInit, B_DecryptUpdate, and B_DecryptFinal. The RC5 Cipher The RC5 cipher is more properly known as RC5 w/r/b, where w stands for word-size, r stands for rounds, and b stands for key size in bytes. The word size parameter is designed to take advantage of variable hardware word sizes.
Block Ciphers B_ALGORITHM_OBJ rc5Encrypter = (B_ALGORITHM_OBJ)NULL_PTR; if ((status = B_CreateAlgorithmObject (&rc5Encrypter)) != 0) break; Step 2: Setting The Algorithm Object There are a number of RC5 AIs from which to choose. Table 4-6 on page 105 describes the AIs. For this example, you will use a different cipher from AI_FeedbackCipher. Choose AI_RC5_CBCPad.
Block Ciphers unsigned char initVector[8]; A_RC5_CBC_PARAMS rc5Params; /* Complete steps 1 - 4 of Generating Random Numbers, then call B_GenerateRandomBytes. */ if ((status = B_GenerateRandomBytes (randomAlgorithm, (unsigned char *)initVector, 8, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; rc5Params.version = 0x10; rc5Params.rounds = 12; rc5Params.wordSizeInBits = 32; rc5Params.
Block Ciphers typedef struct { unsigned char *data; unsigned int len; } ITEM; Use a random number generator to create 10 bytes: ITEM rc5KeyItem; rc5KeyItem.data = NULL_PTR; rc5KeyItem.len = 10; rc5KeyItem.data = T_malloc (rc5KeyItem.len); if ((status = (rc5KeyItem.data == NULL_PTR)) != 0) break; if ((status = B_GenerateRandomBytes (randomAlgorithm, rc5KeyItem.data, rc5KeyItem.
Block Ciphers Now that you have a key, you need an algorithm chooser and a surrender context. This is a speedy function, so you can use a properly cast NULL_PTR for the surrender context; but you do want to build a chooser: B_ALGORITHM_METHOD *RC5_CHOOSER[] = { &AM_RC5_CBC_ENCRYPT, (B_ALGORITHM_METHOD *)NULL_PTR }; if ((status = B_EncryptInit (rc5Encrypter, rc5Key, RC5_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; Step 4: Update Enter the data to encrypt through B_EncryptUpdate.
Block Ciphers encryptedDataLen = dataToEncryptLen + 8; encryptedData = T_malloc (encryptedDataLen); if ((status = (encryptedData == NULL_PTR)) != 0) break; if ((status = B_EncryptUpdate (rc5Encrypter, encryptedData, &outputLenUpdate, encryptedDataLen, dataToEncrypt, dataToEncryptLen, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; Step 5: Final unsigned int outputLenFinal; if ((status = B_EncryptFinal (rc5Encrypter, encryptedData + outputLenUpdate, &outputLenFinal, dataToEncryptLen +
Block Ciphers if (encryptedData != NULL_PTR) { T_memset (encryptedData, 0, encryptedDataLen); T_free (encryptedData); encryptedData = NULL_PTR; } Decrypting As in the “Introductory Example” on page 9, decrypting is similar to encrypting. Use the same AI, IV, and key data. Use the proper decrypting AM and call B_DecryptInit, B_DecryptUpdate, and B_DecryptFinal.
Block Ciphers that, as specified in the Reference Manual entry for AI_RC6_CBCPad, this AI requires an initialized A_RC6_CBC_PARAMS structure, which is defined as follows: typedef struct { unsigned int rounds; unsigned char *iv; } A_RC6_CBC_PARAMS; As mentioned previously, the number of rounds must be 20. CBC mode requires an initialization vector, so assume that you have the following buffer containing arbitrary bytes to use as the IV.
Block Ciphers Step 3: Init The next step is to make a call to B_EncryptInit. To do this, you need a key object. You will first create a key object, and then set the key data. Step 3a: Creating a Key Object B_KEY_OBJ rc6Key = (B_KEY_OBJ)NULL_PTR; if ((status = B_CreateKeyObject (&rc6Key)) != 0) break; Step 3b: Setting the Key Data Now you need to set the key size and pass the bytes of key data. According to the Reference Manual entry for AI_RC6_CBCPad, the compatible KI type is KI_Item.
Block Ciphers if (rc6KeyItem.data != NULL_PTR) { T_memset (rc6KeyItem.data, 0, rc6KeyItem.len); T_free (rc6KeyItem.data); rc6KeyItem.data = NULL_PTR; rc6KeyItem.len = 0; } To call B_EncryptInit, we also need an algorithm chooser. The Reference Manual entry for AI_RC6_CBCPad gives us the AMs necessary.
Block Ciphers for the surrender context: unsigned char *dataToEncrypt = (unsigned char *)"Encrypt this sentence.
Block Ciphers been allocated: B_DestroyAlgorithmObject (&rc6Encrypter); if (rc6KeyItem.data != NULL_PTR) { T_memset (rc6KeyItem.data, 0, rc6KeyItem.len); T_free (rc6KeyItem.data); rc6KeyItem.data = NULL_PTR; rc6KeyItem.len = 0; } Decrypting As in the “Introductory Example” on page 9, decrypting is similar to encrypting. Use the same AI, IV, and key data. Use the proper decrypting AM and call B_DecryptInit, B_DecryptUpdate, and B_DecryptFinal.
Block Ciphers unsigned char *aesParams CBC mode requires an initialization vector, so assume that you have the following buffer containing arbitrary bytes to use as the IV. Note that this information must be made available to the entity which decrypts the message. The IV is not secret information and may be sent in the clear with the ciphertext. #define BLOCK_SIZE 16 unsigned char initVector[BLOCK_SIZE]; Now fill in an A_AES_CBC_PARAMS structure and call B_SetAlgorithmInfo.
Block Ciphers Step 3a: Creating a Key Object /* Create a key object */ if ((status = B_CreateKeyObject (&aesKey)) != 0) break; Step 3b: Setting the Key Data Now you need to set the key size and pass the bytes of key data. According to the Reference Manual entry for AI_AES_CBCPad, the compatible KI type is KI_Item. A key anywhere from 1-255 bytes is supported. Here, you can use a random 24-byte key. For most applications, a 128-bit key should be sufficient.
Block Ciphers if (aesKeyItem.data != NULL_PTR) { T_memset (aesKeyItem.data, 0, aesKeyItem.len); T_free (aesKeyItem.data); aesKeyItem.data = NULL_PTR; aesKeyItem.len = 0; } To call B_EncryptInit, we also need an algorithm chooser. The Reference Manual entry for AI_AES_CBCPad gives us the AMs necessary.
Block Ciphers unsigned char *dataToEncrypt = (unsigned char *)"Encrypt this sentence.
Block Ciphers B_DestroyAlgorithmObject (&rc6Encrypter); if (aesKeyItem.data != NULL_PTR) { T_memset (aesKeyItem.data, 0, aesKeyItem.len); T_free (aesKeyItem.data); aesKeyItem.data = NULL_PTR; aesKeyItem.len = 0; } Password-Based Encryption In previous encryption methods, you used a random number generator to produce a key. In password-based encryption (PBE), you will use a message digest algorithm to derive a key from a password. See “Message Digests” on page 47 for information on that topic.
Block Ciphers Step 2: Setting The Algorithm Object There are a number of PBE AIs from which to choose (see “Summary of AIs” on page 103 for a more detailed description). For now, choose AI_MD5WithRC2_CBCPad.
Block Ciphers rc2PBEParams.effectiveKeyBits = 64; rc2PBEParams.salt = saltData; rc2PBEParams.iterationCount = 5; if ((status = B_SetAlgorithmInfo (pbEncrypter, AI_MD5WithRC2_CBCPad, (POINTER)&rc2PBEParams)) != 0) break; Step 3: Init You need a key before you can initialize the algorithm object for encryption. In PBE, the password is the key. Simply enter the password data as the key data; Crypto-C will generate the symmetric key from the password and salt.
Block Ciphers secure; it is used for illustrative purposes only. It is not for duplication: unsigned char enteredPassword[MAX_PW_LEN]; ITEM pbeKeyItem; puts ("Enter the password, then press Return or Enter"); gets ((char *)enteredPassword); pbeKeyItem.data = enteredPassword; pbeKeyItem.len = strlen (enteredPassword); if ((status = B_SetKeyInfo (pbeKey, KI_Item, (POINTER)&pbeKeyItem)) != 0) break; You should zeroize any sensitive data after leaving the do-while.
Block Ciphers Step 4: Update Enter the data to encrypt through B_EncryptUpdate. The Reference Manual Chapter 2 entry on AI_MD5WithRC2_CBCPad states that you can pass (B_ALGORITHM_OBJ)NULL_PTR for all randomAlgorithm arguments. Assuming you have some input data, call B_EncryptUpdate. Remember that the RC2 cipher is a block cipher and requires the input to be a multiple of eight bytes. But because you are using AI_MD5WithRC2_CBCPad, Crypto-C will pad to make the input a multiple of eight bytes.
Block Ciphers Step 5: Final unsigned int outputLenFinal; if ((status = B_EncryptFinal (pbEncrypter, encryptedData + outputLenUpdate, &outputLenFinal, encryptedDataLen - outputLenUpdate, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; Step 6: Destroy Remember to destroy all objects and free up any allocated memory: B_DestroyKeyObject (&pbeKey); B_DestroyAlgorithmObject (&pbEncrypter); B_DestroyAlgorithmObject (&randomAlgorithm); if (pbeKeyItem.
212
Chapter 7 Public-Key Operations In public-key cryptography, two associated keys are necessary: one to encrypt, and the other to decrypt. The sender encrypts a message using the recipient’s public key. Once a message is encrypted, it can be decrypted only with the recipient’s private key. This is in contrast to algorithms like DES and the RC2, RC4, and RC5 algorithms, which are called symmetric-key encryption algorithms because the key used to encrypt is the same key needed to decrypt.
Performing RSA Operations Performing RSA Operations The RSA algorithm is a public-key algorithm that relies on the difficulty of factoring a number that is the product of two large primes. If you are not familiar with the RSA algorithm and terminology, you may want to read “The RSA Algorithm” on page 51 before you continue. The algorithm chooser used throughout the sections concerning executing the RSA algorithm can be found in “Algorithm Choosers” on page 116.
Performing RSA Operations Step 2: Setting the Algorithm Object For this example, use AI_RSAKeyGen to generate an RSA key pair.
Performing RSA Operations keygenParams.modulusBits = 512; keygenParams.publicExponent.data = f4Data; keygenParams.publicExponent.len = 3; if ((status = B_SetAlgorithmInfo (keypairGenerator, AI_RSAKeyGen, (POINTER)&keygenParams)) != 0) break; Step 3: Init Look up the description and prototype for B_GenerateInit in Chapter 4 of the Reference Manual.
Performing RSA Operations generates a candidate and tests to see if it is prime. If the candidate passes the test, Crypto-C has one of the primes; if not, Crypto-C builds a new number. If you are lucky, two early numbers Crypto-C creates will pass the test. Sometimes, though, Crypto-C has to try many numbers before it finds a pair. Note: The numbers Crypto-C produces are not provably prime. They are numbers for which the probability is very low that they are not prime.
MultiPrime MultiPrime This section provides an overview of the MulitPrime enhancement to Crypto-C including information on how to generate an RSA MultiPrime key. What is MultiPrime? In classic RSA, you create a modulus (called "n") by multiplying two large primes together. The public and private exponents are then "e" (generally a Fermat number such as 3, 17, or 65,537) and –1 d = e mod ( ϕ ( n ) ) where ϕ is the Euler "phi-function".
MultiPrime Two-Prime RSA 48.8 17.5 0.8 Three-Prime RSA 48.8 10.9 0.8 This means 3-prime private operations can be about 38% faster than 2-prime operations. Or with 2-prime RSA, you can perform about 57 signatures per second, but with 3-prime RSA, you can perform about 91 signatures per second. How Many Primes? Using three primes is faster than using two primes. Is 4-prime RSA faster than 3prime? Yes, but there is a security tradeoff. One way to break RSA is to factor the modulus.
MultiPrime does not allow you to generate an RSA key pair if the number of primes is more than three. Furthermore, the toolkit will not allow you to generate 3-prime RSA key pairs of less than 1024 bits. In the future, as more research is published, we may adjust these limits and allow you to generate key pairs of more than three primes at more key lengths. Sample MultiPrime RSA differs from classic 2-prime RSA in only two areas: key pair generation and the makeup of the private key.
MultiPrime B_ALGORITHM_METHOD *RSA_GEN_CHOOSER[] = { &AM_RSA_KEY_GEN, (B_ALGORITHM_METHOD *)NULL_PTR }; A_RSA_MULTI_PRIME_KEY_GEN_PARAMS genParams; ITEM *privateKeyBER = (ITEM *)NULL_PTR; unsigned char expo[1] = { 3 }; do { if ((status = B_CreateKeyObject (&pubKey)) != 0) break; if ((status = B_CreateKeyObject (&priKey)) != 0) break; if ((status = B_CreateAlgorithmObject (&rsaGen)) != 0) break; genParams.modulusBits = 1024; genParams.numberOfPrimes = 3; genParams.publicExponent.data = expo; genParams.
MultiPrime Generating an RSA MultiPrime Key Refer to the RSA_CreateMultiPrimeRSAKeypair routine defined in the samples/pkalg/ rsa/rsautil.c file for an example that shows the use of AI_RSAMultiPrimeKeyGen to generate an RSA public/private key pair. This routine is called by the rsamultp.c sample. RSA MultiPrime key generation follows the same steps as standard RSA key pair generation with a couple of exceptions. The differences are that AI_RSAMultiPrimeKeyGen must be used instead of AI_RSAKeyGen.
MultiPrime unsigned char f4Data[] = {0x01, 0x00, 0x01}; A_RSA_MULTI_PRIME_KEY_GEN_PARAMS keygenParams; keygenParams.modulusBits = keyBits; keygenParams.numberOfPrimes = numPrimes; keygenParams.publicExponent.data = f4Data; keygenParams.publicExponent.
MultiPrime Crypto-C Format publicKey is a key object that was set by the Crypto-C function B_GenerateKeypair. Its key info type (KI) is KI_RSAPublic.
MultiPrime is unique to Crypto-C. If the recipient is not using Crypto-C, how do you give that recipient the information? Suppose your application mails this key to a certification authority. What information do you send? The BER-encoding standard defines what the public key consists of and how that information should be formatted. It is defined in ASN.1, which defines the Basic Encoding Rules (BER) and Distinguished Encoding Rules (DER). See “BER/DER Encoding” on page 123 for more information.
MultiPrime send it off. Remember to free any memory you allocated: T_free (myPublicKeyBER.data); Note: The conversion into BER or DER is known as BER-encoding or DERencoding; the conversion between binary to ASCII is known as encoding and decoding. In general, the word “encoding” without “BER” in front of it means binary to ASCII. If the encoding is BER- or DER-encoding, the BER or DER should be explicitly stated.
MultiPrime info to B_SetAlgorithmInfo as NULL_PTR: if ((status = B_SetAlgorithmInfo (rsaEncryptor, AI_PKCS_RSAPublic, NULL_PTR)) != 0) break; Step 3: Init You will encrypt using the recipient’s RSA public key. Normally, you would obtain the public key from the recipient or a certificate service. For this exercise, though, you will simply use the public key you generated in “Generating a Key Pair” on page 214.
MultiPrime You are encrypting 8 bytes, so you do not need to worry about that constraint. However, the output of RSA encryption is the same size as the modulus, as described in “The RSA Algorithm” on page 51. That means you must set the output buffer, which will hold the encrypted data, to be the same size as the modulus. Your modulus is 512 bits, or 64 bytes. Note: The input to the RSA algorithm must also be the same size as the modulus, but AI_PKCS_RSAPublic will automatically pad.
MultiPrime Step 6: Destroy When you are done with all your objects, remember to destroy them. B_DestroyAlgorithmObject (&randomAlgorithm); B_DestroyAlgorithmObject (&rsaEncryptor); B_DestroyKeyObject (&publicKey); RSA Private-Key Decryption This example shows how to decrypt using an RSA private key. Remember that with Crypto-C, you have the choice of doing your private-key operations normally or utilizing the blinding technique (see “Timing Attacks and Blinding” on page 95).
MultiPrime Step 3: Init To decrypt, you must use the RSA private key that is associated with the public key that was used to encrypt, which would be the key you generated in “Generating a Key Pair” on page 214. B_DecryptInit is quick, so you are safe in passing NULL_PTR as the surrender context.
MultiPrime /* generalFlag is for the surrender function.*/ generalFlag = 0; if ((status = B_DecryptUpdate (rsaDecryptor, decryptedData, &outputLenUpdate, BLOCK_SIZE, encryptedData, outputLenTotal, NULL_PTR, &generalSurrenderContext)) != 0) break; Step 5: Final unsigned int outputLenFinal; /* generalFlag is for the surrender generalFlag = 0; if ((status = B_DecryptFinal (rsaDecryptor, decryptedData + &outputLenFinal, BLOCK_SIZE &generalSurrenderContext)) != break; function.
MultiPrime encrypt is usually 8, 16, or (for BER-encoded digests) 34 or 35. If you want to encrypt and decrypt more than k – 11 bytes, use raw RSA encryption and decryption. Note: In general, there should be no need for raw RSA encryption or decryption. For most applications, if you have a longer message, it is faster and simpler to encrypt the message with a symmetric algorithm and then use the RSA algorithm to encrypt the key. (See “Digital Envelopes” on page 55.
MultiPrime RSA Digital Signatures The section “Authentication and Digital Signatures” on page 57 discusses what a digital signature is. This section describes how to write Crypto-C code that computes or verifies digital signatures. For signing, Crypto-C offers B_SignInit, B_SignUpdate, and B_SignFinal, which will digest the data and encrypt the digest using RSA encryption with a private key.
MultiPrime B_CreateAlgorithmObject: B_ALGORITHM_OBJ digitalSigner = (B_ALGORITHM_OBJ)NULL_PTR; if ((status = B_CreateAlgorithmObject (&digitalSigner)) != 0) break; Step 2: Setting The Algorithm Object Crypto-C provides three methods for computing RSA digital signatures: MD2 with RSA encryption, MD5 with RSA encryption, and SHA1 with RSA encryption.
MultiPrime entry for the AI in use: B_ALGORITHM_METHOD *SIGN_SAMPLE_CHOOSER[] = { &AM_SHA, &AM_RSA_CRT_ENCRYPT, (B_ALGORITHM_METHOD *)NULL_PTR }; Note: If you want to sign using the blinding technique to thwart timing attacks (see “Timing Attacks and Blinding” on page 95), use AM_RSA_CRT_ENCRYPT_BLIND in the algorithm chooser.
MultiPrime surrender context outlined in “The Surrender Context” on page 118: #define BLOCK_SIZE 64; /* Assuming we are using a 512-bit key */ unsigned char signature[BLOCK_SIZE]; unsigned int signatureLen; /* generalFlag is for the surrender function. */ generalFlag = 0; if ((status = B_SignFinal (digitalSigner, signature, &signatureLen, 64, (B_ALGORITHM_OBJ)NULL_PTR, &generalSurrenderContext)) != 0) break; Step 6: Destroy When you are done with all objects, remember to destroy them.
MultiPrime B_CreateAlgorithmObject: B_ALGORITHM_OBJ digitalVerifier = (B_ALGORITHM_OBJ)NULL_PTR; if ((status = B_CreateAlgorithmObject (&digitalVerifier)) != 0) break; Step 2: Setting The Algorithm Object The signer should tell you which message digest and decryption algorithms you need to use to verify the signature.
MultiPrime Note: If the algorithm object was not set to AI_MD5WithRSAEncryption, AI_MD2WithRSAEncryption, AI_SHA1WithRSAEncryption, or their BER counterparts, you cannot use B_VerifyInit. Step 4: Update Use B_VerifyUpdate to digest the data that was signed. Its prototype is in Chapter 4 of the Reference Manual. Unless there is an extraordinarily large amount of data (for example, a megabyte), B_VerifyUpdate is quick and a NULL_PTR for the surrender context should be no problem.
Performing DSA Operations Step 6: Destroy When you are done with all objects, remember to destroy them: B_DestroyAlgorithmObject (&digitalVerifier); B_DestroyKeyObject (&publicKey); Performing DSA Operations The Digital Signature Algorithm (DSA) is part of the Digital Signature Standard (DSS), published by the National Institute of Standards and Technology (NIST, a division of the US Department of Commerce); it is the digital authentication standard of the US government.
Performing DSA Operations of info supplied to B_SetAlgorithmInfo is a pointer to the following: typedef struct { unsigned int primeBits; } B_DSA_PARAM_GEN_PARAMS; /* size of prime in bits */ Crypto-C will generate the prime, but you must decide how big that prime will be. The number of prime bits can be anywhere from 512 to 2048. Larger numbers provide greater security, but are also much slower. As with the RSA algorithm, RSA Security recommends using 768 bits.
Performing DSA Operations Step 5: Generate To generate DSA parameters, call the Crypto-C function B_GenerateParameters. The Reference Manual Chapter 4 entry for this call indicates there are four arguments. The first is the algorithm object that generates the parameters; in this example, that is dsaParamGenerator. The second is a result algorithm object. Crypto-C will generate some values and will need to place them somewhere.
Performing DSA Operations Generating a DSA Key Pair The previous code generated the DSA parameters and set an algorithm object. With that algorithm object, you can generate the key pair. Remember, the algorithm object has already been created and set, so you can jump directly to Step 3. Step 3: Init When it generated the parameters, Crypto-C set the algorithm object dsaKeyGenObj to AI_DSAKeyGen. That means that when you build an algorithm chooser for the Init call, you need to include AM_DSA_KEY_GEN.
Performing DSA Operations contains the AM for SHA1 random number generation. The last argument is the surrender context.
Performing DSA Operations Computing a Digital Signature Step 1: Creating An Algorithm Object Declare a variable to be B_ALGORITHM_OBJ.
Performing DSA Operations properly cast NULL_PTR for the surrender context: B_ALGORITHM_METHOD *DSA_SIGN_CHOOSER[] = { &AM_SHA, &AM_DSA_SIGN, (B_ALGORITHM_METHOD *)NULL_PTR }; if ((status = B_SignInit (dsaSigner, dsaPrivateKey, DSA_SIGN_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; Step 4: Update Digest the data to sign with B_SignUpdate, the prototype of which is in Chapter 4 of the Reference Manual.
Performing DSA Operations page 118: #define MAX_SIG_LEN 48 unsigned char signature[MAX_SIG_LEN]; unsigned int signatureLen; /* generalFlag is for the surrender function.
Performing DSA Operations Step 2: Setting The Algorithm Object To verify the signature created here, use the same AI: if ((status = B_SetAlgorithmInfo (dsaVerifier, AI_DSAWithSHA1, NULL_PTR)) != 0) break; Step 3: Init Associate a key and algorithm method with the algorithm object through B_VerifyInit. The Chapter 4 Reference Manual entry on this function shows that it takes four arguments: the algorithm object, a key object, an algorithm chooser, and a surrender context.
Performing DSA Operations data and you know its length, your call is the following: if ((status = B_VerifyUpdate (dsaVerifier, inputData, inputDataLen, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; Step 5: Final B_VerifyUpdate digested the data. Check the signature with B_VerifyFinal. The Reference Manual Chapter 2 entry on AI_DSAWithSHA1 states: You must pass a random algorithm in B_SignFinal, but may pass (B_ALGORITHM_OBJ)NULL_PTR for all other randomAlgorithm arguments.
Performing Diffie-Hellman Key Agreement Performing Diffie-Hellman Key Agreement Diffie-Hellman Key Agreement is a method for two parties to obtain the same symmetric key. In this procedure, a central authority generates parameters and gives them to the two individuals seeking to generate a secret key. In Phase 1, each individual uses these parameters to produce a public value and a private value.
Performing Diffie-Hellman Key Agreement Step 2: Setting The Algorithm Object There is only one AI for generating Diffie-Hellman parameters: AI_DHParamGen. The format of info supplied to B_SetAlgorithmInfo is a pointer to the following struct: typedef struct { unsigned int primeBits; unsigned int exponentBits; } A_DH_PARAM_GEN_PARAMS; /* size of prime modulus in bits */ /* size of random exponent in bits */ Crypto-C will generate the prime, but you must decide how big that prime will be.
Performing Diffie-Hellman Key Agreement A_DH_PARAM_GEN_PARAMS dhParams; dhParams.primeBits = 512; dhParams.exponentBits = 504; if ((status = B_SetAlgorithmInfo (dhParamGenerator, AI_DHParamGen, (POINTER)&dhParams)) != 0) break; Step 3: Init Initialize the generation process with B_GenerateInit. Build an algorithm chooser. Because this function is quick, it is reasonable to pass NULL_PTR as the surrender context.
Performing Diffie-Hellman Key Agreement The second is a result algorithm object. Crypto-C will generate some values and will need to place them somewhere. So you might as well place them into an algorithm object now. (This is similar to generating an RSA key pair, where the results were placed into key objects.) Create an algorithm object, but do not set it; B_GenerateParameters will do that. The third argument is a random algorithm. Complete Steps 1 through 4 of “Generating Random Numbers” on page 165.
Performing Diffie-Hellman Key Agreement Distributing Diffie-Hellman Parameters The central authority, after computing the parameters, must send this information to the parties seeking agreement on a secret key. This can be done using Crypto-C format or BER-encoded format. Note: It is not necessary to generate parameters each time two parties wish to agree on a secret key. Any number of key agreements can use the same parameters.
Performing Diffie-Hellman Key Agreement A_DH_KEY_AGREE_PARAMS *dhKeyAgreeParams = (A_DH_KEY_AGREE_PARAMS *)NULL_PTR; if ((status = B_GetAlgorithmInfo ((POINTER *)&dhKeyAgreeParams, dhParametersObj, AI_DHKeyAgree)) != 0) break; If you look at the elements of the struct: dhKeyAgreeParams->prime.data dhKeyAgreeParams->prime.len dhKeyAgreeParams->base.data dhKeyAgreeParams->base.len dhKeyAgreeParams->exponentBits you will see the parameters Crypto-C generated.
Performing Diffie-Hellman Key Agreement Format of info returned by B_GetAlgorithmInfo: pointer to an ITEM structure which gives the address and length of the DER-encoded algorithm identifier. Crypto-C returns a pointer to where that information resides, not the information. As soon as the object that contains that information is destroyed, the information will no longer be accessible.
Performing Diffie-Hellman Key Agreement Diffie-Hellman Key Agreement If you are one of the parties involved in the key agreement, perform the following steps. Note that instead of Update and Final, you use B_KeyAgreePhase1 and B_KeyAgreePhase2. Also, if you are writing an application that executes the DiffieHellman key agreement, the application must be interactive. This process will produce an agreed-upon secret value. That value may be larger than necessary.
Performing Diffie-Hellman Key Agreement if ((status = B_SetAlgorithmInfo (dhKeyAgreeAlg, AI_DHKeyAgreeBER, (POINTER)&dhParametersBER)) != 0) break; Step 3: Init Initialize the algorithm object with B_KeyAgreeInit. The Reference Manual Chapter 4 entry on this function indicates it takes four arguments. The first is the algorithm object, dhKeyAgreeAlg. The second is a key object. The Diffie-Hellman key agreement algorithm does not require a key, so use a properly cast NULL_PTR for this argument.
Performing Diffie-Hellman Key Agreement The fourth is the size of the buffer you allocated; if the buffer is not big enough to hold the output, Crypto-C will generate an error. The fifth argument is a random algorithm object. For this, complete Steps 1 through 4 of “Generating Random Numbers” on page 165. You do not need random bytes, only an algorithm that can generate them. The last argument is a surrender context. This function does not return immediately, so a surrender context is helpful.
Performing Diffie-Hellman Key Agreement parties might only need eight bytes for a session key. If that is the case, it is the application’s responsibility to specify which bytes of the agreed-upon secret value will be used. This function does not return immediately, so a surrender context is useful: /* The other party should send their public value and its length.
Performing Elliptic Curve Operations Performing Elliptic Curve Operations Elliptic curve cryptosystems can be used for a number of public-key operations.
Performing Elliptic Curve Operations The second, ecParamsObj, is set and initialized by B_GenerateParameters; it will hold the newly-generated elliptic curve parameters.
Performing Elliptic Curve Operations version number; in Crypto-C, the only version available is 0. The second argument specifies that you want your base field to be of the form Fp (p is an odd prime). The third argument sets the length of a field element in bits; in this example, set it to be 160. For the prime field case, the size of a field element can be anywhere from 64 to 384 bits.
Performing Elliptic Curve Operations B_EC_PARAM_GEN_PARAMS paramGenInfo; paramGenInfo.version = 0; paramGenInfo.fieldType = FT_FP; paramGenInfo.fieldElementBits = 160; paramGenInfo.pointRepresentation = CI_NO_COMPRESS; paramGenInfo.minOrderBits = 0; paramGenInfo.trialDivBound = 0; if ((status = B_SetAlgorithmInfo(paramGenObj, AI_ECParamGen, (POINTER)¶mGenInfo)) != 0) break; Step 3: Init You can pass a NULL_PTR for the surrender context, because B_GenerateInit is a speedy function.
Performing Elliptic Curve Operations Step 5: Generate This function may take a while, so you should use a surrender function. See “The Surrender Context” on page 118. B_GenerateParameters places the newly-generated elliptic curve parameters in ecParamsObj: generalSurrenderContext.Surrender = GeneralSurrenderFunction; generalSurrenderContext.handle = (POINTER)&generalFlag; generalSurrenderContext.
Performing Elliptic Curve Operations Type of information this allows you to use: the parameters generated by executing AI_ECParamGen for either generating keys or executing key agreements.
Performing Elliptic Curve Operations The following procedure, AllocAndCopyECParamInfo, is an example of an applicationspecific procedure that allocates space to store the parameters. You can also write your own procedure to satisfy the needs of your application: int AllocAndCopyECParamInfo(output, input) A_EC_PARAMS *output; A_EC_PARAMS *input; { int status; do { output->version = input->version; output->fieldType = input->fieldType; output->fieldInfo.len = input->fieldInfo.len; output->fieldInfo.
Performing Elliptic Curve Operations output->order.len = input->order.len; output->order.data = T_malloc(output->order.len); if ((status = (output->order.data == NULL_PTR)) != 0) break; T_memcpy(output->order.data, input->order.data, output->order.len); output->cofactor.len = input->cofactor.len; output->cofactor.data = T_malloc(output->cofactor.len); if ((status = (output->cofactor.data == NULL_PTR)) != 0) break; T_memcpy(output->cofactor.data, input->cofactor.data, output->cofactor.
Performing Elliptic Curve Operations In the sample code, FreeECParamInfo is implemented as follows: void FreeECParamInfo(ecParams) A_EC_PARAMS *ecParams; { T_free(ecParams->fieldInfo.data); T_free(ecParams->coeffA.data); T_free(ecParams->coeffB.data); T_free(ecParams->base.data); T_free(ecParams->order.data); T_free(ecParams->cofactor.
Performing Elliptic Curve Operations if ((status = B_CreateKeyObject (&publicKey)) != 0) break; if ((status = B_CreateKeyObject (&privateKey)) != 0) break; Step 2: Set The Reference Manual indicates that the appropriate AI to use for generating an elliptic curve key pair is AI_ECKeyGen. You must set the algorithm object with the parameter information for the elliptic curve that you are using to generate the key. You do this by providing B_SetAlgorithmInfo with a pointer to a B_EC_PARAMS structure.
Performing Elliptic Curve Operations if ((status = B_SetAlgorithmInfo (ecKeyGen, AI_ECAcceleratorTable, (POINTER)&accelTableItem)) != 0) break; Step 3: Initialize Here, you can pass a NULL_PTR for the surrender context, because B_GenerateInit is a speedy function.
Performing Elliptic Curve Operations B_DestroyAlgorithmObject(&ecKeyGen); B_DestroyAlgorithmObject(&randomAlgorithm); B_DestroyKeyObject(&publicKey); B_DestroyKeyObject(&privateKey); Retrieving an Elliptic Curve Key If you need to store or transport information about your elliptic curve keys, you need to be able to retrieve the key information from an algorithm object. This section outlines the steps needed to retrieve information for a public key. The steps for retrieving a private key are similar.
Performing Elliptic Curve Operations B_GetKeyInfo gives a pointer to memory, but this memory is owned by Crypto-C. If you want to store this information, you need to make your own copy of the information because another call to Crypto-C may modify the memory owned by Crypto-C. The routines AllocAndCopyECPubKeyInfo and FreeECPubKeyInfo given here retrieve and store the key information. These routines are used in the sample code for building public-key acceleration tables.
Performing Elliptic Curve Operations /* * * This procedure takes a pointer to an A_EC_PUBLIC_KEY structure containing space allocated by AllocAndCopyECPubKeyInfo and frees all data allocated with T_malloc. */ void FreeECPubKeyInfo(pubKey) A_EC_PUBLIC_KEY *pubKey; { T_free(pubKey->publicKey.
Performing Elliptic Curve Operations Step 1: Create Declare a variable to be B_ALGORITHM_OBJ.
Performing Elliptic Curve Operations The first field in this structure, parameterInfoType, is used to interpret the elliptic curve parameter information you supply in the second field, parameterInfoValue. The EC parameter information you have is an A_EC_PARAMS structure containing the data that describes the EC parameters. The B_INFO_TYPE that is used to properly interpret that information is AI_ECParameters.
Performing Elliptic Curve Operations Step 5: Final Step 5a: Allocate memory You must allocate sufficient memory to hold the acceleration table. According to the Reference Manual, you can use B_BuildTableGetBufSize to tell how much space will be required to store the acceleration table: ITEM accelTableItem; unsigned int maxTableLen; if ((status = B_BuildTableGetBufSize(buildTable, &maxTableLen)) != 0) break; accelTableItem.data = T_malloc(maxTableLen); if ((status = (accelTableItem.
Performing Elliptic Curve Operations Step 6: Destroy You must free all allocated memory and destroy all objects when they are no longer needed so that all sensitive information is zeroized and freed: T_memset(accelTableItem.data, 0, accelTableItem.len); T_free(accelTableItem.data); B_DestroyAlgorithmObject(&buildTable); Generating a Public-Key Acceleration Table This special-purpose acceleration table can be used to speed up ECDSA verification.
Performing Elliptic Curve Operations Of course, you can write your own versions of these procedures to satisfy the needs of your application: A_EC_PUBLIC_KEY *cryptocPublicKeyInfo; A_EC_PUBLIC_KEY publicKeyInfo; if ((status = B_GetKeyInfo((POINTER *)&cryptocPublicKeyInfo, *publicKey, KI_ECPublic)) != 0) break; if ((status = AllocAndCopyECPubKeyInfo(&publicKeyInfo, cryptocPublicKeyInfo)) != 0) break; When the information is no longer needed, don’t forget to free the allocated memory: FreeECPubKeyInfo(&publ
Performing Elliptic Curve Operations Step 3: Init To initialize the proper algorithms, you must supply an algorithm chooser with the appropriate algorithm methods.
Performing Elliptic Curve Operations Step 5b: Build the public-key acceleration table It can take a while to generate the table, so use a surrender function. See “The Surrender Context” on page 118 for more information: ITEM pubKeyAccelTableItem; generalSurrenderContext.Surrender = GeneralSurrenderFunction; generalSurrenderContext.handle = (POINTER)&generalFlag; generalSurrenderContext.reserved = NULL_PTR; generalFlag = 0; if ((status = B_BuildTableFinal (buildTable, pubKeyAccelTableItem.
Performing Elliptic Curve Operations To initialize ecParamsObj with a set of parameters describing an elliptic curve, follow the steps in the section “Generating Elliptic Curve Parameters” on page 260. Assume that these steps have been successfully completed and ecParamsObj contains the common parameters for Alice and Bob. Put the elliptic curve parameters in the A_EC_PARAMS structure, ecParams.
Performing Elliptic Curve Operations typedef struct { B_INFO_TYPE parameterInfoType; POINTER parameterInfoValue; } B_EC_PARAMS; Because you have the EC parameters in the A_EC_PARAMS structure ecParams, the appropriate AI that describes the data is AI_ECParameters: B_EC_PARAMS commonECParams; commonECParams.parameterInfoType = AI_ECParameters; commonECParams.
Performing Elliptic Curve Operations if ((status = B_KeyAgreeInit(alice, (B_KEY_OBJ)NULL_PTR, EC_DH_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; You must allocate space to hold the results of Phase 1 and Phase 2. The largest size of Phase 1 output you can get is one byte larger than twice the field element size. For Phase 2, the size of the output should be the same as the field element size. (See the Reference Manual Chapter 2 entry for AI_EC_DHKeyAgree for details.
Performing Elliptic Curve Operations Step 5: Phase 2 By the time you have reached this step, Alice and Bob have exchanged public values.
Performing Elliptic Curve Operations To sign an arbitrarily long message with the elliptic curve version of DSA, you can use AI_EC_DSAWithDigest. First, you need to generate parameters for an elliptic curve and a key pair from that curve. Then, you will specify a digest algorithm for use with ECDSA in signing the message. Currently, the only digest algorithm supported for this operation is SHA1. The example in this section corresponds to the file ecdsadig.c.
Performing Elliptic Curve Operations B_KEY_OBJ publicKey = (B_KEY_OBJ)NULL_PTR; B_KEY_OBJ privateKey = (B_KEY_OBJ)NULL_PTR; if ((status = GenerateECKeys (&publicKey, &privateKey, &ecParamsObj, &randomAlgorithm) != 0) Assume that the steps in “Generating an Elliptic Curve Key Pair” on page 268 have been completed and that publicKey and privateKey are ready to be used. Computing a Digital Signature Step 1: Create Declare a variable to be B_ALGORITHM_OBJ.
Performing Elliptic Curve Operations B_DIGEST_SPECIFIER digestInfo; digestInfo.digestInfoType = AI_SHA1; digestInfo.
Performing Elliptic Curve Operations if ((status = B_SignInit (ecDSASign, privateKey, EC_DSA_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; Step 4: Update Now, using B_SignUpdate, pass in the data to be signed: unsigned char *dataToSign = "Some arbitrarily long piece of data to sign...
Performing Elliptic Curve Operations initialized random algorithm in B_SignFinal: unsigned int signatureLen; if ((status = B_SignFinal (ecDSASign, signature, &signatureLen, maxSignatureLen, randomAlgorithm, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; Step 6: Destroy Destroy all objects that are no longer needed: B_DestroyAlgorithmObject(&ecDSASign); B_DestroyKeyObject(&privateKey); Verifying a Digital Signature To verify the signature, you must go through a similar procedure.
Performing Elliptic Curve Operations Step 2b (Optional): Set Public Key Acceleration Table Info You can use either the public key acceleration table or the generic acceleration table to accelerate ECDSA verification. Verification using the public key acceleration table is faster than verification using only the generic acceleration table.
Performing Elliptic Curve Operations if ((status = B_VerifyFinal (ecDSAVerify, signature, signatureLen, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; Step 6: Destroy Destroy all objects that are no longer needed: T_free(signature); B_DestroyAlgorithmObject(&ecParamsObj); B_DestroyAlgorithmObject(&ecDSAVerify); B_DestroyKeyObject(&publicKey); Performing ECDSA with X9.
Performing Elliptic Curve Operations B_ALGORITHM_OBJ *ecParamsObj = (B_ALGORITHM_OBJ)NULL_PTR; if((status = B_CreateAlgorithmObject (ecParamsObj)) != 0) break; Step 2: Setting the Algorithm Object You need to set the algorithm object that will then be used to generate the key pair. To supply the necessary information, pass a pointer to an ITEM structure that contains the ANSI X9.62-compliant BER encoding of an elliptic curve’s parameters. In compliance with X9.
Performing Elliptic Curve Operations stockECParamsBER.data = ECParamsBER; stockECParamsBER.len = 154; if ((status = B_SetAlgorithmInfo (*ecParamsObj, AI_ECParametersBER, (POINTER)&stockECParamsBER)) != 0) break; Generating an EC Key Pair See “Generating an Elliptic Curve Key Pair” on page 268 for the required steps. To complete those steps, you will need a properly initialized random algorithm, the parameters describing an elliptic curve (see the x962.
Performing Elliptic Curve Operations if ((status = B_SetAlgorithmInfo (ecDSASign, AI_EC_DSA, (POINTER)NULL_PTR)) != 0) break; Step 3: Init Build an algorithm chooser with the appropriate AMs: B_ALGORITHM_METHOD *EC_DSA_CHOOSER[] = { &AM_ECFP_DSA_SIGN, &AM_ECF2POLY_SA_SIGN, &AM_ECFP_DSA_VERIFY, &AM_ECF2POLY_DSA_VERFIY, (B_ALGORITHM_METHOD *)NULL_PTR }; Now associate your private key and your algorithm chooser with the algorithm object: if ((status = B_SignInit (ecDSASign, privateKey, EC_DSA_CHOOSER, (A_SU
Performing Elliptic Curve Operations Step 5: Final First you must allocate space to store the signature. The output of the ECDSA signature is the BER encoding of a sequence of two integers, (r,s). At most, the size of the output will be six bytes more than twice the length of the order. Retrieve the field element length from ecParamsObj and do a simple manipulation to find the field element length in bytes.
Performing Elliptic Curve Operations Verifying a Digital Signature To verify the signature, you must go through a similar procedure. At the end, if the signature is valid, B_VerifyFinal returns 0. If it is not valid, B_VerifyFinal will return an error. Step 1: Create Declare a variable to be B_ALGORITHM_OBJ.
Performing Elliptic Curve Operations if ((status = B_VerifyUpdate (ecDSAVerify, dataToSign, dataToSignLen, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; Step 5: Final Pass in the signature that was received with the message.
Performing Elliptic Curve Operations Using Elliptic Curve Parameters See the section “Generating Elliptic Curve Parameters” on page 260 for the steps you must complete to generate a new curve. You need a properly initialized pseudorandom number generator. Assume that the function InitializeRandomAlgorithm goes through Steps 1 through 4 in the section “Generating Random Numbers” on page 165.
Performing Elliptic Curve Operations Step 1: Create First, create the algorithm object that will hold the information necessary to perform the encryption operation: B_ALGORITHM_OBJ ecESEncrypt = (B_ALGORITHM_OBJ)NULL_PTR; if ((status = B_CreateAlgorithmObject (&ecESEncrypt)) != 0) break; Step 2: Set Associate the elliptic curve encryption AI, AI_EC_ES, with the algorithm object.
Performing Elliptic Curve Operations Step 3: Init You must initialize the algorithm object to perform encryption. You also need to provide the key that will be used for encryption.
Performing Elliptic Curve Operations unsigned int maxEncryptedDataLen; unsigned int outputLenUpdate; maxEncryptedDataLen = 21 + (2 * fieldElementLen) + dataToEncryptLen; encryptedData = T_malloc(maxEncryptedDataLen); if ((status = (encryptedData == NULL_PTR)) != 0) break; if ((status = B_EncryptUpdate (ecESEncrypt, encryptedData, &outputLenUpdate, maxEncryptedDataLen, dataToEncrypt, dataToEncryptLen, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; Step 5: Final unsigned int outputLen
Performing Elliptic Curve Operations ECAES Private-Key Decryption The steps for decryption are similar to those for encryption.
Performing Elliptic Curve Operations unsigned char *decryptedData; unsigned int maxDecryptedDataLen; unsigned int outputLenUpdate; maxDecryptedDataLen = outputLenTotal; /* Use the outputLenTotal from */ /* Step 5 of ECAES encryption */ decryptedData = T_malloc(maxDecryptedDataLen); if ((status = (decryptedData == NULL_PTR)) != 0) break; if ((status = B_DecryptUpdate (ecESDecrypt, decryptedData, &outputLenUpdate, maxDecryptedDataLen, encryptedData, outputLenTotal, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CT
304
Chapter 8 Secret Sharing Operations Secret Sharing Secret sharing allows a system to require a certain number of “shares” to retrieve a secret. The process encrypts information and then creates a number of shares of the encrypted information. The information can be recovered by collecting a declared number (called the threshold) of shares. Note that the threshold must be less than or equal to the total number of shares. Typically, the secret is a key used for encrypting sensitive data.
Secret Sharing The example in this section corresponds to the file scrtshar.c. Step 1: Creating An Algorithm Object Declare a variable to be B_ALGORITHM_OBJ.
Secret Sharing if ((status = B_EncryptInit (secretSplitter, (B_KEY_OBJ)NULL_PTR, (B_ALGORITHM_CHOOSER)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; Step 4: Update Call B_EncryptUpdate once for each of the total number of shares. Each call to B_EncryptUpdate produces a share. For each share, you must allocate a space that is one byte larger than the secret. A share is actually the same size as the secret, but Crypto-C also appends one byte containing the number of the share.
Secret Sharing for (count = 0; count < TOTAL_SHARES; ++count) { secretShare[count] = T_malloc (SECRET_SIZE + 1); if ((status = (secretShare[count] == NULL_PTR)) != 0) break; if ((status = B_EncryptUpdate (secretSplitter, secretShare[count], &(secretShareLen[count]), SECRET_SIZE + 1, secretKey, SECRET_SIZE, randomAlgorithm, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; } if (status != 0) break; Step 5: Final Finalize the process with B_EncryptFinal.
Secret Sharing Reconstructing the Secret To reconstruct the secret, call B_DecryptUpdate for each share you are entering. You need at least threshold number of shares; if you enter fewer, B_DecryptFinal will return an error. Any combination of threshold shares will work. Step 1: Creating An Algorithm Object Declare a variable to be B_ALGORITHM_OBJ.
Secret Sharing if ((status = B_DecryptInit (secretReconstructer, (B_KEY_OBJ)NULL_PTR, (B_ALGORITHM_CHOOSER)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; Step 4: Update Call B_DecryptUpdate once for each of the shares you are using to reconstruct the secret. You can use any number of shares from the threshold number to the total number of shares. Each call to B_DecryptUpdate produces no output, so pass NULL_PTRs. The input is a share. This call does not need a random algorithm, so pass a NULL_PTR.
Secret Sharing unsigned char getSecret[SECRET_SIZE] unsigned int getSecretLen; if ((status = B_DecryptFinal (secretReconstructer, getSecret, &getSecretLen, SECRET_SIZE, (B_ALGORITHM_OBJ)NULL_PTR, (A_SURRENDER_CTX *)NULL_PTR)) != 0) Step 6: Destroy Remember to destroy all objects and free up any allocated memory when you are done: B_DestroyAlgorithmObject (&secretReconstructer); Chapter 8 Secret Sharing Operations 311
312
Chapter 9 Putting It All Together: An X9.31 Example The example in this chapter shows how to perform RSA digital signing and verifying according to the ANSI X9.31 standard. This example, available on the CD-ROM as x931.c, includes the following separate operations: • Generate random input using AI_X931Random. AI_X931Random is a special-purpose AI that generates the six separate streams of randomness required by the X9.31 standard. • Generate an RSA key pair using AI_RSAStrongKeyGen.
The X9.31 Sample Program The X9.31 Sample Program #include #include #include #include #include "aglobal.h" "bsafe.
The X9.31 Sample Program static unsigned char f4Data[] = {0x01, 0x00, 0x01}; A_SURRENDER_CTX generalSurrenderContext; int generalFlag; char *inputData = "Sign this sentence."; unsigned int inputDataLen; unsigned char signature[64]; unsigned int signatureLen; unsigned int status; generalSurrenderContext.Surrender = GeneralSurrenderFunction; generalSurrenderContext.handle = (POINTER)&generalFlag; generalSurrenderContext.
The X9.31 Sample Program To create a random algorithm object and set the parameters: /* /* ======================================================== */ Generate random bytes using AI_X931Random. AI_X931Random is a SHA-1 based pseudo-random number generator that allows you to generate multiple streams of randomness. AI_X931Random satisfies the requirements of independent generation of large and private prime factors, as specified by the ANSI X.931 standard.
The X9.31 Sample Program Providing the Seed In this example, the seed is provided by keyboard input and stored in an ITEM structure, randomSeed. The amount of seed data passed in the A_X931_RANDOM_PARAMS structure must be greater than or equal to 20 * (number of streams) bytes and less than or equal to 64 * (number of streams) bytes. With 6 streams, this means the seed size must be between 120 bytes and 384 bytes.
The X9.31 Sample Program /* Step 3: Initialize the random algorithm. The only difference in this example is that X931_SAMPLE_CHOOSER includes AM_X931_RANDOM. */ if ((status = B_RandomInit (randomAlgorithm, X931_SAMPLE_CHOOSER, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; /* Step 4: Since the random seed has already been passed in via the x931Params structure, we do not have to call B_RandomUpdate(). */ /* Step 5: Generate.
The X9.31 Sample Program /* ======================================================== printf ("\n Generating a Keypair \n"); printf (" ==================== \n"); */ if ((status = B_CreateAlgorithmObject (&keypairGenerator)) != 0) break; keygenParams.modulusBits = RSA_MODULUS_BITS; keygenParams.publicExponent.data = f4Data; keygenParams.publicExponent.len = 3; /* For this example, AI_RSAStrongKeyGen is used, rather than AI_RSAKeyGen.
The X9.31 Sample Program Computing a Digital Signature Now you can use the key pair to compute a digital signature. For X9.31, this is done using AI_SignVerify. AI_SignVerify provides ANSI X9.31-compliant digital signing and verification. The procedure to sign and verify using AI_SignVerify is similar to the steps outlined in “RSA Digital Signatures” on page 233. However, AI_SignVerify is a little different because it is more general purpose than the other signing and verifying AIs.
The X9.31 Sample Program • • • For digestMethodName, use "sha1"; currently this is the only digest supported. For formatMethodName, use "formatX931"; currently this is the only format method supported. formatParams requires a pointer to an A_X931_PARAMS structure, which is defined as follows: typedef struct { unsigned int blockLen; unsigned int oidNum; ITEM OID; } A_X931_PARAMS; The parameters are: blockLen: the smallest number of bytes you can use for your block.
The X9.31 Sample Program signVerifyParams.encryptionMethodName = (unsigned char *)"rsaSignX931"; signVerifyParams.encryptionParams = NULL_PTR; signVerifyParams.digestMethodName = (unsigned char *)"sha1"; signVerifyParams.digestParams = NULL_PTR; signVerifyParams.formatMethodName = (unsigned char *)"formatX931"; signVerifyParams.
The X9.31 Sample Program Verifying the Signature Verifying an X9.31 RSA signature is almost identical to signing, except that you pass "rsaVerifyX931" for encryptionMethodName in Ai_SignVerify.
The X9.31 Sample Program /* Step 4: Update */ if ((status = B_VerifyUpdate (digitalVerifier, (unsigned char *)inputData, inputDataLen, (A_SURRENDER_CTX *)NULL_PTR)) != 0) break; /* Step 5: Final */ generalFlag = 0; if ((status = B_VerifyFinal (digitalVerifier, signature, signatureLen, (B_ALGORITHM_OBJ)NULL_PTR, &generalSurrenderContext)) != 0) break; } while (0); if (status != 0) { printf ("Status = %i \n", status); printf ("Digital Signature failed"); } else { printf ("\nDigital Signature verified.
The X9.31 Sample Program Surrendering Control The following function, included as part of x931.c, can be used whenever an action may take a long time, and you need a mechanism for surrendering control.
The X9.31 Sample Program Printing the Buffer Contents The following procedure prints the current contents of the buffer. /* This procedure will print out what’s in the buffer.
Appendix A Command-Line Demos Overview of the Demos In addition to the sample programs included on the CD, there are three Crypto-C command-line demo applications: BDEMO, BDEMODSA, and BDEMOEC. These are actual applications that demonstrate some of the aspects of building cryptographic applications using Crypto-C. They use the Crypto-C library routines and are provided to all Crypto-C customers in source form. The BDEMO application is found in bdemo.c with supporting files fileio.c, filebsl.c, tstdlib.
Command-Line Demo User’s Guide • BDEMOEC can use ECDSA to create and verify digital signatures for a file, and it can use the Elliptic Curve Authenticated Encryption Scheme (ECAES) to seal and open a digital envelope, placing the output in another file. These demo programs support input files of arbitrary length. As with BDEMO, the file to be sealed with the digital envelope is encrypted using the DES algorithm; however, in BDEMOEC, the DES key is encrypted using ECAES instead of RSA encryption.
Command-Line Demo User’s Guide > bdemo -s < testin Notice that this uses ‘<’ to redirect testin as the input to BDEMO. The -s option to BDEMO eliminates the menu prompts when BDEMO is taking input from a file. Any line that is blank or begins with ’#’ is ignored. This means that the file used in response file mode may contain blank lines and comment lines that begin with ’#’. Specifying User Keys BDEMO comes pre-loaded with RSA key pairs for two test users: User 1 and User 2.
Command-Line Demo User’s Guide • the name and location of the file to be signed • the name of the file you want to create to hold the signature • the private key used for signing 3. Once this information is supplied, BDEMO uses the private key to create a signature. Create a File Envelope To create an envelope for a file: 1. Enter “e” at the top-level menu. 2.
Command-Line Demo User’s Guide • • • • the name and location of the file that contains the encrypted data the name and location of the of the file that contains the encrypted DES key the name and location of the of the file that contains the IV the name of the file where the decrypted content should be stored. To print the content to the screen instead, use a hyphen (-) as the file name. • the recipient’s user number 3. BDEMO uses the recipient’s private key to recover the DES key.
Command-Line Demo User’s Guide BDEMODSA BDEMODSA demonstrates the use of DSA to digitally sign and verify the integrity of data files. Running BDEMODSA Command Line mode To start BDEMODSA, enter the following after the system prompt: > bdemodsa Input Redirection mode You may also run BDEMODSA in input redirection mode where your responses to the menu prompts are read from a file.
Command-Line Demo User’s Guide Once a key pair has been generated, the following top-level menu is displayed: S - Sign a file using DSA/SHA V - Verify a DSA signed file Q - Quit Enter choice: Commands may be entered in either upper or lower case, and all but the initial letter of a command is ignored. So, for example, to sign a file you may either type “s” or “sign”. The commands on this top-level menu are described below. Sign a File To sign a file: 1. Enter s. 2.
Command-Line Demo User’s Guide BDEMOEC BDEMOEC provides the same functionality as BDEMO, but uses elliptic curve for its algorithms. The algorithm used for sealing and opening digital envelopes is ECAES to encrypt the DES symmetric key. Digital signatures are created and verified using ECDSA with SHA1. A set of elliptic curve parameters are hard-coded in the demo along with two key pairs generated with that curve.
File Reference File Reference The C source code files for the demo programs provide a convenient means to learn Crypto-C by example and are a good starting point for your own Crypto-C applications. The source files for the demo programs are described in Table A-1. Table A-1 Demo Program Source Files File(s) Description bdemo.c This file contains BDEMO’s main function, menu interpreter, and drivers for each of the menu commands.
BSLite Table A-1 Demo Program Source Files File(s) Description fbslec.c, fbslec.h, fileio.c and fileio.h These files are used by BDEMOEC. These files call on the routines in bslec.c and handle the file I/O for each operation. These files use the standard C library functions such as printf and fopen. The files fbslec.c and fbslec.h are analogous to filebsl.c and filebsl.h used by BDEMO. tstdlib.
BSLite A single C source file, bslite.c, with a single header file, bslite.h, contains the entire BSLite Code. For more information on BSLite, see the file blreadme.
338
Glossary This section lists security and cryptographic terms and abbreviations, along with their definitions, that are used throughout the RSA BSAFE Crypto-C documentation set.
AES block cipher Advanced Encryption Standard. A symmetric cipher which encrypts a message by breaking it down into fixed size blocks and encrypting each block. algorithm A series of steps used to complete a task. Alice The name traditionally used for the first user of cryptography in a system; Bob's friend. Bob The name traditionally used for the second user of cryptography in a system; Alice's friend. ANSI American National Standards Institute. API CA See certifying authority.
Data Encryption Standard distributed key See DES. A key that is split up into many parts and shared (distributed) among different participants. See also secret sharing. decryption The inverse (reverse) of encryption. The process by which the ciphertext is converted into plaintext. DER DMS Defense Messaging Service. Distinguished Encoding Rules. A subset of BER which gives a unique encoding to each ASN.1 value. DOD DES Digital Signature Algorithm.
ECDSA factor Elliptic Curve DSA (Digital Signature Algorithm). An elliptic curve analogue of DSA. Given an integer n, any number that divides it is called a factor of n. For example, 7 is a factor of 91, because 91/7 is an integer. EDI Electronic (business) Data Interchange. factoring elliptic curve The breaking down of an integer into its prime factors. This is a hard problem. The set of points (x, y) satisfying an equation of the form for variables x, y and constants a, b Î F, where F is a field.
identification key pair A process through which one ascertains the identity of another person or entity. The full key information in a public-key cryptosystem, consisting of the public key and private key. key A string of bits used widely in cryptography, allowing people to encrypt and decrypt data; a key can be used to perform other mathematical operations as well. Given a cipher, a key determines the mapping of the plaintext to the ciphertext.
NIST PKI National Institute of Standards and Technology. A United States agency that produces security and cryptography related standards (as well as others); these standards are published as FIPS documents. Public-key Infrastructure. PKIs are designed to solve the key management problem. See also key management. NSA National Security Agency. A securityconscious U. S. government agency whose mission is to decipher and monitor foreign communications.
private key counter, are considered random. In public-key cryptography, this key is the secret key. It is primarily used for decryption but is also used for encryption with digital signatures. relatively prime pseudo-random number Two integers are relatively prime if they have no common factors. For example, 14 and 25 are relatively prime, while 14 and 91 are not; 7 is a common factor. A number extracted from a pseudorandom sequence.
secret sharing stream cipher based MAC Splitting a secret (for examle, a private key) into many pieces such that any specified subset of k pieces may be combined to form the secret, but k-1 pieces are not enough. MAC that uses linear feedback shift registers (LFSRs) to reduce the size of the data it processes. seed A typically random bit sequence used to generate another, usually longer pseudo-random bit sequence.
verification The act of recognizing that a person or entity is who or what it claims to be. XOR A binary bitwise operator yielding the result one if the two values are different and zero otherwise. XOR is an abbreviation for exclusive-OR.
348
Index A acceleration table 273 Adelman, Leonard 52 Advanced Encryption Standard xvii See AES Advanced PKCS #11 147 AES xvii, 40, 41 AI See algorithm info type algorithm chooser 15, 116–?? hardware chooser 132 RC4 sample chooser 117 RSA algorithm chooser 117 Algorithm Choosers 116 algorithm info type 11, 101 ASCII-encoding types 104 BHAPI 111, 133 message authentication types 104 message digest types 103 public-key types 107–111 random number types 104 secret-sharing types 111 symmetric-key types 104–107 al
certificate See digital certificate CFB See modes of operation characteristic See elliptic curve cryptography chooser See algorithm chooser Cipher Block Chaining See modes of operation Cipher Feedback See modes of operation collision 48 collision-free 48 communicating with other packages See BER encoding compatibility BSAFE 2.x 9 D database applications 85 decoding BER vs.
elliptic curve cryptography 65–79 algorithm info types 110 curve generation 262 examples acceleration table 273–280 key pair generation 268–270 key retrieval 271–272 parameter generation 260–264 parameter retrieval 264–267 interoperability 90 key 72, 100, 262 key info types 115 output considerations 276 recommendations 90 RSA algorithm vs.
key (continued) RC2 39, 99 RC4 87, 99 RC5 99, 190 recovery 89 registering 61 RSA 53, 54, 97, 98 size 97, 98, 129 token (hardware) 111, 132 Triple DES 99 weak and semi-weak DES keys 94 See also public-key cryptography, symmetric-key cryptography key agreement 77 applications 86 digital envelopes vs. 88 See also Diffie-Hellman key agreement, Elliptic Curve Diffie-Hellman Key Agreement key derivation function (KDF) 76 key escrow 82 secret sharing vs.
P padding 37, 126, 180 RSA algorithm 227 parameters Diffie-Hellman key agreement 63, 99, 249 Digital Signature Algorithm 60, 239 surrender context and 118 See also elliptic curve parameters parity bits 129 password 93 password-based encryption 49 algorithm info types 106 dictionary attack 50 example 206–211 key 208 salt 207 PBE See password-based encryption PEM encoding 103 Performing EC Diffie-Hellman Key Agreement 280 PKCS #11 Advanced 147 DSA Support 144 random number generator 148 PKCS standards 4 point
RSA Security Inc. FAQ 55 Web site 48 S salt 49, 94 iterations 207 sample program files berder.c 124 descbc.c 178 dhagree.c 256 dhparam.c 249 dintorex.c 26 dsasign.c 239 ecdh.c 280 ecdsadig.c 285 eces.c 297 ecparam.c 260, 273 encdec.c 172 hmac.c 161 introex.c 9 mdber.c 155 mdigest.c 152 pbe.c 206 rc2.c 184 rc5.c 190 rc6.c 196 rc6fb.c 196 rsapkcs.c 214 rsasign.c 233 scrtshar.c 305 secret key See symmetric-key cryptography secret sharing 80, 305 algorithm info types 111 example 305–311 key escrow vs.