Thursday, July 2, 2020

Sample C Code to Sign a Message


C++
//-------------------------------------------------------------------
//   Copyright (C) Microsoft.  All rights reserved.

#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#include <windows.h>
#include <wincrypt.h>

// Link with the Crypt32.lib file.
#pragma comment (lib, "Crypt32")

#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)

//-------------------------------------------------------------------
//   Define the name of a certificate subject.
//   To use this program, the definition of SIGNER_NAME
//   must be changed to the name of the subject of
//   a certificate that has access to a private key. That certificate
//   must have either the CERT_KEY_PROV_INFO_PROP_ID or 
//   CERT_KEY_CONTEXT_PROP_ID property set for the context to 
//   provide access to the private signature key.

//-------------------------------------------------------------------
//    You can use a command similar to the following to create a 
//    certificate that can be used with this example:
//
//    makecert -n "cn=Test" -sk Test -ss my

//#define SIGNER_NAME L"test"
#define SIGNER_NAME L"Insert_signer_name_here"

//-------------------------------------------------------------------
//    Define the name of the store where the needed certificate
//    can be found. 

#define CERT_STORE_NAME  L"MY"

//-------------------------------------------------------------------
//   Local function prototypes.
void MyHandleError(LPTSTR psz);
bool SignMessage(CRYPT_DATA_BLOB *pSignedMessageBlob);
bool VerifySignedMessage(
    CRYPT_DATA_BLOB *pSignedMessageBlob, 
    CRYPT_DATA_BLOB *pDecodedMessageBlob);

int _tmain(int argc, _TCHAR* argv[])
{
    UNREFERENCED_PARAMETER(argc);
    UNREFERENCED_PARAMETER(argv);
    
    CRYPT_DATA_BLOB SignedMessage;

    if(SignMessage(&SignedMessage))
    {
        CRYPT_DATA_BLOB DecodedMessage;

        if(VerifySignedMessage(&SignedMessage, &DecodedMessage))
        {
            free(DecodedMessage.pbData);
        }

        free(SignedMessage.pbData);
    }

    _tprintf(TEXT("Press any key to exit."));
    _getch();
}

//-------------------------------------------------------------------
//    MyHandleError
void MyHandleError(LPTSTR psz)
{
    _ftprintf(stderr, TEXT("An error occurred in the program. \n"));
    _ftprintf(stderr, TEXT("%s\n"), psz);
    _ftprintf(stderr, TEXT("Error number %x.\n"), GetLastError());
    _ftprintf(stderr, TEXT("Program terminating. \n"));
} // End of MyHandleError

