Skip to content
This repository has been archived by the owner on Aug 12, 2024. It is now read-only.

Commit

Permalink
Add MemoryBuffers
Browse files Browse the repository at this point in the history
  • Loading branch information
Cach30verfl0w committed Jun 16, 2024
1 parent 1bc9c9a commit cdc8bf8
Show file tree
Hide file tree
Showing 15 changed files with 373 additions and 166 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,21 @@

package io.karma.advcrypto.android.keys

import io.karma.advcrypto.annotations.InsecureCryptoApi
import io.karma.advcrypto.keys.Key
import io.karma.advcrypto.keys.enum.KeyFormat
import io.karma.advcrypto.keys.enum.KeyType
import io.karma.advcrypto.store.MemoryBuffer

typealias RawKey = java.security.Key

class AndroidKey(val raw: RawKey, override val purposes: UByte, override val type: KeyType): Key {
override val algorithm: String = raw.algorithm
@InsecureCryptoApi
override val encoded: ByteArray? = null
override val format: KeyFormat? = null

override fun copyEncodedInto(buffer: MemoryBuffer) {
TODO("Not yet implemented")
}

override fun toString(): String {
return "AndroidKey(algorithm='$algorithm', purposes=$purposes, raw=$raw)"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2024 Cach30verfl0w
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.karma.advcrypto.store

/**
* This method creates a memory buffer from the specified byte array. This can be used to
* copy data directly into the byte array
*
* @author Cedric Hammes
* @since 16/06/2024
*/
actual fun emptyBuffer(): MemoryBuffer {
TODO("Not yet implemented")
}

/**
* This method creates a secure memory buffer based on the platform.
*
* @author Cedric Hammes
* @since 16/06/2024
*/
actual fun secureBuffer(): MemoryBuffer {
TODO("Not yet implemented")
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,7 @@ package io.karma.advcrypto.annotations
@RequiresOptIn("By using this function of the API, the confidentiality of sensitive data is in risk", RequiresOptIn.Level.ERROR)
@MustBeDocumented
@Retention(AnnotationRetention.BINARY)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FIELD, AnnotationTarget.PROPERTY)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FIELD, AnnotationTarget.PROPERTY,
AnnotationTarget.FUNCTION
)
annotation class InsecureCryptoApi
15 changes: 13 additions & 2 deletions kmp-advcrypto/src/commonMain/kotlin/io/karma/advcrypto/keys/Key.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ package io.karma.advcrypto.keys
import io.karma.advcrypto.annotations.InsecureCryptoApi
import io.karma.advcrypto.keys.enum.KeyFormat
import io.karma.advcrypto.keys.enum.KeyType
import io.karma.advcrypto.store.MemoryBuffer
import io.karma.advcrypto.store.emptyBuffer

/**
* This interface represents every single key which can be generated by this library. These keys are
Expand All @@ -33,15 +35,24 @@ import io.karma.advcrypto.keys.enum.KeyType
interface Key: AutoCloseable {

/**
* This value represents the raw encoded key in the format also specified in this key. This is
* This method copies the internal encoded buffer into the specified memory buffer. This can
* be used to copy data securely into a secure memory.
*
* @author Cedric Hammes
* @since 16/06/2024
*/
fun copyEncodedInto(buffer: MemoryBuffer)

/**
* This method returns the raw encoded key in the format also specified in this key. This is
* used to create another key by a key. Warning: If you use this method, the key can be copied
* into insecure memory that can be vulnerable to information leakage.
*
* @author Cedric Hammes
* @since 14/06/2024
*/
@InsecureCryptoApi
val encoded: ByteArray?
fun encoded(): ByteArray = emptyBuffer().apply { copyEncodedInto(this) }.toByteArray()

/**
* This value represents the format of the raw encoded key. This format is used to transform the
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright (c) 2024 Cach30verfl0w
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.karma.advcrypto.store

import io.karma.advcrypto.annotations.InsecureCryptoApi

/**
* This method creates a empty memory buffer based on the platform.
*
* @author Cedric Hammes
* @since 16/06/2024
*/
expect fun emptyBuffer(): MemoryBuffer

/**
* This method creates a secure memory buffer based on the platform.
*
* @author Cedric Hammes
* @since 16/06/2024
*/
expect fun secureBuffer(): MemoryBuffer

/**
* This is the implementation of a memory buffer. Memory buffers are used to provide cross-platform
* copy and write operations for insecure and secure memory.
*
* @author Cedric Hammes
* @since 16/06/2024
*/
@OptIn(ExperimentalStdlibApi::class)
interface MemoryBuffer: AutoCloseable {

/**
* This method copies this memory buffer into another memory buffer.
*
* @author Cedric Hammes
* @since 16/06/2024
*/
fun copyInto(buffer: MemoryBuffer, size: Int = this.size)

/**
* This method returns the content of the memory buffer as byte array. If you are using a secure
* buffer, this data can be leaked into insecure memory.
*
* @author Cedric Hammes
* @since 16/06/2024
*/
@InsecureCryptoApi
fun toByteArray(): ByteArray

val size: Int

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2024 Cach30verfl0w
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.karma.advcrypto.store

/**
* This method creates a memory buffer from the specified byte array. This can be used to
* copy data directly into the byte array
*
* @author Cedric Hammes
* @since 16/06/2024
*/
actual fun emptyBuffer(): MemoryBuffer {
TODO("Not yet implemented")
}

/**
* This method creates a secure memory buffer based on the platform.
*
* @author Cedric Hammes
* @since 16/06/2024
*/
actual fun secureBuffer(): MemoryBuffer {
TODO("Not yet implemented")
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,35 @@

package io.karma.advcrypto.linux.keys

import io.karma.advcrypto.annotations.InsecureCryptoApi

import io.karma.advcrypto.keys.Key
import io.karma.advcrypto.keys.enum.KeyFormat
import io.karma.advcrypto.keys.enum.KeyType
import io.karma.advcrypto.linux.utils.SecureHeap
import io.karma.advcrypto.store.MemoryBuffer
import io.karma.advcrypto.store.PointerMemoryBuffer
import kotlinx.cinterop.CPointer
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.UByteVar
import kotlinx.cinterop.get
import kotlinx.cinterop.reinterpret
import kotlinx.cinterop.toKString
import libssl.ERR_error_string
import libssl.ERR_get_error
import libssl.RAND_bytes

@OptIn(ExperimentalForeignApi::class)
class OpenSSLKey(private val secureHeap: SecureHeap,
override val purposes: UByte,
override val algorithm: String,
val rawDataPtr: CPointer<UByteVar>,
val rawDataSize: ULong,
override val type: KeyType
class OpenSSLKey(
private val secureHeap: SecureHeap,
override val purposes: UByte,
override val algorithm: String,
val rawDataPtr: CPointer<UByteVar>,
val rawDataSize: ULong,
override val type: KeyType
): Key {
@InsecureCryptoApi
override val encoded: ByteArray = ByteArray(rawDataSize.toInt()) { rawDataPtr[it].toByte() }
override fun copyEncodedInto(buffer: MemoryBuffer) {
PointerMemoryBuffer(rawDataPtr, rawDataSize.toInt()).copyInto(buffer)
}

override val format: KeyFormat = KeyFormat.DER // TODO: Derive from key

override fun close() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,15 @@

package io.karma.advcrypto.linux.keys

import io.karma.advcrypto.annotations.InsecureCryptoApi
import io.karma.advcrypto.keys.Key
import io.karma.advcrypto.keys.enum.KeyFormat
import io.karma.advcrypto.keys.enum.KeyType
import io.karma.advcrypto.store.BIOMemoryBuffer
import io.karma.advcrypto.store.MemoryBuffer
import io.karma.advcrypto.store.emptyBuffer
import kotlinx.cinterop.CPointer
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.refTo
import kotlinx.cinterop.toKString
import libssl.BIO_ctrl_pending
import libssl.BIO_free
import libssl.BIO_new
import libssl.BIO_read
import libssl.BIO_s_mem
import libssl.EVP_PKEY
import libssl.EVP_PKEY_ED25519
import libssl.EVP_PKEY_RSA
Expand All @@ -37,34 +33,25 @@ import libssl.EVP_PKEY_get_base_id
import libssl.OBJ_nid2sn
import libssl.PEM_write_bio_PUBKEY
import libssl.i2d_PUBKEY_bio
import libssl.i2d_PrivateKey_bio

@OptIn(ExperimentalForeignApi::class)
class OpenSSLPKey(val rawKey: CPointer<EVP_PKEY>,
override val purposes: UByte, override val type: KeyType,
override val format: KeyFormat = KeyFormat.DER): Key {
@InsecureCryptoApi
override val encoded: ByteArray?
get() {
return when(this.format) {
KeyFormat.DER -> {
val bio = BIO_new(BIO_s_mem())
i2d_PUBKEY_bio(bio, rawKey)
val data = ByteArray(BIO_ctrl_pending(bio).toInt())
BIO_read(bio, data.refTo(0), data.size)
BIO_free(bio)
data
override fun copyEncodedInto(buffer: MemoryBuffer) {
(emptyBuffer() as BIOMemoryBuffer).apply {
when(format) {
KeyFormat.DER -> when(type) {
KeyType.PUBLIC -> i2d_PUBKEY_bio(this.bio, rawKey)
KeyType.PRIVATE -> i2d_PrivateKey_bio(this.bio, rawKey)
else -> throw UnsupportedOperationException("Unsupported key type")
}
KeyFormat.PEM -> {
val bio = BIO_new(BIO_s_mem())
PEM_write_bio_PUBKEY(bio, rawKey)
val data = ByteArray(BIO_ctrl_pending(bio).toInt())
BIO_read(bio, data.refTo(0), data.size)
BIO_free(bio)
data
}
else -> null
KeyFormat.PEM -> PEM_write_bio_PUBKEY(this.bio, rawKey)
else -> throw UnsupportedOperationException("Format '${format}' supported")
}
}
}.copyInto(buffer)
}
override val algorithm: String = when(val baseId = EVP_PKEY_get_base_id(rawKey)) {
EVP_PKEY_RSA -> "RSA"
EVP_PKEY_ED25519 -> "ED25519"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class DefaultKeyStoreProvider: AbstractProvider(
"This provider provides access to the keystore interface on Linux devices",
"1.0.0-Dev"
) {
private val secHeap = SecureHeap(UShort.MAX_VALUE.toULong() + 1u, 0u)
private val secHeap = SecureHeap()

override fun initialize(providers: Providers) {
keyStore("Default") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ class OpenSSLCryptoProvider: AbstractProvider(
"This class provides access to the default asymmetric and symmetric algorithms on Linux",
"1.0.0-Dev"
) {
private val secureHeap = SecureHeap(UShort.MAX_VALUE.toULong() + 1u, 0u)
private val secureHeap = SecureHeap()

@OptIn(ExperimentalForeignApi::class, ExperimentalStdlibApi::class)
override fun initialize(providers: Providers) {
Expand Down
Loading

0 comments on commit cdc8bf8

Please sign in to comment.