Document Signing
EidKit uses the nonRepudiation key on the Romanian CEI chip to produce a qualified ECDSA-SHA384 signature over a document hash. This enables PAdES/eIDAS-compatible PDF signing.
How it works
- Your app computes a SHA-384 hash of the document byte range to be signed
- The user taps the card and enters their 6-digit signing PIN
- The chip signs the hash using the nonRepudiation key (key ref
0x8Ein the GenPKI applet) - EidKit returns the raw 96-byte
r||sECDSA signature and the DER X.509 certificate
Sign a document
- Android (Kotlin)
- iOS (Swift)
// 1. Compute the SHA-384 hash of your document content
val hash = MessageDigest.getInstance("SHA-384").digest(documentBytes)
// hash.size == 48
// 2. Execute the signing session
val result = EidKit.signer(can = userEnteredCan)
.sign(hash, signingPin = userEnteredSigningPin)
.execute(isoDep)
// result.signature — 96-byte raw ECDSA-SHA384 r||s
// result.certificate — DER-encoded X.509 CE8E certificate
import CryptoKit
// 1. Compute the SHA-384 hash of your document content
let hash = Data(SHA384.hash(data: documentBytes))
// hash.count == 48
// 2. Execute the signing session
let result = try await EidKit.signer(can: userEnteredCan)
.sign(hash: hash, signingPin: userEnteredSigningPin)
.execute()
// result.signature — 96-byte raw ECDSA-SHA384 r||s
// result.certificate — DER-encoded X.509 CE8E certificate
Embedding the signature in a PDF
SignResult.signature is a raw r||s value. To embed it in a PDF (PAdES/eIDAS), it must be wrapped in a CMS/PKCS#7 SignedData structure together with the certificate.
Options:
- EidKit signing service — set
EidKitConfig.signingServiceUrlto delegate CMS wrapping, timestamping, and LTV to the EidKit backend (or your own on-premise instance) - DIY — use Apache PDFBox (Android) or PDFKit/BouncyCastle to build the CMS structure yourself from
result.signatureandresult.certificate
Progress events
- Android (Kotlin)
- iOS (Swift)
EidKit.signer(can = userEnteredCan)
.sign(hash, signingPin = userEnteredSigningPin)
.executeFlow(isoDep)
.collect { event ->
when (event) {
is SignEvent.PaceEstablished -> showStep("Secure channel opened")
is SignEvent.PinVerified -> showStep("PIN accepted")
is SignEvent.Done -> showResult(event.result)
}
}
let result = try await EidKit.signer(can: userEnteredCan)
.sign(hash: hash, signingPin: userEnteredSigningPin)
.execute { event in
switch event {
case .paceEstablished: showStep("Secure channel opened")
case .pinVerified: showStep("PIN accepted")
}
}
Signing PIN
The signing PIN is 6 digits — different from the 4-digit authentication PIN used for KYC. The Romanian CEI allows only 3 incorrect signing PIN attempts before the signing key is permanently blocked.