//-------------------------------------------------------------------
//    SignMessage
bool SignMessage(CRYPT_DATA_BLOB *pSignedMessageBlob)
{
    bool fReturn = false;
    BYTE* pbMessage;
    DWORD cbMessage;
    HCERTSTORE hCertStore = NULL;   
    PCCERT_CONTEXT pSignerCert; 
    CRYPT_SIGN_MESSAGE_PARA  SigParams;
    DWORD cbSignedMessageBlob;
    BYTE  *pbSignedMessageBlob = NULL;

    // Initialize the output pointer.
    pSignedMessageBlob->cbData = 0;
    pSignedMessageBlob->pbData = NULL;

    // The message to be signed.
    // Usually, the message exists somewhere and a pointer is
    // passed to the application.
    pbMessage = 
        (BYTE*)TEXT("CryptoAPI is a good way to handle security");

    // Calculate the size of message. To include the 
    // terminating null character, the length is one more byte 
    // than the length returned by the strlen function.
    cbMessage = (lstrlen((TCHAR*) pbMessage) + 1) * sizeof(TCHAR);

    // Create the MessageArray and the MessageSizeArray.
    const BYTE* MessageArray[] = {pbMessage};
    DWORD_PTR MessageSizeArray[1];
    MessageSizeArray[0] = cbMessage;

    //  Begin processing. 
    _tprintf(TEXT("The message to be signed is \"%s\".\n"),
        pbMessage);

    // Open the certificate store.
    if ( !( hCertStore = CertOpenStore(
       CERT_STORE_PROV_SYSTEM,
       0,
       NULL,
       CERT_SYSTEM_STORE_CURRENT_USER,
       CERT_STORE_NAME)))
    {
         MyHandleError(TEXT("The MY store could not be opened."));
         goto exit_SignMessage;
    }

    // Get a pointer to the signer's certificate.
    // This certificate must have access to the signer's private key.
    if(pSignerCert = CertFindCertificateInStore(
       hCertStore,
       MY_ENCODING_TYPE,
       0,
       CERT_FIND_SUBJECT_STR,
       SIGNER_NAME,
       NULL))
    {
       _tprintf(TEXT("The signer's certificate was found.\n"));
    }
    else
    {
        MyHandleError( TEXT("Signer certificate not found."));
        goto exit_SignMessage;
    }

    // Initialize the signature structure.
    SigParams.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA);
    SigParams.dwMsgEncodingType = MY_ENCODING_TYPE;
    SigParams.pSigningCert = pSignerCert;
    SigParams.HashAlgorithm.pszObjId = szOID_RSA_SHA1RSA;
    SigParams.HashAlgorithm.Parameters.cbData = NULL;
    SigParams.cMsgCert = 1;
    SigParams.rgpMsgCert = &pSignerCert;
    SigParams.cAuthAttr = 0;
    SigParams.dwInnerContentType = 0;
    SigParams.cMsgCrl = 0;
    SigParams.cUnauthAttr = 0;
    SigParams.dwFlags = 0;
    SigParams.pvHashAuxInfo = NULL;
    SigParams.rgAuthAttr = NULL;

    // First, get the size of the signed BLOB.
    if(CryptSignMessage(
        &SigParams,
        FALSE,
        1,
        MessageArray,
        MessageSizeArray,
        NULL,
        &cbSignedMessageBlob))
    {
        _tprintf(TEXT("%d bytes needed for the encoded BLOB.\n"),
            cbSignedMessageBlob);
    }
    else
    {
        MyHandleError(TEXT("Getting signed BLOB size failed"));
        goto exit_SignMessage;
    }

    // Allocate memory for the signed BLOB.
    if(!(pbSignedMessageBlob = 
       (BYTE*)malloc(cbSignedMessageBlob)))
    {
        MyHandleError(
            TEXT("Memory allocation error while signing."));
        goto exit_SignMessage;
    }

    // Get the signed message BLOB.
    if(CryptSignMessage(
          &SigParams,
          FALSE,
          1,
          MessageArray,
          MessageSizeArray,
          pbSignedMessageBlob,
          &cbSignedMessageBlob))
    {
        _tprintf(TEXT("The message was signed successfully. \n"));

        // pbSignedMessageBlob now contains the signed BLOB.
        fReturn = true;
    }
    else
    {
        MyHandleError(TEXT("Error getting signed BLOB"));
        goto exit_SignMessage;
    }

exit_SignMessage:

    // Clean up and free memory as needed.
    if(pSignerCert)
    {
        CertFreeCertificateContext(pSignerCert);
    }
    
    if(hCertStore)
    {
        CertCloseStore(hCertStore, CERT_CLOSE_STORE_CHECK_FLAG);
        hCertStore = NULL;
    }

    // Only free the signed message if a failure occurred.
    if(!fReturn)
    {
        if(pbSignedMessageBlob)
        {
            free(pbSignedMessageBlob);
            pbSignedMessageBlob = NULL;
        }
    }

    if(pbSignedMessageBlob)
    {
        pSignedMessageBlob->cbData = cbSignedMessageBlob;
        pSignedMessageBlob->pbData = pbSignedMessageBlob;
    }
    
    return fReturn;
}

