diff --git a/kmp-advcrypto/src/linuxX64Main/kotlin/io/karma/advcrypto/linux/providers/OpenSSLCryptoProvider.kt b/kmp-advcrypto/src/linuxX64Main/kotlin/io/karma/advcrypto/linux/providers/OpenSSLCryptoProvider.kt index 92f2857..df3ba61 100644 --- a/kmp-advcrypto/src/linuxX64Main/kotlin/io/karma/advcrypto/linux/providers/OpenSSLCryptoProvider.kt +++ b/kmp-advcrypto/src/linuxX64Main/kotlin/io/karma/advcrypto/linux/providers/OpenSSLCryptoProvider.kt @@ -14,17 +14,25 @@ * limitations under the License. */ +@file:OptIn(ExperimentalForeignApi::class) + package io.karma.advcrypto.linux.providers import io.karma.advcrypto.AbstractProvider import io.karma.advcrypto.Providers +import io.karma.advcrypto.algorithm.BlockMode +import io.karma.advcrypto.algorithm.delegates.CipherDelegate import io.karma.advcrypto.algorithm.delegates.KeyGenContext +import io.karma.advcrypto.annotations.InsecureCryptoApi import io.karma.advcrypto.keys.Key import io.karma.advcrypto.keys.KeyPair import io.karma.advcrypto.keys.enum.KeyType import io.karma.advcrypto.linux.keys.OpenSSLKey import io.karma.advcrypto.linux.keys.OpenSSLPKey +import io.karma.advcrypto.linux.utils.KeyReaderHelper import io.karma.advcrypto.linux.utils.SecureHeap +import kotlinx.cinterop.ByteVar +import kotlinx.cinterop.CPointer import kotlinx.cinterop.CValuesRef import kotlinx.cinterop.ExperimentalForeignApi import kotlinx.cinterop.UIntVar @@ -39,9 +47,16 @@ import kotlinx.cinterop.value import libssl.BN_free import libssl.BN_new import libssl.BN_set_word +import libssl.EVP_CIPHER +import libssl.EVP_CIPHER_CTX +import libssl.EVP_CIPHER_CTX_ctrl +import libssl.EVP_CIPHER_CTX_new +import libssl.EVP_CTRL_GCM_SET_IVLEN +import libssl.EVP_DecryptInit_ex import libssl.EVP_DigestFinal import libssl.EVP_DigestInit import libssl.EVP_DigestUpdate +import libssl.EVP_EncryptInit_ex import libssl.EVP_MAX_MD_SIZE import libssl.EVP_MD import libssl.EVP_MD_CTX_free @@ -49,6 +64,18 @@ import libssl.EVP_MD_CTX_new import libssl.EVP_PKEY_free import libssl.EVP_PKEY_new import libssl.EVP_PKEY_set1_RSA +import libssl.EVP_aes_128_cbc +import libssl.EVP_aes_128_ctr +import libssl.EVP_aes_128_ecb +import libssl.EVP_aes_128_gcm +import libssl.EVP_aes_192_cbc +import libssl.EVP_aes_192_ctr +import libssl.EVP_aes_192_ecb +import libssl.EVP_aes_192_gcm +import libssl.EVP_aes_256_cbc +import libssl.EVP_aes_256_ctr +import libssl.EVP_aes_256_ecb +import libssl.EVP_aes_256_gcm import libssl.EVP_md5 import libssl.EVP_sha1 import libssl.EVP_sha224 @@ -65,6 +92,75 @@ import libssl.RSA_free import libssl.RSA_generate_key_ex import libssl.RSA_new +data class BlockCipherContext( + val encryptCipher: CPointer, + val decryptCipher: CPointer, + val cipherType: CPointer, + // val keyBuffer: CPointer, + val blockMode: BlockMode +) + +/** + * This method creates the method delegates for a default OpenSSL-based Cipher for a algorithm + * provider. This is used for AES etc. + */ +@OptIn(InsecureCryptoApi::class) +fun CipherDelegate.initializeSymmetricOpenSSLBlockCipher( + secureHeap: SecureHeap, + defaultBlockMode: BlockMode +) { + initializer { spec, key -> + // TODO: If key format is not BINARY, derive key encoding to BINARY + val bitSize = KeyReaderHelper.readKeySizeInBits(key) + //val keyBuffer = checkNotNull(secureHeap.allocate((bitSize / 8).toULong())) + // TODO: Write encoded key securely into key buffer + + val blockMode = spec.blockMode?: defaultBlockMode + val cipherType = checkNotNull(when(blockMode) { + BlockMode.GCM -> when(bitSize) { + 128 -> EVP_aes_128_gcm() + 192 -> EVP_aes_192_gcm() + 256 -> EVP_aes_256_gcm() + else -> throw IllegalArgumentException("AES-$blockMode-$bitSize is not supported") + } + BlockMode.CTR -> when(bitSize) { + 128 -> EVP_aes_128_ctr() + 192 -> EVP_aes_192_ctr() + 256 -> EVP_aes_256_ctr() + else -> throw IllegalArgumentException("AES-$blockMode-$bitSize is not supported") + } + BlockMode.CBC -> when(bitSize) { + 128 -> EVP_aes_128_cbc() + 192 -> EVP_aes_192_cbc() + 256 -> EVP_aes_256_cbc() + else -> throw IllegalArgumentException("AES-$blockMode-$bitSize is not supported") + } + BlockMode.ECB -> when(bitSize) { + 128 -> EVP_aes_128_ecb() + 192 -> EVP_aes_192_ecb() + 256 -> EVP_aes_256_ecb() + else -> throw IllegalArgumentException("AES-$blockMode-$bitSize is not supported") + } + }) + + val encryptCipherContext = checkNotNull(EVP_CIPHER_CTX_new()).apply { + EVP_EncryptInit_ex(this, cipherType, null, null, null) + if (blockMode == BlockMode.GCM) { + EVP_CIPHER_CTX_ctrl(this, EVP_CTRL_GCM_SET_IVLEN, 16, null) + } + } + + val decryptCipherContext = checkNotNull(EVP_CIPHER_CTX_new()).apply { + EVP_DecryptInit_ex(this, cipherType, null, null, null) + if (blockMode == BlockMode.GCM) { + EVP_CIPHER_CTX_ctrl(this, EVP_CTRL_GCM_SET_IVLEN, 16, null) + } + } + + BlockCipherContext(encryptCipherContext, decryptCipherContext, cipherType, blockMode) + } +} + class OpenSSLCryptoProvider: AbstractProvider( "Default", "This class provides access to the default asymmetric and symmetric algorithms on Linux", @@ -118,6 +214,9 @@ class OpenSSLCryptoProvider: AbstractProvider( openSSLHasher("SHA3-512", EVP_sha3_512()) algorithm(providers, "AES") { + allowedBlockModes = BlockMode.entries.toTypedArray() + defaultBlockMode = BlockMode.GCM + keyGenerator(Key.PURPOSES_SYMMETRIC, arrayOf(128, 196, 256), 256) { initializer { spec -> KeyGenContext(spec, Unit) } generateKey { context -> @@ -130,6 +229,10 @@ class OpenSSLCryptoProvider: AbstractProvider( ) } } + + cipher { + initializeSymmetricOpenSSLBlockCipher(secureHeap, defaultBlockMode!!) + } } algorithm(providers, "RSA") {