
Indispensable Core Data Structures and Functions for Cryptographic Material
This Kotlin Multiplatform library provides platform-independent data types and functionality related to crypto and PKI applications:
- EC Math
- EC Point Class
- EC Curve Class
- Mathematical operations
- Bit Length
- Point Compression
- Public Keys (RSA and EC)
- Private Keys (RSA and EC)
- KDF definitions for HKDF, PBKDF2, and scrypt
- Algorithm Identifiers (Signatures, Hashing)
- X509 Certificate Class (create, encode, decode)
- Extensions
- Alternative Names
- Distinguished Names
- Certification Request (CSR)
- CSR Attributes
- Exposes Multibase Encoder/Decoder as an API dependency including Matthew Nelson's smashing Base16, Base32, and Base64 encoders
In effect, you can work with X509 Certificates, public keys, CSRs and arbitrary ASN.1 structures on all KMP targets except watchosDeviceArm64!
Tip
Do check out the full API docs here!
Using it in your Projects
This library was built for Kotlin Multiplatform. Currently, it targets the JVM, Android and iOS.
Simply declare the desired dependency to get going:
Structure and Class Overview
As the name Indispensable implies, this is the base module for all KMP crypto operations. It includes types, abstractions, and functionality considered absolutely essential to even entertain the thought of working with and on cryptographic data.
Package Organisation
Fundamental Cryptographic Data Structures
The main package housing all data classes is at.asitplus.signum.indispensable.
It contains essentials such as:
CryptoPublicKeyrepresenting a public key. Currently, we support RSA and EC public keys on NIST curves.CryptoPrivateKeyrepresenting a private key. Currently, we support RSA (CryptoPrivateKey.RSA) and EC (CryptoPrivateKey.EC) private keys on NIST curves. RSA keys always include the public key, EC keys may or may not contain a public key and/or curve.- Has an additional specialization
CryptoPrivateKey.WithPublicKeythat always includes a public key - Encodes to PKCS#8 by default
- RSA keys also support PKCS#1 encoding (
.asPKCS1) - EC keys also support SEC1 encoding (
.asSEC1)
- Has an additional specialization
Digestcontaining an enumeration of supported digestsECCurverepresenting an EC CurveECPointrepresenting a point on an elliptic curveCryptoSignatrerepresenting a cryptographic signature including descriptive information regarding the algorithms and signature dataSignatureAlgorithmcontaining an enumeration of supported signature algorithmsX509SignatureAlgorithmenumeration of supported X.509 signature algorithms (maps to and fromSignatureAlgorithm)
Attestationrepresenting a container to convey attestation statementsAndroidKeystoreAttestationcontains the certificate chain from Google's root certificate down to the attested keyIosHomebrewAttestationcontains the new iOS attestation format introduces in Supreme 0.2.0 (see the Attestation section of the Supreme manual for details).SelfAttestationis used on the JVM. It has no specific semantics, but could be used, if an attestation-supporting HSM is used on the JVM. WIP!
KeyAgreementPrivateValuedenotes what the name implies. Currently, only ECDH is implemented, hence, there is a single subinterfaceKeyAgreementPrivateValue.ECDH, which is implemented byCryptoPrivateKey.ECKeyAgreementPublicValuedenotes what the name implies. Currently, only ECDH is implemented, hence, there is a single subinterfaceKeyAgreementPublicValue.ECDH, which is implemented byCryptoPublicKey.ECMACdefines the interface for message authentication codesHMACdefines HMAC for all supportedDigestalgorithms. The Supreme KMP crypto provider implements the actual HMAC functionality.
KDFdefines the interface for key derivation functionsHKDFdefines the configuration of an HKDF key derivation function. The Supreme KMP crypto provider implements the actual derivation functionality.PBKDF2defines the configuration of an PBKDF2 key derivation function. The Supreme KMP crypto provider implements the actual derivation functionality.SCryptdefines the configuration of an scrypt key derivation function. The Supreme KMP crypto provider implements the actual derivation functionality.
SymmetricEncryptionAlgorithmrepresents symmetric encryption algorithms. Indispensable currently ships with definitions for AES-CBC, a flexible AES-CBC-HMAC, and AES-GCM, while the Supreme KMP crypto provider implements the actual AES functionality.BlockCipherdenotes a BlockCipherWithIVdenotes a Cipher requiring an initialization vectorUnauthenticateddenotes a non-authenticated encryption algorithmAuthenticateddenotes an authenticated encryption algorithmAuthenticated.WithDedicatedMacdescribes an encryption authenticated encryption algorithm based on a non-authenticated one and a dedicatedMAC, to achieve authenticated encryption
Ciphertextstores ciphertext produced by a symmetric cipher. It has dedicated accessors for every component of the ciphertext, such asivandencryptedDataUnauthenticateddenotes a ciphertext produced by aSymmetricEncryptionAlgorithm.UnauthenticatedAuthenticateddenotes a ciphertext produced by aSymmetricEncryptionAlgorithm.Authenticated, it also contains anauthTagand,aadAuthenticated.WithDedicatedMacrestrictsCiphertext.Authenticatedto ciphertexts produced by aSymmetricEncryptionAlgorithm.Authenticated.WithDedicatedMac
PKI-Related Data Structures
The pki package contains data classes relevant in the PKI context:
X509Certificatedoes what you think it doesX509CertificateExtensioncontains a convenience abstraction of X.509 certificate extensionsAlternativeNamescontains definitions of subject/issuer alternative namesRelativeDistinguishedNamecontains definitions of RDNs (Common Name, City, …)
Pkcs10CertificateRequestcontains a CSR abstractionPcs10CertificateRequestAttributescontains a CSR attribute extension
Conversion from/to Platform Types
Obviously, a world outside this library's data structures exists. The following functions provide interop functionality with platform types.
JVM/Android
SignatureAlgorithm.getJCASignatureInstance()gets a pre-configured JCA instance for this algorithmSpecializedSignatureAlgorithm.getJCASignatureInstance()gets a pre-configured JCA instance for this algorithmSignatureAlgorithm.getJCASignatureInstancePreHashed()gets a pre-configured JCA instance for pre-hashed data for this algorithmSpecializedSignatureAlgorithm.getJCASignatureInstancePreHashed()gets a pre-configured JCA instance for pre-hashed data for this algorithm
Digest.jcaPSSParamsreturns a sane defaultPSSParameterSpecfor computing PSS signaturesDigest.jcaNamereturns the JCA name of the digestDigest?.jcaAlgorithmComponentdigest part of the digest part of thewith JCA algorithm identifier (which differs fom the above)
ECCurve.jcaNamereturns the curve's name used by JCAECCurve.byJcaName()returns the curve matching the provided JCA curve nameECCurve.iosEncodedPublicKeyLengthreturns the number of bytes of a public key matching this curve, when exporting such a key from iOS.ECCurve.iosEncodedPrivateKeyLengthreturns the number of bytes of a private key matching this curve, when exporting such a key from iOS.ECCurve.fromIosEncodedPublicKeyLengthreturns the curve matching the length of an encoded public key, when exported from iOS. (Apple does not encode curve identifiers, when exporting keys.)ECCurve.fromIosEncodedPrivateKeyLengthreturns the curve matching the length of an encoded private key, when exported from iOS. (Apple does not encode curve identifiers, when exporting keys.)
CryptoPublicKey.toJcaPublicKey()returns the JCA-representation of the public keyCryptoPublicKey.EC.toJcaPublicKey()returns the JCA-representation of the public key (convenience helper)CryptoPublicKey.RSA.toJcaPublicKey()returns the JCA-representation of the public key (convenience helper)PublicKey.toCryptoPublicKey()creates aCryptoPublicKeyfrom a JCA Public KeyECPublicKey.toCryptoPublicKey()creates aCryptoPublicKey.ECfrom a JCA EC Public KeyRSAPublicKey.toCryptoPublicKey()creates aCryptoPublicKey.RSAfrom a JCA RSA Public Key
CryptoPrivateKey.WihtPublicKey<*>.toJcaPublicKey()returns the JCA-representation of the private keyCryptoPrivateKey.EC.WithPublicKey.toJcaPublicKey()returns the JCA-representation of the private key (convenience helper)CryptoPrivateKey.RSA.toJcaPublicKey()returns the JCA-representation of the private key (convenience helper)PrivateKey.toCryptoPrivateKey()creates aCryptoPrivateKey.WithPublicKey<*>from a JCA Public KeyECPrivateKey.toCryptoPrivateKey()creates aCryptoPrivateKey.EC.WithPublicKeyfrom a JCA EC Public KeyRSAPrivateKey.toCryptoPrivateKey()creates aCryptoPrivateKey.RSAfrom a JCA RSA Public Key
CryptoSignature.jcaSignatureBytesreturns the JCA-native encoded representation of a signatureCryptoSignature.parseFromJca()returns a signature object form a JCA-native encoded representation of a signatureCryptoSignature.EC.parseFromJca()returns an EC signature object form a JCA-native encoded representation of a signatureCryptoSignature.RSA.parseFromJca()returns an RSA signature object form a JCA-native encoded representation of a signatureCryptoSignature.EC.parseFromJcaP1363parses a signature produced by the JCA digestWithECDSAinP1363Format algorithm.X509Certificate.toJcaCertificate()converts the certificate to a JCA-nativeX509Certificatejava.security.cert.X509Certificate.toKmpCertificate()converts a JCA-native certificate to a SignumX509Certificate
iOS
CryptoPublicKey.iosEncodedencodes a public key as iOS doesCryptoPublicKey.fromIosEncoded()decodes a public key that was encoded in iOS
CryptoPrivateKey.toSecKey()produces aSecKeyusable on iOSCryptoPrivateKey.fromIosEncoded()decodes a private key as it is exported from iOS
SignatureAlgorithm.secKeyAlgorithmreturns an algorithm identifier constant usable with CommonCryptoSpecializedSignatureAlgorithm.secKeyAlgorithmreturns an algorithm identifier constant usable with CommonCryptoSpecializedSignatureAlgorithm.secKeyAlgorithmreturns an algorithm identifier constant usable with CommonCryptoSignatureAlgorithm.secKeyAlgorithmPreHashedreturns an algorithm identifier constant usable with CommonCrypto (for pre-hashed data)-
SpecializedSignatureAlgorithm.secKeyAlgorithmPreHashedreturns an algorithm identifier constant usable with CommonCrypto (for pre-hashed data) -
CryptoSignature.iosEncodedencodes a signature object as iOS would natively do
ASN.1 Engine Addons
Relevant classes like CryptoPublicKey, CryptoPrivateKey, X509Certificate, Pkcs10CertificationRequest, etc. all
implement Asn1Encodable and their respective companions implement Asn1Decodable.
This is an essential pattern, making the ASN.1 engine work the way it does.
We have opted against using kotlinx.serialization for maximum flexibility and more convenient debugging.
The following section provides more details on the various patterns used for ASN.1 encoding and decoding.
Generic Patterns
As mentioned before, classes like CryptoPublicKey, X509Certificate, and ObjectIdentifier all implement Asn1Encodable
while their companions implement Asn1Decodable.
These interfaces essentially provide a mapping between custom types and low-level TLV structures that can directly be encoded, conforming to DER.
In addition, CryptoPublicKey, CryptoPrivateKey, X509Certificate, Pkcs10CertificationRequest also implement PemEncodable,
while their respective companions implement PemDecodable.
This brings about the encodeToPem and decodeFromPem functions doing what their names imply:
Encode/decode to/from PEM strings.
Low-Level Addons
This module provides the following low-level addons for Kotlin MP BigNum:
Asn1Primitive.decodeToBigInteger()throws on errorAsn1Primitive.decodeToBigIntegerOrNull()returnsnullon errorBigInteger.decodeFromAsn1ContentBytes()encodeToAsn1Primitive()produces an ASN.1 primitiveBigIntegerencodeToAsn1ContentBytes()producing the content bytes of anAsn1PrimitiveforBigInteger
Notes on Object Identifiers
Signum also ships with a indispensable-oids module, included by default, which adds extension properties to KnownOIDs for all ASN.1 object identifiers from Peter Guttmann's
dumpasn1.cfg.
Hence, handy constants such as KnownOIDs.ecdsaWithSHA256 are available, but also rather obscure ones such as
KnownOIDs.asAdjacencyAttest. To also describe these properties, call the KnownOIDs.describeAll() extension once.
While it is convenient to have virtually the whole world's OIDs available as constants, including descriptions,, this will add a couple of megabytes to klibs and any XCode frameworks. Thus, it may make sense to exclude indispensable-oids from your framework export.