├── .github
├── actions
│ ├── run-android-emulator-tests
│ │ └── action.yml
│ └── setup-environment
│ │ └── action.yml
└── workflows
│ ├── ci-branch.yml
│ ├── ci-kotlin-eap.yml
│ ├── ci-main.yml
│ ├── ci-pr.yml
│ ├── ci-release.yml
│ ├── deploy-website.yml
│ ├── publish-local.yml
│ ├── publish-release.yml
│ ├── publish-snapshot.yml
│ ├── publish-website.yml
│ ├── run-build-project.yml
│ ├── run-build-website.yml
│ ├── run-checks.yml
│ ├── run-slow-tasks.yml
│ ├── run-tests-compatibility.yml
│ └── run-tests-default.yml
├── .gitignore
├── .idea
├── codeStyles
│ ├── Project.xml
│ └── codeStyleConfig.xml
├── copyright
│ ├── Apache_2_0.xml
│ └── profiles_settings.xml
└── vcs.xml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── build-logic
├── build.gradle.kts
├── settings.gradle.kts
└── src
│ └── main
│ └── kotlin
│ ├── ckbuild.documentation.gradle.kts
│ ├── ckbuild.multiplatform-android.gradle.kts
│ ├── ckbuild.multiplatform-base.gradle.kts
│ ├── ckbuild.multiplatform-library.gradle.kts
│ ├── ckbuild.multiplatform-provider-tests.gradle.kts
│ ├── ckbuild.publication.gradle.kts
│ ├── ckbuild.use-openssl.gradle.kts
│ └── ckbuild
│ ├── OptIns.kt
│ ├── artifacts.kt
│ ├── documentation
│ └── DocumentationExtension.kt
│ ├── native.kt
│ ├── openssl
│ ├── OpensslExtension.kt
│ └── UnzipTask.kt
│ ├── targets.kt
│ └── tests
│ ├── GenerateProviderTestsTask.kt
│ ├── ProviderTestsExtension.kt
│ ├── TestAggregation.kt
│ └── TestFilters.kt
├── build-settings
├── build.gradle.kts
├── settings.gradle.kts
└── src
│ └── main
│ └── kotlin
│ ├── cksettings.default.settings.gradle.kts
│ ├── cksettings.gradle.settings.gradle.kts
│ ├── cksettings.kotlin-version-override.settings.gradle.kts
│ ├── cksettings.repositories.settings.gradle.kts
│ └── cksettings
│ └── ProjectsScope.kt
├── build.gradle.kts
├── cryptography-bigint
├── README.md
├── api
│ ├── cryptography-bigint.api
│ └── cryptography-bigint.klib.api
├── build.gradle.kts
└── src
│ ├── commonMain
│ └── kotlin
│ │ ├── BigInt.kt
│ │ ├── BigIntSerializers.kt
│ │ └── hex.kt
│ ├── commonTest
│ └── kotlin
│ │ ├── BigIntArrayTest.kt
│ │ ├── BigIntCompareTest.kt
│ │ ├── BigIntHexTest.kt
│ │ ├── BigIntPrimitiveTest.kt
│ │ ├── BigIntStringTest.kt
│ │ └── checks.kt
│ ├── jsAndWasmJsMain
│ └── kotlin
│ │ ├── BigInt.jsAndWasmJs.kt
│ │ └── JsBigInt.kt
│ ├── jsMain
│ └── kotlin
│ │ └── JsBigInt.js.kt
│ ├── jvmMain
│ └── kotlin
│ │ └── BigInt.jvm.kt
│ ├── nativeAndWasmWasiMain
│ └── kotlin
│ │ └── BigInt.nativeAndWasmWasi.kt
│ └── wasmJsMain
│ └── kotlin
│ └── JsBigInt.wasmJs.kt
├── cryptography-bom
└── build.gradle.kts
├── cryptography-core
├── README.md
├── api
│ ├── cryptography-core.api
│ └── cryptography-core.klib.api
├── build.gradle.kts
└── src
│ ├── commonMain
│ └── kotlin
│ │ ├── BinarySize.kt
│ │ ├── CryptographyAlgorithm.kt
│ │ ├── CryptographyAlgorithmNotFoundException.kt
│ │ ├── CryptographyException.kt
│ │ ├── CryptographyProvider.kt
│ │ ├── CryptographyProviderApi.kt
│ │ ├── DelicateCryptographyApi.kt
│ │ ├── algorithms
│ │ ├── AES.kt
│ │ ├── Digest.kt
│ │ ├── EC.kt
│ │ ├── ECDH.kt
│ │ ├── ECDSA.kt
│ │ ├── HKDF.kt
│ │ ├── HMAC.kt
│ │ ├── PBKDF2.kt
│ │ ├── RSA.kt
│ │ ├── asymmetric
│ │ │ └── deprecated.kt
│ │ ├── digest
│ │ │ └── deprecated.kt
│ │ └── symmetric
│ │ │ ├── SymmetricKeySize.kt
│ │ │ └── deprecated.kt
│ │ ├── materials
│ │ └── key
│ │ │ ├── EncodableKey.kt
│ │ │ ├── Key.kt
│ │ │ ├── KeyDecoder.kt
│ │ │ ├── KeyFormat.kt
│ │ │ └── KeyGenerator.kt
│ │ ├── operations
│ │ ├── AuthenticatedCipher.kt
│ │ ├── Cipher.kt
│ │ ├── Hash.kt
│ │ ├── SecretDerivation.kt
│ │ ├── SharedSecretGenerator.kt
│ │ ├── Signature.kt
│ │ ├── UpdateFunction.kt
│ │ ├── cipher
│ │ │ └── deprecated.kt
│ │ ├── hash
│ │ │ └── deprecated.kt
│ │ └── signature
│ │ │ └── deprecated.kt
│ │ └── unsafe.kt
│ ├── jvmMain
│ └── kotlin
│ │ └── CryptographyProvider.jvm.kt
│ └── nonJvmMain
│ └── kotlin
│ └── CryptographyProvider.nonJvm.kt
├── cryptography-providers-tests-api
├── build.gradle.kts
└── src
│ ├── androidMain
│ ├── AndroidManifest.xml
│ └── kotlin
│ │ └── TestPlatform.android.kt
│ ├── commonMain
│ └── kotlin
│ │ ├── AlgorithmTest.kt
│ │ ├── ProviderTest.kt
│ │ ├── TestContext.kt
│ │ ├── TestLogger.kt
│ │ ├── TestPlatform.kt
│ │ ├── TestProvider.kt
│ │ ├── TestScope.kt
│ │ ├── compatibility
│ │ ├── ByteStringAsStringSerializer.kt
│ │ ├── CompatibilityApi.kt
│ │ ├── CompatibilityStorageApi.kt
│ │ ├── CompatibilityTest.kt
│ │ ├── CompatibilityTestScope.kt
│ │ ├── InMemoryApi.kt
│ │ ├── Models.kt
│ │ └── ServerApi.kt
│ │ ├── generators.kt
│ │ ├── support.kt
│ │ └── utils.kt
│ ├── jsMain
│ └── kotlin
│ │ ├── TestPlatform.js.kt
│ │ └── utils.js.kt
│ ├── jvmMain
│ └── kotlin
│ │ └── TestPlatform.jvm.kt
│ ├── nativeMain
│ └── kotlin
│ │ └── TestPlatform.native.kt
│ ├── nonJsMain
│ └── kotlin
│ │ └── utils.nonJs.kt
│ └── wasmJsMain
│ └── kotlin
│ └── TestPlatform.wasmJs.kt
├── cryptography-providers-tests
├── build.gradle.kts
└── src
│ └── commonMain
│ └── kotlin
│ ├── DefaultProviderTest.kt
│ ├── SupportedAlgorithmsTest.kt
│ ├── compatibility
│ ├── AesBasedCompatibilityTest.kt
│ ├── AesCbcCompatibilityTest.kt
│ ├── AesCmacCompatibilityTest.kt
│ ├── AesCtrCompatibilityTest.kt
│ ├── AesEcbCompatibilityTest.kt
│ ├── AesGcmCompatibilityTest.kt
│ ├── DigestCompatibilityTest.kt
│ ├── EcCompatibilityTest.kt
│ ├── EcdhCompatibilityTest.kt
│ ├── EcdsaCompatibilityTest.kt
│ ├── HkdfCompatibilityTest.kt
│ ├── HmacCompatibilityTest.kt
│ ├── Pbkdf2CompatibilityTest.kt
│ ├── RsaBasedCompatibilityTest.kt
│ ├── RsaOaepCompatibilityTest.kt
│ ├── RsaPkcs1CompatibilityTest.kt
│ ├── RsaPkcs1EsCompatibilityTest.kt
│ ├── RsaPssCompatibilityTest.kt
│ └── RsaRawCompatibilityTest.kt
│ ├── default
│ ├── AesBasedTest.kt
│ ├── AesCbcTest.kt
│ ├── AesCmacTest.kt
│ ├── AesCtrTest.kt
│ ├── AesGcmTest.kt
│ ├── CipherTest.kt
│ ├── DigestTest.kt
│ ├── EcdsaTest.kt
│ ├── HmacTest.kt
│ ├── RsaOaepTest.kt
│ ├── RsaPkcs1Test.kt
│ ├── RsaPssTest.kt
│ └── SignatureTest.kt
│ └── testvectors
│ ├── AesCmacTestvectorsTest.kt
│ ├── HkdfTestvectorsTest.kt
│ └── HmacTestvectorsTest.kt
├── cryptography-providers
├── apple
│ ├── README.md
│ ├── api
│ │ └── cryptography-provider-apple.klib.api
│ ├── build.gradle.kts
│ └── src
│ │ ├── commonMain
│ │ └── kotlin
│ │ │ ├── AppleCryptographyProvider.kt
│ │ │ ├── algorithms
│ │ │ ├── CCAes.kt
│ │ │ ├── CCAesCbc.kt
│ │ │ ├── CCAesCtr.kt
│ │ │ ├── CCAesEcb.kt
│ │ │ ├── CCAesIvCipher.kt
│ │ │ ├── CCDigest.kt
│ │ │ ├── CCHashAlgorithm.kt
│ │ │ ├── CCHkdf.kt
│ │ │ ├── CCHmac.kt
│ │ │ ├── CCPbkdf2.kt
│ │ │ ├── SecEcdsa.kt
│ │ │ ├── SecRsa.kt
│ │ │ ├── SecRsaOaep.kt
│ │ │ ├── SecRsaPkcs1.kt
│ │ │ ├── SecRsaPss.kt
│ │ │ └── SecRsaRaw.kt
│ │ │ └── internal
│ │ │ ├── CCCipher.kt
│ │ │ ├── SecCipherFunction.kt
│ │ │ ├── SecSignature.kt
│ │ │ ├── clozy.kt
│ │ │ ├── digest.kt
│ │ │ ├── keys.kt
│ │ │ └── utils.kt
│ │ └── commonTest
│ │ └── kotlin
│ │ └── AppleDefaultProviderTest.kt
├── base
│ ├── README.md
│ ├── api
│ │ ├── cryptography-provider-base.api
│ │ └── cryptography-provider-base.klib.api
│ ├── build.gradle.kts
│ └── src
│ │ ├── appleMain
│ │ └── kotlin
│ │ │ └── NSData.kt
│ │ ├── commonMain
│ │ └── kotlin
│ │ │ ├── algorithms
│ │ │ ├── BaseAesImplicitIvFunctions.kt
│ │ │ ├── BaseAesIvAuthenticatedCipher.kt
│ │ │ ├── BaseAesIvCipher.kt
│ │ │ ├── BaseHkdf.kt
│ │ │ └── Ec.kt
│ │ │ ├── bytes.kt
│ │ │ ├── materials
│ │ │ └── keys.kt
│ │ │ └── operations
│ │ │ ├── AccumulatingCipherFunction.kt
│ │ │ ├── BaseAuthenticatedCipher.kt
│ │ │ ├── BaseCipher.kt
│ │ │ └── BaseCipherFunction.kt
│ │ └── nativeMain
│ │ └── kotlin
│ │ └── bytes.kt
├── cryptokit
│ ├── README.md
│ ├── api
│ │ └── cryptography-provider-cryptokit.klib.api
│ ├── build.gradle.kts
│ └── src
│ │ └── commonMain
│ │ ├── kotlin
│ │ ├── CryptoKitCryptographyProvider.kt
│ │ ├── algorithms
│ │ │ ├── CryptoKitAesGcm.kt
│ │ │ ├── CryptoKitDigest.kt
│ │ │ ├── CryptoKitEcdh.kt
│ │ │ ├── CryptoKitEcdsa.kt
│ │ │ ├── CryptoKitHkdf.kt
│ │ │ └── CryptoKitHmac.kt
│ │ ├── internal
│ │ │ └── swift.kt
│ │ └── operations
│ │ │ └── HashBasedFunction.kt
│ │ └── swift
│ │ ├── SwiftAesGcm.swift
│ │ ├── SwiftEcdh.swift
│ │ ├── SwiftEcdsa.swift
│ │ ├── SwiftHash.swift
│ │ ├── SwiftHkdf.swift
│ │ └── SwiftHmac.swift
├── jdk
│ ├── README.md
│ ├── android-tests
│ │ ├── build.gradle.kts
│ │ └── src
│ │ │ └── androidInstrumentedTest
│ │ │ └── kotlin
│ │ │ └── AndroidJdkDefaultProviderTest.kt
│ ├── api
│ │ ├── cryptography-provider-jdk.api
│ │ └── cryptography-provider-jdk.klib.api
│ ├── build.gradle.kts
│ └── src
│ │ ├── jvmMain
│ │ ├── kotlin
│ │ │ ├── JTypealiases.kt
│ │ │ ├── JdkCryptographyProvider.kt
│ │ │ ├── JdkCryptographyState.kt
│ │ │ ├── algorithms
│ │ │ │ ├── JdkAesCbc.kt
│ │ │ │ ├── JdkAesCmac.kt
│ │ │ │ ├── JdkAesCtr.kt
│ │ │ │ ├── JdkAesEcb.kt
│ │ │ │ ├── JdkAesGcm.kt
│ │ │ │ ├── JdkAesIvCipher.kt
│ │ │ │ ├── JdkDigest.kt
│ │ │ │ ├── JdkEc.kt
│ │ │ │ ├── JdkEcdh.kt
│ │ │ │ ├── JdkEcdsa.kt
│ │ │ │ ├── JdkHkdf.kt
│ │ │ │ ├── JdkHmac.kt
│ │ │ │ ├── JdkPbkdf2.kt
│ │ │ │ ├── JdkRsa.kt
│ │ │ │ ├── JdkRsaOaep.kt
│ │ │ │ ├── JdkRsaPkcs1.kt
│ │ │ │ ├── JdkRsaPss.kt
│ │ │ │ └── JdkRsaRaw.kt
│ │ │ ├── internal
│ │ │ │ └── utils.kt
│ │ │ ├── materials
│ │ │ │ ├── JdkEncodableKey.kt
│ │ │ │ ├── JdkKeyPairGenerator.kt
│ │ │ │ ├── JdkPrivateKeyDecoder.kt
│ │ │ │ ├── JdkPublicKeyDecoder.kt
│ │ │ │ ├── JdkSecretKeyDecoder.kt
│ │ │ │ └── JdkSecretKeyGenerator.kt
│ │ │ ├── operations
│ │ │ │ ├── JdkCipherFunction.kt
│ │ │ │ ├── JdkKeyAgreement.kt
│ │ │ │ ├── JdkMacSignature.kt
│ │ │ │ ├── JdkSignatureGenerator.kt
│ │ │ │ └── JdkSignatureVerifier.kt
│ │ │ └── pooling.kt
│ │ └── resources
│ │ │ └── META-INF
│ │ │ └── services
│ │ │ └── dev.whyoleg.cryptography.CryptographyProviderContainer
│ │ └── jvmTest
│ │ └── kotlin
│ │ ├── JdkDefaultProviderTest.kt
│ │ └── PoolingTest.kt
├── openssl3
│ ├── README.md
│ ├── api
│ │ ├── api
│ │ │ └── cryptography-provider-openssl3-api.klib.api
│ │ ├── build.gradle.kts
│ │ └── src
│ │ │ └── commonMain
│ │ │ ├── cinterop
│ │ │ └── declarations.def
│ │ │ └── kotlin
│ │ │ ├── Openssl3CryptographyProvider.kt
│ │ │ ├── algorithms
│ │ │ ├── Openssl3Aes.kt
│ │ │ ├── Openssl3AesCbc.kt
│ │ │ ├── Openssl3AesCmac.kt
│ │ │ ├── Openssl3AesCtr.kt
│ │ │ ├── Openssl3AesEcb.kt
│ │ │ ├── Openssl3AesGcm.kt
│ │ │ ├── Openssl3AesIvCipher.kt
│ │ │ ├── Openssl3Digest.kt
│ │ │ ├── Openssl3Ec.kt
│ │ │ ├── Openssl3Ecdh.kt
│ │ │ ├── Openssl3Ecdsa.kt
│ │ │ ├── Openssl3Hkdf.kt
│ │ │ ├── Openssl3Hmac.kt
│ │ │ ├── Openssl3Pbkdf2.kt
│ │ │ ├── Openssl3Rsa.kt
│ │ │ ├── Openssl3RsaOaep.kt
│ │ │ ├── Openssl3RsaPkcs1.kt
│ │ │ ├── Openssl3RsaPss.kt
│ │ │ └── Openssl3RsaRaw.kt
│ │ │ ├── internal
│ │ │ ├── arrays.kt
│ │ │ ├── clozy.kt
│ │ │ ├── errors.kt
│ │ │ ├── hash.kt
│ │ │ └── refs.kt
│ │ │ ├── materials
│ │ │ ├── Openssl3KeyDecoder.kt
│ │ │ ├── Openssl3KeyEncodable.kt
│ │ │ └── Openssl3KeyPairGenerator.kt
│ │ │ └── operations
│ │ │ ├── EvpCipherFunction.kt
│ │ │ ├── EvpPKeyCipherFunction.kt
│ │ │ ├── Openssl3DigestSignatureGenerator.kt
│ │ │ └── Openssl3DigestSignatureVerifier.kt
│ ├── prebuilt
│ │ ├── api
│ │ │ └── cryptography-provider-openssl3-prebuilt.klib.api
│ │ ├── build.gradle.kts
│ │ └── src
│ │ │ ├── commonMain
│ │ │ ├── cinterop
│ │ │ │ └── linking.def
│ │ │ └── kotlin
│ │ │ │ └── stub.kt
│ │ │ ├── commonTest
│ │ │ └── kotlin
│ │ │ │ ├── PrebuiltLibCrypto3Test.kt
│ │ │ │ └── PrebuiltOpensslDefaultProviderTest.kt
│ │ │ └── mingwMain
│ │ │ └── libs
│ │ │ └── libz.a
│ ├── shared
│ │ ├── api
│ │ │ └── cryptography-provider-openssl3-shared.klib.api
│ │ ├── build.gradle.kts
│ │ └── src
│ │ │ ├── commonMain
│ │ │ ├── cinterop
│ │ │ │ └── linking.def
│ │ │ └── kotlin
│ │ │ │ └── stub.kt
│ │ │ └── commonTest
│ │ │ └── kotlin
│ │ │ ├── SharedLibCrypto3Test.kt
│ │ │ └── SharedOpensslDefaultProviderTest.kt
│ └── test
│ │ ├── build.gradle.kts
│ │ └── src
│ │ └── commonMain
│ │ └── kotlin
│ │ ├── LibCrypto3Test.kt
│ │ └── utils.kt
└── webcrypto
│ ├── README.md
│ ├── api
│ └── cryptography-provider-webcrypto.klib.api
│ ├── build.gradle.kts
│ └── src
│ ├── commonMain
│ └── kotlin
│ │ ├── WebCryptoCryptographyProvider.kt
│ │ ├── algorithms
│ │ ├── WebCryptoAes.kt
│ │ ├── WebCryptoAesCbc.kt
│ │ ├── WebCryptoAesCtr.kt
│ │ ├── WebCryptoAesGcm.kt
│ │ ├── WebCryptoDigest.kt
│ │ ├── WebCryptoEc.kt
│ │ ├── WebCryptoEcdh.kt
│ │ ├── WebCryptoEcdsa.kt
│ │ ├── WebCryptoHkdf.kt
│ │ ├── WebCryptoHmac.kt
│ │ ├── WebCryptoPbkdf2.kt
│ │ ├── WebCryptoRsa.kt
│ │ ├── WebCryptoRsaOaep.kt
│ │ ├── WebCryptoRsaPkcs1.kt
│ │ └── WebCryptoRsaPss.kt
│ │ ├── internal
│ │ ├── Algorithms.kt
│ │ ├── Keys.kt
│ │ ├── WebCrypto.kt
│ │ ├── digest.kt
│ │ └── utils.kt
│ │ ├── materials
│ │ ├── WebCryptoAsymmetricKeyGenerator.kt
│ │ ├── WebCryptoEncodableKey.kt
│ │ ├── WebCryptoKeyDecoder.kt
│ │ ├── WebCryptoKeyProcessor.kt
│ │ ├── WebCryptoKeyWrapper.kt
│ │ └── WebCryptoSymmetricKeyGenerator.kt
│ │ └── operations
│ │ ├── WebCryptoSignatureGenerator.kt
│ │ └── WebCryptoSignatureVerifier.kt
│ ├── commonTest
│ └── kotlin
│ │ └── DefaultProviderTest.kt
│ ├── jsMain
│ └── kotlin
│ │ ├── WebCryptoCryptographyProvider.js.kt
│ │ └── internal
│ │ ├── Algorithms.js.kt
│ │ ├── Keys.js.kt
│ │ ├── SubtleCrypto.js.kt
│ │ ├── WebCrypto.js.kt
│ │ └── interop.js.kt
│ └── wasmJsMain
│ └── kotlin
│ ├── WebCryptoCryptographyProvider.wasmJs.kt
│ └── internal
│ ├── Algorithms.wasmJs.kt
│ ├── Keys.wasmJs.kt
│ ├── SubtleCrypto.wasmJs.kt
│ ├── WebCrypto.wasmJs.kt
│ └── interop.wasmJs.kt
├── cryptography-random
├── README.md
├── api
│ ├── cryptography-random.api
│ └── cryptography-random.klib.api
├── build.gradle.kts
└── src
│ ├── appleMain
│ └── kotlin
│ │ └── CryptographyRandom.apple.kt
│ ├── commonMain
│ └── kotlin
│ │ ├── AbstractRandom.kt
│ │ └── CryptographyRandom.kt
│ ├── commonTest
│ └── kotlin
│ │ └── CryptographyRandomTest.kt
│ ├── jsMain
│ └── kotlin
│ │ └── CryptographyRandom.js.kt
│ ├── jvmMain
│ └── kotlin
│ │ └── CryptographyRandom.jvm.kt
│ ├── linuxAndAndroidNativeMain
│ └── kotlin
│ │ ├── CryptographyRandom.linuxAndAndroidNative.kt
│ │ ├── GetRandom.kt
│ │ ├── LinuxRandom.kt
│ │ ├── URandom.kt
│ │ └── errno.kt
│ ├── linuxTest
│ └── kotlin
│ │ └── LinuxRandomTest.kt
│ ├── mingwMain
│ └── kotlin
│ │ └── CryptographyRandom.mingw.kt
│ ├── wasmJsMain
│ └── kotlin
│ │ └── CryptographyRandom.wasmJs.kt
│ └── wasmWasiMain
│ └── kotlin
│ └── CryptographyRandom.wasmWasi.kt
├── cryptography-serialization
├── asn1
│ ├── README.md
│ ├── api
│ │ ├── cryptography-serialization-asn1.api
│ │ └── cryptography-serialization-asn1.klib.api
│ ├── build.gradle.kts
│ ├── modules
│ │ ├── README.md
│ │ ├── api
│ │ │ ├── cryptography-serialization-asn1-modules.api
│ │ │ └── cryptography-serialization-asn1-modules.klib.api
│ │ ├── build.gradle.kts
│ │ └── src
│ │ │ └── commonMain
│ │ │ └── kotlin
│ │ │ ├── AlgorithmIdentifier.kt
│ │ │ ├── AlgorithmIdentifierSerializer.kt
│ │ │ ├── EC.kt
│ │ │ ├── KeyAlgorithmIdentifier.kt
│ │ │ ├── KeyAlgorithmIdentifierSerializer.kt
│ │ │ ├── KeyInfo.kt
│ │ │ └── RSA.kt
│ └── src
│ │ ├── commonMain
│ │ └── kotlin
│ │ │ ├── Annotations.kt
│ │ │ ├── BitArray.kt
│ │ │ ├── Der.kt
│ │ │ ├── ObjectIdentifier.kt
│ │ │ └── internal
│ │ │ ├── ByteArrayInput.kt
│ │ │ ├── ByteArrayOutput.kt
│ │ │ ├── DerDecoder.kt
│ │ │ ├── DerEncoder.kt
│ │ │ ├── DerInput.kt
│ │ │ ├── DerOutput.kt
│ │ │ └── DerTag.kt
│ │ └── commonTest
│ │ └── kotlin
│ │ ├── ContextSpecificEncodingTest.kt
│ │ ├── ObjectIdentifierEncodingTest.kt
│ │ └── SequenceEncodingTest.kt
└── pem
│ ├── README.md
│ ├── api
│ ├── cryptography-serialization-pem.api
│ └── cryptography-serialization-pem.klib.api
│ ├── build.gradle.kts
│ └── src
│ ├── commonMain
│ └── kotlin
│ │ ├── Pem.kt
│ │ ├── PemContent.kt
│ │ └── PemLabel.kt
│ └── commonTest
│ └── kotlin
│ └── PemTest.kt
├── cryptography-version-catalog
└── build.gradle.kts
├── docs
├── bom.md
├── examples.md
├── gradle-version-catalog.md
└── providers
│ └── index.md
├── gradle.properties
├── gradle
├── gradle-daemon-jvm.properties
├── libs.updates.gradle.kts
├── libs.versions.toml
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── karma.config.d
└── config.js
├── mkdocs.yml
├── settings.gradle.kts
├── swiftinterop
├── build.gradle.kts
├── settings.gradle.kts
└── src
│ └── main
│ └── kotlin
│ ├── SwiftInteropExtension.kt
│ ├── SwiftInteropPlugin.kt
│ └── tasks
│ ├── GenerateSwiftCinteropDefinitionTask.kt
│ ├── GenerateSwiftPackageDefinitionTask.kt
│ ├── LibtoolBuildStaticTask.kt
│ ├── XcodebuildBuildKonanTargetInfo.kt
│ ├── XcodebuildBuildTarget.kt
│ ├── XcodebuildBuildTask.kt
│ └── utils.kt
├── tests-publication
├── build.gradle.kts
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle.kts
└── src
│ └── commonTest
│ └── kotlin
│ └── JustTest.kt
└── testtool
├── build.gradle.kts
├── client
├── build.gradle.kts
└── src
│ ├── commonMain
│ └── kotlin
│ │ └── TesttoolClient.kt
│ ├── jvmMain
│ └── kotlin
│ │ └── TesttoolClient.jvm.kt
│ └── nonJvmMain
│ └── kotlin
│ └── TesttoolClient.nonJvm.kt
├── gradle.properties
├── plugin
├── build.gradle.kts
└── src
│ └── main
│ └── kotlin
│ ├── TesttoolServerConfiguration.kt
│ ├── TesttoolServerPlugin.kt
│ └── TesttoolServerService.kt
├── server
├── build.gradle.kts
└── src
│ └── main
│ └── kotlin
│ ├── TesttoolServer.kt
│ └── compatibility.kt
└── settings.gradle.kts
/.github/actions/run-android-emulator-tests/action.yml:
--------------------------------------------------------------------------------
1 | name: 'Run Android emulator tests'
2 | description: 'Setups android emulator caching and running'
3 | inputs:
4 | api-level:
5 | description: Android API level for testing
6 | required: true
7 | run:
8 | description: Arguments for running gradle with Android Emulator
9 | required: false
10 | default: ''
11 | test-reports-classifier:
12 | description: Classifier for published tests report
13 | required: true
14 | runs:
15 | using: 'composite'
16 | steps:
17 | - name: Enable KVM group perms
18 | shell: bash
19 | run: |
20 | echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
21 | sudo udevadm control --reload-rules
22 | sudo udevadm trigger --name-match=kvm
23 |
24 | - name: Run tests
25 | uses: reactivecircus/android-emulator-runner@v2
26 | with:
27 | arch: x86_64
28 | api-level: ${{ inputs.api-level }}
29 | script: ${{ inputs.run }}
30 |
31 | # Android test failures are not available in gradle build scans
32 | - name: Upload test reports
33 | if: failure()
34 | uses: actions/upload-artifact@v4
35 | with:
36 | name: android-test-reports-${{ inputs.test-reports-classifier }}-${{ inputs.api-level }}
37 | path: '**/build/reports/androidTests'
38 |
--------------------------------------------------------------------------------
/.github/workflows/ci-branch.yml:
--------------------------------------------------------------------------------
1 | name: Branch CI
2 | on:
3 | workflow_dispatch:
4 | push:
5 | branches-ignore:
6 | - main
7 | - kotlin-eap/*
8 |
9 | jobs:
10 | checks:
11 | uses: ./.github/workflows/run-checks.yml
12 |
13 | publish:
14 | needs: [ checks ]
15 | uses: ./.github/workflows/publish-local.yml
16 | secrets: inherit
17 |
--------------------------------------------------------------------------------
/.github/workflows/ci-kotlin-eap.yml:
--------------------------------------------------------------------------------
1 | name: Kotlin EAP CI
2 | on:
3 | workflow_dispatch:
4 | inputs:
5 | kotlinVersion:
6 | description: 'Kotlin version'
7 | required: false
8 | default: '2.1.0-dev-+'
9 |
10 | schedule:
11 | - cron: '0 0 * * MON'
12 |
13 | defaults:
14 | run:
15 | shell: bash
16 |
17 | jobs:
18 | kotlin-eap:
19 | runs-on: ${{ matrix.os }}
20 | strategy:
21 | fail-fast: false
22 | matrix:
23 | os: [ 'ubuntu-latest', 'macos-latest', 'windows-latest' ]
24 | kotlin-version: [ '', '${{ inputs.kotlinVersion }}' ]
25 | try-next: [ 'true', 'false' ]
26 | steps:
27 | - uses: actions/checkout@v4
28 | - uses: ./.github/actions/setup-environment
29 | with:
30 | cache-disabled: true
31 |
32 | - run: >
33 | ./gradlew
34 | build publishToMavenLocal
35 | --continue
36 | -Pckbuild.skipTestTasks=true
37 | -Pckbuild.warningsAsErrors=false
38 | -Pckbuild.kotlinVersionOverride=${{ matrix.kotlin-version }}
39 | -Pkotlin.experimental.tryNext=${{ matrix.try-next }}
40 |
--------------------------------------------------------------------------------
/.github/workflows/ci-main.yml:
--------------------------------------------------------------------------------
1 | name: main CI
2 | on:
3 | workflow_dispatch:
4 | push:
5 | branches:
6 | - main
7 |
8 | jobs:
9 | checks:
10 | uses: ./.github/workflows/run-checks.yml
11 |
12 | publish:
13 | needs: [ checks ]
14 | uses: ./.github/workflows/publish-snapshot.yml
15 | secrets: inherit
16 |
--------------------------------------------------------------------------------
/.github/workflows/ci-pr.yml:
--------------------------------------------------------------------------------
1 | name: Pull Request CI
2 | on:
3 | pull_request
4 |
5 | jobs:
6 | checks:
7 | uses: ./.github/workflows/run-checks.yml
8 |
--------------------------------------------------------------------------------
/.github/workflows/ci-release.yml:
--------------------------------------------------------------------------------
1 | name: Release CI
2 | on:
3 | push:
4 | tags:
5 | - '*'
6 |
7 | jobs:
8 | checks:
9 | uses: ./.github/workflows/run-checks.yml
10 |
11 | publish:
12 | needs: [ checks ]
13 | uses: ./.github/workflows/publish-release.yml
14 | secrets: inherit
15 |
--------------------------------------------------------------------------------
/.github/workflows/deploy-website.yml:
--------------------------------------------------------------------------------
1 | name: Deploy website
2 | on:
3 | workflow_dispatch:
4 |
5 | jobs:
6 | build-website:
7 | uses: ./.github/workflows/run-build-website.yml
8 |
9 | publish-website:
10 | needs: [ build-website ]
11 | uses: ./.github/workflows/publish-website.yml
12 | permissions:
13 | contents: read
14 | pages: write
15 | id-token: write
16 |
--------------------------------------------------------------------------------
/.github/workflows/publish-local.yml:
--------------------------------------------------------------------------------
1 | name: Publish testing
2 | on: [ workflow_call ]
3 |
4 | jobs:
5 | publish:
6 | runs-on: macos-latest
7 | steps:
8 | - uses: actions/checkout@v4
9 | - uses: ./.github/actions/setup-environment
10 | with:
11 | cache-disabled: true
12 |
13 | - name: Publish to Maven Local
14 | run: ./gradlew publishToMavenLocal --no-configuration-cache
15 | env:
16 | ORG_GRADLE_PROJECT_signingInMemoryKey: ${{secrets.signingKey}}
17 | ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{secrets.signingPassword}}
18 | ORG_GRADLE_PROJECT_mavenCentralUsername: ${{secrets.sonatypeUsername}}
19 | ORG_GRADLE_PROJECT_mavenCentralPassword: ${{secrets.sonatypePassword}}
20 |
--------------------------------------------------------------------------------
/.github/workflows/publish-release.yml:
--------------------------------------------------------------------------------
1 | name: Publish release
2 | on: [ workflow_call ]
3 |
4 | concurrency:
5 | group: publish-release
6 | cancel-in-progress: false
7 |
8 | jobs:
9 | publish:
10 | if: github.repository == 'whyoleg/cryptography-kotlin'
11 | runs-on: macos-latest
12 | steps:
13 | - uses: actions/checkout@v4
14 | - uses: ./.github/actions/setup-environment
15 | with:
16 | cache-disabled: true
17 |
18 | - name: Publish release to Maven Central
19 | run: ./gradlew publishToMavenCentral -Pversion=${{ github.ref_name }} --no-configuration-cache
20 | env:
21 | ORG_GRADLE_PROJECT_signingInMemoryKey: ${{secrets.signingKey}}
22 | ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{secrets.signingPassword}}
23 | ORG_GRADLE_PROJECT_mavenCentralUsername: ${{secrets.sonatypeUsername}}
24 | ORG_GRADLE_PROJECT_mavenCentralPassword: ${{secrets.sonatypePassword}}
25 |
--------------------------------------------------------------------------------
/.github/workflows/publish-snapshot.yml:
--------------------------------------------------------------------------------
1 | name: Publish snapshot
2 | on: [ workflow_call ]
3 |
4 | concurrency:
5 | group: publish-snapshot
6 | cancel-in-progress: false
7 |
8 | jobs:
9 | publish:
10 | if: github.repository == 'whyoleg/cryptography-kotlin'
11 | runs-on: macos-latest
12 | steps:
13 | - uses: actions/checkout@v4
14 | - uses: ./.github/actions/setup-environment
15 | with:
16 | cache-disabled: true
17 |
18 | - name: Publish snapshot to Maven Central
19 | run: ./gradlew publishToMavenCentral -Pversion=0.4.1-SNAPSHOT --no-configuration-cache
20 | env:
21 | ORG_GRADLE_PROJECT_signingInMemoryKey: ${{secrets.signingKey}}
22 | ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{secrets.signingPassword}}
23 | ORG_GRADLE_PROJECT_mavenCentralUsername: ${{secrets.sonatypeUsername}}
24 | ORG_GRADLE_PROJECT_mavenCentralPassword: ${{secrets.sonatypePassword}}
25 |
--------------------------------------------------------------------------------
/.github/workflows/publish-website.yml:
--------------------------------------------------------------------------------
1 | name: Publish website
2 | on: [ workflow_call ]
3 |
4 | concurrency:
5 | group: publish-website
6 | cancel-in-progress: false
7 |
8 | jobs:
9 | deploy:
10 | if: github.repository == 'whyoleg/cryptography-kotlin'
11 | runs-on: ubuntu-latest
12 | environment:
13 | name: github-pages
14 | url: ${{ steps.deployment.outputs.page_url }}
15 | steps:
16 | - name: Deploy to GitHub Pages
17 | id: deployment
18 | uses: actions/deploy-pages@v4
19 |
--------------------------------------------------------------------------------
/.github/workflows/run-build-project.yml:
--------------------------------------------------------------------------------
1 | name: Build project
2 | on:
3 | workflow_dispatch:
4 | workflow_call:
5 |
6 | defaults:
7 | run:
8 | shell: bash
9 |
10 | jobs:
11 | build:
12 | runs-on: ${{ matrix.os }}
13 | strategy:
14 | fail-fast: false
15 | matrix:
16 | os: [ 'ubuntu-latest', 'macos-latest', 'windows-latest' ]
17 | steps:
18 | - uses: actions/checkout@v4
19 | - uses: ./.github/actions/setup-environment
20 | with:
21 | cache-read-only: ${{ github.ref_name != 'main' }}
22 | - run: >
23 | ./gradlew
24 | build publishToMavenLocal
25 | --continue
26 | -Pckbuild.skipTestTasks=true
27 | -Pckbuild.skipLinkTasks=true
28 |
--------------------------------------------------------------------------------
/.github/workflows/run-build-website.yml:
--------------------------------------------------------------------------------
1 | name: Build website
2 | on:
3 | workflow_dispatch:
4 | workflow_call:
5 |
6 | jobs:
7 | website:
8 | runs-on: macos-latest
9 | steps:
10 | - uses: actions/checkout@v4
11 | - uses: actions/setup-python@v5
12 | with:
13 | python-version: 3.x
14 | - run: pip install mkdocs-material
15 | - uses: ./.github/actions/setup-environment
16 |
17 | - name: Build documentation
18 | run: ./gradlew mkdocsBuild
19 |
20 | - name: Upload artifact
21 | uses: actions/upload-pages-artifact@v3
22 | with:
23 | path: site
24 |
--------------------------------------------------------------------------------
/.github/workflows/run-checks.yml:
--------------------------------------------------------------------------------
1 | name: Run checks
2 | on:
3 | workflow_dispatch:
4 | workflow_call:
5 |
6 | jobs:
7 | build-project:
8 | uses: ./.github/workflows/run-build-project.yml
9 |
10 | build-website:
11 | needs: [ build-project ]
12 | uses: ./.github/workflows/run-build-website.yml
13 |
14 | default-tests:
15 | needs: [ build-project ]
16 | uses: ./.github/workflows/run-tests-default.yml
17 |
18 | compatibility-tests:
19 | needs: [ default-tests ]
20 | uses: ./.github/workflows/run-tests-compatibility.yml
21 |
22 | slow-tasks:
23 | needs: [ compatibility-tests ]
24 | uses: ./.github/workflows/run-slow-tasks.yml
25 |
--------------------------------------------------------------------------------
/.github/workflows/run-slow-tasks.yml:
--------------------------------------------------------------------------------
1 | name: Run slow tasks
2 | on:
3 | workflow_dispatch:
4 | workflow_call:
5 |
6 | defaults:
7 | run:
8 | shell: bash
9 |
10 | jobs:
11 | link-native:
12 | runs-on: ${{ matrix.os }}
13 | strategy:
14 | fail-fast: false
15 | matrix:
16 | os: [ 'ubuntu-latest', 'macos-latest', 'windows-latest' ]
17 | steps:
18 | - uses: actions/checkout@v4
19 | - uses: ./.github/actions/setup-environment
20 | - run: ./gradlew linkAll --continue
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | syntax: glob
2 |
3 | **/.idea/*
4 | !/.idea/vcs.xml
5 | !/.idea/copyright
6 | !/.idea/codeStyles
7 | *.iml
8 |
9 | .gradle
10 | .kotlin
11 | .build
12 | classes
13 | build/
14 | *.log
15 | /local.properties
16 | /docs/api
17 | /docs/modules
18 | /docs/README.md
19 | /docs/CHANGELOG.md
20 | /site
21 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/copyright/Apache_2_0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/build-logic/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | plugins {
6 | `kotlin-dsl`
7 | }
8 |
9 | dependencies {
10 | implementation(libs.kotlin.gradle.plugin)
11 | implementation(libs.kotlin.dokka.gradle.plugin)
12 | implementation(libs.kotlinx.bcv.gradle.plugin)
13 | implementation(libs.kotlinx.kover.gradle.plugin)
14 | implementation(libs.android.gradle.plugin)
15 | implementation(libs.maven.publish.gradle.plugin)
16 | implementation(libs.apache.commons.compress)
17 | implementation("testtool:plugin")
18 | }
19 |
--------------------------------------------------------------------------------
/build-logic/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | pluginManagement {
6 | includeBuild("../build-settings")
7 | includeBuild("../testtool")
8 | }
9 |
10 | plugins {
11 | id("cksettings.default")
12 | }
13 |
14 | dependencyResolutionManagement {
15 | versionCatalogs.named("libs") {
16 | from(files("../gradle/libs.versions.toml"))
17 | }
18 | }
19 |
20 | rootProject.name = "build-logic"
21 |
--------------------------------------------------------------------------------
/build-logic/src/main/kotlin/ckbuild.documentation.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | import ckbuild.documentation.*
6 | import java.net.*
7 |
8 | plugins {
9 | id("org.jetbrains.dokka")
10 | }
11 |
12 | val documentation = extensions.create("documentation").apply {
13 | moduleName.convention(project.name)
14 | includes.set("README.md")
15 | }
16 |
17 | tasks.register("mkdocsCopy") {
18 | // store into variables to work around configuration cache issues
19 | val includes = documentation.includes
20 | val moduleName = documentation.moduleName
21 |
22 | onlyIf { includes.isPresent }
23 | if (includes.isPresent) from(file(includes))
24 | into(rootDir.resolve("docs/modules"))
25 | rename { "${moduleName.get()}.md" }
26 | }
27 |
28 | dokka {
29 | moduleName.set(documentation.moduleName)
30 | dokkaPublications.configureEach {
31 | // we don't suppress inherited members explicitly as without it classes like RSA.OAEP don't show functions like keyGenerator
32 | suppressInheritedMembers.set(false)
33 | failOnWarning.set(true)
34 | }
35 | dokkaSourceSets.configureEach {
36 | if (documentation.includes.isPresent) includes.from(file(documentation.includes))
37 | reportUndocumented.set(false) // set true later
38 | sourceLink {
39 | localDirectory.set(rootDir)
40 | remoteUrl.set(URI("https://github.com/whyoleg/cryptography-kotlin/tree/${version}/"))
41 | remoteLineSuffix.set("#L")
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/build-logic/src/main/kotlin/ckbuild.multiplatform-library.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | import kotlinx.validation.*
6 |
7 | plugins {
8 | id("ckbuild.multiplatform-base")
9 | id("ckbuild.publication")
10 | id("ckbuild.documentation")
11 |
12 | id("org.jetbrains.kotlinx.binary-compatibility-validator")
13 | }
14 |
15 | kotlin {
16 | explicitApi()
17 | }
18 |
19 | apiValidation {
20 | @OptIn(ExperimentalBCVApi::class)
21 | klib {
22 | enabled = true
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/build-logic/src/main/kotlin/ckbuild.use-openssl.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | import ckbuild.openssl.*
6 |
7 | val service = gradle.sharedServices.registerIfAbsent("OpensslService", OpensslService::class)
8 |
9 | extensions.add("openssl", OpensslExtension(service))
10 |
11 | if (project == rootProject) {
12 | val service = service.get()
13 | fun configureOpenssl(
14 | classifier: String,
15 | version: String,
16 | tag: String,
17 | property: DirectoryProperty,
18 | ) {
19 | val configuration = configurations.create("openssl_$classifier")
20 | dependencies {
21 | configuration("ckbuild.dependencies.openssl:openssl-$version:$tag@zip")
22 | }
23 |
24 | val setupOpenssl = tasks.register("setupOpenssl_$classifier") {
25 | inputFile.set(project.layout.file(provider { configuration.singleFile }))
26 | outputDirectory.set(temporaryDir)
27 | }
28 |
29 | property.set(setupOpenssl.map { it.outputDirectory.get() })
30 | }
31 |
32 | configureOpenssl("v3_0", "3.0.15", "3.0.15_1", service.v3_0)
33 | configureOpenssl("v3_1", "3.1.7", "3.1.7_1", service.v3_1)
34 | configureOpenssl("v3_2", "3.2.3", "3.2.3_1", service.v3_2)
35 | configureOpenssl("v3_3", "3.3.2", "3.3.2_1", service.v3_3)
36 | }
37 |
--------------------------------------------------------------------------------
/build-logic/src/main/kotlin/ckbuild/OptIns.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package ckbuild
6 |
7 | @Suppress("ConstPropertyName")
8 | object OptIns {
9 | const val CryptographyProviderApi = "dev.whyoleg.cryptography.CryptographyProviderApi"
10 | const val DelicateCryptographyApi = "dev.whyoleg.cryptography.DelicateCryptographyApi"
11 |
12 | const val ExperimentalSubclassOptIn = "kotlin.ExperimentalSubclassOptIn"
13 | const val ExperimentalStdlibApi = "kotlin.ExperimentalStdlibApi"
14 | const val ExperimentalForeignApi = "kotlinx.cinterop.ExperimentalForeignApi"
15 | const val ExperimentalEncodingApi = "kotlin.io.encoding.ExperimentalEncodingApi"
16 | }
17 |
--------------------------------------------------------------------------------
/build-logic/src/main/kotlin/ckbuild/artifacts.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package ckbuild
6 |
7 | // all artifacts that are published and documentable
8 | val artifacts
9 | get() = listOf(
10 | "cryptography-bigint",
11 | "cryptography-random",
12 | "cryptography-serialization-pem",
13 | "cryptography-serialization-asn1",
14 | "cryptography-serialization-asn1-modules",
15 | "cryptography-core",
16 | "cryptography-provider-base",
17 | "cryptography-provider-jdk",
18 | "cryptography-provider-apple",
19 | "cryptography-provider-cryptokit",
20 | "cryptography-provider-webcrypto",
21 | "cryptography-provider-openssl3-api",
22 | "cryptography-provider-openssl3-shared",
23 | "cryptography-provider-openssl3-prebuilt",
24 | )
25 |
--------------------------------------------------------------------------------
/build-logic/src/main/kotlin/ckbuild/documentation/DocumentationExtension.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package ckbuild.documentation
6 |
7 | import org.gradle.api.provider.*
8 |
9 | abstract class DocumentationExtension {
10 | abstract val moduleName: Property
11 | abstract val includes: Property
12 | }
13 |
--------------------------------------------------------------------------------
/build-logic/src/main/kotlin/ckbuild/native.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package ckbuild
6 |
7 | import org.jetbrains.kotlin.gradle.plugin.mpp.*
8 |
9 | fun KotlinNativeTarget.cinterop(
10 | defFileName: String,
11 | groupName: String = "common",
12 | compilationName: String = "main",
13 | block: DefaultCInteropSettings.() -> Unit = {},
14 | ) {
15 | compilations.getByName(compilationName) {
16 | cinterops.create(defFileName) {
17 | defFile("src/${groupName}${compilationName.replaceFirstChar(Char::uppercase)}/cinterop/$defFileName.def")
18 | block()
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/build-logic/src/main/kotlin/ckbuild/tests/TestAggregation.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package ckbuild.tests
6 |
7 | import org.gradle.api.*
8 | import org.gradle.api.tasks.*
9 | import org.jetbrains.kotlin.gradle.dsl.*
10 | import org.jetbrains.kotlin.gradle.plugin.*
11 |
12 | fun Project.registerTestAggregationTask(
13 | name: String,
14 | taskDependencies: () -> TaskCollection<*>,
15 | targetFilter: (KotlinTarget) -> Boolean,
16 | ) {
17 | extensions.configure("kotlin") {
18 | var called = false
19 | targets.matching(targetFilter).configureEach {
20 | if (called) return@configureEach
21 | called = true
22 |
23 | tasks.register(name) {
24 | group = "verification"
25 | dependsOn(taskDependencies())
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/build-settings/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | plugins {
6 | `kotlin-dsl`
7 | }
8 |
9 | dependencies {
10 | implementation("com.gradle:develocity-gradle-plugin:4.0")
11 | implementation("com.gradle:common-custom-user-data-gradle-plugin:2.2.1")
12 | implementation("org.gradle.toolchains:foojay-resolver:0.10.0")
13 | }
14 |
--------------------------------------------------------------------------------
/build-settings/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | pluginManagement {
6 | repositories {
7 | mavenCentral()
8 | gradlePluginPortal()
9 | }
10 | }
11 |
12 | dependencyResolutionManagement {
13 | repositories {
14 | mavenCentral()
15 | gradlePluginPortal()
16 | }
17 | }
18 |
19 | rootProject.name = "build-settings"
20 |
--------------------------------------------------------------------------------
/build-settings/src/main/kotlin/cksettings.default.settings.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | plugins {
6 | id("cksettings.kotlin-version-override")
7 | id("cksettings.repositories")
8 | id("cksettings.gradle")
9 | }
10 |
--------------------------------------------------------------------------------
/build-settings/src/main/kotlin/cksettings.gradle.settings.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | plugins {
6 | id("com.gradle.develocity")
7 | id("com.gradle.common-custom-user-data-gradle-plugin")
8 | id("org.gradle.toolchains.foojay-resolver-convention")
9 | }
10 |
11 | develocity {
12 | buildScan {
13 | publishing.onlyIf { System.getenv("CI").toBoolean() }
14 | }
15 | }
16 |
17 | enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
18 |
--------------------------------------------------------------------------------
/build-settings/src/main/kotlin/cksettings.kotlin-version-override.settings.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | @file:Suppress("UnstableApiUsage")
6 |
7 | val kotlinVersionOverride = providers.gradleProperty("ckbuild.kotlinVersionOverride").orNull?.takeIf(String::isNotBlank)
8 |
9 | // we need to create it eagerly to be able to override later
10 | dependencyResolutionManagement {
11 | versionCatalogs.create("libs")
12 | }
13 |
14 | if (kotlinVersionOverride != null) {
15 | val kotlinDevRepository = "https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev"
16 | val kotlinGroup = "org.jetbrains.kotlin"
17 |
18 | logger.lifecycle("Kotlin version override: $kotlinVersionOverride, repository: $kotlinDevRepository")
19 |
20 | pluginManagement {
21 | repositories {
22 | maven(kotlinDevRepository) {
23 | content { includeGroupAndSubgroups(kotlinGroup) }
24 | }
25 | }
26 | }
27 |
28 | dependencyResolutionManagement {
29 | repositories {
30 | maven(kotlinDevRepository) {
31 | content { includeGroupAndSubgroups(kotlinGroup) }
32 | }
33 | }
34 |
35 | versionCatalogs.named("libs") {
36 | version("kotlin", kotlinVersionOverride)
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/build-settings/src/main/kotlin/cksettings.repositories.settings.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | @file:Suppress("UnstableApiUsage")
6 |
7 | pluginManagement {
8 | repositories {
9 | google {
10 | content {
11 | includeGroupAndSubgroups("com.android")
12 | includeGroupAndSubgroups("com.google")
13 | includeGroupAndSubgroups("androidx")
14 | }
15 | }
16 | gradlePluginPortal {
17 | content {
18 | includeGroupAndSubgroups("com.gradle")
19 | includeGroupAndSubgroups("org.gradle")
20 | }
21 | }
22 | mavenCentral()
23 | }
24 | }
25 |
26 | dependencyResolutionManagement {
27 | repositories {
28 | google {
29 | content {
30 | includeGroupAndSubgroups("com.android")
31 | includeGroupAndSubgroups("com.google")
32 | includeGroupAndSubgroups("androidx")
33 | }
34 | }
35 | gradlePluginPortal {
36 | content {
37 | includeGroupAndSubgroups("com.gradle")
38 | includeGroupAndSubgroups("org.gradle")
39 | }
40 | }
41 | mavenCentral()
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/build-settings/src/main/kotlin/cksettings/ProjectsScope.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package cksettings
6 |
7 | import org.gradle.api.initialization.*
8 |
9 | fun Settings.projects(rootProjectName: String, block: ProjectsScope.() -> Unit = {}) {
10 | rootProject.name = rootProjectName
11 | ProjectsScope(settings, emptyList(), emptyList()).apply(block)
12 | }
13 |
14 | class ProjectsScope(
15 | private val settings: Settings,
16 | private val pathParts: List,
17 | private val prefixParts: List,
18 | ) {
19 |
20 | fun module(name: String) {
21 | val moduleName = (prefixParts + name).joinToString("-")
22 | val modulePath = (pathParts + name).joinToString("/")
23 |
24 | settings.include(moduleName)
25 | settings.project(":$moduleName").projectDir = settings.rootDir.resolve(modulePath)
26 | }
27 |
28 | fun module(name: String, prefix: String? = name, nested: ProjectsScope.() -> Unit = {}) {
29 | module(name)
30 | folder(name, prefix, nested)
31 | }
32 |
33 | fun folder(name: String, prefix: String? = name, block: ProjectsScope.() -> Unit) {
34 | val prefixParts = when (prefix) {
35 | null -> prefixParts
36 | else -> prefixParts + prefix
37 | }
38 | ProjectsScope(settings, pathParts + name, prefixParts).apply(block)
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | import org.jetbrains.kotlin.gradle.targets.js.nodejs.*
6 | import org.jetbrains.kotlin.gradle.targets.js.npm.*
7 |
8 | plugins {
9 | alias(libs.plugins.kotlin.dokka)
10 |
11 | alias(libs.plugins.android.library) apply false
12 | alias(libs.plugins.kotlin.multiplatform) apply false
13 | alias(libs.plugins.kotlin.plugin.serialization) apply false
14 |
15 | id("ckbuild.use-openssl")
16 | }
17 |
18 | plugins.withType {
19 | // ignore package lock
20 | extensions.configure {
21 | lockFileDirectory.set(layout.buildDirectory.dir("kotlin-js-store"))
22 | packageLockMismatchReport.set(LockFileMismatchReport.NONE)
23 | }
24 | }
25 | dependencies {
26 | ckbuild.artifacts.forEach {
27 | dokka(project(":$it"))
28 | }
29 | }
30 |
31 | tasks.dokkaGeneratePublicationHtml {
32 | outputDirectory.set(file("docs/api"))
33 | }
34 |
35 | tasks.register("mkdocsCopy") {
36 | into(rootDir.resolve("docs"))
37 | from("README.md")
38 | from("CHANGELOG.md")
39 | }
40 |
41 | tasks.register("mkdocsBuild") {
42 | dependsOn(tasks.dokkaGeneratePublicationHtml)
43 | dependsOn(tasks.named("mkdocsCopy"))
44 | dependsOn(subprojects.mapNotNull { it.tasks.findByName("mkdocsCopy") })
45 | commandLine("mkdocs", "build", "--clean", "--strict")
46 | }
47 |
--------------------------------------------------------------------------------
/cryptography-bigint/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | import ckbuild.*
6 | import org.jetbrains.kotlin.gradle.*
7 |
8 | plugins {
9 | id("ckbuild.multiplatform-library")
10 | alias(libs.plugins.kotlin.plugin.serialization)
11 | }
12 |
13 | description = "cryptography-kotlin BigInt API"
14 |
15 | @OptIn(ExperimentalKotlinGradlePluginApi::class)
16 | kotlin {
17 | jvmTarget()
18 | jsTarget()
19 | nativeTargets()
20 | wasmTargets()
21 |
22 | compilerOptions {
23 | freeCompilerArgs.add("-Xexpect-actual-classes")
24 | }
25 |
26 | applyDefaultHierarchyTemplate {
27 | common {
28 | group("nonJvm") {
29 | // js and wasmJs
30 | group("jsAndWasmJs") {
31 | withJs()
32 | withWasmJs()
33 | }
34 | // all native targets + wasmWasi
35 | group("nativeAndWasmWasi") {
36 | group("native")
37 | withWasmWasi()
38 | }
39 | }
40 | }
41 | }
42 |
43 | sourceSets {
44 | commonMain.dependencies {
45 | compileOnly(libs.kotlinx.serialization.core)
46 | }
47 | // other targets don't support `compileOnly` dependencies
48 | named("nonJvmMain").dependencies {
49 | api(libs.kotlinx.serialization.core)
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/cryptography-bigint/src/commonMain/kotlin/BigIntSerializers.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.bigint
6 |
7 | import kotlinx.serialization.*
8 | import kotlinx.serialization.builtins.*
9 | import kotlinx.serialization.descriptors.*
10 | import kotlinx.serialization.encoding.*
11 |
12 | public object BigIntAsStringSerializer : KSerializer {
13 | override val descriptor: SerialDescriptor =
14 | PrimitiveSerialDescriptor("BigInt", PrimitiveKind.STRING)
15 |
16 | override fun serialize(encoder: Encoder, value: BigInt) {
17 | encoder.encodeString(value.toString())
18 | }
19 |
20 | override fun deserialize(decoder: Decoder): BigInt {
21 | return decoder.decodeString().toBigInt()
22 | }
23 | }
24 |
25 | public object BigIntAsByteArraySerializer : KSerializer {
26 | @OptIn(ExperimentalSerializationApi::class)
27 | override val descriptor: SerialDescriptor =
28 | SerialDescriptor("BigInt", ByteArraySerializer().descriptor)
29 |
30 | override fun serialize(encoder: Encoder, value: BigInt) {
31 | encoder.encodeSerializableValue(ByteArraySerializer(), value.encodeToByteArray())
32 | }
33 |
34 | override fun deserialize(decoder: Decoder): BigInt {
35 | return decoder.decodeSerializableValue(ByteArraySerializer()).decodeToBigInt()
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/cryptography-bigint/src/commonMain/kotlin/hex.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | @file:JvmMultifileClass
6 | @file:JvmName("BigIntKt")
7 |
8 | package dev.whyoleg.cryptography.bigint
9 |
10 | import kotlin.jvm.*
11 |
12 | @ExperimentalStdlibApi
13 | public fun BigInt.toHexString(format: HexFormat = HexFormat.Default): String = encodeToByteArray().toHexString(format)
14 |
15 | @ExperimentalStdlibApi
16 | public fun String.hexToBigInt(format: HexFormat = HexFormat.Default): BigInt = hexToByteArray(format).decodeToBigInt()
17 |
--------------------------------------------------------------------------------
/cryptography-bigint/src/commonTest/kotlin/BigIntArrayTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.bigint
6 |
7 | import kotlin.math.*
8 | import kotlin.random.*
9 | import kotlin.test.*
10 |
11 | @OptIn(ExperimentalStdlibApi::class)
12 | class BigIntArrayTest {
13 |
14 | @Test
15 | fun testEmptyArray() {
16 | assertFails { byteArrayOf().decodeToBigInt() }
17 | }
18 |
19 | @Test
20 | fun testZeroArrays() {
21 | listOf(
22 | byteArrayOf(0),
23 | byteArrayOf(0, 0, 0),
24 | ByteArray(10000)
25 | ).forEach {
26 | val bigInt = it.decodeToBigInt()
27 | assertEquals(BigInt.ZERO, bigInt)
28 | assertEquals("0", bigInt.toString())
29 | assertContentEquals(byteArrayOf(0), bigInt.encodeToByteArray())
30 | }
31 | }
32 |
33 | @Test
34 | fun testRandomArrays() {
35 | fun test(pow: Int) {
36 | val array = Random.nextBytes(10.0.pow(pow).toInt())
37 | val bigIntFromHex = array.decodeToBigInt()
38 | val string = bigIntFromHex.toString()
39 | val hex = bigIntFromHex.toHexString()
40 | checkBigInt(bigIntFromHex, string, hex)
41 | }
42 |
43 | repeat(100) { test(2) }
44 | repeat(1000) { test(3) }
45 | repeat(50) { test(4) }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/cryptography-bigint/src/commonTest/kotlin/BigIntHexTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.bigint
6 |
7 | import kotlin.random.*
8 | import kotlin.test.*
9 |
10 | @OptIn(ExperimentalStdlibApi::class)
11 | class BigIntHexTest {
12 |
13 | @Test
14 | fun testIntSize() {
15 | repeat(1000) {
16 | val number = Random.nextInt()
17 | val padChar = if (number >= 0) '0' else 'f'
18 | val padCharInv = if (number >= 0) 'f' else '0'
19 | assertEquals(number.toHexString(), number.toBigInt().toHexString().padStart(8, padChar))
20 | assertEquals((-number).toHexString(), (-number).toBigInt().toHexString().padStart(8, padCharInv))
21 | }
22 | }
23 |
24 | @Test
25 | fun testLongSize() {
26 | repeat(1000) {
27 | val number = Random.nextLong()
28 | val padChar = if (number >= 0) '0' else 'f'
29 | val padCharInv = if (number >= 0) 'f' else '0'
30 | assertEquals(number.toHexString(), number.toBigInt().toHexString().padStart(16, padChar))
31 | assertEquals((-number).toHexString(), (-number).toBigInt().toHexString().padStart(16, padCharInv))
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/cryptography-bigint/src/jsAndWasmJsMain/kotlin/JsBigInt.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.bigint
6 |
7 | internal expect interface JsBigInt {
8 | fun convertToString(): String
9 | fun convertToString(radix: Int): String
10 | }
11 |
12 | internal expect fun jsBigInt(value: Int): JsBigInt
13 | internal expect fun jsBigInt(value: String): JsBigInt
14 |
15 | internal expect fun jsBigIntNegate(value: JsBigInt): JsBigInt
16 |
17 | internal expect fun jsBigIntSign(value: JsBigInt): Int
18 | internal expect fun jsBigIntCompareTo(a: JsBigInt, b: JsBigInt): Int
19 | internal expect fun jsBigIntEquals(a: JsBigInt, b: JsBigInt): Boolean
20 |
21 | internal expect fun jsBigIntAsInt(value: JsBigInt, bits: Int): JsBigInt
22 |
--------------------------------------------------------------------------------
/cryptography-bigint/src/jsMain/kotlin/JsBigInt.js.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.bigint
6 |
7 | internal actual external interface JsBigInt {
8 | @JsName("toString")
9 | actual fun convertToString(): String
10 |
11 | @JsName("toString")
12 | actual fun convertToString(radix: Int): String
13 | }
14 |
15 | @JsName("BigInt")
16 | internal actual external fun jsBigInt(value: Int): JsBigInt
17 |
18 | @JsName("BigInt")
19 | internal actual external fun jsBigInt(value: String): JsBigInt
20 |
21 | internal actual fun jsBigIntNegate(value: JsBigInt): JsBigInt = js("-value").unsafeCast()
22 |
23 | internal actual fun jsBigIntSign(value: JsBigInt): Int {
24 | return js(
25 | code = """
26 | if (value == 0) return 0
27 | if (value > 0) return 1
28 | return -1
29 | """
30 | ).unsafeCast()
31 | }
32 |
33 | internal actual fun jsBigIntCompareTo(a: JsBigInt, b: JsBigInt): Int {
34 | return js(
35 | code = """
36 | if (a < b) return -1
37 | if (a > b) return 1
38 | return 0
39 | """
40 | ).unsafeCast()
41 | }
42 |
43 | internal actual fun jsBigIntEquals(a: JsBigInt, b: JsBigInt): Boolean =
44 | js("a === b").unsafeCast()
45 |
46 | internal actual fun jsBigIntAsInt(value: JsBigInt, bits: Int): JsBigInt =
47 | js("BigInt.asIntN(bits, value)").unsafeCast()
48 |
--------------------------------------------------------------------------------
/cryptography-bigint/src/wasmJsMain/kotlin/JsBigInt.wasmJs.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.bigint
6 |
7 | @Suppress("ACTUAL_CLASSIFIER_MUST_HAVE_THE_SAME_SUPERTYPES_AS_NON_FINAL_EXPECT_CLASSIFIER_WARNING")
8 | internal actual external interface JsBigInt : JsAny {
9 | @JsName("toString")
10 | actual fun convertToString(): String
11 |
12 | @JsName("toString")
13 | actual fun convertToString(radix: Int): String
14 | }
15 |
16 | @JsName("BigInt")
17 | internal actual external fun jsBigInt(value: Int): JsBigInt
18 |
19 | @JsName("BigInt")
20 | internal actual external fun jsBigInt(value: String): JsBigInt
21 |
22 | internal actual fun jsBigIntNegate(value: JsBigInt): JsBigInt = js("-value")
23 |
24 | internal actual fun jsBigIntSign(value: JsBigInt): Int {
25 | js(
26 | code = """
27 | if (value == 0) return 0
28 | if (value > 0) return 1
29 | return -1
30 | """
31 | )
32 | }
33 |
34 | internal actual fun jsBigIntCompareTo(a: JsBigInt, b: JsBigInt): Int {
35 | js(
36 | code = """
37 | if (a < b) return -1
38 | if (a > b) return 1
39 | return 0
40 | """
41 | )
42 | }
43 |
44 | internal actual fun jsBigIntEquals(a: JsBigInt, b: JsBigInt): Boolean =
45 | js("a === b")
46 |
47 | internal actual fun jsBigIntAsInt(value: JsBigInt, bits: Int): JsBigInt =
48 | js("BigInt.asIntN(bits, value)")
49 |
--------------------------------------------------------------------------------
/cryptography-bom/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | plugins {
6 | `java-platform`
7 | id("ckbuild.publication")
8 | }
9 |
10 | description = "cryptography-kotlin BOM"
11 |
12 | dependencies {
13 | constraints {
14 | ckbuild.artifacts.forEach {
15 | api(project(":$it"))
16 | }
17 | }
18 | }
19 |
20 | publishing {
21 | publications {
22 | val bom by creating(MavenPublication::class) {
23 | from(components["javaPlatform"])
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/cryptography-core/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | import ckbuild.*
6 | import org.jetbrains.kotlin.gradle.*
7 |
8 | plugins {
9 | id("ckbuild.multiplatform-library")
10 | }
11 |
12 | description = "cryptography-kotlin core API"
13 |
14 | kotlin {
15 | jvmTarget()
16 | jsTarget()
17 | nativeTargets()
18 | wasmTargets()
19 |
20 | @OptIn(ExperimentalKotlinGradlePluginApi::class)
21 | applyDefaultHierarchyTemplate {
22 | common {
23 | group("nonJvm") {
24 | withJs()
25 | withWasmJs()
26 | withWasmWasi()
27 | group("native")
28 | }
29 | }
30 | }
31 |
32 | sourceSets.commonMain.dependencies {
33 | api(projects.cryptographyBigint)
34 | api(projects.cryptographyRandom)
35 | api(libs.kotlinx.io.core)
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/cryptography-core/src/commonMain/kotlin/BinarySize.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography
6 |
7 | import kotlin.jvm.*
8 |
9 | @JvmInline
10 | public value class BinarySize private constructor(private val bits: Int) : Comparable {
11 | init {
12 | require(bits >= 0) { "Value must be greater than or equal to 0" }
13 | require(bits % 8 == 0) { "Value must be a multiple of 8" }
14 | }
15 |
16 | public val inBits: Int get() = bits
17 | public val inBytes: Int get() = bits / 8
18 |
19 | public operator fun plus(other: BinarySize): BinarySize = BinarySize(bits + other.bits)
20 | public operator fun minus(other: BinarySize): BinarySize = BinarySize(bits - other.bits)
21 | public operator fun times(other: Int): BinarySize = BinarySize(bits * other)
22 | public operator fun div(other: Int): BinarySize = BinarySize(bits / other)
23 | public operator fun rem(other: Int): BinarySize = BinarySize(bits % other)
24 | public override operator fun compareTo(other: BinarySize): Int = bits.compareTo(other.bits)
25 |
26 | override fun toString(): String = "$bits bits"
27 |
28 | public companion object {
29 | public val Int.bits: BinarySize get() = BinarySize(this)
30 | public val Int.bytes: BinarySize get() = BinarySize(this * 8)
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/cryptography-core/src/commonMain/kotlin/CryptographyAlgorithm.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography
6 |
7 | @SubclassOptInRequired(CryptographyProviderApi::class)
8 | public interface CryptographyAlgorithm {
9 | public val id: CryptographyAlgorithmId<*>
10 | }
11 |
12 | @SubclassOptInRequired(CryptographyProviderApi::class)
13 | public abstract class CryptographyAlgorithmId(public val name: String)
14 |
--------------------------------------------------------------------------------
/cryptography-core/src/commonMain/kotlin/CryptographyAlgorithmNotFoundException.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography
6 |
7 | @Suppress("DEPRECATION_ERROR")
8 | @Deprecated(
9 | "IllegalStateException is throw instead",
10 | level = DeprecationLevel.ERROR
11 | )
12 | public class CryptographyAlgorithmNotFoundException(
13 | algorithm: CryptographyAlgorithmId<*>,
14 | ) : CryptographyException("Algorithm not found: $algorithm")
15 |
--------------------------------------------------------------------------------
/cryptography-core/src/commonMain/kotlin/CryptographyException.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography
6 |
7 | @Deprecated(
8 | "IllegalStateException is throw instead",
9 | level = DeprecationLevel.ERROR
10 | )
11 | public open class CryptographyException : RuntimeException {
12 | public constructor(message: String?) : super(message)
13 | public constructor(message: String?, cause: Throwable?) : super(message, cause)
14 | public constructor(cause: Throwable?) : super(cause)
15 | }
16 |
--------------------------------------------------------------------------------
/cryptography-core/src/commonMain/kotlin/CryptographyProviderApi.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography
6 |
7 | @RequiresOptIn(
8 | message = "API of everything what is implemented in providers is experimental for now and subject to change (if possible in backward-compatible way)",
9 | level = RequiresOptIn.Level.ERROR
10 | )
11 | public annotation class CryptographyProviderApi
12 |
--------------------------------------------------------------------------------
/cryptography-core/src/commonMain/kotlin/DelicateCryptographyApi.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography
6 |
7 | @RequiresOptIn(
8 | message = "API marked with this annotation should be used only when you know what you are doing. Avoid usage of such declarations as much as possible. They are provided mostly for backward compatibility with older services that require them.",
9 | level = RequiresOptIn.Level.ERROR
10 | )
11 | public annotation class DelicateCryptographyApi
12 |
--------------------------------------------------------------------------------
/cryptography-core/src/commonMain/kotlin/algorithms/Digest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | @file:OptIn(CryptographyProviderApi::class)
6 |
7 | package dev.whyoleg.cryptography.algorithms
8 |
9 | import dev.whyoleg.cryptography.*
10 | import dev.whyoleg.cryptography.operations.*
11 |
12 | //simple hash algorithms, that can be used in HMAC/ECDSA contexts
13 | @SubclassOptInRequired(CryptographyProviderApi::class)
14 | public interface Digest : CryptographyAlgorithm {
15 | override val id: CryptographyAlgorithmId
16 | public fun hasher(): Hasher
17 | }
18 |
19 | @DelicateCryptographyApi
20 | public object MD5 : CryptographyAlgorithmId("MD5")
21 |
22 | @DelicateCryptographyApi
23 | public object SHA1 : CryptographyAlgorithmId("SHA-1")
24 | public object SHA224 : CryptographyAlgorithmId("SHA-224")
25 | public object SHA256 : CryptographyAlgorithmId("SHA-256")
26 | public object SHA384 : CryptographyAlgorithmId("SHA-384")
27 | public object SHA512 : CryptographyAlgorithmId("SHA-512")
28 |
29 | @Suppress("ClassName")
30 | public object SHA3_224 : CryptographyAlgorithmId("SHA3-224")
31 |
32 | @Suppress("ClassName")
33 | public object SHA3_256 : CryptographyAlgorithmId("SHA3-256")
34 |
35 | @Suppress("ClassName")
36 | public object SHA3_384 : CryptographyAlgorithmId("SHA3-384")
37 |
38 | @Suppress("ClassName")
39 | public object SHA3_512 : CryptographyAlgorithmId("SHA3-512")
40 |
41 | @DelicateCryptographyApi
42 | public object RIPEMD160 : CryptographyAlgorithmId("RIPEMD-160")
43 |
--------------------------------------------------------------------------------
/cryptography-core/src/commonMain/kotlin/algorithms/ECDH.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.algorithms
6 |
7 | import dev.whyoleg.cryptography.*
8 | import dev.whyoleg.cryptography.operations.*
9 |
10 | @SubclassOptInRequired(CryptographyProviderApi::class)
11 | public interface ECDH : EC {
12 | override val id: CryptographyAlgorithmId get() = Companion
13 |
14 | public companion object : CryptographyAlgorithmId("ECDH")
15 |
16 | @SubclassOptInRequired(CryptographyProviderApi::class)
17 | public interface KeyPair : EC.KeyPair
18 |
19 | @SubclassOptInRequired(CryptographyProviderApi::class)
20 | public interface PublicKey : EC.PublicKey {
21 | public fun sharedSecretGenerator(): SharedSecretGenerator
22 | }
23 |
24 | @SubclassOptInRequired(CryptographyProviderApi::class)
25 | public interface PrivateKey : EC.PrivateKey {
26 | public fun sharedSecretGenerator(): SharedSecretGenerator
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/cryptography-core/src/commonMain/kotlin/algorithms/ECDSA.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.algorithms
6 |
7 | import dev.whyoleg.cryptography.*
8 | import dev.whyoleg.cryptography.operations.*
9 |
10 | @SubclassOptInRequired(CryptographyProviderApi::class)
11 | public interface ECDSA : EC {
12 | override val id: CryptographyAlgorithmId get() = Companion
13 |
14 | public companion object : CryptographyAlgorithmId("ECDSA")
15 |
16 | @SubclassOptInRequired(CryptographyProviderApi::class)
17 | public interface KeyPair : EC.KeyPair
18 |
19 | @SubclassOptInRequired(CryptographyProviderApi::class)
20 | public interface PublicKey : EC.PublicKey {
21 | public fun signatureVerifier(
22 | digest: CryptographyAlgorithmId,
23 | format: SignatureFormat,
24 | ): SignatureVerifier
25 | }
26 |
27 | @SubclassOptInRequired(CryptographyProviderApi::class)
28 | public interface PrivateKey : EC.PrivateKey {
29 | public fun signatureGenerator(
30 | digest: CryptographyAlgorithmId,
31 | format: SignatureFormat,
32 | ): SignatureGenerator
33 | }
34 |
35 | public enum class SignatureFormat {
36 | //IEEE P1363 / X9.63 format
37 | RAW,
38 |
39 | //X.509 format
40 | DER
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/cryptography-core/src/commonMain/kotlin/algorithms/HKDF.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.algorithms
6 |
7 | import dev.whyoleg.cryptography.*
8 | import dev.whyoleg.cryptography.operations.*
9 | import kotlinx.io.bytestring.*
10 |
11 | @SubclassOptInRequired(CryptographyProviderApi::class)
12 | public interface HKDF : CryptographyAlgorithm {
13 | override val id: CryptographyAlgorithmId get() = Companion
14 |
15 | public companion object : CryptographyAlgorithmId("HKDF")
16 |
17 | public fun secretDerivation(
18 | digest: CryptographyAlgorithmId,
19 | outputSize: BinarySize,
20 | salt: ByteArray?,
21 | info: ByteArray? = null,
22 | ): SecretDerivation
23 |
24 | public fun secretDerivation(
25 | digest: CryptographyAlgorithmId,
26 | outputSize: BinarySize,
27 | salt: ByteString?,
28 | info: ByteString? = null,
29 | ): SecretDerivation = secretDerivation(digest, outputSize, salt?.asByteArray(), info?.asByteArray())
30 | }
31 |
--------------------------------------------------------------------------------
/cryptography-core/src/commonMain/kotlin/algorithms/HMAC.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.algorithms
6 |
7 | import dev.whyoleg.cryptography.*
8 | import dev.whyoleg.cryptography.materials.key.*
9 | import dev.whyoleg.cryptography.operations.*
10 |
11 | @SubclassOptInRequired(CryptographyProviderApi::class)
12 | public interface HMAC : CryptographyAlgorithm {
13 | override val id: CryptographyAlgorithmId get() = Companion
14 |
15 | public companion object : CryptographyAlgorithmId("HMAC")
16 |
17 | public fun keyDecoder(digest: CryptographyAlgorithmId): KeyDecoder
18 | public fun keyGenerator(digest: CryptographyAlgorithmId = SHA512): KeyGenerator
19 |
20 | @SubclassOptInRequired(CryptographyProviderApi::class)
21 | public interface Key : EncodableKey {
22 | public fun signatureGenerator(): SignatureGenerator
23 | public fun signatureVerifier(): SignatureVerifier
24 |
25 | public enum class Format : KeyFormat { RAW, JWK }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/cryptography-core/src/commonMain/kotlin/algorithms/PBKDF2.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.algorithms
6 |
7 | import dev.whyoleg.cryptography.*
8 | import dev.whyoleg.cryptography.operations.*
9 | import kotlinx.io.bytestring.*
10 |
11 | @SubclassOptInRequired(CryptographyProviderApi::class)
12 | public interface PBKDF2 : CryptographyAlgorithm {
13 | override val id: CryptographyAlgorithmId get() = Companion
14 |
15 | public companion object : CryptographyAlgorithmId("PBKDF2")
16 |
17 | public fun secretDerivation(
18 | digest: CryptographyAlgorithmId,
19 | iterations: Int,
20 | outputSize: BinarySize,
21 | salt: ByteArray,
22 | ): SecretDerivation
23 |
24 | public fun secretDerivation(
25 | digest: CryptographyAlgorithmId,
26 | iterations: Int,
27 | outputSize: BinarySize,
28 | salt: ByteString,
29 | ): SecretDerivation = secretDerivation(digest, iterations, outputSize, salt.asByteArray())
30 | }
31 |
--------------------------------------------------------------------------------
/cryptography-core/src/commonMain/kotlin/algorithms/asymmetric/deprecated.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.algorithms.asymmetric
6 |
7 | @Deprecated(
8 | "Moved to another package",
9 | ReplaceWith("EC", "dev.whyoleg.cryptography.algorithms.EC"),
10 | DeprecationLevel.ERROR
11 | )
12 | public typealias EC = dev.whyoleg.cryptography.algorithms.EC
13 |
14 | @Deprecated(
15 | "Moved to another package",
16 | ReplaceWith("ECDSA", "dev.whyoleg.cryptography.algorithms.ECDSA"),
17 | DeprecationLevel.ERROR
18 | )
19 | public typealias ECDSA = dev.whyoleg.cryptography.algorithms.ECDSA
20 |
21 | @Deprecated(
22 | "Moved to another package",
23 | ReplaceWith("RSA", "dev.whyoleg.cryptography.algorithms.RSA"),
24 | DeprecationLevel.ERROR
25 | )
26 | public typealias RSA = dev.whyoleg.cryptography.algorithms.RSA
27 |
--------------------------------------------------------------------------------
/cryptography-core/src/commonMain/kotlin/algorithms/symmetric/SymmetricKeySize.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.algorithms.symmetric
6 |
7 | import dev.whyoleg.cryptography.*
8 | import dev.whyoleg.cryptography.BinarySize.Companion.bits
9 | import kotlin.jvm.*
10 |
11 | @Suppress("DEPRECATION_ERROR")
12 | @Deprecated(
13 | "Replaced by BinarySize as wrapper class is not needed",
14 | ReplaceWith("BinarySize", "dev.whyoleg.cryptography.BinarySize"),
15 | DeprecationLevel.ERROR
16 | )
17 | @JvmInline
18 | public value class SymmetricKeySize
19 | @Deprecated(
20 | "Replaced by BinarySize as wrapper class is not needed",
21 | ReplaceWith("value"),
22 | DeprecationLevel.ERROR
23 | )
24 | constructor(public val value: BinarySize) {
25 | @Deprecated(
26 | "Replaced by AES.Key.Size as it's not really needed outside of AES",
27 | ReplaceWith("AES.Key.Size", "dev.whyoleg.cryptography.algorithms.AES"),
28 | DeprecationLevel.ERROR
29 | )
30 | public companion object {
31 | public val B128: SymmetricKeySize get() = SymmetricKeySize(128.bits)
32 | public val B192: SymmetricKeySize get() = SymmetricKeySize(192.bits)
33 | public val B256: SymmetricKeySize get() = SymmetricKeySize(256.bits)
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/cryptography-core/src/commonMain/kotlin/algorithms/symmetric/deprecated.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.algorithms.symmetric
6 |
7 | @Deprecated(
8 | "Moved to another package",
9 | ReplaceWith("AES", "dev.whyoleg.cryptography.algorithms.AES"),
10 | DeprecationLevel.ERROR
11 | )
12 | public typealias AES = dev.whyoleg.cryptography.algorithms.AES
13 |
14 | @Deprecated(
15 | "Moved to another package",
16 | ReplaceWith("HMAC", "dev.whyoleg.cryptography.algorithms.HMAC"),
17 | DeprecationLevel.ERROR
18 | )
19 | public typealias HMAC = dev.whyoleg.cryptography.algorithms.HMAC
20 |
--------------------------------------------------------------------------------
/cryptography-core/src/commonMain/kotlin/materials/key/EncodableKey.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.materials.key
6 |
7 | import dev.whyoleg.cryptography.*
8 | import kotlinx.io.bytestring.*
9 |
10 | @SubclassOptInRequired(CryptographyProviderApi::class)
11 | public interface EncodableKey : Key {
12 | public suspend fun encodeToByteArray(format: KF): ByteArray = encodeToByteArrayBlocking(format)
13 | public fun encodeToByteArrayBlocking(format: KF): ByteArray
14 |
15 | public suspend fun encodeToByteString(format: KF): ByteString = encodeToByteArray(format).asByteString()
16 | public fun encodeToByteStringBlocking(format: KF): ByteString = encodeToByteArrayBlocking(format).asByteString()
17 |
18 | @Deprecated(
19 | "Renamed to encodeToByteArray",
20 | ReplaceWith("encodeToByteArray(format)"),
21 | level = DeprecationLevel.ERROR,
22 | )
23 | public suspend fun encodeTo(format: KF): ByteArray = encodeToByteArray(format)
24 |
25 | @Deprecated(
26 | "Renamed to encodeToByteArrayBlocking",
27 | ReplaceWith("encodeToByteArrayBlocking(format)"),
28 | level = DeprecationLevel.ERROR,
29 | )
30 | public fun encodeToBlocking(format: KF): ByteArray = encodeToByteArrayBlocking(format)
31 | }
32 |
--------------------------------------------------------------------------------
/cryptography-core/src/commonMain/kotlin/materials/key/Key.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.materials.key
6 |
7 | import dev.whyoleg.cryptography.*
8 |
9 | @SubclassOptInRequired(CryptographyProviderApi::class)
10 | public interface Key
11 |
--------------------------------------------------------------------------------
/cryptography-core/src/commonMain/kotlin/materials/key/KeyDecoder.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.materials.key
6 |
7 | import dev.whyoleg.cryptography.*
8 | import kotlinx.io.bytestring.*
9 |
10 | @SubclassOptInRequired(CryptographyProviderApi::class)
11 | public interface KeyDecoder {
12 | public suspend fun decodeFromByteArray(format: KF, bytes: ByteArray): K = decodeFromByteArrayBlocking(format, bytes)
13 | public fun decodeFromByteArrayBlocking(format: KF, bytes: ByteArray): K
14 |
15 | public suspend fun decodeFromByteString(format: KF, byteString: ByteString): K =
16 | decodeFromByteArray(format, byteString.asByteArray())
17 |
18 | public fun decodeFromByteStringBlocking(format: KF, byteString: ByteString): K =
19 | decodeFromByteArrayBlocking(format, byteString.asByteArray())
20 |
21 | @Deprecated(
22 | "Renamed to decodeFromByteArray",
23 | ReplaceWith("decodeFromByteArray(format, data)"),
24 | level = DeprecationLevel.ERROR,
25 | )
26 | public suspend fun decodeFrom(format: KF, data: ByteArray): K = decodeFromByteArray(format, data)
27 |
28 | @Deprecated(
29 | "Renamed to decodeFromByteArrayBlocking",
30 | ReplaceWith("decodeFromByteArrayBlocking(format, data)"),
31 | level = DeprecationLevel.ERROR,
32 | )
33 | public fun decodeFromBlocking(format: KF, data: ByteArray): K = decodeFromByteArrayBlocking(format, data)
34 | }
35 |
--------------------------------------------------------------------------------
/cryptography-core/src/commonMain/kotlin/materials/key/KeyFormat.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.materials.key
6 |
7 | import dev.whyoleg.cryptography.*
8 |
9 | @SubclassOptInRequired(CryptographyProviderApi::class)
10 | public interface KeyFormat {
11 | public val name: String
12 | override fun toString(): String
13 | }
14 |
--------------------------------------------------------------------------------
/cryptography-core/src/commonMain/kotlin/materials/key/KeyGenerator.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.materials.key
6 |
7 | import dev.whyoleg.cryptography.*
8 |
9 | @SubclassOptInRequired(CryptographyProviderApi::class)
10 | public interface KeyGenerator {
11 | public suspend fun generateKey(): K = generateKeyBlocking()
12 | public fun generateKeyBlocking(): K
13 | }
14 |
--------------------------------------------------------------------------------
/cryptography-core/src/commonMain/kotlin/operations/SecretDerivation.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.operations
6 |
7 | import dev.whyoleg.cryptography.*
8 | import kotlinx.io.bytestring.*
9 |
10 | @SubclassOptInRequired(CryptographyProviderApi::class)
11 | public interface SecretDerivation {
12 | public suspend fun deriveSecretToByteArray(input: ByteArray): ByteArray {
13 | return deriveSecretToByteArrayBlocking(input)
14 | }
15 |
16 | public suspend fun deriveSecretToByteArray(input: ByteString): ByteArray {
17 | return deriveSecretToByteArray(input.asByteArray())
18 | }
19 |
20 | public suspend fun deriveSecret(input: ByteArray): ByteString {
21 | return deriveSecretToByteArray(input).asByteString()
22 | }
23 |
24 | public suspend fun deriveSecret(input: ByteString): ByteString {
25 | return deriveSecretToByteArray(input.asByteArray()).asByteString()
26 | }
27 |
28 | public fun deriveSecretToByteArrayBlocking(input: ByteArray): ByteArray
29 |
30 | public fun deriveSecretToByteArrayBlocking(input: ByteString): ByteArray {
31 | return deriveSecretToByteArrayBlocking(input.asByteArray())
32 | }
33 |
34 | public fun deriveSecretBlocking(input: ByteArray): ByteString {
35 | return deriveSecretToByteArrayBlocking(input).asByteString()
36 | }
37 |
38 | public fun deriveSecretBlocking(input: ByteString): ByteString {
39 | return deriveSecretToByteArrayBlocking(input.asByteArray()).asByteString()
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/cryptography-core/src/commonMain/kotlin/operations/SharedSecretGenerator.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.operations
6 |
7 | import dev.whyoleg.cryptography.*
8 | import dev.whyoleg.cryptography.materials.key.*
9 | import kotlinx.io.bytestring.*
10 |
11 | @SubclassOptInRequired(CryptographyProviderApi::class)
12 | public interface SharedSecretGenerator {
13 | public suspend fun generateSharedSecretToByteArray(other: K): ByteArray {
14 | return generateSharedSecretToByteArrayBlocking(other)
15 | }
16 |
17 | public suspend fun generateSharedSecret(other: K): ByteString {
18 | return generateSharedSecretToByteArray(other).asByteString()
19 | }
20 |
21 | public fun generateSharedSecretToByteArrayBlocking(other: K): ByteArray
22 |
23 | public fun generateSharedSecretBlocking(other: K): ByteString {
24 | return generateSharedSecretToByteArrayBlocking(other).asByteString()
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/cryptography-core/src/commonMain/kotlin/operations/hash/deprecated.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.operations.hash
6 |
7 | @Deprecated(
8 | "Moved to another package",
9 | ReplaceWith("Hasher", "dev.whyoleg.cryptography.operations.Hasher"),
10 | DeprecationLevel.ERROR
11 | )
12 | public typealias Hasher = dev.whyoleg.cryptography.operations.Hasher
13 |
--------------------------------------------------------------------------------
/cryptography-core/src/commonMain/kotlin/operations/signature/deprecated.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.operations.signature
6 |
7 | @Deprecated(
8 | "Moved to another package",
9 | ReplaceWith("SignatureGenerator", "dev.whyoleg.cryptography.operations.SignatureGenerator"),
10 | DeprecationLevel.ERROR
11 | )
12 | public typealias SignatureGenerator = dev.whyoleg.cryptography.operations.SignatureGenerator
13 |
14 | @Deprecated(
15 | "Moved to another package",
16 | ReplaceWith("SignatureVerifier", "dev.whyoleg.cryptography.operations.SignatureVerifier"),
17 | DeprecationLevel.ERROR
18 | )
19 | public typealias SignatureVerifier = dev.whyoleg.cryptography.operations.SignatureVerifier
20 |
--------------------------------------------------------------------------------
/cryptography-core/src/commonMain/kotlin/unsafe.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography
6 |
7 | import kotlinx.io.bytestring.*
8 | import kotlinx.io.bytestring.unsafe.*
9 |
10 | @Suppress("NOTHING_TO_INLINE")
11 | @OptIn(UnsafeByteStringApi::class)
12 | internal inline fun ByteArray.asByteString(): ByteString {
13 | return UnsafeByteStringOperations.wrapUnsafe(this)
14 | }
15 |
16 | @Suppress("NOTHING_TO_INLINE")
17 | @OptIn(UnsafeByteStringApi::class)
18 | internal inline fun ByteString.asByteArray(): ByteArray {
19 | UnsafeByteStringOperations.withByteArrayUnsafe(this) { return it }
20 | }
21 |
--------------------------------------------------------------------------------
/cryptography-core/src/jvmMain/kotlin/CryptographyProvider.jvm.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography
6 |
7 | import java.util.*
8 |
9 | @CryptographyProviderApi
10 | public interface CryptographyProviderContainer {
11 | public val provider: Lazy
12 | }
13 |
14 | @OptIn(CryptographyProviderApi::class)
15 | internal actual fun initProviders(): List> = Iterable {
16 | ServiceLoader.load(
17 | CryptographyProviderContainer::class.java,
18 | CryptographyProviderContainer::class.java.classLoader
19 | ).iterator()
20 | }.map { it.provider }
21 |
--------------------------------------------------------------------------------
/cryptography-core/src/nonJvmMain/kotlin/CryptographyProvider.nonJvm.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography
6 |
7 | internal actual fun initProviders(): List> = emptyList()
8 |
--------------------------------------------------------------------------------
/cryptography-providers-tests-api/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/cryptography-providers-tests-api/src/androidMain/kotlin/TestPlatform.android.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.tests.api
6 |
7 | import android.os.*
8 |
9 | internal actual val currentTestPlatform: TestPlatform = TestPlatform.Android(
10 | apiLevel = Build.VERSION.SDK_INT
11 | )
12 |
--------------------------------------------------------------------------------
/cryptography-providers-tests-api/src/commonMain/kotlin/AlgorithmTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.tests.api
6 |
7 | import dev.whyoleg.cryptography.*
8 | import kotlinx.coroutines.test.*
9 |
10 | abstract class AlgorithmTest(
11 | protected val algorithmId: CryptographyAlgorithmId,
12 | provider: CryptographyProvider,
13 | ) : ProviderTest(provider) {
14 | fun testWithAlgorithm(
15 | block: suspend AlgorithmTestScope.() -> Unit,
16 | ): TestResult = testWithAlgorithm(algorithmId, block)
17 | }
18 |
--------------------------------------------------------------------------------
/cryptography-providers-tests-api/src/commonMain/kotlin/TestContext.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.tests.api
6 |
7 | import kotlinx.serialization.*
8 |
9 | @Serializable
10 | data class TestContext(
11 | val platform: TestPlatform,
12 | val provider: TestProvider,
13 | )
14 |
--------------------------------------------------------------------------------
/cryptography-providers-tests-api/src/commonMain/kotlin/TestLogger.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.tests.api
6 |
7 | class TestLogger(
8 | private val enabled: Boolean,
9 | private val tag: String?,
10 | ) {
11 |
12 | fun child(tag: String): TestLogger = TestLogger(
13 | enabled = enabled,
14 | tag = when (this.tag) {
15 | null -> tag
16 | else -> "${this.tag}|$tag"
17 | }
18 | )
19 |
20 | fun print(message: String) {
21 | println(buildString {
22 | append("[TEST")
23 | if (tag != null) append("|").append(tag)
24 | append("] ")
25 | append(message)
26 | })
27 | }
28 |
29 | fun log(message: () -> String) {
30 | if (enabled) print(message())
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/cryptography-providers-tests-api/src/commonMain/kotlin/TestScope.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.tests.api
6 |
7 | import dev.whyoleg.cryptography.*
8 |
9 | open class TestScope(
10 | val logger: TestLogger,
11 | )
12 |
13 | open class ProviderTestScope(
14 | logger: TestLogger,
15 | val context: TestContext,
16 | val provider: CryptographyProvider,
17 | ) : TestScope(logger)
18 |
19 | open class AlgorithmTestScope(
20 | logger: TestLogger,
21 | context: TestContext,
22 | provider: CryptographyProvider,
23 | val algorithm: A,
24 | ) : ProviderTestScope(logger, context, provider)
25 |
--------------------------------------------------------------------------------
/cryptography-providers-tests-api/src/commonMain/kotlin/compatibility/ByteStringAsStringSerializer.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.tests.api.compatibility
6 |
7 | import kotlinx.io.bytestring.*
8 | import kotlinx.serialization.*
9 | import kotlinx.serialization.descriptors.*
10 | import kotlinx.serialization.encoding.*
11 | import kotlin.io.encoding.*
12 |
13 | typealias ByteStringAsString = @Serializable(ByteStringAsStringSerializer::class) ByteString
14 |
15 | internal object ByteStringAsStringSerializer : KSerializer {
16 | override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("ByteString#Base64", PrimitiveKind.STRING)
17 | override fun deserialize(decoder: Decoder): ByteString = Base64.decodeToByteString(decoder.decodeString())
18 | override fun serialize(encoder: Encoder, value: ByteString): Unit = encoder.encodeString(Base64.encode(value))
19 | }
20 |
--------------------------------------------------------------------------------
/cryptography-providers-tests-api/src/commonMain/kotlin/compatibility/CompatibilityApi.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.tests.api.compatibility
6 |
7 | sealed class CompatibilityApi {
8 | abstract val keys: CompatibilityStorageApi
9 | abstract val keyPairs: CompatibilityStorageApi
10 | abstract val digests: CompatibilityStorageApi
11 | abstract val signatures: CompatibilityStorageApi
12 | abstract val ciphers: CompatibilityStorageApi
13 | abstract val sharedSecrets: CompatibilityStorageApi
14 | abstract val derivedSecrets: CompatibilityStorageApi
15 | }
16 |
--------------------------------------------------------------------------------
/cryptography-providers-tests-api/src/commonMain/kotlin/compatibility/CompatibilityTestScope.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.tests.api.compatibility
6 |
7 | import dev.whyoleg.cryptography.*
8 | import dev.whyoleg.cryptography.providers.tests.api.*
9 |
10 | open class CompatibilityTestScope(
11 | logger: TestLogger,
12 | context: TestContext,
13 | provider: CryptographyProvider,
14 | algorithm: A,
15 | val api: CompatibilityApi,
16 | ) : AlgorithmTestScope(logger, context, provider, algorithm)
17 |
--------------------------------------------------------------------------------
/cryptography-providers-tests-api/src/jsMain/kotlin/utils.js.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.tests.api
6 |
7 | actual fun disableJsConsoleDebug() {
8 | eval("console.debug = function(){}")
9 | }
10 |
--------------------------------------------------------------------------------
/cryptography-providers-tests-api/src/jvmMain/kotlin/TestPlatform.jvm.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.tests.api
6 |
7 | internal actual val currentTestPlatform: TestPlatform = run {
8 | val version = System.getProperty("java.version") ?: ""
9 | TestPlatform.JDK(
10 | major = when (val major = version.substringBefore(".").toIntOrNull() ?: -1) {
11 | 1 -> 8
12 | else -> major
13 | },
14 | version = version,
15 | os = System.getProperty("os.name") ?: "",
16 | arch = System.getProperty("os.arch") ?: ""
17 | )
18 | }
19 |
--------------------------------------------------------------------------------
/cryptography-providers-tests-api/src/nativeMain/kotlin/TestPlatform.native.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.tests.api
6 |
7 | import kotlin.experimental.*
8 |
9 | @OptIn(ExperimentalNativeApi::class)
10 | internal actual val currentTestPlatform: TestPlatform = TestPlatform.Native(
11 | os = Platform.osFamily.toString(),
12 | arch = Platform.cpuArchitecture.toString(),
13 | debug = Platform.isDebugBinary
14 | )
15 |
--------------------------------------------------------------------------------
/cryptography-providers-tests-api/src/nonJsMain/kotlin/utils.nonJs.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.tests.api
6 |
7 | actual fun disableJsConsoleDebug() {
8 | //no-op, needed only for JS
9 | }
10 |
--------------------------------------------------------------------------------
/cryptography-providers-tests/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | import ckbuild.*
6 | import org.jetbrains.kotlin.gradle.*
7 |
8 | plugins {
9 | id("ckbuild.multiplatform-base")
10 | id("ckbuild.multiplatform-android")
11 |
12 | id("org.jetbrains.kotlin.plugin.serialization")
13 | }
14 |
15 | @OptIn(ExperimentalKotlinGradlePluginApi::class)
16 | kotlin {
17 | jvmTarget()
18 | jsTarget()
19 | nativeTargets()
20 | wasmJsTarget()
21 |
22 | compilerOptions {
23 | optIn.addAll(
24 | OptIns.DelicateCryptographyApi,
25 | OptIns.CryptographyProviderApi,
26 |
27 | OptIns.ExperimentalStdlibApi,
28 | OptIns.ExperimentalEncodingApi,
29 | )
30 | }
31 |
32 | sourceSets {
33 | commonMain.dependencies {
34 | api(projects.cryptographyProvidersTestsApi)
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/cryptography-providers-tests/src/commonMain/kotlin/DefaultProviderTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.tests
6 |
7 | import dev.whyoleg.cryptography.*
8 | import kotlin.test.*
9 |
10 | abstract class DefaultProviderTest(private val provider: CryptographyProvider) {
11 | @Test
12 | fun test() {
13 | assertEquals(CryptographyProvider.Default.name, provider.name)
14 | assertEquals(CryptographyProvider.Default, provider)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/cryptography-providers-tests/src/commonMain/kotlin/default/AesCmacTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.tests.default
6 |
7 | import dev.whyoleg.cryptography.*
8 | import dev.whyoleg.cryptography.algorithms.*
9 | import dev.whyoleg.cryptography.random.*
10 | import kotlin.test.*
11 |
12 | abstract class AesCmacTest(provider: CryptographyProvider) : AesBasedTest(AES.CMAC, provider) {
13 |
14 | @Test
15 | fun verifyResult() = runTestForEachKeySize {
16 | val key = algorithm.keyGenerator(keySize).generateKey()
17 | val data = CryptographyRandom.nextBytes(100)
18 | val signature = key.signatureGenerator().generateSignature(data)
19 | assertTrue(key.signatureVerifier().tryVerifySignature(data, signature))
20 | }
21 | }
--------------------------------------------------------------------------------
/cryptography-providers-tests/src/commonMain/kotlin/default/AesCtrTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.tests.default
6 |
7 | import dev.whyoleg.cryptography.*
8 | import dev.whyoleg.cryptography.algorithms.*
9 | import dev.whyoleg.cryptography.providers.tests.api.*
10 | import dev.whyoleg.cryptography.random.*
11 | import kotlinx.io.bytestring.*
12 | import kotlin.test.*
13 |
14 | private const val ivSize = 16
15 |
16 | abstract class AesCtrTest(provider: CryptographyProvider) : AesBasedTest(AES.CTR, provider) {
17 | @Test
18 | fun testFunctions() = runTestForEachKeySize {
19 | if (!supportsFunctions()) return@runTestForEachKeySize
20 |
21 | val key = algorithm.keyGenerator(keySize).generateKey()
22 | val cipher = key.cipher()
23 | repeat(100) {
24 | val size = CryptographyRandom.nextInt(20000)
25 | val data = ByteString(CryptographyRandom.nextBytes(size))
26 | assertCipherViaFunction(cipher, cipher, data)
27 | }
28 | }
29 |
30 | @Test
31 | fun testFunctionsWithIv() = runTestForEachKeySize {
32 | if (!supportsFunctions()) return@runTestForEachKeySize
33 |
34 | val key = algorithm.keyGenerator(keySize).generateKey()
35 | val cipher = key.cipher()
36 | repeat(100) {
37 | val size = CryptographyRandom.nextInt(20000)
38 | val data = ByteString(CryptographyRandom.nextBytes(size))
39 | assertCipherWithIvViaFunction(cipher, cipher, ivSize, data)
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/cryptography-providers-tests/src/commonMain/kotlin/default/CipherTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.tests.default
6 |
7 | import dev.whyoleg.cryptography.operations.*
8 | import dev.whyoleg.cryptography.providers.tests.api.*
9 | import kotlinx.io.*
10 | import kotlinx.io.bytestring.*
11 |
12 | interface CipherTest {
13 | suspend fun AlgorithmTestScope<*>.assertCipherViaFunction(
14 | encryptor: Encryptor,
15 | decryptor: Decryptor,
16 | plaintext: ByteString,
17 | ) {
18 | listOf(
19 | encryptor.encrypt(plaintext),
20 | encryptor.encryptingSource(Buffer(plaintext).bufferedSource()).buffered().use { it.readByteString() },
21 | Buffer().also { output ->
22 | encryptor.encryptingSink(output.bufferedSink()).buffered().use { it.write(plaintext) }
23 | }.readByteString(),
24 | ).forEach { ciphertext ->
25 | assertContentEquals(plaintext, decryptor.decrypt(ciphertext))
26 | assertContentEquals(
27 | plaintext,
28 | decryptor.decryptingSource(Buffer(ciphertext).bufferedSource()).buffered().use { it.readByteString() }
29 | )
30 | assertContentEquals(
31 | plaintext,
32 | Buffer().also { output ->
33 | decryptor.decryptingSink(output.bufferedSink()).buffered().use { it.write(ciphertext) }
34 | }.readByteString()
35 | )
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/cryptography-providers/apple/api/cryptography-provider-apple.klib.api:
--------------------------------------------------------------------------------
1 | // Klib ABI Dump
2 | // Targets: [iosArm64, iosSimulatorArm64, iosX64, macosArm64, macosX64, tvosArm64, tvosSimulatorArm64, tvosX64, watchosArm32, watchosArm64, watchosDeviceArm64, watchosSimulatorArm64, watchosX64]
3 | // Rendering settings:
4 | // - Signature version: 2
5 | // - Show manifest properties: true
6 | // - Show declarations: true
7 |
8 | // Library unique name:
9 | final val dev.whyoleg.cryptography.providers.apple/Apple // dev.whyoleg.cryptography.providers.apple/Apple|@dev.whyoleg.cryptography.CryptographyProvider.Companion{}Apple[0]
10 | final fun (dev.whyoleg.cryptography/CryptographyProvider.Companion).(): dev.whyoleg.cryptography/CryptographyProvider // dev.whyoleg.cryptography.providers.apple/Apple.|@dev.whyoleg.cryptography.CryptographyProvider.Companion(){}[0]
11 |
--------------------------------------------------------------------------------
/cryptography-providers/apple/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | import ckbuild.*
6 | import org.jetbrains.kotlin.gradle.*
7 |
8 | plugins {
9 | id("ckbuild.multiplatform-library")
10 | id("ckbuild.multiplatform-provider-tests")
11 | }
12 |
13 | description = "cryptography-kotlin Apple provider"
14 |
15 | @OptIn(ExperimentalKotlinGradlePluginApi::class)
16 | kotlin {
17 | appleTargets()
18 |
19 | compilerOptions {
20 | optIn.addAll(
21 | OptIns.DelicateCryptographyApi,
22 | OptIns.CryptographyProviderApi,
23 |
24 | OptIns.ExperimentalForeignApi,
25 | )
26 | }
27 |
28 | sourceSets.commonMain.dependencies {
29 | api(projects.cryptographyCore)
30 | implementation(projects.cryptographyProviderBase)
31 | }
32 | }
33 |
34 | providerTests {
35 | packageName.set("dev.whyoleg.cryptography.providers.apple")
36 | providerInitializers.put("Apple", "CryptographyProvider.Apple")
37 | }
38 |
--------------------------------------------------------------------------------
/cryptography-providers/apple/src/commonMain/kotlin/algorithms/CCAes.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.apple.algorithms
6 |
7 | import dev.whyoleg.cryptography.*
8 | import dev.whyoleg.cryptography.algorithms.*
9 | import dev.whyoleg.cryptography.materials.key.*
10 | import dev.whyoleg.cryptography.random.*
11 |
12 | internal abstract class CCAes : AES {
13 | protected abstract fun wrapKey(key: ByteArray): K
14 |
15 | final override fun keyDecoder(): KeyDecoder = AesKeyDecoder()
16 |
17 | final override fun keyGenerator(keySize: BinarySize): KeyGenerator =
18 | AesCtrKeyGenerator(keySize.inBytes)
19 |
20 | private inner class AesKeyDecoder : KeyDecoder {
21 | override fun decodeFromByteArrayBlocking(format: AES.Key.Format, bytes: ByteArray): K = when (format) {
22 | AES.Key.Format.RAW -> {
23 | require(bytes.size == 16 || bytes.size == 24 || bytes.size == 32) {
24 | "AES key size must be 128, 192 or 256 bits"
25 | }
26 | wrapKey(bytes.copyOf())
27 | }
28 | AES.Key.Format.JWK -> error("JWK is not supported")
29 | }
30 | }
31 |
32 | private inner class AesCtrKeyGenerator(private val keySizeBytes: Int) : KeyGenerator {
33 | override fun generateKeyBlocking(): K {
34 | val key = CryptographyRandom.nextBytes(keySizeBytes)
35 | return wrapKey(key)
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/cryptography-providers/apple/src/commonMain/kotlin/algorithms/CCAesCbc.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.apple.algorithms
6 |
7 | import dev.whyoleg.cryptography.algorithms.*
8 | import platform.CoreCrypto.*
9 |
10 | internal object CCAesCbc : CCAes(), AES.CBC {
11 | override fun wrapKey(key: ByteArray): AES.CBC.Key = AesCbcKey(key)
12 |
13 | private class AesCbcKey(private val key: ByteArray) : AES.CBC.Key {
14 | override fun cipher(padding: Boolean): AES.IvCipher = CCAesIvCipher(
15 | algorithm = kCCAlgorithmAES,
16 | mode = kCCModeCBC,
17 | padding = if (padding) ccPKCS7Padding else ccNoPadding,
18 | key = key,
19 | ivSize = 16
20 | ) {
21 | require(it % kCCBlockSizeAES128.toInt() == 0) { "Ciphertext is not padded" }
22 | }
23 |
24 | override fun encodeToByteArrayBlocking(format: AES.Key.Format): ByteArray = when (format) {
25 | AES.Key.Format.RAW -> key.copyOf()
26 | AES.Key.Format.JWK -> error("JWK is not supported")
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/cryptography-providers/apple/src/commonMain/kotlin/algorithms/CCAesCtr.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.apple.algorithms
6 |
7 | import dev.whyoleg.cryptography.algorithms.*
8 | import kotlinx.cinterop.*
9 | import platform.CoreCrypto.*
10 |
11 | internal object CCAesCtr : CCAes(), AES.CTR {
12 | override fun wrapKey(key: ByteArray): AES.CTR.Key = AesCtrKey(key)
13 |
14 | private class AesCtrKey(private val key: ByteArray) : AES.CTR.Key {
15 | override fun cipher(): AES.IvCipher = CCAesIvCipher(
16 | algorithm = kCCAlgorithmAES,
17 | mode = kCCModeCTR,
18 | padding = 0.convert(), // not applicable
19 | key = key,
20 | ivSize = 16
21 | )
22 |
23 | override fun encodeToByteArrayBlocking(format: AES.Key.Format): ByteArray = when (format) {
24 | AES.Key.Format.RAW -> key.copyOf()
25 | AES.Key.Format.JWK -> error("JWK is not supported")
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/cryptography-providers/apple/src/commonMain/kotlin/algorithms/CCHkdf.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.apple.algorithms
6 |
7 | import dev.whyoleg.cryptography.*
8 | import dev.whyoleg.cryptography.algorithms.*
9 | import dev.whyoleg.cryptography.providers.apple.*
10 | import dev.whyoleg.cryptography.providers.base.algorithms.*
11 | import platform.CoreCrypto.*
12 |
13 | internal object CCHkdf : BaseHkdf(AppleCryptographyProvider) {
14 | override fun digestSize(digest: CryptographyAlgorithmId): Int {
15 | return when (digest) {
16 | SHA1 -> CC_SHA1_DIGEST_LENGTH
17 | SHA224 -> CC_SHA224_DIGEST_LENGTH
18 | SHA256 -> CC_SHA256_DIGEST_LENGTH
19 | SHA384 -> CC_SHA384_DIGEST_LENGTH
20 | SHA512 -> CC_SHA512_DIGEST_LENGTH
21 | else -> throw IllegalStateException("Unsupported hash algorithm: $digest")
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/cryptography-providers/apple/src/commonMain/kotlin/internal/SecCipherFunction.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024-2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.apple.internal
6 |
7 | import dev.whyoleg.cryptography.providers.base.*
8 | import dev.whyoleg.cryptography.providers.base.operations.*
9 | import kotlinx.cinterop.*
10 | import platform.CoreFoundation.*
11 | import platform.Foundation.*
12 | import platform.Security.*
13 |
14 | internal fun SecCipherFunction(
15 | key: SecKeyRef,
16 | algorithm: SecKeyAlgorithm?,
17 | finalizer: (SecKeyRef?, SecKeyAlgorithm?, CFDataRef?, error: CValuesRef) -> CFDataRef?,
18 | ): CipherFunction = AccumulatingCipherFunction { input ->
19 | memScoped {
20 | val error = alloc()
21 | input.useNSData { inputData ->
22 | val output = finalizer.invoke(
23 | key,
24 | algorithm,
25 | inputData.retainBridgeAs(),
26 | error.ptr
27 | )?.releaseBridgeAs()
28 |
29 | if (output == null) {
30 | val nsError = error.value.releaseBridgeAs()
31 | error("Failed to perform operation: ${nsError?.description}")
32 | }
33 |
34 | output.toByteArray()
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/cryptography-providers/apple/src/commonMain/kotlin/internal/clozy.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.apple.internal
6 |
7 | import kotlin.concurrent.*
8 | import kotlin.experimental.*
9 | import kotlin.native.ref.*
10 |
11 | // TODO: clozy use-cases
12 |
13 | @OptIn(ExperimentalNativeApi::class)
14 | internal open class SafeCloseable(closeAction: SafeCloseAction) : AutoCloseable {
15 | private val handler = CloseHandler(closeAction)
16 | private val cleaner = createCleaner(handler, CloseHandler::onClose)
17 | override fun close(): Unit = handler.onClose()
18 | }
19 |
20 | internal interface SafeCloseAction {
21 | fun onClose()
22 | }
23 |
24 | internal inline fun SafeCloseAction(resource: T, crossinline closeAction: (T) -> Unit): SafeCloseAction =
25 | object : SafeCloseAction {
26 | override fun onClose(): Unit = closeAction(resource)
27 | }
28 |
29 | private class CloseHandler(private val closeAction: SafeCloseAction) {
30 | private val executed = AtomicInt(0)
31 | fun onClose() {
32 | if (executed.compareAndSet(0, 1)) closeAction.onClose()
33 | }
34 | }
35 |
36 | internal class Resource(
37 | private var value: T?,
38 | private val recycle: (T) -> Unit,
39 | ) : AutoCloseable {
40 | fun access(): T = checkNotNull(value) { "Already closed" }
41 |
42 | override fun close() {
43 | recycle(value ?: return)
44 | value = null
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/cryptography-providers/apple/src/commonMain/kotlin/internal/keys.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024-2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.apple.internal
6 |
7 | import dev.whyoleg.cryptography.providers.base.*
8 | import kotlinx.cinterop.*
9 | import platform.CoreFoundation.*
10 | import platform.Foundation.*
11 | import platform.Security.*
12 |
13 | internal fun decodeSecKey(input: ByteArray, attributes: CFMutableDictionaryRef?): SecKeyRef = memScoped {
14 | val error = alloc()
15 | input.useNSData {
16 | SecKeyCreateWithData(
17 | keyData = it.retainBridgeAs(),
18 | attributes = attributes,
19 | error = error.ptr
20 | )
21 | } ?: error("Failed to decode key: ${error.releaseAndGetMessage}")
22 | }
23 |
24 | // returns private key
25 | internal fun generateSecKey(attributes: CFMutableDictionaryRef?): SecKeyRef = memScoped {
26 | val error = alloc()
27 | SecKeyCreateRandomKey(
28 | parameters = attributes,
29 | error = error.ptr
30 | ) ?: error("Failed to generate key pair: ${error.releaseAndGetMessage}")
31 | }
32 |
33 | internal fun exportSecKey(key: SecKeyRef): ByteArray = memScoped {
34 | val error = alloc()
35 | SecKeyCopyExternalRepresentation(
36 | key = key,
37 | error = error.ptr
38 | )?.releaseBridgeAs()
39 | ?.toByteArray()
40 | ?: error("Failed to export key: ${error.releaseAndGetMessage}")
41 | }
42 |
--------------------------------------------------------------------------------
/cryptography-providers/apple/src/commonMain/kotlin/internal/utils.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.apple.internal
6 |
7 | import kotlinx.cinterop.*
8 | import platform.CoreFoundation.*
9 | import platform.Foundation.*
10 |
11 | internal val CFErrorRefVar.releaseAndGetMessage get() = value.releaseBridgeAs()?.description
12 |
13 | @Suppress("UNCHECKED_CAST")
14 | internal fun Any?.retainBridgeAs(): T? = retainBridge()?.let { it as T }
15 | internal fun Any?.retainBridge(): CFTypeRef? = CFBridgingRetain(this)
16 |
17 | @Suppress("UNCHECKED_CAST")
18 | internal fun CFTypeRef?.releaseBridgeAs(): T? = releaseBridge()?.let { it as T }
19 | internal fun CFTypeRef?.releaseBridge(): Any? = CFBridgingRelease(this)
20 |
21 | internal fun CFTypeRef?.release(): Unit = CFRelease(this)
22 |
23 | internal inline fun T.use(block: (T) -> R): R {
24 | try {
25 | return block(this)
26 | } finally {
27 | releaseBridge()
28 | }
29 | }
30 |
31 | internal fun CFMutableDictionaryRef?.add(key: CFTypeRef?, value: CFTypeRef?) {
32 | CFDictionaryAddValue(this, key, value)
33 | }
34 |
35 | @Suppress("FunctionName")
36 | @OptIn(UnsafeNumber::class)
37 | internal inline fun CFMutableDictionary(size: Int, block: CFMutableDictionaryRef?.() -> Unit): CFMutableDictionaryRef? {
38 | val dict = CFDictionaryCreateMutable(null, size.convert(), null, null)
39 | dict.block()
40 | return dict
41 | }
42 |
--------------------------------------------------------------------------------
/cryptography-providers/apple/src/commonTest/kotlin/AppleDefaultProviderTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.apple
6 |
7 | import dev.whyoleg.cryptography.*
8 | import dev.whyoleg.cryptography.providers.tests.*
9 |
10 | class AppleDefaultProviderTest : DefaultProviderTest(CryptographyProvider.Apple)
11 |
--------------------------------------------------------------------------------
/cryptography-providers/base/README.md:
--------------------------------------------------------------------------------
1 | # Module cryptography-provider-base
2 |
3 | Shared implementation details for providers
4 |
--------------------------------------------------------------------------------
/cryptography-providers/base/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | import ckbuild.*
6 |
7 | plugins {
8 | id("ckbuild.multiplatform-library")
9 | }
10 |
11 | description = "cryptography-kotlin base provider"
12 |
13 | kotlin {
14 | jvmTarget()
15 | jsTarget()
16 | nativeTargets()
17 | wasmTargets()
18 |
19 | sourceSets.commonMain.dependencies {
20 | api(projects.cryptographyCore)
21 | api(projects.cryptographySerializationPem)
22 | api(projects.cryptographySerializationAsn1)
23 | api(projects.cryptographySerializationAsn1Modules)
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/cryptography-providers/base/src/commonMain/kotlin/bytes.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.base
6 |
7 | import dev.whyoleg.cryptography.*
8 |
9 | @CryptographyProviderApi
10 | public val EmptyByteArray: ByteArray = ByteArray(0)
11 |
12 | @CryptographyProviderApi
13 | public fun checkBounds(size: Int, startIndex: Int, endIndex: Int) {
14 | if (startIndex < 0 || endIndex > size) {
15 | throw IndexOutOfBoundsException(
16 | "startIndex ($startIndex) and endIndex ($endIndex) are not within the range [0..size($size))"
17 | )
18 | }
19 | if (startIndex > endIndex) {
20 | throw IllegalArgumentException("startIndex ($startIndex) > endIndex ($endIndex)")
21 | }
22 | }
23 |
24 | @CryptographyProviderApi
25 | public fun ByteArray.ensureSizeExactly(expectedSize: Int): ByteArray = when (size) {
26 | expectedSize -> this
27 | else -> copyOf(expectedSize)
28 | }
29 |
--------------------------------------------------------------------------------
/cryptography-providers/base/src/nativeMain/kotlin/bytes.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.base
6 |
7 | import dev.whyoleg.cryptography.*
8 | import kotlinx.cinterop.*
9 |
10 | // this hack should be dropped (or not?) with introducing of new IO or functions APIs
11 |
12 | @OptIn(ExperimentalForeignApi::class)
13 | private val almostEmptyArrayPinned = ByteArray(1).pin()
14 |
15 | @ExperimentalForeignApi
16 | public fun Pinned.safeAddressOf(index: Int): CPointer {
17 | if (index == get().size) return almostEmptyArrayPinned.addressOf(0)
18 | return addressOf(index)
19 | }
20 |
21 | @CryptographyProviderApi
22 | @ExperimentalForeignApi
23 | public fun ByteArray.safeRefTo(index: Int): CValuesRef {
24 | if (index == size) return almostEmptyArrayPinned.addressOf(0)
25 | return refTo(index)
26 | }
27 |
28 | //unsafe casts instead of asUByteArray().refTo() because of boxing when pinning
29 | @CryptographyProviderApi
30 | @ExperimentalForeignApi
31 | @Suppress("UNCHECKED_CAST")
32 | public fun Pinned.safeAddressOfU(index: Int): CPointer = safeAddressOf(index) as CPointer
33 |
34 | @CryptographyProviderApi
35 | @ExperimentalForeignApi
36 | @Suppress("UNCHECKED_CAST")
37 | public fun ByteArray.safeRefToU(index: Int): CValuesRef = safeRefTo(index) as CValuesRef
38 |
39 | @CryptographyProviderApi
40 | @ExperimentalForeignApi
41 | @Suppress("UNCHECKED_CAST")
42 | public fun ByteArray.refToU(index: Int): CValuesRef = refTo(index) as CValuesRef
43 |
--------------------------------------------------------------------------------
/cryptography-providers/cryptokit/api/cryptography-provider-cryptokit.klib.api:
--------------------------------------------------------------------------------
1 | // Klib ABI Dump
2 | // Targets: [iosArm64, iosSimulatorArm64, iosX64, macosArm64, macosX64, tvosArm64, tvosSimulatorArm64, tvosX64, watchosArm64, watchosDeviceArm64, watchosSimulatorArm64, watchosX64]
3 | // Rendering settings:
4 | // - Signature version: 2
5 | // - Show manifest properties: true
6 | // - Show declarations: true
7 |
8 | // Library unique name:
9 | final val dev.whyoleg.cryptography.providers.cryptokit/CryptoKit // dev.whyoleg.cryptography.providers.cryptokit/CryptoKit|@dev.whyoleg.cryptography.CryptographyProvider.Companion{}CryptoKit[0]
10 | final fun (dev.whyoleg.cryptography/CryptographyProvider.Companion).(): dev.whyoleg.cryptography/CryptographyProvider // dev.whyoleg.cryptography.providers.cryptokit/CryptoKit.|@dev.whyoleg.cryptography.CryptographyProvider.Companion(){}[0]
11 |
--------------------------------------------------------------------------------
/cryptography-providers/cryptokit/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | import ckbuild.*
6 |
7 | plugins {
8 |
9 | id("ckbuild.multiplatform-library")
10 | id("ckbuild.multiplatform-provider-tests")
11 | id("dev.whyoleg.swiftinterop")
12 | }
13 |
14 | description = "cryptography-kotlin Cryptokit provider"
15 |
16 | swiftInterop {
17 | packageName = "dev.whyoleg.cryptography.providers.cryptokit.internal.swiftinterop"
18 | iosVersion = "14"
19 | macosVersion = "11"
20 | tvosVersion = "14"
21 | watchosVersion = "7"
22 | }
23 |
24 | kotlin {
25 | appleTargets(
26 | supportsWatchosArm32 = false,
27 | )
28 |
29 | compilerOptions {
30 | optIn.addAll(
31 | OptIns.DelicateCryptographyApi,
32 | OptIns.CryptographyProviderApi,
33 |
34 | OptIns.ExperimentalForeignApi,
35 | )
36 | }
37 |
38 | sourceSets.commonMain.dependencies {
39 | api(projects.cryptographyCore)
40 | implementation(projects.cryptographyProviderBase)
41 | }
42 | }
43 |
44 | providerTests {
45 | packageName.set("dev.whyoleg.cryptography.providers.cryptokit")
46 | providerInitializers.put("CryptoKit", "CryptographyProvider.CryptoKit")
47 | }
48 |
--------------------------------------------------------------------------------
/cryptography-providers/cryptokit/src/commonMain/kotlin/algorithms/CryptoKitDigest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.cryptokit.algorithms
6 |
7 | import dev.whyoleg.cryptography.*
8 | import dev.whyoleg.cryptography.algorithms.*
9 | import dev.whyoleg.cryptography.operations.*
10 | import dev.whyoleg.cryptography.providers.base.*
11 | import dev.whyoleg.cryptography.providers.cryptokit.internal.swiftinterop.*
12 | import dev.whyoleg.cryptography.providers.cryptokit.operations.*
13 | import kotlinx.cinterop.*
14 | import platform.Foundation.*
15 |
16 | @OptIn(UnsafeNumber::class)
17 | internal class CryptoKitDigest(
18 | override val id: CryptographyAlgorithmId,
19 | private val algorithm: SwiftHashAlgorithm,
20 | ) : Digest, Hasher {
21 | override fun hasher(): Hasher = this
22 | override fun createHashFunction(): HashFunction = CryptoKitHashFunction(algorithm)
23 | }
24 |
25 | @OptIn(UnsafeNumber::class)
26 | private class CryptoKitHashFunction(
27 | algorithm: SwiftHashAlgorithm,
28 | ) : HashBasedFunction(algorithm), HashFunction {
29 | private fun hashToNSData(): NSData = function.doFinal().also { reset() }
30 | override fun hashIntoByteArray(destination: ByteArray, destinationOffset: Int): Int {
31 | return hashToNSData().getIntoByteArray(destination, destinationOffset)
32 | }
33 |
34 | override fun hashToByteArray(): ByteArray {
35 | return hashToNSData().toByteArray()
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/cryptography-providers/cryptokit/src/commonMain/kotlin/operations/HashBasedFunction.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.cryptokit.operations
6 |
7 | import dev.whyoleg.cryptography.operations.*
8 | import dev.whyoleg.cryptography.providers.base.*
9 | import dev.whyoleg.cryptography.providers.cryptokit.internal.swiftinterop.*
10 | import kotlinx.cinterop.*
11 |
12 | @OptIn(UnsafeNumber::class)
13 | internal abstract class HashBasedFunction(
14 | private val algorithm: SwiftHashAlgorithm,
15 | ) : UpdateFunction {
16 | private var _function: SwiftHashFunction? = SwiftHashFunction(algorithm)
17 |
18 | protected val function: SwiftHashFunction
19 | get() = _function ?: error("Hash function is closed")
20 |
21 | final override fun update(source: ByteArray, startIndex: Int, endIndex: Int) {
22 | source.useNSData(startIndex, endIndex, function::doUpdate)
23 | }
24 |
25 | final override fun reset() {
26 | checkNotNull(_function) { "Hash function is closed" }
27 | _function = SwiftHashFunction(algorithm)
28 | }
29 |
30 | final override fun close() {
31 | _function = null
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/cryptography-providers/cryptokit/src/commonMain/swift/SwiftAesGcm.swift:
--------------------------------------------------------------------------------
1 | import CryptoKit
2 | import Foundation
3 |
4 | @objc public class SwiftAesGcm: NSObject {
5 | @objc public static func encrypt(
6 | key: NSData,
7 | nonce: NSData,
8 | plaintext: NSData,
9 | authenticatedData: NSData
10 | ) throws -> Data {
11 | return try AES.GCM.seal(
12 | plaintext as Data,
13 | using: SymmetricKey(data: key as Data),
14 | nonce: try AES.GCM.Nonce(data: nonce as Data),
15 | authenticating: authenticatedData
16 | ).combined!
17 | }
18 |
19 | @objc public static func decrypt(
20 | key: NSData,
21 | nonce: NSData,
22 | ciphertext: NSData,
23 | tag: NSData,
24 | authenticatedData: NSData
25 | ) throws -> Data {
26 | return try AES.GCM.open(
27 | try AES.GCM.SealedBox(
28 | nonce: try AES.GCM.Nonce(data: nonce),
29 | ciphertext: ciphertext,
30 | tag: tag
31 | ),
32 | using: SymmetricKey(data: key as Data),
33 | authenticating: authenticatedData
34 | )
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/cryptography-providers/cryptokit/src/commonMain/swift/SwiftHmac.swift:
--------------------------------------------------------------------------------
1 | import CryptoKit
2 | import Foundation
3 |
4 | @objc public class SwiftHmacFunction: NSObject {
5 | private var wrapper: AnyHmacWrapper
6 |
7 | @objc public init(algorithm: SwiftHashAlgorithm, key: NSData) {
8 | let secretKey = SymmetricKey(data: key as Data)
9 | self.wrapper =
10 | switch algorithm {
11 | case .md5: HmacWrapper(key: secretKey)
12 | case .sha1: HmacWrapper(key: secretKey)
13 | case .sha256: HmacWrapper(key: secretKey)
14 | case .sha384: HmacWrapper(key: secretKey)
15 | case .sha512: HmacWrapper(key: secretKey)
16 | }
17 | super.init()
18 | }
19 |
20 | @objc(doUpdate:) public func doUpdate(data: NSData) {
21 | wrapper.doUpdate(data: data)
22 | }
23 |
24 | @objc public func doFinal() -> Data {
25 | return Data(wrapper.doFinal())
26 | }
27 | }
28 |
29 | private protocol AnyHmacWrapper {
30 | func doUpdate(data: NSData)
31 | func doFinal() -> Data
32 | }
33 |
34 | private final class HmacWrapper: AnyHmacWrapper where H.Digest: ContiguousBytes {
35 | private var value: HMAC
36 |
37 | init(key: SymmetricKey) {
38 | self.value = HMAC(key: key)
39 | }
40 |
41 | func doUpdate(data: NSData) {
42 | value.update(data: data)
43 | }
44 |
45 | func doFinal() -> Data {
46 | return Data(value.finalize())
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/cryptography-providers/jdk/android-tests/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | plugins {
6 | id("ckbuild.multiplatform-base")
7 | id("ckbuild.multiplatform-android")
8 | id("ckbuild.multiplatform-provider-tests")
9 | }
10 |
11 | kotlin {
12 | sourceSets {
13 | androidInstrumentedTest.dependencies {
14 | implementation(projects.cryptographyProviderJdk)
15 | implementation(libs.bouncycastle)
16 | }
17 | }
18 | }
19 |
20 | providerTests {
21 | packageName.set("dev.whyoleg.cryptography.providers.jdk.android")
22 | imports.addAll(
23 | "dev.whyoleg.cryptography.providers.jdk.*",
24 | "org.bouncycastle.jce.provider.*"
25 | )
26 | providerInitializers.put("JDK_Android", "CryptographyProvider.JDK")
27 | providerInitializers.put("JDK_BC_Android", "CryptographyProvider.JDK(BouncyCastleProvider())")
28 | }
29 |
--------------------------------------------------------------------------------
/cryptography-providers/jdk/android-tests/src/androidInstrumentedTest/kotlin/AndroidJdkDefaultProviderTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.jdk.android
6 |
7 | import dev.whyoleg.cryptography.*
8 | import dev.whyoleg.cryptography.providers.jdk.*
9 | import dev.whyoleg.cryptography.providers.tests.*
10 |
11 | class AndroidJdkDefaultProviderTest : DefaultProviderTest(CryptographyProvider.JDK)
12 |
--------------------------------------------------------------------------------
/cryptography-providers/jdk/api/cryptography-provider-jdk.klib.api:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/whyoleg/cryptography-kotlin/5b1f52dfc418e1d6f0e4111c2fa5eaf6b844a8a2/cryptography-providers/jdk/api/cryptography-provider-jdk.klib.api
--------------------------------------------------------------------------------
/cryptography-providers/jdk/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | import ckbuild.*
6 | import org.jetbrains.kotlin.gradle.*
7 |
8 | plugins {
9 | id("ckbuild.multiplatform-library")
10 | id("ckbuild.multiplatform-provider-tests")
11 | }
12 |
13 | description = "cryptography-kotlin JDK provider"
14 |
15 | @OptIn(ExperimentalKotlinGradlePluginApi::class)
16 | kotlin {
17 | jvmTarget()
18 |
19 | compilerOptions {
20 | optIn.addAll(
21 | OptIns.DelicateCryptographyApi,
22 | OptIns.CryptographyProviderApi,
23 | )
24 | }
25 |
26 | sourceSets {
27 | jvmMain.dependencies {
28 | api(projects.cryptographyCore)
29 | implementation(projects.cryptographyProviderBase)
30 | }
31 | jvmTest.dependencies {
32 | implementation(libs.bouncycastle)
33 | }
34 | }
35 | }
36 |
37 | providerTests {
38 | packageName.set("dev.whyoleg.cryptography.providers.jdk")
39 | imports.addAll("org.bouncycastle.jce.provider.*")
40 | providerInitializers.put("JDK", "CryptographyProvider.JDK")
41 | providerInitializers.put("JDK_BC", "CryptographyProvider.JDK(BouncyCastleProvider())")
42 | }
43 |
--------------------------------------------------------------------------------
/cryptography-providers/jdk/src/jvmMain/kotlin/JTypealiases.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.jdk
6 |
7 | import java.security.*
8 | import javax.crypto.*
9 |
10 | internal typealias JCipher = Cipher
11 | internal typealias JKeyGenerator = KeyGenerator
12 | internal typealias JKeyPairGenerator = KeyPairGenerator
13 | internal typealias JKeyPair = KeyPair
14 | internal typealias JPrivateKey = PrivateKey
15 | internal typealias JPublicKey = PublicKey
16 | internal typealias JSecretKey = SecretKey
17 | internal typealias JSecretKeyFactory = SecretKeyFactory
18 | internal typealias JKey = Key
19 | internal typealias JMessageDigest = MessageDigest
20 | internal typealias JMac = Mac
21 | internal typealias JProvider = Provider
22 | internal typealias JSignature = Signature
23 | internal typealias JSecureRandom = SecureRandom
24 | internal typealias JKeyFactory = KeyFactory
25 | internal typealias JAlgorithmParameters = AlgorithmParameters
26 | internal typealias JAlgorithmParameterGenerator = AlgorithmParameterGenerator
27 | internal typealias JKeyAgreement = KeyAgreement
28 |
--------------------------------------------------------------------------------
/cryptography-providers/jdk/src/jvmMain/kotlin/algorithms/JdkHkdf.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.jdk.algorithms
6 |
7 | import dev.whyoleg.cryptography.*
8 | import dev.whyoleg.cryptography.algorithms.*
9 | import dev.whyoleg.cryptography.providers.base.algorithms.*
10 | import dev.whyoleg.cryptography.providers.jdk.*
11 |
12 | internal class JdkHkdf(
13 | private val state: JdkCryptographyState,
14 | provider: CryptographyProvider,
15 | ) : BaseHkdf(provider) {
16 | override fun digestSize(digest: CryptographyAlgorithmId): Int {
17 | return state.messageDigest(digest.name).use { it.digestLength }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/cryptography-providers/jdk/src/jvmMain/kotlin/internal/utils.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.jdk.internal
6 |
7 | internal fun ByteArray.trimLeadingZeros(): ByteArray {
8 | val firstNonZeroIndex = indexOfFirst { it != 0.toByte() }
9 | if (firstNonZeroIndex == -1) return this
10 | return copyOfRange(firstNonZeroIndex, size)
11 | }
12 |
--------------------------------------------------------------------------------
/cryptography-providers/jdk/src/jvmMain/kotlin/materials/JdkEncodableKey.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.jdk.materials
6 |
7 | import dev.whyoleg.cryptography.materials.key.*
8 | import dev.whyoleg.cryptography.providers.jdk.*
9 |
10 | internal abstract class JdkEncodableKey(
11 | private val key: JKey,
12 | ) : EncodableKey {
13 |
14 | protected fun encodeToRaw(): ByteArray {
15 | check(key.format == "RAW") { "Wrong JDK Key format, expected `RAW` got `${key.format}`" }
16 | return key.encoded
17 | }
18 |
19 | protected fun encodeToDer(): ByteArray {
20 | check(key.format == "PKCS#8" || key.format == "X.509") { "Wrong JDK Key format, expected `PKCS#8` or `X.509 got `${key.format}`" }
21 | return key.encoded
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/cryptography-providers/jdk/src/jvmMain/kotlin/materials/JdkKeyPairGenerator.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.jdk.materials
6 |
7 | import dev.whyoleg.cryptography.providers.jdk.*
8 | import dev.whyoleg.cryptography.materials.key.*
9 |
10 | internal abstract class JdkKeyPairGenerator(
11 | protected val state: JdkCryptographyState,
12 | algorithm: String,
13 | ) : KeyGenerator {
14 | private val keyPairGenerator = state.keyPairGenerator(algorithm)
15 |
16 | protected abstract fun JKeyPairGenerator.init()
17 |
18 | protected abstract fun JKeyPair.convert(): K
19 |
20 | final override fun generateKeyBlocking(): K = keyPairGenerator.use {
21 | it.init()
22 | it.generateKeyPair()
23 | }.convert()
24 | }
25 |
--------------------------------------------------------------------------------
/cryptography-providers/jdk/src/jvmMain/kotlin/materials/JdkPrivateKeyDecoder.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.jdk.materials
6 |
7 | import dev.whyoleg.cryptography.materials.key.*
8 | import dev.whyoleg.cryptography.providers.jdk.*
9 | import java.security.spec.*
10 |
11 | internal abstract class JdkPrivateKeyDecoder(
12 | protected val state: JdkCryptographyState,
13 | algorithm: String,
14 | ) : KeyDecoder {
15 | protected val keyFactory = state.keyFactory(algorithm)
16 |
17 | protected fun decode(spec: KeySpec): K = keyFactory.use { it.generatePrivate(spec) }.convert()
18 |
19 | protected fun decodeFromDer(input: ByteArray): K = decode(PKCS8EncodedKeySpec(input))
20 |
21 | protected abstract fun JPrivateKey.convert(): K
22 | }
23 |
--------------------------------------------------------------------------------
/cryptography-providers/jdk/src/jvmMain/kotlin/materials/JdkPublicKeyDecoder.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.jdk.materials
6 |
7 | import dev.whyoleg.cryptography.materials.key.*
8 | import dev.whyoleg.cryptography.providers.jdk.*
9 | import java.security.spec.*
10 |
11 | internal abstract class JdkPublicKeyDecoder(
12 | protected val state: JdkCryptographyState,
13 | algorithm: String,
14 | private val pemAlgorithm: String = algorithm,
15 | ) : KeyDecoder {
16 | protected val keyFactory = state.keyFactory(algorithm)
17 |
18 | protected fun decodeFromDer(input: ByteArray): K = keyFactory.use { it.generatePublic(X509EncodedKeySpec(input)) }.convert()
19 |
20 | protected abstract fun JPublicKey.convert(): K
21 | }
22 |
--------------------------------------------------------------------------------
/cryptography-providers/jdk/src/jvmMain/kotlin/materials/JdkSecretKeyDecoder.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.jdk.materials
6 |
7 |
8 | import dev.whyoleg.cryptography.materials.key.*
9 | import dev.whyoleg.cryptography.providers.jdk.*
10 | import javax.crypto.spec.*
11 |
12 | internal class JdkSecretKeyDecoder(
13 | private val algorithm: String,
14 | private val keyWrapper: (JSecretKey) -> K,
15 | ) : KeyDecoder {
16 | override fun decodeFromByteArrayBlocking(format: KF, bytes: ByteArray): K = when (format.name) {
17 | "RAW" -> keyWrapper(SecretKeySpec(bytes, algorithm))
18 | else -> error("$format is not supported")
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/cryptography-providers/jdk/src/jvmMain/kotlin/materials/JdkSecretKeyGenerator.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.jdk.materials
6 |
7 | import dev.whyoleg.cryptography.providers.jdk.*
8 | import dev.whyoleg.cryptography.materials.key.*
9 |
10 | internal class JdkSecretKeyGenerator(
11 | state: JdkCryptographyState,
12 | algorithm: String,
13 | private val keyWrapper: (JSecretKey) -> K,
14 | private val keyGeneratorInit: JKeyGenerator.() -> Unit,
15 | ) : KeyGenerator {
16 | private val keyGenerator = state.keyGenerator(algorithm)
17 | override fun generateKeyBlocking(): K = keyWrapper(keyGenerator.use {
18 | it.keyGeneratorInit()
19 | it.generateKey()
20 | })
21 | }
22 |
--------------------------------------------------------------------------------
/cryptography-providers/jdk/src/jvmMain/kotlin/operations/JdkKeyAgreement.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.jdk.operations
6 |
7 | import dev.whyoleg.cryptography.providers.jdk.*
8 |
9 | internal fun Pooled.doAgreement(
10 | state: JdkCryptographyState,
11 | privateKey: JPrivateKey,
12 | publicKey: JPublicKey,
13 | ): ByteArray = use {
14 | it.init(privateKey, state.secureRandom)
15 | it.doPhase(publicKey, true)
16 | it.generateSecret()
17 | }
18 |
--------------------------------------------------------------------------------
/cryptography-providers/jdk/src/jvmMain/resources/META-INF/services/dev.whyoleg.cryptography.CryptographyProviderContainer:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (c) 2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | #
4 |
5 | dev.whyoleg.cryptography.providers.jdk.JdkCryptographyProviderContainer
6 |
--------------------------------------------------------------------------------
/cryptography-providers/jdk/src/jvmTest/kotlin/JdkDefaultProviderTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.jdk
6 |
7 | import dev.whyoleg.cryptography.*
8 | import dev.whyoleg.cryptography.providers.tests.*
9 |
10 | class JdkDefaultProviderTest : DefaultProviderTest(CryptographyProvider.JDK)
11 |
--------------------------------------------------------------------------------
/cryptography-providers/openssl3/api/api/cryptography-provider-openssl3-api.klib.api:
--------------------------------------------------------------------------------
1 | // Klib ABI Dump
2 | // Targets: [androidNativeArm32, androidNativeArm64, androidNativeX64, androidNativeX86, iosArm64, iosSimulatorArm64, iosX64, linuxArm64, linuxX64, macosArm64, macosX64, mingwX64, tvosArm64, tvosSimulatorArm64, tvosX64, watchosArm32, watchosArm64, watchosDeviceArm64, watchosSimulatorArm64, watchosX64]
3 | // Rendering settings:
4 | // - Signature version: 2
5 | // - Show manifest properties: true
6 | // - Show declarations: true
7 |
8 | // Library unique name:
9 | final val dev.whyoleg.cryptography.providers.openssl3/Openssl3 // dev.whyoleg.cryptography.providers.openssl3/Openssl3|@dev.whyoleg.cryptography.CryptographyProvider.Companion{}Openssl3[0]
10 | final fun (dev.whyoleg.cryptography/CryptographyProvider.Companion).(): dev.whyoleg.cryptography/CryptographyProvider // dev.whyoleg.cryptography.providers.openssl3/Openssl3.|@dev.whyoleg.cryptography.CryptographyProvider.Companion(){}[0]
11 |
--------------------------------------------------------------------------------
/cryptography-providers/openssl3/api/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | import ckbuild.*
6 | import ckbuild.openssl.*
7 | import org.jetbrains.kotlin.gradle.*
8 | import org.jetbrains.kotlin.gradle.plugin.mpp.*
9 | import org.jetbrains.kotlin.gradle.tasks.*
10 |
11 | plugins {
12 | id("ckbuild.multiplatform-library")
13 | id("ckbuild.use-openssl")
14 | }
15 |
16 | description = "cryptography-kotlin OpenSSL3 provider (API)"
17 |
18 | @OptIn(ExperimentalKotlinGradlePluginApi::class)
19 | kotlin {
20 | nativeTargets()
21 |
22 | compilerOptions {
23 | optIn.addAll(
24 | OptIns.DelicateCryptographyApi,
25 | OptIns.CryptographyProviderApi,
26 |
27 | OptIns.ExperimentalForeignApi,
28 | )
29 | }
30 |
31 | sourceSets.commonMain.dependencies {
32 | api(projects.cryptographyCore)
33 | implementation(projects.cryptographyProviderBase)
34 | }
35 |
36 | targets.withType().configureEach {
37 | cinterop("declarations", "common")
38 | }
39 | }
40 |
41 | tasks.withType().configureEach {
42 | uses(openssl.v3_0) {
43 | settings.includeDirs(includeDirectory(konanTarget))
44 | }
45 | }
46 |
47 | documentation {
48 | moduleName.set("cryptography-provider-openssl3")
49 | includes.set("../README.md")
50 | }
51 |
--------------------------------------------------------------------------------
/cryptography-providers/openssl3/api/src/commonMain/cinterop/declarations.def:
--------------------------------------------------------------------------------
1 | package = dev.whyoleg.cryptography.providers.openssl3.internal.cinterop
2 | headerFilter = openssl/*
3 | headers = openssl/evp.h \
4 | openssl/kdf.h \
5 | openssl/err.h \
6 | openssl/encoder.h \
7 | openssl/decoder.h \
8 | openssl/ec.h
9 | noStringConversion = OSSL_PARAM_construct_double \
10 | OSSL_PARAM_construct_int \
11 | OSSL_PARAM_construct_int32 \
12 | OSSL_PARAM_construct_int64 \
13 | OSSL_PARAM_construct_long \
14 | OSSL_PARAM_construct_size_t \
15 | OSSL_PARAM_construct_time_t \
16 | OSSL_PARAM_construct_uint \
17 | OSSL_PARAM_construct_uint32 \
18 | OSSL_PARAM_construct_uint64 \
19 | OSSL_PARAM_construct_ulong \
20 | OSSL_PARAM_construct_BN \
21 | OSSL_PARAM_construct_utf8_string \
22 | OSSL_PARAM_construct_utf8_ptr \
23 | OSSL_PARAM_construct_octet_string \
24 | OSSL_PARAM_construct_octet_ptr \
25 | OSSL_ENCODER_CTX_new_for_pkey \
26 | OSSL_DECODER_CTX_new_for_pkey
27 | compilerOpts = -DOPENSSL_NO_DEPRECATED
--------------------------------------------------------------------------------
/cryptography-providers/openssl3/api/src/commonMain/kotlin/algorithms/Openssl3AesCbc.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.openssl3.algorithms
6 |
7 | import dev.whyoleg.cryptography.*
8 | import dev.whyoleg.cryptography.algorithms.*
9 | import dev.whyoleg.cryptography.providers.openssl3.internal.*
10 | import dev.whyoleg.cryptography.providers.openssl3.internal.cinterop.*
11 | import kotlin.experimental.*
12 | import kotlin.native.ref.*
13 |
14 | internal object Openssl3AesCbc : AES.CBC, Openssl3Aes() {
15 | override fun wrapKey(keySize: BinarySize, key: ByteArray): AES.CBC.Key = AesCbcKey(keySize, key)
16 |
17 | private class AesCbcKey(keySize: BinarySize, key: ByteArray) : AES.CBC.Key, AesKey(key) {
18 | private val algorithm = when (keySize) {
19 | AES.Key.Size.B128 -> "AES-128-CBC"
20 | AES.Key.Size.B192 -> "AES-192-CBC"
21 | AES.Key.Size.B256 -> "AES-256-CBC"
22 | else -> error("Unsupported key size")
23 | }
24 |
25 | private val cipher = EVP_CIPHER_fetch(null, algorithm, null)
26 |
27 | @OptIn(ExperimentalNativeApi::class)
28 | private val cleaner = createCleaner(cipher, ::EVP_CIPHER_free)
29 |
30 | override fun cipher(padding: Boolean): AES.IvCipher {
31 | return Openssl3AesIvCipher(cipher, key, ivSize = 16) { context ->
32 | checkError(EVP_CIPHER_CTX_set_padding(context, if (padding) 1 else 0))
33 | }
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/cryptography-providers/openssl3/api/src/commonMain/kotlin/algorithms/Openssl3AesCtr.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.openssl3.algorithms
6 |
7 | import dev.whyoleg.cryptography.*
8 | import dev.whyoleg.cryptography.algorithms.*
9 | import dev.whyoleg.cryptography.providers.openssl3.internal.cinterop.*
10 | import kotlin.experimental.*
11 | import kotlin.native.ref.*
12 |
13 | internal object Openssl3AesCtr : AES.CTR, Openssl3Aes() {
14 | override fun wrapKey(keySize: BinarySize, key: ByteArray): AES.CTR.Key = AesCtrKey(keySize, key)
15 |
16 | private class AesCtrKey(keySize: BinarySize, key: ByteArray) : AES.CTR.Key, AesKey(key) {
17 | private val algorithm = when (keySize) {
18 | AES.Key.Size.B128 -> "AES-128-CTR"
19 | AES.Key.Size.B192 -> "AES-192-CTR"
20 | AES.Key.Size.B256 -> "AES-256-CTR"
21 | else -> error("Unsupported key size")
22 | }
23 |
24 | private val cipher = EVP_CIPHER_fetch(null, algorithm, null)
25 |
26 | @OptIn(ExperimentalNativeApi::class)
27 | private val cleaner = createCleaner(cipher, ::EVP_CIPHER_free)
28 |
29 | override fun cipher(): AES.IvCipher {
30 | return Openssl3AesIvCipher(cipher, key, ivSize = 16)
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/cryptography-providers/openssl3/api/src/commonMain/kotlin/internal/arrays.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.openssl3.internal
6 |
7 | import dev.whyoleg.cryptography.providers.openssl3.internal.cinterop.*
8 | import kotlinx.cinterop.*
9 |
10 | internal fun NativePlacement.OSSL_PARAM_array(vararg values: CValue): CArrayPointer {
11 | return allocArrayOf(*values, OSSL_PARAM_construct_end())
12 | }
13 |
14 | internal fun NativePlacement.OSSL_PARAM_arrayNotNull(vararg values: CValue?): CArrayPointer {
15 | return allocArrayOf(*values.filterNotNull().toTypedArray(), OSSL_PARAM_construct_end())
16 | }
17 |
18 | //for stdlib
19 | internal inline fun NativePlacement.allocArrayOf(vararg elements: CValue): CArrayPointer {
20 | val array = allocArray(elements.size)
21 | elements.forEachIndexed { index, element -> array[index] = element }
22 | return array
23 | }
24 |
25 | internal inline operator fun CArrayPointer.set(index: Int, value: CValue) {
26 | value.place(get(index).ptr)
27 | }
28 |
--------------------------------------------------------------------------------
/cryptography-providers/openssl3/api/src/commonMain/kotlin/internal/clozy.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.openssl3.internal
6 |
7 | import kotlin.concurrent.*
8 | import kotlin.experimental.*
9 | import kotlin.native.ref.*
10 |
11 | // TODO: clozy use-cases
12 |
13 | @OptIn(ExperimentalNativeApi::class)
14 | internal open class SafeCloseable(closeAction: SafeCloseAction) : AutoCloseable {
15 | private val handler = CloseHandler(closeAction)
16 | private val cleaner = createCleaner(handler, CloseHandler::onClose)
17 | final override fun close(): Unit = handler.onClose()
18 | }
19 |
20 | internal interface SafeCloseAction {
21 | fun onClose()
22 | }
23 |
24 | internal inline fun SafeCloseAction(resource: T, crossinline closeAction: (T) -> Unit): SafeCloseAction =
25 | object : SafeCloseAction {
26 | override fun onClose(): Unit = closeAction(resource)
27 | }
28 |
29 | private class CloseHandler(private val closeAction: SafeCloseAction) {
30 | private val executed = AtomicInt(0)
31 | fun onClose() {
32 | if (executed.compareAndSet(0, 1)) closeAction.onClose()
33 | }
34 | }
35 |
36 | internal class Resource(
37 | private var value: T?,
38 | private val recycle: (T) -> Unit,
39 | ) : AutoCloseable {
40 | fun access(): T = checkNotNull(value) { "Already closed" }
41 |
42 | override fun close() {
43 | recycle(value ?: return)
44 | value = null
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/cryptography-providers/openssl3/api/src/commonMain/kotlin/internal/errors.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.openssl3.internal
6 |
7 | import dev.whyoleg.cryptography.providers.openssl3.internal.cinterop.*
8 | import kotlinx.cinterop.*
9 | import platform.posix.*
10 |
11 | internal fun checkError(result: T?): T {
12 | if (result != null) return result
13 | fail(0)
14 | }
15 |
16 | @OptIn(UnsafeNumber::class)
17 | internal fun checkError(result: size_t): size_t {
18 | if (result > 0.convert()) return result
19 | fail(result.convert())
20 | }
21 |
22 | internal fun checkError(result: Int): Int {
23 | if (result > 0) return result
24 | fail(result)
25 | }
26 |
27 | @OptIn(UnsafeNumber::class)
28 | private fun fail(result: Int): Nothing {
29 | val message = buildString {
30 | var code = ERR_get_error()
31 | if (code.toInt() != 0) do {
32 | val message = memScoped {
33 | val buffer = allocArray(256)
34 | ERR_error_string(code, buffer)?.toKString()
35 | }
36 | append(message)
37 | code = ERR_get_error()
38 | if (code.toInt() != 0) append(", ")
39 | } while (code.toInt() != 0)
40 | }
41 | throw IllegalStateException("OPENSSL failure: $message (result: $result)")
42 | }
43 |
--------------------------------------------------------------------------------
/cryptography-providers/openssl3/api/src/commonMain/kotlin/internal/hash.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.openssl3.internal
6 |
7 | import dev.whyoleg.cryptography.*
8 | import dev.whyoleg.cryptography.algorithms.*
9 | import dev.whyoleg.cryptography.providers.openssl3.internal.cinterop.*
10 |
11 | internal fun hashAlgorithm(digest: CryptographyAlgorithmId): String = when (digest) {
12 | SHA1 -> "SHA1"
13 | SHA224 -> "SHA224"
14 | SHA256 -> "SHA256"
15 | SHA384 -> "SHA384"
16 | SHA512 -> "SHA512"
17 | SHA3_224 -> "SHA3-224"
18 | SHA3_256 -> "SHA3-256"
19 | SHA3_384 -> "SHA3-384"
20 | SHA3_512 -> "SHA3-512"
21 | else -> throw IllegalStateException("Unsupported hash algorithm: $digest")
22 | }
23 |
24 | internal fun digestSize(hashAlgorithm: String): Int {
25 | val md = checkError(EVP_MD_fetch(null, hashAlgorithm, null))
26 | try {
27 | return EVP_MD_get_size(md)
28 | } finally {
29 | EVP_MD_free(md)
30 | }
31 | }
32 |
33 | internal fun blockSize(hashAlgorithm: String): Int {
34 | val md = checkError(EVP_MD_fetch(null, hashAlgorithm, null))
35 | try {
36 | return EVP_MD_get_block_size(md)
37 | } finally {
38 | EVP_MD_free(md)
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/cryptography-providers/openssl3/api/src/commonMain/kotlin/internal/refs.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.openssl3.internal
6 |
7 | import dev.whyoleg.cryptography.providers.openssl3.internal.cinterop.*
8 | import kotlinx.cinterop.*
9 | import kotlin.experimental.*
10 | import kotlin.native.ref.*
11 |
12 | @ExperimentalNativeApi
13 | internal fun CPointer.cleaner(): Cleaner = createCleaner(this, ::EVP_PKEY_free)
14 |
15 | internal fun CPointer.upRef(): CPointer {
16 | checkError(EVP_PKEY_up_ref(this))
17 | return this
18 | }
19 |
--------------------------------------------------------------------------------
/cryptography-providers/openssl3/api/src/commonMain/kotlin/materials/Openssl3KeyPairGenerator.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.openssl3.materials
6 |
7 | import dev.whyoleg.cryptography.materials.key.*
8 | import dev.whyoleg.cryptography.providers.openssl3.internal.*
9 | import dev.whyoleg.cryptography.providers.openssl3.internal.cinterop.*
10 | import kotlinx.cinterop.*
11 |
12 | internal abstract class Openssl3KeyPairGenerator(
13 | private val algorithm: String,
14 | ) : KeyGenerator {
15 | protected abstract fun MemScope.createParams(): CValuesRef?
16 | protected abstract fun wrapKeyPair(keyPair: CPointer): K
17 |
18 | final override fun generateKeyBlocking(): K = memScoped {
19 | val context = checkError(EVP_PKEY_CTX_new_from_name(null, algorithm, null))
20 | try {
21 | checkError(EVP_PKEY_keygen_init(context))
22 | checkError(EVP_PKEY_CTX_set_params(context, createParams()))
23 | val pkeyVar = alloc>()
24 | checkError(EVP_PKEY_generate(context, pkeyVar.ptr))
25 | val pkey = checkError(pkeyVar.value)
26 | //we do upRef here, because key pair contains 2 separate instances: public and private key
27 | wrapKeyPair(pkey.upRef())
28 | } finally {
29 | EVP_PKEY_CTX_free(context)
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/cryptography-providers/openssl3/prebuilt/api/cryptography-provider-openssl3-prebuilt.klib.api:
--------------------------------------------------------------------------------
1 | // Klib ABI Dump
2 | // Targets: [androidNativeArm32, androidNativeArm64, androidNativeX64, androidNativeX86, iosArm64, iosSimulatorArm64, iosX64, linuxArm64, linuxX64, macosArm64, macosX64, mingwX64, tvosArm64, tvosSimulatorArm64, tvosX64, watchosArm32, watchosArm64, watchosDeviceArm64, watchosSimulatorArm64, watchosX64]
3 | // Rendering settings:
4 | // - Signature version: 2
5 | // - Show manifest properties: true
6 | // - Show declarations: true
7 |
8 | // Library unique name:
9 |
--------------------------------------------------------------------------------
/cryptography-providers/openssl3/prebuilt/src/commonMain/cinterop/linking.def:
--------------------------------------------------------------------------------
1 | staticLibraries = libcrypto.a
2 | # libz.a is taken from mingw toolchain used in K/N
3 | staticLibraries.mingw = libz.a
4 | libraryPaths.mingw = src/mingwMain/libs
5 |
6 | linkerOpts.mingw = -lws2_32 -lcrypt32
7 | linkerOpts.linux = -lz
8 | linkerOpts.android = -lz
9 | linkerOpts.android_x86 = -latomic
10 |
--------------------------------------------------------------------------------
/cryptography-providers/openssl3/prebuilt/src/commonMain/kotlin/stub.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.openssl3.prebuilt
6 |
7 | private fun stub(): Unit = Unit
8 |
--------------------------------------------------------------------------------
/cryptography-providers/openssl3/prebuilt/src/commonTest/kotlin/PrebuiltLibCrypto3Test.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.openssl3.prebuilt
6 |
7 | import dev.whyoleg.cryptography.providers.openssl3.internal.cinterop.*
8 | import dev.whyoleg.cryptography.providers.openssl3.test.*
9 | import kotlinx.cinterop.*
10 | import kotlin.test.*
11 |
12 | class PrebuiltLibCrypto3Test : LibCrypto3Test() {
13 |
14 | @Test
15 | fun testExactVersion() {
16 | assertEquals("3.3.2", OpenSSL_version(OPENSSL_VERSION_STRING)?.toKString())
17 | assertEquals(3, OPENSSL_version_major().toInt())
18 | assertEquals(3, OPENSSL_version_minor().toInt())
19 | assertEquals(2, OPENSSL_version_patch().toInt())
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/cryptography-providers/openssl3/prebuilt/src/commonTest/kotlin/PrebuiltOpensslDefaultProviderTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.openssl3.prebuilt
6 |
7 | import dev.whyoleg.cryptography.*
8 | import dev.whyoleg.cryptography.providers.openssl3.*
9 | import dev.whyoleg.cryptography.providers.tests.*
10 |
11 | class PrebuiltOpensslDefaultProviderTest : DefaultProviderTest(CryptographyProvider.Openssl3)
12 |
--------------------------------------------------------------------------------
/cryptography-providers/openssl3/prebuilt/src/mingwMain/libs/libz.a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/whyoleg/cryptography-kotlin/5b1f52dfc418e1d6f0e4111c2fa5eaf6b844a8a2/cryptography-providers/openssl3/prebuilt/src/mingwMain/libs/libz.a
--------------------------------------------------------------------------------
/cryptography-providers/openssl3/shared/api/cryptography-provider-openssl3-shared.klib.api:
--------------------------------------------------------------------------------
1 | // Klib ABI Dump
2 | // Targets: [linuxArm64, linuxX64, macosArm64, macosX64, mingwX64]
3 | // Rendering settings:
4 | // - Signature version: 2
5 | // - Show manifest properties: true
6 | // - Show declarations: true
7 |
8 | // Library unique name:
9 |
--------------------------------------------------------------------------------
/cryptography-providers/openssl3/shared/src/commonMain/cinterop/linking.def:
--------------------------------------------------------------------------------
1 | linkerOpts = -lcrypto
2 |
3 | linkerOpts.osx = -L/opt/homebrew/opt/openssl@3/lib \
4 | -L/usr/local/opt/openssl@3/lib
5 |
6 | linkerOpts.linux = -L/home/linuxbrew/.linuxbrew/opt/openssl@3/lib \
7 | -L/usr/lib64 \
8 | -L/usr/lib/x86_64-linux-gnu \
9 | -L/lib/x86_64-linux-gnu
10 |
11 | linkerOpts.mingw = -LC:/msys64/mingw64/lib \
12 | -LC:/Tools/msys64/mingw64/lib \
13 | -LC:/Tools/msys2/mingw64/lib
14 |
--------------------------------------------------------------------------------
/cryptography-providers/openssl3/shared/src/commonMain/kotlin/stub.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.openssl3.shared
6 |
7 | private fun stub(): Unit = Unit
8 |
--------------------------------------------------------------------------------
/cryptography-providers/openssl3/shared/src/commonTest/kotlin/SharedLibCrypto3Test.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.openssl3.shared
6 |
7 | import dev.whyoleg.cryptography.providers.openssl3.test.*
8 |
9 | class SharedLibCrypto3Test : LibCrypto3Test()
10 |
--------------------------------------------------------------------------------
/cryptography-providers/openssl3/shared/src/commonTest/kotlin/SharedOpensslDefaultProviderTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.openssl3.shared
6 |
7 | import dev.whyoleg.cryptography.*
8 | import dev.whyoleg.cryptography.providers.openssl3.*
9 | import dev.whyoleg.cryptography.providers.tests.*
10 |
11 | class SharedOpensslDefaultProviderTest : DefaultProviderTest(CryptographyProvider.Openssl3)
12 |
--------------------------------------------------------------------------------
/cryptography-providers/openssl3/test/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | import ckbuild.*
6 | import org.jetbrains.kotlin.gradle.*
7 |
8 | plugins {
9 | id("ckbuild.multiplatform-base")
10 | }
11 |
12 | @OptIn(ExperimentalKotlinGradlePluginApi::class)
13 | kotlin {
14 | nativeTargets()
15 |
16 | compilerOptions {
17 | optIn.addAll(
18 | OptIns.ExperimentalForeignApi,
19 | )
20 | }
21 |
22 | sourceSets.commonMain.dependencies {
23 | api(kotlin("test"))
24 | api(projects.cryptographyProviderOpenssl3Api)
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/cryptography-providers/webcrypto/api/cryptography-provider-webcrypto.klib.api:
--------------------------------------------------------------------------------
1 | // Klib ABI Dump
2 | // Targets: [js, wasmJs]
3 | // Rendering settings:
4 | // - Signature version: 2
5 | // - Show manifest properties: true
6 | // - Show declarations: true
7 |
8 | // Library unique name:
9 | final val dev.whyoleg.cryptography.providers.webcrypto/WebCrypto // dev.whyoleg.cryptography.providers.webcrypto/WebCrypto|@dev.whyoleg.cryptography.CryptographyProvider.Companion{}WebCrypto[0]
10 | final fun (dev.whyoleg.cryptography/CryptographyProvider.Companion).(): dev.whyoleg.cryptography/CryptographyProvider // dev.whyoleg.cryptography.providers.webcrypto/WebCrypto.|@dev.whyoleg.cryptography.CryptographyProvider.Companion(){}[0]
11 |
12 | // Targets: [js]
13 | final val dev.whyoleg.cryptography.providers.webcrypto/initHook // dev.whyoleg.cryptography.providers.webcrypto/initHook|{}initHook[0]
14 | final fun (): dynamic // dev.whyoleg.cryptography.providers.webcrypto/initHook.|(){}[0]
15 |
--------------------------------------------------------------------------------
/cryptography-providers/webcrypto/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | import ckbuild.*
6 | import org.jetbrains.kotlin.gradle.*
7 |
8 | plugins {
9 | id("ckbuild.multiplatform-library")
10 | id("ckbuild.multiplatform-provider-tests")
11 | }
12 |
13 | description = "cryptography-kotlin WebCrypto provider"
14 |
15 | @OptIn(ExperimentalKotlinGradlePluginApi::class)
16 | kotlin {
17 | jsTarget()
18 | wasmJsTarget()
19 |
20 | compilerOptions {
21 | optIn.addAll(
22 | OptIns.DelicateCryptographyApi,
23 | OptIns.CryptographyProviderApi,
24 | )
25 | freeCompilerArgs.add("-Xexpect-actual-classes")
26 | }
27 |
28 | sourceSets.commonMain.dependencies {
29 | api(projects.cryptographyCore)
30 | implementation(projects.cryptographyProviderBase)
31 | }
32 | }
33 |
34 | providerTests {
35 | packageName.set("dev.whyoleg.cryptography.providers.webcrypto")
36 | providerInitializers.put("WebCrypto", "CryptographyProvider.WebCrypto")
37 | }
38 |
--------------------------------------------------------------------------------
/cryptography-providers/webcrypto/src/commonMain/kotlin/WebCryptoCryptographyProvider.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.webcrypto
6 |
7 | import dev.whyoleg.cryptography.*
8 | import dev.whyoleg.cryptography.algorithms.*
9 | import dev.whyoleg.cryptography.providers.webcrypto.algorithms.*
10 |
11 | internal val defaultProvider = lazy { WebCryptoCryptographyProvider }
12 |
13 | public val CryptographyProvider.Companion.WebCrypto: CryptographyProvider by defaultProvider
14 |
15 | internal object WebCryptoCryptographyProvider : CryptographyProvider() {
16 | override val name: String get() = "WebCrypto"
17 |
18 | @Suppress("UNCHECKED_CAST")
19 | override fun getOrNull(identifier: CryptographyAlgorithmId): A? = when (identifier) {
20 | SHA1 -> WebCryptoDigest.sha1
21 | SHA256 -> WebCryptoDigest.sha256
22 | SHA384 -> WebCryptoDigest.sha384
23 | SHA512 -> WebCryptoDigest.sha512
24 | HMAC -> WebCryptoHmac
25 | AES.CBC -> WebCryptoAesCbc
26 | AES.CTR -> WebCryptoAesCtr
27 | AES.GCM -> WebCryptoAesGcm
28 | RSA.OAEP -> WebCryptoRsaOaep
29 | RSA.PSS -> WebCryptoRsaPss
30 | RSA.PKCS1 -> WebCryptoRsaPkcs1
31 | ECDSA -> WebCryptoEcdsa
32 | ECDH -> WebCryptoEcdh
33 | PBKDF2 -> WebCryptoPbkdf2
34 | HKDF -> WebCryptoHkdf
35 | else -> null
36 | } as A?
37 | }
38 |
--------------------------------------------------------------------------------
/cryptography-providers/webcrypto/src/commonMain/kotlin/algorithms/WebCryptoDigest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.webcrypto.algorithms
6 |
7 | import dev.whyoleg.cryptography.*
8 | import dev.whyoleg.cryptography.algorithms.*
9 | import dev.whyoleg.cryptography.operations.*
10 | import dev.whyoleg.cryptography.providers.webcrypto.internal.*
11 | import kotlinx.io.*
12 | import kotlinx.io.bytestring.*
13 | import kotlinx.io.bytestring.unsafe.*
14 |
15 | internal class WebCryptoDigest private constructor(
16 | private val algorithm: String,
17 | override val id: CryptographyAlgorithmId,
18 | ) : Digest, Hasher {
19 | companion object {
20 | val sha1 = WebCryptoDigest("SHA-1", SHA1)
21 | val sha256 = WebCryptoDigest("SHA-256", SHA256)
22 | val sha384 = WebCryptoDigest("SHA-384", SHA384)
23 | val sha512 = WebCryptoDigest("SHA-512", SHA512)
24 | }
25 |
26 | override fun hasher(): Hasher = this
27 |
28 | override suspend fun hash(data: ByteArray): ByteArray {
29 | return WebCrypto.digest(algorithm, data)
30 | }
31 |
32 | @OptIn(UnsafeByteStringApi::class)
33 | override suspend fun hash(data: RawSource): ByteString {
34 | return UnsafeByteStringOperations.wrapUnsafe(hash(data.buffered().readByteArray()))
35 | }
36 |
37 | override fun createHashFunction(): HashFunction = nonBlocking()
38 | override fun hashBlocking(data: ByteArray): ByteArray = nonBlocking()
39 | override fun hashBlocking(data: RawSource): ByteString = nonBlocking()
40 | }
41 |
--------------------------------------------------------------------------------
/cryptography-providers/webcrypto/src/commonMain/kotlin/internal/Keys.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024-2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.webcrypto.internal
6 |
7 | internal expect interface CryptoKey
8 |
9 | internal expect interface CryptoKeyPair {
10 | val privateKey: CryptoKey
11 | val publicKey: CryptoKey
12 | }
13 |
14 | internal expect val CryptoKey.algorithm: Algorithm
15 |
--------------------------------------------------------------------------------
/cryptography-providers/webcrypto/src/commonMain/kotlin/internal/WebCrypto.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.webcrypto.internal
6 |
7 | internal expect object WebCrypto {
8 | suspend fun digest(algorithmName: String, data: ByteArray): ByteArray
9 |
10 | suspend fun encrypt(algorithm: Algorithm, key: CryptoKey, data: ByteArray): ByteArray
11 | suspend fun decrypt(algorithm: Algorithm, key: CryptoKey, data: ByteArray): ByteArray
12 |
13 | suspend fun sign(algorithm: Algorithm, key: CryptoKey, data: ByteArray): ByteArray
14 | suspend fun verify(algorithm: Algorithm, key: CryptoKey, signature: ByteArray, data: ByteArray): Boolean
15 |
16 | suspend fun deriveBits(algorithm: Algorithm, baseKey: CryptoKey, length: Int): ByteArray
17 |
18 | suspend fun importKey(
19 | format: String,
20 | keyData: ByteArray,
21 | algorithm: Algorithm,
22 | extractable: Boolean,
23 | keyUsages: Array,
24 | ): CryptoKey
25 |
26 | suspend fun exportKey(format: String, key: CryptoKey): ByteArray
27 |
28 | suspend fun generateKey(algorithm: Algorithm, extractable: Boolean, keyUsages: Array): CryptoKey
29 |
30 | suspend fun generateKeyPair(algorithm: Algorithm, extractable: Boolean, keyUsages: Array): CryptoKeyPair
31 | }
32 |
--------------------------------------------------------------------------------
/cryptography-providers/webcrypto/src/commonMain/kotlin/internal/digest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.webcrypto.internal
6 |
7 | import dev.whyoleg.cryptography.*
8 | import dev.whyoleg.cryptography.algorithms.*
9 |
10 | internal fun CryptographyAlgorithmId.blockSizeBits(): Int = when (this) {
11 | SHA1 -> 64
12 | SHA256 -> 64
13 | SHA384 -> 128
14 | SHA512 -> 128
15 | else -> throw IllegalStateException("Unsupported hash algorithm: $name")
16 | } * 8
17 |
18 | internal fun CryptographyAlgorithmId.hashAlgorithmName(): String = when (this) {
19 | SHA1 -> "SHA-1"
20 | SHA256 -> "SHA-256"
21 | SHA384 -> "SHA-384"
22 | SHA512 -> "SHA-512"
23 | else -> throw IllegalStateException("Unsupported hash algorithm: $name")
24 | }
25 |
26 | internal fun CryptographyAlgorithmId.digestSize(): Int = when (this) {
27 | SHA1 -> 20
28 | SHA256 -> 32
29 | SHA384 -> 48
30 | SHA512 -> 64
31 | else -> throw IllegalStateException("Unsupported hash algorithm: $name")
32 | }
33 |
34 | internal fun hashSize(hashAlgorithmName: String): Int = when (hashAlgorithmName) {
35 | "SHA-1" -> 20
36 | "SHA-256" -> 32
37 | "SHA-384" -> 48
38 | "SHA-512" -> 64
39 | else -> throw IllegalStateException("Unsupported hash algorithm: $hashAlgorithmName")
40 | }
41 |
--------------------------------------------------------------------------------
/cryptography-providers/webcrypto/src/commonMain/kotlin/internal/utils.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.webcrypto.internal
6 |
7 | internal fun nonBlocking(): Nothing = throw IllegalStateException("Only non-blocking(suspend) calls are supported in WebCrypto")
8 |
--------------------------------------------------------------------------------
/cryptography-providers/webcrypto/src/commonMain/kotlin/materials/WebCryptoAsymmetricKeyGenerator.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.webcrypto.materials
6 |
7 | import dev.whyoleg.cryptography.materials.key.*
8 | import dev.whyoleg.cryptography.providers.webcrypto.internal.*
9 |
10 | internal class WebCryptoAsymmetricKeyGenerator(
11 | private val algorithm: Algorithm,
12 | private val keyUsages: Array,
13 | private val keyPairWrapper: (CryptoKeyPair) -> K,
14 | ) : KeyGenerator {
15 | override suspend fun generateKey(): K {
16 | return keyPairWrapper(WebCrypto.generateKeyPair(algorithm, true, keyUsages))
17 | }
18 |
19 | override fun generateKeyBlocking(): K = nonBlocking()
20 | }
21 |
--------------------------------------------------------------------------------
/cryptography-providers/webcrypto/src/commonMain/kotlin/materials/WebCryptoEncodableKey.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.webcrypto.materials
6 |
7 | import dev.whyoleg.cryptography.materials.key.*
8 | import dev.whyoleg.cryptography.providers.webcrypto.internal.*
9 |
10 | internal abstract class WebCryptoEncodableKey(
11 | private val key: CryptoKey,
12 | private val keyProcessor: WebCryptoKeyProcessor,
13 | ) : EncodableKey {
14 | override suspend fun encodeToByteArray(format: KF): ByteArray = keyProcessor.afterEncoding(
15 | format = format,
16 | key = WebCrypto.exportKey(keyProcessor.stringFormat(format), key)
17 | )
18 |
19 | override fun encodeToByteArrayBlocking(format: KF): ByteArray = nonBlocking()
20 | }
21 |
--------------------------------------------------------------------------------
/cryptography-providers/webcrypto/src/commonMain/kotlin/materials/WebCryptoKeyDecoder.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.webcrypto.materials
6 |
7 | import dev.whyoleg.cryptography.materials.key.*
8 | import dev.whyoleg.cryptography.providers.webcrypto.internal.*
9 |
10 | internal class WebCryptoKeyDecoder(
11 | private val algorithm: Algorithm,
12 | private val keyProcessor: WebCryptoKeyProcessor,
13 | private val keyWrapper: WebCryptoKeyWrapper,
14 | ) : KeyDecoder {
15 | override suspend fun decodeFromByteArray(format: KF, bytes: ByteArray): K = keyWrapper.wrap(
16 | WebCrypto.importKey(
17 | format = keyProcessor.stringFormat(format),
18 | keyData = keyProcessor.beforeDecoding(algorithm, format, bytes),
19 | algorithm = algorithm,
20 | extractable = true,
21 | keyUsages = keyWrapper.usages
22 | )
23 | )
24 |
25 | override fun decodeFromByteArrayBlocking(format: KF, bytes: ByteArray): K = nonBlocking()
26 | }
27 |
--------------------------------------------------------------------------------
/cryptography-providers/webcrypto/src/commonMain/kotlin/materials/WebCryptoKeyProcessor.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.webcrypto.materials
6 |
7 | import dev.whyoleg.cryptography.materials.key.*
8 | import dev.whyoleg.cryptography.providers.webcrypto.internal.*
9 |
10 | internal abstract class WebCryptoKeyProcessor {
11 | abstract fun stringFormat(format: KF): String
12 | abstract fun beforeDecoding(algorithm: Algorithm, format: KF, key: ByteArray): ByteArray
13 | abstract fun afterEncoding(format: KF, key: ByteArray): ByteArray
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/cryptography-providers/webcrypto/src/commonMain/kotlin/materials/WebCryptoKeyWrapper.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.webcrypto.materials
6 |
7 | import dev.whyoleg.cryptography.materials.key.*
8 | import dev.whyoleg.cryptography.providers.webcrypto.internal.*
9 |
10 | internal class WebCryptoKeyWrapper(
11 | val usages: Array,
12 | val wrap: (CryptoKey) -> K,
13 | )
14 |
--------------------------------------------------------------------------------
/cryptography-providers/webcrypto/src/commonMain/kotlin/materials/WebCryptoSymmetricKeyGenerator.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.webcrypto.materials
6 |
7 | import dev.whyoleg.cryptography.materials.key.*
8 | import dev.whyoleg.cryptography.providers.webcrypto.internal.*
9 |
10 | internal class WebCryptoSymmetricKeyGenerator(
11 | private val algorithm: Algorithm,
12 | private val keyWrapper: WebCryptoKeyWrapper,
13 | ) : KeyGenerator {
14 | override suspend fun generateKey(): K = keyWrapper.wrap(
15 | WebCrypto.generateKey(
16 | algorithm = algorithm,
17 | extractable = true,
18 | keyUsages = keyWrapper.usages
19 | )
20 | )
21 |
22 | override fun generateKeyBlocking(): K = nonBlocking()
23 | }
24 |
--------------------------------------------------------------------------------
/cryptography-providers/webcrypto/src/commonMain/kotlin/operations/WebCryptoSignatureGenerator.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.webcrypto.operations
6 |
7 | import dev.whyoleg.cryptography.operations.*
8 | import dev.whyoleg.cryptography.providers.webcrypto.internal.*
9 | import kotlinx.io.*
10 | import kotlinx.io.bytestring.*
11 | import kotlinx.io.bytestring.unsafe.*
12 |
13 | internal class WebCryptoSignatureGenerator(
14 | private val algorithm: Algorithm,
15 | private val key: CryptoKey,
16 | ) : SignatureGenerator {
17 | override suspend fun generateSignature(data: ByteArray): ByteArray {
18 | return WebCrypto.sign(algorithm, key, data)
19 | }
20 |
21 | @OptIn(UnsafeByteStringApi::class)
22 | override suspend fun generateSignature(data: RawSource): ByteString {
23 | return UnsafeByteStringOperations.wrapUnsafe(generateSignature(data.buffered().readByteArray()))
24 | }
25 |
26 | override fun createSignFunction(): SignFunction = nonBlocking()
27 | override fun generateSignatureBlocking(data: ByteArray): ByteArray = nonBlocking()
28 | override fun generateSignatureBlocking(data: RawSource): ByteString = nonBlocking()
29 | }
30 |
--------------------------------------------------------------------------------
/cryptography-providers/webcrypto/src/commonTest/kotlin/DefaultProviderTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.webcrypto
6 |
7 | import dev.whyoleg.cryptography.*
8 | import dev.whyoleg.cryptography.providers.tests.*
9 |
10 | class WebCryptoDefaultProviderTest : DefaultProviderTest(CryptographyProvider.WebCrypto)
11 |
--------------------------------------------------------------------------------
/cryptography-providers/webcrypto/src/jsMain/kotlin/WebCryptoCryptographyProvider.js.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.webcrypto
6 |
7 | import dev.whyoleg.cryptography.*
8 |
9 | // declaration should be public for EagerInitialization to work
10 | // Deprecated to make it `internal`ish
11 | @Suppress("DEPRECATION")
12 | @OptIn(ExperimentalStdlibApi::class, ExperimentalJsExport::class)
13 | @EagerInitialization
14 | @JsExport
15 | @Deprecated("", level = DeprecationLevel.HIDDEN)
16 | public val initHook: dynamic = CryptographyProvider.Registry.registerProvider(defaultProvider)
17 |
--------------------------------------------------------------------------------
/cryptography-providers/webcrypto/src/jsMain/kotlin/internal/Keys.js.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.webcrypto.internal
6 |
7 | internal actual external interface CryptoKey
8 |
9 | internal actual external interface CryptoKeyPair {
10 | actual val privateKey: CryptoKey
11 | actual val publicKey: CryptoKey
12 | }
13 |
14 | internal actual val CryptoKey.algorithm: Algorithm get() = keyAlgorithm(this)
15 |
16 | @Suppress("UNUSED_PARAMETER")
17 | private fun keyAlgorithm(key: CryptoKey): Algorithm = js("key.algorithm").unsafeCast()
18 |
--------------------------------------------------------------------------------
/cryptography-providers/webcrypto/src/jsMain/kotlin/internal/interop.js.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.webcrypto.internal
6 |
7 | import org.khronos.webgl.*
8 | import kotlin.coroutines.*
9 | import kotlin.js.Promise
10 |
11 | internal suspend fun Promise.await() = suspendCoroutine { continuation ->
12 | then(
13 | { continuation.resume(it); null },
14 | { continuation.resumeWithException(it); null }
15 | )
16 | }
17 |
18 | internal fun ArrayBuffer.toByteArray(): ByteArray = Int8Array(this).unsafeCast()
19 |
20 | internal fun ByteArray.toInt8Array(): Int8Array = this.unsafeCast()
21 |
--------------------------------------------------------------------------------
/cryptography-providers/webcrypto/src/wasmJsMain/kotlin/WebCryptoCryptographyProvider.wasmJs.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.webcrypto
6 |
7 | import dev.whyoleg.cryptography.*
8 |
9 | @Suppress("DEPRECATION")
10 | @OptIn(ExperimentalStdlibApi::class)
11 | @EagerInitialization
12 | internal val initHook = CryptographyProvider.Registry.registerProvider(defaultProvider)
13 |
--------------------------------------------------------------------------------
/cryptography-providers/webcrypto/src/wasmJsMain/kotlin/internal/Keys.wasmJs.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.providers.webcrypto.internal
6 |
7 | @Suppress("ACTUAL_CLASSIFIER_MUST_HAVE_THE_SAME_SUPERTYPES_AS_NON_FINAL_EXPECT_CLASSIFIER_WARNING")
8 | internal actual external interface CryptoKey : JsAny
9 |
10 | @Suppress("ACTUAL_CLASSIFIER_MUST_HAVE_THE_SAME_SUPERTYPES_AS_NON_FINAL_EXPECT_CLASSIFIER_WARNING")
11 | internal actual external interface CryptoKeyPair : JsAny {
12 | actual val privateKey: CryptoKey
13 | actual val publicKey: CryptoKey
14 | }
15 |
16 | internal actual val CryptoKey.algorithm: Algorithm get() = keyAlgorithm(this)
17 |
18 | @Suppress("UNUSED_PARAMETER")
19 | private fun keyAlgorithm(key: CryptoKey): Algorithm = js("key.algorithm")
20 |
--------------------------------------------------------------------------------
/cryptography-random/api/cryptography-random.api:
--------------------------------------------------------------------------------
1 | public abstract class dev/whyoleg/cryptography/random/CryptographyRandom : kotlin/random/Random {
2 | public static final field Default Ldev/whyoleg/cryptography/random/CryptographyRandom$Default;
3 | public fun ()V
4 | }
5 |
6 | public final class dev/whyoleg/cryptography/random/CryptographyRandom$Default : dev/whyoleg/cryptography/random/CryptographyRandom {
7 | public fun nextBits (I)I
8 | public fun nextBoolean ()Z
9 | public fun nextBytes (I)[B
10 | public fun nextBytes ([B)[B
11 | public fun nextBytes ([BII)[B
12 | public fun nextDouble ()D
13 | public fun nextDouble (D)D
14 | public fun nextDouble (DD)D
15 | public fun nextFloat ()F
16 | public fun nextInt ()I
17 | public fun nextInt (I)I
18 | public fun nextInt (II)I
19 | public fun nextLong ()J
20 | public fun nextLong (J)J
21 | public fun nextLong (JJ)J
22 | }
23 |
24 | public final class dev/whyoleg/cryptography/random/CryptographyRandom_jvmKt {
25 | public static final fun asCryptographyRandom (Ljava/security/SecureRandom;)Ldev/whyoleg/cryptography/random/CryptographyRandom;
26 | public static final fun asSecureRandom (Ldev/whyoleg/cryptography/random/CryptographyRandom;)Ljava/security/SecureRandom;
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/cryptography-random/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | import ckbuild.*
6 | import org.jetbrains.kotlin.gradle.*
7 |
8 | plugins {
9 | id("ckbuild.multiplatform-library")
10 | }
11 |
12 | description = "cryptography-kotlin random API"
13 |
14 | @OptIn(ExperimentalKotlinGradlePluginApi::class)
15 | kotlin {
16 | jvmTarget()
17 | jsTarget()
18 | nativeTargets()
19 | wasmTargets()
20 |
21 | applyDefaultHierarchyTemplate {
22 | common {
23 | group("linuxAndAndroidNative") {
24 | group("linux")
25 | group("androidNative")
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/cryptography-random/src/commonMain/kotlin/AbstractRandom.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.random
6 |
7 | internal abstract class AbstractRandom : CryptographyRandom() {
8 | final override fun nextBits(bitCount: Int): Int {
9 | val numBytes = (bitCount + 7) / 8
10 | val b = nextBytes(numBytes)
11 |
12 | var next = 0
13 | for (i in 0 until numBytes) {
14 | next = (next shl 8) + (b[i].toInt() and 0xFF)
15 | }
16 | return next ushr numBytes * 8 - bitCount
17 | }
18 |
19 | //we can also implement nextBytes(array, index, index)
20 | final override fun nextBytes(array: ByteArray): ByteArray {
21 | if (array.isNotEmpty()) fillBytes(array)
22 | return array
23 | }
24 |
25 | protected abstract fun fillBytes(array: ByteArray)
26 | }
27 |
--------------------------------------------------------------------------------
/cryptography-random/src/jsMain/kotlin/CryptographyRandom.js.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.random
6 |
7 | import org.khronos.webgl.*
8 |
9 | internal actual fun defaultCryptographyRandom(): CryptographyRandom = WebCryptoCryptographyRandom
10 |
11 | private object WebCryptoCryptographyRandom : AbstractRandom() {
12 | private const val MAX_ARRAY_SIZE = 65536
13 | private val crypto: Crypto = getCrypto()
14 | override fun fillBytes(array: ByteArray) {
15 | fillBytes(array.unsafeCast())
16 | }
17 |
18 | private fun fillBytes(jsArray: Int8Array) {
19 | val size = jsArray.length
20 | if (size <= MAX_ARRAY_SIZE) {
21 | crypto.getRandomValues(jsArray)
22 | } else {
23 | var filled = 0
24 | do {
25 | val chunkSize = minOf(MAX_ARRAY_SIZE, size - filled)
26 | crypto.getRandomValues(jsArray.subarray(filled, filled + chunkSize))
27 | filled += chunkSize
28 | } while (filled < size)
29 | }
30 | }
31 | }
32 |
33 | private external interface Crypto {
34 | fun getRandomValues(array: Int8Array)
35 | }
36 |
37 | //language=JavaScript
38 | private fun getCrypto(): Crypto = js("(globalThis ? globalThis.crypto : (window.crypto || window.msCrypto))")
39 |
--------------------------------------------------------------------------------
/cryptography-random/src/linuxAndAndroidNativeMain/kotlin/CryptographyRandom.linuxAndAndroidNative.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.random
6 |
7 | internal actual fun defaultCryptographyRandom(): CryptographyRandom = createGetRandom() ?: createURandom()
8 |
--------------------------------------------------------------------------------
/cryptography-random/src/linuxAndAndroidNativeMain/kotlin/GetRandom.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.random
6 |
7 | import kotlinx.cinterop.*
8 | import platform.posix.*
9 |
10 | internal fun createGetRandom(): CryptographyRandom? = if (getRandomAvailable()) GetRandom else null
11 |
12 | private object GetRandom : LinuxRandom() {
13 | @OptIn(ExperimentalForeignApi::class, UnsafeNumber::class)
14 | override fun fillBytes(pointer: CPointer, size: Int): Int = getrandom(pointer, size.convert(), 0.convert())
15 | }
16 |
17 | // https://docs.piston.rs/dev_menu/libc/constant.SYS_getrandom.html
18 | private const val SYS_getrandom = 318
19 |
20 | // https://docs.piston.rs/dev_menu/libc/constant.GRND_NONBLOCK.html
21 | private const val GRND_NONBLOCK = 0x0001
22 |
23 | private fun getRandomAvailable(): Boolean {
24 | val stubArray = ByteArray(1)
25 | val stubSize = stubArray.size
26 |
27 | @OptIn(ExperimentalForeignApi::class, UnsafeNumber::class)
28 | stubArray.usePinned {
29 | if (getrandom(it.addressOf(0), stubSize.convert(), GRND_NONBLOCK.convert()) >= 0) return true
30 | }
31 |
32 | return when (errno) {
33 | ENOSYS, EPERM -> false
34 | else -> true
35 | }
36 | }
37 |
38 | @OptIn(ExperimentalForeignApi::class, UnsafeNumber::class)
39 | private fun getrandom(out: CPointer?, outSize: size_t, flags: UInt): Int =
40 | syscall(SYS_getrandom.convert(), out, outSize, flags).convert()
41 |
--------------------------------------------------------------------------------
/cryptography-random/src/linuxAndAndroidNativeMain/kotlin/LinuxRandom.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.random
6 |
7 | import kotlinx.cinterop.*
8 |
9 | @OptIn(ExperimentalForeignApi::class)
10 | internal abstract class LinuxRandom : AbstractRandom() {
11 | protected abstract fun fillBytes(pointer: CPointer, size: Int): Int
12 | final override fun fillBytes(array: ByteArray) {
13 | val size = array.size
14 | array.usePinned {
15 | var filled = 0
16 | while (filled < size) {
17 | val chunkSize = fillBytes(it.addressOf(filled), size - filled)
18 | if (chunkSize < 0) errnoCheck()
19 | filled += chunkSize
20 | }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/cryptography-random/src/linuxAndAndroidNativeMain/kotlin/errno.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.random
6 |
7 | import platform.posix.*
8 |
9 | internal fun errnoCheck(): Nothing {
10 | val message = when (val value = errno) {
11 | EFAULT -> "The address referred to by buf is outside the accessible address space."
12 | EINTR -> "The call was interrupted by a signal handler; see the description of how interrupted read(2) calls on 'slow' devices are handled with and without the SA_RESTART flag in the signal(7) man page."
13 | EINVAL -> "An invalid flag was specified in flags."
14 | else -> "POSIX error: $value"
15 | }
16 | error(message)
17 | }
18 |
--------------------------------------------------------------------------------
/cryptography-random/src/linuxTest/kotlin/LinuxRandomTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.random
6 |
7 | class URandomTest : CryptographyRandomTest(createURandom())
8 |
9 | class GetRandomTest : CryptographyRandomTest(createGetRandom()!!)
10 |
--------------------------------------------------------------------------------
/cryptography-random/src/mingwMain/kotlin/CryptographyRandom.mingw.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.random
6 |
7 | import kotlinx.cinterop.*
8 | import platform.windows.*
9 |
10 | internal actual fun defaultCryptographyRandom(): CryptographyRandom = BCryptCryptographyRandom
11 |
12 | private object BCryptCryptographyRandom : AbstractRandom() {
13 | override fun fillBytes(array: ByteArray) {
14 | @OptIn(ExperimentalForeignApi::class)
15 | val status = array.asUByteArray().usePinned { pinned ->
16 | BCryptGenRandom(
17 | hAlgorithm = null,
18 | pbBuffer = pinned.addressOf(0),
19 | cbBuffer = pinned.get().size.convert(),
20 | dwFlags = BCRYPT_USE_SYSTEM_PREFERRED_RNG.toUInt()
21 | )
22 | }
23 | if (status != 0) error("BCryptGenRandom failed: $status")
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/cryptography-random/src/wasmWasiMain/kotlin/CryptographyRandom.wasmWasi.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.random
6 |
7 | import kotlin.wasm.*
8 | import kotlin.wasm.unsafe.*
9 |
10 | internal actual fun defaultCryptographyRandom(): CryptographyRandom = WasiPreview1CryptographyRandom
11 |
12 | private object WasiPreview1CryptographyRandom : AbstractRandom() {
13 | @OptIn(UnsafeWasmMemoryApi::class)
14 | override fun fillBytes(array: ByteArray) {
15 | val size = array.size
16 | withScopedMemoryAllocator { allocator ->
17 | val pointer = allocator.allocate(size)
18 | val result = wasiRandomGet(pointer.address.toInt(), size)
19 | if (result != 0) error("wasi error code: $result")
20 |
21 | repeat(size) {
22 | array[it] = (pointer + it).loadByte()
23 | }
24 | }
25 | }
26 | }
27 |
28 | @WasmImport("wasi_snapshot_preview1", "random_get")
29 | private external fun wasiRandomGet(address: Int, size: Int): Int
30 |
--------------------------------------------------------------------------------
/cryptography-serialization/asn1/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | import ckbuild.*
6 |
7 | plugins {
8 | id("ckbuild.multiplatform-library")
9 | alias(libs.plugins.kotlin.plugin.serialization)
10 | }
11 |
12 | description = "cryptography-kotlin ASN.1 (DER) API"
13 |
14 | kotlin {
15 | jvmTarget()
16 | jsTarget()
17 | nativeTargets()
18 | wasmTargets()
19 |
20 | sourceSets {
21 | commonMain.dependencies {
22 | api(projects.cryptographyBigint)
23 | api(libs.kotlinx.serialization.core)
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/cryptography-serialization/asn1/modules/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | import ckbuild.*
6 |
7 | plugins {
8 | id("ckbuild.multiplatform-library")
9 | alias(libs.plugins.kotlin.plugin.serialization)
10 | }
11 |
12 | description = "cryptography-kotlin ASN.1 modules"
13 |
14 | kotlin {
15 | jvmTarget()
16 | jsTarget()
17 | nativeTargets()
18 | wasmTargets()
19 |
20 | sourceSets {
21 | commonMain.dependencies {
22 | api(projects.cryptographySerializationAsn1)
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/cryptography-serialization/asn1/modules/src/commonMain/kotlin/AlgorithmIdentifier.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.serialization.asn1.modules
6 |
7 | import dev.whyoleg.cryptography.serialization.asn1.*
8 |
9 | /**
10 | * ```
11 | * AlgorithmIdentifier ::= SEQUENCE {
12 | * algorithm OBJECT IDENTIFIER,
13 | * parameters ANY DEFINED BY algorithm OPTIONAL
14 | * }
15 | * ```
16 | */
17 | public interface AlgorithmIdentifier {
18 | public val algorithm: ObjectIdentifier
19 | public val parameters: Any?
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/cryptography-serialization/asn1/modules/src/commonMain/kotlin/KeyAlgorithmIdentifier.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.serialization.asn1.modules
6 |
7 | import dev.whyoleg.cryptography.serialization.asn1.*
8 | import kotlinx.serialization.*
9 |
10 | @Serializable(KeyAlgorithmIdentifierSerializer::class)
11 | public interface KeyAlgorithmIdentifier : AlgorithmIdentifier
12 |
13 | public class UnknownKeyAlgorithmIdentifier(override val algorithm: ObjectIdentifier) : KeyAlgorithmIdentifier {
14 | override val parameters: Nothing? get() = null
15 | }
16 |
17 |
--------------------------------------------------------------------------------
/cryptography-serialization/asn1/modules/src/commonMain/kotlin/KeyInfo.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.serialization.asn1.modules
6 |
7 | import dev.whyoleg.cryptography.serialization.asn1.*
8 | import kotlinx.serialization.*
9 |
10 | /**
11 | * ```
12 | * SubjectPublicKeyInfo ::= SEQUENCE {
13 | * algorithm AlgorithmIdentifier,
14 | * subjectPublicKey BIT STRING
15 | * }
16 | * ```
17 | */
18 | @Serializable
19 | public class SubjectPublicKeyInfo(
20 | @Contextual
21 | public val algorithm: KeyAlgorithmIdentifier,
22 | public val subjectPublicKey: BitArray,
23 | )
24 |
25 | /**
26 | * ```
27 | * PrivateKeyInfo ::= SEQUENCE {
28 | * version Version,
29 | * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
30 | * privateKey PrivateKey,
31 | * attributes [0] IMPLICIT Attributes OPTIONAL
32 | * }
33 | *
34 | * Version ::= INTEGER
35 | * PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
36 | * PrivateKey ::= OCTET STRING
37 | * ```
38 | *
39 | * `Attributes` is not yet supported:
40 | * ```
41 | * Attributes ::= SET OF Attribute
42 | * Attribute ::= SEQUENCE {
43 | * type OBJECT IDENTIFIER,
44 | * values AttributeSetValue
45 | * }
46 | * AttributeSetValue ::= SET OF ANY
47 | * ```
48 | */
49 | @Serializable
50 | public class PrivateKeyInfo(
51 | public val version: Int,
52 | @Contextual
53 | public val privateKeyAlgorithm: KeyAlgorithmIdentifier,
54 | public val privateKey: ByteArray,
55 | )
56 |
--------------------------------------------------------------------------------
/cryptography-serialization/asn1/src/commonMain/kotlin/Annotations.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.serialization.asn1
6 |
7 | import kotlinx.serialization.*
8 |
9 | @Target(AnnotationTarget.PROPERTY)
10 | @OptIn(ExperimentalSerializationApi::class)
11 | @SerialInfo
12 | public annotation class ContextSpecificTag(
13 | public val classIndex: Byte,
14 | public val type: TagType,
15 | ) {
16 | public enum class TagType { IMPLICIT, EXPLICIT }
17 | }
18 |
--------------------------------------------------------------------------------
/cryptography-serialization/asn1/src/commonMain/kotlin/BitArray.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.serialization.asn1
6 |
7 | import kotlinx.serialization.*
8 |
9 | @Serializable
10 | public class BitArray(
11 | public val unusedBits: Int,
12 | public val byteArray: ByteArray,
13 | ) {
14 | init {
15 | if (byteArray.isEmpty()) {
16 | check(unusedBits == 0) { "empty array couldn't have unused bits" }
17 | } else {
18 | check(unusedBits <= byteArray.last().countTrailingZeroBits()) { "At least $unusedBits last bits should be unused" }
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/cryptography-serialization/asn1/src/commonMain/kotlin/ObjectIdentifier.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.serialization.asn1
6 |
7 | import kotlinx.serialization.*
8 | import kotlin.jvm.*
9 |
10 | @Serializable
11 | @JvmInline
12 | public value class ObjectIdentifier(public val value: String) {
13 | public companion object
14 | }
15 |
--------------------------------------------------------------------------------
/cryptography-serialization/asn1/src/commonMain/kotlin/internal/ByteArrayOutput.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.serialization.asn1.internal
6 |
7 | internal class ByteArrayOutput {
8 | private var array: ByteArray = ByteArray(32)
9 | private var position: Int = 0
10 |
11 | val size: Int get() = position
12 |
13 | private fun ensureCapacity(elementsToAppend: Int) {
14 | if (position + elementsToAppend <= array.size) return
15 |
16 | array = array.copyOf((position + elementsToAppend).takeHighestOneBit() shl 1)
17 | }
18 |
19 | fun toByteArray(): ByteArray = array.copyOf(position)
20 |
21 | fun write(byte: Byte) {
22 | ensureCapacity(1)
23 | array[position++] = byte
24 | }
25 |
26 | fun write(byte: Int) {
27 | write(byte.toByte())
28 | }
29 |
30 | fun write(bytes: ByteArray) {
31 | if (bytes.isEmpty()) return
32 |
33 | ensureCapacity(bytes.size)
34 | bytes.copyInto(array, position)
35 | position += bytes.size
36 | }
37 |
38 | fun write(output: ByteArrayOutput) {
39 | if (output.size == 0) return
40 |
41 | ensureCapacity(output.position)
42 | output.array.copyInto(array, position, 0, output.position)
43 | position += output.position
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/cryptography-serialization/asn1/src/commonTest/kotlin/ObjectIdentifierEncodingTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.serialization.asn1
6 |
7 | import dev.whyoleg.cryptography.serialization.asn1.internal.*
8 | import kotlinx.serialization.*
9 | import kotlin.test.*
10 |
11 | @OptIn(ExperimentalStdlibApi::class)
12 | class ObjectIdentifierEncodingTest {
13 |
14 | @Test
15 | fun testSha256WithRSAEncryption() = checkOid(
16 | oid = "1.2.840.113549.1.1.11",
17 | hex = "06092a864886f70d01010b"
18 | )
19 |
20 | @Test
21 | fun testRSAEncryption() = checkOid(
22 | oid = "1.2.840.113549.1.1.1",
23 | hex = "06092a864886f70d010101"
24 | )
25 |
26 | @Test
27 | fun testOidWithZeroElement() = checkOid(
28 | oid = "1.3.132.0.34",
29 | hex = "06052b81040022"
30 | )
31 |
32 | @Test
33 | fun testOidWithRedundantZero() = checkOid(
34 | oid = "1.2.840.10045.2.1",
35 | hex = "06072a8648ce3d0201"
36 | )
37 |
38 | private fun checkOid(
39 | oid: String,
40 | hex: String,
41 | ) {
42 | val value = ObjectIdentifier(oid)
43 | val bytes = ByteArrayOutput().also { DerOutput(it).writeObjectIdentifier(null, value) }.toByteArray()
44 |
45 | assertEquals(hex, bytes.toHexString())
46 | assertEquals(value, DerInput(ByteArrayInput(bytes)).readObjectIdentifier(null))
47 |
48 | assertContentEquals(bytes, Der.encodeToByteArray(value))
49 | assertEquals(value, Der.decodeFromByteArray(bytes))
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/cryptography-serialization/asn1/src/commonTest/kotlin/SequenceEncodingTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.serialization.asn1
6 |
7 | import kotlinx.serialization.*
8 | import kotlin.test.*
9 |
10 | @OptIn(ExperimentalStdlibApi::class)
11 | class SequenceEncodingTest {
12 |
13 | @Serializable
14 | class SimpleAlgorithmIdentifier(
15 | val algorithm: ObjectIdentifier,
16 | val parameters: Nothing?,
17 | )
18 |
19 | @Test
20 | fun testAlgorithmIdentifier() {
21 | val algorithm = SimpleAlgorithmIdentifier(ObjectIdentifier("1.2.840.113549.1.1.11"), null)
22 | val bytes = Der.encodeToByteArray(algorithm)
23 | assertEquals("300d06092a864886f70d01010b0500", bytes.toHexString())
24 |
25 | val decoded = Der.decodeFromByteArray(bytes)
26 |
27 | assertEquals(algorithm.algorithm, decoded.algorithm)
28 | assertNull(decoded.parameters)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/cryptography-serialization/pem/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | import ckbuild.*
6 |
7 | plugins {
8 | id("ckbuild.multiplatform-library")
9 | }
10 |
11 | description = "cryptography-kotlin PEM API"
12 |
13 | kotlin {
14 | jvmTarget()
15 | jsTarget()
16 | nativeTargets()
17 | wasmTargets()
18 |
19 | sourceSets {
20 | commonMain.dependencies {
21 | api(libs.kotlinx.io.core)
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/cryptography-serialization/pem/src/commonMain/kotlin/PemContent.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.serialization.pem
6 |
7 | import kotlinx.io.bytestring.*
8 | import kotlinx.io.bytestring.unsafe.*
9 |
10 | public class PemContent(
11 | public val label: PemLabel,
12 | public val bytes: ByteArray,
13 | ) {
14 | public constructor(
15 | label: PemLabel,
16 | byteString: ByteString,
17 | ) : this(label, byteString.toByteArray())
18 |
19 | @OptIn(UnsafeByteStringApi::class)
20 | public val byteString: ByteString get() = UnsafeByteStringOperations.wrapUnsafe(bytes)
21 | }
22 |
23 | public fun PemContent.ensurePemLabel(label: PemLabel): PemContent {
24 | check(this.label == label) { "Wrong PEM label, expected $label, actual ${this.label}" }
25 | return this
26 | }
27 |
--------------------------------------------------------------------------------
/cryptography-serialization/pem/src/commonMain/kotlin/PemLabel.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.serialization.pem
6 |
7 | import kotlin.jvm.*
8 |
9 | @JvmInline
10 | public value class PemLabel(public val representation: String) {
11 | public companion object {
12 | public val PublicKey: PemLabel = PemLabel("PUBLIC KEY")
13 | public val PrivateKey: PemLabel = PemLabel("PRIVATE KEY")
14 | public val RsaPublicKey: PemLabel = PemLabel("RSA PUBLIC KEY")
15 | public val RsaPrivateKey: PemLabel = PemLabel("RSA PRIVATE KEY")
16 | public val EcPrivateKey: PemLabel = PemLabel("EC PRIVATE KEY")
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/cryptography-version-catalog/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | plugins {
6 | `version-catalog`
7 | id("ckbuild.publication")
8 | }
9 |
10 | description = "cryptography-kotlin Gradle Version Catalog"
11 |
12 | catalog {
13 | versionCatalog {
14 | //just a hint on a version used by the library
15 | version("kotlin", libs.versions.kotlin.asProvider().get())
16 | val cryptographyVersion = version("cryptography", version.toString())
17 | (ckbuild.artifacts + "cryptography-bom").forEach { name ->
18 | library(
19 | /* alias = */ name.substringAfter("cryptography-"),
20 | /* group = */ "dev.whyoleg.cryptography",
21 | /* artifact = */ name
22 | ).versionRef(cryptographyVersion)
23 | }
24 | }
25 | }
26 |
27 | publishing {
28 | publications {
29 | val versionCatalog by creating(MavenPublication::class) {
30 | from(components["versionCatalog"])
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/docs/bom.md:
--------------------------------------------------------------------------------
1 | # BOM
2 |
3 | Library provides [Maven BOM](https://docs.gradle.org/current/userguide/platforms.html#sub:bom_import)
4 | which could simplify adding dependencies by allowing omitting versions.
5 | Additionally, Gradle will
6 | automatically [align dependencies](https://docs.gradle.org/current/userguide/dependency_version_alignment.html#aligning_versions_natively_with_gradle)
7 | of all modules because of direct dependency on the BOM module
8 |
9 | ## Using in your projects
10 |
11 | ```kotlin
12 | dependencies {
13 | implementation(platform("dev.whyoleg.cryptography:cryptography-bom:0.4.0"))
14 |
15 | // now you can declare other dependencies without a version
16 | implementation("dev.whyoleg.cryptography:cryptography-core")
17 | // some provider
18 | implementation("dev.whyoleg.cryptography:cryptography-provider-jdk")
19 | }
20 | ```
21 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (c) 2023-2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | #
4 |
5 | group=dev.whyoleg.cryptography
6 | version=0.4.0
7 | #Kotlin
8 | kotlin.mpp.import.enableKgpDependencyResolution=true
9 | kotlin.mpp.enableCInteropCommonization=true
10 | kotlin.native.ignoreDisabledTargets=true
11 | kotlin.js.yarn=false
12 | #Dokka
13 | org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
14 | org.jetbrains.dokka.experimental.gradle.pluginMode.nowarn=true
15 | #Android
16 | android.useAndroidX=true
17 | android.experimental.testOptions.managedDevices.allowOldApiLevelDevices=true
18 | android.suppressUnsupportedOptionWarnings=\
19 | android.experimental.testOptions.managedDevices.allowOldApiLevelDevices,\
20 | android.suppressUnsupportedOptionWarnings
21 | #Gradle
22 | org.gradle.kotlin.dsl.skipMetadataVersionCheck=false
23 | org.gradle.kotlin.dsl.allWarningsAsErrors=true
24 | org.gradle.parallel=true
25 | org.gradle.caching=true
26 | org.gradle.configureondemand=true
27 | org.gradle.configuration-cache=true
28 | org.gradle.configuration-cache.parallel=true
29 | org.gradle.jvmargs=-Xmx4g
30 |
--------------------------------------------------------------------------------
/gradle/gradle-daemon-jvm.properties:
--------------------------------------------------------------------------------
1 | #This file is generated by updateDaemonJvm
2 | toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/e2d97f28068cf05b0467aa8e97b19f69/redirect
3 | toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/a41f952f4496c2309be30fd168c6c117/redirect
4 | toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/e2d97f28068cf05b0467aa8e97b19f69/redirect
5 | toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/a41f952f4496c2309be30fd168c6c117/redirect
6 | toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/e7806cd9471741d622398825f14d2da6/redirect
7 | toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/0402cc5012ae8124ea0ad01bd29342ef/redirect
8 | toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/e2d97f28068cf05b0467aa8e97b19f69/redirect
9 | toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/a41f952f4496c2309be30fd168c6c117/redirect
10 | toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/86ea5d26c5757681ffe78d87258b45ec/redirect
11 | toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/ea8232621e1368089cec8b12816df5e3/redirect
12 | toolchainVersion=21
13 |
--------------------------------------------------------------------------------
/gradle/libs.updates.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | /**
6 | * run to check for dependencies:
7 | * ./gradlew dependencyUpdates --init-script gradle/libs.updates.gradle.kts --no-configuration-cache
8 | */
9 |
10 | initscript {
11 | repositories {
12 | gradlePluginPortal()
13 | }
14 | dependencies {
15 | classpath("com.github.ben-manes:gradle-versions-plugin:+")
16 | }
17 | }
18 |
19 | rootProject {
20 | apply()
21 | tasks.named("dependencyUpdates") {
22 | gradle.includedBuilds.forEach {
23 | dependsOn(it.task(":dependencyUpdates"))
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/whyoleg/cryptography-kotlin/5b1f52dfc418e1d6f0e4111c2fa5eaf6b844a8a2/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/karma.config.d/config.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | config.client = config.client || {}
6 | config.client.mocha = config.client.mocha || {}
7 | config.client.mocha.timeout = '6000s'
8 | config.browserNoActivityTimeout = 6000000
9 | config.browserDisconnectTimeout = 6000000
10 |
--------------------------------------------------------------------------------
/swiftinterop/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | import org.jetbrains.kotlin.gradle.dsl.*
6 |
7 | plugins {
8 | alias(libs.plugins.kotlin.jvm)
9 | `java-gradle-plugin`
10 | }
11 |
12 | dependencies {
13 | implementation(libs.kotlin.gradle.plugin)
14 | }
15 |
16 | kotlin {
17 | compilerOptions {
18 | languageVersion.set(KotlinVersion.KOTLIN_1_8)
19 | apiVersion.set(KotlinVersion.KOTLIN_1_8)
20 | }
21 | }
22 |
23 | dependencies {
24 | compileOnly(kotlin("stdlib"))
25 | compileOnly(libs.kotlin.gradle.plugin)
26 | }
27 |
28 | gradlePlugin {
29 | plugins {
30 | create("swiftinterop") {
31 | id = "dev.whyoleg.swiftinterop"
32 | implementationClass = "dev.whyoleg.swiftinterop.SwiftInteropPlugin"
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/swiftinterop/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | import cksettings.*
6 |
7 | pluginManagement {
8 | includeBuild("../build-settings")
9 | }
10 |
11 | plugins {
12 | id("cksettings.default")
13 | }
14 |
15 | dependencyResolutionManagement {
16 | versionCatalogs.named("libs") {
17 | from(files("../gradle/libs.versions.toml"))
18 | }
19 | }
20 |
21 | projects("swiftinterop")
22 |
--------------------------------------------------------------------------------
/swiftinterop/src/main/kotlin/SwiftInteropExtension.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.swiftinterop
6 |
7 | import org.gradle.api.model.*
8 | import org.gradle.api.provider.*
9 | import javax.inject.*
10 |
11 | abstract class SwiftInteropExtension @Inject constructor(objects: ObjectFactory) {
12 | val packageName: Property = objects.property(String::class.java)
13 |
14 | val swiftToolsVersion: Property = objects.property(String::class.java).convention("5.10")
15 |
16 | // TODO: make defaults equal to K/N values ?
17 | // TODO: rename to min*
18 | val iosVersion: Property = objects.property(String::class.java)
19 | val macosVersion: Property = objects.property(String::class.java)
20 | val tvosVersion: Property = objects.property(String::class.java)
21 | val watchosVersion: Property = objects.property(String::class.java)
22 |
23 | internal val swiftinteropModuleName = packageName.map { it.replace(".", "_") }
24 | }
25 |
--------------------------------------------------------------------------------
/swiftinterop/src/main/kotlin/tasks/LibtoolBuildStaticTask.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.swiftinterop.tasks
6 |
7 | import org.gradle.api.*
8 | import org.gradle.api.file.*
9 | import org.gradle.api.provider.*
10 | import org.gradle.api.tasks.*
11 | import org.gradle.process.*
12 | import javax.inject.*
13 |
14 | abstract class LibtoolBuildStaticTask : DefaultTask() {
15 |
16 | @get:Input
17 | abstract val swiftinteropModuleName: Property
18 |
19 | @get:InputFiles
20 | @get:PathSensitive(PathSensitivity.RELATIVE)
21 | abstract val objectFiles: ConfigurableFileCollection
22 |
23 | @get:OutputDirectory
24 | abstract val outputDirectory: DirectoryProperty
25 |
26 | @get:Inject
27 | abstract val exec: ExecOperations
28 |
29 | @TaskAction
30 | fun build() {
31 | outputDirectory.get().asFile.recreateDirectories()
32 |
33 | exec.exec { spec ->
34 | spec.commandLine(
35 | "libtool", "-static",
36 | "-o", outputDirectory.get().asFile.resolve("libswiftinterop_${swiftinteropModuleName.get()}.a").absolutePath,
37 | *objectFiles.asFileTree.map { it.absolutePath }.toTypedArray()
38 | )
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/swiftinterop/src/main/kotlin/tasks/XcodebuildBuildTarget.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.swiftinterop.tasks
6 |
7 | internal sealed interface XcodebuildBuildTarget {
8 | val destination: String
9 |
10 | enum class Generic(
11 | private val platform: String,
12 | val disambiguationClassifier: String,
13 | ) : XcodebuildBuildTarget {
14 | MACOS("macOS", "macos"),
15 | IOS("iOS", "ios"),
16 | IOS_SIMULATOR("iOS Simulator", "iosSimulator"),
17 | TVOS("tvOS", "tvos"),
18 | TVOS_SIMULATOR("tvOS Simulator", "tvosSimulator"),
19 | WATCHOS("watchOS", "watchos"),
20 | WATCHOS_SIMULATOR("watchOS Simulator", "watchosSimulator");
21 |
22 | override val destination: String get() = "generic/platform=$platform"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/swiftinterop/src/main/kotlin/tasks/utils.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.swiftinterop.tasks
6 |
7 | import java.io.*
8 |
9 | internal fun File.recreateDirectories() {
10 | deleteRecursively()
11 | mkdirs()
12 | }
13 |
--------------------------------------------------------------------------------
/tests-publication/gradle.properties:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (c) 2023 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | #
4 |
5 | #Gradle
6 | org.gradle.parallel=true
7 | org.gradle.caching=true
8 | org.gradle.configureondemand=true
9 | org.gradle.jvmargs=-Xmx2g
10 |
--------------------------------------------------------------------------------
/tests-publication/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/whyoleg/cryptography-kotlin/5b1f52dfc418e1d6f0e4111c2fa5eaf6b844a8a2/tests-publication/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/tests-publication/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/tests-publication/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | pluginManagement {
6 | repositories {
7 | mavenCentral()
8 | gradlePluginPortal()
9 | }
10 | }
11 |
12 | dependencyResolutionManagement {
13 | repositories {
14 | mavenCentral()
15 | }
16 |
17 | versionCatalogs {
18 | create("cryptographyLibs") {
19 | from("dev.whyoleg.cryptography:cryptography-version-catalog:0.4.0")
20 | }
21 | }
22 | }
23 |
24 | rootProject.name = "tests-publication"
25 |
--------------------------------------------------------------------------------
/tests-publication/src/commonTest/kotlin/JustTest.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | import dev.whyoleg.cryptography.*
6 | import dev.whyoleg.cryptography.algorithms.*
7 | import kotlinx.coroutines.test.*
8 | import kotlin.test.*
9 |
10 | class JustTest {
11 |
12 | @OptIn(ExperimentalStdlibApi::class)
13 | @Test
14 | fun test() = runTest {
15 | val digest =
16 | CryptographyProvider.Default
17 | .get(SHA256)
18 | .hasher()
19 | .hash("Hello World".encodeToByteArray())
20 | .toHexString()
21 |
22 | assertEquals("a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e", digest)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/testtool/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | plugins {
6 | alias(libs.plugins.kotlin.jvm) apply false
7 | alias(libs.plugins.kotlin.multiplatform) apply false
8 | }
9 |
10 | group = "testtool"
11 |
--------------------------------------------------------------------------------
/testtool/client/src/jvmMain/kotlin/TesttoolClient.jvm.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.testtool.client
6 |
7 | internal actual fun hostOverride(): String? {
8 | // on android emulator `localhost` is not accessible, and we need to use this specific address
9 | if (System.getProperty("java.vendor")!!.contains("android", ignoreCase = true)) {
10 | return "10.0.2.2"
11 | }
12 | return null
13 | }
14 |
--------------------------------------------------------------------------------
/testtool/client/src/nonJvmMain/kotlin/TesttoolClient.nonJvm.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.testtool.client
6 |
7 | internal actual fun hostOverride(): String? = null
8 |
--------------------------------------------------------------------------------
/testtool/gradle.properties:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | #
4 |
5 | #Kotlin
6 | kotlin.native.ignoreDisabledTargets=true
7 | kotlin.js.yarn=false
8 |
--------------------------------------------------------------------------------
/testtool/plugin/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | import org.jetbrains.kotlin.gradle.dsl.*
6 |
7 | plugins {
8 | alias(libs.plugins.kotlin.jvm)
9 | `java-gradle-plugin`
10 | }
11 |
12 | kotlin {
13 | compilerOptions {
14 | languageVersion.set(KotlinVersion.KOTLIN_1_8)
15 | apiVersion.set(KotlinVersion.KOTLIN_1_8)
16 | }
17 | }
18 |
19 | dependencies {
20 | compileOnly(kotlin("stdlib"))
21 | compileOnly(gradleKotlinDsl())
22 | compileOnly(libs.kotlin.gradle.plugin)
23 | compileOnly(libs.android.gradle.plugin)
24 |
25 | implementation(projects.server)
26 | }
27 |
28 | gradlePlugin {
29 | plugins {
30 | create("testtool.server") {
31 | id = "testtool.server"
32 | implementationClass = "dev.whyoleg.cryptography.testtool.plugin.TesttoolServerPlugin"
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/testtool/plugin/src/main/kotlin/TesttoolServerConfiguration.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.testtool.plugin
6 |
7 | import org.gradle.api.*
8 | import org.gradle.api.file.*
9 | import org.gradle.api.provider.*
10 |
11 | class TesttoolServerConfiguration(rootProject: Project) {
12 | init {
13 | require(rootProject == rootProject.rootProject) { "Root project required" }
14 | }
15 |
16 | val instanceId: Provider = rootProject.providers.gradleProperty("ckbuild.testtool.instanceId")
17 | val buildDir: Provider = rootProject.layout.buildDirectory.dir("testtool")
18 | val serverStorageDir: Provider = buildDir.map { it.dir("server-storage") }
19 | }
20 |
--------------------------------------------------------------------------------
/testtool/plugin/src/main/kotlin/TesttoolServerPlugin.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.testtool.plugin
6 |
7 | import com.android.build.gradle.internal.tasks.*
8 | import org.gradle.api.*
9 | import org.gradle.api.tasks.testing.*
10 | import org.gradle.kotlin.dsl.*
11 |
12 | open class TesttoolServerPlugin : Plugin {
13 | override fun apply(target: Project): Unit = with(target) {
14 | val instance = TesttoolServerConfiguration(rootProject)
15 | val serverProvider = gradle.sharedServices.registerIfAbsent(
16 | "testtool-server-service",
17 | TesttoolServerService::class.java
18 | ) {
19 | it.parameters {
20 | it.instanceId.set(instance.instanceId)
21 | it.storage.set(instance.serverStorageDir)
22 | }
23 | }
24 |
25 | tasks.matching {
26 | it is AbstractTestTask || it is AndroidTestTask
27 | }.configureEach {
28 | it.doFirst {
29 | if (instance.instanceId.isPresent) serverProvider.get()
30 | }
31 | it.usesService(serverProvider)
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/testtool/plugin/src/main/kotlin/TesttoolServerService.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.testtool.plugin
6 |
7 | import dev.whyoleg.cryptography.testtool.server.*
8 | import org.gradle.api.file.*
9 | import org.gradle.api.provider.*
10 | import org.gradle.api.services.*
11 | import java.util.*
12 |
13 | abstract class TesttoolServerService : BuildService, AutoCloseable {
14 | interface Parameters : BuildServiceParameters {
15 | val instanceId: Property
16 | val storage: DirectoryProperty
17 | }
18 |
19 | // use random prefix to easy local dev
20 | private val server = startTesttoolServer(
21 | instanceId = "${parameters.instanceId.get()}-${UUID.randomUUID()}",
22 | storagePath = parameters.storage.get().asFile.toPath()
23 | )
24 |
25 | override fun close(): Unit = server.close()
26 | }
27 |
--------------------------------------------------------------------------------
/testtool/server/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | import org.jetbrains.kotlin.gradle.dsl.*
6 |
7 | plugins {
8 | alias(libs.plugins.kotlin.jvm)
9 | }
10 |
11 | kotlin {
12 | compilerOptions {
13 | languageVersion.set(KotlinVersion.KOTLIN_1_8)
14 | apiVersion.set(KotlinVersion.KOTLIN_1_8)
15 | }
16 | }
17 |
18 | dependencies {
19 | implementation(libs.ktor.server.core)
20 | implementation(libs.ktor.server.cio)
21 | implementation(libs.ktor.server.calllogging)
22 | implementation(libs.ktor.server.cors)
23 |
24 | implementation(libs.logback.classic)
25 | }
26 |
--------------------------------------------------------------------------------
/testtool/server/src/main/kotlin/TesttoolServer.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2025 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.whyoleg.cryptography.testtool.server
6 |
7 | import io.ktor.server.application.*
8 | import io.ktor.server.cio.*
9 | import io.ktor.server.engine.*
10 | import io.ktor.server.plugins.calllogging.*
11 | import io.ktor.server.plugins.cors.routing.*
12 | import io.ktor.server.routing.*
13 | import java.io.*
14 | import java.nio.file.*
15 |
16 | fun startTesttoolServer(
17 | instanceId: String,
18 | storagePath: Path,
19 | ): Closeable {
20 | println("TesttoolServer: starting...")
21 | val server = embeddedServer(CIO, 9000) {
22 | //TODO: redirect logback to file
23 | install(CallLogging) {
24 | disableDefaultColors()
25 | }
26 | install(CORS) { anyHost() }
27 | routing {
28 | routes(instanceId, storagePath)
29 | }
30 | }.start()
31 |
32 | println("TesttoolServer: started")
33 |
34 | return Closeable {
35 | println("TesttoolServer: stopping...")
36 | server.stop()
37 | println("TesttoolServer: stopped")
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/testtool/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023-2024 Oleg Yukhnevich. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | import cksettings.*
6 |
7 | pluginManagement {
8 | includeBuild("../build-settings")
9 | }
10 |
11 | plugins {
12 | id("cksettings.default")
13 | }
14 |
15 | dependencyResolutionManagement {
16 | versionCatalogs.named("libs") {
17 | from(files("../gradle/libs.versions.toml"))
18 | }
19 | }
20 |
21 | projects("testtool") {
22 | module("client")
23 | module("server")
24 | module("plugin")
25 | }
26 |
--------------------------------------------------------------------------------