//-------------------------------------------------------------------
//    VerifySignedMessage
//
//    Verify the message signature. Usually, this would be done in 
//    a separate program. 
bool VerifySignedMessage(
    CRYPT_DATA_BLOB *pSignedMessageBlob, 
    CRYPT_DATA_BLOB *pDecodedMessageBlob)
{
    bool fReturn = false;
    DWORD cbDecodedMessageBlob;
    BYTE *pbDecodedMessageBlob = NULL;
    CRYPT_VERIFY_MESSAGE_PARA VerifyParams;

    // Initialize the output.
    pDecodedMessageBlob->cbData = 0;
    pDecodedMessageBlob->pbData = NULL;

    // Initialize the VerifyParams data structure.
    VerifyParams.cbSize = sizeof(CRYPT_VERIFY_MESSAGE_PARA);
    VerifyParams.dwMsgAndCertEncodingType = MY_ENCODING_TYPE;
    VerifyParams.hCryptProv = 0;
    VerifyParams.pfnGetSignerCertificate = NULL;
    VerifyParams.pvGetArg = NULL;

    // First, call CryptVerifyMessageSignature to get the length 
    // of the buffer needed to hold the decoded message.
    if(CryptVerifyMessageSignature(
        &VerifyParams,
        0,
        pSignedMessageBlob->pbData,
        pSignedMessageBlob->cbData,
        NULL,
        &cbDecodedMessageBlob,
        NULL))
    {
        _tprintf(TEXT("%d bytes needed for the decoded message.\n"),
            cbDecodedMessageBlob);

    }
    else
    {
        _tprintf(TEXT("Verification message failed. \n"));
        goto exit_VerifySignedMessage;
    }

    //---------------------------------------------------------------
    //   Allocate memory for the decoded message.
    if(!(pbDecodedMessageBlob = 
       (BYTE*)malloc(cbDecodedMessageBlob)))
    {
        MyHandleError(
            TEXT("Memory allocation error allocating decode BLOB."));
        goto exit_VerifySignedMessage;
    }

    //---------------------------------------------------------------
    // Call CryptVerifyMessageSignature again to verify the signature
    // and, if successful, copy the decoded message into the buffer. 
    // This will validate the signature against the certificate in 
    // the local store.
    if(CryptVerifyMessageSignature(
        &VerifyParams,
        0,
        pSignedMessageBlob->pbData,
        pSignedMessageBlob->cbData,
        pbDecodedMessageBlob,
        &cbDecodedMessageBlob,
        NULL))
    {
        _tprintf(TEXT("The verified message is \"%s\".\n"),
            pbDecodedMessageBlob);

        fReturn = true;
    }
    else
    {
        _tprintf(TEXT("Verification message failed. \n"));
    }

exit_VerifySignedMessage:
    // If something failed and the decoded message buffer was 
    // allocated, free it.
    if(!fReturn)
    {
        if(pbDecodedMessageBlob)
        {
            free(pbDecodedMessageBlob);
            pbDecodedMessageBlob = NULL;
        }
    }

    // If the decoded message buffer is still around, it means the 
    // function was successful. Copy the pointer and size into the 
    // output parameter.
    if(pbDecodedMessageBlob)
    {
        pDecodedMessageBlob->cbData = cbDecodedMessageBlob;
        pDecodedMessageBlob->pbData = pbDecodedMessageBlob;
    }

    return fReturn;
}

Procedure for Signing Data: More About Crypto Message Syntax used in Digital Signature and encryption Standards


This page from Microsoft defines the concepts.

https://docs.microsoft.com/en-us/windows/win32/seccrypto/procedure-for-signing-data

PKCS #12
The Personal Information Exchange Syntax Standard, developed and maintained by RSA Data Security, Inc. This syntax standard specifies a portable format for storing or transporting a user's private keys, certificates, and miscellaneous secrets.

PKCS #7
The Cryptographic Message Syntax Standard. A general syntax for data to which cryptography may be applied, such as digital signatures and encryption. It also provides a syntax for disseminating certificates or certificate revocation lists and other message attributes, such as time stamps, to the message.


PKCS #7 Signed Data
A data object that is signed with the Public Key Cryptography Standard #7 (PKCS #7) and that encapsulates the information used to sign a file. Typically, it includes the signer's certificate and the root certificate.



The content types defined in the PKCS #7 standard are as follows.
TABLE 1
Content typeDescription
DataAn octet (BYTE) string.
Signed DataContent of any type and encrypted message hashes (digests) of the content for zero or more signers.
Enveloped DataEncrypted content of any type and encrypted content-encryption keys for one or more recipients. The combination of encrypted content and encrypted content-encryption key for a recipient is a digital envelope for that recipient.
Signed-and-Enveloped DataEncrypted content of any type, encrypted content-encryption keys for one or more recipients, and doubly encrypted message digests for one or more signers. The double encryption consists of an encryption with a signer's private key followed by an encryption with the content-encryption key.
Digested DataContent of any type and a message hash (digest) of the content.
Encrypted DataEncrypted content of any type. Unlike the enveloped-data content type, the encrypted-data content type has neither recipients nor encrypted content-encryption keys. Keys are assumed to be managed by other means.

