| Introduction | PKCS#11 | NCryptoki | API Documentation | Wiki | Tutorial C# | Tutorial VB 6 |
Introduction
NCryptoki is a library for .NET framework that implements the PKCS#11 specifications and supplies an API for C#, VB.NET, Visual Basic 6, Delphi and other COM interop languages for integrating a PKCS#11 compliant token in any application.
NCryptoki maps the cryptoki's functions defined in PKCS#11 specification in a set of high level classes usable in C#, VB.NET and propose a programming paradigm that allows to integrate your PKCS#11 compliant token in your applications easily with a few lines of code.
NCryptoki supplies also a COM interface that allows to use the supplied classes in any language that supports COM interop like Visual Basic 6, Delphi etc.
The main features are:
-
Compliant with PKCS#11 2.20 specifications
-
Compliant with any PKCS#11 token
-
32 or 64 bit platform
-
.NET Framework 2.0, 3.5 and 4.0
PKCS#11
PKCS#11 (Public Key Cryptography Standards No. 11) specifications, developed by RSA Data Security labs, defines an high-level, platform-independent API to cryptographic devices (such as smart cards, USB Tokens, HSMs, etc.), that hides the low level operational logic of a cryptographic devices, presenting to the applications a unified abstraction layer for a generic cryptographic token with an higher level set of functions.
The high flexibility and the simple logic of such a model made the PKCS#11 specifications a de-facto standard widely used by applications interacting with smart cards. PKCS#11 is largely adopted to access smart cards, cryptographic tokens and HSMs. Most commercial Certification Authority software uses PKCS#11 to access the CA signing key or to enroll user certificates as well as cross-platform software that needs to use smart cards uses PKCS#11, such as Mozilla Firefox and OpenSSL (using an extension).
Because the API is defined in C language, the PKCS#11 module is implemented in C as native library (a Dinamically Linked Library (.dll) in Windows OS or as Shared Object (.so) on Linux and MacOS) that exports the functions of the API. This means that if your application is in C/C++ you can easily import the API functions in your code, But what if your application is in C# or VB.NET? Or what if you application is in Visual Basic 6 or Delphi? NCryptoki addresses this stuffs and allows to call PKCS#11 API in your .NET applications.
Architecture
A typical Cryptoki-based system architecture is depicted in Figure 2.
The cryptographic device (aka token) is connected to the system via a slot. Typically, a slot corresponds to a smart card reader or a specific card terminal. However, because Cryptoki offers a purely logical view of the system it could happens that different slots point to the same physical reader device or, viceversa, a single slot could have more than one device.
The logical structure of a token
A specific Cryptoki implementation maps the token’s physical structure, typically composed by memory zones in which data, cryptographic keys and their digital certificates are stored, into a logical structure that adheres to the hierarchical model shown in Figure 3.
The specifications define three main object classes:
-
Dataobjects host generic data which semantics is defined by the application who created them;
-
Certificateobjects store digital certificates;
-
Keyobjects contain a public, private or secret cryptographic key.
Cryptoki’s objects are classified depending on their visibility in public objects (i.e. accessible by all applications), and private objects (visible only after granting access permissions typically performed via PIN-verification as described later), and on their persistency in: token objects which persist when the token is plugged-out from the slot and in session objects which don’t persist. For each class of objects the specifications define a set of attributes (as described later) characterizing all instances of the class, which, are inherited by derived classes, similarly to an object-oriented model (for example, the Private Key class inherits all attributes from the Key class etc.)
The PKCS#11 API
PKCS#11 specifications define an API named Cryptoki (CRYPtographic TOKen Interface) that implements an API to an abstract model of a cryptographic device, such as a microprocessor-based smart card, a USB cryptographic token or an HSM. The API follows a simple object-based approach, addressing the goals of technology independence (any kind of device) and resource sharing (multiple applications accessing multiple devices), presenting to applications a common, logical view of the device called a cryptographic token. The API defines the most commonly used cryptographic object types (RSA keys, X.509 Certificates, DES/Triple DES keys, etc.) and all the functions needed to use, create/generate, modify and delete those objects:
The programming language used to define the functions and data types is ANSI C. Along with specifications, RSA Data Security published three C header files (pkcs11.h, pkcs11t.h and pkcs11f.h, available at this page: http://www.rsa.com/rsalabs/node.asp?id=2133) that define function prototypes, Cryptoki-specific data types and a set of macros to manage objects classes and their attributes.
Using the Cryptoki API in a .NET application
As we said above, the API is defined in C language and the PKCS#11 modules are implemented in C as native unmanaged libraries. In order to use it in a .NET application we have no chance to avoid from using platform invoke services (P-Invoke), supplied by the .NET framework, to import the unmanaged functions of the native API in our C# and/or VB.NET managed code. But importing such functions from an unmanaged dll, expecially from a highly complex PKCS#11 dll, requires very advanced skills in C/C++ and .NET and compels a lot of tedious work to write the declaration of the prototypes related to the functions using the P-Invoke rules and to deal with the marshalling of custom parameters.
NCryptoki library allows to avoid from dealing with P-Invoke declarations and unmanaged code saving a lot of tedious work.
NCryptoki
NCryptoki is a library for .NET framework that implements the PKCS#11 specifications and supplies an API for C#, VB.NET, Visual Basic 6, Delphi and other COM interop languages for integrating a PKCS#11 compliant token in any application.
NCryptoki maps the cryptoki's functions defined in PKCS#11 specification in a set of high level classes usable in C#, VB.NET and propose a programming paradigm that allows to integrate your PKCS#11 compliant token in your applications easily with a few lines of code.
NCryptoki supplies also a COM interface that allows to use the supplied classes in any language that supports COM interop like Visual Basic 6, Delphi etc.
The programming paradigm is very similar to the one described in C programming language in PKCS#11 specifications: the PKCS#11 C functions are mapped into a set of .NET classes that follows the same classification described above.
Figure 1 at right shows the class hierarchy of NCryptoki.
Cryptokiis the main class that allows to use the library, the classes Slot and Token enclose the slot-handling and token-handling functions, while the class CryptokiObject encapsulates the object-handling functions as well as the definitions related to objects’ classes and their attributes. The class Session includes the OpenSession and CloseSession functions, the functions related to login and logout, the search functions to search for PKCS#11 objects and, finally, the cryptographic and hashing functions and the other functions defined in the PKCS#11 specifications.
The documentation is available here:
Online HTML: API Documentation
Help File (CHM): NCryptokiAPIdoc.chm
Wiki: http://wiki.ncryptoki.com/
White Paper (PDF): How to use NCryptoki
Tutorial C#:
This tutorial shows how to accomplish the following PKCS#11 procedures:
Tutorial Visual Basic 6:
This tutorial shows briefly the following procedures:
1. Instanciate and Initialize a Cryptoki object
// Creates a Cryptoki object and attach it to the PKCS#11 native library smaoscki.dll
Cryptoki cryptoki = new Cryptoki("smaoscki.dll");
int nRet = cryptoki.Initialize();
if (nRet != 0)
{
error(nRet);
}
...
cryptoki.Finalize(IntPtr.Zero);
2. Read available slots:
// Reads the set of available slots
SlotList slots = cryptoki.Slots;
if (slots.Count == 0)
throw new Exception("No slots available");
// Gets the first slot available
Slot slot = slots[0];
3. Open and Close a session
// Gets the first token available
if(!slot.IsTokenInserted)
{
Console.WriteLine("No token found in the slot: " + slot.Info.Description);
return;
}
Token token = slot.Token;
// Prints all information relating to the token
TokenInfo tinfo = token.Info;
Console.WriteLine(tinfo.Label);
Console.WriteLine(tinfo.ManufacturerID);
Console.WriteLine(tinfo.Model);
Console.WriteLine(tinfo.SerialNumber);
Console.WriteLine(tinfo.HardwareVersion);
// Opens a read/write serial session
Session session = token.OpenSession (Session.CKF_SERIAL_SESSION | Session.CKF_RW_SESSION, null, null);
...
session.Close();
4. Login and Logout
// Executes the login passing the user PIN
int nRes = session.Login((int)Session.CKU_USER, "12345678");
if (nRes != 0)
{
Console.WriteLine("Wrong PIN");
return;
}
Console.WriteLine("Logged in:" + session.IsLoggedIn);
5. Search for some objects
// Searchs for an RSA private key object
// Sets the template with its attributes
CryptokiCollection template = new CryptokiCollection();
template.Add(new ObjectAttribute(ObjectAttribute.CKA_CLASS, CryptokiObject.CKO_PRIVATE_KEY));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_KEY_TYPE, Key.CKK_RSA));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_LABEL, "Ugo's new Key 0"));
// Launchs the search specifying the template just created
CryptokiCollection objects = session.Objects.Find(template, 10);
// If the private keys is found continue
if (objects.Count > 0)
{
foreach (Object obj in objects)
{
Console.WriteLine(((PrivateKey)obj).Label);
}
RSAPrivateKey privateKey;
privateKey = (RSAPrivateKey)objects[objects.Count - 1];
Console.WriteLine(privateKey.Label);
}
6. Create a Data object
CryptokiCollection template = new CryptokiCollection();
template.Add(new ObjectAttribute(ObjectAttribute.CKA_CLASS, CryptokiObject.CKO_DATA));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_LABEL, label));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_APPLICATION, application));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_TOKEN, true));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_PRIVATE, true);
template.Add(new ObjectAttribute(ObjectAttribute.CKA_MODIFIABLE, true);
template.Add(new ObjectAttribute(ObjectAttribute.CKA_VALUE, value));
Data data = (Data)session.Objects.Create(template);
7. Create a Certificate object
CryptokiCollection template = new CryptokiCollection();
template.Add(new ObjectAttribute(ObjectAttribute.CKA_CLASS, CryptokiObject.CKO_CERTIFICATE));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_SUBJECT, cert.SubjectName.RawData));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_ISSUER, cert.Issuer));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_SERIAL_NUMBER, cert.SerialNumber));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_ID, id));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_LABEL, label));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_TOKEN, true));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_VALUE, cert.RawData));
template.Add(new ObjectAttribute(ObjectAttribute.CKA_MODIFIABLE, modifiable));
CryptokiObject certificate = CurrentSession.Objects.Create(template);
8. Generate a key pair
// Prepares the templates for key pair generation
CryptokiCollection templatePub = new CryptokiCollection();
templatePub.Add(new ObjectAttribute(ObjectAttribute.CKA_CLASS, CryptokiObject.CKO_PUBLIC_KEY));
templatePub.Add(new ObjectAttribute(ObjectAttribute.CKA_TOKEN, true));
templatePub.Add(new ObjectAttribute(ObjectAttribute.CKA_PRIVATE, false));
templatePub.Add(new ObjectAttribute(ObjectAttribute.CKA_LABEL, "Ugo's new Key"));
templatePub.Add(new ObjectAttribute(ObjectAttribute.CKA_ID, "1"));
templatePub.Add(new ObjectAttribute(ObjectAttribute.CKA_MODULUS_BITS, 1024));
templatePub.Add(new ObjectAttribute(ObjectAttribute.CKA_PUBLIC_EXPONENT, 0x010001));
CryptokiCollection templatePri = new CryptokiCollection();
templatePri.Add(new ObjectAttribute(ObjectAttribute.CKA_CLASS, CryptokiObject.CKO_PRIVATE_KEY));
templatePri.Add(new ObjectAttribute(ObjectAttribute.CKA_TOKEN, true));
templatePri.Add(new ObjectAttribute(ObjectAttribute.CKA_PRIVATE, true));
templatePri.Add(new ObjectAttribute(ObjectAttribute.CKA_LABEL, "Ugo's new Key 0"));
templatePri.Add(new ObjectAttribute(ObjectAttribute.CKA_ID, "1"));
//generate the key objects
Key[] keys = session.GenerateKeyPair(Mechanism.RSA_PKCS_KEY_PAIR_GEN, templatePub, templatePri);
RSAPrivateKey privateKey = (RSAPrivateKey)keys[1];
RSAPublicKey publicKey = (RSAPublicKey)keys[0];
9. Encrypt and decrypt
string helloworld = "Hello World";
byte[] text = Encoding.ASCII.GetBytes(helloworld);
// launches the encryption operation DES mechanism
nRes = session.EncryptInit(Mechanism.DES, key);
// computes the encryption
byte[] encrypted = session.Encrypt(text);
...
nRes = session.DecryptInit(Mechanism.DES, key);
byte[] decrypted = session.Decrypt(encrypted);
10. Sign and Verify
string helloworld = "Hello World";
byte[] text = Encoding.ASCII.GetBytes(helloworld);
// launches the digital signing operation with a RSA_PKCS mechanism
nRes = session.SignInit(Mechanism.SHA1_RSA_PKCS, privateKey);
// computes the signature
byte[] signature = session.Sign(text);
...
nRes = session.VerifyInit(Mechanism.SHA1_RSA_PKCS, publicKey);
nRes = session.Verify(text, signature);
if(nRes == 0)
Console.Write("Verify " + nRes);
Tutorial Visual Basic 6 (COM interop)
Setup NCryptoki in Visual Basic 6
In order to use NCryptoki in a Visual Basic 6 application it must be registered by regasm. Open a DOS shell and type the following lines:
regasm /tlb /codebase <yourpathtoncryproki>/NCryptoki.dll
regasm /tlb /codebase <yourpathtoncryproki>/NCryptokiMngd.dll
Then to use NCryptoki in your project you must add the type library ncryptoki.tlb in the refences of your Visual Basic project
Dim ctoki As Cryptoki
Dim slots As SlotList
Dim slt As Slot
Dim tkn As Token
Dim sess As Session
Dim sessInfo As Session
Dim objs As CryptokiObjects
Dim I As Integer
' Creates new Cryptoki object
Set ctoki = New Cryptoki
' attach to pkcs11 module
ctoki.Attach ("SmaOScki.dll")
' initialize
ctoki.Initialize
' Get available slots
Set slots = ctoki.slots
' Get the first slot
Set slt = slots.GetSlot(1)
' Wait for a smart card inserted
Do While Not sltInfo.IsTokenPresent
MsgBox ("Insert Smart Card")
ctoki.WaitForSlotEvent (0)
Loop
' Get the token
Set tkn = slt.Token
' Open a session
Set sess = tkn.OpenSession(CKF_RW_SESSION Or CKF_SERIAL_SESSION)
' Login
sess.Login CKU_USER, "64005666"
' Prepares the templates to generate a key pair
Dim attrListPub As CryptokiCollection
Dim attrListPri As CryptokiCollection
Dim mech As Mechanism
Dim att As ObjectAttribute
Set attrListPub = New CryptokiCollection
Set attrListPri = New CryptokiCollection
' creates attributes object
Set att = New ObjectAttribute
att.Set CKA_CLASS, CKO_PUBLIC_KEY
attrListPub.Add att
Set att = New ObjectAttribute
att.Set CKA_TOKEN, True
attrListPub.Add att
Set att = New ObjectAttribute
att.Set CKA_PRIVATE, True
attrListPub.Add att
Set att = New ObjectAttribute
att.Set CKA_ENCRYPT, True
attrListPub.Add att
Set att = New ObjectAttribute
att.Set CKA_LABEL, "My Key"
attrListPub.Add att
' creates attributes object
Set att = New ObjectAttribute
att.Set CKA_CLASS, CKO_PRIVATE_KEY
attrListPri.Add att
Set att = New ObjectAttribute
att.Set CKA_TOKEN, True
attrListPri.Add att
Set att = New ObjectAttribute
att.Set CKA_PRIVATE, True
attrListPri.Add att
Set att = New ObjectAttribute
att.Set CKA_DECRYPT, True
attrListPri.Add att
Set att = New ObjectAttribute
att.Set CKA_LABEL, "My Key"
attrListPri.Add att
' Set mechanism
Set mech = New Mechanism
Dim val(1) As Byte
val(0) = 1
mech.Set CKM_RSA_PKCS_KEY_PAIR_GEN, val(0)
Dim pubKey As PublicKey
Dim priKey As PrivateKey
sess.GenerateKeyPair mech, attrListPub, attrListPri, pubKey, priKey
' Find Object just created
Dim attrList As CryptokiCollection
Set att = New ObjectAttribute
att.Set CKA_CLASS, CKO_PUBLIC_KEY
attrList.Add att
Set att = New ObjectAttribute
att.Set CKA_TOKEN, True
attrList.Add att
Set att = New ObjectAttribute
att.Set CKA_PRIVATE, True
attrList.Add att
Dim objList As CryptokiCollection
Set objList = objs.Find(attrList, 4)
' prepare buffer to encrypt
Dim toEncrypt(10) As Byte
Dim encrypted() As Byte
For I = 0 To 10
toEncrypt(I) = &H41 ' A
Next
mech.Set CKM_RSA_PKCS, Nothing
sess.EncryptInit mech, objList.Item(0)
encrypted = sess.Encrypt(toEncrypt(0))