├── .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 | 24 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/copyright/Apache_2_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 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 | --------------------------------------------------------------------------------