Dpkcs11: Dart PKCS11 Wrapper
The Dpkcs11 library provides a Dart FFI wrapper for the PKCS11 (Cryptographic Token Interface) standard. This library allows Dart applications to interface with PKCS11-compatible hardware security modules (HSMs) and smart cards for cryptographic operations like hashing, signing, and verification.
Features
- **PKCS11 Standard Support:**Access to core PKCS11 functions: signing, verification and hashing/digest operations.
- Dart FFI Integration: Seamless integration with native PKCS11 libraries (e.g., dynamic link libraries on Windows, shared objects on Linux/macOS).
- Secure Operations: Enables applications to utilize the security features of hardware tokens for sensitive cryptographic tasks.
Getting Started
Prerequisites
To use this library, you must have:
- A PKCS11 compatible library (e.g.,
libpkcs11.so,pkcs11.dll) installed on your system.
Installation
Add dpkcs11 to your project's pubspec.yaml file:
dependencies:
dpkcs11: ^1.0.0 # Use the latest version
Then, run:
dart pub get
Initialization
You need to initialize the library by pointing it to the native PKCS11 implementation file.
import 'package:dpkcs11/dpkcs11.dart';
// Replace 'path/to/your/pkcs11/library' with the actual path
String libraryPath = 'path/to/your/pkcs11/library';
Dpkcs11 dpkcs11 = Dpkcs11(libraryPath: libraryPath);
//initialize, lists available slots
dpkcs11.init();
try {
PKCS11Slot slot = dpkcs11.selectFirstSlot(); // get a slot;
PKCS11Session session = slot.openSession(); // open slot to the session
try {
var pin = '123456';
session.login(pin);
try {
//some actions here
} finally {
session.logout();
}
} finally {
session.close();
}
} finally {
dpkcs11.close();
}
⚠️ Critical Resource Management Note: PKCS11 resources (sessions and library connections) must be released. Always pair init() and openSession() calls with close() and session.close() in a finally block to prevent resource leaks and potential security issues.
Key Type Support: RSA and ECDSA
The Dpkcs11 library simplifies the signing process by automatically selecting the correct PKCS11 signing mechanism based on the properties of the retrieved key object from the HSM/Smartcard.
Specifically:
- No Manual Mechanism Selection: You do not need to manually specify the low-level PKCS11 mechanisms (e.g.,
CKM_RSA_PKCSorCKM_ECDSA) when callingkeyPair.sign(). - Automatic Determination: The library examines the Key Type (e.g.,
CKO_RSA_PUBLIC_KEY,CKO_ECDSA_PUBLIC_KEY) and the relevant Digest Algorithm used (if the data is hashed internally by the token) to determine the necessary mechanism for the underlying PKCS11 call.
This design ensures that signing works seamlessly for both RSA and ECDSA key types stored on the hardware token, provided the key attributes allow the signature operation (CKA_SIGN is set to TRUE).
Examples
Signing
var datatosign = "Hello world";
//Keys are searched based on their PKCS11 Object Attributes
//(e.g., CKA_SIGN, CKA_VERIFY) stored on the token.
PKCS11Keypair? kp = session.getKeyPairByAttribute(
PKCS11Attribute.SIGN,
true,
);
if (kp == null) {
throw Exception("No key found for signing");
}
List<int> signature = kp.sign(datatosign);
print("Signature: $signature");
Verification
var datatosign = "Hello world";
List<int> = signature = [];
//get a keypair with signing capability
PKCS11Keypair? kp = session.getKeyPairByAttribute(
PKCS11Attribute.VERIFY,
true,
);
if (kp == null) {
throw Exception("No key found for verify");
}
bool signatureResult = kp.verify(datatosign, signature);
print("Verify signature: $signatureResult");
Digest
List<int> hash = session.digest(DigestMethod.SHA_1, "welcome1");
print("Digest: $hash");
🔑 Supported Digest Methods
The Dpkcs11 library supports the following common cryptographic hash algorithms, ensuring standard PKCS11 compatibility for digest operations:
- MD5
- SHA_1
- SHA224
- SHA256
- SHA384
- SHA512
🧩 Advanced Usage: Integrating with XML Digital Signatures
While Dpkcs11 focuses on direct PKCS11 interactions (signing, verification),
it can be seamlessly used with other Dart libraries to perform XML Digital Signatures (XMLDSig).
A great library for this purpose is xml_crypto, which handles the complexities of XML
canonicalization and signature structure. You can find the package details on pub.flutter-io.cn.
PKCS11 devices are commonly used to store private keys for securing XML documents, especially in regulated environments.
How it Works:
- Key Access:
Dpkcs11is used to securely access the private key from the HSM/Token (as shown in the Signing example). - Signing Engine: The
xml_cryptolibrary handles the complex process of:- Canonicalizing the XML data.
- Calculating the digest of the data.
- Generating the full XML signature structure (e.g.,
<Signature>,<SignedInfo>).
- Signature Generation: The
xml_cryptolibrary passes the final hash/data to be signed to theDpkcs11key object (kp.sign(data)), which then returns the hardware-generated signature bytes.
This integration allows Dart applications to leverage the hardware-level security of your PKCS11 device for creating legally compliant and verifiable XML signatures.
💡 XML Signature Example
This pseudo-code demonstrates how to connect the signing capability of a
Dpkcs11 key with a dedicated XML signature library like xml_crypto.
import 'package:dpkcs11/dpkcs11.dart';
import 'package:xml_crypto/xml_crypto.dart'; // Assume this is the XML signing library
// 1. Define the Dpkcs11 Signing Handler class
// This class acts as the bridge for xml_crypto
class MyPKCS11Signer implements SignatureAlgorithm {
final String algorithmUri;
final PKCS11Keypair pkcs11Keypair;
MyPKCS11Signer({required pkcs11Keypair, required this.algorithmUri});
@override
String get algorithmName => algorithmUri;
@override
String getSignature(String xml,Uint8List signingKey, [CalculateSignatureCallback? callback]) {
return base64.encode(pkcs11Keypair.sign(xml));
}
}
// 3. Integrate the Handler with xml_crypto (Conceptual)
void performXmlSignature() {
String xml = '<Document id="data">...</Document>';
String signAlgo = "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384"; //ecdsa-sha384
var config = {
"signatureAlgorithm": signAlgo,
"canonicalizationAlgorithm": "http://www.w3.org/2001/10/xml-exc-c14n#", // exclusive
"idAttribute": ["Id", "id"],
};
// 2. Dpkcs11 Initialization and Key Retrieval
// ... (Initialization, Session opening, Login, etc.) ...
// get pkcs11Keypair from session.
//bind PKCS11Signer HERE
SignedXml.signatureAlgorithms[signAlgo] = MyPKCS11Signer(pkcs11Keypair: kp ,algorithmUri: signAlgo);
final sig = SignedXml("",config)
..addReference(/*...*/)
..addReference(/*...*/)
..signingKey = Uint8List(0) // just pass an empty list
..computeSignature(xml.trim());
return sig.signedXml;
}
// ... (Logout, Close Session, Close Dpkcs11, etc. in finally blocks) ...
Contributing
Contributions are welcome! Please check the issue tracker for open tasks or submit a pull request with your improvements.
License
This library is distributed under the BSD 3-Clause License. See the LICENSE file for more information.