Saturday, June 6, 2020

Commonly Used Terms and Acronyms

OAEP: In RSA cryptography, OAEP stands for Optimal Asymmetric Encryption Padding, a padding structure often used with RSA encryption. The OAEP algorithm accomplishes two goals:
  • Add an element of randomness which can be used to transform the deterministic encryption (e.g. RSA encryption) to a probabilistic one.
  • Defend against any partial decryption (or other information leakage) attacks against ciphertext by ensuring that the attacker cannot obtain any part of the plaintext without being able to invert the trap door one way permutation. See https://en.wikipedia.org/wiki/Optimal_asymmetric_encryption_padding.
OAEP is a type of Feistel Network.

CAdES-BES: CMS Advanced Electronic Signature - Basic Electronic Signature

PKCS#7:
see: https://boringssl.googlesource.com/boringssl/+/master/include/openssl/pkcs7.h

// Deprecated functions.
//
// These functions are a compatibility layer over a subset of OpenSSL's PKCS#7
// API. It intentionally does not implement the whole thing, only the minimum
// needed to build cryptography.io.

typedef struct {
   STACK_OF(X509) *cert;
   STACK_OF(X509_CRL) *crl;
} PKCS7_SIGNED;

typedef struct {
   STACK_OF(X509) *cert;
   STACK_OF(X509_CRL) *crl;
} PKCS7_SIGN_ENVELOPE;

typedef void PKCS7_ENVELOPE;
typedef void PKCS7_DIGEST;
typedef void PKCS7_ENCRYPT;

typedef struct {
   uint8_t *ber_bytes;
   size_t ber_len;

// Unlike OpenSSL, the following fields are immutable. They filled in when the
// object is parsed and ignored in serialization.
ASN1_OBJECT *type;
  union {
   char *ptr;
   ASN1_OCTET_STRING *data;
   PKCS7_SIGNED *sign;
   PKCS7_ENVELOPE *enveloped;
   PKCS7_SIGN_ENVELOPE *signed_and_enveloped;
   PKCS7_DIGEST *digest;
   PKCS7_ENCRYPT *encrypted;
   ASN1_TYPE *other;
  } d;
} PKCS7;

// d2i_PKCS7 parses a BER-encoded, PKCS#7 signed data ContentInfo structure from
// |len| bytes at |*inp|. If |out| is not NULL then, on exit, a pointer to the
// result is in |*out|. Note that, even if |*out| is already non-NULL on entry,
// it will not be written to. Rather, a fresh |PKCS7| is allocated and the
// previous one is freed. On successful exit, |*inp| is advanced past the BER
// structure. It returns the result or NULL on error.
OPENSSL_EXPORT PKCS7 *d2i_PKCS7(PKCS7 **out, const uint8_t **inp,
size_t len);

Monday, December 16, 2019

Deepfake can be defeated by Controlled Capture ...

Controlled Capture at TruePic.com is the set of software and tools to define the optimal ways to
track authenticity, integrity, provenance and digital edits of images, audio and video from
capture to sharing to ongoing use.
See: https://lab.witness.org/ticks-or-it-didnt-happen/

  1. Right to privacy
  2. Freedom of surveillance

Monday, December 26, 2016

ION Allocator, Revisited

4 years ago I wrote a LWN paper on ION Allocator.
I'm surprised to see ION still is changing, after 4 years of in staging.

Here's the latest ION interface in ion.h, but Laura is mainly proposing to adjust ION API so that it relies on the kernel's DMA abstraction layer, the DMA mapping API, to handle DMA cache synchronization and MMU mapping, by updating mainly ion_map_dma_buf() in  ion.c file, so that clients does not have to peek into ION objects to manage DMA operations.

It seems the new way would be to call dma_map_sg() directly using the ION object (or the dma_buf object associated with the ION object).

In comparison, the old way is shown in the call flow below.




