Skip to content

PascalLG/cinnabar-c

master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Cinnabar

Cinnabar is that mineral powder that gives this bright red tint to Asian name seals. It is also a (hopefully) portable piece of C code to generate and check RSA signatures.

Key features:

  • Implements RSASSA-PKCS1-v1_5 with SHA-256 as hashing function
  • Supports any key length > 496 bits
  • Easy to integrate: just drop cinnabar.h and cinnabar.c in your project
  • Should compile on any platform with a decent 32-bit or 64-bit C compiler
  • Works on both little endian and big endian platforms

It is primarily intended for embedded systems where usual crypto libraries are not available, and for applications where you must compile the exact same source code on (possibly very) different platforms.

Key generation

Signing requires a RSA private key. Verifying a signature requires the corresponding public key. Cinnabar accepts keys in the PEM format. You can easily generate such keys using openssl, which should be available on any Unix-like system.

You can generate a private key by typing the following command in a terminal:

openssl genrsa -out private.pem 2048

This generates a 2048-bit RSA pair and write it to a file named private.pem. From this private key, you can then ask openssl to generate a public key:

openssl rsa -in private.pem -outform PEM -pubout -out public.pem

You can open these files in a text editor and check that the private key is enclosed between -----BEGIN RSA PRIVATE KEY----- and -----END RSA PRIVATE KEY----- lines, while the public key is enclosed between -----BEGIN PUBLIC KEY----- and -----END PUBLIC KEY----- lines.

Remember that your private key should remain, huh, well… secret. This means that you must generate it on your computer (or on the final user's computer) and never grab one on a random web site. A private key must never be sent over an insecure channel such as an email. It is also usually not the best idea to embed a private key in your source code: an executable file is not a secure place and moreover, if your key is uncovered after your application is deployed on thousands of computers, your would not be able to change it easily. The exact key management scheme depends on your application though.

Usage

To be portable and not rely upon any specific file system or operating system, Cinnabar does not directly read PEM files. Instead, your code must load key content in memory by any mean that pertains to your application or use case, and then pass Cinnabar functions a pointer to this content.

Signing

You compute the signature of a piece of data by calling the following function:

CnbrStatus CnbrSignature(CNBR_SIGNATURE * signature, const void * document_data, size_t document_length, const char * pem_private_key)

  • signature is a pointer to a statically allocated CNBR_SIGNATURE structure that will receive signature data
  • document_data is a pointer to the data to sign
  • document_length is the length (in bytes) of the data to sign
  • pem_private_key is a pointer to the content of an RSA private key PEM file

On success, the function returns CnbrSuccess and the CNBR_SIGNATURE structure contains signature data and length. In the event of an error, the function returns one of the error code defined in the CnbrStatus enumeration. Your original data is unchanged (note the parameter is defined as a pointer to const data).

The CNBR_SIGNATURE structure holds a pointer to the signature data. How you use this signature depends on your application and use case. For example, if your application is signing a mail, you can encode this signature to base64 and join it as an attachment to the mail.

Once you are done with the signature data, you must call CnbrEraseSignature to erase any sensitive information and free allocated memory.

Verifying a signature

You verify a signature by calling the following function:

CnbrStatus CnbrVerifySignature(const uint8_t * signature_data, size_t signature_length, const void * document_data, size_t document_length, const char * pem_public_key)

  • signature_data is a pointer to a signature previously generated by the CnbrSignature function (or by any other RSASSA-PKCS1-v1_5 compliant implementation)
  • signature_length is the length (in bytes) of the signature
  • document_data is a pointer to the data whose signature is being verified
  • document_length is the length (in bytes) of the data
  • pem_public_key is a pointer to the content of a public key PEM file

If the signature is valid, the function returns CnbrSuccess. If an error occurred or if the signature is not valid, the function returns one of the error code defined in the CnbrStatus enumeration.

A valid signature ensures authentication, non-repudiation and integrity: it gives a strong indication that the message was created by a known sender, that the sender cannot deny having signed the message, and that the message was not altered afterwards.

Tests

The test folder contains a small application that runs unit tests on several functions of cinnabar.c. (Note: to allow testing of private functions and data structures, the code for this test application does not link against the cinnabar library but directly includes cinnabar.c. Of course, this is not how you are supposed to use cinnabar.c in your own projects.)

To run the test suite on macOS:

  • Open the Xcode project file that resides in the same folder
  • Build and run the project

For other platforms, a CMakeFileLists.txt file is provided. To run the test suite:

  • Change to the test directory
  • Create a build subdirectory here and jump to it: mkdir build && cd build
  • Generate a makefile: cmake -DCMAKE_BUILD_TYPE=Release ..
  • Build the project: make
  • Run it: ./CnbrTest

Sample code

The sample folder contains an application implementing basic file signature and verification. (Note: this is just a minimal sample to demonstrate cinnabar usage. A real life application should have better handling of errors and corner cases. For example, it should back up files before modifying them.)

A CMakeFileLists.txt file is provided to build this sample:

  • Change to the sample directory
  • Create a build subdirectory here and jump to it: mkdir build && cd build
  • Generate a makefile: cmake -DCMAKE_BUILD_TYPE=Release ..
  • Build the project: make

You also have to generate private.pem and public.pem key files, as explained above. Then, to sign a file named foo.txt for example:

rsa-sign sign private.pem foo.txt

This appends to foo.txt a small trailer containing the signature and some management information. To verify the signature and hence the file was not tampered:

rsa-sign verify public.pem foo.txt

You can also remove the trailer containing the signature and restore the original file by adding the -r option:

rsa-sign verify -r public.pem foo.txt

About

Library implementing the RSASSA signature scheme.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published