Signum Kotlin Multiplatform Library

repository·main·Indexed 41 days ago

https://github.com/a-sit-plus/signum

A Kotlin Multiplatform (KMP) library for Cryptography, PKI, and ASN.1 parsing/encoding targeting JVM, Android, and iOS. It provides hardware-backed security leveraging Android KeyStore and iOS Secure Enclave, supporting ECDSA, RSA, AES, HMAC, and KDFs. The library includes a type-safe ASN.1 engine and support for JOSE (JWT, JWK) and COSE (CWT) formats via modules such as indispensable, indispensable-asn1, indispensable-josef, indispensable-cosef, and supreme.

Tokens
28.1K
Snippets
71
Records
110
Agent score
52%

What's inside Signum

  1. Overview of Signum capabilities

    main

    Signum is a Kotlin Multiplatform (KMP) library designed for cryptography and Public Key Infrastructure (PKI) applications. It provides platform-independent data types while leveraging platform-native functionality for security-critical operations.

    Key Features:

    • Platform-Native Crypto: ECDSA and RSA signing/verification, ECDH key agreement, and AES/HMAC. It supports hardware-backed crypto (Android KeyStore / iOS Secure Enclave) via the Supreme module.
    • KDF Support: PBKDF2, HKDF, and scrypt using platform-native hashing.
    • PKI & ASN.1: X.509 Certificate management, Certificate Signing Requests (CSR), and a powerful, type-safe ASN.1 DSL for parsing and encoding arbitrary structures.
    • Data Formats: Support for JOSE (JWT, JWK, JWS, JWE, JCT) and COSE (CWT, COSE Keys) via specialized add-on modules.
    • Utilities: 100% pure Kotlin BitSet and Multibase encoding/decoding (Base16, Base32, Base64).
  2. Overview of Indispensable ASN.1 Engine

    main

    Indispensable ASN.1 is a Kotlin Multiplatform (KMP) library designed for parsing and encoding ASN.1 structures. It is built to be highly portable, depending only on kotlinx-* libraries and KmmResult for smooth iOS interop.

    Key features include:

    • ASN.1 Parser and Encoder: Includes a DSL for generating ASN.1 structures.
    • ObjectIdentifier: Supports human-readable notation (e.g., 1.2.9.6245.3.72.13.4.7.6).
    • ASN.1 Integer: Supports variable-length integers.
    • BitSet: A 100% pure Kotlin implementation.
    • Generic Abstractions: Allows operating on and creating arbitrary ASN.1 data.

    Platform Support: Supports all KMP targets except wasm/WASI (due to Kotest limitations).

  3. Overview of Signum Kotlin Multiplatform Library

    main

    Signum is a Kotlin Multiplatform (KMP) library designed for Cryptography, Public Key Infrastructure (PKI), and ASN.1 parsing/encoding. It targets the JVM, Android, and iOS, leveraging platform-native crypto hardware (like Android KeyStore and iOS Secure Enclave) where available.

    Key Capabilities:

    • Crypto/PKI: ECDSA and RSA signing/verification, ECDH key agreement, AES, HMAC, RSA encryption, and KDFs (PBKDF2, HKDF, scrypt).
    • Hardware-Backed Security: Supports hardware-backed crypto and platform-native attestation on Android and iOS.
    • ASN.1 Engine: A sophisticated parser and encoder with a type-safe DSL for creating arbitrary ASN.1 structures across all supported platforms.
    • Data Structures: Includes X.509 certificates, Certificate Signing Requests (CSR), ObjectIdentifiers, and support for JOSE (JWT, JWK, etc.) and COSE (CWT, etc.) formats.
    • Utilities: Includes a pure Kotlin BitSet and Multibase encoding/decoding (Base16, Base32, Base64).
  4. Understand the limitations of Signum

    main

    When using Signum for cryptographic and ASN.1 operations, be aware of the following constraints:

    • ASN.1 Encoding: Only DER encoding and parsing of ASN.1 structures are supported.
    • X509Certificate Abstractions: High-level abstractions like X509Certificate may exhibit leniency or strictness that differs from some specifications. For example, DSA-signed certificates will not parse into an X509Certificate instance. However, certificates violating the spec by containing duplicate extensions may still parse successfully.
    • Revocation Checks: The library does not provide built-in OCSP or CRL checks, although the data required for these checks can be parsed from certificates.
    • Algorithm Support: Supported algorithms are limited to standard cryptographic primitives; specialized curves (e.g., Bernstein curves) are not currently supported.
  5. Core concepts of indispensable-cosef

    main

    The indispensable-cosef library provides platform-independent COSE (CBOR Object Signing and Encryption) data types and utility functions. It is designed to interoperate with Indispensable data classes such as SignatureAlgorithm, CryptoSignature, and CryptoPublicKey.

    Key features include:

    • Predefined JOSE algorithm identifiers.
    • Guaranteed correct serialization using kotlinx.serialization.
    • Specialized classes like CborWebToken that include built-in serialize() and deserialize() functions.
    • A preconfigured serializer named coseCompliantSerializer that ensures compliant serialization of all COSE-related data structures.
  6. Compare Signum with cryptography-kotlin

    main

    Signum is a Kotlin Multiplatform (KMP) library designed for developers who prioritize tight platform integration, hardware-backed security, and comprehensive support for cryptographic data structures.

    Key Differentiators

    • Hardware-Backed Crypto & Attestation: Signum supports hardware-backed storage and in-hardware execution of cryptographic operations on Android and iOS. This ensures that hardware-backed private keys never leave the hardware crypto modules.
    • Data Structure Support: Signum provides a fully-featured ASN.1 engine, along with comprehensive support for COSE and JOSE data structures based on kotlinx-serialization.
    • Platform Interop: Signum allows for easy conversion between its data structures and platform-native types (e.g., converting a Json Web Key to a JCA key on JVM/Android or a SecKeyRef on iOS).
    • Target Platforms: Signum's Supreme KMP provider is optimized for JVM, Android, and iOS.

    Feature Comparison

    FeatureSignumcryptography-kotlin
    Digital Signatures✔ (ECDSA, RSA)✔ (ECDSA, RSA)
    Symmetric Encryption✔ (AES + ChaChaPoly)✔ (AES)
    Asymmetric Encryption✔ (RSA)✔ (RSA)
    Digest✔ (SHA-1, SHA-2)✔ (MD5, SHA-1, SHA-2)
    MAC✔ (HMAC)✔ (HMAC)
    Key Agreement✔ (ECDH)✔ (ECDH)
    KDF/PRF/KSF✔ (PBKDF2, HKDF, scrypt)✔ (PBKDF2, HKDF)
    Hardware-Backed Crypto✔✗
    Attestation✔✗
    ASN.1 Engine✔✗
    COSE✔✗
    JOSE✔✗
    Provider TargetsJVM, Android, iOSAll KMP targets
  7. Understand symmetric encryption characteristics

    main

    Signum uses the concept of characteristics to enforce type safety across algorithms, keys, and SealedBox objects. These characteristics define the properties of the cryptographic primitives:

    • AuthCapability: Defines if the algorithm is authenticated.
      • Unauthenticated: Non-authenticated encryption.
      • Authenticated: AEAD algorithms.
        • Integrated: Authentication is inherent to the cipher.
        • WithDedicatedMac: Uses an encrypt-then-MAC construction (e.g., AES-CBC-HMAC).
    • NonceTrait: Defines if a nonce/IV is required.
      • Without: No nonce required.
      • Required: A nonce of a specific length is required (auto-generated by default during encryption).
    • KeyType: Defines the key structure.
      • Integrated: A single byte array used for encryption (and derivation if needed).
      • WithDedicatedMac: Consists of a separate encryption key and a dedicated MAC key.
  8. How ASN.1 elements are structured

    main

    Parsed Asn1Elements are categorized into two types:

    Primitives (Asn1Primitive)

    These have a tag and a value. Common convenience wrappers include:

    • Asn1BitString
    • Asn1PrimitiveOctetString

    Structures (Asn1Structure)

    These contain child nodes. Common types include:

    • Asn1Sequence and Asn1SequenceOf
    • Asn1Set and Asn1SetOf (children are sorted by default)
    • Asn1EncapsulatingOctetString (contains a valid ASN.1 structure or primitive)
    • Asn1ExplicitlyTagged (user-specified tag + CONTEXT_SPECIFIC + CONSTRUCTED)
    • Asn1CustomStructure (any other CONSTRUCTED tag)

    You can use convenience wrappers like .asSequence() to cast to a subtype, which throws an Asn1Exception if the cast is invalid.

  9. Use Ephemeral Keys and Signers

    main

    Ephemeral keys and signers are not backed by a persistent provider and are not persisted. They are delegated to platform functionality but work consistently across all platforms.

    There are two ways to use them:

    1. Directly via Signer.Ephemeral{}: Pass EC or RSA-specific configuration options directly.
    2. Via EphemeralKey{}: Create an ephemeral key first, then call .getSigner{} on it. When calling .getSigner{}, you can pass algorithm-specific configuration options (like hash algorithms or padding) if multiple options were specified during key creation.
    // Option 1: Direct ephemeral signer
    val signer = Signer.Ephemeral(ecConfig)
    
    // Option 2: Via EphemeralKey
    val ephemeralKey = EphemeralKey(ecConfig)
    val signer = ephemeralKey.getSigner(hashConfig)
  10. Use Kotlin contracts to narrow cryptographic types

    main

    The Supreme KMP provider uses Kotlin contracts to allow the compiler to smart-cast objects based on their cryptographic properties. You can combine these to steadily narrow down what an object is capable of:

    • isAuthenticated(): Smart-casts AuthCapability to Authenticated<*> or Unauthenticated.
    • hasDedicatedMac(): Smart-casts KeyType to WithDedicatedMac and AuthCapability to Authenticated.WithDedicatedMac (or handles the Unauthenticated/Integrated union).
    • requiresNonce(): Smart-casts NonceTrait to Nonce.Required or Nonce.Without.
    • isIntegrated(): (Only for Authenticated.Integrated objects) Smart-casts AuthCapability and KeyType to their integrated variants.
    • isBlockCipher() / isStreamCipher(): Smart-casts the algorithm to BlockCipher or StreamCipher respectively.
  11. How ASN.1 encoding and decoding works

    main

    The ASN.1 engine uses a two-tier pattern for encoding and decoding.

    High-level types (like X509Certificate or CryptoPublicKey) implement Asn1Encodable and their companions implement Asn1Decodable. These types provide enriched semantics for complex structures.

    Low-level elements (like Asn1Element, Asn1Primitive, and Asn1Structure) operate on the raw TLV (Tag-Length-Value) structures.

    A typical pipeline follows this flow:

    1. Encoded Bytes $\rightarrow$ Asn1Element.parse() $\rightarrow$ ASN.1 Element (Low-level)
    2. ASN.1 Element $\rightarrow$ decodeFromTlv() $\rightarrow$ Rich Type (High-level, e.g., ObjectIdentifier)

    For encoding, the flow is reversed:

    1. Rich Type $\rightarrow$ encodeToTlv() $\rightarrow$ ASN.1 Element
    2. ASN.1 Element $\rightarrow$ derEncoded $\rightarrow$ Encoded Bytes
  12. How Supreme's Provider and Signer model works

    main

    Unlike the Java Cryptography Architecture (JCA), Supreme uses a Provider to manage private key material and create Signer instances.

    • Provider: Manages signing keys and creates signers.
    • Signer: An object used to perform signing operations with a private key.
    • Verifier: Instantiated on a SignatureAlgorithm and takes a CryptoPublicKey as a parameter to verify signatures.
    • Ephemeral Keys: Creating temporary keys is a dedicated operation decoupled from a Provider.

    Important: Supreme relies heavily on KmmResult to communicate success or failure. Do not ignore the results returned by any operation, as the library is designed to never throw exceptions.