1090 static struct dma_buf_ops dma_buf_ops = {
1091         .map_dma_buf = ion_map_dma_buf,
878 static struct sg_table *ion_map_dma_buf(struct dma_buf_attachment *attachment,
879                                         enum dma_data_direction direction)
75 /**
 76  * ion_client_create() -  allocate a client and returns it
 77  * @dev:                the global ion device
 78  * @name:               used for debugging
 79  */
 80 struct ion_client *ion_client_create(struct ion_device *dev,
 81                                      const char *name);
 82 
 83 /**
 84  * ion_client_destroy() -  free's a client and all it's handles
 85  * @client:     the client
 86  *
 87  * Free the provided client and all it's resources including
 88  * any handles it is holding.
 89  */
 90 void ion_client_destroy(struct ion_client *client);
 91 
 92 /**
 93  * ion_alloc - allocate ion memory
 94  * @client:             the client
 95  * @len:                size of the allocation
 96  * @align:              requested allocation alignment, lots of hardware blocks
 97  *                      have alignment requirements of some kind
 98  * @heap_id_mask:       mask of heaps to allocate from, if multiple bits are set
 99  *                      heaps will be tried in order from highest to lowest
100  *                      id
101  * @flags:              heap flags, the low 16 bits are consumed by ion, the
102  *                      high 16 bits are passed on to the respective heap and
103  *                      can be heap custom
104  *
105  * Allocate memory in one of the heaps provided in heap mask and return
106  * an opaque handle to it.
107  */
108 struct ion_handle *ion_alloc(struct ion_client *client, size_t len,
109                              size_t align, unsigned int heap_id_mask,
110                              unsigned int flags);
111 
112 /**
113  * ion_free - free a handle
114  * @client:     the client
115  * @handle:     the handle to free
116  *
117  * Free the provided handle.
118  */
119 void ion_free(struct ion_client *client, struct ion_handle *handle);
120 
121 /**
122  * ion_map_kernel - create mapping for the given handle
123  * @client:     the client
124  * @handle:     handle to map
125  *
126  * Map the given handle into the kernel and return a kernel address that
127  * can be used to access this address.
128  */
129 void *ion_map_kernel(struct ion_client *client, struct ion_handle *handle);
130 
131 /**
132  * ion_unmap_kernel() - destroy a kernel mapping for a handle
133  * @client:     the client
134  * @handle:     handle to unmap
135  */
136 void ion_unmap_kernel(struct ion_client *client, struct ion_handle *handle);
137 
138 /**
139  * ion_share_dma_buf() - share buffer as dma-buf
140  * @client:     the client
141  * @handle:     the handle
142  */
143 struct dma_buf *ion_share_dma_buf(struct ion_client *client,
144                                                 struct ion_handle *handle);
145 
146 /**
147  * ion_share_dma_buf_fd() - given an ion client, create a dma-buf fd
148  * @client:     the client
149  * @handle:     the handle
150  */
151 int ion_share_dma_buf_fd(struct ion_client *client, struct ion_handle *handle);
152 
153 /**
154  * ion_import_dma_buf() - get ion_handle from dma-buf
155  * @client:     the client
156  * @dmabuf:     the dma-buf
157  *
158  * Get the ion_buffer associated with the dma-buf and return the ion_handle.
159  * If no ion_handle exists for this buffer, return newly created ion_handle.
160  * If dma-buf from another exporter is passed, return ERR_PTR(-EINVAL)
161  */
162 struct ion_handle *ion_import_dma_buf(struct ion_client *client,
163                                       struct dma_buf *dmabuf);
164 
165 /**
166  * ion_import_dma_buf_fd() - given a dma-buf fd from the ion exporter get handle
167  * @client:     the client
168  * @fd:         the dma-buf fd
169  *
170  * Given an dma-buf fd that was allocated through ion via ion_share_dma_buf_fd,
171  * import that fd and return a handle representing it. If a dma-buf from
172  * another exporter is passed in this function will return ERR_PTR(-EINVAL)
173  */
174 struct ion_handle *ion_import_dma_buf_fd(struct ion_client *client, int fd);
175 
176 #endif /* _LINUX_ION_H */

Thursday, December 22, 2016

Advanced Cryptography, Number Theory and Algebra

Interesting link b/w public key cryptography taught by David Moneh of Stanford. He recommended math book by Victor Shoup of New York University:
  1. https://www.coursera.org/learn/crypto/supplement/wCCF4/more-background-on-number-theory
  2. http://shoup.net/ntb/ntb-v2.pdf