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)
- 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 the JVM, Android, and iOS.
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:
CryptoPublicKey
representing a public key. Currently, we support RSA and EC public keys on NIST curves.CryptoPrivateKey
representing a private key. Currently, we support RSA and 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.WithPublicKey
that 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
Digest
containing an enumeration of supported digestsECCurve
representing an EC CurveECPoint
representing a point on an elliptic curveCryptoSignatre
representing a cryptographic signature including descriptive information regarding the algorithms and signature dataSignatureAlgorithm
containing an enumeration of supported signature algorithmsX509SignatureAlgorithm
enumeration of supported X.509 signature algorithms (maps to and fromSignatureAlgorithm
)
Attestation
representing a container to convey attestation statementsAndroidKeystoreAttestation
contains the certificate chain from Google's root certificate down to the attested keyIosHomebrewAttestation
contains the new iOS attestation format introduces in Supreme 0.2.0 (see the Attestation section of the Supreme manual for details).SelfAttestation
is used on the JVM. It has no specific semantics, but could be used, if an attestation-supporting HSM is used on the JVM. WIP!
PKI-Related data Structures
The pki
package contains data classes relevant in the PKI context:
X509Certificate
does what you think it doesX509CertificateExtension
contains a convenience abstraction of X.509 certificate extensionsAlternativeNames
contains definitions of subject/issuer alternative namesRelativeDistinguishedName
contains definitions of RDNs (Common Name, City, …)
Pkcs10CertificateRequest
contains a CSR abstractionPcs10CertificateRequestAttributes
contains 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.jcaPSSParams
returns a sane defaultPSSParameterSpec
for computing PSS signaturesDigest.jcaName
returns the JCA name of the digestDigest?.jcaAlgorithmComponent
digest part of the digest part of thewith JCA algorithm identifier (which differs fom the above)
ECCurve.jcaName
returns the curve's name used by JCAECCurve.byJcaName()
returns the curve matching the provided JCA curve nameECCurve.iosEncodedPublicKeyLength
returns the number of bytes of a public key matching this curve, when exporting such a key from iOS.ECCurve.iosEncodedPrivateKeyLength
returns the number of bytes of a private key matching this curve, when exporting such a key from iOS.ECCurve.fromIosEncodedPublicKeyLength
returns the curve matching the length of an encoded public key, when exported from iOS. (Apple does not encode curve identifiers, when exporting keys.)ECCurve.fromIosEncodedPrivateKeyLength
returns 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 aCryptoPublicKey
from a JCA Public KeyECPublicKey.toCryptoPublicKey()
creates aCryptoPublicKey.EC
from a JCA EC Public KeyRSAPublicKey.toCryptoPublicKey()
creates aCryptoPublicKey.RSA
from 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.WithPublicKey
from a JCA EC Public KeyRSAPrivateKey.toCryptoPrivateKey()
creates aCryptoPrivateKey.RSA
from a JCA RSA Public Key
CryptoSignature.jcaSignatureBytes
returns 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.RSAorHMAC.parseFromJca()
returns an RSA signature object form a JCA-native encoded representation of a signatureCryptoSignature.EC.parseFromJcaP1363
parses a signature produced by the JCA digestWithECDSAinP1363Format algorithm.X509Certificate.toJcaCertificate()
converts the certificate to a JCA-nativeX509Certificate
java.security.cert.X509Certificate.toKmpCertificate()
converts a JCA-native certificate to a SignumX509Certificate
iOS
CryptoPublicKey.iosEncoded
encodes a public key as iOS doesCryptoPublicKey.fromIosEncoded()
decodes a public key that was encoded in iOS
CryptoPrivateKey.toSecKey()
produces aSecKey
usable on iOSCryptoPrivateKey.fromIosEncoded()
decodes a private key as it is exported from iOS
SignatureAlgorithm.secKeyAlgorithm
returns an algorithm identifier constant usable with CommonCryptoSpecializedSignatureAlgorithm.secKeyAlgorithm
returns an algorithm identifier constant usable with CommonCryptoSpecializedSignatureAlgorithm.secKeyAlgorithm
returns an algorithm identifier constant usable with CommonCryptoSignatureAlgorithm.secKeyAlgorithmPreHashed
returns an algorithm identifier constant usable with CommonCrypto (for pre-hashed data)-
SpecializedSignatureAlgorithm.secKeyAlgorithmPreHashed
returns an algorithm identifier constant usable with CommonCrypto (for pre-hashed data) -
CryptoSignature.iosEncoded
encodes 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.
This also means, a direct serialization of such custom types is valuable for debugging, but not for encoding.
Hence, decoding a kotlinx.serialization output of those classes is unsupported.
Low-Level Addons
This module provides the following low-level addons for Kotlin MP BigNum:
Asn1Primitive.decodeToBigInteger()
throws on errorAsn1Primitive.decodeToBigIntegerOrNull()
returnsnull
on errorBigInteger.decodeFromAsn1ContentBytes()
encodeToAsn1Primitive()
produces an ASN.1 primitiveBigInteger
encodeToAsn1ContentBytes()
producing the content bytes of anAsn1Primitive
forBigInteger