zoukankan      html  css  js  c++  java
  • RSA Encrypting/Decrypting、RSA+AES Encrypting/Decrypting

    catalogue

    1. CryptoAPI介绍
    2. RSA Encrypting/Decrypting File

    1. CryptoAPI介绍

    0x1: Cryptography Service Providers (CSPs)

    The Cryptography API contains functions that allow applications to encrypt or digitally sign data in a flexible manner, while providing protection for the user's sensitive private key data. All cryptographic operations are performed by independent modules known as cryptographic service providers (CSPs). One CSP, the Microsoft RSA Base Provider, is included with the operating system.
    Each CSP provides a different implementation of the Cryptography API layer.

    1. Some provide stronger cryptographic algorithms
    2. while others contain hardware components such as smartcards [plastic cards containing microchips that hold security data about the user]. 
    3. In addition, some CSPs may occasionally communicate with users directly, such as when digital signatures are performed using the user's signature private key.

    0x2: Key Databases

    Each CSP has a key database in which it stores its persistent cryptographic keys. Each key database contains one or more key containers, each of which contains all the key pairs belonging to a specific user (or Cryptography API client). Each key container is given a unique name, which applications provide to the CryptAcquireContext function when acquiring a handle to the key container. Figure 1 is an illustration of the contents of a key database:

    The CSP stores each key container from session to session, including all the public/private key pairs it contains. However, session keys are not preserved from session to session(会话key在程序运行结束后就消失了).

    Although it is possible to find these keys on a computer, they are stored in an encrypted and secure format.

    Generally, a default key container is created for each user. This key container takes the user's logon name as its own name, which is then used by any number of applications. It is also possible for an application to create its own key container (and key pairs), which it usually names after itself.

    0x3: Keys

    1. Session Keys

    Session keys are used when encrypting and decrypting data. They are created by applications using either the CryptGenKey or the CryptDeriveKey function. These keys are kept inside the CSP for safekeeping.
    Unlike the key pairs, session keys are volatile. Applications can save these keys for later use or transmission to other users by exporting them from the CSP into application space in the form of an encrypted key binary large object or key blob using the CryptExportKey function.

    2. Public or Private Key Pairs

    Each user generally has two public or private key pairs.

    1. One key pair is used to encrypt session keys: key exchange key pair
    2. the other to create digital signatures: signature key pair

    0x4: Encryption

    Once a message has been encrypted, it can be stored on nonsecure media or transmitted on a nonsecure network and still remain secret. Later, the message can be decrypted into its original form.

    When a message is encrypted, an encryption key is used. This is analogous to the physical key that is used to lock a padlock. To decrypt the message, the corresponding decryption key must be used. It is very important to properly restrict access to the decryption key, because anyone who possesses it will be able to decrypt all messages that were encrypted with the matching encryption key.
    This may come as a surprise, but data encryption/decryption is pretty straightforward. The really difficult part is keeping the keys safe and transmitting them securely to other users. This topic is beyond the scope of this article but I would recommend that the reader read the section titled "Exchanging Cryptographic Keys" in the Win32® Cryptography API documentation (MSDN Library, Platform, SDK, and DDK Documentation).

    There are two main classes of encryption algorithms

    1. symmetric algorithms: Systems that use symmetric algorithms are sometimes referred to as conventional.
    2. public-key algorithms (also known as asymmetric algorithms).

    0x5: Algorithms

    1. Symmetric algorithms

    Symmetric algorithms are the most common type of encryption algorithm. They are known as "symmetric" because the same key is used for both encryption and decryption. Unlike the keys used with public-key algorithms, symmetric keys are frequently changed. For this reason, they are referred to here as session keys(会话密钥).

    Compared to public-key algorithms, symmetric algorithms are very fast and thus are preferred when encrypting large amounts of data. Some of the more common symmetric algorithms are

    1. RC2
    2. RC4
    3. the Data Encryption Standard (DES).

    2. Public-key (asymmetric) algorithms

    Public-key (asymmetric) algorithms use a pair of different keys: a public key and a private key. The private key is kept private to the owner of the key pair, and the public key can be distributed to anyone who requests it. If one key is used to encrypt a message, the other key is required to decrypt the message. Public-key algorithms are very slow, on the order of a thousand times slower than symmetric algorithms. Consequently, they are normally used only to encrypt session keys. They are also used to digitally sign messages, as discussed in the next section. One of the most common public-key algorithms is the RSA Public-Key Cipher.

    0x6: Some Cryptography API Functions

    1. Initiating the CSP: CryptAcquireContext, CryptReleaseContext

    1. CryptAcquireContext
    The CryptAcquireContext function is used to obtain a handle to a particular key container within a particular CSP. This returned handle can then be used to make calls to the selected CSP. The CryptAcquireContext function performs two operations.
        1) It first attempts to find a CSP with the characteristics described by various parameters. 
        2) If the CSP is found, the function attempts to find a key container within the CSP that matches the specified container name.
    
    2. CryptReleaseContext
    The CryptReleaseContext function is used to release the handle returned from a call to CryptAcquireContext. The CryptReleaseContext function does not delete any Cryptography API objects, but merely releases the handle to an object.

    CryptAcquireContext

    BOOL WINAPI CryptAcquireContext(
      _Out_ HCRYPTPROV *phProv,
      _In_  LPCTSTR    pszContainer,
      _In_  LPCTSTR    pszProvider,
      _In_  DWORD      dwProvType,
      _In_  DWORD      dwFlags
    );
    
    1. phProv [out]: A pointer to a handle of a CSP. When you have finished using the CSP, release the handle by calling the CryptReleaseContext function.
    
    2. pszContainer [in]: The key container name. This is a null-terminated string that identifies the key container to the CSP. This name is independent of the method used to store the keys. Some CSPs store their key containers internally (in hardware), some use the system registry, and others use the file system. In most cases, when dwFlags is set to CRYPT_VERIFYCONTEXT, pszContainer must be set to NULL(获取默认container).  
    
    3. pszProvider [in]: A null-terminated string that contains the name of the CSP to be used. If this parameter is NULL, the user default provider is used.(每个container下面有很多provider layer)  
    An application can obtain the name of the CSP in use by using the CryptGetProvParam function to read the PP_NAME CSP value in the dwParam parameter.
    The default CSP can change between operating system releases. To ensure interoperability on different operating system platforms, the CSP should be explicitly set by using this parameter instead of using the default CSP.
    
    4. dwProvType [in]: Specifies the type of provider to acquire. 
    The field of cryptography is large and growing. There are many different standard data formats and protocols. These are generally organized into groups or families, each of which has its own set of data formats and way of doing things. Even if two families use the same algorithm (for example, the RC2 block cipher), they will often use different padding schemes, different key lengths, and different default modes. CryptoAPI is designed so that a CSP provider type represents a particular family.
    When an application connects to a CSP of a particular type, each of the CryptoAPI functions will, by default, operate in a way prescribed by the family that corresponds to that CSP type. An application's choice of provider type specifies the following items:
        1) PROV_RSA_FULL
        2) PROV_RSA_AES
        3) PROV_RSA_SIG
        4) PROV_RSA_SCHANNEL
        5) PROV_DSS
        6) PROV_DSS_DH
        7) PROV_DH_SCHANNEL
        8) PROV_FORTEZZA
        9) PROV_MS_EXCHANGE
        10) PROV_SSL
    
    5. dwFlags [in]: Flag values. This parameter is usually set to zero, but some applications set one or more of the following flags.
        1) CRYPT_VERIFYCONTEXT: This option is intended for applications that are using ephemeral keys, or applications that do not require access to persisted private keys, such as applications that perform only hashing, encryption, and digital signature verification. Only applications that create signatures or decrypt messages need access to a private key. In most cases, this flag should be set.
        For file-based CSPs, when this flag is set, the pszContainer parameter must be set to NULL. The application has no access to the persisted private keys of public/private key pairs. When this flag is set, temporary public/private key pairs can be created, but they are not persisted.
        For hardware-based CSPs, such as a smart card CSP, if the pszContainer parameter is NULL or blank, this flag implies that no access to any keys is required, and that no UI should be presented to the user. This form is used to connect to the CSP to query its capabilities but not to actually use its keys. If the pszContainer parameter is not NULL and not blank, then this flag implies that access to only the publicly available information within the specified container is required. The CSP should not ask for a PIN. Attempts to access private information (for example, the CryptSignHash function) will fail.
        When CryptAcquireContext is called, many CSPs require input from the owning user before granting access to the private keys in the key container. For example, the private keys can be encrypted, requiring a password from the user before they can be used. However, if the CRYPT_VERIFYCONTEXT flag is specified, access to the private keys is not required and the user interface can be bypassed.
    
        2) CRYPT_NEWKEYSET: Creates a new key container with the name specified by pszContainer. If pszContainer is NULL, a key container with the default name is created.
        3) CRYPT_MACHINE_KEYSET: By default, keys and key containers are stored as user keys. For Base Providers, this means that user key containers are stored in the user's profile. A key container created without this flag by an administrator can be accessed only by the user creating the key container and a user with administration privileges.
     
        4) CRYPT_DELETEKEYSET: Delete the key container specified by pszContainer. If pszContainer is NULL, the key container with the default name is deleted. All key pairs in the key container are also destroyed.
        5) CRYPT_SILENT : The application requests that the CSP not display any user interface (UI) for this context. If the CSP must display the UI to operate, the call fails and the NTE_SILENT_CONTEXT error code is set as the last error. In addition, if calls are made to CryptGenKey with the CRYPT_USER_PROTECTED flag with a context that has been acquired with the CRYPT_SILENT flag, the calls fail and the CSP sets NTE_SILENT_CONTEXT.
     
        6) CRYPT_DEFAULT_CONTAINER_OPTIONAL: Obtains a context for a smart card CSP that can be used for hashing and symmetric key operations but cannot be used for any operation that requires authentication to a smart card using a PIN. This type of context is most often used to perform operations on an empty smart card, such as setting the PIN by using CryptSetProvParam. This flag can only be used with smart card CSPs.

    CryptReleaseContext

    BOOL WINAPI CryptReleaseContext(
      _In_ HCRYPTPROV hProv,
      _In_ DWORD      dwFlags
    );
     
    1. hProv [in]: Handle of a cryptographic service provider (CSP) created by a call to CryptAcquireContext.
    2. dwFlags [in]: Reserved for future use and must be zero. If dwFlags is not set to zero, this function returns FALSE but the CSP is released

    To obtain a handle to the default key container of the default CSP the code would look like this:

    #include <wincrypt.h>      // CryptoAPI definitions 
    
    BOOL bResult;
    HCRYPTPROC hProv;
    
    // Attempt to acquire a handle to the default key container.
    bResult = CryptAcquireContext(
                &hProv,        // Variable to hold returned handle.
                NULL,        // Use default key container.
                NULL,            // Use default CSP.
                PROV_RSA_AES,        // Type of provider to acquire.
            /*
            This option is intended for applications that are using ephemeral keys, or applications that do not require access to persisted private keys, such as applications that perform only hashing, encryption, and digital signature verification. Only applications that create signatures or decrypt messages need access to a private key. In most cases, this flag should be set.
            只需要加密不需要解密的场景可以传入此参数
            */
                CRYPT_VERIFYCONTEXT);                 
    .
    .
    .
    //Do some work.
    .
    .
    .
    // Release handle to container.
    CryptReleaseContext(hProv);

    2. Hashing Data: CryptCreateHash, CryptHashData, CryptGetHashParam, and CryptDestroyHash

    • The CryptCreateHash function is used to initiate the hashing of data. It returns a handle to a CSP hash object, which can be used in subsequent calls to CryptHashData in order to hash the data.
    • The next step is to use the CryptGetHashParam function to retrieve the hash value.
    • The CryptDestroyHash function is used to release the handle returned from CryptCreateHash. CryptDestroyHash does not delete any Cryptography API objects, but merely releases the handle to a hash object.

    The CryptHashData function is used to compute the cryptographic hash of some supplied data. This function can be called multiple times to compute the hash on large data or different pieces of data. As an example, we will hash the data that is contained in a buffer pointed to by pBuffer and that is dwBufferLen bytes long. I have chosen the CALG_MD5 hashing algorithm for the purpose of this example only. There are many other algorithms available and fully explained in the Cryptography API SDK documentation. This example assumes only one piece of data to hash. Once the hash value has been retrieved via CryptGetHashParam, no more data can be hashed with this instance of the hash object.

    #include <wincrypt.h>      // CryptoAPI definitions
    /*
    For non C/C++ users the constants used here are:
    #define ALG_CLASS_HASH                  (4 << 13)
    #define ALG_TYPE_ANY                    (0)
    #define ALG_SID_MD5                     3
    #define CALG_MD5        (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD5)
    #define HP_HASHVAL              0x0002  // Hash value
    #define HP_HASHSIZE             0x0004  // Hash value size
    */
    BOOL bResult;
    HCRYPTHASH hHash;
    DWORD dwBufferSize;
    DWORD dwValue;
    PBYTE pBuffer;
    
    // Obtain handle to hash object.
    bResult = CryptCreateHash(
                hProv,               // Handle to CSP obtained earlier
                CALG_MD5,            // Hashing algorithm
                0,                   // Non-keyed hash
                0,                   // Should be zero
                &hHash);             // Variable to hold hash object handle 
    
    // Hash data.
    bResult = CryptHashData(
                hHash,               // Handle to hash object
                pBuffer,             // Pointer to data buffer
                dwBufferlen,         // Length of data
                0);                  // No special flags
    
    // Get size of hash value.
    dwBufferSize = sizeof(DWORD);
    bResult = CryptGetHashParam(
                hHash,               // Handle to hash object
                HP_HASHSIZE,         // Get hash value
                &dwValue,            // Buffer to hold hash value length
                &dwBufferSize,       // Length of data buffer
                0);                  // Must be zero
    
    // Create buffer to hold hash value.
    pBuffer = new char [dwBufferSize];
    
    // Get hash value.
    bResult = CryptGetHashParam(
                hHash,              // Handle to hash object
                HP_HASHVAL,         // Get hash value
                pBuffer,            // Buffer to hold hash value
                &dwBufferSize,      // Length of data
                0);                 // Must be zero
    
    // Release hash object.
    CryptDestroyHash(hHash);

    The above example generated a hash value for the data pointed to by pBuffer. If there was more data to hash, calling CryptHashData with that data would have hashed the new data with the old value. Be warned—calling CryptGetHashParam with the HP_HASHVALUE parameter prevents any further hashing with that particular object.

    3. Generating Keys: CryptDeriveKey, CryptGenKey, CryptDestroyKey

    These three functions are the ones used to generate handles to keys:

    1. The CryptDeriveKey function is used to generate a key from a specified password.
    If the CryptGenKey function is used, it is recommended that the CRYPT_EXPORTABLE parameter be used to create an exportable session key. This creates a value that can be moved from one computer to another. Without this parameter the value returned is only valid on that particular computer/session.
    
    2. The CryptGenKey function is used to generate a key from random generated data.
    3. The CryptDestroyKey function is used to release the handle to the key object.

    CryptDeriveKey

    The CryptDeriveKey function generates cryptographic session keys derived from a base data value. This function guarantees that when the same cryptographic service provider (CSP) and algorithms are used, the keys generated from the same base data are identical. The base data can be a password or any other user data.
    This function is the same as CryptGenKey, except that the generated session keys are derived from base data instead of being random. CryptDeriveKey can only be used to generate session keys. It cannot generate public/private key pairs.

    BOOL WINAPI CryptDeriveKey(
      _In_    HCRYPTPROV hProv,
      _In_    ALG_ID     Algid,
      _In_    HCRYPTHASH hBaseData,
      _In_    DWORD      dwFlags,
      _Inout_ HCRYPTKEY  *phKey
    ); 
    
    1. hProv [in]: A HCRYPTPROV handle of a CSP created by a call to CryptAcquireContext.
    2. Algid [in]: An ALG_ID structure that identifies the symmetric encryption algorithm for which the key is to be generated. The algorithms available will most likely be different for each CSP. 
        1) CALG_MD2: MD2 hashing algorithm 
        2) CALG_MD5: MD5 hashing algorithm
        3) CALG_SHA: SHA hashing algorithm
        4) CALG_SHA1: Same as CALG_SHA
        5) CALG_MAC: Message Authentication Code (MAC) keyed-hash algorithm Block cipher MAC.
        6) CALG_HMAC: MAC keyed-hash algorithm HMAC computation.
        7) CALG_SSL3_SHAMD5: SLL3 client authentication algorithm
        8) CALG_RSA_SIGN: RSA public key signature algorithm, Key length: can be set from 384 bits to 16,384 bits in 8-bit increments. Default key length: 512 bits.
        9) CALG_RSA_KEYX: RSA public key exchange algorithm, Key length: can be set from 384 bits to 1024 bits in 8-bit increments.
        10) CALG_RC2: RC2 block encryption algorithm, Key length: 40 bits.
        11) CALG_RC4: RC4 stream encryption algorithm
        12) CALG_DES: DES encryption  
    
    3. hBaseData [in]: A handle to a hash object that has been fed the exact base data. To obtain this handle, an application must first create a hash object with CryptCreateHash and then add the base data to the hash object with CryptHashData. This process is described in detail in Hashes and Digital Signatures.
    
    4. dwFlags [in]: Specifies the type of key generated.(The sizes of a session key)
        1) CRYPT_CREATE_SALT
        2) CRYPT_EXPORTABLE: If this flag is set, the session key can be transferred out of the CSP into a key BLOB through the CryptExportKey function. Because keys generally must be exportable, this flag should usually be set.
        3) CRYPT_NO_SALT: This flag specifies that a no salt value gets allocated for a 40-bit symmetric key. 
        4) CRYPT_UPDATE_KEY: Some CSPs use session keys that are derived from multiple hash values. When this is the case, CryptDeriveKey must be called multiple times.
        5) CRYPT_SERVER: 1024 (0x400): This flag is used only with Schannel providers. If this flag is set, the key to be generated is a server-write key; otherwise, it is a client-write key.
     
    5. phKey [in, out]: A pointer to a HCRYPTKEY variable to receive the address of the handle of the newly generated key. When you have finished using the key, release the handle by calling the CryptDestroyKey function.

    CryptGenKey

    The CryptGenKey function generates a random cryptographic session key or a public/private key pair. A handle to the key or key pair is returned in phKey. This handle can then be used as needed with any CryptoAPI function that requires a key handle.
    The calling application must specify the algorithm when calling this function. Because this algorithm type is kept bundled with the key, the application does not need to specify the algorithm later when the actual cryptographic operations are performed.

    BOOL WINAPI CryptGenKey(
      _In_  HCRYPTPROV hProv,
      _In_  ALG_ID     Algid,
      _In_  DWORD      dwFlags,
      _Out_ HCRYPTKEY  *phKey
    );
    
    1. hProv [in]: A handle to a cryptographic service provider (CSP) created by a call to CryptAcquireContext.
    2. Algid [in]: An ALG_ID value that identifies the algorithm for which the key is to be generated. Values for this parameter vary depending on the CSP used.
    3. dwFlags [in]: Specifies the type of key generated. The sizes of a session key, The RSA1024BIT_KEY value can be used to specify a 1024-bit RSA key.
    4. phKey [out]: Address to which the function copies the handle of the newly generated key. When you have finished using the key, delete the handle to the key by calling the CryptDestroyKey function.

    Following is an example of how to use the CryptDeriveKey function, assuming that pPassword points to a user-defined password and dwPasswordLength contains the length of the password.

    #include <wincrypt.h>      // CryptoAPI definitions
    /*
    For non C/C++ users the constants used here are:
    #define ALG_CLASS_HASH                  (4 << 13)
    #define ALG_TYPE_ANY                    (0)
    #define ALG_SID_MD5                     3
    #define CALG_MD5        (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD5)
    #define CRYPT_EXPORTABLE        0x00000001
    #define ALG_CLASS_DATA_ENCRYPT          (3 << 13)
    #define ALG_TYPE_STREAM                 (4 << 9)
    #define ALG_SID_RC2                     2
    #define CALG_RC4        (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_STREAM|ALG_SID_RC4)
    */
    BOOL bResult;
    HCRYPTHASH hHash;
    HCRYPTKEY hKey;
    
    // Obtain handle to hash object.
    bResult = CryptCreateHash(
                hProv,             // Handle to CSP obtained earlier
                CALG_MD5,          // Hashing algorithm
                0,                 // Non-keyed hash
                0,                 // Should be zero
                &hHash);           // Variable to hold hash object handle 
    
    // Hash data.
    bResult = CryptHashData(
                hHash,             // Handle to hash object
                pPassword,         // Pointer to password
                dwPasswordLength,  // Length of data
                0);                // No special flags
    
    
    // Create key from specified password.
    /*
    微软采用了一个通用OO的方式来封装了不同provider的密钥生成过程,例如
    1. RSA: 产生的应该是一对公私钥
    2. RC4: 产生的就只是一个流密钥
    ..
    */
    bResult = CryptDeriveKey(
                hProv,               // Handle to CSP obtained earlier.
                CALG_RC4,            // Use a stream cipher.
                hHash,               // Handle to hashed password.
                CRYPT_EXPORTABLE,    // Make key exportable.
                &hKey);              // Variable to hold handle of key.
    .
    .
    .
    Use key to do something.
    .
    .
    .
    // Release hash object.
    CryptDestroyHash(hHash);
    
    // Release key object.
    CryptDestroyKey(hKey);

    4. Encrypting and Decrypting Data: CryptEncrypt, CryptDecrypt, CryptImportKey

    the Cryptography API revolves around these two functions—the encrypting (CryptEncrypt) and decrypting (CryptDecrypt) of data.

    When encrypting or decrypting two streams of data simultaneously with the same cryptographic key, a certain amount of care must be taken. The same physical session key must not be used for both operations, because every session key contains internal state information and it will get mixed up if used for more than one operation at a time. A fairly simple solution to this problem is to make a copy of the session key. In this way, the original key can be used for one operation and the copy used for the other.

    Copying a session key is done by exporting the key with CryptExportKey and then using CryptImportKey to import it back in. When the key is imported, the CSP will give the "new" key its own section of internal memory, as if it were not related at all to the original key.(CryptImportKey的作用是为了多线程操作)

    CryptImportKey

    BOOL WINAPI CryptImportKey(
      _In_  HCRYPTPROV hProv,
      _In_  BYTE       *pbData,
      _In_  DWORD      dwDataLen,
      _In_  HCRYPTKEY  hPubKey,
      _In_  DWORD      dwFlags,
      _Out_ HCRYPTKEY  *phKey
    );
    
    1. hProv [in]: The handle of a CSP obtained with the CryptAcquireContext function.
    2. pbData [in]: A BYTE array that contains a PUBLICKEYSTRUC BLOB header followed by the encrypted key. This key BLOB is created by the CryptExportKey function, either in this application or by another application possibly running on a different computer.
    3. dwDataLen [in]: Contains the length, in bytes, of the key BLOB.
    4. hPubKey [in]: A handle to the cryptographic key that decrypts the key stored in pbData. This key must come from the same CSP to which hProv refers. The meaning of this parameter differs depending on the CSP type and the type of key BLOB being imported:
        1) If the key BLOB is encrypted with the key exchange key pair, for example, a SIMPLEBLOB, this parameter can be the handle to the key exchange key.
        2) If the key BLOB is encrypted with a session key, for example, an encrypted PRIVATEKEYBLOB, this parameter contains the handle of this session key.
        3) If the key BLOB is not encrypted, for example, a PUBLICKEYBLOB, this parameter is not used and must be zero(NULL).
        4) If the key BLOB is encrypted with a session key in an Schannel CSP, for example, an encrypted OPAQUEKEYBLOB or any other vendor-specific OPAQUEKEYBLOB, this parameter is not used and must be set to zero.
    
    5. dwFlags [in]: Currently used only when a public/private key pair in the form of a PRIVATEKEYBLOB is imported into the CSP(只有在同时导入了私钥的情况下这个参数才会被设置). This parameter can be one of the following values.
        1) CRYPT_EXPORTABLE: The key being imported is eventually to be reexported. If this flag is not used, then calls to CryptExportKey with the key handle fail.
        2) CRYPT_OAEP: This flag causes PKCS #1 version 2 formatting to be checked with RSA encryption and decryption when importing SIMPLEBLOBs.
        3) CRYPT_NO_SALT: A no-salt value gets allocated for a 40-bit symmetric key. For more information, see Salt Value Functionality.
        4) CRYPT_USER_PROTECTED: If this flag is set, the CSP notifies the user through a dialog box or some other method when certain actions are attempted using this key. The precise behavior is specified by the CSP or the CSP type used. If the provider context was acquired with CRYPT_SILENT set, using this flag causes a failure and the last error is set to NTE_SILENT_CONTEXT.
        5) CRYPT_IPSEC_HMAC_KEY: Allows for the import of an RC2 key that is larger than 16 bytes. If this flag is not set, calls to the CryptImportKey function with RC2 keys that are greater than 16 bytes fail, and a call to GetLastError will return NTE_BAD_DATA.
    
    6. phKey [out]: A pointer to a HCRYPTKEY value that receives the handle of the imported key. When you have finished using the key, release the handle by calling the CryptDestroyKey function

    CryptEncrypt

    BOOL WINAPI CryptEncrypt(
      _In_    HCRYPTKEY  hKey,
      _In_    HCRYPTHASH hHash,
      _In_    BOOL       Final,
      _In_    DWORD      dwFlags,
      _Inout_ BYTE       *pbData,
      _Inout_ DWORD      *pdwDataLen,
      _In_    DWORD      dwBufLen
    );
    
    1. hKey [in]: A handle to the encryption key. An application obtains this handle by using either the CryptGenKey or the CryptImportKey function.
    The key specifies the encryption algorithm used.
    2. hHash [in]: A handle to a hash object. If data is to be hashed and encrypted simultaneously, a handle to a hash object can be passed in the hHash parameter. The hash value is updated with the plaintext passed in. This option is useful when generating signed and encrypted text.
    Before calling CryptEncrypt, the application must obtain a handle to the hash object by calling the CryptCreateHash function. After the encryption is complete, the hash value can be obtained by using the CryptGetHashParam function, or the hash can be signed by using the CryptSignHash function.
    If no hash is to be done, this parameter must be NULL.
    
    3. Final [in]: A Boolean value that specifies whether this is the last section in a series being encrypted. Final is set to TRUE for the last or only block and to FALSE if there are more blocks to be encrypted. For more information, see Remarks.
    4. dwFlags [in]: The following dwFlags value is defined but reserved for future use.
        1) CRYPT_OAEP: Use Optimal Asymmetric Encryption Padding (OAEP) (PKCS #1 version 2). This flag is only supported by the Microsoft Enhanced Cryptographic Provider with RSA encryption/decryption.
    
    5. pbData [in, out]: A pointer to a buffer that contains the plaintext to be encrypted. The plaintext in this buffer is overwritten with the ciphertext created by this function.
    6. pdwDataLen [in, out]: A pointer to a DWORD value that , on entry, contains the length, in bytes, of the plaintext in the pbData buffer. On exit, this DWORD contains the length, in bytes, of the ciphertext written to the pbData buffer.
     
    7. dwBufLen [in]: Specifies the total size, in bytes, of the input pbData buffer.

    The following example shows how to import a key from a key BLOB. For a full example for this function

    #include <windows.h>
    #include <stdio.h>
    #include <Wincrypt.h>
    
    BOOL ImportKey(HCRYPTPROV hProv, LPBYTE pbKeyBlob, DWORD dwBlobLen)
    {
        HCRYPTKEY hPubKey;
    
        //---------------------------------------------------------------
        // This code assumes that a cryptographic provider (hProv) 
        // has been acquired and that a key BLOB (pbKeyBlob) that is 
        // dwBlobLen bytes long has been acquired. 
    
        //---------------------------------------------------------------
        // Get the public key of the user who created the digital 
        // signature and import it into the CSP by using CryptImportKey. 
        // The key to be imported is in the buffer pbKeyBlob that is  
        // dwBlobLen bytes long. This function returns a handle to the 
        // public key in hPubKey.
    
        if(CryptImportKey(
            hProv,
            pbKeyBlob,
            dwBlobLen,
            0,
            0,
            &hPubKey))
        {
            printf("The key has been imported.
    ");
        }
        else
        {
            printf("Public key import failed.
    ");
            return FALSE;
        }
    
        //---------------------------------------------------------------
        // Insert code that uses the imported public key here.
        //---------------------------------------------------------------
    
        //---------------------------------------------------------------
        // When you have finished using the key, you must release it.
        if(CryptDestroyKey(hPubKey))
        {
            printf("The public key has been released.");
        }
        else
        {
            printf("The public key has not been released.");
            return FALSE;
        }
    
        return TRUE;
    }

    encryp

    BOOL bResult;
    PBYTE pBuffer;
    DWORD dwSize;
    
    // Set variable to length of data in buffer.
    dwSize = dwDataLen;
    
    // Have API return us the required buffer size.
    bResult = CryptEncrypt(
                hKey,            // Key obtained earlier
                0,               // No hashing of data
                TRUE,            // Final or only buffer of data
                0,               // Must be zero
                NULL,            // No data yet, simply return size
                &dwSize,         // Size of data
                dwSize);         // Size of block
    
    // We now have a size for the output buffer, so create buffer.
    pBuffer = new char[dwSize];
    
    // Now encrypt data.
    bResult = CryptEncrypt(
                hKey,            // Key obtained earlier
                0,               // No hashing of data
                TRUE,            // Final or only buffer of data
                0,               // Must be zero
                pBuffer,         // Data buffer
                &dwSize,         // Size of data
                dwSize);         // Size of block

    Relevant Link:

    https://msdn.microsoft.com/en-us/library/windows/desktop/aa380244(v=vs.85).aspx
    https://msdn.microsoft.com/en-us/library/windows/desktop/aa379886(v=vs.85).aspx
    https://msdn.microsoft.com/en-us/library/windows/desktop/aa380268(v=vs.85).aspx
    https://msdn.microsoft.com/en-us/library/windows/desktop/aa375599(v=vs.85).aspx
    https://msdn.microsoft.com/en-us/library/windows/desktop/aa379916(v=vs.85).aspx
    https://msdn.microsoft.com/en-us/library/windows/desktop/aa379941(v=vs.85).aspx
    https://msdn.microsoft.com/en-us/library/aa380207(VS.85).aspx 
    https://msdn.microsoft.com/en-us/library/windows/desktop/aa379924(v=vs.85).aspx
    https://msdn.microsoft.com/en-us/library/ms867086.aspx
    https://msdn.microsoft.com/en-us/library/windows/desktop/aa379913(v=vs.85).aspx
    https://msdn.microsoft.com/en-us/library/windows/desktop/aa382383(v=vs.85).aspx
    https://msdn.microsoft.com/en-us/library/windows/desktop/aa382375(v=vs.85).aspx

    2. RSA Encrypting/Decrypting File

    // Encrypting_a_File.cpp : Defines the entry point for the console 
    // application.
    //
    #include "stdafx.h"
    #include "targetver.h"
    
    #include <windows.h>
    #include <wincrypt.h>
    #include <conio.h>
    
    
    // Link with the Advapi32.lib file.
    #pragma comment (lib, "advapi32")
    
    #define KEYLENGTH  0x00800000
    #define ENCRYPT_ALGORITHM CALG_RC4 
    #define ENCRYPT_BLOCK_SIZE 8 
    
    bool MyEncryptFile(
        LPTSTR szSource,
        LPTSTR szDestination,
        LPTSTR szPassword);
    
    void MyHandleError(
        LPTSTR psz,
        int nErrorNumber);
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        if (argc < 3)
        {
            _tprintf(TEXT("Usage: <example.exe> <source file> ")
                TEXT("<destination file> | <password>
    "));
            _tprintf(TEXT("<password> is optional.
    "));
            _tprintf(TEXT("Press any key to exit."));
            _gettch();
            return 1;
        }
    
        LPTSTR pszSource = argv[1];
        LPTSTR pszDestination = argv[2];
        LPTSTR pszPassword = NULL;
    
        if (argc >= 4)
        {
            pszPassword = argv[3];
        }
    
        //---------------------------------------------------------------
        // Call EncryptFile to do the actual encryption.
        if (MyEncryptFile(pszSource, pszDestination, pszPassword))
        {
            _tprintf(
                TEXT("Encryption of the file %s was successful. 
    "),
                pszSource);
            _tprintf(
                TEXT("The encrypted data is in file %s.
    "),
                pszDestination);
        }
        else
        {
            MyHandleError(
                TEXT("Error encrypting file!
    "),
                GetLastError());
        }
    
        return 0;
    }
    
    //-------------------------------------------------------------------
    // Code for the function MyEncryptFile called by main.
    //-------------------------------------------------------------------
    // Parameters passed are:
    //  pszSource, the name of the input, a plaintext file.
    //  pszDestination, the name of the output, an encrypted file to be 
    //   created.
    //  pszPassword, either NULL if a password is not to be used or the 
    //   string that is the password.
    bool MyEncryptFile(
        LPTSTR pszSourceFile,
        LPTSTR pszDestinationFile,
        LPTSTR pszPassword)
    {
        //---------------------------------------------------------------
        // Declare and initialize local variables.
        bool fReturn = false;
        HANDLE hSourceFile = INVALID_HANDLE_VALUE;
        HANDLE hDestinationFile = INVALID_HANDLE_VALUE;
    
        HCRYPTPROV hCryptProv = NULL;
        HCRYPTKEY hKey = NULL;
        HCRYPTKEY hXchgKey = NULL;
        HCRYPTHASH hHash = NULL;
    
        PBYTE pbKeyBlob = NULL;
        DWORD dwKeyBlobLen;
    
        PBYTE pbBuffer = NULL;
        DWORD dwBlockLen;
        DWORD dwBufferLen;
        DWORD dwCount;
    
        //---------------------------------------------------------------
        // Open the source file. 
        hSourceFile = CreateFile(
            pszSourceFile,
            FILE_READ_DATA,
            FILE_SHARE_READ,
            NULL,
            OPEN_EXISTING,
            FILE_ATTRIBUTE_NORMAL,
            NULL);
        if (INVALID_HANDLE_VALUE != hSourceFile)
        {
            _tprintf(
                TEXT("The source plaintext file, %s, is open. 
    "),
                pszSourceFile);
        }
        else
        {
            MyHandleError(
                TEXT("Error opening source plaintext file!
    "),
                GetLastError());
            goto Exit_MyEncryptFile;
        }
    
        //---------------------------------------------------------------
        // Open the destination file. 
        hDestinationFile = CreateFile(
            pszDestinationFile,
            FILE_WRITE_DATA,
            FILE_SHARE_READ,
            NULL,
            OPEN_ALWAYS,
            FILE_ATTRIBUTE_NORMAL,
            NULL);
        if (INVALID_HANDLE_VALUE != hDestinationFile)
        {
            _tprintf(
                TEXT("The destination file, %s, is open. 
    "),
                pszDestinationFile);
        }
        else
        {
            MyHandleError(
                TEXT("Error opening destination file!
    "),
                GetLastError());
            goto Exit_MyEncryptFile;
        }
    
        //---------------------------------------------------------------
        // Get the handle to the default provider. 
        if (CryptAcquireContext(
            &hCryptProv,
            NULL,
            MS_ENHANCED_PROV,
            PROV_RSA_FULL,
            0))
        {
            _tprintf(
                TEXT("A cryptographic provider has been acquired. 
    "));
        }
        else
        {
            MyHandleError(
                TEXT("Error during CryptAcquireContext!
    "),
                GetLastError());
            goto Exit_MyEncryptFile;
        }
    
        //---------------------------------------------------------------
        // Create the session key.
        if (!pszPassword || !pszPassword[0])
        {
            //-----------------------------------------------------------
            // No password was passed.
            // Encrypt the file with a random session key, and write the 
            // key to a file. 
    
            //-----------------------------------------------------------
            // Create a random session key. 
            if (CryptGenKey(
                hCryptProv,
                ENCRYPT_ALGORITHM,
                KEYLENGTH | CRYPT_EXPORTABLE,
                &hKey))
            {
                _tprintf(TEXT("A session key has been created. 
    "));
            }
            else
            {
                MyHandleError(
                    TEXT("Error during CryptGenKey. 
    "),
                    GetLastError());
                goto Exit_MyEncryptFile;
            }
    
            //-----------------------------------------------------------
            // Get the handle to the exchange public key. 
            if (CryptGetUserKey(
                hCryptProv,
                AT_KEYEXCHANGE,
                &hXchgKey))
            {
                _tprintf(
                    TEXT("The user public key has been retrieved. 
    "));
            }
            else
            {
                if (NTE_NO_KEY == GetLastError())
                {
                    // No exchange key exists. Try to create one.
                    if (!CryptGenKey(
                        hCryptProv,
                        AT_KEYEXCHANGE,
                        CRYPT_EXPORTABLE,
                        &hXchgKey))
                    {
                        MyHandleError(
                            TEXT("Could not create "
                                "a user public key.
    "),
                            GetLastError());
                        goto Exit_MyEncryptFile;
                    }
                }
                else
                {
                    MyHandleError(
                        TEXT("User public key is not available and may ")
                        TEXT("not exist.
    "),
                        GetLastError());
                    goto Exit_MyEncryptFile;
                }
            }
    
            //-----------------------------------------------------------
            // Determine size of the key BLOB, and allocate memory. 
            if (CryptExportKey(
                hKey,
                hXchgKey,
                SIMPLEBLOB,
                0,
                NULL,
                &dwKeyBlobLen))
            {
                _tprintf(
                    TEXT("The key BLOB is %d bytes long. 
    "),
                    dwKeyBlobLen);
            }
            else
            {
                MyHandleError(
                    TEXT("Error computing BLOB length! 
    "),
                    GetLastError());
                goto Exit_MyEncryptFile;
            }
    
            if (pbKeyBlob = (BYTE *)malloc(dwKeyBlobLen))
            {
                _tprintf(
                    TEXT("Memory is allocated for the key BLOB. 
    "));
            }
            else
            {
                MyHandleError(TEXT("Out of memory. 
    "), E_OUTOFMEMORY);
                goto Exit_MyEncryptFile;
            }
    
            //-----------------------------------------------------------
            // Encrypt and export the session key into a simple key 
            // BLOB. 
            if (CryptExportKey(
                hKey,
                hXchgKey,
                SIMPLEBLOB,
                0,
                pbKeyBlob,
                &dwKeyBlobLen))
            {
                _tprintf(TEXT("The key has been exported. 
    "));
            }
            else
            {
                MyHandleError(
                    TEXT("Error during CryptExportKey!
    "),
                    GetLastError());
                goto Exit_MyEncryptFile;
            }
    
            //-----------------------------------------------------------
            // Release the key exchange key handle. 
            if (hXchgKey)
            {
                if (!(CryptDestroyKey(hXchgKey)))
                {
                    MyHandleError(
                        TEXT("Error during CryptDestroyKey.
    "),
                        GetLastError());
                    goto Exit_MyEncryptFile;
                }
    
                hXchgKey = 0;
            }
    
            //-----------------------------------------------------------
            // Write the size of the key BLOB to the destination file. 
            if (!WriteFile(
                hDestinationFile,
                &dwKeyBlobLen,
                sizeof(DWORD),
                &dwCount,
                NULL))
            {
                MyHandleError(
                    TEXT("Error writing header.
    "),
                    GetLastError());
                goto Exit_MyEncryptFile;
            }
            else
            {
                _tprintf(TEXT("A file header has been written. 
    "));
            }
    
            //-----------------------------------------------------------
            // Write the key BLOB to the destination file. 
            if (!WriteFile(
                hDestinationFile,
                pbKeyBlob,
                dwKeyBlobLen,
                &dwCount,
                NULL))
            {
                MyHandleError(
                    TEXT("Error writing header.
    "),
                    GetLastError());
                goto Exit_MyEncryptFile;
            }
            else
            {
                _tprintf(
                    TEXT("The key BLOB has been written to the ")
                    TEXT("file. 
    "));
            }
    
            // Free memory.
            free(pbKeyBlob);
        }
        else
        {
    
            //-----------------------------------------------------------
            // The file will be encrypted with a session key derived 
            // from a password.
            // The session key will be recreated when the file is 
            // decrypted only if the password used to create the key is 
            // available. 
    
            //-----------------------------------------------------------
            // Create a hash object. 
            if (CryptCreateHash(
                hCryptProv,
                CALG_MD5,
                0,
                0,
                &hHash))
            {
                _tprintf(TEXT("A hash object has been created. 
    "));
            }
            else
            {
                MyHandleError(
                    TEXT("Error during CryptCreateHash!
    "),
                    GetLastError());
                goto Exit_MyEncryptFile;
            }
    
            //-----------------------------------------------------------
            // Hash the password. 
            if (CryptHashData(
                hHash,
                (BYTE *)pszPassword,
                lstrlen(pszPassword),
                0))
            {
                _tprintf(
                    TEXT("The password has been added to the hash. 
    "));
            }
            else
            {
                MyHandleError(
                    TEXT("Error during CryptHashData. 
    "),
                    GetLastError());
                goto Exit_MyEncryptFile;
            }
    
            //-----------------------------------------------------------
            // Derive a session key from the hash object. 
            if (CryptDeriveKey(
                hCryptProv,
                ENCRYPT_ALGORITHM,
                hHash,
                KEYLENGTH,
                &hKey))
            {
                _tprintf(
                    TEXT("An encryption key is derived from the ")
                    TEXT("password hash. 
    "));
            }
            else
            {
                MyHandleError(
                    TEXT("Error during CryptDeriveKey!
    "),
                    GetLastError());
                goto Exit_MyEncryptFile;
            }
        }
    
        //---------------------------------------------------------------
        // The session key is now ready. If it is not a key derived from 
        // a  password, the session key encrypted with the private key 
        // has been written to the destination file.
    
        //---------------------------------------------------------------
        // Determine the number of bytes to encrypt at a time. 
        // This must be a multiple of ENCRYPT_BLOCK_SIZE.
        // ENCRYPT_BLOCK_SIZE is set by a #define statement.
        dwBlockLen = 1000 - 1000 % ENCRYPT_BLOCK_SIZE;
    
        //---------------------------------------------------------------
        // Determine the block size. If a block cipher is used, 
        // it must have room for an extra block. 
        if (ENCRYPT_BLOCK_SIZE > 1)
        {
            dwBufferLen = dwBlockLen + ENCRYPT_BLOCK_SIZE;
        }
        else
        {
            dwBufferLen = dwBlockLen;
        }
    
        //---------------------------------------------------------------
        // Allocate memory. 
        if (pbBuffer = (BYTE *)malloc(dwBufferLen))
        {
            _tprintf(
                TEXT("Memory has been allocated for the buffer. 
    "));
        }
        else
        {
            MyHandleError(TEXT("Out of memory. 
    "), E_OUTOFMEMORY);
            goto Exit_MyEncryptFile;
        }
    
        //---------------------------------------------------------------
        // In a do loop, encrypt the source file, 
        // and write to the source file. 
        bool fEOF = FALSE;
        do
        {
            //-----------------------------------------------------------
            // Read up to dwBlockLen bytes from the source file. 
            if (!ReadFile(
                hSourceFile,
                pbBuffer,
                dwBlockLen,
                &dwCount,
                NULL))
            {
                MyHandleError(
                    TEXT("Error reading plaintext!
    "),
                    GetLastError());
                goto Exit_MyEncryptFile;
            }
    
            if (dwCount < dwBlockLen)
            {
                fEOF = TRUE;
            }
    
            //-----------------------------------------------------------
            // Encrypt data. 
            if (!CryptEncrypt(
                hKey,
                NULL,
                fEOF,
                0,
                pbBuffer,
                &dwCount,
                dwBufferLen))
            {
                MyHandleError(
                    TEXT("Error during CryptEncrypt. 
    "),
                    GetLastError());
                goto Exit_MyEncryptFile;
            }
    
            //-----------------------------------------------------------
            // Write the encrypted data to the destination file. 
            if (!WriteFile(
                hDestinationFile,
                pbBuffer,
                dwCount,
                &dwCount,
                NULL))
            {
                MyHandleError(
                    TEXT("Error writing ciphertext.
    "),
                    GetLastError());
                goto Exit_MyEncryptFile;
            }
    
            //-----------------------------------------------------------
            // End the do loop when the last block of the source file 
            // has been read, encrypted, and written to the destination 
            // file.
        } while (!fEOF);
    
        fReturn = true;
    
    Exit_MyEncryptFile:
        //---------------------------------------------------------------
        // Close files.
        if (hSourceFile)
        {
            CloseHandle(hSourceFile);
        }
    
        if (hDestinationFile)
        {
            CloseHandle(hDestinationFile);
        }
    
        //---------------------------------------------------------------
        // Free memory. 
        if (pbBuffer)
        {
            free(pbBuffer);
        }
    
    
        //-----------------------------------------------------------
        // Release the hash object. 
        if (hHash)
        {
            if (!(CryptDestroyHash(hHash)))
            {
                MyHandleError(
                    TEXT("Error during CryptDestroyHash.
    "),
                    GetLastError());
            }
    
            hHash = NULL;
        }
    
        //---------------------------------------------------------------
        // Release the session key. 
        if (hKey)
        {
            if (!(CryptDestroyKey(hKey)))
            {
                MyHandleError(
                    TEXT("Error during CryptDestroyKey!
    "),
                    GetLastError());
            }
        }
    
        //---------------------------------------------------------------
        // Release the provider handle. 
        if (hCryptProv)
        {
            if (!(CryptReleaseContext(hCryptProv, 0)))
            {
                MyHandleError(
                    TEXT("Error during CryptReleaseContext!
    "),
                    GetLastError());
            }
        }
    
        return fReturn;
    } // End Encryptfile.
    
    
      //-------------------------------------------------------------------
      //  This example uses the function MyHandleError, a simple error
      //  handling function, to print an error message to the  
      //  standard error (stderr) file and exit the program. 
      //  For most applications, replace this function with one 
      //  that does more extensive error reporting.
    
    void MyHandleError(LPTSTR psz, int nErrorNumber)
    {
        _ftprintf(stderr, TEXT("An error occurred in the program. 
    "));
        _ftprintf(stderr, TEXT("%s
    "), psz);
        _ftprintf(stderr, TEXT("Error number %x.
    "), nErrorNumber);
    }

    Relevant Link:

    https://msdn.microsoft.com/en-us/library/windows/desktop/aa382358(v=vs.85).aspx
    https://blogs.msdn.microsoft.com/alejacma/2008/01/28/how-to-generate-key-pairs-encrypt-and-decrypt-data-with-cryptoapi/
    http://stackoverflow.com/questions/20208671/how-can-i-use-cryptimportkey-function-import-a-private-key-to-encrypt-data-same
    http://blog.csdn.net/w_sx12553/article/details/38821419

    Copyright (c) 2017 LittleHann All rights reserved

  • 相关阅读:
    jQuery中.bind() .live() .delegate() .on()的区别
    jq中Deferred对象的使用
    事件捕获和事件冒泡
    exec与match方法的区别
    json的转换操作
    iframe内容自适应高度
    Html:upload
    小米盒子
    APUE读书笔记:关于sigsuspend
    我的C笔记
  • 原文地址:https://www.cnblogs.com/LittleHann/p/6851423.html
Copyright © 2011-2022 走看看